/*
 * Admin shell: a permanent left sidebar with every section, so moving between them is one
 * click instead of a trip through the dashboard.
 *
 * Loaded after app-modern.css. The sidebar is dark on purpose - it separates navigation
 * from content without needing a border, and it makes the active item readable at a
 * glance on a page that is otherwise mostly white cards and tables.
 */

.admin-shell {
    --admin-nav-w: 236px;
    --admin-nav-bg: var(--color-slate-900);
    --admin-nav-fg: var(--color-border-slate);
    --admin-nav-fg-strong: var(--color-surface-cool);
    --admin-nav-active: var(--color-admin-edge);
    --admin-accent: var(--color-success);
    /* One number governs both the card's inner padding and the heading indent, so the
       page's left reading edge cannot drift apart again. */
    --admin-card-pad: 18px;

    display: flex;
    align-items: flex-start;
    min-height: 100vh;
}

/* ---------- sidebar ---------------------------------------------------------------- */

.admin-nav {
    position: sticky;
    top: 0;
    display: flex;
    flex: 0 0 var(--admin-nav-w);
    flex-direction: column;
    width: var(--admin-nav-w);
    height: 100vh;
    padding: 20px 14px;
    background: var(--admin-nav-bg);
    color: var(--admin-nav-fg);
}

/*
 * The signed-in account, sitting where the logo used to be. It IS the sidebar header:
 * an operator does not need the product's own name repeated on every admin page, they
 * need to know which account they are acting as.
 */
.admin-nav__account {
    display: flex;
    gap: 10px;
    align-items: center;
    margin-bottom: 20px;
    padding: 8px;
    border-radius: 10px;
    color: inherit;
    text-decoration: none;
    transition: background .12s ease;
}

/* Email and role stack on one left edge. min-width:0 lets the column shrink so a long
   email clips instead of widening the sidebar. */
