/* Recon Brief design system (phase 7c station 1).
   Source of truth: docs/planning/phase7c-polish/style-guide.md.
   Tokens only — components never use raw hex below the token block.
   Dark is the default theme; [data-theme="light"] overrides. */

/* ---- Fonts (self-hosted, OFL; latin subsets) --------------------- */

@font-face {
    font-family: "Nunito";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("/static/fonts/nunito-400.woff2") format("woff2");
}

@font-face {
    font-family: "Nunito";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("/static/fonts/nunito-600.woff2") format("woff2");
}

@font-face {
    font-family: "Nunito";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("/static/fonts/nunito-700.woff2") format("woff2");
}

@font-face {
    font-family: "Nunito";
    font-style: normal;
    font-weight: 800;
    font-display: swap;
    src: url("/static/fonts/nunito-800.woff2") format("woff2");
}

@font-face {
    font-family: "IBM Plex Mono";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("/static/fonts/ibm-plex-mono-400.woff2") format("woff2");
}

/* ---- Tokens ------------------------------------------------------ */

:root {
    /* surfaces */
    --ground: #16283f;
    --chrome: #0f1b2e;
    --surface: #1e3046;
    --surface-2: #263445;
    --inset: #162539;
    --border: #313e4f;
    --border-strong: #313e4f;
    --track: #404a59;

    /* text */
    --ink: #f5efe3;
    --ink-2: #9fb0c9;
    --ink-3: #929fb4;
    --placeholder: #838e9e;

    /* accent + status */
    --accent: #e89f3d;
    --accent-strong: #cf8a2c;
    --on-accent: #16283f;
    --ok: #49cf8a;
    --ok-strong: #27ae60;
    --warn: #e8c23d;
    --danger: #ec9b9b;
    --watermark-opacity: 0.05;

    /* tint strengths for status pills and alert/notice boxes */
    --pill-mix: 12%;
    --tint-bg: 12%;
    --tint-border: 35%;

    /* type */
    --font-display: "Nunito", system-ui, "Segoe UI", sans-serif;
    --font-body: "Nunito", system-ui, "Segoe UI", sans-serif;
    --font-mono: "IBM Plex Mono", ui-monospace, Consolas, monospace;

    --shadow: 0 1px 3px rgb(0 0 0 / 0.25);
    --scroll-shadow: rgb(0 0 0 / 0.38);
    color-scheme: dark;
}

:root[data-theme="light"] {
    --ground: #f4f1ea;
    --chrome: #1d2a3e;
    --surface: #ffffff;
    --surface-2: #e6dfd0;
    --inset: #faf8f4;
    --border: #cdc5b3;
    --border-strong: #8b7c57;
    --track: #d0cabb;

    --ink: #1d2a3e;
    --ink-2: #43536b;
    --ink-3: #586378;
    --placeholder: #a0a8b6;

    --accent: #724809;
    --accent-strong: #573708;
    --on-accent: #ffffff;
    --ok: #145c33;
    --ok-strong: #0f4b28;
    --warn: #644f08;
    --danger: #962424;
    --watermark-opacity: 0.025;

    --pill-mix: 18%;
    --tint-bg: 22%;
    --tint-border: 55%;

    --shadow: 0 1px 3px rgb(29 42 62 / 0.1);
    --scroll-shadow: rgb(29 42 62 / 0.22);
    color-scheme: light;
}

/* ---- Base -------------------------------------------------------- */

* { box-sizing: border-box; }

/* Sticky footer (#209): the page is a column that is at least as tall
   as the viewport, with <main> taking the slack — so the footer sits on
   the bottom edge of a short page (/contact) instead of floating in the
   middle of it, and simply follows the content on a long one. The
   chrome rows keep their natural height (`flex: none`) so a tall page
   can never squeeze them. */
