/* ============================================================================
   ui.css — the component layer
   ----------------------------------------------------------------------------
   Every screen composes from what is in this file. Nothing here knows which
   screen it is on, and no screen invents chrome of its own: if a layout needs
   a surface, a table, a stat, a pill or a toolbar, it uses these.

   Everything is expressed in tokens from ds/tokens. No raw colours, no raw
   radii, no magic numbers below except where the value IS the design (a 1px
   rule, a 3px accent edge).

   Order: layout · surfaces · data display · controls · mobile.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   1 · LAYOUT
--------------------------------------------------------------------------- */

/* The app bar. Brand, the four destinations, the two global actions. It
   replaces the 248px rail: navigation is four items, which is a row, not a
   column — and the column was costing a fifth of every screen. */
.appbar { display: flex; align-items: center; gap: var(--space-6);
          height: var(--appbar-h); flex: none; padding: 0 var(--page-pad-desktop);
          border-bottom: var(--border-w) solid var(--border-subtle);
          background: var(--surface-card); position: relative; z-index: var(--z-sticky); }
.appbar-brand { display: flex; align-items: center; gap: var(--space-5); flex: none; }
.appbar-brand .mark { width: 34px; height: 34px; flex: none; }
.appbar-brand .name { font-family: var(--font-display); font-size: var(--text-xl);
                      font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight);
                      color: var(--text-strong); }
.appbar-nav { display: flex; align-items: center; gap: var(--space-3);
              margin: 0 auto; min-width: 0; }
.appbar-actions { display: flex; align-items: center; gap: var(--space-4); flex: none; }

.navpill { display: inline-flex; align-items: center; gap: var(--space-3);
           height: var(--control-h-md); padding: 0 var(--space-6);
           border-radius: var(--radius-control); color: var(--text-muted);
           font-size: var(--text-sm); font-weight: var(--weight-medium);
           white-space: nowrap; transition: var(--transition-control); }
.navpill:hover { background: var(--action-ghost-hover); color: var(--text-body); }
.navpill[aria-current="page"] { background: var(--surface-brand-soft); color: var(--text-brand);
                                font-weight: var(--weight-semibold); }
.navpill .count { font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--text-subtle); }
.navpill[aria-current="page"] .count { color: var(--text-brand); }

.avatar { display: inline-grid; place-items: center; width: 32px; height: 32px; flex: none;
          border-radius: var(--radius-circle); background: var(--surface-brand-soft);
          color: var(--text-brand); font-size: var(--text-xs);
          font-weight: var(--weight-semibold); }
.avatarbtn { display: inline-flex; align-items: center; gap: var(--space-3);
             padding: var(--space-2); border-radius: var(--radius-pill);
             color: var(--text-subtle); transition: var(--transition-control); }
.avatarbtn:hover { background: var(--action-ghost-hover); }

/* The page. One container, one max width, one gutter — so the left edge never
   moves between destinations. */
.page { max-width: var(--page-max); margin: 0 auto; width: 100%;
        padding: var(--space-8) var(--page-pad-desktop) 72px; }
.page.wide { max-width: none; }

/* A page that fills the viewport instead of growing past it, so the thing
   inside it does the scrolling. The surface must stop scrolling for this to
   mean anything — otherwise you get two scrollbars racing each other. */
.surface:has(> .page.fits) { overflow: hidden; }
.page.fits { height: 100%; display: flex; flex-direction: column;
             min-height: 0; padding-bottom: var(--space-7); }