.admin-nav__account-meta {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.admin-nav__account:hover {
    background: var(--admin-nav-active);
}

.admin-nav__avatar {
    display: grid;
    flex: 0 0 34px;
    height: 34px;
    border-radius: 10px;
    background: linear-gradient(140deg, var(--color-success), var(--color-info-bright));
    color: var(--color-admin-avatar-ink);
    font-size: 14px;
    font-weight: 700;
    place-items: center;
}

.admin-nav__account-email {
    overflow: hidden;
    color: var(--admin-nav-fg-strong);
    font-size: 13.5px;
    font-weight: 600;
    line-height: 1.2;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A plain coloured caption sitting flush under the email — same left edge, no pill or dot
   to push the text sideways. Colour alone carries the role. */
.admin-nav__account-role {
    display: block;
    max-width: 100%;
    overflow: hidden;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-overflow: ellipsis;
    text-transform: uppercase;
    white-space: nowrap;
}

.admin-nav__account-role--admin {
    color: var(--color-admin-role-ink);
}

.admin-nav__account-role--user {
    color: var(--color-slate-400);
}

.admin-nav__list {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    overflow-y: auto;
}

.admin-nav__item {
    position: relative;
    display: block;
    padding: 9px 12px;
    border-radius: 9px;
    color: var(--admin-nav-fg);
    font-size: 14px;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    transition: background .12s ease, color .12s ease;
}

.admin-nav__item:hover {
    background: var(--admin-nav-active);
    color: var(--admin-nav-fg-strong);
}

.admin-nav__item.is-active {
    background: var(--admin-nav-active);
    color: var(--admin-nav-fg-strong);
    font-weight: 600;
}

/* The marker is what makes "where am I" readable without reading. */
.admin-nav__item.is-active::before {
    position: absolute;
    top: 50%;
    left: 0;
    width: 3px;
    height: 18px;
    border-radius: 0 3px 3px 0;
    background: var(--admin-accent);
    content: "";
    transform: translateY(-50%);
}

/* ---------- build / release footer -------------------------------------------------- */

/*
 * Which release the panel runs. Two shapes, because the two states deserve very
 * different loudness: at rest it is one row the weight of a nav item (an id and a
 * refresh affordance, no words), and once a newer release is live the same slot
 * becomes an accent bar carrying the actions. State is in the shape, so the quiet
 * case - which is nearly always - costs a single row.
 *
 * Driven by templates/admin/_shell.html.twig, which flips .is-stale on the
 * `app:build-stale` event from _version_notify.html.twig.
 */
.admin-nav__build {
    margin-top: auto;
    padding: 10px 2px 4px;
    border-top: 1px solid var(--color-admin-edge);
}

/*
 * The template toggles parts of this widget with the `hidden` attribute, and the
 * rules below give several of them a `display` - which beats the UA's
 * `[hidden] { display: none }` and left an empty actions box eating the row's
 * width (the release id was truncated to "202609...") plus a stray refresh icon
 * inside the stale bar. Restate the guard for this subtree.
 */
.admin-nav__build [hidden] {
    display: none !important;
}

/*
 * The row gets a surface of its own. On the flat navy everything below the nav
 * read as the same plane, so the release state was invisible until you looked
 * for it: a slightly lifted panel with a hairline and a soft top highlight puts
 * it on its own layer without borrowing the active-item treatment.
 */
.admin-nav__build-row {
    display: flex;
    gap: 8px;
    align-items: center;
    padding: 7px 9px;
    border: 1px solid var(--color-admin-panel-line);
    border-radius: 10px;
    background: linear-gradient(180deg, var(--color-admin-panel-top) 0%, var(--color-admin-panel-bottom) 100%);
    box-shadow: inset 0 1px 0 rgba(148, 163, 184, .07);
    transition: border-color .12s ease, background .12s ease;
}

.admin-nav__build-row:hover {
    border-color: var(--color-admin-panel-line-hover);
    background: linear-gradient(180deg, var(--color-admin-panel-top-hover) 0%, var(--color-admin-panel-bottom-hover) 100%);
}

.admin-nav__build-dot {
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    /* Muted while current: the dot is a state light, not decoration. */
    background: var(--color-slate-650);
    box-shadow: 0 0 0 3px rgba(71, 85, 105, .18);
}

.admin-nav__build-age {
    flex: 1 1 auto;
    overflow: hidden;
    color: var(--color-admin-ink);
    /* An age is prose ("9 min ago"), not a hash: no monospace. Tabular digits
       keep it from twitching as the number changes under the minute timer. */
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    text-overflow: ellipsis;
    white-space: nowrap;
    cursor: default;
}

/* Only affordance in the quiet state: check now, rather than wait for the poll. */
.admin-nav__build-icon {
    display: grid;
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: 7px;
    background: transparent;
    color: var(--color-slate-450);
    font-size: 13px;
    line-height: 1;
    cursor: pointer;
    place-items: center;
    transition: color .12s ease, border-color .12s ease;
}

.admin-nav__build-row:hover .admin-nav__build-icon {
    border-color: var(--color-admin-icon-line-hover);
    color: var(--admin-nav-fg);
}

.admin-nav__build-icon:disabled {
    cursor: default;
    opacity: .5;
}

/* Inline inside the row, right of the age and left of the check button. */
.admin-nav__build-status:empty {
    display: none;
}

.admin-nav__build-status {
    flex: 0 1 auto;
    overflow: hidden;
    margin: 0;
    color: var(--color-admin-ink-soft);
    font-size: 11px;
    line-height: 1.4;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---- loud state: a newer release is live ---- */

.admin-nav__build.is-stale .admin-nav__build-row {
    flex-wrap: wrap;
    padding: 10px;
    /* Same object, loud: the seam on top is the accent, so the state change is
       legible even in a screenshot with no colour memory to compare against. */
    border-color: var(--color-admin-alert-line);
    background:
        linear-gradient(90deg, var(--color-success) 0%, var(--color-link-bright) 100%) top left / 100% 2px no-repeat,
        linear-gradient(180deg, var(--color-admin-alert-top) 0%, var(--color-admin-alert-bottom) 100%);
    box-shadow: inset 0 1px 0 rgba(167, 243, 208, .12);
}

.admin-nav__build.is-stale .admin-nav__build-dot {
    background: var(--admin-accent);
    box-shadow: 0 0 0 3px rgba(34, 197, 94, .2);
}

.admin-nav__build.is-stale .admin-nav__build-title {
    flex: 1 1 auto;
    color: var(--color-admin-alert-ink);
    font-size: 13px;
    font-weight: 700;
}

.admin-nav__build.is-stale .admin-nav__build-age {
    flex: 1 1 100%;
    color: var(--color-admin-alert-ink-soft);
}

.admin-nav__build-actions {
    display: flex;
    flex: 1 1 100%;
    gap: 6px;
}

.admin-nav__build-btn {
    padding: 5px 9px;
    border: 1px solid var(--color-admin-alert-line);
    border-radius: 7px;
    background: transparent;
    color: var(--color-admin-alert-ink);
    font-family: inherit;
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    transition: background .12s ease;
}

.admin-nav__build-btn:hover {
    background: rgba(34, 197, 94, .14);
}

.admin-nav__build-btn--go {
    border-color: transparent;
    background: var(--admin-accent);
    color: var(--color-admin-cta-ink);
    font-weight: 700;
}

.admin-nav__build-btn--go:hover {
    background: var(--color-admin-cta);
}

.admin-nav__logout {
    padding: 9px 12px;
    color: var(--color-slate-400);
    font-size: 14px;
    text-decoration: none;
}

.admin-nav__logout:hover {
    color: var(--color-danger-soft);
}

/* ---------- content ----------------------------------------------------------------- */

.admin-shell__content {
    flex: 1 1 auto;
    /* Without this a wide table stretches the flex item instead of scrolling inside it. */
    min-width: 0;
}

/*
 * The page container now lives inside the remaining space, so it must not centre itself
 * against the viewport - that would push every page off to the right by half the sidebar.
 */
/*
 * No width cap: this is an admin area and every card on it already opts into full width.
 * The wide tables are the whole point of these screens - capping the container was hiding
 * three columns behind the pinned Actions column on a display that had room for them.
 */
.admin-shell__content .page-container {
    max-width: none;
    margin: 20px 0 48px;
    padding: 0 28px;
}

/*
 * Everything on the page shares one left reading edge: a heading flush against the
 * container started to the left of the first word inside the card below it, which reads
 * as two competing margins.
 *
 * The indent must equal the card's inner padding, and that is NOT the 2rem from the base
 * stylesheet - admin cards carry .admin-card-spaced, which overrides it to 18px.
 */
.admin-shell__content .admin-card-spaced {
    padding: var(--admin-card-pad);
}

.admin-shell__content .page-container > h1,
.admin-shell__content .page-container > h2,
.admin-shell__content .page-container > p {
    padding-left: var(--admin-card-pad);
}

@media (max-width: 1280px) {
    .admin-shell__content .page-container {
        margin: 16px 0 32px;
        padding: 0 16px;
    }
}

/* ---------- narrow screens ----------------------------------------------------------- */

@media (max-width: 1280px) {
    .admin-shell {
        display: block;
    }

    /* The sidebar becomes a scrollable strip: still every section, no burger to press. */
    .admin-nav {
        position: static;
        flex-direction: row;
        gap: 6px;
        align-items: center;
        width: auto;
        height: auto;
        padding: 10px 12px;
        overflow-x: auto;
        overscroll-behavior-x: contain;
    }

    .admin-nav__account {
        margin-bottom: 0;
        padding: 4px;
    }

    .admin-nav__account-meta {
        display: none;
    }

    .admin-nav__list {
        flex-direction: row;
        overflow: visible;
    }

    .admin-nav__item.is-active::before {
        top: auto;
        bottom: -2px;
        left: 12px;
        width: calc(100% - 24px);
        height: 3px;
        border-radius: 3px 3px 0 0;
        transform: none;
    }

    /* In the horizontal strip the build block is one more inline item: the row
       keeps the id, the status line has nowhere to go. The stale bar stays - it
       is the one thing worth the space. */
    .admin-nav__build {
        margin-top: 0;
        padding: 0 4px;
        border-top: 0;
        border-left: 1px solid var(--color-admin-edge);
        white-space: nowrap;
    }

    .admin-nav__build-status {
        display: none;
    }

    .admin-nav__build.is-stale .admin-nav__build-row {
        flex-wrap: nowrap;
    }

    .admin-nav__build.is-stale .admin-nav__build-age,
    .admin-nav__build-actions {
        flex: 0 0 auto;
    }

    .admin-nav__logout {
        border-left: 1px solid var(--color-admin-edge);
        white-space: nowrap;
    }

}

/* ---------- error alerts panel (system logs) -------------------------------------- */
/*
 * One grid for the whole panel, and it is the point of the layout.
 *
 * The first version put helper text after each control, so it began at a different x on
 * every row and reading one row meant crossing the panel and coming back. Here every row
 * is label / control / note on the same three tracks: controls share a left edge, notes
 * share a left edge, and the eye scans two vertical lines instead of a zigzag.
 */
.alerts {
    --alerts-label: 176px;
    --alerts-control: 232px;
    --alerts-gutter: 24px;
}

/* What the form below cannot show: transport, last delivery, who edited it last. The
   values it CAN show are not repeated here - saying them twice made the panel look busy
   and told nobody anything. */
.alerts-status {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 28px;
    margin-bottom: 14px;
    padding: 12px 16px;
    border: 1px solid var(--color-border);
    border-left: 3px solid var(--color-brand);
    border-radius: 8px;
    background: var(--color-brand-surface);
}
.alerts-status--off {
    border-left-color: var(--color-border-strong);
    background: var(--color-surface);
}
.alerts-summary { font-weight: 600; font-size: 14.5px; color: var(--color-ink); }
.alerts-fact {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    color: var(--color-ink-muted);
}
.alerts-k {
    font-size: 10.5px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-ink-faint);
}
.alerts-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 9px;
    border-radius: 999px;
    border: 1px solid var(--color-border-strong);
    background: var(--color-surface);
    font-size: 11px;
    letter-spacing: 0.04em;
    color: var(--color-ink-soft);
    white-space: nowrap;
}
.alerts-pill--live { border-color: var(--color-brand); color: var(--color-brand-dark); }
.alerts-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }

/* A group is a band: its heading sits inside the same bordered block as its rows, so
   which rows a heading owns is a fact of the layout rather than an inference from
   spacing. A floating uppercase label above a hairline was the version that failed. */
.alerts-band {
    border: 1px solid var(--color-border);
    border-radius: 8px;
    overflow: hidden;
    margin-bottom: 12px;
}
.alerts-band__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 9px 16px;
    border-bottom: 1px solid var(--color-border);
    background: var(--color-surface-cool);
}
.alerts-band__head h3 {
    margin: 0;
    font-size: 13px;
    font-weight: 700;
    color: var(--color-ink);
}
.alerts-band__head span { font-size: 12px; color: var(--color-ink-faint); }
.alerts-band__body { padding: 16px; }

.alerts-rows {
    display: grid;
    grid-template-columns: var(--alerts-label) var(--alerts-control) 1fr;
    column-gap: var(--alerts-gutter);
    row-gap: 16px;
    align-items: center;
}
.alerts-rows .field-control { width: 100%; }
.alerts-label { font-size: 13.5px; font-weight: 600; color: var(--color-ink); }
.alerts-note { font-size: 12.5px; color: var(--color-ink-faint); }
/* A Slack channel id is eleven characters. A field sized for a sentence invites
   one, and a wrong id looks the same as a right one until the test button. */
