/*
 * The customer's own view of one server.
 *
 * Plain CSS for the same reason as order-cards.css: the panels have no Vite
 * build and serve Filament's pre-compiled app.css, so `class="flex gap-4"` in a
 * Blade view here is inert markup. Anything bespoke brings its own rules.
 *
 * Registered on the client panel only, in ClientPanelProvider:
 *
 *     Css::make('service-page', resource_path('css/service-page.css'))
 *
 * which `php artisan filament:assets` copies to public/css/app/service-page.css.
 * Editing this file therefore needs that command re-run — composer's
 * post-autoload-dump does it too, by way of `filament:upgrade`.
 *
 * Every colour is a variable FilamentColor writes into :root at runtime
 * (--gray-*, --primary-*, --success-*, --warning-*, --danger-*, --info-*) and
 * every size comes from the theme block in app.css (--radius-xl, --text-sm), so
 * this page tracks the panel's palette and its dark mode instead of defining a
 * second one. Dark mode is the `.dark` class on <html>.
 *
 * The namespace is `sv-`, kept apart from order-cards' `oc-` because both files
 * load on every client page and a shared prefix would let a rule written for the
 * order form silently restyle a server.
 */

.sv-page {
    display: grid;
    gap: 1rem;
}

/* ------------------------------------------------------------------ *
 * State banner — the one thing that outranks the rest of the page
 * ------------------------------------------------------------------ */

.sv-banner {
    display: flex;
    gap: 0.75rem;
    align-items: flex-start;
    padding: 0.875rem 1rem;
    border-radius: var(--radius-xl, 0.75rem);
    background-color: color-mix(in oklab, var(--info-500) 8%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--info-500) 25%, transparent);
}

.sv-banner--warning {
    background-color: color-mix(in oklab, var(--warning-500) 9%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--warning-500) 28%, transparent);
}

.sv-banner--danger {
    background-color: color-mix(in oklab, var(--danger-500) 9%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--danger-500) 28%, transparent);
}

.sv-banner-icon {
    flex: none;
    width: 1.25rem;
    height: 1.25rem;
    margin-top: 0.0625rem;
    color: var(--info-600);
}

.sv-banner--warning .sv-banner-icon {
    color: var(--warning-600);
}

.sv-banner--danger .sv-banner-icon {
    color: var(--danger-600);
}

.dark .sv-banner-icon {
    color: var(--info-400);
}

.dark .sv-banner--warning .sv-banner-icon {
    color: var(--warning-400);
}

.dark .sv-banner--danger .sv-banner-icon {
    color: var(--danger-400);
}

/* The icon spins only while something is actually in flight, which is the whole
   signal — a still cog beside "Building" reads as a stalled build. */
.sv-banner-icon--spin {
    animation: sv-spin 1.4s linear infinite;
}

@keyframes sv-spin {
    to {
        transform: rotate(360deg);
    }
}

.sv-banner-title {
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    color: var(--gray-950);
}

.sv-banner-body {
    margin-top: 0.125rem;
    font-size: var(--text-sm, 0.875rem);
    line-height: 1.35rem;
    color: var(--gray-600);
}

.dark .sv-banner-title {
    color: var(--gray-50);
}

.dark .sv-banner-body {
    color: var(--gray-400);
}

/* ------------------------------------------------------------------ *
 * Hero — the identity of the machine, said once and said properly
 * ------------------------------------------------------------------ */

.sv-hero {
    position: relative;
    overflow: hidden;
    padding: 1.25rem;
    border-radius: var(--radius-xl, 0.75rem);
    background-color: white;
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-950) 6%, transparent);
}

/* A wash rather than a picture. It gives the top of the page a horizon without
   putting a decorative image in front of a customer who came here to reboot. */
.sv-hero::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 6rem;
    background-image: linear-gradient(120deg, color-mix(in oklab, var(--primary-500) 12%, transparent), transparent 62%);
    pointer-events: none;
}

.dark .sv-hero {
    background-color: var(--gray-900);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, white 10%, transparent);
}