.page.fits > .tablewrap { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.page.fits > .tablewrap > .tablescroll { flex: 1; min-height: 0; overflow: auto; }
/* the header stays put while the rows move under it */
.page.fits table.data thead th { position: sticky; top: 0; z-index: 2; }
.page.fits > .tablefoot { flex: none; }
/* On a phone the table is a list of cards, so there is no header to stick and
   no column to hold still — the page scrolls, the way every other phone
   screen does. A fixed-height pane here would only trap the list. */
body.is-mobile .surface:has(> .page.fits) { overflow: auto; }
body.is-mobile .page.fits { height: auto; display: block; padding-bottom: 96px; }
body.is-mobile .page.fits > .tablewrap,
body.is-mobile .page.fits > .tablewrap > .tablescroll { display: block; overflow: visible; }

.pagehead { display: flex; align-items: flex-start; gap: var(--space-6);
            margin-bottom: var(--space-7); }
.pagehead .titles { flex: 1; min-width: 0; }
.pagehead h1 { font-family: var(--font-display); font-size: var(--text-3xl);
               font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight);
               color: var(--text-strong); }
.pagehead .sub { font-size: var(--text-sm); color: var(--text-muted); margin-top: var(--space-2);
                 max-width: var(--prose-max); }
.pagehead .acts { display: flex; align-items: center; gap: var(--space-4); flex: none; }

/* Search, filters, sort, view — the same bar on every screen that lists things. */
.toolbar { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap;
           margin-bottom: var(--space-7); }
.toolbar .search { flex: 0 1 300px; }
.toolbar .grow { flex: 1; }

/* Items stretch to the row height by default — four cards in a row at four
   different heights was the single worst thing about the old stat strip.
   .cols.top opts out where a column genuinely should not stretch. */
.cols { display: grid; gap: var(--space-6); }
.cols.top { align-items: start; }
.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.cols-main { grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); }
.stack { display: flex; flex-direction: column; gap: var(--space-5); min-width: 0; }

/* ---------------------------------------------------------------------------
   2 · SURFACES
--------------------------------------------------------------------------- */

/* One card. Everything needing a raised surface is this, optionally with a
   head. Five different card shapes for the same job is what the stylesheet
   had before, and it is why nothing looked related to anything. */
.card { background: var(--surface-card); border: var(--border-w) solid var(--border-subtle);
        border-radius: var(--radius-card); padding: var(--space-7);
        transition: var(--transition-control); min-width: 0; }
.card.tight { padding: var(--space-6); }
.card.flush { padding: 0; overflow: hidden; }
.card.sunken { background: var(--surface-sunken); }
.card.hoverable { cursor: pointer; }
.card.hoverable:hover { border-color: var(--border-strong); background: var(--surface-raised); }
.card.selected { border-color: var(--border-brand); background: var(--surface-brand-soft); }
.card.dim { opacity: .62; }

.cardhead { display: flex; align-items: center; gap: var(--space-5);
            margin-bottom: var(--space-6); }
.cardhead h2, .cardhead h3 { font-size: var(--text-lg); font-weight: var(--weight-semibold);
                             color: var(--text-strong); letter-spacing: var(--tracking-tight); }
.cardhead .grow { flex: 1; }
.cardhead:has(.titles) { align-items: flex-start; }
.cardhead .titles { flex: 1; min-width: 0; }
.cardhead .titles .sub { font-size: var(--text-sm); color: var(--text-muted);
                         margin-top: var(--space-2); }

/* Section heading, used between cards rather than inside them. */
.sectionhead { display: flex; align-items: baseline; gap: var(--space-5);
               margin: var(--space-8) 0 var(--space-5); }
.sectionhead:first-child { margin-top: 0; }
.sectionhead h2 { font-size: var(--text-xl); font-weight: var(--weight-semibold);
                  color: var(--text-strong); letter-spacing: var(--tracking-tight); }
.sectionhead .n { color: var(--text-subtle); font-weight: var(--weight-regular); }
.sectionhead .grow { flex: 1; }
.sectionhead .sub { font-size: var(--text-sm); color: var(--text-muted); }

/* Numbered panel — Settings is a set of these. */
.panel { background: var(--surface-card); border: var(--border-w) solid var(--border-subtle);
         border-radius: var(--radius-card); padding: var(--space-7); min-width: 0; }
.panel > h2 { font-size: var(--text-lg); font-weight: var(--weight-semibold);
              color: var(--text-strong); margin-bottom: var(--space-6); }