body {
    margin: 0;
    font-family: var(--font-body);
    background: var(--ground);
    color: var(--ink);
    line-height: 1.5;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

body > .topbar,
body > .subnav,
body > .site-footer { flex: none; }

/* `width: 100%` is load-bearing, not decoration: `.content` centres
   itself with `margin: 2rem auto`, and auto inline margins on a flex
   item suppress the stretch that a block child gets for free — the used
   width collapses to fit-content, which let a wide table push the
   document sideways at 390px and left content-light pages short of
   their 960 max at 1440. An explicit 100% restores block sizing (the
   global `box-sizing: border-box` keeps the gutter inside the max). */
body > .content {
    flex: 1 0 auto;
    width: 100%;
}

h1, h2, h3 {
    font-family: var(--font-display);
    font-weight: 700;
    line-height: 1.2;
}

h1 { font-size: 1.5rem; }

a { color: var(--accent); }

/* :where() keeps the original a:hover specificity, so anchors styled as buttons
   (.btn and its variants) keep their own text colour on hover. */
a:hover:where(:not(.btn)) { color: var(--accent-strong); }

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.muted { color: var(--ink-3); }

.mono {
    font-family: var(--font-mono);
    font-size: 0.8125rem;
}

/* ---- Top bar + navigation ---------------------------------------- */

.topbar {
    display: flex;
    align-items: center;
    gap: 2rem;
    padding: 0.55rem 1.5rem;
    background: var(--chrome);
}

.brand {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    color: #f5efe3;
    text-decoration: none;
    flex: 0 0 auto;
}

.brand__logo {
    width: 34px;
    height: 34px;
    flex: 0 0 auto;
    display: block;
}

.brand__name {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 800;
    letter-spacing: 0.02em;
}

.nav {
    display: flex;
    align-items: center;
    gap: 1.5rem;
}

.nav-link {
    color: #9fb0c9;
    text-decoration: none;
    font-size: 0.95rem;
    font-weight: 600;
    padding: 0.35rem 0;
    border-bottom: 2px solid transparent;
}

.nav-link:hover { color: #f5efe3; }

.nav-link.is-active {
    color: #f5efe3;
    border-bottom-color: var(--accent);
}

/* The Organization tab wears the firm's own name on a wide bar and the
   generic word on a narrow one (#289 N3). `display: none` is the point:
   a visually-hidden span would stay in the accessible name and the tab
   would read as both labels at once. The wide name is ellipsed rather
   than allowed to push the bar around — the link's `title` carries it
   in full. */
.nav-link__narrow { display: none; }

.nav-link__wide {
    display: inline-block;
    vertical-align: bottom;
    max-width: 12rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.topbar__side {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 1rem;
}

/* The permanent "New deposition" button (#289 N2). It sits ahead of
   the user menu on every page a seat with can_process can start a run
   from; the narrow rule further down swaps the words for a "+". */
.topbar-action {
    flex: 0 0 auto;
    white-space: nowrap;
}

.topbar-action__short { display: none; }

/* The user menu is a CSS-only <details> dropdown. */
.user-menu { position: relative; }

.user-menu > summary {
    list-style: none;
    cursor: pointer;
    color: #f5efe3;
    font-family: var(--font-mono);
    font-size: 0.85rem;
    padding: 0.3rem 0.6rem;
    border: 1px solid #313e4f;
    border-radius: 999px;
    /* A long display name is ellipsed rather than wrapped: the pill
       stays a one-line pill and never widens the header (#107). */
    max-width: 10rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.user-menu > summary::-webkit-details-marker { display: none; }

.user-menu > summary::after { content: " ▾"; color: #6e7e9a; }

/* The floating half of a CSS-only <details> menu — shared by the user
   menu and the usage page's org picker (#74). The opener sets its own
   `position: relative`; each user pins its own edge and width. */
.popover-panel {
    position: absolute;
    top: calc(100% + 0.4rem);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: var(--shadow);
    padding: 0.4rem;
    z-index: 20;
    display: flex;
    flex-direction: column;
}

.user-menu__panel {
    right: 0;
    min-width: 11rem;
}

.user-menu__item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.45rem 0.7rem;
    border: none;
    background: none;
    border-radius: 7px;
    color: var(--ink);
    text-decoration: none;
    font-size: 0.95rem;
    font-family: var(--font-body);
    /* Buttons don't inherit line-height; without this the Sign out
       button renders shorter than the links beside it (#104). */
    line-height: inherit;
    cursor: pointer;
}

.user-menu__item:hover {
    background: var(--surface-2);
    color: var(--ink);
}

.logout-form { margin: 0; }

.subnav {
    display: flex;
    gap: 0.3rem;
    padding: 0.35rem 1.5rem;
    background: var(--chrome);
    border-top: 1px solid #1c2c44;
}

.subnav__link {
    color: #9fb0c9;
    text-decoration: none;
    font-size: 0.88rem;
    font-weight: 600;
    padding: 0.25rem 0.7rem;
    border-radius: 999px;
}

.subnav__link:hover { color: #f5efe3; }

.subnav__link.is-active {
    color: #f5efe3;
    background: #223349;
}

/* The hairline between sub-nav groups (#289 N9) — decorative, and the
   only thing separating operations from people from money. */
.subnav__sep {
    align-self: center;
    width: 1px;
    height: 1.1em;
    margin: 0 0.45rem;
    background: #31425c;
}

/* Narrow widths: the header collapses onto two lines inside the same
   dark bar — brand + user menu on the first, the primary nav on the
   second — instead of forcing a ~650px minimum document width (#107).
   CSS only; no hamburger, no JS. */
@media (max-width: 860px) {
    .topbar {
        flex-wrap: wrap;
        gap: 0.5rem 1rem;
        padding: 0.55rem 1rem;
    }

    .nav {
        order: 3;
        flex-basis: 100%;
        gap: 1rem;
        overflow-x: auto;
    }

    .nav-link { flex: 0 0 auto; }

    /* Below this width the bar has already wrapped onto two lines: the
       firm's name gives way to the word (#289 N3). */
    .nav-link__wide { display: none; }

    .nav-link__narrow { display: inline; }

    .subnav {
        flex-wrap: wrap;
        row-gap: 0.2rem;
        padding: 0.35rem 1rem;
    }

    .subnav__link { flex: 0 0 auto; }
}

/* Phone: the primary nav holds five links now (the Deliverables page
   joined Cases and Reports for its trial), and at 390px the 1rem gap
   above pushed `Billing` off the end of the scroll strip on EVERY
   page. A tighter gap fits all five with room to spare. Deliberately
   here rather than in the Deliverables section: it protects the whole
   app, so deleting that section at cutover must not revert it. */
@media (max-width: 600px) {
    .nav { gap: 0.6rem; }

    /* Phone: the action button keeps its place in the bar but gives up
       its words (#289 N2). The accessible name lives on the link's
       aria-label, so it reads "New deposition" either way. */
    .topbar-action__full { display: none; }

    .topbar-action__short {
        display: inline;
        font-size: 1.1rem;
        line-height: 1;
    }

    .topbar-action { padding-inline: 0.7rem; }
}

/* The account page's three groups (#289 N8) — a heading over each run
   of cards, so the page reads as Profile / Preferences / Security
   rather than six cards of equal weight. */
.account-group + .account-group { margin-top: 2rem; }

.account-group > h2 { margin-bottom: 0.75rem; }

/* ---- Page container ---------------------------------------------- */

/* The column uses more of a wide monitor than it used to (#268): the
   old fixed 960/1160px left ~40% of a 1920px viewport blank while data
   tables scrolled sideways inside it. The vw half of each `min()` keeps
   a breathing margin on huge screens and leaves narrow screens exactly
   as they were (below ~1360px the px value never wins). */
.content {
    max-width: min(1280px, 94vw);
    margin: 2rem auto;
    padding: 0 1.5rem;
    position: relative;
}

.content--wide { max-width: min(1480px, 96vw); }

/* Logo watermark behind the page ground (dashboard). */
.watermarked::before {
    content: "";
    position: fixed;
    inset: 0;
    background: url("/static/logo.png") no-repeat right -8rem top 4rem;
    background-size: 42rem;
    opacity: var(--watermark-opacity);
    pointer-events: none;
    z-index: -1;
}

/* ---- Site footer (#209) -------------------------------------------
   One quiet line under every page: the copyright mark and the five
   policy links, dot-separated as the signed-off design shows, wrapping
   onto as many lines as a narrow screen needs. Plain inline flow, not
   flex: the separators then travel with the item they follow (each is
   glued to it by a non-breaking space in the partial), so a wrapped
   line never opens with a stray dot.

   Deliberately muted rather than accent-amber — the footer must never
   pull the eye away from the content above it — so the links carry an
   underline to say they are links, and brighten on hover. */

.site-footer {
    max-width: min(1280px, 94vw);
    width: 100%;
    box-sizing: border-box;
    margin: 2.5rem auto 1.5rem;
    padding: 1rem 1.5rem 0;
    border-top: 1px solid var(--border);
    color: var(--ink-3);
    font-size: 0.8125rem;
    text-align: center;
}

/* Wide pages (`content--wide`) carry the wide footer, so its rule spans
   the same column the content does — base.html sets the flag. */
.site-footer--wide { max-width: min(1480px, 96vw); }

.site-footer__nav { display: inline; }

/* Each item is atomic: without this, "Sub-processors" broke at its own
   hyphen and the phone-width footer read "Sub- / processors". */
.site-footer__mark,
.site-footer a { white-space: nowrap; }

.site-footer a {
    color: var(--ink-3);
    text-decoration: underline;
}

.site-footer a:hover { color: var(--ink); }

/* ---- Legal documents (#209) ---------------------------------------
   The prose quotes bare URLs, and a URL is one unbreakable token: at
   phone width it is wider than its own paragraph and shoves the whole
   document sideways (the #107 bar). `anywhere` — not `break-word` —
   because only `anywhere` shrinks the paragraph's min-content width,
   which is what the overflow is measured against. Links only; the
   sentences around them keep breaking on spaces as prose should. */

.legal-doc a { overflow-wrap: anywhere; }

/* ---- Contact page ------------------------------------------------- */

.contact-card {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.4rem 1.2rem;
    margin: 1.2rem 0 0;
}

.contact-card dt {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-2);
    align-self: center;
}

.contact-card dd { margin: 0; }

/* ---- Overflow ----------------------------------------------------
   The `min-width: auto` trap: a flex or grid item defaults to
   `min-width: auto`, i.e. it refuses to shrink below its widest
   unbreakable token. One 60-char run name (a manifest-less run falls
   back to its run name) therefore shoves its row, its card, and the
   page past the viewport. The fix is an explicit `min-width: 0` on
   every flex/grid child that holds text, plus a way out for the token
   itself: an ellipsis where the full string is reachable another way
   (an expandable row), wrapping everywhere else (#62). */

.truncate {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.wrap-anywhere {
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Containers never grow past their parent (grid items default to
   `min-width: auto` too). */
.card,
.dash-grid > * { min-width: 0; }

/* Expandable rows (/home, /reports, /jobs): the case label is the long
   one. Collapsed it truncates so the row stays one tidy line; opening
   the row shows the whole label, wrapped. */
.job-row__summary > * { min-width: 0; }

/* The case label is the long one; the timestamp joins it because a run
   whose name is not a parseable timestamp falls back to the raw
   65-char run name (#107). */
.job-row__case,
.job-row__ts {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.job-row[open] > .job-row__summary .job-row__case,
.job-row[open] > .job-row__summary .job-row__ts {
    overflow: visible;
    white-space: normal;
    overflow-wrap: anywhere;
}

/* A <select> sizes itself to its widest <option>, so one long org name
   drags the page sideways. It stops at its container instead (#107). */
select {
    min-width: 0;
    max-width: 100%;
}

/* The dashboard hero greets the user by display name, so its heading
   carries a user-supplied token (#107). */
.hero > * { min-width: 0; }

/* Two more flex rows that render user- or pipeline-supplied strings:
   the queue row's progress note and the org line on a staff user's
   page (a long org name) (#107). */
.queue-row__progress > * { min-width: 0; }

/* Everything below a row wraps — nothing here is worth an ellipsis,
   because there is no second place to read it. */
.job-row__body,
.job-facts dd,
.report-card__files li,
.queue-row__case,
.case-card,
.case-card__title,
.hero__title,
.hero__lede,
.queue-row__progress,
.form-card p,
.page-head h1,
.page-lede { overflow-wrap: anywhere; }

/* Bare <details> summaries that render user-supplied text. Tag-qualified
   so these win over the component rules further down the file, which set
   only cursor/padding but sit later. */
details.invoice-tree__user > summary,
details.invoice-tree__case > summary,
.permissions-summary { overflow-wrap: anywhere; }

.case-card__title { min-width: 0; }

/* Log lists: 32-char job ids and storage-key targets sit in the 1fr
   track and used to cross the row border (#100). */
.log-row__summary > *,
.log-list__head > * { min-width: 0; overflow-wrap: anywhere; }

/* The fixed rem tracks are wider than a narrow viewport, so below
   ~950px the grid stops being a grid: rows wrap and the page stops
   scrolling sideways. The chevron is a flex item there. */
@media (max-width: 960px) {
    .log-list .log-list__head { display: none; }

    .log-list .log-row__summary {
        display: flex;
        flex-wrap: wrap;
        gap: 0.4rem 0.8rem;
    }
}

/* A wide table scrolls inside its card instead of escaping it (#62), and
   is allowed to be wider than the card rather than crushing its columns
   into mid-token wraps (#126): max-content grows the table to its content,
   min-width fills the card when there is room to spare. Short tokens --
   dates, amounts, usernames, buttons -- stay on one line; the cells that
   hold prose opt back into wrapping with `cell--wrap`, capped so one long
   note cannot stretch the table without limit. */
/* A wide table scrolls sideways inside its card (#126); this is the hint
   that it does (#129). Two "cover" layers painted in the card surface
   scroll WITH the content (`background-attachment: local`) on top of two
   fixed shadow layers, so an edge shadow shows only while there is content
   past that edge and disappears when the table fits. Table cells carry no
   background of their own, so the covers stay visible through the rows. */
.table-scroll {
    overflow-x: auto;
    max-width: 100%;
    background-image:
        linear-gradient(to right, var(--surface) 60%, transparent),
        linear-gradient(to left, var(--surface) 60%, transparent),
        linear-gradient(to right, var(--scroll-shadow), transparent),
        linear-gradient(to left, var(--scroll-shadow), transparent);
    background-position: left center, right center, left center, right center;
    background-size: 2.5rem 100%, 2.5rem 100%, 0.9rem 100%, 0.9rem 100%;
    background-repeat: no-repeat;
    background-attachment: local, local, scroll, scroll;
    scrollbar-width: thin;
    scrollbar-color: var(--track) transparent;
}

/* Overlay scrollbars (touch, macOS) hide themselves until you drag, so the
   WebKit bar is pinned thin-but-present. */
.table-scroll::-webkit-scrollbar { height: 6px; }
.table-scroll::-webkit-scrollbar-track { background: transparent; }

.table-scroll::-webkit-scrollbar-thumb {
    background: var(--track);
    border-radius: 999px;
}

.table-scroll > .data-table {
    width: max-content;
    min-width: 100%;
}

.data-table th,
.data-table td { white-space: nowrap; }

/* Prose cells, plus the spanning cells that carry an empty-state sentence. */
.data-table td.cell--wrap,
.data-table td[colspan] {
    white-space: normal;
    overflow-wrap: anywhere;
    max-width: 22rem;
}

.data-table td .btn { white-space: nowrap; }

/* Action cells (#82): a bare link plus one <form> per POST action —
   each POST needs its own CSRF input, so the siblings are structural.
   `.inline-form` is a block-level flex container, so they stack unless
   something makes the cell a row. The flex wrapper is a <div> inside
   the cell rather than the <td> itself: a `display: flex` td stops
   being a table-cell, and its bottom border then tracks its own
   content instead of the row. Buttons already opt out of wrapping via
   `.data-table td .btn` above. */
.data-table td .cell--actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    align-items: center;
}

.data-table td .cell--actions > .inline-form { margin: 0; }

/* The invite link sits next to its Copy button (#114); the default input
   width truncated it mid-token. The table already scrolls sideways. */
.invite-link { min-width: 18rem; }

/* ---- Page header (interior pages) -------------------------------- */

.page-head { margin-bottom: 1.5rem; }

.page-head h1 {
    font-size: 1.8rem;
    font-weight: 800;
    margin: 0 0 0.35rem;
}

.page-lede {
    color: var(--ink-2);
    max-width: 40rem;
    margin: 0;
}

/* ---- Cards ------------------------------------------------------- */

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 1.5rem;
    box-shadow: var(--shadow);
}

.card-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1rem;
}

.card-label {
    color: var(--ink-2);
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.card-link {
    font-size: 0.9rem;
    font-weight: 600;
    text-decoration: none;
}

.card-foot {
    margin-top: 0.8rem;
    display: flex;
    justify-content: flex-end;
}

/* Long legal prose inside a card (#147: the ToS gate). The text scrolls
   in its own box so the accept button below it is always on screen;
   both themes inherit the card's surface and border tokens. */
.terms-scroll {
    max-height: 26rem;
    overflow-y: auto;
    padding: 0.2rem 1rem;
    margin: 1rem 0;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface-2);
    scrollbar-width: thin;
    scrollbar-color: var(--track) transparent;
}

/* ---- Dashboard --------------------------------------------------- */

.hero {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1.5rem;
    flex-wrap: wrap;
    margin-bottom: 1.5rem;
}

.hero__title {
    font-size: 2.5rem;
    font-weight: 800;
    margin: 0 0 0.4rem;
}

.hero__lede {
    color: var(--ink-2);
    max-width: 34rem;
    margin: 0;
}

.dash-grid {
    display: grid;
    grid-template-columns: 5fr 6fr;
    gap: 1.5rem;
    margin-top: 1.5rem;
    align-items: start;
}

@media (max-width: 860px) {
    .dash-grid { grid-template-columns: 1fr; }
    .hero__title { font-size: 1.8rem; }
}

.queue-row {
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface-2);
    padding: 0.7rem 0.9rem;
    margin: 0.5rem 0;
}

.queue-row__main {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    flex-wrap: wrap;
}

.queue-row__case {
    flex: 1 1 8rem;
    min-width: 0;
    font-weight: 700;
}

.queue-row__meta {
    color: var(--ink-3);
    white-space: nowrap;
}

.queue-row__progress {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    margin-top: 0.55rem;
}

/* ---- Stat cards -------------------------------------------------- */

.stat-cards {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    margin: 1.5rem 0;
}

/* The scope line sits on its own row above the tiles (#63). */
.stat-cards__scope {
    flex: 1 0 100%;
    margin: 0;
    font-size: 0.9rem;
}

.stat-cards__scope a { margin-left: 0.5rem; }

/* A swap target only (#276) — the tiles stay direct flex children. */
#dash-tiles { display: contents; }

/* The basis is the floor a money value needs (#268): at 10rem a tile
   could get narrower than "$12,012.00" and the value broke mid-number
   ("$12,012." / "00"). 13rem measured as a near-exact floor for that
   value -- it still poked ~2px past the card edge around a 1024px
   viewport -- so 14rem, which clears it with room to spare. The row
   wraps a tile onto a second line before a tile gets that narrow, and
   the value itself never wraps at all. */
.stat-card {
    flex: 1 1 14rem;
    min-width: 0;
    padding: 1.1rem 1.3rem;
    text-align: left;
}

.stat-card__value {
    font-family: var(--font-display);
    font-size: 2.25rem;
    font-weight: 800;
    line-height: 1.15;
    white-space: nowrap;
}

.stat-card__label {
    color: var(--ink-2);
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin-bottom: 0.3rem;
}

.stat-card__note {
    font-size: 0.8rem;
    margin-top: 0.3rem;
}

/* ---- Pills + progress -------------------------------------------- */

.status-pill {
    display: inline-block;
    border-radius: 999px;
    padding: 0.12rem 0.65rem;
    font-size: 0.8rem;
    font-weight: 700;
    white-space: nowrap;
}

.status-pill--pending {
    background: color-mix(in srgb, var(--ink-2) var(--pill-mix), transparent);
    color: var(--ink-2);
}

.status-pill--processing {
    background: color-mix(in srgb, var(--accent) var(--pill-mix), transparent);
    color: var(--accent);
}

.status-pill--completed {
    background: color-mix(in srgb, var(--ok) var(--pill-mix), transparent);
    color: var(--ok);
}

.status-pill--failed {
    background: color-mix(in srgb, var(--danger) var(--pill-mix), transparent);
    color: var(--danger);
}

.status-pill--cancelled {
    background: color-mix(in srgb, var(--warn) var(--pill-mix), transparent);
    color: var(--warn);
}

.status-pill--ok {
    background: color-mix(in srgb, var(--ok) var(--pill-mix), transparent);
    color: var(--ok);
}

.status-pill--calm {
    background: color-mix(in srgb, var(--ink-2) var(--pill-mix), transparent);
    color: var(--ink-2);
}

.status-pill--warn {
    background: color-mix(in srgb, var(--warn) var(--pill-mix), transparent);
    color: var(--warn);
}

.progress {
    flex: 1;
    height: 7px;
    border-radius: 999px;
    background: var(--track);
    overflow: hidden;
    position: relative;
}

.progress--indeterminate::after {
    content: "";
    position: absolute;
    inset: 0;
    width: 35%;
    border-radius: 999px;
    background: var(--accent-strong);
    animation: progress-slide 1.6s ease-in-out infinite;
}

/* A deposition's real checkpoint fraction (#52), handed in as
   --progress by the row. No animation loop — the 5 s poll re-renders
   the bar, and the transition carries it to the new width. */
.progress--determinate::after {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: var(--progress, 0%);
    border-radius: 999px;
    background: var(--accent-strong);
    transition: width 0.4s ease;
}

@keyframes progress-slide {
    0% { transform: translateX(-100%); }
    100% { transform: translateX(300%); }
}

/* ---- Buttons ----------------------------------------------------- */

.btn {
    padding: 0.55rem 1.1rem;
    border: 1px solid var(--border-strong);
    border-radius: 10px;
    background: var(--surface-2);
    color: var(--ink);
    font-size: 0.95rem;
    font-family: var(--font-body);
    font-weight: 600;
    cursor: pointer;
    /* Anchors styled as buttons must not keep the UA's link underline. */
    text-decoration: none;
}

.btn:hover { background: color-mix(in srgb, var(--surface-2) 80%, var(--ink) 6%); }

.btn--primary {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
    border-radius: 999px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 800;
    font-size: 0.88rem;
    padding: 0.65rem 1.4rem;
}

.btn--primary:hover { background: var(--accent-strong); border-color: var(--accent-strong); }

.btn--danger {
    background: color-mix(in srgb, var(--danger) 14%, transparent);
    border-color: color-mix(in srgb, var(--danger) 40%, transparent);
    color: var(--danger);
}

.btn--danger:hover { background: color-mix(in srgb, var(--danger) 22%, transparent); }

.btn--ghost { background: none; }

.btn--small {
    padding: 0.35rem 0.7rem;
    font-size: 0.88rem;
}

.btn--full { width: 100%; }

/* The acceptance gate's single action: the primary pill, sized up to
   the login card's submit so it reads as the obvious next click at the
   foot of a long document. `max-width` lets the label wrap rather than
   push the card sideways on a phone. */
.tos-accept {
    margin-top: 1.2rem;
    font-size: 0.95rem;
    padding: 0.75rem 1.8rem;
    max-width: 100%;
}

/* A disabled button must READ as disabled, not as a faded copy of the
   live one (#70): an inert flat fill, muted label, soft edge, and no
   hover response — opacity alone left an unavailable action looking
   like an offered one. The `--primary` selectors drop the accent fill
   so an unavailable action never wears the call-to-action colour. The
   sign-in card's bare <button>s join the list for #208: submit-once
   disables them while the POST is in flight, and that must read. */
.btn:disabled,
.btn:disabled:hover,
.btn--primary:disabled,
.btn--primary:disabled:hover,
.login-card button:disabled,
.login-card button:disabled:hover {
    background: var(--surface-2);
    border-color: var(--border);
    color: var(--ink-3);
    box-shadow: none;
    opacity: 1;
    cursor: not-allowed;
}

.linklike {
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    font-family: inherit;
    font-size: inherit;
}

/* ---- Forms ------------------------------------------------------- */

input[type="text"],
input[type="search"],
input[type="password"],
input[type="email"],
input[type="date"],
input[type="month"],
input[type="number"],
select,
textarea {
    background: var(--inset);
    color: var(--ink);
    border: 1px solid var(--border-strong);
    border-radius: 10px;
    padding: 0.5rem 0.7rem;
    font-size: 1rem;
    font-family: var(--font-body);
}

::placeholder { color: var(--placeholder); }

.form__row {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
}

.form__field {
    flex: 1;
    min-width: 14rem;
    display: flex;
    flex-direction: column;
    margin-bottom: 0.8rem;
}

.form__field label {
    color: var(--ink-2);
    font-size: 0.9rem;
    margin-bottom: 0.25rem;
}

.case-form__confirm {
    display: flex;
    gap: 0.6rem;
    align-items: flex-start;
    margin: 0.8rem 0;
}

.stacked-form {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    max-width: 26rem;
}

.stacked-form label {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    font-size: 0.92rem;
    color: var(--ink-2);
}

.checkbox-label {
    flex-direction: row !important;
    align-items: center;
    gap: 0.4rem !important;
}

.inline-form {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    align-items: center;
    margin: 0.4rem 0;
}

/* ---- Login ------------------------------------------------------- */

.login-card {
    max-width: 380px;
    margin: 3rem auto;
}

.login-card h1 {
    margin-top: 0;
    font-size: 1.4rem;
}

.login-card form {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.login-card label {
    font-size: 0.9rem;
    color: var(--ink-2);
    margin-top: 0.6rem;
}

.login-card button {
    margin-top: 1.2rem;
    padding: 0.6rem;
    border: none;
    border-radius: 999px;
    background: var(--accent);
    color: var(--on-accent);
    font-size: 0.95rem;
    font-family: var(--font-body);
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    cursor: pointer;
}

.login-card button:hover { background: var(--accent-strong); }

/* ---- Alerts + notices -------------------------------------------- */

.alert,
.notice {
    border-radius: 10px;
    padding: 0.6rem 0.8rem;
    margin: 0.6rem 0;
    font-size: 0.92rem;
}

.notice {
    background: color-mix(in srgb, var(--warn) var(--tint-bg), transparent);
    border: 1px solid color-mix(in srgb, var(--warn) var(--tint-border), transparent);
}

.alert--success {
    background: color-mix(in srgb, var(--ok) var(--tint-bg), transparent);
    border: 1px solid color-mix(in srgb, var(--ok) var(--tint-border), transparent);
}

.alert--info {
    background: color-mix(in srgb, var(--ink-2) var(--tint-bg), transparent);
    border: 1px solid color-mix(in srgb, var(--ink-2) var(--tint-border), transparent);
}

.alert--warning {
    background: color-mix(in srgb, var(--warn) var(--tint-bg), transparent);
    border: 1px solid color-mix(in srgb, var(--warn) var(--tint-border), transparent);
}

.alert--danger {
    background: color-mix(in srgb, var(--danger) var(--tint-bg), transparent);
    border: 1px solid color-mix(in srgb, var(--danger) var(--tint-border), transparent);
}

/* Warnings carry a left accent so the box reads as a warning in both themes
   (light's --warn is deep enough that its tint alone looks like neutral tan). */
.notice,
.alert--warning {
    border-left: 4px solid var(--warn);
}

.form-error {
    background: color-mix(in srgb, var(--danger) var(--tint-bg), transparent);
    border: 1px solid color-mix(in srgb, var(--danger) var(--tint-border), transparent);
    border-radius: 10px;
    padding: 0.3rem 0.5rem;
    font-size: 0.88rem;
    margin-top: 0.4rem;
    max-width: 28rem;
}

/* ---- Tables ------------------------------------------------------ */

.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.95rem;
}

.data-table th,
.data-table td {
    text-align: left;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border);
}

.data-table th {
    color: var(--ink-2);
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.data-table .num { text-align: right; }

.row--flagged { background: color-mix(in srgb, var(--warn) 10%, transparent); }

/* "Here is the row you just made" (#311) — a token tint, so it reads in
   both themes. */
.row--highlight { background: color-mix(in srgb, var(--accent) 12%, transparent); }

/* ---- Job rows + report cards ------------------------------------- */

.job-row {
    border: 1px solid var(--border);
    border-radius: 10px;
    margin: 0.5rem 0;
    background: var(--surface-2);
}

.job-row__summary {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    padding: 0.6rem 0.8rem;
    cursor: pointer;
    flex-wrap: wrap;
    list-style: none;
}

.job-row__summary::-webkit-details-marker { display: none; }

/* Any `display` other than list-item kills the native triangle, so the
   row draws its own (#67) — and rotates it to announce open/closed. */
.job-row__summary::before {
    content: "▸";
    color: var(--ink-3);
    display: inline-block;
    width: 1em;
    transition: transform 120ms;
}

.job-row[open] > .job-row__summary::before { transform: rotate(90deg); }

.job-row__ts {
    color: var(--ink-3);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    white-space: nowrap;
}

.job-row__case {
    flex: 1 1 10rem;
    min-width: 0;
    font-weight: 700;
}

.job-row__pages {
    color: var(--ink-3);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    white-space: nowrap;
}

.job-row__kind {
    color: var(--ink-3);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    white-space: nowrap;
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 0 0.5rem;
}

.job-row__user {
    color: var(--ink-3);
    font-size: 0.88rem;
}

.job-row__body {
    border-top: 1px solid var(--border);
    padding: 0.6rem 0.8rem;
}

.job-row__body dl {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.2rem 1rem;
    margin: 0 0 0.5rem;
}

.job-row__body dt { color: var(--ink-2); }

.job-row__body dd { margin: 0; }

.job-row__staff-meta {
    margin: 0.4rem 0;
    font-size: 0.9rem;
}

/* ---- Log lists (events / audit / job timeline) -------------------
   Same expand-below-the-row shape as the report card: the whole row is
   the <details>, the detail JSON opens underneath at full width (#100).
   Columns line up across rows because every row shares the page's
   --log-cols track list; the leading track is the chevron gutter. */

.log-row {
    border: 1px solid var(--border);
    border-radius: 10px;
    margin: 0.5rem 0;
    background: var(--surface-2);
}

.log-row__summary,
.log-list__head {
    display: grid;
    grid-template-columns: 1.2rem var(--log-cols);
    gap: 0.8rem;
    align-items: baseline;
}

.log-list__head {
    padding: 0.6rem 0.8rem 0.2rem;
    border: 1px solid transparent;
    color: var(--ink-2);
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.log-list__head::before { content: ""; }

/* No detail ⇒ no <details>, so nothing to promise: no pointer, but the
   chevron gutter stays reserved so the columns still line up. */
.log-row--flat .log-row__summary { cursor: default; }

.log-row--flat .log-row__summary::before { content: ""; }

/* The Event cell (#102/#101): the human label leads, the slug stays
   beside it (the filter box matches on the slug), and the row's own
   summary of its detail drops onto a second line beneath. Label and
   slug wrap inside the cell when they don't fit on one line. */
.log-row__event { font-weight: 600; }

.log-row__slug { font-size: 0.85rem; }

.log-row__summary-line {
    display: block;
    margin-top: 0.15rem;
    font-size: 0.85rem;
    overflow-wrap: anywhere;
}

/* `main.content` caps this list at ~860px however wide the viewport is,
   so the tracks share ~54rem, not a screenful: 1.2 chevron + 14
   timestamp + 13.5 event + 8 username + 3.2 of gaps leaves ~12rem for
   the Job column. Anything wider starves that column and the 32-char
   job id wraps one character per line (`overflow-wrap: anywhere`),
   which is what a fat Event track cost on the first pass. */
.log-list--events { --log-cols: 14rem 13.5rem 8rem 1fr; }

.log-list--timeline { --log-cols: 14rem 5rem 1fr; }

.log-list--audit { --log-cols: 14rem 13rem 9rem 1fr; }

.report-card__owner {
    color: var(--ink-3);
    font-size: 0.88rem;
    white-space: nowrap;
}

.report-card__files {
    margin: 0.3rem 0 0;
    padding-left: 1.2rem;
}

.report-card__files li { margin: 0.25rem 0; }

.job-tag {
    display: inline-block;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    color: var(--ink-2);
    padding: 0.05rem 0.55rem;
    font-size: 0.8rem;
    margin-right: 0.35rem;
    white-space: nowrap;
}

.job-facts {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.2rem 1rem;
    margin: 0.8rem 0;
}

.job-facts dt { color: var(--ink-2); }
.job-facts dd { margin: 0; }

/* ---- Upload flow ------------------------------------------------- */

.dropzone {
    border: 2px dashed color-mix(in srgb, var(--accent) 55%, transparent);
    border-radius: 12px;
    padding: 2rem;
    text-align: center;
    background: var(--surface-2);
    cursor: pointer;
}

.dropzone--dragover {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 8%, var(--surface-2));
}

.dropzone__label { cursor: pointer; display: block; }

.dropzone__title {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.05rem;
}

.dropzone__hint {
    color: var(--ink-3);
    font-size: 0.9rem;
    margin-top: 0.4rem;
}

.dropzone input[type="file"] { display: none; }

.upload-indicator { margin-top: 0.8rem; }

.price-box {
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 0.8rem 1rem;
    margin: 0.8rem 0;
    background: var(--surface-2);
    display: inline-block;
    min-width: 14rem;
}

.price-box__label {
    color: var(--ink-2);
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.price-box__value {
    font-family: var(--font-display);
    font-size: 1.6rem;
    font-weight: 800;
}

.price-box__detail {
    color: var(--ink-3);
    font-size: 0.9rem;
}

/* ---- Filter bar + worker banner ---------------------------------- */

.filter-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    margin: 0.8rem 0;
}

.filter-bar__search {
    flex: 1 1 14rem;
    min-width: 10rem;
}

.filter-bar__date {
    color: var(--ink-2);
    font-size: 0.9rem;
    display: flex;
    gap: 0.3rem;
    align-items: center;
}

.filter-bar__clear { font-size: 0.9rem; }

/* Organization multi-select (#74): a <details> checkbox list over the
   shared popover panel. Long org names wrap instead of widening the
   panel past a phone's viewport, and a long list scrolls. */
.filter-bar__picker { position: relative; }

.filter-bar__picker > summary { list-style: none; }

.filter-bar__picker > summary::-webkit-details-marker { display: none; }

.filter-bar__panel {
    left: 0;
    width: max-content;
    max-width: min(20rem, 90vw);
    max-height: 15rem;
    overflow-y: auto;
}

.filter-bar__option {
    display: flex;
    gap: 0.45rem;
    align-items: flex-start;
    padding: 0.3rem 0.5rem;
    font-size: 0.9rem;
    line-height: 1.35;
    color: var(--ink);
    overflow-wrap: anywhere;
    cursor: pointer;
}

.filter-bar__option input { margin-top: 0.2rem; }

/* On a phone the picker takes its own row, so the panel opens flush
   with the form and can never hang off the side of the viewport. */
@media (max-width: 480px) {
    .filter-bar__picker { flex: 1 1 100%; }

    .filter-bar__panel {
        width: 100%;
        max-width: 100%;
    }
}

.jobs-count { margin: 0.3rem 0; }

.worker-banner {
    border-radius: 10px;
    padding: 0.5rem 0.8rem;
    margin: 0.6rem 0;
    font-size: 0.92rem;
}

.worker-banner--calm {
    background: var(--surface-2);
    border: 1px solid var(--border);
    color: var(--ink-2);
}

.worker-banner--ok {
    background: color-mix(in srgb, var(--ok) var(--tint-bg), transparent);
    border: 1px solid color-mix(in srgb, var(--ok) var(--tint-border), transparent);
}

.worker-banner--warn {
    background: color-mix(in srgb, var(--warn) var(--tint-bg), transparent);
    border: 1px solid color-mix(in srgb, var(--warn) var(--tint-border), transparent);
}

/* ---- Cases ------------------------------------------------------- */

.cases-list {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    margin-top: 1rem;
}

.case-card {
    border: 1px solid var(--border);
    border-radius: 14px;
    background: var(--surface);
    padding: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    box-shadow: var(--shadow);
}

/* The head row wraps: a long case name takes the first line on its own
   and the meta (owner · Complete · count) drops to the next, instead of
   the meta spans being shrunk to a character per line by the title
   (#127). The title stays the only flexible item — `min-width: 0` plus
   #62's `overflow-wrap: anywhere` let it wrap inside the card; the meta
   spans are short unbreakable tokens that never shrink. */
.case-card__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.25rem 0.6rem;
}

.case-card__title { margin: 0; font-size: 1.05rem; }
.case-card__owner,
.case-card__count { white-space: nowrap; flex: 0 0 auto; }
.case-card__count { margin-left: auto; font-variant-numeric: tabular-nums; }
.case-card__deponents,
.case-card__window,
.case-card__expiry,
.case-card__hint { margin: 0; font-size: 0.95rem; }

.case-card__actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}

/* #65: the card expands to its own report rows. The summary is the
   card's quiet control — muted, and the same 0.95rem as the deponents
   line above it. The rows are .job-row blocks, which already wrap and
   carry a vertical margin; inside a card they only need to stay
   shrinkable, so a 390px viewport keeps them within its padding. */
.case-card__reports > summary {
    cursor: pointer;
    font-size: 0.95rem;
}

.case-card__reports .report-card {
    min-width: 0;
    margin: 0.5rem 0 0;
}

/* ---- Billing / staff surfaces ------------------------------------ */

/* The billing month control (#80). Two bare accent glyphs read as
   decoration, not navigation — and the month, the thing you are
   actually looking at, was the dimmest text in the row. Now: a
   caption saying what the row steps, real buttons with chrome and a
   tappable target, the month prominent in body ink, and a fixed
   shape — on the current month the Next slot holds a disabled button
   (#70's inert style) beside the badge instead of vanishing. */
.month-nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    margin: 1rem 0;
}