.dark .sv-hero::before {
    background-image: linear-gradient(120deg, color-mix(in oklab, var(--primary-400) 16%, transparent), transparent 62%);
}

.sv-hero-top {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    align-items: center;
}

/* The image the request was about. Sized in rem so it holds its place whatever
   the PNG's intrinsic size is, and `contain` so a square Windows mark and a wide
   Ubuntu one both sit inside the same tile without either being cropped. */
.sv-hero-logo {
    flex: none;
    display: grid;
    place-items: center;
    width: 3.5rem;
    height: 3.5rem;
    padding: 0.5rem;
    border-radius: 0.875rem;
    background-color: white;
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-950) 8%, transparent), 0 1px 2px color-mix(in oklab, var(--gray-950) 6%, transparent);
}

.sv-hero-logo img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.dark .sv-hero-logo {
    background-color: color-mix(in oklab, white 6%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, white 12%, transparent);
}

.sv-hero-main {
    flex: 1 1 16rem;
    min-width: 0;
}

.sv-hero-name {
    font-size: var(--text-xl, 1.25rem);
    font-weight: 700;
    line-height: 1.75rem;
    color: var(--gray-950);
    word-break: break-word;
}

.sv-hero-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
    align-items: center;
    margin-top: 0.25rem;
    font-size: var(--text-sm, 0.875rem);
    color: var(--gray-500);
}

.dark .sv-hero-name {
    color: var(--gray-50);
}

.dark .sv-hero-meta {
    color: var(--gray-400);
}

.sv-sep {
    width: 0.1875rem;
    height: 0.1875rem;
    border-radius: 9999px;
    background-color: currentColor;
    opacity: 0.55;
}

.sv-hero-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
    align-items: center;
}

/* ------------------------------------------------------------------ *
 * Badges — a dot and a word, coloured from the enum's own colour
 * ------------------------------------------------------------------ */

.sv-badge {
    display: inline-flex;
    gap: 0.375rem;
    align-items: center;
    padding: 0.25rem 0.5rem;
    border-radius: 0.5rem;
    font-size: var(--text-xs, 0.75rem);
    font-weight: 600;
    white-space: nowrap;
    color: var(--gray-700);
    background-color: color-mix(in oklab, var(--gray-500) 10%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-500) 18%, transparent);
}

.sv-badge-dot {
    width: 0.375rem;
    height: 0.375rem;
    border-radius: 9999px;
    background-color: currentColor;
}

.sv-badge--success {
    color: var(--success-700);
    background-color: color-mix(in oklab, var(--success-500) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--success-500) 22%, transparent);
}

.sv-badge--warning {
    color: var(--warning-700);
    background-color: color-mix(in oklab, var(--warning-500) 14%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--warning-500) 24%, transparent);
}

.sv-badge--danger {
    color: var(--danger-700);
    background-color: color-mix(in oklab, var(--danger-500) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--danger-500) 22%, transparent);
}

.sv-badge--info {
    color: var(--info-700);
    background-color: color-mix(in oklab, var(--info-500) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--info-500) 22%, transparent);
}

.sv-badge--primary {
    color: var(--primary-700);
    background-color: color-mix(in oklab, var(--primary-500) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--primary-500) 22%, transparent);
}

.dark .sv-badge {
    color: var(--gray-300);
}

.dark .sv-badge--success {
    color: var(--success-300);
}

.dark .sv-badge--warning {
    color: var(--warning-300);
}

.dark .sv-badge--danger {
    color: var(--danger-300);
}

.dark .sv-badge--info {
    color: var(--info-300);
}

.dark .sv-badge--primary {
    color: var(--primary-300);
}

/* A running server gets a halo on its dot. It is the one piece of motion on a
   healthy page and it answers "is it up" from across the room. */
.sv-badge--success .sv-badge-dot {
    box-shadow: 0 0 0 0.1875rem color-mix(in oklab, var(--success-500) 22%, transparent);
}