.panel > h2 .num { color: var(--text-subtle); font-variant-numeric: tabular-nums;
                   margin-right: var(--space-3); }
/* A line of explanation under a panel heading. NOT .note — that class is the
   review annotation, which is display:none unless ?review=1, so calling this
   one .note made the whole Account panel vanish for anyone not in review
   mode. A component may not borrow a name that already means something. */
.panel .blurb { font-size: var(--text-sm); color: var(--text-muted);
                margin: calc(var(--space-4) * -1) 0 var(--space-6); max-width: var(--prose-max); }

/* Label/value pairs in a row — the meta strip under a record title. */
.metagrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
            gap: var(--space-6) var(--space-8); }
.metagrid .k { display: block; font-size: var(--text-2xs); font-weight: var(--weight-semibold);
               letter-spacing: var(--tracking-caps); text-transform: uppercase;
               color: var(--text-subtle); margin-bottom: var(--space-3); }
.metagrid .v { font-size: var(--text-md); color: var(--text-strong);
               font-weight: var(--weight-medium); overflow-wrap: anywhere; }
.metagrid .v2 { font-size: var(--text-sm); color: var(--text-muted); margin-top: 2px;
                overflow-wrap: anywhere; }

.rule { height: 1px; background: var(--border-subtle); border: 0; margin: var(--space-6) 0; }

/* An overline label above a block of prose. */
.overline { display: block; font-size: var(--text-2xs); font-weight: var(--weight-semibold);
            letter-spacing: var(--tracking-caps); text-transform: uppercase;
            color: var(--text-subtle); margin-bottom: var(--space-4); }

/* ---------------------------------------------------------------------------
   3 · DATA DISPLAY
--------------------------------------------------------------------------- */

/* One table. Jobs and Files are both this. */
.tablewrap { background: var(--surface-card); border: var(--border-w) solid var(--border-subtle);
             border-radius: var(--radius-card); overflow: hidden; }
.tablescroll { overflow-x: auto; }
table.data { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
table.data th { text-align: left; padding: var(--space-5) var(--space-6);
                font-size: var(--text-2xs); font-weight: var(--weight-semibold);
                letter-spacing: var(--tracking-caps); text-transform: uppercase;
                color: var(--text-subtle); background: var(--surface-sunken);
                border-bottom: var(--border-w) solid var(--border-subtle); white-space: nowrap; }
table.data td { padding: var(--space-5) var(--space-6); color: var(--text-body);
                border-bottom: var(--border-w) solid var(--border-subtle); vertical-align: middle; }
table.data tbody tr:last-child td { border-bottom: 0; }
table.data tbody tr { transition: var(--transition-control); }
table.data tbody tr.rowlink { cursor: pointer; }
table.data tbody tr.rowlink:hover { background: var(--surface-raised); }
table.data tbody tr[aria-selected="true"] { background: var(--surface-brand-soft); }
table.data td.num { font-variant-numeric: tabular-nums; color: var(--text-muted); white-space: nowrap; }
table.data td.dim { color: var(--text-muted); }
table.data td.actions { text-align: right; white-space: nowrap; }
table.data td.actions .iconbtn + .iconbtn { margin-left: var(--space-2); }
.tablefoot { display: flex; align-items: center; gap: var(--space-5); flex-wrap: wrap;
             margin-top: var(--space-5); font-size: var(--text-xs); color: var(--text-subtle); }
.tablefoot .grow { flex: 1; }

/* The identity cell: a letter tile and the name it belongs to. */
.idcell { display: flex; align-items: center; gap: var(--space-5); min-width: 0; }
.idtile { display: inline-grid; place-items: center; width: 30px; height: 30px; flex: none;
          border-radius: var(--radius-md); background: var(--surface-brand-soft);
          color: var(--text-brand); font-size: var(--text-sm);
          font-weight: var(--weight-semibold); }
.idcell .nm { font-weight: var(--weight-semibold); color: var(--text-strong);
              overflow-wrap: anywhere; }

/* KPI card. The accent edge is the only thing that varies. */
.stat { position: relative; background: var(--surface-card);
        border: var(--border-w) solid var(--border-subtle);
        border-radius: var(--radius-card); padding: var(--space-6) var(--space-6) var(--space-6) 18px;
        overflow: hidden; min-width: 0; }
.stat::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
                background: var(--stat-accent, var(--action-primary)); }