.alerts-mono {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 12.5px;
}
/* Sized to what it holds. A Slack channel id is eleven characters, so a field the
   width of the band invited a sentence and left the value floating in whitespace. */
.alerts-rows .field-control.alerts-mono { width: 22ch; max-width: 100%; }

/* The three bands are one row on a wide screen. Stacked, each was a short block of
   three rows with two thirds of the window blank beside it, and the save button
   sat below the fold. */
.alerts-bands {
    /* Self-contained defaults so the band grid can be reused outside the .alerts root
       (the gateway settings use it too); .alerts overrides them where it wraps this. */
    --alerts-label: 176px;
    --alerts-control: 232px;
    --alerts-gutter: 24px;

    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 12px;
    align-items: start;
}
/* Inside a third of the window there is no room for label / control / note across:
   the rows stack, and the note keeps its place directly under what it explains. */
.alerts-bands .alerts-rows {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 6px;
}
/* Two exceptions to "sized to its value": a ping URL is a URL, and a list of patterns
   needs room to be read as a list rather than as one long line. */
.alerts-bands .field-control.alerts-wide,
.alerts-bands .field-control.alerts-area { width: 100%; }
.alerts-area { min-height: 62px; resize: vertical; line-height: 1.45; }

/* A number of alerts per minute is two digits. Stretched across the band it read as
   a text field someone forgot to size, and the unit sat a hand's width from it. */