/* ------------------------------------------------------------------ *
 * Copying — the flash that says a value went to the clipboard
 * ------------------------------------------------------------------ */

/* Feedback has to be on the thing that was pressed. A toast for a copy is a
   notification for something the customer already knows they did. */
.sv-copied.sv-copy-btn {
    color: var(--success-600);
}

.dark .sv-copied.sv-copy-btn {
    color: var(--success-400);
}

/* Both marks ship in the markup and this is what decides which one is seen. In
   JavaScript it would be one more thing to keep in step with the flash class, and
   a frame with no icon at all between removing one and inserting the other. */
.sv-copy-check {
    display: none;
}

.sv-copied .sv-copy-icon {
    display: none;
}

.sv-copied .sv-copy-check {
    display: block;
}

/* ------------------------------------------------------------------ *
 * Stat tiles — four numbers, each with a unit, none of them a sentence
 * ------------------------------------------------------------------ */

.sv-stats {
    display: grid;
    gap: 0.75rem;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
}

.sv-stat {
    display: flex;
    gap: 0.75rem;
    align-items: flex-start;
    padding: 0.875rem 1rem;
    border-radius: var(--radius-xl, 0.75rem);
    background-color: white;
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-950) 6%, transparent);
}

.dark .sv-stat {
    background-color: var(--gray-900);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, white 10%, transparent);
}

.sv-stat-icon {
    flex: none;
    display: grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    border-radius: 0.5rem;
    color: var(--primary-600);
    background-color: color-mix(in oklab, var(--primary-500) 10%, transparent);
}

.sv-stat-icon svg {
    width: 1.125rem;
    height: 1.125rem;
}

.dark .sv-stat-icon {
    color: var(--primary-300);
    background-color: color-mix(in oklab, var(--primary-400) 16%, transparent);
}

.sv-stat-body {
    min-width: 0;
    flex: 1 1 auto;
}

.sv-stat-label {
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--gray-500);
}

.sv-stat-value {
    display: flex;
    gap: 0.25rem;
    align-items: baseline;
    margin-top: 0.125rem;
    font-size: var(--text-lg, 1.125rem);
    font-weight: 700;
    line-height: 1.5rem;
    color: var(--gray-950);
}

.sv-stat-unit {
    font-size: var(--text-xs, 0.75rem);
    font-weight: 500;
    color: var(--gray-500);
}

.sv-stat-note {
    margin-top: 0.125rem;
    font-size: var(--text-xs, 0.75rem);
    color: var(--gray-500);
}

.dark .sv-stat-label,
.dark .sv-stat-unit,
.dark .sv-stat-note {
    color: var(--gray-400);
}

.dark .sv-stat-value {
    color: var(--gray-50);
}

/* The meter only appears on a metered allowance, so its absence is information:
   an unmetered server shows no bar to read into. */
.sv-meter {
    height: 0.25rem;
    margin-top: 0.4375rem;
    border-radius: 9999px;
    overflow: hidden;
    background-color: var(--gray-200);
}

.dark .sv-meter {
    background-color: color-mix(in oklab, white 12%, transparent);
}

.sv-meter-fill {
    height: 100%;
    border-radius: 9999px;
    background-color: var(--primary-500);
}

.sv-meter-fill--warning {
    background-color: var(--warning-500);
}

.sv-meter-fill--danger {
    background-color: var(--danger-500);
}

/* ------------------------------------------------------------------ *
 * Cards — the containers everything else lives in
 * ------------------------------------------------------------------ */

/* Two columns where there is room and one where there is not. `auto-fit` with a
   floor rather than a media query, because the panel's sidebar can be open or
   collapsed and the breakpoint that matters is the width of this column, not the
   width of the window. */
.sv-grid {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    align-items: start;
}

.sv-card {
    display: flex;
    flex-direction: column;
    border-radius: var(--radius-xl, 0.75rem);
    background-color: white;
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-950) 6%, transparent);
}

.dark .sv-card {
    background-color: var(--gray-900);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, white 10%, transparent);
}