.stat .k { display: flex; align-items: center; gap: var(--space-4);
           font-size: var(--text-2xs); font-weight: var(--weight-semibold);
           letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--text-subtle); }
.stat .k .dot { width: 7px; height: 7px; border-radius: var(--radius-circle);
                background: var(--stat-accent, var(--action-primary)); margin-left: auto; flex: none; }
.stat .v { font-family: var(--font-display); font-size: var(--text-4xl);
           font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight);
           color: var(--text-strong); margin-top: var(--space-3); line-height: 1.05; }
.stat .v.sm { font-size: var(--text-2xl); }
.stat .s { font-size: var(--text-xs); color: var(--text-muted); margin-top: var(--space-3); }
/* Tone is an ATTRIBUTE, not a class. As classes these modifiers were bare
   words — .brand, .warn — and the app already had global rules of exactly
   those names from the old rail and the warning message, which the stat cards
   silently inherited: one became a 60px flex row, another shrank to
   width:fit-content. An attribute cannot be picked up by a class rule.

   A stat's accent names the STAGE its number is about, not the derived value
   it was computed from. Sourcing from the derived tokens was more literally
   faithful — the edge on "Ball with you" was the same colour as the ball dot
   on every row it counted — but activity-active, ball-you and status-applied
   are all indigo, so three of the four edges on the Dashboard came out the
   same and the distinction was invisible. Stage colours give four that differ:
   scheduled wears Interviewing, ball-with-you wears In conversation, sent
   wears Applied.

   The fourth is a total rather than a stage, so it gets no hue. border-strong
   is a light gray edge in light theme and its counterpart in dark; a literal
   light gray would have been the LOUDEST edge on the strip in dark theme,
   because the loam ramp is fixed and only the semantic tokens flip. */
.stat[data-tone="active"]    { --stat-accent: var(--activity-active-fg); }
.stat[data-tone="sched"]     { --stat-accent: var(--ball-sched); }
.stat[data-tone="you"]       { --stat-accent: var(--ball-you); }
.stat[data-tone="them"]      { --stat-accent: var(--ball-them); }
.stat[data-tone="applied"]   { --stat-accent: var(--status-applied-fg); }
.stat[data-tone="talking"]   { --stat-accent: var(--status-talking-fg); }
.stat[data-tone="interview"] { --stat-accent: var(--status-interview-fg); }
.stat[data-tone="offer"]     { --stat-accent: var(--status-offer-fg); }
.stat[data-tone="closed"]    { --stat-accent: var(--status-closed-fg); }
/* generic tones, for counts that are not about a status */
.stat[data-tone="quiet"]  { --stat-accent: var(--border-strong); }
.stat[data-tone="brand"]  { --stat-accent: var(--action-primary); }
.stat[data-tone="info"]   { --stat-accent: var(--status-info-fg); }
.stat[data-tone="warn"]   { --stat-accent: var(--status-warning-fg); }
.stat[data-tone="good"]   { --stat-accent: var(--status-success-fg); }
.stat[data-tone="danger"] { --stat-accent: var(--status-danger-fg); }
/* On Analytics the cards are plain: no edge, no dot. The number is the whole
   point there, so the colour belongs on it rather than on a rule beside it. */
.stat.plain { padding-left: var(--space-6); }
.stat.plain::before { display: none; }
.stat.plain .k .dot { display: none; }
.stat .v.accent { color: var(--stat-accent); }
.stat .up   { color: var(--status-success-fg); }
.stat .down { color: var(--status-danger-fg); }