/* <button> keeps the UA's line-height: normal while the anchors
   inherit the body's 1.5, which left the two controls 2px apart in the
   same row. Pin it so the pair is one control. */
.month-nav .btn { line-height: 1.5; }

.month-nav__caption {
    color: var(--ink-2);
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.month-nav__label {
    color: var(--ink);
    font-size: 1.15rem;
    font-weight: 700;
}

.month-nav__jump { font-size: 0.85rem; }

/* The /usage window statement (#115): the same label the billing month
   nav shows, on a page with no stepper to hold it — one flex row so the
   org admin's scope toggle sits beside it. */
.usage-window {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.6rem;
    margin: 1rem 0;
}

.month-nav .badge {
    display: inline-block;
    background: var(--inset);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0.15rem 0.5rem;
    color: var(--ink-2);
    font-size: 0.78rem;
    font-weight: 600;
}

/* Billing > Invoices (#289 N7): the month's runs grouped by case. Each
   group is a titled block inside the card — a case's name, its chip and
   its one ask on the head row, its runs under it, its subtotal below.
   Bordered rather than nested cards so a month of six cases still reads
   as one page. */
.billing-case {
    border-top: 1px solid var(--border);
    padding-top: 0.9rem;
    margin-top: 0.9rem;
}

.billing-case:first-of-type {
    border-top: 0;
    padding-top: 0;
    margin-top: 0;
}

.billing-case__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 0.5rem;
}