.alerts-bands .alerts-suffixed { width: 13ch; }
/* The pickers keep the full width: their job is to show every option at once, and a
   segmented control narrower than its labels is a control that truncates them. */
.alerts-bands select.field-control,
.alerts-bands .alerts-seg { width: 100%; }
.alerts-bands .alerts-label { margin-top: 6px; }
.alerts-bands .alerts-label:first-child { margin-top: 0; }
.alerts-bands .alerts-band { margin-bottom: 0; }

@media (max-width: 1180px) {
    .alerts-bands { grid-template-columns: minmax(0, 1fr); }
    .alerts-bands .alerts-rows {
        grid-template-columns: var(--alerts-label) var(--alerts-control) 1fr;
        row-gap: 16px;
    }
    .alerts-bands .alerts-label { margin-top: 0; }
    .alerts-bands .alerts-band { margin-bottom: 12px; }
}

/* The id and the button that proves it works sit on one line: they are one thought,
   and the field is sized to its value, so the space beside it was going spare anyway. */
.alerts-channel { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.alerts-channel .field-control { flex: 0 0 auto; }

.alerts-tiny {
    font: inherit;
    font-size: 12px;
    padding: 5px 10px;
    border-radius: 8px;
    border: 1px solid var(--color-border-strong);
    background: transparent;
    color: var(--color-ink-soft);
    cursor: pointer;
}
.alerts-tiny:hover:not(:disabled) { border-color: var(--color-ink-charcoal); color: var(--color-ink); }
.alerts-tiny:disabled { opacity: 0.5; cursor: default; }
.alerts-result { font-size: 11.5px; color: var(--color-ink-faint); }
.alerts-result.is-ok { color: var(--color-brand-dark); }
.alerts-result.is-bad { color: var(--color-danger); }

.alerts-seg {
    display: inline-flex;
    width: 100%;
    border: 1px solid var(--color-border-strong);
    border-radius: 8px;
    overflow: hidden;
    background: var(--color-surface);
}
.alerts-seg button {
    flex: 1;
    appearance: none;
    border: 0;
    border-right: 1px solid var(--color-border);
    background: transparent;
    padding: 7px 12px;
    font: inherit;
    font-size: 13px;
    color: var(--color-ink-soft);
    cursor: pointer;
    white-space: nowrap;
}
.alerts-seg button:last-child { border-right: 0; }
.alerts-seg button[aria-pressed="true"] {
    background: var(--color-ink-charcoal);
    color: var(--color-surface);
    font-weight: 600;
}

/*
 * A warning that has to STAY on the screen.
 *
 * Not `.alert.alert-error`: that one is fixed to the top of the viewport and fades after
 * three seconds, which is right for "saved" and wrong for "this setting is spending
 * money right now" - it covered the page heading and then vanished.
 */
.alerts-cost {
    margin-top: 12px;
    padding: 10px 12px;
    border: 1px solid var(--color-warning-light);
    border-radius: 8px;
    background: var(--color-warning-surface);
    color: var(--color-warning-ink);
    font-size: 13px;
    line-height: 1.45;
}

/* A unit belongs inside its field. As text to the right of the input it was the thing
   that made the panel's right side ragged. */
.alerts-suffixed { position: relative; display: block; width: 100%; }
.alerts-suffixed .field-control { padding-right: 62px; font-variant-numeric: tabular-nums; }
.alerts-unit {
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 11.5px;
    color: var(--color-ink-faint);
    pointer-events: none;
}

/* The bar holds the action and nothing else: the form's state IS the button, whose label
   counts what is pending. A "no changes" chip beside it was a second object to read for
   information the button already carried. */
.alerts-actionbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px 20px;
    margin: 14px calc(-1 * var(--admin-card-pad)) calc(-1 * var(--admin-card-pad));
    padding: 13px var(--admin-card-pad);
    border-top: 1px solid var(--color-border);
    background: var(--color-surface-cool);
}
.alerts-effect { font-size: 12.5px; color: var(--color-ink-faint); }