/* Horizontal bars — the funnel and the by-portal breakdown are both this. */
.bars { display: grid; gap: var(--space-5); }
/* The bar IS the value — there is no empty channel behind it, and the count
   sits where the bar stops rather than in a column of its own, so the eye
   reads length and number as one thing. */
/* The count sits where the bar stops, so the longest bar must stop short of
   the column's end — otherwise a 100% bar fills the row and its number is
   pushed out on top of the percentage beside it. --bar-max is that headroom,
   and every width is a fraction of it, so the bars stay in proportion to each
   other rather than being squeezed one at a time. */
.bars { --bar-max: 84%; }
.bar { display: grid; grid-template-columns: minmax(90px, 160px) minmax(0, 1fr) auto;
       align-items: center; gap: var(--space-5); font-size: var(--text-sm); }
.bar .k { color: var(--text-muted); overflow-wrap: anywhere; }
.bar .run { display: flex; align-items: center; gap: var(--space-5); min-width: 0; }
.bar .fill { height: 26px; border-radius: var(--radius-sm); min-width: 4px;
             flex: 0 1 auto;                 /* a last-resort shrink, never an overlap */
             background: var(--bar-accent, var(--action-primary)); }
.bar .n { font-variant-numeric: tabular-nums; color: var(--text-strong);
          font-weight: var(--weight-semibold); flex: none; white-space: nowrap; }
.bar .pct { font-variant-numeric: tabular-nums; color: var(--status-success-fg);
            font-size: var(--text-xs); min-width: 5ch; text-align: right; }
.bar[data-tone="info"] { --bar-accent: var(--status-info-fg); }
.bar[data-tone="good"] { --bar-accent: var(--status-success-fg); }

.legend { display: grid; gap: var(--space-4); font-size: var(--text-sm); }
.legend li { display: flex; align-items: center; gap: var(--space-4); color: var(--text-muted); }
.legend .sw { width: 9px; height: 9px; border-radius: var(--radius-circle); flex: none; }

.donutwrap { display: flex; align-items: center; gap: var(--space-8); flex-wrap: wrap; }
.donut { position: relative; width: 136px; height: 136px; flex: none; }
.donut .mid { position: absolute; inset: 0; display: grid; place-content: center;
              text-align: center; gap: 2px; }
.donut .mid b { font-family: var(--font-display); font-size: var(--text-2xl);
                font-weight: var(--weight-bold); color: var(--text-strong); }
.donut .mid span { font-size: var(--text-2xs); color: var(--text-subtle); }

/* Vertical timeline with a rail down the icons. */
.lifecycle { display: grid; gap: var(--space-5); }
.lcitem { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-6);
          position: relative; }
.lcitem::before { content: ''; position: absolute; left: 13px; top: 34px;
                  bottom: calc(var(--space-5) * -1); width: 1px; background: var(--border-subtle); }
.lcitem:last-child::before { display: none; }
.lcdot { display: inline-grid; place-items: center; width: 27px; height: 27px; flex: none;
         border-radius: var(--radius-circle); background: var(--surface-page);
         border: var(--border-w) solid var(--border-default); color: var(--text-subtle);
         margin-top: var(--space-5); z-index: 1; }
.lcdot .lc { width: 14px; height: 14px; }
.lcitem.done .lcdot { border-color: var(--status-success-border); color: var(--status-success-fg); }
.lcitem.next .lcdot { border-color: var(--border-brand); color: var(--text-brand); }
.lcbody { background: var(--surface-card); border: var(--border-w) solid var(--border-subtle);
          border-radius: var(--radius-card); padding: var(--space-6); min-width: 0; }
.lcbody .t { display: flex; align-items: center; gap: var(--space-5); }
.lcbody .t b { flex: 1; font-size: var(--text-md); font-weight: var(--weight-semibold);
               color: var(--text-strong); overflow-wrap: anywhere; }
.lcbody .d { font-size: var(--text-sm); color: var(--text-muted); margin-top: var(--space-3);
             overflow-wrap: anywhere; }