.billing-case__name {
    margin: 0;
    font-size: 1rem;
}

/* Pushes the ask (or the pending note) to the end of the head row,
   which is where every other action row on the app puts it. */
.billing-case__actions { margin-left: auto; }

.billing-case__subtotal {
    margin: 0.4rem 0 0;
    text-align: right;
    font-weight: 700;
}

.billing-month-total {
    border-top: 2px solid var(--border);
    margin-top: 1rem;
    padding-top: 0.7rem;
    text-align: right;
    font-size: 1.05rem;
}

/* The expand-below row under an issued invoice: the runs live in a
   full-width cell so the <details> is not squeezed into a column. */
.billing-runs-row > td {
    padding-top: 0;
    border-top: 0;
}

.invoice-tree__user > summary {
    cursor: pointer;
    font-weight: 700;
    padding: 0.4rem 0;
}

.invoice-tree__case { margin: 0.3rem 0 0.6rem 1.2rem; }

.invoice-tree__case > summary {
    cursor: pointer;
    padding: 0.25rem 0;
}

.novo-block {
    background: var(--inset);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.6rem;
    font-size: 0.8rem;
    font-family: var(--font-mono);
    overflow-x: auto;
}

/* In the outstanding-invoices table the block hangs off a <details> in a
   capped cell (#156) — hold it to the cell so it scrolls itself. */