@media (max-width: 720px) {
    .alerts-rows { grid-template-columns: 1fr; row-gap: 12px; }
}

/* Plans & pricing editor (Payment manager -> Pricing). It borrows the alerts band -
   a bordered block with its heading and its on/off state in the head - and lays the
   plan rows on ONE set of aligned columns instead of relabelling every row. */
/* The cohort head reads top-down: the name, then one control row under it, so a long
   group name no longer fights the toggle and weight for the same line. */
.pricing-band__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 10px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--color-border);
    background: var(--color-surface-cool);
}
.pricing-band__head h3 {
    margin: 0;
    font-size: 13.5px;
    font-weight: 700;
    color: var(--color-ink);
}
/* Plan-type badges under the cohort name: the plan list at a glance, one colour per
   type so the same plan reads the same everywhere. In the pricing-status family, just a
   different hue per key. */
.plan-pill {
    font-size: 11px;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 999px;
    white-space: nowrap;
}
/* Default (card headings): name on its own line, the pills stacked under it. */
.cohort-label { display: block; }
.cohort-label__name { display: block; font-weight: 700; }
.cohort-label__types { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
/* On one line (table cells): the name, then the pills right after it. */
.cohort-label--inline { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.cohort-label--inline .cohort-label__name { display: inline; }
.cohort-label--inline .cohort-label__types { display: inline-flex; margin-top: 0; }

.plan-pill--monthly { color: var(--color-plan-monthly-ink); background: var(--color-plan-monthly-surface); }
.plan-pill--yearly  { color: var(--color-plan-yearly-ink);  background: var(--color-plan-yearly-surface); }
.plan-pill--weekly  { color: var(--color-plan-weekly-ink);  background: var(--color-plan-weekly-surface); }

/* The traffic rows carry inputs, so they stood ~11px taller than the revenue tables that
   show the same cohorts as plain text. Tighten the cell padding and let the controls sit
   at the row's text height so both tabs read at the same density. */
.traffic-table td { padding-block: 8px; vertical-align: middle; }
.traffic-table .field-control { padding-block: 5px; }
/* The cohort's assignment controls, as a strip across the foot of the band: the toggle
   on the left, the weight on the right, so the band reads plans-then-controls and the two
   controls are not crowded together in the middle. */
.pricing-cohort {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px 16px;
    margin: 14px -16px -16px;
    padding: 11px 16px;
    border-top: 1px solid var(--color-border);
    background: var(--color-surface-cool);
    border-radius: 0 0 8px 8px;
}
/* The on/off state as a quiet pill: green when a cohort takes new users, grey when it
   is kept only for analytics - readable at a glance across four bands. */
.pricing-status {
    font-size: 11.5px;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 999px;
    white-space: nowrap;
}
.pricing-status--on {
    color: var(--color-success-ink);
    background: var(--color-brand-surface);
}
.pricing-status--off {
    color: var(--color-ink-faint);
    background: var(--color-surface-grey);
}
.pricing-toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    font-weight: 600;
    font-size: 13px;
}
.pricing-weight {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--color-ink-faint);
}
.pricing-weight > span { font-weight: 600; }
.pricing-weight .field-control { width: 72px; }
/* A disabled weight (cohort off) is muted so it does not look editable. */
.pricing-weight .field-control:disabled { opacity: 0.55; }

/* Plan | Amount | Trial days, aligned. The header spans read once at the top; every
   plan's inputs fall under them so a column of amounts is a column. */