/* A line that names the one thing to do next. */
.actionbar { display: flex; align-items: center; gap: var(--space-4);
             margin-top: var(--space-5); padding: var(--space-4) var(--space-5);
             border-radius: var(--radius-control); font-size: var(--text-sm);
             font-weight: var(--weight-medium);
             background: var(--status-warning-bg); color: var(--status-warning-fg); }
.actionbar[data-tone="good"] { background: var(--status-success-bg); color: var(--status-success-fg); }
.actionbar[data-tone="info"] { background: var(--status-info-bg); color: var(--status-info-fg); }

/* ---------------------------------------------------------------------------
   4 · CONTROLS
--------------------------------------------------------------------------- */

/* Segmented control: view switcher, theme switcher, anything with 2–4 states. */
.segmented { display: inline-flex; align-items: center; gap: 2px; flex: none;
             padding: 3px; border-radius: var(--radius-control);
             background: var(--surface-sunken);
             border: var(--border-w) solid var(--border-subtle); }
.segmented button { display: inline-grid; place-items: center; height: 28px;
                    padding: 0 var(--space-5); border-radius: var(--radius-sm);
                    color: var(--text-subtle); font-size: var(--text-xs);
                    font-weight: var(--weight-medium); transition: var(--transition-control); }
.segmented button:hover { color: var(--text-body); }
.segmented button[aria-pressed="true"] { background: var(--action-primary); color: var(--text-inverse); }
.segmented.icons button { width: 30px; padding: 0; }

.dropzone { display: grid; place-items: center; gap: var(--space-4); text-align: center;
            padding: var(--space-8) var(--space-6); border-radius: var(--radius-card);
            border: 1px dashed var(--border-default); color: var(--text-subtle);
            background: var(--surface-sunken); font-size: var(--text-sm);
            cursor: pointer; transition: var(--transition-control); }
.dropzone:hover, .dropzone.over { border-color: var(--border-brand); color: var(--text-brand);
                                  background: var(--surface-brand-soft); }

/* Sign in: what the app is on one side, the way in on the other. */
.authpage { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
            height: 100%; min-height: 0; }
.authpitch { position: relative; display: flex; flex-direction: column; justify-content: space-between;
             gap: var(--space-8); padding: var(--space-8) var(--space-9);
             background: linear-gradient(150deg,
               color-mix(in oklab, var(--action-primary) 24%, var(--surface-page)),
               var(--surface-page) 62%);
             border-right: var(--border-w) solid var(--border-subtle); overflow: hidden; }
.pitchcopy { max-width: 42ch; }
.pitchcopy h1 { font-family: var(--font-display); font-size: var(--text-4xl);
                font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight);
                color: var(--text-strong); text-wrap: balance; }
.pitchcopy p { font-size: var(--text-md); color: var(--text-muted); margin-top: var(--space-6);
               line-height: var(--leading-relaxed); text-wrap: pretty; }
.authform { display: grid; place-items: center; padding: var(--space-8); overflow: auto; }
.authbox { width: 100%; max-width: 380px; }
.authbox h2 { font-family: var(--font-display); font-size: var(--text-2xl);
              font-weight: var(--weight-bold); color: var(--text-strong); }
.authbox .sub { font-size: var(--text-sm); color: var(--text-muted); margin-top: var(--space-2);
                margin-bottom: var(--space-7); }
.authbox .btn.wide { margin-top: var(--space-6); }
body.is-mobile .authpage { grid-template-columns: minmax(0, 1fr); }
body.is-mobile .authpitch { display: none; }

/* Dashboard pieces. All of these are compositions of the card above — a row
   of facts, a row of buttons, and a quiet list row — not new surfaces. */
.schedmeta { display: flex; align-items: center; gap: var(--space-6); flex-wrap: wrap;
             font-size: var(--text-sm); color: var(--text-body); }