.data-table .novo-block { max-width: 20rem; }

/* An outbound email's body, shown verbatim (#314). Same inset block as
   `.novo-block`, but it wraps: mail is prose, and a long line should
   fold rather than scroll away. */
.email-body {
    background: var(--inset);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.6rem;
    font-size: 0.85rem;
    font-family: var(--font-mono);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.settings-table td { vertical-align: top; }

.setting-description {
    font-size: 0.85rem;
    max-width: 28rem;
}

.setting-edit-form {
    display: flex;
    gap: 0.4rem;
    align-items: flex-start;
}

.setting-edit-form input[type="text"],
.setting-edit-form textarea {
    font-family: var(--font-mono);
    font-size: 0.9rem;
    width: 14rem;
}

.setting-edit-form textarea { width: 20rem; }

.settings-table .btn--small {
    padding: 0.35rem 0.7rem;
    font-size: 0.88rem;
}

.settings-table .btn--ghost { background: none; color: inherit; }

.setting-reset-form { margin-top: 0.4rem; }

/* The jump links over a long single page (#289 N11). Wraps to as many
   rows as it needs; `scroll-margin-top` keeps a jumped-to heading clear
   of the sticky bar it would otherwise land behind. */
.page-jumps {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1rem;
    margin: 0 0 1.2rem;
    font-size: 0.9rem;
}

.settings-group { scroll-margin-top: 5rem; }

/* Grouped sections + on-demand descriptions keep the page scannable (#98). */
.settings-group h2 {
    margin-top: 0;
    font-size: 1.05rem;
}

.setting-help > summary {
    cursor: pointer;
    font-size: 0.82rem;
    color: var(--ink-2);
}

.setting-help .setting-description { margin: 0.3rem 0 0; }

.setting-json {
    font-family: var(--font-mono);
    font-size: 0.8rem;
    margin: 0;
}

/* An overridden row wears a left accent so the eye finds it (#98). */
.settings-table tr.is-overridden > td:first-child {
    border-left: 3px solid var(--warn);
    padding-left: 0.55rem;
}

/* llm_prices edits as rows, not raw JSON (#97). */
.price-table { max-width: 23rem; }

/* Every track collapsible (`minmax(0, ...)`): fixed track minimums summed
   to a hard ~291px floor, so under ~370px of card the grid outgrew its
   `.table-scroll` and clipped the Remove column (#97). The fr ratios are
   unchanged, so wide viewports lay out exactly as before — only the floor
   is gone. `auto` on the last track keeps the Remove label whole. */
.price-row {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 0.7fr) minmax(0, 0.7fr) auto;
    gap: 0.35rem;
    align-items: center;
    margin-bottom: 0.3rem;
}