.sv-card-head {
    display: flex;
    gap: 0.625rem;
    align-items: center;
    padding: 0.875rem 1rem;
    border-bottom: 1px solid color-mix(in oklab, var(--gray-950) 6%, transparent);
}

.dark .sv-card-head {
    border-bottom-color: color-mix(in oklab, white 10%, transparent);
}

.sv-card-icon {
    flex: none;
    width: 1.125rem;
    height: 1.125rem;
    color: var(--gray-400);
}

.sv-card-title {
    flex: 1 1 auto;
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    color: var(--gray-950);
}

.dark .sv-card-title {
    color: var(--gray-50);
}

.sv-card-body {
    padding: 0.25rem 1rem 0.875rem;
}

/* ------------------------------------------------------------------ *
 * Rows — a label and a value, aligned down a card
 * ------------------------------------------------------------------ */

.sv-rows {
    display: grid;
}

.sv-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    align-items: center;
    justify-content: space-between;
    padding: 0.625rem 0;
    border-bottom: 1px solid color-mix(in oklab, var(--gray-950) 5%, transparent);
}

.dark .sv-row {
    border-bottom-color: color-mix(in oklab, white 8%, transparent);
}

.sv-row:last-child {
    border-bottom: 0;
}

.sv-row-label {
    flex: none;
    font-size: var(--text-sm, 0.875rem);
    color: var(--gray-500);
}

.sv-row-value {
    min-width: 0;
    font-size: var(--text-sm, 0.875rem);
    font-weight: 500;
    text-align: right;
    color: var(--gray-950);
}

.sv-row-value--mono {
    font-family: ui-monospace, "SF Mono", "Cascadia Mono", monospace;
    overflow-wrap: anywhere;
}

.sv-row-note {
    display: block;
    font-size: var(--text-xs, 0.75rem);
    font-weight: 400;
    color: var(--gray-500);
}

/* ------------------------------------------------------------------ *
 * Card actions — buttons at the foot of a card, under its rows
 * ------------------------------------------------------------------ */

/*
 * Extend and the auto-renew switch, at the bottom of the Billing card.
 *
 * A ruled top edge rather than only a gap, because the rows above it are ruled
 * too and a pair of buttons floating in whitespace under the last one reads as
 * something that fell off the bottom of the list. Ruled, it is a footer.
 *
 * `1rem` of clear air above the rule and `0.875rem` below is the asymmetry the
 * rows use — `.sv-row` pads 0.625rem either side of its own rule and
 * `.sv-card-body` closes with 0.875rem — so the rule sits closer to what it
 * separates from than to the card's own edge.
 *
 * Wrapping, because both labels grow: "Turn auto-renew off" beside "Extend"
 * fits a paired card at desktop width and does not in the single column a phone
 * gets. They wrap rather than shrink — a truncated button label is a button
 * nobody presses.
 */
.sv-card-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    margin-top: 1rem;
    padding-top: 0.875rem;
    border-top: 1px solid color-mix(in oklab, var(--gray-950) 5%, transparent);
}

.dark .sv-card-actions {
    border-top-color: color-mix(in oklab, white 8%, transparent);
}

.dark .sv-row-label,
.dark .sv-row-note {
    color: var(--gray-400);
}

.dark .sv-row-value {
    color: var(--gray-50);
}

/* A tone on a value, for the one row that can be bad news: a due date that has
   already passed. Declared after the dark override above so it survives it. */
.sv-row-value--danger {
    color: var(--danger-600);
}

.sv-row-value--success {
    color: var(--success-600);
}

.dark .sv-row-value--danger {
    color: var(--danger-400);
}

.dark .sv-row-value--success {
    color: var(--success-400);
}

/* ------------------------------------------------------------------ *
 * Credential field — the box the password appears in, in place
 * ------------------------------------------------------------------ */

.sv-field {
    padding: 0.625rem 0;
}

.sv-field-label {
    display: block;
    margin-bottom: 0.3125rem;
    font-size: var(--text-sm, 0.875rem);
    color: var(--gray-500);
}