.schedmeta span { display: inline-flex; align-items: center; gap: var(--space-3); }
.schedmeta .lc { width: 15px; height: 15px; color: var(--text-subtle); }
.schedmeta b { font-weight: var(--weight-semibold); color: var(--text-strong); }
.cardacts { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap;
            margin-top: var(--space-6); }

/* A list row inside a flush card: name, context, and the one number that
   makes it worth looking at. */
.quietrow { display: flex; align-items: center; gap: var(--space-5); width: 100%;
            padding: var(--space-5) var(--space-6); text-align: left;
            border-bottom: var(--border-w) solid var(--border-subtle);
            transition: var(--transition-control); }
.quietrow:last-child { border-bottom: 0; }
.quietrow:hover { background: var(--surface-raised); }
.quietrow .body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.quietrow b { font-size: var(--text-md); font-weight: var(--weight-semibold);
              color: var(--text-strong); overflow-wrap: anywhere; }
.quietrow .muted { font-size: var(--text-xs); color: var(--text-muted); overflow-wrap: anywhere; }
.quietrow .silent { flex: none; font-size: var(--text-xs); font-weight: var(--weight-semibold);
                    color: var(--status-warning-fg); white-space: nowrap; }

.filedesc { display: block; font-size: var(--text-xs); color: var(--text-subtle);
            margin-top: 2px; overflow-wrap: anywhere; }
.iconbtn.danger:hover { color: var(--status-danger-fg); background: var(--status-danger-bg); }

/* Record-page pieces. Prose, bullets, a quoted excerpt and a file chip — all
   used by more than one screen, none of them screen-specific. */
.prose { font-size: var(--text-sm); color: var(--text-body); line-height: var(--leading-relaxed);
         max-width: var(--prose-max); white-space: pre-wrap; text-wrap: pretty; }
.quote { font-size: var(--text-sm); color: var(--text-muted); line-height: var(--leading-relaxed);
         max-width: var(--prose-max); font-style: italic; margin-top: var(--space-5);
         padding-left: var(--space-6); border-left: 2px solid var(--border-subtle); }
.bullets { display: grid; gap: var(--space-4); font-size: var(--text-sm);
           color: var(--text-body); max-width: var(--prose-max); }
.bullets li { display: grid; grid-template-columns: auto minmax(0,1fr); gap: var(--space-4);
              line-height: var(--leading-normal); }
.bullets li::before { content: '·'; color: var(--text-subtle); }
.filechip { display: inline-flex; align-items: center; gap: var(--space-3);
            padding: var(--space-3) var(--space-5); border-radius: var(--radius-control);
            background: var(--surface-sunken); border: var(--border-w) solid var(--border-subtle);
            font-size: var(--text-sm); color: var(--text-body); }
.filechip .lc { width: 14px; height: 14px; color: var(--text-subtle); }
.backbtn { flex: none; }

/* One queued upload, waiting to be described. */
.uprow { padding: var(--space-6) 0; border-bottom: var(--border-w) solid var(--border-subtle); }
.uprow:first-of-type { padding-top: 0; }
.uprow:last-of-type { border-bottom: 0; padding-bottom: 0; }
.uphead { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap;
          margin-bottom: var(--space-5); }
.uphead .grow { flex: 1; }

/* Visually hidden, still read aloud. */
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden;
      clip-path: inset(50%); white-space: nowrap; }

.sortpick select { min-width: 176px; }
.ballcell { display: inline-flex; align-items: center; gap: var(--space-4); white-space: nowrap; }

/* Tag tones. A tag is a word, not a status — the tone only helps you find the
   same word again, so it is derived from the word itself. */