.price-row--head {
    font-size: 0.75rem;
    color: var(--ink-2);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.price-row input[type="text"] {
    font-family: var(--font-mono);
    font-size: 0.85rem;
    width: 100%;
    /* A grid item's automatic minimum is its content size; an input's is
       its `size` attribute. Without this the inputs would put the floor
       back that the collapsible tracks just removed. */
    min-width: 0;
}

.price-remove {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.78rem;
}

.setting-price-form .btn { margin-top: 0.2rem; }

/* The settings table is exempt from the #126 max-content sizing: its rows
   are prose descriptions and full-width inputs, and below 861px it stops
   being a table at all (see the stacking media query below). */
.table-scroll > .settings-table { width: 100%; }

.settings-table th,
.settings-table td { white-space: normal; }

/* Narrow widths: a table marked `table--stack` stops behaving like a
   table and stacks — every row a labelled block (each cell captioned
   from its own `data-label`), every control full width, so values and
   action buttons stay on screen instead of hiding behind the sideways
   scroll (#107, generalised for #174). At >= 861px the tables render
   unchanged (the E2E spec matches rows by role at the default
   viewport). Cells with no label — an actions column, an empty-state
   `colspan` row — render no caption line at all. */
@media (max-width: 860px) {
    .table--stack thead { display: none; }

    .table-scroll > .table--stack { width: 100%; }

    .table--stack tr {
        display: block;
        border-bottom: 1px solid var(--border);
        padding: 0.6rem 0;
    }

    .table--stack td {
        display: block;
        border-bottom: none;
        padding: 0.25rem 0;
        white-space: normal;
    }

    .table--stack td::before {
        content: attr(data-label);
        display: block;
        color: var(--ink-2);
        font-size: 0.78rem;
        text-transform: uppercase;
        letter-spacing: 0.06em;
    }

    .table--stack td:not([data-label])::before,
    .table--stack td[data-label=""]::before { content: none; }

    .settings-table tr.is-overridden {
        border-left: 3px solid var(--warn);
        padding-left: 0.55rem;
    }

    .setting-edit-form { flex-wrap: wrap; }

    .setting-edit-form input[type="text"],
    .setting-edit-form select,
    .setting-edit-form textarea { width: 100%; }
}

.badge--override {
    display: inline-block;
    background: color-mix(in srgb, var(--warn) var(--tint-bg), transparent);
    border: 1px solid color-mix(in srgb, var(--warn) var(--tint-border), transparent);
    border-radius: 6px;
    padding: 0.05rem 0.4rem;
    font-size: 0.78rem;
    margin-left: 0.4rem;
}

.badge--inactive {
    display: inline-block;
    background: color-mix(in srgb, var(--danger) var(--tint-bg), transparent);
    border: 1px solid color-mix(in srgb, var(--danger) var(--tint-border), transparent);
    border-radius: 6px;
    padding: 0.05rem 0.4rem;
    font-size: 0.78rem;
    margin-left: 0.4rem;
}

.form-card { margin: 0.8rem 0; }

.form-card h2 {
    margin-top: 0;
    font-size: 1.1rem;
}

.flag-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.8rem;
    padding: 0.4rem 0;
    border-bottom: 1px solid var(--border);
}

.flag-row:last-child { border-bottom: none; }

.plain-list {
    list-style: none;
    padding: 0;
    margin: 0.6rem 0 0;
}

.permissions-summary {
    cursor: pointer;
    font-weight: 700;
}

.permissions-legend {
    margin: 0.6rem 0 0.2rem;
    padding-left: 1.1rem;
    font-size: 0.85rem;
    line-height: 1.5;
}

.permissions-table td:first-child {
    max-width: 34rem;
    white-space: normal;
    overflow-wrap: anywhere;
}

.permissions-table td:first-child .muted { font-size: 0.85rem; }

.permissions-table .radio-cell {
    display: flex;
    gap: 0.35rem;
    align-items: center;
    color: var(--ink-2);
    font-size: 0.9rem;
}

.events-table__ts { white-space: nowrap; }

.events-table__detail {
    background: var(--inset);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.5rem;
    font-size: 0.82rem;
    font-family: var(--font-mono);
    overflow-x: auto;
    margin: 0.3rem 0 0;
}

.pagination {
    display: flex;
    gap: 1rem;
    align-items: center;
    margin-top: 0.8rem;
}

/* ---- MFA --------------------------------------------------------- */

.mfa-qr {
    margin: 1rem 0;
    max-width: 240px;
    background: #ffffff;
    border-radius: 10px;
    padding: 0.6rem;
}

.mfa-qr svg {
    width: 100%;
    height: auto;
    display: block;
}

/* The code rows are `.inline-form` with a wider gap (#116): the input is
   autofocused, and the 2px focus ring at 2px offset eats 4px of the
   0.4rem default on each side — enough that the ring reads as touching
   the label and the submit button. */
.mfa-code-form { gap: 0.6rem; }

.mfa-recovery-codes {
    font-family: var(--font-mono);
    font-size: 1rem;
    letter-spacing: 0.06em;
    line-height: 1.8;
    background: var(--inset);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 0.8rem 1rem;
    user-select: all;
}

/* ---- Confirmation dialog ----------------------------------------- */
/* Native <dialog>, centred by the UA; app.js opens it with showModal.
   Card surface + tokens so it reads as one of our surfaces in both
   themes (#76). */

.dialog {
    background: var(--surface);
    color: var(--ink);
    border: 1px solid var(--border);
    border-radius: 14px;
    box-shadow: var(--shadow);
    padding: 1.5rem;
    max-width: 28rem;
    width: calc(100% - 2rem);
}

/* A literal scrim, not a token: ::backdrop only inherits custom
   properties from the dialog in recent engines, so a var() here would
   resolve to nothing (and dim nothing) elsewhere. */
.dialog::backdrop {
    background: rgb(0 0 0 / 0.5);
}

.dialog__title {
    margin: 0 0 0.6rem;
    font-size: 1.15rem;
}

.dialog p {
    color: var(--ink-2);
    margin: 0 0 1rem;
}

.dialog textarea {
    width: 100%;
    font-size: 0.95rem;
}

.dialog__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 0.6rem;
    margin-top: 1.2rem;
}