.dark .sv-field-label {
    color: var(--gray-400);
}

.sv-field-box {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    padding: 0.4375rem 0.5rem 0.4375rem 0.625rem;
    border-radius: 0.625rem;
    background-color: var(--gray-50);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-950) 8%, transparent);
}

.dark .sv-field-box {
    background-color: color-mix(in oklab, white 5%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, white 10%, transparent);
}

.sv-field-text {
    flex: 1 1 auto;
    min-width: 0;
    font-family: ui-monospace, "SF Mono", "Cascadia Mono", monospace;
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    color: var(--gray-950);
    overflow-wrap: anywhere;
}

.dark .sv-field-text {
    color: var(--gray-50);
}

/* The mask is not the password with a filter over it — there is no password in
   the page until somebody asks the server for one. It is twelve dots that stand
   in for a value the browser has never been sent. */
.sv-field-mask {
    letter-spacing: 0.15em;
    color: var(--gray-400);
}

.sv-field-actions {
    display: flex;
    flex: none;
    gap: 0.125rem;
    align-items: center;
}

.sv-icon-btn {
    display: grid;
    place-items: center;
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    border: 0;
    border-radius: 0.4375rem;
    cursor: pointer;
    color: var(--gray-500);
    background-color: transparent;
    transition: background-color 120ms, color 120ms;
}

.sv-icon-btn svg {
    width: 1rem;
    height: 1rem;
}

.sv-icon-btn:hover {
    color: var(--gray-700);
    background-color: color-mix(in oklab, var(--gray-950) 6%, transparent);
}

.sv-icon-btn:focus-visible {
    outline: 2px solid var(--primary-600);
    outline-offset: 1px;
}

.sv-icon-btn[disabled] {
    cursor: not-allowed;
    opacity: 0.5;
}

.dark .sv-icon-btn {
    color: var(--gray-400);
}

.dark .sv-icon-btn:hover {
    color: var(--gray-200);
    background-color: color-mix(in oklab, white 10%, transparent);
}

.sv-field-hint {
    margin-top: 0.375rem;
    font-size: var(--text-xs, 0.75rem);
    line-height: 1.125rem;
    color: var(--gray-500);
}

.dark .sv-field-hint {
    color: var(--gray-400);
}

/* ------------------------------------------------------------------ *
 * Connect command — the line a customer pastes into a terminal
 * ------------------------------------------------------------------ */

.sv-code {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    padding: 0.5rem 0.5rem 0.5rem 0.625rem;
    border-radius: 0.625rem;
    color: var(--gray-100);
    background-color: var(--gray-900);
}

.dark .sv-code {
    background-color: color-mix(in oklab, black 45%, var(--gray-900));
    box-shadow: inset 0 0 0 1px color-mix(in oklab, white 8%, transparent);
}

.sv-code-text {
    flex: 1 1 auto;
    min-width: 0;
    font-family: ui-monospace, "SF Mono", "Cascadia Mono", monospace;
    font-size: var(--text-xs, 0.75rem);
    line-height: 1.125rem;
    overflow-wrap: anywhere;
}

.sv-code-prompt {
    color: var(--gray-500);
    user-select: none;
}

.sv-code .sv-icon-btn {
    color: var(--gray-400);
}

.sv-code .sv-icon-btn:hover {
    color: white;
    background-color: color-mix(in oklab, white 12%, transparent);
}

.sv-code .sv-copied {
    color: var(--success-400);
}

/* ------------------------------------------------------------------ *
 * Network — one block per address, because an address has four facts
 * ------------------------------------------------------------------ */

.sv-nets {
    display: grid;
    gap: 0.625rem;
    padding-top: 0.625rem;
}

.sv-net {
    padding: 0.75rem;
    border-radius: 0.625rem;
    background-color: var(--gray-50);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--gray-950) 6%, transparent);
}

.dark .sv-net {
    background-color: color-mix(in oklab, white 4%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, white 8%, transparent);
}