.tags { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
/* Seven hues, each one a token that already flips with the theme. Only the ink
   is set — the outline and the wash are mixed from it by .tag itself. */
.tag.t0 { --tag-ink: var(--status-info-fg); }
.tag.t1 { --tag-ink: var(--status-success-fg); }
.tag.t2 { --tag-ink: var(--text-brand); }
.tag.t3 { --tag-ink: var(--status-warning-fg); }
.tag.t4 { --tag-ink: var(--status-danger-fg); }
.tag.t5 { --tag-ink: var(--status-talking-fg); }
.tag.t6 { --tag-ink: var(--status-accepted-fg); }

/* ---------------------------------------------------------------------------
   5 · MOBILE
   Nothing here is a narrowed desktop. Columns become stacks, tables become
   cards, the app bar keeps only what a thumb needs.
--------------------------------------------------------------------------- */
body.is-mobile .appbar { padding: 0 var(--page-pad-mobile); gap: var(--space-4); }
body.is-mobile .appbar-nav { display: none; }
body.is-mobile .page { padding: var(--space-6) var(--page-pad-mobile) 96px; }
body.is-mobile .pagehead { flex-direction: column; gap: var(--space-5); }
body.is-mobile .pagehead h1 { font-size: var(--text-2xl); }
body.is-mobile .pagehead .acts { width: 100%; }
body.is-mobile .pagehead .acts .btn { flex: 1; }
body.is-mobile .toolbar .search { flex: 1 1 100%; }
/* the view switch sits at the right edge, where the thumb is */
body.is-mobile .toolbar .segmented { margin-left: auto; }
body.is-mobile .cols-2, body.is-mobile .cols-3,
body.is-mobile .cols-main { grid-template-columns: minmax(0, 1fr); }
/* Counts stay two across — a single column of four turns the top of the phone
   Dashboard into a scroll before a single job is visible. They shrink to suit. */
body.is-mobile .cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); }
body.is-mobile .stat { padding: var(--space-5) var(--space-5) var(--space-5) 14px; }
body.is-mobile .stat .k { font-size: 10px; letter-spacing: var(--tracking-wide); }
body.is-mobile .stat .v { font-size: var(--text-2xl); }
body.is-mobile .stat .v.sm { font-size: var(--text-lg); }
body.is-mobile .stat .s { font-size: 11px; }

/* A phone has no keyboard, so nothing may spend space naming its shortcuts. */
body.is-mobile .kbd, body.is-mobile .keyhint { display: none; }
body.is-mobile .card { padding: var(--space-6); }
body.is-mobile .metagrid { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: var(--space-5); }
body.is-mobile .bar { grid-template-columns: minmax(72px, 1fr) minmax(0, 1.3fr) auto auto; gap: var(--space-4); }
body.is-mobile .donutwrap { gap: var(--space-6); }

/* A table on a phone is not a table with its cells stacked — that gives one
   labelled block per column and a 378px row for a single job. It is a LIST
   CARD: identity and its trailing control on one line, the secondary facts
   joined into one muted line under it, tags last. One component, used by both
   table screens, so the two never drift apart. */
body.is-mobile .tablewrap { background: none; border: 0; border-radius: 0; overflow: visible; }
body.is-mobile .tablescroll { overflow-x: visible; }

.listcards { display: flex; flex-direction: column; gap: var(--space-4); }
.listcard { display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
            align-items: center; gap: var(--space-3) var(--space-5);
            width: 100%; text-align: left; padding: var(--space-6);
            background: var(--surface-card); border-radius: var(--radius-card);
            border: var(--border-w) solid var(--border-subtle);
            transition: var(--transition-control); }
.listcard:hover { border-color: var(--border-strong); }
.listcard > .tile { grid-row: 1 / span 2; }
.listcard .nm { font-size: var(--text-md); font-weight: var(--weight-semibold);
                color: var(--text-strong); overflow-wrap: anywhere; }
.listcard .trail { grid-column: 3; grid-row: 1; justify-self: end; display: flex;
                   align-items: center; gap: var(--space-2); }
.listcard .meta { grid-column: 2 / -1; font-size: var(--text-xs); color: var(--text-muted);
                  overflow-wrap: anywhere; }
.listcard .meta .sep { color: var(--text-disabled); margin: 0 var(--space-2); }
.listcard .tags { grid-column: 2 / -1; margin-top: var(--space-2); }