/* ---- Deliverables ----------------------------------------------------
   The Deliverables page (design doc §1): a sidebar of cases beside a
   panel for the selected one. Which column a phone leads with is
   decided server-side by `.deliverables--landing` / `.deliverables--case`, so
   the responsive rule at the bottom is pure CSS and the page keeps its
   no-JS floor.

   Cluster D — the segmented layout. Every section on this page is a
   `.dl-panel`: a bounded `--surface` box with a `--surface-2` header
   strip naming it, and hairline-separated rows inside rather than a
   stack of floating cards. Nothing floats on the ground any more, so
   a section stops melting into it. Radii are tight (panels 6px,
   buttons 5px, pills stay round) and the type has three tiers: titles
   in `--ink`, sentences in `--ink-2`, mono stamps in `--ink-3`.

   Tokens only, no raw colour anywhere in this section (decision 15):
   the mockups are dark because dark is the default, and light has to
   read as well without a second palette. Pills reuse `.status-pill`. */

.deliverables {
    display: grid;
    grid-template-columns: 22.5rem minmax(0, 1fr);
    gap: 1.25rem;
    align-items: start;
    margin-top: 1rem;
}

.deliverables__side { min-width: 0; }

/* The main column is not itself a surface: it is the column the
   panels stack in, so the ground shows between them and each section
   keeps its own edge. */
.deliverables__main {
    display: flex;
    flex-direction: column;
    gap: 1.1rem;
    min-width: 0;
}

/* ---- the panel: every section on this page is one of these ---- */

.dl-panel {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: var(--shadow);
    overflow: hidden;
    min-width: 0;
}

/* The strip is what makes a section obvious: its own fill, a hairline
   under it, and a small letter-spaced label that never competes with
   the content's own headings. `--surface-2` rather than `--inset`
   because the inset tint is invisible on the light theme's paper. */
.dl-panel__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    padding: 0.55rem 1rem;
    background: var(--surface-2);
    border-bottom: 1px solid var(--border);
}

/* The label is the section's HEADING element (an h2; the landing's
   display "Just finished" h1 sits above its panel), so it has to shed
   what the base h2 rule gives it — the margin, the display face and the
   tight heading leading — and keep the strip exactly as tall as it
   was when this was a span. */
.dl-panel__label {
    margin: 0;
    color: var(--ink-2);
    font-family: var(--font-body);
    font-size: 0.72rem;
    font-weight: 800;
    line-height: 1.5;
    text-transform: uppercase;
    letter-spacing: 0.12em;
}

.dl-panel__meta {
    margin-left: auto;
    color: var(--ink-3);
    font-size: 0.75rem;
    text-align: right;
}

.dl-panel__body {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.7rem 1rem;
    padding: 0.9rem 1.1rem;
}

.dl-panel__body > p { margin: 0; }

/* Rows inside a panel are divided by hairlines, not by gaps: the panel
   edge is already the container, so a row needs no card of its own. */
.dl-panel__rows > * + * { border-top: 1px solid var(--border); }

/* ---- sidebar: search, view controls, scope ---- */

.deliverables__filters {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 0.7rem 0.75rem;
    border-bottom: 1px solid var(--border);
}

.deliverables__search {
    width: 100%;
    border-radius: 5px;
    border-color: var(--border);
    padding: 0.4rem 0.6rem;
    font-size: 0.85rem;
}

/* Show / Sort / Apply are one compact toolbar row. */
.deliverables__controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem;
}

/* Each control is a small inset chip: the label and its <select> read
   as one field. The <label> still wraps the control, so the select's
   accessible name is unchanged. */
.deliverables__control {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    min-width: 0;
    padding: 0.2rem 0.35rem;
    border: 1px solid var(--border);
    border-radius: 5px;
    background: var(--inset);
}

/* The chip is the control as far as the eye is concerned, so the ring
   goes round the chip and the select's own is suppressed — the label,
   the value and the caret light together instead of a box round the
   value alone. Same 2px/2px as the global `:focus-visible` ring. */
.deliverables__control:focus-within {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.deliverables__control select:focus-visible { outline: none; }

/* The native dropdown arrow costs ~18px a chip — more than this
   toolbar has to spare, and Show / Sort / Apply have to share one row.
   So the select gives up its own arrow and the chip draws the caret
   after it, a border triangle in `--ink-3`. */
.deliverables__control select {
    max-width: 100%;
    padding: 0;
    border: none;
    border-radius: 0;
    background: none;
    color: var(--ink);
    font-size: 0.72rem;
    font-weight: 700;
    appearance: none;
}

.deliverables__control::after {
    content: "";
    flex: 0 0 auto;
    width: 0;
    height: 0;
    border-left: 3.5px solid transparent;
    border-right: 3.5px solid transparent;
    border-top: 4px solid var(--ink-3);
}

.deliverables__label {
    color: var(--ink-2);
    font-size: 0.6rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    white-space: nowrap;
}

.deliverables__controls .btn { margin-left: auto; }

.deliverables__scope {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.4rem;
    margin: 0;
    font-size: 0.8rem;
}

.deliverables__scope-name {
    color: var(--ink);
    font-weight: 700;
}

/* An empty column has to say what to do next, not just sit there — it
   is inside the panel now, so the panel's own edge is its container. */
.deliverables__empty {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 1rem;
}

.deliverables__empty p {
    margin: 0;
    color: var(--ink-2);
}

.deliverables__empty-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
}

/* ---- sidebar: the case rows ---- */

.deliverables__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.side-item {
    display: grid;
    gap: 0.12rem;
    padding: 0.65rem 0.8rem;
    /* The bar the selected row fills in — reserved on every row so the
       list does not shift by 3px when the selection moves. */
    border-left: 3px solid transparent;
    color: var(--ink);
    text-decoration: none;
}

.deliverables__list li + li .side-item { border-top: 1px solid var(--border); }

.side-item:hover {
    background: var(--inset);
    color: var(--ink);
}

/* Selected = the amber bar and an amber title, the canvas's one
   selection signal. `aria-current` carries it for anyone not looking
   at colour. */
.side-item--selected {
    background: var(--inset);
    border-left-color: var(--accent);
}

.side-item--selected .side-item__title { color: var(--accent); }

.side-item__title {
    font-family: var(--font-display);
    font-size: 0.92rem;
    font-weight: 700;
    /* Case names are free text: a long one wraps inside the row
       rather than pushing the column sideways (#62). */
    overflow-wrap: anywhere;
}

/* The "there is a new report in here" dot (decision 3) — a window, not
   per-user read state, so it fades on its own. */
.side-item__dot {
    display: inline-block;
    width: 0.45rem;
    height: 0.45rem;
    margin-right: 0.35rem;
    border-radius: 50%;
    background: var(--accent);
    vertical-align: 0.1em;
}

.side-item__meta,
.side-item__updated,
.side-item__owner {
    color: var(--ink-3);
    font-size: 0.74rem;
    overflow-wrap: anywhere;
}

.side-item__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
}

.side-item__updated { margin-right: auto; }

.side-item__foot .status-pill { font-size: 0.7rem; }

/* ---- buttons inside the Deliverables page ---- */

/* Tighter than the app-wide button: this page is a dense reading
   surface, and a 10px-round chunky control read as bubbly beside the
   6px panels. Pills (`.status-pill`) keep their round ends. */
.deliverables .btn {
    border-radius: 5px;
    padding: 0.4rem 0.75rem;
    font-size: 0.81rem;
    font-weight: 700;
}

.deliverables .btn--small {
    padding: 0.28rem 0.5rem;
    font-size: 0.76rem;
}

.deliverables .btn--primary {
    border-radius: 5px;
    padding: 0.45rem 0.9rem;
    font-size: 0.75rem;
}

/* ---- the download button ---- */

.cta {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.38rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: 5px;
    background: var(--surface-2);
    color: var(--ink);
    font-size: 0.81rem;
    /* A `<button class="cta">` (the case header's close/reopen) has to
       come out the same box as the anchors beside it, and the UA gives
       buttons their own font and `line-height: normal` -- the same
       three-line reset `.month-nav .btn` needs. */
    font-family: var(--font-body);
    line-height: 1.5;
    cursor: pointer;
    font-weight: 600;
    text-decoration: none;
    max-width: 100%;
}

.cta:hover {
    border-color: var(--border-strong);
    color: var(--ink);
    background: color-mix(in srgb, var(--surface-2) 80%, var(--ink) 6%);
}

/* The destructive twin of the box above: `.btn--danger`'s tints on the
   cta's shape, so "Case closed" sits beside "Download all" as a matched
   pair in a different colour (#281). It follows `.cta:hover` so its own
   hover keeps the red label instead of falling back to `--ink`. */
.cta--danger {
    background: color-mix(in srgb, var(--danger) 14%, transparent);
    border-color: color-mix(in srgb, var(--danger) 40%, transparent);
    color: var(--danger);
}

.cta--danger:hover {
    background: color-mix(in srgb, var(--danger) 22%, transparent);
    border-color: color-mix(in srgb, var(--danger) 40%, transparent);
    color: var(--danger);
}