.pricing-rows {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) 150px 170px;
    column-gap: var(--alerts-gutter, 16px);
    row-gap: 10px;
    align-items: center;
}
.pricing-rows .field-control { width: 100%; }
.pricing-colhead {
    font-size: 12px;
    font-weight: 600;
    color: var(--color-ink-faint);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
/* A reserved empty plan row: spans all three columns and stands the height of a field,
   so a cohort with fewer plans keeps the same band height as its neighbours. */
.pricing-spacer {
    grid-column: 1 / -1;
    height: 38px;
}

/* The plan name is shown, not edited - muted so it reads as a label the amount belongs to. */
.pricing-name {
    background: var(--color-surface-cool);
    color: var(--color-ink-faint);
    font-weight: 600;
}

.pricing-save {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: flex-end;
    justify-content: flex-end;
    margin-top: 4px;
}
.pricing-why { flex: 1 1 260px; }

/* The cohorts flow left-to-right, the same way the alert bands do (Sending / Channels
   / Volume / Checks), instead of one tall column with the save button below the fold.
   auto-fit means one wide cohort fills the row and four wrap to a tidy grid. */
.pricing-bands {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
    gap: 12px;
    align-items: start;
    margin-bottom: 12px;
}
.pricing-bands .pricing-band { margin-bottom: 0; }
/* Side by side each cohort is narrower, so the plan columns tighten: the name keeps
   what is left, amount and trial get just enough for their digits. */
.pricing-bands .pricing-rows {
    grid-template-columns: minmax(0, 1fr) 92px 92px;
    column-gap: 10px;
}

/* On a narrow screen the three columns cannot sit across: each plan stacks, and the
   column headers would float away from their values, so they hide and the muted plan
   name carries the row instead. */
@media (max-width: 720px) {
    .pricing-rows { grid-template-columns: minmax(0, 1fr); row-gap: 6px; }
    .pricing-colhead { display: none; }
    .pricing-rows .field-control { margin-bottom: 2px; }
}

/* The invoice modal: the facts on the left, the raw gateway JSON on the right; one
   column below 760px so it stays readable on a phone.

   The facts column is sized in PIXELS, not in a share of the modal. As `3fr 7fr` it came
   out ~290px wide inside the 1040px dialog, and a 150px label column left ~130px for the
   value: every date wrapped, and a gateway payment id broke into three lines mid-token.
   A support agent reads this before deciding on a refund, so the facts are the part that
   must not be crushed - the JSON pane wraps and scrolls happily with whatever is left. */
.invoice-grid {
    display: grid;
    grid-template-columns: minmax(300px, 360px) minmax(0, 1fr);
    gap: 24px;
    align-items: start;
}
@media (max-width: 760px) {
    .invoice-grid { grid-template-columns: minmax(0, 1fr); }
}

/* A container query, not a media query: the pane is narrow inside a WIDE dialog, which
   is exactly the case a viewport query cannot see. Below this the label moves above its
   value instead of fighting it for the line. */
.invoice-facts { container-type: inline-size; }

/* Money and its verdict first - that is what the row was opened to check. */
.invoice-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px 12px;
    padding-bottom: 14px;
    margin-bottom: 8px;
    border-bottom: 1px solid var(--color-border);
}
.invoice-head__amount { font-size: 26px; font-weight: 700; line-height: 1.15; }
.invoice-head__currency { font-size: 14px; font-weight: 600; color: var(--color-ink-soft); }
.invoice-head__meta { flex-basis: 100%; font-size: 13px; color: var(--color-ink-soft); }

.invoice-row {
    display: grid;
    grid-template-columns: minmax(0, 132px) minmax(0, 1fr);
    gap: 2px 12px;
    padding: 5px 0;
    align-items: baseline;
    text-align: left;
}
@container (max-width: 340px) {
    .invoice-row { grid-template-columns: minmax(0, 1fr); }
}
.invoice-row__label { margin: 0; }
.invoice-row__value { min-width: 0; overflow-wrap: break-word; }

/* A gateway id is one unbreakable token. Wrapped mid-string it is unreadable and cannot
   be double-clicked cleanly, so it stays on one line, clips, and the button is how it
   leaves the page - which is the only thing anyone does with an id: paste it into the
   provider's dashboard. The full value is on the element's title either way. */
.invoice-id { display: flex; align-items: center; gap: 8px; min-width: 0; }
.invoice-id__text {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12.5px;
}
.invoice-copy {
    flex: none;
    padding: 2px 8px;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    background: var(--color-surface);
    color: var(--color-ink-soft);
    font-size: 12px;
    line-height: 1.6;
    cursor: pointer;
}
.invoice-copy:hover { background: var(--color-surface-cool); }
.invoice-copy--done { color: var(--color-success-deep); border-color: var(--color-success-deep); }