.sv-net-top {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
}

.sv-net-addr {
    flex: 1 1 auto;
    min-width: 0;
    font-family: ui-monospace, "SF Mono", "Cascadia Mono", monospace;
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    color: var(--gray-950);
    overflow-wrap: anywhere;
}

.dark .sv-net-addr {
    color: var(--gray-50);
}

/* Gateway, mask and resolvers are reference material: needed exactly once, when
   something is being configured by hand, and noise on every other visit. So they
   are a definition grid under the address rather than four more rows in a list. */
.sv-net-facts {
    display: grid;
    gap: 0.5rem 1rem;
    grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
    margin: 0.625rem 0 0;
}

.sv-net-fact dt {
    font-size: 0.6875rem;
    font-weight: 500;
    color: var(--gray-500);
}

.sv-net-fact dd {
    margin: 0.0625rem 0 0;
    font-family: ui-monospace, "SF Mono", "Cascadia Mono", monospace;
    font-size: var(--text-xs, 0.75rem);
    color: var(--gray-800);
    overflow-wrap: anywhere;
}

.dark .sv-net-fact dt {
    color: var(--gray-400);
}

.dark .sv-net-fact dd {
    color: var(--gray-200);
}

/* ------------------------------------------------------------------ *
 * Price headline, empty states and the notes disclosure
 * ------------------------------------------------------------------ */

.sv-price {
    display: flex;
    gap: 0.375rem;
    align-items: baseline;
    padding: 0.75rem 0 0.5rem;
}

.sv-price-amount {
    font-size: var(--text-2xl, 1.5rem);
    font-weight: 700;
    line-height: 1.75rem;
    color: var(--gray-950);
}

.sv-price-term {
    font-size: var(--text-sm, 0.875rem);
    color: var(--gray-500);
}

.dark .sv-price-amount {
    color: var(--gray-50);
}

.dark .sv-price-term {
    color: var(--gray-400);
}

.sv-empty {
    padding: 0.75rem 0;
    font-size: var(--text-sm, 0.875rem);
    color: var(--gray-500);
}

.dark .sv-empty {
    color: var(--gray-400);
}

/* Notes are the admin's, not the customer's, and are usually absent. A closed
   disclosure keeps them findable and stops an empty card taking a slot on a page
   whose job is the four things above it. */
.sv-notes {
    padding: 0.25rem 1rem 0.875rem;
}

.sv-notes summary {
    display: flex;
    gap: 0.375rem;
    align-items: center;
    padding: 0.5rem 0;
    font-size: var(--text-sm, 0.875rem);
    font-weight: 500;
    cursor: pointer;
    color: var(--gray-600);
    list-style: none;
}

.sv-notes summary::-webkit-details-marker {
    display: none;
}

.sv-notes summary:hover {
    color: var(--gray-950);
}

.sv-notes-caret {
    width: 0.875rem;
    height: 0.875rem;
    transition: transform 150ms;
}

.sv-notes[open] .sv-notes-caret {
    transform: rotate(90deg);
}

.dark .sv-notes summary {
    color: var(--gray-400);
}

.dark .sv-notes summary:hover {
    color: var(--gray-50);
}

.sv-notes-body {
    padding: 0.25rem 0 0;
    font-size: var(--text-sm, 0.875rem);
    line-height: 1.375rem;
    white-space: pre-line;
    color: var(--gray-700);
}

.dark .sv-notes-body {
    color: var(--gray-300);
}

/* ------------------------------------------------------------------ *
 * Narrow screens
 * ------------------------------------------------------------------ */

/* A label and its value stop competing for one line and stack instead. Right
   alignment is what makes a two-column card scannable and what makes a
   single-column one look broken. */
@media (max-width: 30rem) {
    .sv-row {
        flex-direction: column;
        align-items: flex-start;
        gap: 0.125rem;
    }

    .sv-row-value {
        text-align: left;
    }

    .sv-hero-badges {
        width: 100%;
    }
}