.cta__icon {
    color: var(--accent);
    font-weight: 800;
}

.cta__type {
    color: var(--ink-3);
    font-size: 0.66rem;
    letter-spacing: 0.04em;
    font-weight: 400;
}

/* A file that expired or was never produced: dashed and muted, still
   on the row so it can say what the run does not have (#176, #188). */
.cta--gone {
    background: none;
    /* `--border` is nearly the panel's own ink in dark, so a dashed
       edge drawn in it disappears — a tint of `--ink-3` draws a line
       in both themes. */
    border: 1px dashed color-mix(in srgb, var(--ink-3) 45%, transparent);
    color: var(--ink-3);
    font-weight: 500;
    cursor: default;
}

.deliverables__ctas {
    display: flex;
    flex-wrap: wrap;
    gap: 0.45rem;
    margin-top: 0.6rem;
}

/* ---- the case / landing header ---- */

.deliverables__head {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    padding-bottom: 0.85rem;
    border-bottom: 1px solid var(--border);
}

.deliverables__head h1 {
    font-size: 1.6rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    margin: 0;
    overflow-wrap: anywhere;
}

.deliverables__head .page-lede { margin: 0; }

.deliverables__chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.45rem;
}

.deliverables__number {
    color: var(--ink-3);
    font-size: 0.78rem;
}

/* Row 1: the title, with the two case actions pushed to the right.
   Row 2: the number and the chips, forced onto their own full-width
   line (`flex-basis: 100%`), so three chips sit side by side instead of
   being squeezed into two rows by an actions column beside them. */
.deliverables__head--split {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 0.6rem 1rem;
}

.deliverables__head--split > h1 {
    flex: 1 1 auto;
    min-width: 0;
}

.deliverables__head--split > .deliverables__actions { margin-left: auto; }

.deliverables__head--split > .deliverables__chips { flex: 1 0 100%; }

.deliverables__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.deliverables__actions .inline-form { margin: 0; }

/* ---- a deposition row (inside the Depositions panel) ---- */

/* The three full labels want ~590px and the row has ~450px, so beside
   the name they could only ever wrap 2-and-1. They take their own line
   under the name and dates instead — one straight row of three, left
   aligned on the panel's text edge — and the labels stay full words. */
.deliverables__row {
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
    padding: 0.8rem 1.1rem;
}

.deliverables__row-say { min-width: 0; }

.deliverables__row-name {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    margin: 0;
    font-size: 0.94rem;
    overflow-wrap: anywhere;
}

.deliverables__row-meta {
    margin: 0.15rem 0 0;
    color: var(--ink-3);
    font-size: 0.74rem;
}

.deliverables__row-owner,
.deliverables__row-staff {
    margin: 0.25rem 0 0;
    font-size: 0.75rem;
}

.deliverables__row .deliverables__ctas {
    justify-content: flex-start;
    margin-top: 0;
}

/* ---- "Just finished" tiles ---- */

/* Three tiles, one row, divided by vertical hairlines — the panel's
   own edge closes the group, so the tiles need no boxes. Three and not
   four (`JUST_FINISHED_LIMIT`): a fourth squeezed every one of them. */
.deliverables__tiles {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.deliverables__tile {
    padding: 0.9rem 1.05rem;
    min-width: 0;
}

.deliverables__tile + .deliverables__tile { border-left: 1px solid var(--border); }

.deliverables__tile-name {
    margin: 0;
    font-size: 0.94rem;
    overflow-wrap: anywhere;
}

.deliverables__tile-case {
    margin: 0.2rem 0 0;
    font-size: 0.81rem;
    overflow-wrap: anywhere;
}

.deliverables__tile-stamp {
    margin: 0.2rem 0 0;
    color: var(--ink-3);
    font-size: 0.74rem;
}

/* A tile is a third of the panel: its buttons stack, and they are
   sized down just enough that the short label and its type tag stay on
   ONE line at the 1160px content width — a wrapped button reads as two
   controls. `min-width: 0` keeps them inside the tile whatever the
   label. */
.deliverables__tile .deliverables__ctas {
    flex-direction: column;
    align-items: stretch;
    gap: 0.35rem;
    margin-top: 0.55rem;
}

.deliverables__tile .cta {
    min-width: 0;
    gap: 0.3rem;
    padding: 0.3rem 0.5rem;
    font-size: 0.8rem;
}

.deliverables__tile .cta__label { white-space: nowrap; }

/* The type tag rides the right edge, so the three stacked buttons read
   as a column of labels with a column of formats beside it. */
.deliverables__tile .cta__type {
    margin-left: auto;
    font-size: 0.64rem;
}

/* ...except the dead ones, whose full wording has to be readable and
   is longer than any tile is wide. */
.deliverables__tile .cta--gone { white-space: normal; }

/* ---- "Needs attention" rows ---- */

.deliverables__attention-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.9rem;
    padding: 0.75rem 1.1rem;
}

/* The pill sits in a fixed slot rather than being the flex item
   itself: a pill stretched to a column width is not a pill. */
.deliverables__attention-tone {
    flex: 0 0 8.5rem;
    min-width: 0;
}

.deliverables__attention-case {
    flex: 0 1 auto;
    min-width: 0;
    font-family: var(--font-display);
    font-weight: 700;
    overflow-wrap: anywhere;
}

/* `flex-basis: 0` rather than a width: the sentence takes whatever is
   left after the pill, the case and the action, so the action stays on
   the row and the two rows end up the same height. */
.deliverables__attention-say {
    flex: 1 1 0;
    min-width: 6rem;
    color: var(--ink-2);
    font-size: 0.81rem;
}

.deliverables__attention-act {
    flex: 0 0 auto;
    margin-left: auto;
}

.deliverables__attention-act .inline-form { margin: 0; }

/* ---- the matrix band ---- */

/* The band IS a panel — it carries its own header strip because the
   poll swaps this whole element (decision 9). The state pill lives in
   the strip's meta slot, where every other panel puts its right-hand
   fact. */
.deliverables__matrix-say {
    flex: 1 1 22rem;
    min-width: 0;
}

.deliverables__matrix-title {
    margin: 0;
    font-family: var(--font-display);
    font-size: 0.94rem;
    font-weight: 700;
}

.deliverables__matrix-note {
    margin: 0.2rem 0 0;
    color: var(--ink-2);
    font-size: 0.81rem;
}

.deliverables__matrix-act {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.55rem;
    margin-left: auto;
}

.deliverables__matrix-act .inline-form { margin: 0; }

/* ---- billing ---- */

.deliverables__billing { font-size: 0.85rem; }

.deliverables__billing .muted {
    flex: 1 1 12rem;
    min-width: 0;
    color: var(--ink-2);
    font-size: 0.81rem;
}

.deliverables__billing .inline-form {
    margin: 0;
    margin-left: auto;
}

/* The phone back link is desktop-invisible: the sidebar IS the way
   back when both columns are on screen. */
.deliverables__back { display: none; }

/* Phone (§1, decision 2): one column. The landing leads with the
   sidebar — search, then the cases — and the "Just finished" tiles
   follow it, trimmed to two; a case is its own screen with the list
   hidden behind a back link, chips wrapping and buttons stacked. The
   panels keep their edges and simply go full width. Same URLs, no JS:
   the server already said which of the two this is. */
@media (max-width: 600px) {
    .deliverables {
        grid-template-columns: minmax(0, 1fr);
        gap: 1rem;
    }

    .deliverables__main { gap: 0.9rem; }

    .dl-panel__head { padding: 0.5rem 0.85rem; }

    .dl-panel__body,
    .deliverables__row,
    .deliverables__attention-row,
    .deliverables__tile {
        padding-left: 0.85rem;
        padding-right: 0.85rem;
    }

    .deliverables--landing .deliverables__tile:nth-child(n + 3) { display: none; }

    .deliverables--case .deliverables__side { display: none; }

    .deliverables--case .deliverables__back {
        display: inline-block;
        margin-bottom: 0.8rem;
        font-weight: 600;
        text-decoration: none;
    }

    .deliverables__tiles { grid-template-columns: minmax(0, 1fr); }

    .deliverables__tile + .deliverables__tile {
        border-left: none;
        border-top: 1px solid var(--border);
    }

    .deliverables__ctas { flex-direction: column; align-items: stretch; }

    .deliverables__ctas .cta { justify-content: flex-start; }

    /* The four-column row becomes a stack: the pill, the case, the
       sentence and the action each take the full width. */
    .deliverables__attention-tone { flex: 0 0 auto; }

    .deliverables__attention-case,
    .deliverables__attention-say { flex: 1 1 100%; }

    .deliverables__attention-act { margin-left: 0; }

    .deliverables__billing .inline-form { margin-left: 0; }

    .deliverables__matrix-act .btn,
    .deliverables__matrix-act .cta { width: 100%; justify-content: center; }

    .deliverables__matrix-act,
    .deliverables__matrix-act .inline-form { flex: 1 1 100%; margin-left: 0; }
}
