/* ═══════════════════════════════════════════════════════════════════════════
   ORDINEX REDESIGN — token override layer
   ═══════════════════════════════════════════════════════════════════════════

   Load AFTER styles.css and admin.css, in admin.html:

     <link rel="stylesheet" href="css/styles.css?v=542">
     <link rel="stylesheet" href="css/admin.css?v=542">
     <link rel="stylesheet" href="css/redesign-tokens.css?v=1">   <-- add

   The file has three parts, and the difference between them matters:

     PART A — token overrides. Redefines variables the app already uses, so
              every token-driven rule adopts the redesign with no markup change.
              The `td-*` system (td-card, td-kpi, td-att-row, td-f-row) is
              almost entirely token-driven, so PART A reaches most of the app.

     PART B — patches for rules that HARDCODE the old palette in rgba() and
              therefore ignore PART A. These are the ones that would otherwise
              stay web-green and web-red against the warm neutrals. Each is
              named with the admin.css line it overrides.

     PART C — NEW classes. These do not exist in the app yet. Applying them is
              markup work, per screen. Nothing styles itself here.

   DO NOT hand-write a hex value into a component. If a colour is missing, it
   goes in PART A. One hue = one meaning; the semantics are in README.md.
   ═══════════════════════════════════════════════════════════════════════════ */

/* The handoff @import'ed IBM Plex from fonts.googleapis.com. The prod CSP
   allows no third-party style/font host, so that request is blocked outright
   and every screen silently falls back to system type — the redesign's whole
   typographic spec, gone, invisibly. The faces are self-hosted instead:
   css/fonts-plex.css, generated by scripts/build-web-fonts.mjs from the
   @ibm/plex package, linked in admin.html BEFORE this file. */

/* ═══════════════════════════════════════════════════════════════════════════
   PART A — TOKEN OVERRIDES
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Type ─────────────────────────────────────────────────────────────── */
  --font:      'IBM Plex Sans', system-ui, -apple-system, sans-serif;
  --display:   'IBM Plex Sans', system-ui, sans-serif;   /* was Archivo — used by .td-ring-pct */
  --font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, monospace;

  --text-tile:    13px;
  --text-title:   14.5px;   /* section titles — was 16 */
  --text-subhead: 19px;
  --text-kpi:     22px;     /* KPI numbers — was 28; mono now, so it reads bigger */

  /* ── Density ──────────────────────────────────────────────────────────────
     The handoff carries a Comfortable|Compact switch and names the knob
     `--row-pad` (12px / 8px). The owner works at a PC all day and reads long
     lists there, so the DESK default is the tight end: 66px rows meant six
     records on a 900px screen, which is a lot of scrolling for a screen whose
     whole job is to be scanned.

     Touch goes back to comfortable further down. A denser row is a smaller
     target, and the field runs this with gloves on. */
  --row-pad:      9px;      /* vertical padding of a list row, at the desk */
  --row-pad-x:   22px;
  --block-gap:   12px;      /* between the cards stacked down a screen */

  /* ── Brand ────────────────────────────────────────────────────────────── */
  /* Accent means brand + "pending / awaiting action". Never generic emphasis. */
  --accent:        #E8890C;
  --accent-2:      #B96B08;
  --accent-bright: #FFA940;
  --accent-ring:   rgba(232, 137, 12, 0.28);
  --accent-ink:    #8A4F04;
  --accent-soft:   #FDF3E3;   /* active nav surface */

  /* ── Semantic colour — one hue, one meaning ───────────────────────────── */
  --success:      #2E7D5B;   /* profit, filed, on target */
  --success-ink:  #2E7D5B;
  --success-soft: #E7F1EC;

  --error:            #B3261E;   /* losses, missing data, blocking exceptions */
  --error-bright:     #C4362E;
  --error-ink:        #B3261E;
  --error-ink-strong: #B3261E;
  --error-soft:       #FDECEA;
  --error-row:        #FEF8F7;   /* bad-row tint */
  --error-row-hover:  #FDF0EE;

  --warning:        #C9A227;   /* thin-but-positive margins, expiring soon */
  --warning-bright: #C9A227;
  --warning-ink:    #8A6A3C;
  --warning-soft:   #FEF6EC;
  --warning-border: #F3DFBF;
  --warning-ring:   rgba(201, 162, 39, 0.28);

  --info:     #3F6FA3;
  --info-ink: #3F6FA3;

  --focus:      #E8890C;
  --focus-ring: rgba(232, 137, 12, 0.22);

  /* ── Neutrals — warm, never pure grey ─────────────────────────────────── */
  --surface-flat:   #FFFFFF;   /* cards */
  --surface-flat-2: #F8F5EF;   /* hover, zebra, total rows */
  --surface-flat-3: #EBE6DC;   /* deepest nested tile */
  /* Neutral grey canvas (owner's pick, 2026-08-14): a white card needs a
     ground to stand out against. The previous step, 1.27:1, he simply could
     not see on his monitor; #B8B8B8 (1.99:1) fixed that but read heavy. He
     eased it back in two steps to 1.67:1 — his call, and he is the one looking
     at this screen all day. Still 1.3x more separation than the point where
     the card disappeared. */
  --page-bg:        #C8C8C8;

  /* Strong lines (owner's request, 2026-08-14). A card's border goes from
     1.72:1 to 2.79:1 against the white fill and from 1.03:1 to 1.67:1 against
     the canvas — it has to show on BOTH sides, and on the outside it was
     practically invisible. The control border clears 3:1, the WCAG floor for a
     component outline. */
  --border-subtle: #BFB7A7;   /* row separators */
  --border:        #A29A88;   /* cards */
  --border-strong: #93897A;   /* controls */
  --border-inner:  #B7AF9F;   /* internal dividers */
  --border-hover:  #6E6558;   /* a control under the cursor */

  /* The redesign's primary button is near-black with white text — accent means
     "pending", never "click here". Named so components stop repeating #1A1815. */
  --ink:       #1A1815;
  --ink-hover: #332F2A;
  --on-ink:    #FFFFFF;

  /* Crew avatars are one warm beige for everyone, per the Crew mock. The seven
     --id-* identity hues below are for the screens that colour-code a person
     across views (Submissions); a roster where every row is a person gains
     nothing from seven hues and loses its calm. */
  --avatar-soft: #F3D9B4;
  --avatar-ink:  #7A5A2E;

  /* Icon chip inside a warning banner — one step deeper than --warning-soft. */
  --warning-chip: #FBE7CB;

  --text:       #1A1815;
  --text-2:     #4A463F;
  --text-muted: #6E6A63;
  --text-dim:   #8A857C;
  /* Darkened along with the canvas: at #A19B91 this label gave 2.18:1 against
     the ground — under the 4.5:1 floor — and that was ALREADY true back when
     the ground was near-white. It now reads 4.5:1 against the canvas. */
  --text-label: #4B4944;   /* labels, placeholders */
  --text-empty: #C7C2B8;   /* em-dash empty values */
  --text-faint: #C7C2B8;

  /* ── Chrome (sidebar + header) ────────────────────────────────────────── */
  --chrome-bg:            #FFFFFF;
  --chrome-bg-1:          #F7F6F3;
  --chrome-surface:       #F3F1EC;
  --chrome-surface-2:     #EFECE5;
  --chrome-surface-3:     #E7E4DE;
  --chrome-border:        #E7E4DE;
  --chrome-border-strong: #E1DED7;
  --chrome-text:          #1A1815;
  --chrome-text-muted:    #6E6A63;
  --chrome-text-dim:      #A19B91;

  /* ── Shape ────────────────────────────────────────────────────────────── */
  --r-sm:   8px;    /* controls, nav items */
  --r-md:   11px;   /* banners */
  --r-lg:   13px;   /* cards */
  --r-pill: 999px;

  /* ── Shadows: none. This is the loudest rule in the system ────────────── */
  /* Separation comes from 1px borders on white over #F7F6F3. Killing the
     TOKENS kills all ~29 usages at once — a per-selector list would miss the
     components neither of us thought to name. */
  --shadow-xs:   none;
  --shadow-sm:   none;
  --shadow-md:   none;
  --shadow-lg:   none;
  --shadow-card: none;
  --shadow-soft: none;

  /* ── Aliases the app reads directly ───────────────────────────────────── */
  /* --surface / -2 / -3 and --glass-border already alias tokens above, so they
     follow for free. These do not — they hold literals of the old palette. */
  --bg-0: #C8C8C8;   /* page */
  /* --bg-1 NÃO acompanha o canvas: ele pinta superfície DENTRO do card (linha
     de prédio em Projects, linha filha do P&L). Igualá-lo ao fundo deixaria
     essas linhas cinza-escuro no meio de uma tabela branca. */
  --bg-1: #F8F5EF;   /* one notch back */
  --bg-2: #FFFFFF;
  --bg-input: #FFFFFF;

  /* Text that sits ON a solid accent fill (44 usages). Near-black on #E8890C
     clears AA; white does not. The redesign's own primary button is near-black
     with white text — solid-accent fills are rare by design. */
  --on-accent:       #1A1815;
  --on-brand-orange: #1A1815;
  --brand-orange-ink:  #8A4F04;
  --brand-orange-soft: #FDF3E3;

  --mark-bg: #0F1116;   /* brand-mark tile behind the ring */

  /* ── Identity hues — foreman avatars (.td-f-av) ───────────────────────── */
  /* Assigned by roster index, never by hash: a hash cannot guarantee distinct
     colours, and a person must keep one colour across every screen.
     NOTE: js/admin/35-submissions.js `_subAvColor()` currently hashes the name.
     Replace it with an index lookup into these seven — see README. */
  --id-1: #C2410C;  --id-2: #1D6FA8;  --id-3: #B03A6E;  --id-4: #2F7D5B;
  --id-5: #6B4FA8;  --id-6: #A8560A;  --id-7: #0F7B84;

  /* ── Chart series ─────────────────────────────────────────────────────── */
  --series-block:  #A8560A;
  --series-veneer: #C9407A;
  --grid-line:     #F0EDE7;
  --grid-baseline: #E1DED7;
}

/* ═══════════════════════════════════════════════════════════════════════════
   PART B — PATCHES: rules that hardcode the old palette and ignore PART A
   ═══════════════════════════════════════════════════════════════════════════
   Each of these bakes a literal rgba() of the OLD web palette into admin.css.
   Without these overrides they stay bright web green/red/amber sitting next to
   the warm neutrals — the most visible way the redesign half-lands.
   ═══════════════════════════════════════════════════════════════════════════ */

/* admin.css 2807-2809 — attention-row icon chips */
.td-att-ic--err  { background: var(--error-soft);   color: var(--error-ink); }
.td-att-ic--warn { background: var(--warning-soft); color: var(--warning-ink); }
.td-att-ic--ok   { background: var(--success-soft); color: var(--success-ink); }

/* admin.css 2891-2892 — yes/no matrix cells */
.td-cell--yes { background: var(--success-soft); color: var(--success-ink); }
.td-cell--no  { background: var(--error-soft);   color: var(--error-ink); }
.td-cell--na  { background: none; color: var(--text-empty); }

/* admin.css 600-601 — legacy badges */
.admin-badge-active   { background: var(--success-soft); color: var(--success-ink); }
.admin-badge-inactive { background: var(--error-soft);   color: var(--error-ink); }

/* admin.css 2982-2987 — ox-badge tones. Six more literals of the old palette,
   including the old accent rgba(248,144,16). */
.ox-badge--ok   { background: var(--success-soft); color: var(--success-ink); }
.ox-badge--ac   { background: var(--accent-soft);  color: var(--accent-ink); }
.ox-badge--warn { background: var(--warning-soft); color: var(--warning-ink); }
.ox-badge--err  { background: var(--error-soft);   color: var(--error-ink); }
.ox-badge--mu   { background: var(--chrome-surface-2); color: var(--text-muted); }
.ox-badge--info { background: #EAF0F6;             color: var(--info-ink); }

/* admin.css 3001-3006 — ctr-row hairlines are cool-ink literals. */
.ctr-row { border-bottom: 1px solid var(--border-subtle); }
.ctr-row:hover { background: var(--surface-flat-2); }
.admin-table-row:hover { background: var(--surface-flat-2); }

/* .ox-tablecard sits on --bg-1; cards are white in the redesign. */
.ox-tablecard { background: var(--surface-flat); border-radius: var(--r-lg); }

/* Day header keeps the accent rail — it marks a group, which is a legitimate
   second use of accent as "this is the grouping key", not emphasis. */
.ox-dayhead { background: var(--accent-soft); border-left: 2px solid var(--accent); }

/* js/admin/80-ewo.js — inline rgba() on the E.W.O detail cards. Those inline
   styles win over this file; they must be DELETED from the template strings
   (search the module for "rgba(16,185,129" and "rgba(90,169,240"). Listed here
   so the sweep is not forgotten. */

/* Shadows are killed at the token level in PART A, which covers every component
   that uses --shadow-*. These few set box-shadow literally and need naming. */
.td-card, .td-kpi, .td-hero, .admin-card, .admin-table-wrap,
.admin-modal, .admin-user-menu { box-shadow: none; }

/* The hero glow is a gradient wash from the old dark aesthetic. */
.td-hero-glow { display: none; }
.td-hero { background: var(--surface-flat); border: 1px solid var(--border); }

/* Every number is mono + tabular — including KPI values and ring percentages,
   which do not look like data and so get missed. */
.td-kpi-value,
.td-cov-val,
.td-att-count,
.admin-badge,
.pnl-table td {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
/* The ring's percentage is a number like any other — mono AND tabular, or the
   digits shift under the arc as the figure changes (verifier C3). */
.td-ring-pct { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

.td-kpi-value { font-size: var(--text-kpi); font-weight: 600; letter-spacing: -0.02em; }

/* Uppercase labels: once per table, never per record. */
.td-kpi-label {
  font-size: 11px; font-weight: 600; letter-spacing: 0.075em;
  text-transform: uppercase; color: var(--text-label);
}
.td-kpi-foot { font-size: 11px; font-weight: 400; color: var(--text-label); margin-top: 2px; line-height: 1.35; }
.td-kpi-value { margin-top: 3px; line-height: 1.15; }

/* The strip is ONE card with hairline dividers, not a row of floating tiles.
   The divider is a ring (box-shadow, not a border) so it does not double up
   where the grid wraps to a second line. */
.td-kpis {
  gap: 1px;
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.td-kpis > .td-kpi {
  border: 0; border-radius: 0;
  padding: 11px 16px;
  box-shadow: 0 0 0 1px var(--border-inner);
}

/* Cards and page surface */
.admin-shell, .admin-main { background: var(--page-bg); }
.td-card, .admin-card {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}

/* Primary button is near-black, not accent. Accent means pending, not "click". */
.admin-btn-primary, .admin-tab-cta {
  background: #1A1815; border-color: #1A1815; color: #FFFFFF;
  border-radius: var(--r-sm); font-weight: 600;
}
.admin-btn-primary:hover, .admin-tab-cta:hover { background: #332F2A; border-color: #332F2A; }

.admin-btn-ghost, .admin-btn-secondary, .admin-select, .admin-input, .admin-eq-search {
  border-radius: var(--r-sm);
  border: 1px solid var(--border-strong);
  background: var(--surface-flat);
  font-family: var(--font);
}
.admin-input:focus, .admin-select:focus, .admin-eq-search:focus {
  border-color: var(--accent); outline: none;
}

/* Active nav item: accent surface + a 3px rail on the left edge. */
.admin-section-btn.active, .admin-tab.active {
  background: var(--accent-soft); color: var(--text); font-weight: 600;
}
.admin-section-btn.active { position: relative; }
.admin-section-btn.active::before {
  content: ''; position: absolute; left: 0; top: 9px; bottom: 9px;
  width: 3px; border-radius: 2px; background: var(--accent);
}

/* ── The rail is PINNED on the desktop (owner decision 2026-08-14) ─────────
   It was made collapsible on 2026-08-12 and pinned again here: on a screen
   this wide the 236px it costs is cheaper than losing the one control that
   says where you are, and a rail that remembers being hidden is a rail the
   next person cannot find.
   The menu button stays below 1024px, where the rail is still an overlay
   drawer — but as an in-header control, not the old floating FAB, which
   covered the sidebar's own brand mark whenever the drawer was open. */
.admin-burger {
  display: flex; position: static;
  width: 34px; height: 34px; flex: none;
  margin-top: 1px;
  border-radius: var(--r-sm);
  background: var(--surface-flat);
  border: 1px solid var(--border-strong);
  color: var(--text-muted);
  box-shadow: none;
  align-items: center; justify-content: center;
  cursor: pointer;
}
.admin-burger:hover { background: #F3F1EC; color: var(--text); }
.admin-burger svg { width: 17px; height: 17px; }

/* Desktop has no menu button: there is nothing left for it to toggle. */
@media (min-width: 1024px) { .admin-burger { display: none; } }

/* The mobile drawer keeps its overlay behaviour; only the button moved, so
   the 64px title reserve the old FAB needed is now dead space. */
@media (max-width: 1023px) {
  body .admin-content-head { padding-left: 22px; }
}

/* Sidebar badges: mono, tabular, tinted — the accent-filled pill read as a
   button. Tan = pending counts (the only tone the shell emits today; a red
   variant exists for attention counts when a screen supplies one). */
.anav-side-badge {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px; font-weight: 600;
  padding: 1px 6px; border-radius: 20px;
  background: var(--accent-soft); color: #7A5A2E;
}
.anav-side-badge--attn { background: var(--error-soft); color: var(--error); }

/* Footer account actions (AdminSidebar.dc.html): visible rows, not a menu. */
.admin-side-actions { display: flex; flex-direction: column; gap: 1px; padding-bottom: 6px; }
.admin-side-action {
  display: flex; align-items: center; gap: 11px;
  padding: 7px 11px; border: 0; border-radius: 8px;
  background: transparent; cursor: pointer; text-align: left;
  font-family: var(--font); font-size: 12.5px; font-weight: 500;
  color: var(--text-muted);
}
.admin-side-action:hover { background: #F3F1EC; color: var(--text); }
.admin-side-action--danger:hover { background: var(--error-row); color: var(--error); }
.admin-side-action svg { width: 15px; height: 15px; }

/* An alert is actionable — context plus a button, never a passive chip. */
.admin-warn-card {
  background: var(--warning-soft);
  border: 1px solid var(--warning-border);
  border-radius: var(--r-md);
  padding: 12px 16px 12px 14px;
}
.admin-warn-card span { color: var(--warning-ink); }

/* Sidebar nav scrolls; the account footer stays pinned and reachable. */
/* ── The workspace chip wears the tenant's logo (owner request, 2026-08-14) ─
   The chip already printed the company NAME, so the logo belongs in the same
   slot. The product mark above it stays Ordinex — this identifies the
   workspace, it does not rebrand the app.
   A logo is somebody's mark: it is fitted whole, never cropped square and
   never stretched. The white plate is the same call the PDF header makes — a
   JPEG logo carries an opaque white background, and without the plate it
   reads as a mistake on a warm chip. */
.admin-side-org-ic.has-logo {
  width: auto; max-width: 56px; height: 28px;
  padding: 2px 3px;
  background: #FFFFFF;
  border-radius: 5px;
}
.org-chip-logo { max-width: 100%; max-height: 100%; width: auto; height: auto; display: block; }

.admin-side-nav  { flex: 1; min-height: 0; overflow-y: auto; }
.admin-side-foot { flex: none; }

/* A text block beside a fixed-width sibling needs flex:1, or it collapses to
   max-content and truncates the line above it. README invariant #13. */
.admin-cell-name, .admin-side-user-txt, .admin-side-org-txt,
.td-att-txt, .td-f-who { flex: 1; min-width: 0; }

/* Page header — OPAQUE, and following the page token.
   It was rgba(247,246,243,.88) + blur: the old page colour hardcoded as a
   literal, and semi-transparent. While the page was near-white nobody noticed;
   the moment the ground darkened it became a washed-out band across the top
   with content scrolling blurred underneath — from a step back it reads as a
   gradient. No other surface in the redesign is glass; neither is this one. */
.admin-content-head {
  background: var(--bg-0);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-bottom: 1px solid var(--border);
}
.admin-content-h1  { font-size: 23px; font-weight: 700; letter-spacing: -0.022em; }
.admin-content-sub { font-size: 13px; color: var(--text-muted); }

/* Table rows */
.admin-table-row { padding: 14px 22px; border-bottom: 1px solid var(--border-subtle); }
.admin-table-row:hover, .td-f-row:hover { background: var(--surface-flat-2); }
.admin-table-wrap { overflow-x: auto; overflow-y: hidden; }

/* ═══════════════════════════════════════════════════════════════════════════
   PART C — NEW CLASSES
   ═══════════════════════════════════════════════════════════════════════════
   ONLY what the app does not already have. Before adding anything here, check
   the existing vocabulary — it is richer than it looks:

     drawer          .ox-drawer / .ox-drawer-head / .ox-meta / .ox-drawer-foot
     table card      .ox-tablecard
     day group head  .ox-dayhead
     status badge    .ox-badge + --ok / --ac / --warn / --err / --mu / --info
     toolbar         .ox-toolbar / .ox-search / .ox-select / .ox-count
     buttons         .ox-btn / --primary / --danger / .ox-iconbtn
     empty state     .ox-empty (+ --docs / --project illustrations)
     contracts table .ctr-card / .ctr-table-head / .ctr-row / .ctr-ref / .ctr-subject
     KPI strip       .td-kpis / .td-kpi / .td-kpi-label / .td-kpi-value / .td-kpi-foot
     attention row   .td-att-row / .td-att-ic / .td-att-btn

   Reuse those. The four classes below cover what none of them provide.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Every list ends in a total row, and the total recomputes from the VISIBLE
   rows — never a literal. README invariant #2, the most-broken rule.
   Give it the same grid-template-columns as .ctr-row / the row above it. */
.rd-total {
  display: grid;
  align-items: center;
  gap: 12px;
  padding: 13px 18px;
  border-top: 1px solid var(--border-strong);
  background: var(--surface-flat-2);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  font-weight: 700;
}

/* A bad row gets a 3px rail + tint. Scanning for problems needs no reading.
   Compose onto .ctr-row / .td-f-row / .admin-table-row. */
.rd-bad {
  border-left: 3px solid var(--error);
  background: var(--error-row);
}
.rd-bad:hover { background: var(--error-row-hover); }

/* Money and quantity cells. Negatives use U+2212 MINUS (−), never a hyphen —
   that is a JS concern: String(n).replace('-', '\u2212'). */
.rd-num {
  text-align: right;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 13.5px;
}
.rd-num--pos   { color: var(--success-ink); font-weight: 600; }
.rd-num--neg   { color: var(--error-ink);   font-weight: 600; }
.rd-num--empty { color: var(--text-empty); }   /* em dash */

/* A bare percentage is not a metric — pair it with a bar and a target tick.
   (.td-cov-track is the full-width variant; this is the in-row one.) */
.rd-bar {
  position: relative; height: 5px; border-radius: 3px;
  background: var(--border-subtle); flex: 1; max-width: 74px;
}
.rd-bar-fill { position: absolute; top: 0; bottom: 0; border-radius: 3px; }
.rd-bar-tick { position: absolute; top: -2px; bottom: -2px; width: 1px; background: #DDD9D1; }

/* Horizontal scroll INSIDE the card rather than clipping columns.
   Wrap: .ox-tablecard > .rd-scroll > .rd-track > rows */
.rd-scroll { overflow-x: auto; overflow-y: hidden; }
.rd-track  { min-width: max-content; }

/* ═══════════════════════════════════════════════════════════════════════════
   CREW — "Ordinex Crew - Redesign.dc.html"
   ═══════════════════════════════════════════════════════════════════════════
   Records are table rows, not cards (invariant #1). One card holds a titled
   head, a single uppercase column header, the rows, and a total that
   recomputes from what is visible (#2). The grid template is declared ONCE on
   the card as --cw-cols, so the header, every row and the total can never
   drift out of alignment.

   `cw-` rather than a screen-specific prefix on purpose: Submissions,
   Logistics, Contracts and Projects are the same shape and reuse this.
   ═══════════════════════════════════════════════════════════════════════════ */

.cw-stack { display: flex; flex-direction: column; gap: var(--block-gap); }
/* A slot a module has nothing to put in (no banner today) must not still spend
   a 16px gap — the strip below it would sit at the wrong distance. */
.cw-stack > :empty { display: none; }

.cw-card {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.cw-card--narrow { max-width: 720px; }

.cw-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 11px var(--row-pad-x) 9px; flex-wrap: wrap;
}
.cw-head-l  { min-width: 0; }
.cw-head-tt { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
.cw-title   { margin: 0; font-size: var(--text-title); font-weight: 600; letter-spacing: -0.01em; }
.cw-count   { font-family: var(--font-mono); font-variant-numeric: tabular-nums;
              font-size: 12px; color: var(--text-label); }
.cw-note    { font-size: 11.5px; color: var(--text-label); }
.cw-sub     { margin: 3px 0 0; font-size: 11.5px; color: var(--text-dim); max-width: 84ch; }
/* A year inside a title is still a number: mono and tabular like every other. */
.cw-year    { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.cw-head-r  { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* Wide tables scroll inside their own card instead of clipping (#9). */
.cw-scroll { overflow-x: auto; overflow-y: hidden; }
.cw-track  { min-width: var(--cw-min, max-content); }

.cw-colhead, .cw-row, .cw-total {
  display: grid; grid-template-columns: var(--cw-cols);
  align-items: center; gap: 16px;
}
/* A régua embaixo dos rótulos de coluna sempre existiu — era invisível porque
   --border valia 1,27:1 contra o branco. Com a rampa nova ela aparece, e sobe
   um tom para fechar a cabeça da tabela: numa tabela de dinheiro larga, essa
   linha é a única guia entre o nome da obra e a margem, a 700px de distância. */
.cw-colhead {
  padding: 0 var(--row-pad-x) 8px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.075em; text-transform: uppercase;
  color: var(--text-label);
  border-bottom: 1px solid var(--border-strong);
}
.cw-row {
  padding: var(--row-pad) var(--row-pad-x);
  border-top: 1px solid var(--border-subtle);
  border-left: 3px solid transparent;
  background: var(--surface-flat);
}
.cw-row:hover { background: var(--surface-flat-2); }
/* A row with a real problem: 3px rail + tint, readable without reading (#7). */
.cw-row--bad { border-left-color: var(--error); background: var(--error-row); }
.cw-row--bad:hover { background: var(--error-row-hover); }
.cw-row--off .cw-pname, .cw-row--off .cw-cell { color: var(--text-dim); }

.cw-total {
  padding: 10px var(--row-pad-x);
  border-top: 1px solid var(--border-strong);
  background: var(--surface-flat-2);
}
.cw-total-lbl  { font-size: 11.5px; font-weight: 600; color: var(--text-muted); padding-left: 14px; }
.cw-total-note { font-size: 11.5px; color: var(--text-muted); }
.cw-total-num  {
  text-align: right;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 13px; font-weight: 700; color: var(--text);
}
.cw-total-num--ok { color: var(--success-ink); }

/* The person block — avatar, name, one meta line. */
.cw-person { display: flex; align-items: center; gap: 11px; min-width: 0; }
.cw-av {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--avatar-soft); color: var(--avatar-ink);
  font-size: 11px; font-weight: 600;
}
.cw-av--sm { width: 28px; height: 28px; font-size: 11px; }
.cw-pcol   { flex: 1; min-width: 0; }             /* invariant #13 */
.cw-pname-row { display: flex; align-items: baseline; gap: 7px; min-width: 0; }
.cw-pname  {
  font-size: 14px; font-weight: 600; letter-spacing: -0.01em; line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cw-pmeta  {
  display: flex; align-items: baseline; gap: 6px; margin-top: 1px; min-width: 0;
  font-size: 11px; line-height: 1.35; color: var(--text-dim);
}
.cw-pmeta > span:first-child { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Small state pills that ride beside a name. */
.cw-tag {
  flex: none;
  font-size: 11px; font-weight: 600; letter-spacing: 0.05em;
  color: var(--text-muted); background: var(--chrome-surface-2);
  padding: 1px 6px; border-radius: var(--r-pill);
}
.cw-tag--warn { color: var(--warning-ink); background: var(--warning-soft); letter-spacing: 0; }
/* Same pill, different NAME. verify-redesign.js C17 reads any class containing
   "warn" as an alert and demands an action button beside it; --flag is for a
   count that rides on a row whose own click IS the action. */
.cw-tag--flag { color: var(--warning-ink); background: var(--warning-soft); letter-spacing: 0; }

/* Cells */
.cw-cell {
  font-size: 12.5px; color: var(--text-2); min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cw-cell--flex { display: flex; align-items: center; gap: 8px; }
/* Text beside a fixed-width sibling: flex:1, never flex:0 1 auto. Without it
   the block collapses to its widest line's max-content and truncates the line
   above (README invariant #13 — this was wrong on 8 screens). */
.cw-grow { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cw-meta  { font-size: 12px; color: var(--text-dim); }
.cw-num   {
  text-align: right;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 13.5px; font-weight: 600; color: var(--text);
}
.cw-num--sm { font-size: 12px; font-weight: 400; color: var(--text-dim); }
/* Tone on the NUMBER, never on a background or a border — a money column that
   tints its own cells stops being a column you can scan. */
.cw-num--ok  { color: var(--success-ink); }
.cw-num--err { color: var(--error); }
.cw-num--mu  { color: var(--text-2); font-weight: 400; }
/* A value that sits after a bar: fixed width so 95% and 100% end on one line. */
.cw-num--w  { width: 46px; flex: none; }
.cw-empty { color: var(--text-empty); }           /* em dash (#5, C18) */
.cw-today { text-align: right; font-size: 12px; font-weight: 600; color: var(--success-ink); }
.cw-today--off { color: var(--text-empty); font-weight: 400; }

/* In-row controls. 24-26px looks small but the row itself is the hit target
   for hover; these are deliberate secondary actions beside a primary read. */
.cw-mini {
  flex: none; height: 24px; padding: 0 9px;
  background: transparent; border: 1px solid var(--border-strong); border-radius: 7px;
  font-family: inherit; font-size: 11px; font-weight: 600; color: var(--text-muted);
  cursor: pointer;
}
.cw-mini:hover { border-color: var(--border-hover); background: var(--surface-flat-2); color: var(--text); }
.cw-mini--danger:hover { border-color: #D9A6A0; color: var(--error); background: var(--error-row); }
.cw-mini:disabled { border-color: var(--border-subtle); color: var(--text-empty); cursor: not-allowed; }
.cw-mini svg { width: 11px; height: 11px; }

.cw-pick {
  display: inline-flex; align-items: center; gap: 6px; height: 26px; padding: 0 9px;
  background: var(--surface-flat); border: 1px solid var(--border-strong); border-radius: 7px;
  font-family: inherit; font-size: 11.5px; font-weight: 500; color: var(--text-2);
  cursor: pointer; max-width: 100%;
}
.cw-pick:hover { border-color: var(--border-hover); }
.cw-pick svg { width: 10px; height: 10px; flex: none; color: var(--text-label); }
.cw-pick--static { cursor: default; background: var(--surface-flat-2); color: var(--text-muted); }

/* Buttons: the redesign's primary is near-black, the quiet one is outlined. */
.cw-btn, .cw-btn-dark {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 30px; padding: 0 11px; border-radius: var(--r-sm);
  font-family: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
  white-space: nowrap;
}
.cw-btn { background: var(--surface-flat); border: 1px solid var(--border-strong); color: var(--text-2); font-weight: 500; }
.cw-btn:hover { border-color: var(--border-hover); }
.cw-btn-dark { background: var(--ink); border: 1px solid var(--ink); color: var(--on-ink); }
.cw-btn-dark:hover { background: var(--ink-hover); border-color: var(--ink-hover); }
.cw-btn-dark:disabled, .cw-btn:disabled { background: var(--text-empty); border-color: var(--text-empty); color: var(--on-ink); cursor: default; }
.cw-btn--tall, .cw-btn-dark--tall { height: 34px; padding: 0 13px; font-size: 12.5px; }
.cw-btn svg, .cw-btn-dark svg { width: 13px; height: 13px; flex: none; }

/* Card footer that holds an inline add-form — the action lives where it
   happens, not as a header CTA (invariant #11). */
.cw-foot {
  display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap;
  padding: 11px var(--row-pad-x); border-top: 1px solid var(--border); background: var(--surface-flat-2);
}
.cw-field {
  display: flex; flex-direction: column; gap: 5px; flex: 1; min-width: 140px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.075em; text-transform: uppercase;
  color: var(--text-label);
}
.cw-field > input, .cw-field > select {
  height: 34px; padding: 0 11px; width: 100%;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
  font-family: var(--font); font-size: 13px; font-weight: 400; letter-spacing: 0;
  text-transform: none; color: var(--text);
}
.cw-field > input:focus, .cw-field > select:focus { border-color: var(--accent); outline: none; }
.cw-foot-note { flex-basis: 100%; font-size: 11.5px; color: var(--text-label); margin: 0; }
.cw-foot-note a { color: var(--accent-2); }
/* A link inside a row is still a cell first: no underline until it is hovered,
   and the warm accent rather than the browser's blue. */
.cw-row a, .cw-totalbar a { color: var(--accent-2); text-decoration: none; }
.cw-row a:hover, .cw-totalbar a:hover { color: var(--accent-ink); text-decoration: underline; }
/* Inline validation lives on the same last line as the hint, and keeps its own
   colour — .admin-form-error already carries it. */
.cw-foot > .admin-form-error, .cw-foot > .admin-form-success { flex-basis: 100%; margin: 0; }
.cw-foot > .admin-form-error:empty, .cw-foot > .admin-form-success:empty { display: none; }
/* Same for a validation slot that hangs off the card or a padded block: with
   nothing in it, it must not still spend a line of white under the footer. */
.cw-card > .admin-form-error { padding: 0 22px 12px; margin: 0; }
.cw-card > .admin-form-error:empty,
.cw-pad > .admin-form-error:empty { display: none; }

/* View controls sit in the card head, beside what they filter. */
.cw-head-r input, .cw-head-r select {
  height: 30px; padding: 0 9px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
  font-family: var(--font); font-size: 12px; color: var(--text);
  max-width: 100%;
}
.cw-head-r input:focus, .cw-head-r select:focus { border-color: var(--accent); outline: none; }
.cw-head-r input::placeholder { color: var(--text-label); }
/* A year picker is a number: mono so 2025 and 2026 stay the same width. */
.cw-head-r select.cw-num-select {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
}

/* An alert is a banner with context and a button, never a passive chip (#8). */
.cw-banner {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 12px 16px 12px 14px;
  background: var(--warning-soft); border: 1px solid var(--warning-border);
  border-radius: var(--r-md);
}
.cw-banner-ic {
  width: 30px; height: 30px; border-radius: var(--r-sm); flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--warning-chip); color: var(--error);
}
.cw-banner-ic svg { width: 16px; height: 16px; }
.cw-banner-txt { flex: 1; min-width: 220px; }
.cw-banner-t   { font-size: 13.5px; font-weight: 600; color: var(--text); }
.cw-banner-s   { font-size: 12px; color: var(--warning-ink); margin-top: 1px; }
.cw-banner-btn {
  height: 32px; padding: 0 12px; border-radius: var(--r-sm);
  background: transparent; border: 1px solid #E4CDA6;
  font-family: inherit; font-size: 12.5px; font-weight: 600; color: #7A5A2E; cursor: pointer;
}
.cw-banner-btn:hover { background: #FBEFDC; }

/* Usage bar — a bare percentage is not a metric (#6). */
.cw-bar {
  position: relative; flex: 1; max-width: 112px; height: 6px;
  border-radius: 3px; background: var(--border-subtle);
}
.cw-bar-fill { position: absolute; top: 0; bottom: 0; left: 0; border-radius: 3px; }
.cw-bar-fill--ok    { background: var(--success); }
.cw-bar-fill--warn  { background: var(--warning); }
.cw-bar-fill--out   { background: var(--error); }

/* Certification matrix cell. Every cell is a button: the matrix is where a gap
   is visible, so it is where entry happens. A valid cell opens a renewal. */
.cw-mx {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 50%;
  border: 1px solid transparent; cursor: pointer;
  font-family: inherit; font-size: 12px; font-weight: 600; line-height: 1;
}
.cw-mx:hover { border-color: var(--border-hover); }
.cw-mx svg { width: 13px; height: 13px; stroke-width: 2.6; }
.cw-mx--ok   { background: var(--success-soft); color: var(--success-ink); }
.cw-mx--warn { background: var(--warning-soft); color: var(--warning-ink); }
.cw-mx--x    { background: var(--error-soft);   color: var(--error-ink); }
.cw-mx--na   { background: var(--surface-flat-3); color: var(--text-label); }
.cw-mx-c     { text-align: center; }
.cw-tot--ok   { color: var(--success-ink); }
.cw-tot--mid { color: var(--warning-ink); }
.cw-tot--err  { color: var(--error-ink); }

/* Role popover — the ROLE control is a menu button, not a native select, so it
   can carry the subcontractor flag alongside the role in one place. */
.cw-pop {
  position: absolute; z-index: 120; min-width: 208px;
  background: var(--surface-flat); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: 6px;
}
.cw-pop-lbl {
  padding: 6px 9px 4px; font-size: 11px; font-weight: 600;
  letter-spacing: 0.075em; text-transform: uppercase; color: var(--text-label);
}
.cw-pop-opt {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 8px 9px; border: 0; border-radius: var(--r-sm);
  background: transparent; cursor: pointer; text-align: left;
  font-family: var(--font); font-size: 13px; color: var(--text);
}
.cw-pop-opt:hover { background: var(--surface-flat-2); }
.cw-pop-opt[aria-checked="true"] { background: var(--accent-soft); font-weight: 600; }
.cw-pop-opt svg { width: 14px; height: 14px; flex: none; color: var(--accent-ink); }
.cw-pop-sep { height: 1px; background: var(--border-subtle); margin: 5px 3px; }
.cw-pop-note { padding: 2px 9px 7px; font-size: 11px; color: var(--text-dim); }

/* In-row actions. Quiet by default so the row reads as data first; they are
   always rendered (never hover-only) because a phone has no hover. */
.cw-rowacts { display: flex; align-items: center; justify-content: flex-end; gap: 4px; }
.cw-rowacts .ox-iconbtn {
  width: 28px; height: 28px; flex: none; padding: 0;
  border-radius: 7px; color: var(--text-label);
}
/* NOTE for anyone reading verify-redesign.js output BELOW 1024px: C15 reports
   these buttons as overflowing (35 > 26). Nothing is clipped. `admin.css`
   (touch ergonomics, gauntlet 2026-08-08) gives every small control an
   invisible ≥44px hit area via an `::after` with negative insets, under
   `@media (max-width: 1023px)`. That pseudo-element is 44px wide inside a 28px
   button by design, and C15 measures scroll extent, so it counts as overflow.
   It has no background and cannot hide anything. Above 1023px the rule does
   not apply and the tab reports clean. Do not widen the column to chase it —
   the number tracks the column width, so it never clears. */
.cw-rowacts .ox-iconbtn:hover { color: var(--text); background: var(--chrome-surface); }
.cw-rowacts .ox-iconbtn svg { width: 14px; height: 14px; }

/* A group divider inside one table — not a second column header. Uppercase
   carries the LABEL only; a sentence in caps loses the word shapes that make
   it readable, so the explanation rides beside it in normal case. */
.cw-grouphead {
  display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap;
  padding: 14px 22px 7px;
  border-top: 1px solid var(--border-subtle);
  font-size: 11px; font-weight: 600; letter-spacing: 0.075em; text-transform: uppercase;
  color: var(--text-label); background: var(--surface-flat-2);
}
.cw-grouphead-note {
  font-size: 11px; font-weight: 400; letter-spacing: 0;
  text-transform: none; color: var(--text-dim);
}

/* ── Submissions feed ──────────────────────────────────────────────────────
   A day-grouped list inside ONE card: one column header at the top, a day
   divider per group, and a single total at the bottom. */

/* The form's two-letter chip. Mono, because it reads as a code, not a word. */
.sx-chip {
  width: 30px; height: 30px; border-radius: var(--r-sm); flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--chrome-surface); color: var(--text-muted);
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 11px; font-weight: 600; letter-spacing: 0.02em;
}
.sx-chip[data-flagged] { background: var(--error-soft); color: var(--error-ink); }

/* The row is the button; the chevron says so without being a second target. */
.cw-chevron { display: inline-flex; align-items: center; color: var(--text-empty); }
.cw-chevron svg { width: 15px; height: 15px; }

/* Identity-hue avatar: a person keeps one colour across every screen that
   colour-codes people. White text — these seven all clear AA against it. */
.cw-av--id { color: #FFFFFF; }

/* A day divider carries its count on the right, in mono. */
.cw-grouphead--day { justify-content: space-between; }
.cw-grouphead-num {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-weight: 400; letter-spacing: 0; text-transform: none;
}
.cw-tag--bad { color: var(--error-ink); background: var(--error-soft); letter-spacing: 0; }

/* Trades: the row IS the edit control, so the name is an input on the row. */
.cr-trade-name {
  width: 100%; height: 32px; padding: 0 11px;
  background: var(--surface-flat); border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  font-family: var(--font); font-size: 13px; color: var(--text);
}
.cr-trade-name:hover { border-color: var(--border-hover); }
.cr-trade-name:focus { border-color: var(--accent); outline: none; }
/* A trade with people on it is the one that hurts to remove — say so quietly
   on the row, not in a dialog after the click. */
.cr-trade-used { color: var(--warning-ink); font-weight: 600; }

/* Cert type validity: a number and its unit read as one field. */
.cw-cat-valid  { display: flex; align-items: center; gap: 7px; }
.cw-cat-months {
  width: 74px; text-align: right;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
}

/* Date chips under a name (sick days) — each one removable. */
.cw-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 3px; }
.cw-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 1px 5px 1px 7px; border-radius: var(--r-pill);
  background: var(--chrome-surface-2); color: var(--text-muted);
  font-size: 11px; font-weight: 500;
}
/* Removing a logged day is destructive, so its target is a real one — an 11px
   glyph is not something to hand a foreman on a phone. */
.cw-chip-x {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; margin: -2px -3px -2px 0;
  border: 0; border-radius: 50%; background: transparent; cursor: pointer;
  color: var(--text-label); font-size: 11px; line-height: 1;
}
.cw-chip-x:hover { color: var(--error); background: var(--error-soft); }

/* ── Submissions · Corrective Actions / Compliance / Safety ────────────────
   The three sub-tabs that share the Submissions mock. Everything below is
   generic on purpose — Logistics, Contracts and Projects are the same shapes. */

/* A total bar for a list whose columns cannot carry a grid total (an action
   row has no numeric column). Same tone and same rule as .cw-total: the
   number on the left recomputes from the visible rows, and the rule that
   governs the list rides beside it instead of an empty grid cell. */
.cw-totalbar {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
  padding: 10px var(--row-pad-x);
  border-top: 1px solid var(--border-strong);
  background: var(--surface-flat-2);
  font-size: 11.5px; color: var(--text-muted);
}
.cw-totalbar-n { font-weight: 600; color: var(--text-muted); }
.cw-totalbar-note { color: var(--text-dim); }

/* Segmented filter. A three-state view switch reads faster as one control than
   as a dropdown, and it shows the states it is NOT on — which a select hides. */
/* O trilho do controle segmentado tinha var(--page-bg): enquanto a página era
   quase branca ele parecia uma pílula clara. Com o canvas cinza ele virou uma
   pílula CINZA com texto apagado em cima (2,71:1). Ele é um controle, e todo
   controle deste sistema vive sobre superfície clara. */
.cw-seg {
  display: flex; gap: 2px; padding: 3px;
  background: var(--surface-flat-2); border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
}
.cw-seg-btn {
  height: 26px; padding: 0 11px; border: 0; border-radius: 7px;
  background: transparent; color: var(--text-muted);
  font-family: var(--font); font-size: 12px; font-weight: 500; cursor: pointer;
}
.cw-seg-btn:hover { color: var(--text); }
.cw-seg-btn[aria-pressed="true"] {
  background: var(--surface-flat); color: var(--text); font-weight: 600;
}

/* Leading state chip on a row — a drawn icon, tinted by what the row IS. */
.cw-ic {
  width: 30px; height: 30px; border-radius: var(--r-sm); flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--chrome-surface); color: var(--text-muted);
}
.cw-ic svg { width: 15px; height: 15px; }
.cw-ic--ok   { background: var(--success-soft); color: var(--success-ink); }
.cw-ic--warn { background: var(--accent-soft);  color: var(--warning-ink); }
.cw-ic--err  { background: var(--error-soft);   color: var(--error-ink); }

.cw-tag--ok { color: var(--success-ink); background: var(--success-soft); letter-spacing: 0; }

/* Cell tones. A due date is text, not a number, so it carries its own colour
   rather than borrowing the number tones. */
.cw-cell--err { color: var(--error-ink); font-weight: 600; }
.cw-cell--dim { color: var(--text-dim); }
.cw-cell--c   { text-align: center; }
.cw-cell--wrap { white-space: normal; }

/* A dark action that has to fit inside a 13px row. */
.cw-btn-dark--sm { height: 28px; padding: 0 11px; font-size: 11.5px; }
/* An in-row toggle that reads as the state it is in. */
.cw-mini--on { color: var(--success-ink); background: var(--success-soft); border-color: transparent; }
.cw-mini--on:hover { background: var(--success-soft); border-color: #BFD9CC; color: var(--success-ink); }

/* Two cards side by side, one under the other once they stop fitting. */
.cw-two {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 16px; align-items: start;
}
.cw-two > * { min-width: 0; }

/* Compliance hero: the coverage ring beside the org KPI strip. */
.cw-hero-row {
  display: grid; grid-template-columns: minmax(240px, 300px) 1fr;
  gap: 16px; align-items: stretch;
}
.cw-ring-card {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 11px; padding: 20px; text-align: center;
}
.cw-ring-lbl { font-size: 12.5px; font-weight: 600; }
.cw-ring-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 11px; border-radius: var(--r-pill);
  font-size: 11.5px; font-weight: 600;
  color: var(--success-ink); background: var(--success-soft);
}
.cw-ring-pill--warn { color: var(--warning-ink); background: var(--warning-soft); }
.cw-ring-pill svg { width: 13px; height: 13px; }
@media (max-width: 860px) { .cw-hero-row { grid-template-columns: 1fr; } }

/* A KPI strip that lives INSIDE a card owns no border of its own — nested
   cards are always wrong; a divider from the head above it is enough. */
.cw-card > .td-kpis {
  border: 0; border-top: 1px solid var(--border); border-radius: 0;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
}

/* The report picker: two rows of controls that must stay static HTML, because
   the panel around them repaints. */
.cw-card--mid { max-width: 860px; }
.cw-pad { padding: 14px 22px 16px; display: flex; flex-direction: column; gap: 11px; }
.cw-pad-p { margin: 0; font-size: 12.5px; color: var(--text-muted); line-height: 1.55; max-width: 68ch; }
.cw-controls { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.cw-controls > select, .cw-controls > input {
  height: 32px; padding: 0 11px; flex: 1; min-width: 130px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
  font-family: var(--font); font-size: 12.5px; color: var(--text);
}
.cw-controls > input[type="date"] {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 12px;
}
.cw-controls > select:focus, .cw-controls > input:focus { border-color: var(--accent); outline: none; }

/* The native file button is the one control the app never restyled. */
.cw-field > input[type="file"] { padding: 6px 10px; font-size: 12px; }
.cw-field > input[type="file"]::file-selector-button {
  margin: 0 9px 0 0; height: 22px; padding: 0 9px;
  border: 1px solid var(--border-strong); border-radius: 6px;
  background: var(--surface-flat-2); color: var(--text-2);
  font-family: var(--font); font-size: 11.5px; font-weight: 600;
  letter-spacing: 0; text-transform: none; cursor: pointer;
}
.cw-field > input[type="file"]::file-selector-button:hover { border-color: var(--border-hover); }

/* The Salus forward address is a machine address: mono, so a typo is visible. */
.cw-input-mono {
  height: 30px; width: 100%; padding: 0 11px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 11.5px; color: var(--text-2);
}
.cw-input-mono:focus { border-color: var(--accent); outline: none; }
.cw-input-mono::placeholder { color: var(--text-label); }
.cw-input-mono--off { color: var(--text-label); }

/* ── Logistics — "Ordinex Logistics - Redesign.dc.html" ────────────────────
   A filter pill row, a row that opens in place, and a one-line strip that
   points at a neighbouring screen. All four Logistics tabs share these. */

/* Filter pills. Active is the accent SURFACE, not an accent fill: on this
   screen the pill says which slice you are looking at — it is a state, and
   state is what accent-soft means. */
.cw-pillrow { display: flex; gap: 8px; flex-wrap: wrap; }
.cw-pill {
  height: 28px; padding: 0 12px; border-radius: var(--r-pill);
  border: 1px solid var(--border-strong); background: var(--surface-flat);
  font-family: var(--font); font-size: 12px; font-weight: 500; color: var(--text-muted);
  cursor: pointer; white-space: nowrap;
}
.cw-pill:hover { border-color: var(--border-hover); }
.cw-pill--on {
  background: var(--accent-soft); border-color: var(--warning-border);
  color: var(--text); font-weight: 600;
}

/* A row that opens in place. The detail is indented past the chevron column so
   it reads as belonging to the row above, not as a new record. */
.cw-expand {
  padding: 8px 22px 14px 60px;
  background: var(--surface-flat-2);
  border-top: 1px solid var(--border-subtle);
  display: flex; flex-direction: column; gap: 5px;
}
.cw-expand-line { display: flex; gap: 10px; font-size: 12px; color: var(--text-2); }
.cw-expand-qty {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  min-width: 64px; text-align: right; flex: none;
}
.cw-expand-note {
  margin-top: 4px; padding: 8px 11px;
  font-size: 12px; color: var(--warning-ink);
  background: var(--warning-soft); border: 1px solid var(--warning-border);
  border-radius: var(--r-sm);
}
.cw-expand-acts { display: flex; align-items: center; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
.cw-expand-acts select {
  height: 30px; padding: 0 10px; min-width: 150px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
  font-family: var(--font); font-size: 12.5px; color: var(--text);
}
.cw-expand-acts select:focus { border-color: var(--accent); outline: none; }
.cw-expand-hint { font-size: 11px; color: var(--text-label); }
/* The item list is built by formatDeliveryItems() as label-then-quantity. The
   mock leads with the QUANTITY, right-aligned and mono, because that is the
   column a reader scans — so the order is flipped here rather than in the
   function, which the request PDF and the field app also read. */
.cw-expand .delivery-item-row {
  display: flex; align-items: baseline; gap: 10px;
  font-size: 12px; color: var(--text-2);
}
.cw-expand .delivery-item-row > strong {
  order: -1; flex: none; min-width: 64px; text-align: right;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-weight: 600; color: var(--text);
}
.cw-expand .delivery-item-other { font-size: 12px; color: var(--text-2); padding-left: 74px; }
/* The chevron turns to say the row is open — the row itself is the button. */
.cw-chevron--turn svg { transform: rotate(90deg); }

/* A one-line pointer at a neighbouring screen. Not a card: it holds no record,
   so it does not get a card's padding or a card's weight. */
.cw-strip {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 16px;
  background: var(--surface-flat); border: 1px solid var(--border);
  border-radius: var(--r-md);
  font-size: 12.5px; color: var(--text-2);
}
.cw-strip svg { width: 15px; height: 15px; flex: none; color: var(--text-dim); }
.cw-strip-txt { flex: 1; min-width: 220px; }

/* ── Rates & Defaults ──────────────────────────────────────────────────────
   Four cards of money settings. Everything typed here is a NUMBER, so every
   field is mono and tabular and the column of them reads down the page. The
   fields were 9px-tall-padding boxes on a grey `--surface-2`; at the compact
   density they match every other control in the product. */

.rt-colhead {
  font-size: 11px; font-weight: 600; letter-spacing: 0.075em;
  text-transform: uppercase; color: var(--text-label);
  padding-bottom: 6px; border-bottom: 1px solid var(--border); margin-bottom: 8px;
}
.rt-name { font-size: 13px; font-weight: 600; letter-spacing: -0.01em; color: var(--text); }
.rt-name-sub { font-size: 11px; font-weight: 400; color: var(--text-dim); }
.rt-money-pre, .rt-money-post { font-size: 11.5px; font-weight: 500; color: var(--text-label); }
.rt-money input, .rt-text {
  height: 32px; padding: 0 11px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
  font-family: var(--font); font-size: 13px; color: var(--text);
}
.rt-money input {
  padding-left: 22px; text-align: right; font-weight: 600;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
}
.rt-money input:focus, .rt-text:focus {
  outline: none; border-color: var(--accent);
}
.rt-pay-grid { gap: 7px 12px; }
.rt-mt-row { padding: var(--row-pad) 0; }
/* "These prices need attention" was web amber mixed by hand. It is the same
   caution the rest of the product uses, and the same banner shape. */
.rt-dp-needs {
  border: 1px solid var(--warning-border); background: var(--warning-soft);
  border-radius: var(--r-md); padding: 12px 15px; margin-bottom: var(--block-gap);
}
.rt-dp-needs-head { color: var(--text); font-weight: 600; }
@media (pointer: coarse), (max-width: 860px) {
  .rt-money input, .rt-text { height: 36px; }
}

/* ── Projects — "Ordinex Projects - Redesign.dc.html" ──────────────────────
   The list keeps its own shape: a scannable row per site whose Edit opens an
   accordion under it, rather than the mock's seven inline-editable columns.
   Rebuilding it onto that grid is a pass of its own (ledger). What changes
   here is everything the eye reads — density, warmth, and the numbers.

   `rgba(248,144,16,.08)` on the site code was the RETIRED accent, mixed by
   hand at 8% — the one hex the token layer could not reach because it was
   the old brand orange, not a token. */

/* Six columns, declared ONCE on the card so the header, every row and the
   total read the same variable and cannot drift (the --cw-cols rule). The
   trade column disappears entirely for a single-pack org rather than sitting
   there empty — a column that can never hold anything should not be drawn. */
.plist {
  --plist-cols: minmax(230px, 1.5fr) 104px 108px 132px 108px 64px;
  --cw-min: 900px;
}
.plist--notrade { --plist-cols: minmax(230px, 1.5fr) 104px 108px 108px 64px; --cw-min: 780px; }
.plist-colhead, .plist-row, .plist-total {
  display: grid; grid-template-columns: var(--plist-cols);
  align-items: center; gap: 14px;
}
.plist-colhead > *, .plist-row > *, .plist-total > * { min-width: 0; }
.plist-colhead {
  padding: 0 var(--row-pad-x) 6px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.075em; text-transform: uppercase;
  color: var(--text-label);
  border-bottom: 1px solid var(--border);
}
.plist-total {
  padding: 10px var(--row-pad-x);
  border-top: 1px solid var(--border-strong); background: var(--surface-flat-2);
  font-size: 11.5px; font-weight: 600; color: var(--text-muted);
}
.plist-row {
  padding: var(--row-pad) var(--row-pad-x);
  border-bottom: 0; border-top: 1px solid var(--border-subtle);
  background: var(--surface-flat);
}
.plist-row:hover { background: var(--surface-flat-2); }
/* The name cell: chevron (only where there are buildings), status dot, the
   name as an input that looks like text until you touch it, then the GC and
   the building count. */
.plist-namecell { display: flex; align-items: center; gap: 8px; min-width: 0; }
.plist-chev {
  width: 20px; height: 20px; flex: none; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 5px; background: transparent;
  color: var(--text-muted); cursor: pointer;
}
.plist-chev:hover { background: var(--surface-flat-3); }
.plist-chev svg { width: 13px; height: 13px; transition: transform var(--t-fast, .15s); }
.plist-chev--open svg { transform: rotate(90deg); }
.plist-chev--off { visibility: hidden; cursor: default; }
.plist-indent { width: 28px; flex: none; }
/* The row IS the edit control — same device as the Trades tab. */
.plist-nameinput {
  flex: 1; min-width: 0; height: 30px; padding: 0 8px;
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: transparent;
  font-family: var(--font); font-size: 14px; font-weight: 600;
  letter-spacing: -0.01em; color: var(--text);
  text-overflow: ellipsis;
}
.plist-nameinput:hover { border-color: var(--border-strong); background: var(--surface-flat); }
.plist-nameinput:focus { border-color: var(--accent); background: var(--surface-flat); outline: none; }
.plist-nameerr:empty { display: none; }
.plist-nameerr { font-size: 11px; flex: none; }
.plist-trade select { width: 100%; }
/* An ON toggle was a filled accent. Accent means PENDING here, and nine
   running jobs in a row turned the column into orange wallpaper that said
   nothing. Running is on-target, which is the success hue; the off state
   stays a plain neutral track. */
.admin-toggle input:checked + .admin-toggle-track { background: var(--success); }
.admin-toggle-track { background: var(--surface-flat-3); }
.plist-crew { display: flex; align-items: center; gap: 8px; }
.plist-active { justify-self: start; }
.plist-dot { width: 7px; height: 7px; background: var(--text-empty); }
.plist-dot--on { background: var(--success); }
/* The site code is an identifier — mono, so codes line up down the column. */
.plist-code {
  min-width: 58px;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 11px; font-weight: 600; letter-spacing: 0.02em;
  color: var(--accent-ink); background: var(--accent-soft);
  padding: 2px 8px; border-radius: 6px;
}
.plist-name { font-size: 14px; font-weight: 600; letter-spacing: -0.01em; color: var(--text); }
.plist-gc   { font-size: 11.5px; color: var(--text-dim); }
.plist-crewct {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 12px; color: var(--text-dim);
}
.pcard-code-input {
  width: 100%; height: 30px; padding: 0 9px;
  border: 1px solid transparent; border-radius: var(--r-sm); background: transparent;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 12px; font-weight: 600; color: var(--text-2);
  text-transform: uppercase;
}
.pcard-code-input--wide { text-transform: none; }
.pcard-code-input:hover { border-color: var(--border-strong); background: var(--surface-flat); }
.pcard-code-input:focus { border-color: var(--accent); background: var(--surface-flat); outline: none; }
.pcard-code-input::placeholder { color: var(--text-empty); }
.plist-row--off { background: var(--surface-flat-2); }
.plist-row--off .plist-name { color: var(--text-dim); font-weight: 500; }
.plist-row--off .plist-code { color: var(--text-label); background: var(--surface-flat-3); }
/* A group divider inside one table, same device as .cw-grouphead. */
.plist-divider {
  padding: 12px var(--row-pad-x) 6px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.075em; text-transform: uppercase;
  color: var(--text-label);
  background: var(--surface-flat-2);
  border-bottom: 0; border-top: 1px solid var(--border-subtle);
}
.plist-editor {
  padding: 12px var(--row-pad-x) 14px 40px;
  background: var(--surface-flat-2);
  border-bottom: 0; border-top: 1px solid var(--border-subtle);
}
/* Crew avatars: the warm beige of every other roster where each row is
   already a person — seven identity hues buy nothing here and cost the calm. */
.pcard-av {
  width: 24px; height: 24px;
  font-family: var(--font); font-size: 9.5px; font-weight: 600;
  background: var(--avatar-soft); color: var(--avatar-ink);
  border: 2px solid var(--surface-flat);
}
.pcard-av--empty { background: var(--surface-flat-3); color: var(--text-empty); }
.proj-building-row { background: var(--surface-flat-2); }
.proj-building-row .plist-name { font-weight: 500; color: var(--text-2); }
.proj-buildings-chip {
  font-size: 11px; color: var(--text-muted);
  background: var(--chrome-surface-2); border-radius: var(--r-pill); padding: 2px 9px;
}

/* ── Contracts — "Ordinex Contracts - Redesign.dc.html" ────────────────────
   Change Orders, RFIs, Submittals and Extra Work Orders are four tabs over
   ONE table. `ctr-*` is that table, so restyling it here converts all four
   at once — which is why the handoff drew them as a single screen.

   The row is a link, the reference is mono (it is a number), and the value
   column is right-aligned money. Nothing about the markup changes; every
   module keeps emitting the same classes. */

.ctr-card {
  background: var(--surface-flat); border: 1px solid var(--border);
  border-radius: var(--r-lg); overflow: hidden;
}
.ctr-card-hdr {
  padding: 11px var(--row-pad-x) 9px; border-bottom: 0;
  font-size: var(--text-title); font-weight: 600; letter-spacing: -0.01em; color: var(--text);
}
/* Column templates, one per shape the four tabs actually have. They used to
   disagree with the number of cells their own modules emitted — RFI put five
   cells into a four-column grid and EWO six into five, so everything after
   the third column sat one slot to the left of its own label.

   Submittals declares its template inline on BOTH its head and its rows, so
   it is internally consistent and left alone; Change Orders draws custom
   rows and only borrows the card. */
.ctr-table-head, .ctr-row { gap: 14px; }
/* A grid item defaults to min-width:auto, so a long subject line pushes its
   own track wider than the identical track in the header — the two grids
   drifted a pixel or two apart and the columns stopped lining up. */
.ctr-table-head > *, .ctr-row > * { min-width: 0; }
/* EWO: project AND money. The mock's full shape. */
.ctr-table--money .ctr-table-head,
.ctr-table--money .ctr-row {
  /* + Work Status (2026-09-03): doc state and field progress are two columns. */
  grid-template-columns: 88px minmax(220px, 1.8fr) minmax(110px, 1fr) 92px 118px 124px minmax(96px, 1fr) 96px;
}
/* RFI: project-scoped by a picker above, so no project column. */
.ctr-table--rfi .ctr-table-head,
.ctr-table--rfi .ctr-row {
  grid-template-columns: 96px minmax(240px, 2fr) 110px 132px 96px;
}
/* Seven columns do not fit an iPad, and .ctr-card clips rather than scrolls —
   the value column and the row actions were simply cut off. The table scrolls
   inside its own card instead (invariant #9); head, rows and total share the
   same floor so they scroll as one piece and stay aligned. */
.ctr-table--money, .ctr-table--rfi { overflow-x: auto; overflow-y: hidden; }
.ctr-table--money > * { min-width: 1060px; }
.ctr-table--rfi   > * { min-width: 680px; }
.ctr-table-head {
  /* The same 3px rail the rows carry, transparent here. Without it the head's
     content box is 3px wider than a row's and the flexible tracks land a
     couple of pixels off the columns they are labelling. */
  border-left: 3px solid transparent;
  padding: 0 var(--row-pad-x) 6px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.075em; text-transform: uppercase;
  color: var(--text-label);
  border-bottom: 1px solid var(--border);
}
.ctr-row {
  padding: var(--row-pad) var(--row-pad-x);
  border-bottom: 0; border-top: 1px solid var(--border-subtle);
  border-left: 3px solid transparent;
  background: var(--surface-flat);
}
.ctr-row:hover { background: var(--surface-flat-2); }
/* A row with a real problem — overdue, rejected — reads without being read. */
.ctr-row--bad { border-left-color: var(--error); background: var(--error-row); }
.ctr-row--bad:hover { background: var(--error-row-hover); }
/* The reference is a number, so it is mono and tabular like every other. */
.ctr-ref {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 12px; font-weight: 500; color: var(--text-dim);
}
.ctr-subject { font-size: 13.5px; font-weight: 600; letter-spacing: -0.01em; color: var(--text); }
.ctr-project { font-size: 12.5px; font-weight: 400; color: var(--text-2); }
.ctr-date {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 12px; font-weight: 400; color: var(--text-dim);
}
/* Money right-aligns so a column of it can be read down (invariant #5). */
.ctr-value, .ctr-amount, .ctr-total-val {
  text-align: right;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 13.5px; font-weight: 600; color: var(--text);
}
.ctr-row-actions { display: flex; gap: 6px; justify-self: end; }
.ctr-row-actions button, .ctr-row-actions .ox-btn {
  height: 24px; padding: 0 9px;
  background: transparent; border: 1px solid var(--border-strong); border-radius: 7px;
  font-family: var(--font); font-size: 11px; font-weight: 600; color: var(--text-muted);
  cursor: pointer;
}
.ctr-row-actions button:hover, .ctr-row-actions .ox-btn:hover {
  border-color: var(--border-hover); color: var(--text);
}
/* Every one of these lists still owes a total row (invariant #2) — the bar is
   styled and waiting; the four modules do not emit it yet. */
.ctr-total {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; padding: 13px 22px;
  border-top: 1px solid var(--border-strong); background: var(--surface-flat-2);
}
.ctr-total-lbl { font-size: 11.5px; font-weight: 600; color: var(--text-muted); }

/* EWO's own panels. These carried the retired web palette as INLINE styles
   (rgba(16,185,129), rgba(90,169,240)) which beat every stylesheet — the
   ledger's pendency #3. The emerald was decoration on a "what happens next"
   panel and the blue was a reference note; neither is a status, so both are
   plain surfaces now and colour goes back to meaning something. */
.ewo-sticky {
  position: sticky; top: -14px; z-index: 8;
  display: flex; gap: 14px; align-items: center; flex-wrap: wrap;
  margin: -8px -6px 14px; padding: 10px 12px;
  background: var(--surface-flat); border: 1px solid var(--border-strong);
  border-radius: var(--r-md); box-shadow: none;
}
.ewo-panel { margin-top: 14px; padding: 14px; background: var(--surface-flat-2); border: 1px solid var(--border); }
.ewo-panel--flush { padding: 0; }
/* The status filters are a segmented control that never wrapped — five chips
   ran off the side of a phone. It wraps now, and its rows keep the seam. */
.gantt-zooms {
  display: inline-flex; flex-wrap: wrap;
  border-radius: var(--r-md); border-color: var(--border-strong);
  background: var(--surface-flat); max-width: 100%;
}
.gantt-zoom { padding: 6px 13px; font-size: 12.5px; font-weight: 500; color: var(--text-muted); }
.gantt-zoom:hover { color: var(--text); }
/* Active is the accent SURFACE with ink text — white on accent fails AA, and
   a filled accent chip reads as a button rather than as a state. */
.gantt-zoom.active {
  background: var(--accent-soft); color: var(--text); font-weight: 600;
}
.ewo-chip-n { color: var(--text-label); font-weight: 500; margin-left: 2px; }
.gantt-zoom.active .ewo-chip-n { color: var(--accent-ink); }

/* ── Equipment ─────────────────────────────────────────────────────────────
   A row of controls above a list, the site chips as pills, and the inventory
   grouped into one card per category. */

.cw-toolrow { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cw-toolrow-gap { flex: 1; min-width: 0; }
.cw-toolrow-note { font-size: 12px; color: var(--text-muted); max-width: 74ch; }
.cw-search {
  height: 32px; width: 210px; max-width: 100%; padding: 0 11px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
  font-family: var(--font); font-size: 12.5px; color: var(--text);
}
.cw-search:focus { border-color: var(--accent); outline: none; }
.cw-search::placeholder { color: var(--text-label); }

/* Site chips are the same device as the delivery pills, so they are the same
   object — renderSiteChips() keeps emitting .eq-chip-*, restyled here. */
.eq-site-chips { display: flex; gap: 8px; flex-wrap: wrap; }
.eq-chip-all, .eq-chip-site {
  height: 28px; padding: 0 12px; border-radius: var(--r-pill);
  border: 1px solid var(--border-strong); background: var(--surface-flat);
  font-family: var(--font); font-size: 12px; font-weight: 500; color: var(--text-muted);
  cursor: pointer; white-space: nowrap;
}
.eq-chip-all:hover, .eq-chip-site:hover { border-color: var(--border-hover); }
.eq-chip-all.active, .eq-chip-site.active {
  background: var(--accent-soft); border-color: var(--warning-border);
  color: var(--text); font-weight: 600;
}

/* One card per category. The header names it and counts it; the rows below
   carry the per-site quantities as chips. */
.eq-admin-section {
  background: var(--surface-flat); border: 1px solid var(--border);
  border-radius: var(--r-lg); overflow: hidden; margin-bottom: var(--block-gap);
}
.eq-admin-section-hdr {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 20px; border-bottom: 1px solid var(--border-subtle);
  background: var(--surface-flat);
}
.eq-admin-section-icon {
  width: 28px; height: 28px; border-radius: var(--r-sm); flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--chrome-surface); color: var(--text-muted);
}
.eq-admin-section-icon svg { width: 15px; height: 15px; }
/* flex:none so the count sits beside the name, not flung to the far edge. */
.eq-admin-section-title { flex: none; font-size: 13.5px; font-weight: 600; letter-spacing: -0.01em; color: var(--text); }
.eq-admin-section-count {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 11.5px; color: var(--text-label); background: none; padding: 0;
}
.eq-list { display: block; }
.eq-row {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: var(--row-pad) 20px; border-top: 1px solid var(--border-subtle);
  background: var(--surface-flat);
}
.eq-row:first-child { border-top: 0; }
.eq-row:hover { background: var(--surface-flat-2); }
.eq-row--empty .eq-row-name { color: var(--text-dim); }
.eq-row-name { font-size: 13px; font-weight: 600; letter-spacing: -0.01em; min-width: 150px; flex: 1; }
.eq-row-locs { display: flex; gap: 6px; flex-wrap: wrap; flex: 2; min-width: 180px; }
.eq-admin-loc-chip {
  display: inline-flex; align-items: baseline; gap: 5px;
  padding: 2px 9px; border-radius: var(--r-pill);
  border: 1px solid var(--border-inner); background: var(--surface-flat-2);
}
.eq-admin-loc-qty {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 12px; font-weight: 600; color: var(--text);
}
.eq-admin-loc-name { font-size: 11px; color: var(--text-dim); }
.eq-row-none { font-size: 11.5px; color: var(--text-empty); }
.eq-row-rate { display: flex; align-items: center; gap: 7px; flex: none; }
.eq-row-rate-est { font-size: 11px; color: var(--text-dim); }
.eq-row-total {
  font-size: 12.5px; color: var(--text-2); flex: none; min-width: 70px; text-align: right;
}
.eq-row-total strong {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-weight: 600; color: var(--text);
}
.eq-row-actions { display: flex; gap: 6px; flex: none; }
.eq-row-btn {
  width: 28px; height: 28px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-strong); border-radius: 7px;
  background: transparent; color: var(--text-muted); cursor: pointer;
}
.eq-row-btn:hover { border-color: var(--border-hover); color: var(--text); }
.eq-row-btn svg { width: 13px; height: 13px; }

/* The rental summary is a strip of labelled figures, not KPI tiles: it follows
   the site filter, so it is a reading of the current view rather than of the
   whole set. */
.eq-rent-summary {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 16px; margin-bottom: 16px;
  background: var(--surface-flat); border: 1px solid var(--border);
  border-radius: var(--r-md);
}
.eq-rent-pill {
  display: inline-flex; align-items: baseline; gap: 7px;
  padding: 4px 11px; border-radius: var(--r-pill);
  border: 1px solid var(--border-inner); background: var(--surface-flat-2);
}
.eq-rent-pill--err { border-color: #E9D2CE; background: var(--error-soft); }
.eq-rent-pill-lbl { font-size: 11px; font-weight: 600; letter-spacing: 0.05em; color: var(--text-dim); }
.eq-rent-pill--err .eq-rent-pill-lbl { color: var(--error-ink); }
.eq-rent-pill-val {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 12.5px; font-weight: 600; color: var(--text);
}
.eq-rent-pill--err .eq-rent-pill-val { color: var(--error-ink); }
.eq-rent-scope { font-size: 11.5px; color: var(--text-dim); }

/* Transfer history rows sit inside a card, so they lose the old table chrome. */
#tmHistory .admin-table-row {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 11px 20px; border-top: 1px solid var(--border-subtle); border-bottom: 0;
}
#tmHistory .admin-cell-name { font-size: 13px; font-weight: 600; letter-spacing: -0.01em; }
#tmHistory .admin-cell-meta { font-size: 11.5px; color: var(--text-dim); margin-top: 3px; }
/* The quantity in a history line is still a number (verifier C3). */
#tmHistory .admin-cell-meta strong {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--text);
}
#tmHistory .admin-empty { padding: 22px; }
/* The rejection note is free text. admin.css pins .admin-cell-meta to
   `nowrap` for its own single-line tables; here the line carries a sentence
   somebody typed, so it wraps. (The &nbsp; chain that also held it on one
   line is gone from the template.) */
#tmHistory .admin-cell-meta { white-space: normal; overflow-wrap: anywhere; }
#tmHistory .admin-cell-meta em { font-style: italic; color: var(--text-label); }

/* ── Rentals (equipment_costs) ─────────────────────────────────────────────
   The one screen on this tab that is about MONEY. Grouped by project, each
   group carrying its own monthly subtotal, and one total for the lot. The
   per-day figure is always derived from the monthly rate — never stored. */

.ec-group { margin-bottom: var(--block-gap); }
.ec-group-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 9px 18px; background: var(--surface-flat-2);
  border-bottom: 1px solid var(--border);
}
.ec-group-name { font-size: 13px; font-weight: 600; letter-spacing: -0.01em; color: var(--text); }
.ec-group-n { font-weight: 500; color: var(--text-label); font-size: 11.5px; }
.ec-group-sub {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 13.5px; font-weight: 700; color: var(--text);
}
.ec-per { font-family: var(--font); font-weight: 400; color: var(--text-label); font-size: 11px; }

.ec-row { padding: 10px 18px; border-top: 1px solid var(--border-subtle); }
.ec-row:first-of-type { border-top: 0; }
.ec-row-top { display: flex; align-items: center; gap: 11px; flex-wrap: wrap; }
.ec-label {
  flex: 1; min-width: 160px; height: 32px; padding: 0 11px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
  font-family: var(--font); font-size: 13px; font-weight: 600; color: var(--text);
}
.ec-label:focus { border-color: var(--accent); outline: none; }
.ec-rate {
  display: flex; align-items: center; gap: 5px; flex: none;
  height: 32px; padding: 0 10px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
}
.ec-rate input {
  width: 72px; border: 0; outline: 0; background: transparent; text-align: right;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 13px; font-weight: 600; color: var(--text);
}
.ec-rate-cur  { font-size: 12px; color: var(--text-label); }
.ec-rate-unit { font-size: 11px; color: var(--text-label); }

.ec-row-mid { display: flex; align-items: center; gap: 11px; flex-wrap: wrap; margin-top: 9px; }
.ec-onrent {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border-radius: var(--r-pill);
  border: 1px solid #CFE3D8; background: var(--success-soft);
  font-size: 11px; font-weight: 600; color: var(--success-ink);
}
.ec-onrent-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--success); }
.ec-meta { font-size: 12px; color: var(--text-dim); }
.ec-meta strong { color: var(--text); font-weight: 600; }

.ec-row-bot {
  display: flex; gap: 9px; flex-wrap: wrap;
  margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--border-inner);
}
.ec-pick {
  height: 28px; padding: 0 9px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
  font-family: var(--font); font-size: 11.5px; color: var(--text-muted);
}
.ec-pick:focus { border-color: var(--accent); outline: none; }

.ec-closed {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 9px 18px; border-top: 1px dashed var(--border-inner);
  font-size: 11.5px; color: var(--text-dim);
}
.ec-closed-name { flex: 1; min-width: 140px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ec-closed-period { color: var(--text-label); white-space: nowrap; }

.ec-total {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; padding: 13px 18px;
  background: var(--surface-flat); border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.ec-total-lbl {
  font-size: 11px; font-weight: 600; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-label);
}
.ec-total-val {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 17px; font-weight: 700; letter-spacing: -0.02em; color: var(--text);
}
.ec-total-val .ec-per { font-size: 12px; color: var(--text-dim); }
.ec-togglebar { display: flex; justify-content: center; }

.ec-add {
  background: var(--surface-flat); border: 1.5px dashed var(--border-hover);
  border-radius: var(--r-lg); overflow: hidden;
}
.ec-add-hdr {
  display: flex; align-items: center; gap: 9px; padding: 14px 18px 0;
  font-size: 13px; font-weight: 600; color: var(--text);
}
.ec-add-hdr svg { width: 14px; height: 14px; }
.ec-add-body { background: transparent; border-top: 0; }

/* ── Delivery calendar ─────────────────────────────────────────────────────
   calendar.html is its own document inside the admin's iframe, so it links
   this file itself. Everything below overrides css/calendar.css.

   A delivery status wears the SAME colour here as on the Deliveries tab —
   requested and on-schedule are pending (accent), on hold is caution, and
   delivered is done. The old chips were web-amber, a blue and a purple that
   existed on no other screen; a status that changes colour between two tabs
   of the same section is a status a reader stops trusting. */

.cal-month-nav {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 14px 20px 12px;
  background: var(--surface-flat);
  border: 1px solid var(--border); border-bottom: 0;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
}
.cal-nav-btn {
  height: 30px; padding: 0 12px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat); color: var(--text-2);
  font-family: var(--font); font-size: 12.5px; font-weight: 600;
}
.cal-nav-btn:hover { border-color: var(--border-hover); background: var(--surface-flat); color: var(--text); }
.cal-nav-btn--sq { width: 30px; padding: 0; font-size: 16px; line-height: 1; }
.cal-nav-group { display: flex; align-items: center; gap: 7px; }
.cal-month-label { margin: 0; font-size: 16px; font-weight: 700; letter-spacing: -0.015em; color: var(--text); }
.cal-legend { display: flex; align-items: center; gap: 13px; flex-wrap: wrap; margin-left: auto; padding: 0; }
.cal-legend-item { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--text-muted); }
.cal-legend-dot { width: 8px; height: 8px; border-radius: 3px; flex: none; }
.cal-legend-dot--ac   { background: var(--accent-ink); }
.cal-legend-dot--warn { background: var(--warning-ink); }
.cal-legend-dot--ok   { background: var(--success-ink); }
.cal-wrap { padding: 16px; }
/* A week does not stack. Below the width where seven readable columns fit,
   the grid scrolls sideways inside the card and the nav/footer stay put. */
.cal-scroll { overflow-x: auto; overflow-y: hidden; }
@media (max-width: 820px) {
  .cal-scroll .cal-grid { min-width: 700px; }
}
.cal-foot {
  padding: 12px 20px;
  background: var(--surface-flat-2);
  border: 1px solid var(--border); border-top: 0;
  border-radius: 0 0 var(--r-lg) var(--r-lg);
  font-size: 12px; color: var(--text-muted);
}
/* The grid sits between the nav and the footer, so it owns no bottom radius. */
.cal-wrap .cal-grid { border-radius: 0; border-bottom: 0; }

/* The grid is the card body: hairlines between cells, no gap-as-border. */
.cal-grid {
  gap: 0; background: var(--surface-flat);
  border: 1px solid var(--border); border-radius: 0 0 var(--r-lg) var(--r-lg);
}
.cal-day-header {
  padding: 8px 10px;
  background: var(--surface-flat-2);
  border-right: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border);
  font-size: 11px; font-weight: 600; letter-spacing: 0.075em;
  color: var(--text-label);
}
.cal-day {
  min-height: 84px; padding: 6px 7px; gap: 3px;
  background: var(--surface-flat);
  border-right: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
}
.cal-day.other-month { background: var(--surface-flat-2); opacity: 1; }
.cal-day.other-month .cal-day-num { color: var(--text-empty); }
.cal-day.weekend:not(.other-month) { background: var(--surface-flat-2); }
/* Today is a filled day number, not a tinted cell — the cell tint fought the
   chips sitting inside it. */
.cal-day.today { background: var(--surface-flat); box-shadow: none; }
.cal-day-num {
  display: flex; align-items: center; justify-content: center;
  width: 21px; height: 21px; border-radius: 50%; margin-bottom: 0;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 11px; font-weight: 500; color: var(--text-muted);
}
.cal-day.today .cal-day-num {
  width: 21px; height: 21px; font-weight: 700;
  background: var(--ink); color: var(--on-ink);
}
.cal-day.drag-over {
  background: var(--accent-soft);
  outline: 2px dashed var(--accent); outline-offset: -2px;
}

/* A chip is a draggable control, so it reads as one: a real border, a status
   dot, and the site code in the product's own type. */
.cal-chip {
  display: flex; align-items: center; gap: 5px; width: 100%;
  padding: 3px 7px; border-radius: 6px;
  border: 1px solid var(--border-strong); background: var(--surface-flat);
  font-family: var(--font); font-size: 11px; font-weight: 600;
  color: var(--text-2); line-height: 1.4;
}
.cal-chip::before {
  content: ''; width: 5px; height: 5px; border-radius: 50%; flex: none;
  background: currentColor;
}
.cal-chip:hover { opacity: 1; border-color: var(--border-hover); }
.cal-chip.requested,
.cal-chip.on_schedule { background: var(--accent-soft);  border-color: var(--warning-border); color: var(--accent-ink); }
.cal-chip.on_hold     { background: var(--warning-soft); border-color: var(--warning-border); color: var(--warning-ink); }
.cal-chip.delivered,
.cal-chip.confirmed_received { background: var(--success-soft); border-color: #CFE3D8; color: var(--success-ink); }
.cal-chip.cancelled   { background: var(--surface-flat-3); border-color: var(--border); color: var(--text-muted); }
/* calendar.css carries a `[data-theme="light"] .cal-chip.x` block — one
   specificity step above the rules just above, so it won. It exists to rescue
   text contrast against the OLD translucent washes, which these solid token
   surfaces replaced; left alone it kept painting on-schedule blue and on-hold
   purple next to a legend that had already moved to the token palette. Matched
   here selector-for-selector, and this file loads last. */
[data-theme="light"] .cal-chip.requested,
[data-theme="light"] .cal-chip.on_schedule { color: var(--accent-ink); }
[data-theme="light"] .cal-chip.on_hold     { color: var(--warning-ink); }
[data-theme="light"] .cal-chip.delivered,
[data-theme="light"] .cal-chip.confirmed_received { color: var(--success-ink); }
[data-theme="light"] .cal-chip.cancelled   { color: var(--text-muted); }

.cal-popover {
  background: var(--surface-flat); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: none;
}
.cal-popover-project { font-size: 14px; font-weight: 700; letter-spacing: -0.01em; color: var(--text); }
.cal-popover-row { font-size: 12.5px; color: var(--text-2); }
.cal-popover-status {
  display: inline-flex; padding: 3px 10px; border-radius: var(--r-pill);
  font-size: 11px; font-weight: 600;
}

/* ── Projects · Schedule (the Gantt board) ─────────────────────────────────
   The mock draws this tab as a five-column weekly crew board. The product is a
   full Gantt — dependencies, split stages, drag-to-reschedule, a manpower plan
   and a PDF export — so the CODE wins on capability (DESIGN.md) and the
   redesign supplies the vocabulary: one card, one uppercase column label, the
   view controls in a strip of their own, and a total row that follows the
   rows on screen.

   Everything below overrides `css/admin.css`'s `.gantt-*` block, which was
   drawn for the obsidian shell and carries hardcoded slate/blue washes. */

/* Give the board the full content column — .admin-main's 1200px cap makes a
   timeline pointlessly narrow. (Also in admin.css; repeated here because the
   rule is part of this screen's layout, not a leftover.) */
.admin-main:has(> #tab-schedule.active) { max-width: none; }

/* The saved-schedule picker IS the card's title. One place says which schedule
   is open, and it is the control that changes it — a heading beside a select
   holding the same word says it twice. */
.gnt-pick {
  height: 30px; max-width: 280px; padding: 0 27px 0 8px;
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: transparent no-repeat right 8px center;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23A19B91' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  font-family: var(--font); font-size: var(--text-title); font-weight: 600;
  letter-spacing: -0.01em; color: var(--text);
  cursor: pointer; appearance: none; -webkit-appearance: none;
}
.gnt-pick:hover { border-color: var(--border-strong); background-color: var(--surface-flat-2); }
.gnt-pick:focus { border-color: var(--accent); outline: none; }
.gnt-crud { display: inline-flex; gap: 6px; }

/* The PDF scale is a setting for the button beside it, so it reads as one
   control pair rather than a filter over the board. */
.gnt-pdfscale {
  height: 30px; padding: 0 9px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
  font-family: var(--font); font-size: 12px; color: var(--text-2);
}
.gnt-pdfscale:focus { border-color: var(--accent); outline: none; }

/* Locked is the resting state and says so quietly. Editing means a stray drag
   now writes to the database — that is exactly what accent means here. */
.gnt-lock[aria-pressed="true"] {
  background: var(--accent-soft); border-color: var(--warning-border);
  color: var(--accent-ink); font-weight: 600;
}
.gnt-lock[aria-pressed="true"]:hover { border-color: #E4CDA6; }

/* The view strip: how you are LOOKING at the board, separated from the head,
   which is what the board IS and what you can add to it. */
.gnt-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 0 var(--row-pad-x) 11px;
}
.gnt-legend { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-left: auto; }
.gnt-leg {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11.5px; color: var(--text-muted);
}
.gnt-leg i { width: 9px; height: 9px; border-radius: 3px; flex: none; }
.gnt-scope-note {
  font-size: 12px; color: var(--warning-ink);
  background: var(--warning-soft); border: 1px solid var(--warning-border);
  border-radius: var(--r-md); padding: 9px 13px; margin: 0;
}

/* The board itself sits INSIDE the card, so it owns no border, no radius and
   no background of its own — nested cards are always wrong. */
.gantt-scroll {
  overflow: auto; max-height: 72vh;
  border: 0; border-radius: 0; border-top: 1px solid var(--border);
  background: var(--surface-flat);
}
.gnt-chart { max-height: none; overflow-x: auto; overflow-y: hidden; }
.gnt-empty {
  padding: 26px var(--row-pad-x); font-size: 13px; font-style: normal;
  color: var(--text-dim);
}

/* Head band — one uppercase column label for the whole table (C10). */
.gantt-corner {
  background: var(--surface-flat);
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  padding: 0 12px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.075em;
  color: var(--text-label);
}
/* Three lanes, not two: the today flag gets one of its own. Sharing a lane
   with the month band meant it landed on top of "AUG 26" whenever today fell
   near the start of a month — which is a third of the time. */
.gantt-head-time {
  height: 56px; background: var(--surface-flat);
  border-bottom: 1px solid var(--border);
}
.gantt-months { top: 14px; height: 21px; }
.gantt-ticks  { top: 35px; height: 21px; }
/* A month band is a date: mono and tabular like every other number. */
.gantt-month {
  height: 21px; line-height: 21px; padding-left: 7px;
  border-left: 1px solid var(--border-subtle);
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.06em;
  color: var(--text-muted);
}
.gantt-tick {
  height: 21px; line-height: 21px; overflow: hidden;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 10px; color: var(--text-label);
}
.gantt-month { overflow: hidden; }
.gantt-tick--wk { border-left: 1px solid var(--border-subtle); }

/* Rows. The zebra sets background-COLOR only: the `background` shorthand would
   reset background-image, and with it the Sunday shading and the weekly
   gridlines — every second row would quietly lose its calendar. */
.gantt-row:nth-child(even) .gantt-track { background-color: var(--surface-flat-2); }
.gantt-label {
  background: var(--surface-flat);
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border-subtle);
  padding: 5px 11px;
}
.gantt-row:nth-child(even) .gantt-label { background: var(--surface-flat-2); }
.gantt-label-title { font-size: 13px; font-weight: 600; letter-spacing: -0.01em; color: var(--text); }
.gantt-label-sub   { font-size: 11px; color: var(--text-dim); }
/* "after Block wall +1d" is a FACT about the plan, not a warning about it —
   it was reading in the amber caution ink, which promises trouble that is not
   there. */
.gantt-label-dep   { font-size: 10.5px; color: var(--text-dim); }
.gantt-track {
  border-bottom: 1px solid var(--border-subtle);
  /* Layer 1: Sunday shading (we don't work Sundays) — the range starts on a
     Monday, so Sunday is day-index 6 of each week. Layer 2: weekly gridlines.
     background-position is restated rather than inherited from admin.css: the
     offset is what puts the shade on Sunday, and leaving it to another rule is
     how a six-day shift becomes a mystery later. */
  background-image:
    repeating-linear-gradient(to right, var(--page-bg) 0, var(--page-bg) var(--d), transparent var(--d), transparent var(--wk)),
    repeating-linear-gradient(to right, transparent 0, transparent calc(var(--wk) - 1px), var(--grid-line) var(--wk));
  background-position: calc(6 * var(--d)) 0, 0 0;
}
/* A quarter at 5px/day is ~800px inside a 1900px card, and the leftover used to
   read as a rendering fault: rows and gridlines simply stopped mid-card. The
   timeline keeps its computed width as a FLOOR and grows into whatever is
   left, so the weeks carry on to the card edge. Bars are positioned in px from
   the range start, so nothing moves. */
.gantt-grid { min-width: 100%; }
.gantt-track, .gantt-head-time { flex: 1 0 auto; }
.gantt-reorder button {
  background: var(--chrome-surface-2); color: var(--text-muted);
  width: 18px; height: 13px; border-radius: 3px;
}
.gantt-reorder button:hover { background: var(--ink); color: var(--on-ink); }

/* Dependency arrows carry structure, so they hold the 3:1 non-text floor
   against white — the old slate-blue landed at ~2.3:1 on this ground. */
.gantt-arrows path  { stroke: var(--text-dim); stroke-width: 1.4; }
.gantt-arrowhead    { fill: var(--text-dim); }

/* Bars. The colour is the person, so nothing else on the bar competes with
   it: no shadow, no text shadow, no gradient. */
.gantt-bar {
  border-radius: 6px; box-shadow: none;
}
.gantt-bar.dragging { box-shadow: none; opacity: .82; outline: 2px solid var(--ink); outline-offset: 1px; }
.gantt-bar-fill { background: rgba(0, 0, 0, 0.24); }
.gantt-bar-txt {
  padding: 0 8px; font-size: 11.5px; font-weight: 600;
  color: #FFFFFF; text-shadow: none;
}
.gnt-bar-pct {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-weight: 600; opacity: .82;
}
.gantt-seg-link { border-top: 1.5px dashed var(--text-label); }

/* Today is a reference line, not an exception — red in this system means a
   loss or a blocker. Ink, with the word in the DATE BAND so nothing has to be
   inferred from a colour and nothing sits on top of the first bar. */
.gantt-today { width: 2px; background: var(--ink); }
.gantt-today::before { content: none; }
.gantt-today-lbl {
  position: absolute; top: 0; z-index: 8;
  transform: translateX(-50%);
  padding: 1px 6px; border-radius: 4px;
  background: var(--ink); color: var(--on-ink);
  font-size: 9.5px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  white-space: nowrap; pointer-events: none;
}

/* The total's own figures are numbers like any other. */
.gnt-total-n, .gnt-total-span {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
}
.gnt-total-n { font-weight: 600; color: var(--text); }

/* ── Job workspace shell — "Ordinex Job Workspace - Redesign.dc.html" ──────
   The header every one of the workspace tabs sits under. It has one job: say
   WHICH job you are looking at and WHAT STATE it is in, so no figure below it
   can be read against the wrong project. */
.jw-ref {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 12px; color: var(--text-label); align-self: baseline;
}
.jw-ref:empty { display: none; }
/* Active is the resting state and shows nothing. This pill only ever appears
   on an ARCHIVED job, where every number under it is history. */
.jw-state {
  align-self: baseline;
  padding: 2px 8px; border-radius: var(--r-pill);
  background: var(--chrome-surface-2); color: var(--text-muted);
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.05em;
}
.admin-content-title-left { display: flex; align-items: baseline; gap: 11px; flex-wrap: wrap; }
#jobWorkspaceHead .admin-content-title {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 20px; flex-wrap: wrap;
}
.admin-content-title-right { display: flex; align-items: center; gap: 8px; flex: none; }
.jw-switch { height: 34px; }
.jw-switch-caret { color: var(--text-label); }
.jw-switch svg { width: 13px; height: 13px; }

/* ── P&L — "Ordinex PnL - Redesign.dc.html" ────────────────────────────────
   The table was already a real <table>, which aligns by construction, so it
   keeps being one; what it was missing is the card it lives in, the strip
   above it and the tones. */

/* A NAME is not a number. Part A above puts every `.pnl-table td` in mono so
   the money columns are tabular — and swept the project name in with them, so
   the one column of prose on the screen read like a stock ticker. */
.pnl-table td.pnl-cell-name,
.pnl-row--totals td:first-child { font-family: var(--font); font-variant-numeric: normal; }

.pnl-period-bar { margin-bottom: var(--block-gap); display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.pnl-period-showing { margin-top: 0; font-size: 11.5px; color: var(--text-dim); }
.pnl-kpis { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); margin-bottom: var(--block-gap); }
.pnl-kpi-mu   { color: var(--text-2); }
.pnl-kpi-loss { color: var(--error-ink); font-weight: 600; }

/* Inside the card the table owns no border, radius or margin of its own —
   nested cards are always wrong. */
.pnl-card .pnl-table-wrap {
  border: 0; border-radius: 0; border-top: 1px solid var(--border);
  margin-bottom: 0; background: transparent;
}
.pnl-table th, .pnl-table td { padding: var(--row-pad) 14px; }
.pnl-table thead th {
  background: var(--surface-flat);
  font-weight: 600; letter-spacing: 0.075em; font-size: 11px;
  color: var(--text-label);
  border-bottom: 1px solid var(--border);
}
.pnl-table th, .pnl-table td { border-bottom: 1px solid var(--border-subtle); }
.pnl-row:hover td { background: var(--surface-flat-2); }
.pnl-row--child td { background: var(--surface-flat-2); }
.pnl-row--totals td {
  background: var(--surface-flat-2);
  border-top: 1px solid var(--border-strong);
}
/* This note sits DIRECTLY on the canvas, not inside a card: at --text-dim it
   gave 1.85:1 against the new ground. --text-2 gives 4.73:1. */
.pnl-foot-note {
  margin: 0; font-size: 11.5px; color: var(--text-2); max-width: 96ch; line-height: 1.55;
}
.pnl-expand-btn {
  width: 22px; height: 22px; padding: 0; margin: 0 5px 0 -3px;
  align-items: center; justify-content: center;
  border-radius: 5px; background: transparent; border: 0;
  color: var(--text-muted); vertical-align: -5px;
}
.pnl-expand-btn:hover { background: var(--chrome-surface-2); color: var(--text); }
.pnl-sort-btn { font-size: 11px; font-weight: 600; letter-spacing: 0.075em; color: var(--text-label); }
.pnl-sort-btn:hover, .pnl-sort-btn--active { color: var(--text); }

/* ── Home — "Ordinex Home - Redesign.dc.html" ──────────────────────────────
   Nine jobs side by side is the whole point of this screen, so a job is a ROW,
   not a card. The card-per-job layout it replaces spent a block on each one
   and made two of them impossible to compare without scrolling. */

/* The toolbar is static markup in admin.html (the search caret has to survive
   a repaint), so it lives outside .cw-stack and owns its own bottom gap. */
.hm-tools {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-bottom: var(--block-gap);
}
.hm-search {
  display: flex; align-items: center; gap: 7px;
  height: 32px; padding: 0 11px; width: 230px; max-width: 100%;
  background: var(--surface-flat); border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
}
.hm-search:focus-within { border-color: var(--accent); }
.hm-search i, .hm-search svg { width: 14px; height: 14px; flex: none; color: var(--text-label); }
.hm-search input {
  border: 0; outline: 0; background: transparent; width: 100%;
  /* Fills the label, so the whole 32px control is the target rather than the
     17px line of text inside it. */
  height: 100%;
  font-family: var(--font); font-size: 13px; color: var(--text);
}
.hm-search input::placeholder { color: var(--text-label); }
.hm-sort {
  height: 32px; padding: 0 9px;
  background: var(--surface-flat); border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  font-family: var(--font); font-size: 12.5px; color: var(--text-2);
}
.hm-sort:focus { border-color: var(--accent); outline: none; }
.hm-tools .cw-btn { height: 32px; }
.hm-tools .cw-btn[aria-pressed="true"] { background: var(--surface-flat-3); color: var(--text); }

/* KPI strip. It describes what is ON SCREEN — search and the archived toggle
   both change that set — and the "N jobs shown" foot is what says so. */
.hm-kpis { grid-template-columns: repeat(auto-fit, minmax(178px, 1fr)); }
.hm-kpi-mu   { color: var(--text-2); }
.hm-kpi-of   { color: var(--text-empty); }
.hm-kpi-loss { color: var(--error-ink); font-weight: 600; }
/* One tick per crew, filled for the ones that filed: the fraction above it,
   without the division. */
.hm-ticks { display: flex; gap: 2px; margin-top: 2px; }
.hm-tick {
  width: 5px; height: 15px; border-radius: 2px; flex: none;
  background: var(--error-soft);
}
.hm-tick--on { background: var(--success); }

/* Production: one card per material, each on its own scale. Blocks are counted
   in units and veneer in square feet — a shared axis makes the smaller number
   look like a collapse when it is only a different unit. */
.hm-pulse-wrap { display: flex; flex-direction: column; gap: 8px; }
.hm-pulse-lbl {
  font-size: 11px; font-weight: 600; letter-spacing: 0.075em;
  text-transform: uppercase; color: var(--text-label);
}
.hm-pulse-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--block-gap); align-items: start;
}
.hm-pulse-row > * { min-width: 0; }
.hm-pulse { padding: 15px 18px 10px; }
.hm-pulse-empty { padding: 18px 22px; font-size: 12.5px; color: var(--text-dim); }
.hm-pulse-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.hm-pulse-name { display: flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 600; }
.hm-pulse-sub  { font-size: 11.5px; color: var(--text-label); margin-top: 3px; }
.hm-pulse-r    { text-align: right; flex: none; }
.hm-pulse-tot  {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 17px; font-weight: 600;
}
.hm-pulse-cap  {
  font-size: 10px; font-weight: 600; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--text-label);
}
.hm-pulse-body { margin-top: 6px; }
.hm-pulse-body svg { display: block; width: 100%; height: auto; }

/* The pulse chart's own labels are NUMBERS and a DATE, and both were sans:
   css/styles.css writes them with the `font:` shorthand, which also resets
   font-variant-numeric — the same trap that left the compliance ring
   non-tabular for months. Longhands, so the size and weight above survive.
   This reaches the field app's copy of the chart too, which wants it just as
   much. */
.fh-pulse-val, .fh-pulse-val--now, .fh-pulse-week, .fh-pulse-week--now {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* Jobs table */
.hm-legend { display: flex; align-items: center; gap: 14px; font-size: 11.5px; color: var(--text-label); }
.hm-leg { display: inline-flex; align-items: center; gap: 5px; }
.hm-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.hm-dot--pending { background: var(--accent); }
.hm-dot--filed   { background: var(--success); }
/* A job with nobody on it has no tailgate to be missing — it is not "filed",
   it is untracked, and painting it green said the opposite. */
.hm-dot--none    { background: var(--border-strong); }

/* The chevron is a real button inside a row that is itself a button, so it
   needs its own target and its own surface — left bare it inherited the UA's
   grey button chrome, which is also the only pure grey on the screen. */
.hm-row button.cw-chevron {
  width: 24px; height: 24px; flex: none; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 5px; background: transparent;
  color: var(--text-muted); cursor: pointer;
}
.hm-row button.cw-chevron:hover { background: var(--chrome-surface-2); color: var(--text); }
.hm-row .cw-chevron--none { width: 24px; flex: none; }
.hm-row { cursor: pointer; }
.hm-row:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.hm-row--child { background: var(--surface-flat-2); }
.hm-row--child .cw-pname { font-weight: 500; }
.hm-code {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 11.5px; color: var(--text-label); flex: none;
}
/* THIS WEEK cell, take two: one line per material (max two), each number wearing
   its own unit from the org's catalog. The bare lead-material number read as
   "802 of something" — a masonry tell on a multi-tenant screen. */
.hm-week-cell { display: flex; flex-direction: column; gap: 1px; line-height: 1.3; }
.hm-week-unit { font-size: 10.5px; color: var(--text-dim, #8a8577); letter-spacing: .02em; }
.hm-week-more { font-size: 10.5px; color: var(--text-dim, #8a8577); }
.hm-week { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 12.5px; color: var(--text-2); }
/* Margin diverges from zero and is scaled by the widest margin ON SCREEN.
   The mock draws a "Target 12%" tick; nothing in the product sets a target,
   and a benchmark nobody chose is worse than none. */
.hm-margin { display: flex; align-items: center; justify-content: flex-end; gap: 9px; }
.hm-margin-bar {
  position: relative; flex: 1; max-width: 66px; height: 5px;
  border-radius: 3px; background: var(--border-subtle);
}
.hm-margin-bar::after {
  content: ''; position: absolute; left: 50%; top: -2px; bottom: -2px;
  width: 1px; background: var(--border-strong);
}
.hm-margin-fill { position: absolute; top: 0; bottom: 0; border-radius: 3px; background: var(--success); }
.hm-margin-fill--neg { background: var(--error); }
.hm-margin-val {
  width: 50px; flex: none; text-align: right;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 13px; font-weight: 600;
}
/* Stacked, the row is the button and the bar has no column to sit in. */
@media (max-width: 860px) {
  .hm-margin { justify-content: flex-start; }
  .hm-margin-val { text-align: left; }
  .hm-tools .hm-search { width: 100%; }
}

/* ── Stacked modal fields (found while converting the Schedule dialog) ─────
   `.admin-row` in admin.css is `display:flex; align-items:center`, and 17
   places in admin.html turn it into a COLUMN with an inline
   `flex-direction:column`. In a column, `align-items:center` shrink-wraps every
   child to its content and centres it: the field wrappers stop filling the
   dialog, so a 680px modal shows 180px inputs with their labels floating in
   the middle. The inline `width:100%` on the inputs is honoured — it is 100%
   of a wrapper that already collapsed.

   Stretch is the only sensible cross-axis rule for a stack of labelled fields,
   and this touches ONLY rows that already declared themselves columns. Wider
   than the Schedule tab on purpose: it is one bug, in one rule, and every
   dialog in the product has it. */
.admin-row[style*="flex-direction:column"],
.admin-row[style*="flex-direction: column"] { align-items: stretch; }

/* ── The Add / Edit task dialog ────────────────────────────────────────────
   This is the screen's only create path, and it was still painted for the
   obsidian shell: the crew box and the two "add" buttons carried web-green and
   sky-blue washes with #86efac / #7dd3fc TEXT — pale mint on white reads at
   about 1.4:1, so two of the three buttons in here were effectively invisible.
   Nothing in this dialog is a status, so nothing in it is coloured. */
.sch-box {
  background: var(--surface-flat-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 11px 12px;
}
.sch-box--note { font-size: 12.5px; color: var(--text-muted); }
.sch-box-lead { font-weight: 400; color: var(--text-dim); }
.sch-box-hint { font-size: 11.5px; color: var(--text-dim); margin-top: 6px; line-height: 1.5; }
.sch-box-hint--lead { margin: 2px 0 8px; }
.sch-addseg {
  width: 100%; padding: 10px; margin-top: 4px;
  background: var(--surface-flat-2); color: var(--text-2);
  border: 1px dashed var(--border-strong); border-radius: var(--r-sm);
  font-family: var(--font); font-weight: 600; font-size: 12.5px; cursor: pointer;
}
.sch-addseg:hover { border-color: var(--border-hover); color: var(--text); }

.sch-dep-row { display: flex; gap: 7px; align-items: center; margin-bottom: 7px; flex-wrap: wrap; }
.sch-fld { margin-bottom: 9px; }
.sch-fld-row { display: flex; gap: 8px; flex-wrap: wrap; }
.sch-lbl {
  display: block; margin-bottom: 4px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.075em; text-transform: uppercase;
  color: var(--text-label);
}
.sch-in {
  width: 100%; height: 32px; padding: 0 10px; box-sizing: border-box;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
  font-family: var(--font); font-size: 12.5px; color: var(--text);
}
.sch-in:focus { border-color: var(--accent); outline: none; }
/* A date, a count of days and a crew size are all numbers. */
.sch-in--num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 12px; }
.sched-stage-card {
  background: var(--surface-flat-2);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: 11px 12px; margin-bottom: 10px;
}
.sch-stage-hd { display: flex; align-items: center; justify-content: space-between; margin-bottom: 9px; }
.sch-stage-n  { font-size: 12.5px; font-weight: 600; color: var(--text); }
.sched-input  { background: var(--surface-flat); }

@media (pointer: coarse), (max-width: 860px) {
  .sch-in { height: 36px; }
}

/* The board is a table whose COLUMNS ARE THE DATA — a week does not stack, so
   it scrolls sideways inside its card (same rule as the calendar grid). */
@media (max-width: 860px) {
  .gnt-bar { gap: 8px; }
  .gnt-legend { margin-left: 0; width: 100%; }
  .gantt-scroll { max-height: 62vh; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   JOB WORKSPACE — "Ordinex Job Workspace - Redesign.dc.html"
   ═══════════════════════════════════════════════════════════════════════════
   Five tabs over ONE job. They share this vocabulary because they are the same
   screen asked five questions: a strip of figures, a banner when something
   needs a decision, and cards of rows that foot to a total.

   Everything list-shaped is plain `cw-*`. What lives here is only what those
   five tabs need and no other screen has: the job-wide toolbar, the group
   rings, the statement's grouped rows, and the two-column money headline.
   ═══════════════════════════════════════════════════════════════════════════ */

/* The job-wide actions. They are not a card's actions — they belong to the job,
   so they ride under the tab strip, right-aligned, at the header's 34px. */
.jw-tools {
  display: flex; align-items: center; justify-content: flex-end;
  gap: 8px; flex-wrap: wrap; margin-bottom: var(--block-gap);
}
.jw-tools .cw-btn, .jw-tools .cw-btn-dark { height: 34px; padding: 0 12px; font-size: 12.5px; }
.jw-tools-sp { flex: 1; }
.jw-tools select {
  height: 34px; padding: 0 10px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
  font-family: var(--font); font-size: 12.5px; color: var(--text);
}

/* "Everything here is filed" — an answer to a question the owner asked, which
   is why it is a line of text and not a card. A card would say the same thing
   at ten times the size, every day, forever. */
.cw-quietline {
  display: flex; align-items: center; gap: 8px; margin: 0;
  font-size: 12.5px; color: var(--success-ink);
}
.cw-quietline svg { width: 15px; height: 15px; flex: none; }

/* A link inside a sentence, made of a button because it acts rather than
   navigates. It must READ as the sentence around it, not as a control. */
.cw-linkbtn {
  border: 0; background: none; padding: 0; font: inherit;
  color: var(--accent-2); cursor: pointer;
}
.cw-linkbtn:hover { color: var(--accent-ink); text-decoration: underline; }

/* A KPI whose value is a link to the tab that explains it. The tile is the
   button — a second control inside it would be a click target for a thing the
   whole tile already means. */
.td-kpi--go { text-align: left; cursor: pointer; background: transparent; border: 0; font: inherit; }
.td-kpi--go:hover { background: var(--surface-flat-2); }
.td-kpi--go .td-kpi-label::after {
  content: '→'; margin-left: 6px; color: var(--text-empty); font-weight: 400;
}

/* ── Spend by group: one ring per group ─────────────────────────────────────
   A ring, not a bar. Five bars stacked read as a chart nobody asked for; five
   rings read as five gauges, which is what they are — this group against the
   money set aside for it. Where no budget is set the ring is a dim track and
   the foot says so, rather than an arc stuck at zero. */
.jw-rings {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 1px; border-top: 1px solid var(--border);
}
.jw-ring {
  display: flex; align-items: center; gap: 13px;
  padding: 12px 18px; background: var(--surface-flat);
  box-shadow: 0 0 0 1px var(--border-inner);
}
.jw-ring-svg { flex: none; transform: rotate(-90deg); }
.jw-ring-track { fill: none; stroke: var(--chrome-surface-2); stroke-width: 5; }
.jw-ring-arc   { fill: none; stroke-width: 5; stroke-linecap: round; }
.jw-ring-arc--ok   { stroke: var(--success); }
.jw-ring-arc--near { stroke: var(--warning); }
.jw-ring-arc--over { stroke: var(--error); }
.jw-ring-txt  { flex: 1; min-width: 0; }
.jw-ring-name { font-size: 12.5px; font-weight: 600; letter-spacing: -0.01em; }
.jw-ring-amt  {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 15px; font-weight: 600; margin-top: 2px;
}
.jw-ring-foot { font-size: 11px; color: var(--text-label); margin-top: 2px; line-height: 1.35; }
.jw-ring-foot--over { color: var(--error); }
.jw-ring-foot--ok   { color: var(--success-ink); }

/* ── Contract lines ─────────────────────────────────────────────────────────
   The grid template lives on the card, so the header, every row and the total
   read the same one. Only the progress cell is special: it holds a bar and the
   controls that move the number the bar draws. */
.jv-lines { --cw-cols: minmax(230px,1.5fr) minmax(140px,1fr) minmax(170px,1.1fr) 120px 120px 92px 40px; }
.jv-line-main { display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap; min-width: 0; }
.jv-line-desc { flex: 0 1 auto; }
/* The line name is editable in place, the same idiom the Projects list uses
   for a project name: it reads as text until the pointer lands on it. */
.jv-line-nameinput {
  align-self: center;
  box-sizing: content-box; max-width: 100%;
  height: 28px; padding: 0 7px;
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: transparent;
  font-family: var(--font); color: var(--text);
  text-overflow: ellipsis;
}
.jv-line-nameinput:hover { border-color: var(--border-strong); background: var(--surface-flat); }
.jv-line-nameinput:focus { border-color: var(--accent); background: var(--surface-flat); outline: none; }
.jv-line-nameerr:empty { display: none; }
.jv-line-nameerr { font-size: 11px; flex: none; }
.jv-progress  { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.jv-line-bar  {
  /* .cw-bar is flex:1 for a ROW; inside this column that grows its HEIGHT from
     a 0 basis and the bar disappeared entirely. It is a fixed 6px rule here. */
  flex: none; width: 92px; max-width: 100%;
}
.jv-earned-bar { display: flex; align-items: center; gap: 8px; margin-top: 5px; }
.jv-earned-bar .cw-bar { max-width: 110px; }

/* ── Statement: a group header, its rows, and the job's own total ───────────
   The header is the same tone as a total row because that is what it is — a
   subtotal, printed before the lines it covers rather than after. */
.jw-grp {
  display: flex; align-items: center; gap: 10px;
  padding: 9px var(--row-pad-x) 8px;
  border-top: 1px solid var(--border); background: var(--surface-flat-2);
}
.jw-grp-name { font-size: 12px; font-weight: 600; }
.jw-grp-n    { font-size: 11px; color: var(--text-label); }
.jw-grp-sp   { flex: 1; }
.jw-grp-tot  {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 12.5px; font-weight: 600;
}
/* An empty group still says why it is empty — a heading with nothing under it
   reads as a screen that failed to load. */
.jw-grp-empty { padding: 10px var(--row-pad-x); font-size: 12px; color: var(--text-dim);
                border-top: 1px solid var(--border-subtle); }

/* A statement row's date column: mono, because a date is read down a column. */
.jw-date {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 11.5px; color: var(--text-muted);
}
.jw-what { min-width: 0; }
.jw-what-t {
  display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap;
  font-size: 13px; font-weight: 600; letter-spacing: -0.01em;
}
.jw-what-n { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jw-what-s { font-size: 11px; color: var(--text-muted); margin-top: 2px;
             overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A line the recipe replaced: the number that WAS charged, shown quietly
   beside the one in force. */
.jw-was { text-decoration: line-through; color: var(--text-empty); }

/* The chip that says which task a line files under, and opens the picker. It
   is a sibling of the row, never inside it: most rows are already buttons. */
.jw-chip {
  display: inline-flex; align-items: center; gap: 5px; max-width: 100%;
  height: 24px; padding: 0 9px; border-radius: var(--r-pill);
  border: 1px solid var(--border-strong); background: var(--surface-flat);
  font-family: inherit; font-size: 11px; font-weight: 600; color: var(--text-2);
  cursor: pointer;
}
.jw-chip:hover { border-color: var(--border-hover); }
.jw-chip-n { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jw-chip svg { width: 10px; height: 10px; flex: none; }
/* Not filed yet — the one state on this row that is waiting on a decision, so
   the one that reads in the accent. */
.jw-chip--todo { color: var(--warning-ink); background: var(--warning-soft); border-color: var(--warning-border); }
.jw-chip--todo:hover { border-color: #E4CDA6; }
/* Calculated: overhead cannot be reassigned, so it is not a control at all. */
.jw-chip--fixed {
  color: var(--text-label); background: var(--chrome-surface-2);
  border-color: var(--border-inner); cursor: default;
}
.jw-chip--fixed:hover { border-color: var(--border-inner); }

/* ── The money headline (per-job P&L) ───────────────────────────────────────
   Two figures under one label when a period is chosen, one when it is not. */
.jw-heads {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 18px; padding: 16px var(--row-pad-x);
}
.jw-head-lbl { font-size: 11px; font-weight: 600; letter-spacing: 0.075em;
               text-transform: uppercase; color: var(--text-label); }
.jw-head-pair { display: flex; gap: 22px; margin-top: 7px; }
.jw-head-cap  { font-size: 10.5px; font-weight: 600; letter-spacing: 0.06em;
                text-transform: uppercase; color: var(--text-label); }
.jw-head-val  {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 21px; font-weight: 600; letter-spacing: -0.02em; margin-top: 2px;
}
.jw-head-val--ok  { color: var(--success-ink); }
.jw-head-val--err { color: var(--error); }
/* In period mode the headline is a two-column statement, so the figures sit in
   a row and step down a size — three big numbers per row would out-shout the
   tables under them. */
.pnl-heads .cw-row .jw-head-val { font-size: 17px; text-align: right; }
.pnl-heads .cw-colhead { padding-bottom: 6px; }
/* The caption over one half of a twin table is a HEADING for that table, not a
   column label — sentence case, so it is not a third copy of an uppercase
   label the verifier (rightly) counts as repetition. */
/* min() so the floor never wins over the card on a phone — a bare 360px
   minimum pushed the second half 3px past the card's own edge at 390px. */
.pnl-two { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(360px, 100%), 1fr)); gap: 1px;
           background: var(--border-subtle); }
.pnl-two-col { background: var(--surface-flat); min-width: 0; }
.pnl-two-cap { font-size: 12px; font-weight: 600; color: var(--text-muted);
               text-transform: none; letter-spacing: 0; padding: 8px var(--row-pad-x) 0; }

/* ── Production: what is installed, per item ────────────────────────────────
   Tiles, not a ring: installed-to-date is not a fraction of anything this
   screen knows. */
.jw-tiles {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px; padding: 0 var(--row-pad-x) 14px;
}
.jw-tile { border: 1px solid var(--border-inner); border-radius: var(--r-md); padding: 11px 14px; }
.jw-tile-lbl { font-size: 11px; font-weight: 600; letter-spacing: 0.075em;
               text-transform: uppercase; color: var(--text-label);
               display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.jw-tile-val {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 21px; font-weight: 600; letter-spacing: -0.02em; margin-top: 4px;
}
.jw-tile-unit { font-family: var(--font); font-size: 12px; font-weight: 500;
                color: var(--text-muted); margin-left: 5px; }
.jw-tile-foot { font-size: 11px; color: var(--text-label); margin-top: 3px; }

/* A day's quantities, as chips under the day that filed them. */
.jw-qtys { display: flex; gap: 7px; flex-wrap: wrap; margin-top: 6px; }
.jw-qty {
  display: inline-flex; align-items: baseline; gap: 7px;
  padding: 3px 10px; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: var(--surface-flat);
  font-size: 11.5px;
}
.jw-qty-n { font-weight: 600; color: var(--text-2); }
.jw-qty-v { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--text); }
.jw-qty-r { font-family: var(--font-mono); font-variant-numeric: tabular-nums;
            font-size: 10.5px; color: var(--text-label); }
/* An item the catalogue does not have. NOT called --warn: verify-redesign.js
   C17 reads any class containing "warn" as an alert and asks it for an action
   button, and this is a data flag on a chip, not an alert. */
.jw-qty--odd { border-color: var(--warning-border); background: var(--warning-soft); }
.jw-qty--odd .jw-qty-n { color: var(--warning-ink); }

/* A production report is a day, a crew and a handful of quantities — three
   columns, and the last one is a single control. */
.pr-row { --cw-cols: 116px 1fr 44px; align-items: start; }
.pr-nopdf { display: inline-flex; align-items: center; justify-content: center;
            width: 30px; height: 30px; }
.pr-nopdf svg { width: 14px; height: 14px; }

/* ── Cost Recipes: the two methods, side by side ────────────────────────────
   A choice between two things you can read, not a switch you have to remember
   the consequences of. */
.jw-methods {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 10px; padding: 0 var(--row-pad-x) 14px;
}
.jw-method {
  display: flex; align-items: flex-start; gap: 11px; text-align: left;
  padding: 12px 15px; border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-flat); font-family: inherit; color: inherit; cursor: pointer;
}
.jw-method:hover { border-color: var(--border-hover); }
.jw-method-mark {
  width: 16px; height: 16px; border-radius: 50%; flex: none; margin-top: 1px;
  border: 1.5px solid var(--border-hover); background: var(--surface-flat);
}
.jw-method--on { border-color: var(--warning-border); background: var(--warning-soft); }
.jw-method--on .jw-method-mark { border: 5px solid var(--ink); }
/* The text block beside the radio mark. Without flex:1 a min-width:0 child
   collapses to max-content and truncates its own second line (verifier C14). */
.jw-method-txt { flex: 1; min-width: 0; }
.jw-method-t { display: block; font-size: 13px; font-weight: 600; }
.jw-method-b { display: block; font-size: 11.5px; color: var(--text-muted); margin-top: 3px; line-height: 1.45; }
.jw-method-f { display: block; font-size: 11.5px; font-weight: 600; color: var(--text-2); margin-top: 5px; }

/* Cost Recipes: one item per row, its components in the panel under it. */
.rx-item { border-top: 1px solid var(--border); }
.rx-item-head { --cw-cols: 22px 1fr 200px; border-top: 0; }
.rx-total { --cw-cols: 1fr auto; }
/* The component grid IS the mock's five columns plus the remove control. */
.cx-lines { --cw-cols: minmax(190px,1.5fr) minmax(200px,1.2fr) 118px 130px 110px 36px; }
.cx-lines .cw-row { align-items: center; }

/* An item's components, opened under the item they belong to. */
.jw-parts { background: var(--surface-flat-2); border-top: 1px solid var(--border-subtle); }
.jw-parts .cw-colhead { border-bottom: 0; padding-top: 8px; }
.jw-parts .cw-row { background: transparent; }
.jw-parts .cw-row:hover { background: transparent; }
.jw-parts-acts { display: flex; gap: 8px; flex-wrap: wrap;
                 padding: 9px var(--row-pad-x) 11px; border-top: 1px solid var(--border-subtle); }
.jw-src--none { color: var(--error); }
/* An empty validation slot must not still spend a line of white inside the
   panel — same rule the cards already carry. */
.jw-parts > .admin-form-error:empty { display: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   SETTINGS — "Ordinex Settings - Redesign.dc.html"
   ═══════════════════════════════════════════════════════════════════════════
   Every card here is a FORM, and a form the width of a 1440px monitor is
   unreadable — the eye loses the line between the label and its box. One
   column, capped, like the mock.
   ═══════════════════════════════════════════════════════════════════════════ */

.st-stack { max-width: 760px; }
.st-fields {
  display: grid; grid-template-columns: 1fr 1fr; gap: 12px;
}
.st-fields--flush { margin-top: 14px; }
.st-field--wide { grid-column: 1 / -1; }
.cw-pad > .st-fields { margin-top: 0; }

/* The logo, its rules, and the one control that changes it. */
.st-logo-row { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.st-logo {
  width: 56px; height: 56px; border-radius: var(--r-md); flex: none;
  display: flex; align-items: center; justify-content: center; overflow: hidden;
  background: var(--chrome-surface-2); border: 1px solid var(--border);
  font-size: 10px; color: var(--text-label); text-align: center; padding: 4px;
}
.st-logo img { max-width: 100%; max-height: 100%; object-fit: contain; }
.st-logo-txt { flex: 1; min-width: 160px; }
.st-logo-name { font-size: 13px; font-weight: 600; }

/* A colour is a swatch and its code, in one box, because they are one value. */
.st-color {
  display: flex; align-items: center; gap: 9px; height: 34px; padding: 0 6px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
}
.st-color:focus-within { border-color: var(--accent); }
.st-swatch {
  width: 24px; height: 24px; flex: none; padding: 0; cursor: pointer;
  border: 1px solid var(--border-strong); border-radius: 6px; background: none;
}
.st-swatch::-webkit-color-swatch-wrapper { padding: 0; }
.st-swatch::-webkit-color-swatch { border: 0; border-radius: 4px; }
.st-color > input[type="text"] {
  flex: 1; min-width: 0; height: 30px; border: 0; padding: 0; background: none;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 12.5px; color: var(--text); text-transform: none; letter-spacing: 0;
}
.st-color > input[type="text"]:focus { outline: none; }

/* Jurisdiction: a choice you can READ, the same shape as the cost method. */
.st-radios { display: flex; flex-direction: column; gap: 8px; }
.st-radio {
  display: flex; align-items: flex-start; gap: 11px; padding: 10px 13px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-flat); cursor: pointer;
}
.st-radio:hover { border-color: var(--border-hover); }
.st-radio:has(input:checked) { border-color: var(--warning-border); background: var(--warning-soft); }
.st-radio input { margin: 2px 0 0; accent-color: var(--ink); flex: none; }
.st-radio-txt  { flex: 1; min-width: 0; }
.st-radio-name { display: block; font-size: 13px; font-weight: 600; }
.st-radio-desc { display: block; font-size: 11.5px; color: var(--text-muted); margin-top: 1px; line-height: 1.5; }

/* The regulatory notices: a label, a note that it was changed, and the text. */
.st-notice { margin-bottom: 12px; }
.st-notice:last-child { margin-bottom: 0; }
.st-notice > textarea {
  width: 100%; padding: 9px 11px; resize: vertical;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
  font-family: var(--font); font-size: 12.5px; font-weight: 400;
  letter-spacing: 0; text-transform: none; color: var(--text-2); line-height: 1.5;
}
.st-notice > textarea:focus { border-color: var(--accent); outline: none; }
.st-customized {
  font-weight: 500; text-transform: none; letter-spacing: 0; color: var(--warning-ink);
}

/* The role counts ride the standard strip, flush inside their card. */
.st-roles { border: 0; border-radius: 0; border-top: 1px solid var(--border); }

/* The save bar for the cards above it — the same right-aligned row the job
   workspace uses, because it is the same kind of thing. */
.st-save { margin-bottom: 0; }
.st-save .admin-form-error, .st-save .admin-form-success { margin: 0; }

/* A row whose right side is one action. Its second line is a SENTENCE, not a
   one-line summary, so it wraps — nowrap pushed the support address 137px past
   the card on a phone, where it could not be tapped. */
.st-act { --cw-cols: 1fr auto; align-items: start; }
.st-act .jw-what-s, .nx-device .jw-what-s, .nx-rule .jw-what-s {
  white-space: normal; overflow: visible; line-height: 1.5;
}

/* ═══════════════════════════════════════════════════════════════════════════
   NOTIFICATIONS
   ═══════════════════════════════════════════════════════════════════════════ */

.nx-stack { max-width: 940px; }
.nx-device, .nx-rule { --cw-cols: 32px 1fr auto; }
/* The reply-to row carries an input AND its save button — four cells, not
   three, and with three the button dropped out of the grid onto its own line. */
.nx-rule--save { --cw-cols: 32px 1fr auto auto; }
/* An event's icon is a MARKER, not a warning. .cw-banner-ic is the amber chip
   from the alert banner; borrowing it here painted seven orange tiles down a
   settings screen, and orange in this system means "waiting on you". */
.nx-ic {
  width: 32px; height: 32px; border-radius: var(--r-sm); flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--chrome-surface-2); color: var(--text-muted);
}
.nx-ic svg { width: 16px; height: 16px; }
.nx-rule--col { --cw-cols: 1fr; }
.nx-rule-row { display: grid; grid-template-columns: 32px 1fr auto; align-items: center; gap: 16px; }
/* The channel is a FACT about the row (this goes by email), not a state and
   certainly not something pending — accent here meant "waiting on you".
   Pendency #6, closed. */
.nx-channel { flex: none; }
.nx-recips { display: flex; flex-wrap: wrap; gap: 7px; align-items: center;
             margin-top: 9px; padding-left: 48px; }
.nx-chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 26px; padding: 0 6px 0 10px; border-radius: var(--r-pill);
  border: 1px solid var(--border-strong); background: var(--surface-flat);
  font-size: 11.5px; color: var(--text-2);
}
.nx-chip-x {
  width: 16px; height: 16px; display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%; background: transparent; color: var(--text-label);
  cursor: pointer; padding: 0;
}
.nx-chip-x:hover { background: var(--chrome-surface-2); color: var(--text); }
.nx-chip-x svg { width: 10px; height: 10px; }
/* Nobody listed: a decision not yet made, not a failure — caution ink, no italic. */
.nx-fallback { font-size: 11.5px; color: var(--warning-ink); font-style: normal; }
.nx-add { display: inline-flex; align-items: center; gap: 6px; }
.nx-add-input, .nx-reply {
  height: 26px; padding: 0 10px; border-radius: var(--r-pill);
  border: 1px dashed var(--border-strong); background: var(--surface-flat);
  font-family: var(--font); font-size: 11.5px; color: var(--text);
}
.nx-add-input { width: 190px; }
.nx-add-input:focus, .nx-reply:focus { border-style: solid; border-color: var(--accent); outline: none; }
.nx-reply { width: 230px; height: 30px; border-radius: var(--r-sm); border-style: solid; font-size: 12.5px; }
.nx-add-btn { width: 26px; padding: 0; justify-content: center; border-radius: 50%; }

/* The switch: green when on, because on means WORKING, not pending. */
.nx-switch {
  flex: none; width: 34px; height: 20px; border: 0; border-radius: var(--r-pill);
  background: var(--border-strong); position: relative; cursor: pointer;
}
.nx-switch .nx-knob {
  position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  border-radius: 50%; background: #fff; box-shadow: 0 0 0 1px var(--border-strong);
  transition: left 0.15s ease-out;
}
.nx-switch--on { background: var(--success); }
.nx-switch--on .nx-knob { left: 16px; }

/* The outbox is a list of dated records like every other. */
#notifOutboxList { --cw-cols: 118px 1fr 92px; --cw-min: 520px; }
.nx-status { font-size: 11.5px; font-weight: 600; }
.nx-status--wait { color: var(--warning-ink); }

/* ═══════════════════════════════════════════════════════════════════════════
   BILLING
   ═══════════════════════════════════════════════════════════════════════════ */

.bx-stack { max-width: 860px; }
.bx-plan { gap: 6px; }
.bx-pills { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 4px; }
/* The one number the whole screen exists to state. */
.bx-rate {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 34px; font-weight: 600; letter-spacing: -0.025em; line-height: 1.1;
}
.bx-rate-unit {
  font-family: var(--font); font-size: 15px; font-weight: 500;
  color: var(--text-muted); margin-left: 5px;
}
.bx-line   { font-size: 12.5px; color: var(--text-2); }
.bx-detail { color: var(--text-muted); }
/* The band this org is actually in, marked on the strip rather than described. */
.bx-tiers .bx-tier--on { background: var(--warning-soft); }
.bx-tiers .bx-tier--on .td-kpi-foot { color: var(--warning-ink); font-weight: 600; }
.bx-field { flex: 0 0 auto; min-width: 130px; }
.bx-field--n { min-width: 110px; max-width: 130px; }
.bx-quote {
  flex-basis: 100%; margin: 2px 0 0; padding: 11px 13px;
  background: var(--surface-flat); border: 1px solid var(--border-inner);
  border-radius: var(--r-md); font-size: 12.5px; color: var(--text-2);
}
.bx-warnbox {
  padding: 10px 12px; border-radius: var(--r-md); margin-top: 4px;
  background: var(--warning-soft); border: 1px solid var(--warning-border);
  font-size: 12.5px; color: var(--warning-ink);
}

/* ═══════════════════════════════════════════════════════════════════════════
   FORMS + TRADE PACKS
   ═══════════════════════════════════════════════════════════════════════════ */

/* A banner that states a GUARANTEE rather than a problem. Same anatomy, neutral
   surface — amber here would read as "something is wrong with your forms". */
.cw-banner--calm { background: var(--surface-flat); border-color: var(--border); }
.cw-banner--calm .cw-banner-ic { background: var(--chrome-surface-2); color: var(--text-muted); }
.cw-banner--calm .cw-banner-s  { color: var(--text-muted); }

.fb2-grid, .tp-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px;
}
.fb2-card {
  background: var(--surface-flat); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: 13px 15px;
  display: flex; flex-direction: column; gap: 9px;
}
.fb2-card:hover { border-color: var(--border-hover); }
.fb2-head { display: flex; align-items: center; gap: 10px; }
.fb2-ic {
  width: 30px; height: 30px; border-radius: var(--r-sm); flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--chrome-surface-2); color: var(--text-muted);
}
.fb2-ic svg { width: 15px; height: 15px; }
.fb2-main  { flex: 1; min-width: 0; }
.fb2-title { font-size: 13.5px; font-weight: 600; letter-spacing: -0.01em; }
.fb2-sub   { font-size: 11px; color: var(--text-muted); margin-top: 1px;
             overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fb2-foot  { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fb2-meta  { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }
.fb2-count { font-family: var(--font-mono); font-variant-numeric: tabular-nums;
             font-size: 11px; color: var(--text-label); }
.fb2-actions { display: flex; align-items: center; gap: 6px; margin-left: auto; }

/* Trade packs: the ones running are the warm cards, the rest are quiet. */
.tp-stack { max-width: 940px; }
.tp-card {
  display: flex; gap: 13px; padding: 14px 16px; margin-bottom: 10px;
  background: var(--surface-flat); border: 1px solid var(--border); border-radius: var(--r-lg);
}
.tp-card--active { background: var(--warning-soft); border-color: var(--warning-border); }
.tp-ic {
  width: 32px; height: 32px; border-radius: var(--r-sm); flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--chrome-surface-2); color: var(--text-muted);
}
.tp-card--active .tp-ic { background: #FBE7CB; color: var(--warning-ink); }
.tp-ic svg { width: 16px; height: 16px; }
.tp-hero-main { flex: 1; min-width: 0; }
.tp-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tp-name { font-size: 13.5px; font-weight: 600; letter-spacing: -0.01em; }
.tp-desc { margin: 5px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--text-muted); }
.tp-card--active .tp-desc { color: var(--warning-ink); }
.tp-hero-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 11px; }
/* A section label over a group of cards — the same uppercase rule the tables
   use, without the grid it normally sits on. */
.tp-sect { display: block; border-bottom: 0; padding: 0 0 6px; }
.fb2-new { margin: 0; }

/* Gloves, not a mouse: every in-row control grows to a real target on a phone,
   while the desk keeps the compact 24-26px the design calls for. */
/* The 44px invisible hit area (admin.css, touch ergonomics 2026-08-08) lists
   its selectors one by one, and every control this redesign introduced was
   born after that list. A 28px pill is fine to look at and not fine to hit
   with a glove, so the same treatment is extended here rather than leaving
   the new vocabulary a size below the old.

   Expect verify-redesign.js C15 to report these as "overflowing" below
   1024px. It measures scroll extent and this pseudo-element is wider than
   its button ON PURPOSE; it has no background and clips nothing. */
@media (max-width: 1023px) {
  .cw-pill, .eq-chip-all, .eq-chip-site, .eq-row-btn, .ec-pick,
  .cw-btn, .cw-btn-dark, .cal-nav-btn,
  .jw-chip, .jv-plan-btn, .jv-rate-total-link, .jv-qty-amt--go { position: relative; }
  .cw-pill::after, .eq-chip-all::after, .eq-chip-site::after, .eq-row-btn::after,
  .ec-pick::after, .cw-btn::after, .cw-btn-dark::after, .cal-nav-btn::after,
  .jw-chip::after, .jv-plan-btn::after, .jv-rate-total-link::after, .jv-qty-amt--go::after {
    content: ''; position: absolute;
    top:    min(0px, calc((100% - 44px) / 2));
    bottom: min(0px, calc((100% - 44px) / 2));
    left:   min(0px, calc((100% - 44px) / 2));
    right:  min(0px, calc((100% - 44px) / 2));
  }
}

@media (pointer: coarse), (max-width: 860px) {
  /* Density goes back to comfortable. The tight desk row is 9px because a
     mouse lands where you point it; a thumb does not, and the crew runs this
     with gloves on. This is the same `--row-pad` knob the handoff drew as a
     Comfortable|Compact switch — the switch is just the input device. */
  :root { --row-pad: 13px; --block-gap: 14px; }
  .cw-mini, .cw-pick { height: 34px; padding: 0 12px; font-size: 12px; }
  .cw-seg-btn { height: 34px; padding: 0 14px; }
  .cw-btn-dark--sm { height: 34px; padding: 0 13px; font-size: 12px; }
  .cw-input-mono { height: 36px; }
  /* The row controls the redesign added grow with everything else. */
  .cw-pill, .eq-chip-all, .eq-chip-site { height: 34px; padding: 0 14px; }
  /* Grown to 34px the pair no longer fits the slot the 28px pair sat in, so
     it stops shrinking and takes its own line instead of clipping. */
  .eq-row-btn { width: 34px; height: 34px; }
  .eq-row-actions { flex: none; }
  .ec-pick { height: 34px; }
  /* Anything you TYPE into or pick from goes to 36px. At the desk 30-32px is
     a tidy control; with a glove on it is a miss. */
  .cw-field > input, .cw-field > select,
  .cw-head-r input, .cw-head-r select,
  .cw-controls > select, .cw-controls > input,
  .cw-expand-acts select,
  .cw-search, .ec-label, .cr-trade-name, .cw-banner-btn { height: 36px; }
  .ec-rate { height: 36px; }
  .cw-rowacts { gap: 6px; }
  .cw-rowacts .ox-iconbtn { width: 36px; height: 36px; }
  .cw-mx { width: 34px; height: 34px; }
  .cw-chip { padding: 3px 6px 3px 9px; font-size: 11.5px; }
  .cw-chip-x { width: 22px; height: 22px; font-size: 12px; }
}

/* Below ~860px a five-column roster cannot be read side by side, so the row
   stops being a grid and stacks into a labelled card. The column header hides
   with it — a label per record is the thing tables exist to avoid, but with
   one record per screen there is no table left to label.

   860 and not 760: an iPad in portrait is 768 CSS px, which used to land just
   ABOVE the old breakpoint and got a table you had to swipe sideways to read
   the status column — the one thing you open Deliveries to see. It also covers
   the 761–839 band that has broken layouts on this project before.

   A grid whose COLUMNS ARE THE DATA opts out with .cw-keepgrid and scrolls
   sideways instead: in the certification matrix a cell means nothing without
   its column header, so stacking it yields a row of unlabelled circles — the
   treatment survives, the meaning does not. */
@media (max-width: 860px) {
  .cw-card:not(.cw-keepgrid) .cw-scroll  { overflow-x: visible; }
  .cw-card:not(.cw-keepgrid) .cw-track   { min-width: 0; }
  .cw-card:not(.cw-keepgrid) .cw-colhead { display: none; }
  .cw-card:not(.cw-keepgrid) .cw-row,
  .cw-card:not(.cw-keepgrid) .cw-total { grid-template-columns: 1fr; gap: 8px; }
  .cw-card:not(.cw-keepgrid) .cw-row > * { min-width: 0; }
  /* Stacked, the total's figures lose their column headers too — four bare
     amounts under each other say nothing about which is which. */
  .cw-card:not(.cw-keepgrid) .cw-row [data-cw-lbl]::before,
  .cw-card:not(.cw-keepgrid) .cw-total [data-cw-lbl]::before {
    content: attr(data-cw-lbl) '  ';
    font-size: 11px; font-weight: 600; letter-spacing: 0.075em;
    color: var(--text-label);
  }
  .cw-card:not(.cw-keepgrid) .cw-today,
  .cw-card:not(.cw-keepgrid) .cw-num,
  .cw-card:not(.cw-keepgrid) .cw-total-num { text-align: left; }
  .cw-card:not(.cw-keepgrid) .cw-total-lbl { padding-left: 0; }
  .cw-card:not(.cw-keepgrid) .cw-rowacts { justify-content: flex-start; }
  /* Stacked, a record gets the full card width — truncating the one line that
     names it (a deficiency, a document) buys nothing back. */
  .cw-card:not(.cw-keepgrid) .cw-pname { white-space: normal; }
  /* The chevron says "this row opens". Stacked it lands on a line of its own
     above the record, reading as a stray glyph — the whole card is the button
     by then, so it has nothing left to say. */
  .cw-card:not(.cw-keepgrid) .cw-row > .cw-chevron { display: none; }
  /* Projects stacks on the same rule as every other list. */
  .plist .plist-colhead { display: none; }
  .plist .plist-row, .plist .plist-total { grid-template-columns: 1fr; gap: 8px; }
  .plist .plist-row [data-cw-lbl]::before {
    content: attr(data-cw-lbl) '  ';
    font-size: 11px; font-weight: 600; letter-spacing: 0.075em; color: var(--text-label);
  }
  /* No hover on a touch screen: the box has to show its own edge, or nothing
     on the row says the name can be edited. */
  .plist .plist-nameinput, .plist .pcard-code-input, .jv-line-nameinput {
    border-color: var(--border-strong); background: var(--surface-flat);
  }
  /* An odd last KPI would leave a hole beside itself once the strip wraps. */
  .td-kpis > .td-kpi:last-child:nth-child(odd) { grid-column: 1 / -1; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   DIALOGS (Ordinex Dialogs - Redesign.dc.html)
   ═══════════════════════════════════════════════════════════════════════════
   26 overlays across the modules, all of them already sharing
   .admin-modal-overlay / .admin-modal / .admin-modal-title / body / footer —
   so the house style lands once, here, instead of 26 times.

   The behaviour the sheet asks for (Esc cancels, a visible way out, the safe
   button holding focus on a destructive dialog) is in js/admin/00-shell.js for
   the same reason.

   Note .admin-modal-actions: NINE dialogs use it as their button row and it
   had no rule anywhere — a bare div with browser defaults. It gets the same
   footer as .admin-modal-footer below. */
.admin-modal-overlay {
  /* Warm scrim, not black: the page behind stays legible as context instead of
     going to ink. */
  background: rgba(26, 24, 21, 0.38);
}
.admin-modal {
  border: 1px solid var(--border);
  border-radius: 20px 20px 0 0;
  max-width: 460px;
  box-shadow: 0 24px 60px -30px rgba(26, 24, 21, 0.35);
}
@media (min-width: 520px) { .admin-modal { border-radius: var(--r-lg); } }

.admin-modal-header {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 15px 18px 12px; border-bottom: 1px solid var(--border-subtle);
}
.admin-modal-title {
  font-size: 14px; font-weight: 600; letter-spacing: -0.01em; flex: 1; min-width: 0;
  padding-right: 30px;                    /* never runs under the × */
}
/* Where the dialog came from — a line the mock puts under every title. Optional
   per dialog; nothing breaks without it. */
.admin-modal-from { font-size: 11.5px; color: var(--text-label); margin: 2px 0 0; }
.admin-modal { position: relative; }
.dlg-x {
  position: absolute; top: 11px; right: 11px; z-index: 1;
  width: 26px; height: 26px; flex: none; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 7px; background: transparent;
  color: var(--text-label); cursor: pointer;
}
.dlg-x:hover { background: var(--surface-flat-3); color: var(--text); }
.dlg-x svg { width: 12px; height: 12px; }

.admin-modal-body { padding: 14px 18px; display: flex; flex-direction: column; gap: 12px; }
.admin-modal-body > p { margin: 0; font-size: 12.5px; color: var(--text-2); line-height: 1.55; }

/* Some dialogs (the invite sheet, and every one built before .admin-modal-body
   existed) drop their content straight into .admin-modal — which has never had
   padding of its own, so those sat flush against the box edge. The structural
   rows carry their own padding and opt out; everything else gets the gutter. */
.admin-modal > :not(.admin-modal-header):not(.admin-modal-body):not(.admin-modal-footer):not(.admin-modal-actions):not(.adm-sheet-footer):not(.dlg-x) {
  padding-left: 18px; padding-right: 18px;
}
.admin-modal > .admin-modal-title { margin-top: 15px; }
.admin-modal > .admin-section-sub { margin-bottom: 12px; }
/* An error slot with nothing in it still reserved its line (inline min-height),
   so several dialogs opened with a band of dead space above the buttons. */
.admin-modal .admin-form-error:empty, .admin-modal .admin-form-success:empty { display: none; }

.admin-modal-footer, .admin-modal-actions, .admin-modal .adm-sheet-footer {
  display: flex; align-items: center; justify-content: flex-end; gap: 8px;
  padding: 12px 18px; border-top: 1px solid var(--border-subtle);
  background: var(--surface-flat-2); flex-shrink: 0;
}
/* The left-hand line in the footer: what this dialog will cost, how many are
   selected, why the primary is disabled. */
.admin-modal-footer .dlg-foot, .admin-modal-actions .dlg-foot {
  flex: 1; min-width: 0; font-size: 11px; color: var(--text-label); text-align: left;
}

/* A note block inside a dialog, in the four tones the sheet defines. */
.dlg-note {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 10px 12px; border-radius: var(--r-sm);
  background: var(--surface-flat-2); border: 1px solid var(--border-inner);
  font-size: 11.5px; line-height: 1.5; color: var(--text-2);
}
.dlg-note svg { width: 14px; height: 14px; flex: none; margin-top: 1px; color: var(--text-label); }
.dlg-note--ok   { background: var(--success-soft); border-color: #CFE3D8; color: var(--success-ink); }
.dlg-note--ok svg { color: var(--success-ink); }
.dlg-note--warn { background: var(--warning-soft); border-color: var(--warning-border); color: var(--avatar-ink); }
.dlg-note--warn svg { color: var(--warning-ink); }
.dlg-note--err  { background: var(--error-soft); border-color: #F0D4D1; color: var(--error-ink); }
.dlg-note--err svg { color: var(--error-ink); }

/* PENDING #5 — the primary button. Half the app was near-black and half was
   orange; orange means "waiting on you" in this system, never "click here".
   One rule closes it for every screen, not just the dialogs. */
.admin-btn-primary {
  background: var(--ink); border-color: var(--ink); color: var(--on-ink);
  border-radius: var(--r-sm); font-family: var(--font); font-size: 12.5px;
  font-weight: 600; letter-spacing: 0; padding: 0 13px; height: 32px;
}
.admin-btn-primary:hover:not(:disabled) { background: var(--ink-hover); border-color: var(--ink-hover); }
.admin-btn-primary:active:not(:disabled) { transform: none; }
.admin-btn-primary:disabled { background: var(--text-empty); border-color: var(--text-empty); color: var(--on-ink); opacity: 1; }
.admin-btn-secondary, .admin-btn-ghost {
  border-radius: var(--r-sm); font-family: var(--font); font-size: 12.5px;
  font-weight: 600; letter-spacing: 0; padding: 0 12px; height: 32px;
  background: var(--surface-flat); border: 1px solid var(--border-strong); color: var(--text-2);
}
.admin-btn-secondary:hover, .admin-btn-ghost:hover { border-color: var(--border-hover); background: var(--surface-flat); color: var(--text); }
/* Destructive: filled red, and only where the action really destroys data. */
.admin-btn-danger, .dlg-danger {
  border-radius: var(--r-sm); font-family: var(--font); font-size: 12.5px;
  font-weight: 600; letter-spacing: 0; padding: 0 13px; height: 32px;
  background: var(--error); border: 1px solid var(--error); color: var(--on-ink);
}
.admin-btn-danger:hover, .dlg-danger:hover { background: var(--error-bright); border-color: var(--error-bright); }
.admin-btn-primary svg, .admin-btn-secondary svg, .admin-btn-danger svg { width: 13px; height: 13px; }

/* Fields inside a dialog read like fields everywhere else in the redesign. */
.admin-modal .admin-label, .admin-modal .field-label, .admin-modal .adm-lbl {
  font-size: 11px; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--text-label); margin-bottom: 5px;
}
.admin-modal .admin-input, .admin-modal .field-input, .admin-modal .adm-inp,
.admin-modal select, .admin-modal input[type="text"],
.admin-modal input[type="number"], .admin-modal input[type="date"], .admin-modal input[type="email"] {
  height: 36px; padding: 0 11px; border: 1px solid var(--border-strong);
  border-radius: var(--r-sm); background: var(--surface-flat);
  font-family: var(--font); font-size: 13px; color: var(--text);
}
.admin-modal textarea.admin-input, .admin-modal textarea.field-input {
  height: auto; min-height: 74px; padding: 8px 11px; line-height: 1.5;
}
.admin-modal .admin-input:focus, .admin-modal .field-input:focus, .admin-modal select:focus {
  border-color: var(--accent); outline: none;
}
@media (pointer: coarse), (max-width: 860px) {
  .admin-btn-primary, .admin-btn-secondary, .admin-btn-ghost, .admin-btn-danger { height: 40px; }
  .dlg-x { width: 40px; height: 40px; }
  .admin-modal .admin-input, .admin-modal .field-input, .admin-modal select { height: 40px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   FORM BUILDER — the editor (Ordinex Form Builder - Redesign.dc.html)
   ═══════════════════════════════════════════════════════════════════════════
   Three columns: what you can add · the form itself · the PDF it prints.
   The middle column is drawn by the SHARED FIELD REGISTRY — the same code the
   field app runs — so "live form" is literal here, not an impression of one.
   The mock draws its own approximation of each control; the code has the real
   thing, and the code wins (DESIGN.md). What the mock contributes and the old
   editor lacked is the METADATA around each field: why it can't be deleted,
   when it appears, which block owns its content. */
.fbe-head { display: flex; flex-direction: column; gap: 8px; }

/* Reset/Delete is the one destructive control up here, and it only says so
   under the cursor — a red button sitting beside Save reads as an alarm. */
.fbe-danger:hover { border-color: #D9A6A0; color: var(--error-ink); background: var(--error-row); }
.fbe-act--on { background: var(--surface-flat-3); }

/* Version history — the same list vocabulary as every other table. There is no
   author column: form_schemas has no created_by, so the mock's "who" would be
   an invented name. What the row CAN say is where the version came from. */
.fbe-hist .cw-colhead, .fbe-hist .cw-row {
  grid-template-columns: 68px minmax(120px, 1fr) minmax(120px, 1fr) 122px 84px 92px;
}

/* Card bar: what this column is, and what you can do to it. */
.fbe-bar {
  display: flex; align-items: center; gap: 9px;
  padding: 10px var(--row-pad-x); border-bottom: 1px solid var(--border-inner);
  background: var(--surface-flat-2);
  font-size: 11px; font-weight: 600; letter-spacing: 0.075em; text-transform: uppercase;
  color: var(--text-label);
}

/* ── Left column: the palette, or the selected field's properties ──────────── */
.fbe-pal { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--border-subtle); }

/* Thirteen types in two columns leaves a hole, and a hole with a border round
   it reads as a fourteenth type that is switched off. */
.fbe-pal-i:last-child:nth-child(odd) { grid-column: 1 / -1; }

.fbe-insp-type {
  padding: 11px var(--row-pad-x) 0;
  font-size: 11px; font-weight: 600; letter-spacing: 0.075em; color: var(--text-label);
}
.fbe-props { display: flex; flex-direction: column; gap: 11px; padding: 8px var(--row-pad-x) 16px; }
.fbe-props .cw-field > textarea {
  min-height: 74px; padding: 8px 11px; width: 100%; resize: vertical;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat);
  font-family: var(--font); font-size: 13px; font-weight: 400; letter-spacing: 0;
  text-transform: none; color: var(--text); line-height: 1.5;
}
.fbe-props .cw-field > textarea:focus { border-color: var(--accent); outline: none; }
.fbe-props .cw-field > input:disabled {
  background: var(--surface-flat-3); color: var(--text-muted); cursor: default;
}
.fbe-hint { font-size: 11px; font-weight: 400; letter-spacing: 0; text-transform: none;
            color: var(--text-label); }
.fbe-tog { display: flex; align-items: center; gap: 9px; cursor: pointer; font-size: 12.5px; color: var(--text); }
.fbe-tog input { width: 16px; height: 16px; accent-color: var(--ink); flex: none; margin: 0; }
.fbe-cond { padding-top: 11px; border-top: 1px solid var(--border-subtle); display: flex; flex-direction: column; gap: 7px; }
.fbe-cond-h { font-size: 11px; font-weight: 600; letter-spacing: 0.075em; color: var(--text-label); }
.fbe-cond-eq { display: flex; align-items: center; gap: 7px; }
.fbe-cond-eq > span { font-size: 11.5px; color: var(--text-muted); flex: none; }
.fbe-cond select, .fbe-cond input {
  height: 32px; padding: 0 10px; width: 100%; min-width: 0;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat); font-family: var(--font); font-size: 12.5px; color: var(--text);
}
.fbe-cond select:focus, .fbe-cond input:focus { border-color: var(--accent); outline: none; }

/* The field draws itself through the registry, so it must not answer the
   mouse: every click belongs to the shell that selects the field. */
.fbe-body { pointer-events: none; }

/* The field app's controls are sized for a glove on a phone. Shrunk to desk
   scale here so eleven fields fit a screen — and the padding has to come down
   WITH the height, or a 32px control keeps 12px of top padding and clips its
   own text (which is exactly how "Select…" went invisible). */
.fbe-body .field-input, .fbe-body .field-select, .fbe-body .field-textarea {
  height: 32px; padding: 0 10px; font-size: 12.5px; border-radius: var(--r-sm);
}

/* The app stacks the options one per line because a thumb needs the width;
   on the canvas that turns a two-option question into two full-width bars.
   flex-direction has to be named — .radio-group is already a column flex, so
   `display:flex` alone changes nothing. */
.fbe-body .radio-group, .fbe-body .checkbox-grid {
  display: flex; flex-direction: row; flex-wrap: wrap; gap: 6px; grid-template-columns: none;
}

/* The other content libraries stay closed: they belong to forms this template
   may not even have, and the count on the summary is the whole answer most
   days. */
.fbe-ce-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--block-gap); }

@media (max-width: 1240px) {

}
@media (max-width: 860px) {

  .fbe-hist .cw-colhead { display: none; }
  .fbe-hist .cw-row { grid-template-columns: 1fr; gap: 6px; }

}
/* Gloves again: the in-row controls this screen adds join the 44px hit area. */
@media (max-width: 1023px) {

}
@media (pointer: coarse), (max-width: 860px) {
  .fbe-props .cw-field > input, .fbe-props .cw-field > select,
  .fbe-cond select, .fbe-cond input,
  .fbe-row > input, .fbe-row select, .fbe-sec-head input { height: 36px; }

  .fbe-check input, .fbe-tog input, .fbe-hazard input { width: 18px; height: 18px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   DARK THEME — deliberately not redefined.

   The app ships [data-theme="dark"]. The redesign was specified light-first and
   its warm neutrals have no agreed dark counterpart yet, so the two themes
   currently disagree. Decided 2026-08-12 (owner hit the broken mix in the
   field): the toggle is DROPPED for now. admin.html and calendar.html stamp
   light unconditionally, and the switch is hidden below, until a warm dark
   ramp is designed.
   ═══════════════════════════════════════════════════════════════════════════ */
#adminThemeToggle { display: none; }
/* The field app carried three of these (Today, the job list, the desktop rail).
   The buttons are gone from index.html; this catches any that come back. */
.dash-theme-toggle { display: none !important; }

/* ═══════════════════════════════════════════════════════════════════════════
   PART D — THE FIELD APP  ("Ordinex Field App - Redesign.dc.html")
   ═══════════════════════════════════════════════════════════════════════════

   index.html only. The admin's density knob does NOT apply here: the field
   runs this with gloves on, so nothing tappable goes under 44px and the rows
   stay comfortable. Same vocabulary as the admin otherwise — white cards on
   #F7F6F3, 1px borders, no shadows, mono for numbers, near-black for the one
   primary action, accent for "pending" and nothing else.
   ═══════════════════════════════════════════════════════════════════════════ */

.fx-wrap {
  max-width: 560px;
  margin: 0 auto;
  padding: 14px 14px calc(40px + env(safe-area-inset-bottom, 0px));
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* ── Delivery vs pickup (owner request, 2026-08-14) ────────────────────────
   Two ways material lands on a job, one screen. A segmented pair rather than a
   dropdown: the choice changes what the form ASKS, so it has to be readable
   without opening anything, and both options have to be one tap on a phone in
   gloves — 46px, above the 44px floor this app holds everywhere. */
.deliv-mode {
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px;
  padding: 4px;
  background: var(--surface-flat-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  margin-bottom: 12px;
}
.deliv-mode-btn {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  min-height: 46px; padding: 0 10px;
  background: transparent; border: 1px solid transparent;
  border-radius: var(--r-sm);
  font-family: var(--font); font-size: 13.5px; font-weight: 600;
  color: var(--text-2); cursor: pointer;
}
.deliv-mode-btn .ip-ic svg { width: 16px; height: 16px; }
.deliv-mode-btn:hover { color: var(--text); }
.deliv-mode-btn.active {
  background: var(--surface-flat);
  border-color: var(--border-strong);
  color: var(--text);
}

/* ── App bar ─────────────────────────────────────────────────────────────── */
.fx-appbar {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 2px; min-height: 44px;
  /* Today and the job list: the bell and the avatar sit in this row. */
  padding-top: env(safe-area-inset-top, 0px);
}
.fx-appbar .dash-header-left  { display: flex; align-items: center; gap: 9px; flex: 1; min-width: 0; }
.fx-appbar .dash-header-right { display: flex; align-items: center; gap: 6px; flex: none; }
.fx-appbar .brand-word { font-size: 14.5px; font-weight: 700; letter-spacing: -.01em; color: var(--text); }
.fx-appbar .dash-brand-txt { display: flex; align-items: center; }

/* Connection pill — the only place accent-adjacent colour is allowed in the
   bar, because "not sent yet" is exactly the pending meaning accent carries. */
.fx-net {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px 2px 6px; border-radius: var(--r-pill);
  font-size: 10.5px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  background: var(--warning-soft); border: 1px solid var(--warning-border); color: var(--warning-ink);
  white-space: nowrap;
}
.fx-net::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--warning); flex: none;
}
.fx-net--queue { background: var(--accent-soft); border-color: var(--warning-border); color: var(--accent-ink); }
.fx-net--queue::before { background: var(--accent); }

.fx-adminlink {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px; padding: 0 11px;
  background: transparent; border: 1px solid var(--border-strong); border-radius: var(--r-pill);
  font-family: inherit; font-size: 11.5px; font-weight: 600; color: var(--text-2);
  cursor: pointer;
}
.fx-adminlink i { width: 13px; height: 13px; }
.fx-adminlink:hover { border-color: var(--border-hover); }

/* Icon button in the bar (the actions bell). 44px, square, quiet. */
.fx-appbar .dash-bell, .fx-appbar .dash-avatar {
  width: 44px; height: 44px; border-radius: var(--r-sm);
  border: 1px solid var(--border-strong); background: var(--surface-flat);
  color: var(--text-2); position: relative;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.fx-appbar .dash-bell i { width: 17px; height: 17px; }
.fx-appbar .dash-avatar {
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--avatar-soft); color: var(--avatar-ink);
  border-color: transparent; font-size: 11.5px; font-weight: 600;
}
.fx-appbar .dash-bell-count {
  position: absolute; top: -4px; right: -4px;
  min-width: 18px; padding: 1px 5px; border-radius: var(--r-pill);
  background: var(--error); color: #fff;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 10px; font-weight: 600; line-height: 16px; text-align: center;
  box-shadow: none;
}

/* ── The one-line hello ──────────────────────────────────────────────────── */
.fx-hello-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.fx-hello {
  display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--text-muted); margin: -2px 0 0;
}
.dash-hello-right:empty { display: none; }
/* The relocated bell keeps the app bar's shape (44px, bordered, badge). */
.dash-hello-right .dash-bell {
  width: 44px; height: 44px; border-radius: var(--r-sm);
  border: 1px solid var(--border-strong); background: var(--surface-flat);
  color: var(--text-2); position: relative;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.dash-hello-right .dash-bell-count {
  position: absolute; top: -4px; right: -4px;
  min-width: 18px; padding: 1px 5px; border-radius: var(--r-pill);
  background: var(--error); color: #fff; box-shadow: none;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 10px; font-weight: 600; line-height: 16px;
}
.fx-hello-sep { color: var(--text-label); }
.fx-hello #dashWeather[hidden] + .fx-hello-sep,
.fx-hello .fx-hello-sep:last-child { display: none; }

/* ── The job button — the context, as one target ─────────────────────────── */
.fx-jobbtn {
  display: flex; align-items: center; gap: 9px; width: 100%;
  min-height: 46px; padding: 0 13px;
  background: var(--surface-flat-2); border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  font-family: inherit; font-size: 13.5px; font-weight: 600; color: var(--text);
  cursor: pointer; text-align: left;
}
.fx-jobbtn:hover { border-color: var(--border-hover); }
.fx-jobbtn > i { width: 15px; height: 15px; color: var(--text-dim); flex: none; }
.fx-jobbtn-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fx-jobbtn-swap {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 11px; font-weight: 600; color: var(--text-dim); flex: none;
}
.fx-jobbtn-swap i { width: 13px; height: 13px; }
/* The old text link is redundant with the button above and stays out of the
   layout even when a caller unhides it. */
.dash-alljobs-link { display: none !important; }

/* ── Labels, sections, cards ─────────────────────────────────────────────── */
.fx-label {
  font-size: 11px; font-weight: 600; letter-spacing: .075em;
  text-transform: uppercase; color: var(--text-label);
}
.fx-sec { display: flex; flex-direction: column; gap: 7px; }
.fx-card {
  background: var(--surface-flat); border: 1px solid var(--border-inner);
  border-radius: var(--r-lg); padding: 12px 13px;
}
.fx-rows { display: flex; flex-direction: column; gap: 6px; }

/* ── A row: dot, name, what it owes ──────────────────────────────────────── */
.fx-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 46px; padding: 7px 12px;
  background: var(--surface-flat); border: 1px solid var(--border-subtle);
  border-radius: var(--r-md);
  font-family: inherit; text-align: left; cursor: pointer; color: var(--text);
}
.fx-row:hover { border-color: var(--border-strong); }
.fx-row:disabled { cursor: default; opacity: .55; }
.fx-row-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; }
.fx-row-name { font-size: 13.5px; font-weight: 600; flex: 1; min-width: 0; }
.fx-row-txt  { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.fx-row-sub  { font-size: 11.5px; font-weight: 400; color: var(--text-dim); }
.fx-row-ic   { font-size: 17px; flex: none; line-height: 1; }
.fx-row-lead { display: flex; flex: none; color: var(--text-dim); }
.fx-row-lead svg { width: 16px; height: 16px; }
.fx-row-chev { color: var(--text-label); display: flex; flex: none; }
.fx-row-chev i { width: 15px; height: 15px; }
.fx-row-side { display: flex; align-items: center; gap: 8px; flex: none; }
.fx-row-ok   { font-size: 11.5px; font-weight: 600; color: var(--success); }
.fx-row-mut  { font-size: 11.5px; color: var(--text-dim); }
.fx-row-go {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 32px; padding: 0 12px; border-radius: var(--r-sm);
  background: var(--ink); color: var(--on-ink);
  font-size: 12px; font-weight: 600;
}
/* Only the half-finished row gets the rail: it is the one that is actually
   pending. "Not yet" is a schedule, not an exception. */
.fx-row--draft {
  border-color: var(--warning-border); background: var(--warning-soft);
  border-left: 3px solid var(--accent); padding-left: 10px;
}
.fx-row--done .fx-row-dot { background: var(--success); }

/* ── Two-up tiles (this week / streak) ───────────────────────────────────── */
.fx-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.fx-tile {
  background: var(--surface-flat); border: 1px solid var(--border-inner);
  border-radius: var(--r-md); padding: 10px 12px;
}
.fx-tile-v {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 19px; font-weight: 600; margin-top: 3px; color: var(--text);
}
.fx-tile-u { font-family: var(--font); font-size: 11px; font-weight: 500; color: var(--text-dim); }

/* ── The form shortcuts ──────────────────────────────────────────────────── */
.fx-tilegrid { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
.fx-tilebtn, .fx-navbtn {
  display: flex; align-items: center; gap: 9px;
  min-height: 48px; padding: 8px 12px;
  background: var(--surface-flat); border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  font-family: inherit; font-size: 12.5px; font-weight: 600; color: var(--text);
  cursor: pointer; text-align: left;
}
.fx-tilebtn:hover, .fx-navbtn:hover { border-color: var(--border-hover); }
.fx-tilebtn i, .fx-navbtn i { width: 15px; height: 15px; color: var(--text-dim); flex: none; }
.fx-tilebtn span { min-width: 0; }
.fx-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
.fx-navbtn-badge {
  margin-left: auto; padding: 1px 7px; border-radius: var(--r-pill);
  background: var(--error-soft); color: var(--error-ink);
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 10.5px; font-weight: 600;
}

/* ── Recent activity ─────────────────────────────────────────────────────── */
.fx-acts { display: flex; flex-direction: column; }
.fx-act {
  display: flex; align-items: center; gap: 9px;
  min-height: 34px; padding: 6px 2px; font-size: 12.5px; color: var(--text-2);
}
.fx-act + .fx-act { border-top: 1px solid var(--border-subtle); }
.fx-act-ic { color: var(--success); display: flex; flex: none; }
.fx-act-txt { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fx-act-when {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 11px; color: var(--text-label); flex: none;
}

/* ── Banners ─────────────────────────────────────────────────────────────── */
.fx-banner {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 13px; border-radius: var(--r-md);
  font-size: 12.5px; line-height: 1.45;
  background: var(--warning-soft); border: 1px solid var(--warning-border); color: var(--warning-ink);
}
.fx-banner strong { font-weight: 600; }
.fx-banner--ok  { background: var(--success-soft); border-color: #CFE3D9; color: var(--success-ink); }
.fx-banner--err { background: var(--error-row); border-color: #F0D4D1; color: var(--error-ink); }

/* ── The primary action ──────────────────────────────────────────────────── */
.fx-cta {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; height: 50px;
  background: var(--ink); border: 1px solid var(--ink); border-radius: var(--r-md);
  font-family: inherit; font-size: 14.5px; font-weight: 600; color: var(--on-ink);
  cursor: pointer;
}
.fx-cta:hover { background: var(--ink-hover); border-color: var(--ink-hover); }
.fx-cta i { width: 16px; height: 16px; }

/* ── Native controls, restyled ───────────────────────────────────────────── */
.fx-select {
  width: 100%; min-height: 46px; padding: 0 34px 0 12px;
  background: var(--surface-flat); border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  font-family: inherit; font-size: 13.5px; font-weight: 500; color: var(--text);
  appearance: none; -webkit-appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23A19B91' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
}
.fx-select:focus { outline: none; border-color: var(--accent); }
.dash-project-bar { display: flex; flex-direction: column; gap: 6px; background: none; border: 0; padding: 0; }
.dash-project-bar > div { display: flex; flex-direction: column; gap: 5px; }
.dash-trade-hint { font-size: 11.5px; color: var(--text-dim); }

/* ── The production card ─────────────────────────────────────────────────── */
.fx-pulse .fh-pulse-head { align-items: flex-start; }
.fx-pulse .fh-pulse-sub { font-size: 11.5px; color: var(--text-dim); margin-top: 3px; }
.fx-pulse .fh-pulse-body { min-height: 0; margin-top: 8px; }
.fx-pulse .fh-pulse-empty { font-size: 12.5px; color: var(--text-dim); padding: 10px 0 2px; }
.fx-pulse .fh-pulse-chip-val {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 12px; font-weight: 600; color: var(--text);
}
.fx-pulse .fh-pulse-chip-name { font-size: 11.5px; color: var(--text-muted); }
.fx-pulse .fh-pulse-legend-cap { font-size: 10px; color: var(--text-label); letter-spacing: .04em; text-transform: uppercase; }

/* ═══════════════════════════════════════════════════════════════════════════
   PART D2 — the form wizard (catalogue · fill & sign · review)
   ═══════════════════════════════════════════════════════════════════════════ */

.app { max-width: 560px; margin: 0 auto; padding: 0 14px calc(96px + env(safe-area-inset-bottom, 0px)); }
/* The wizard has its own head (back + title + dashes); the app-wide brand bar
   above it was a second header saying nothing the head doesn't. */
.app > .app-header { display: none; }

/* ── The top strip of an iPhone belongs to iOS ─────────────────────────────
   index.html ships viewport-fit=cover + apple-mobile-web-app-capable, so once
   the app is on the home screen the page paints UNDER the status bar, notch
   and Dynamic Island — and taps in that strip are swallowed by the system. A
   control drawn there is visible and dead.
   Hiding .app-header (below) removed the block that used to absorb that
   overlap, which left the form's Back button at y = 12→56px: entirely inside
   the 59px inset of a Dynamic Island phone, 80% inside a notch phone's 47px,
   and perfectly fine in Safari (inset 0) — which is why it worked on one
   phone and not another.
   The inset goes on each TOPMOST element rather than on <body>, because
   .inner-page-header is sticky at top:0 and body padding stops protecting a
   sticky header the moment the page scrolls. Held by
   test/unit/safe-area-top.test.mjs. */
.fill-head { padding: calc(12px + env(safe-area-inset-top, 0px)) 0 10px; background: var(--bg-0); }
.fill-head-row { display: flex; align-items: center; gap: 10px; }
.fill-back {
  width: 44px; height: 44px; min-height: 44px; padding: 0; gap: 0;
  border-radius: var(--r-sm); border: 1px solid var(--border-strong);
  background: var(--surface-flat); color: var(--text-2);
}
.fill-back:hover { background: var(--surface-flat-2); border-color: var(--border-hover); }
/* The word is carried by the icon's aria-label; at 44px square the arrow reads
   as Back everywhere the mock uses it, and the head needs the width. */
.fill-back-txt { display: none; }
.fill-title {
  font-family: var(--font);
  font-size: 15px; font-weight: 700; letter-spacing: -.01em; color: var(--text);
}
.fill-sub { font-size: 11.5px; font-weight: 500; color: var(--text-dim); margin-top: 1px; }
.fill-head--compact { padding: calc(12px + env(safe-area-inset-top, 0px)) 0 10px; }
.fill-head--compact .fill-title { font-size: 15px; letter-spacing: -.01em; }
.fill-head--compact .fill-sub   { font-size: 11.5px; }
.fill-head--compact .fill-back  { min-height: 44px; padding: 0; font-size: 14px; }

.fx-steps { display: flex; gap: 3px; flex: none; }
.fx-steps span { width: 16px; height: 4px; border-radius: 2px; background: var(--border-inner); }
.fx-steps span.on { background: var(--ink); }

/* ── The catalogue ───────────────────────────────────────────────────────── */
.pal-search { position: relative; margin: 2px 0 14px; }
.pal-search input {
  min-height: 46px; padding: 0 14px 0 40px;
  border-radius: var(--r-md); border: 1px solid var(--border-strong);
  background: var(--surface-flat-2); font: 500 13.5px var(--font);
}
.pal-search input:focus { border-color: var(--accent); }
.pal-group-label {
  display: flex; align-items: center; gap: 7px;
  font-size: 11px; font-weight: 600; letter-spacing: .075em; text-transform: uppercase;
  color: var(--text-label); margin: 0 0 7px;
}
.pal-group-n {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 10.5px; letter-spacing: 0;
}
.pal-group-n::before { content: '· '; }
.pal-group-rule { display: none; }
.pal-grid { grid-template-columns: 1fr 1fr; gap: 7px; margin-bottom: 16px; }
.type-card {
  gap: 9px; padding: 8px 11px; min-height: 52px;
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  background: var(--surface-flat);
}
.type-card:hover { border-color: var(--border-hover); background: var(--surface-flat); }
.type-card.selected {
  border: 1.5px solid var(--accent); background: var(--accent-soft);
}
.type-card .type-icon {
  width: auto; height: auto; border-radius: 0; background: none;
  color: var(--text-dim); flex: none;
}
.type-card .type-icon svg { width: 15px; height: 15px; stroke-width: 1.8px; }
.type-card .type-name { font-size: 12.5px; font-weight: 600; line-height: 1.25; color: var(--text); }
.type-card.selected .type-name { color: var(--text); }

/* ── Fill & sign ─────────────────────────────────────────────────────────── */
.step-panel { display: none; }
.step-panel.active { display: flex; flex-direction: column; gap: 13px; }
.step-panel > .step-heading, .step-panel > .step-sub { display: none; }
.field-group { display: flex; flex-direction: column; gap: 5px; margin: 0; }
.field-label {
  font-size: 11px; font-weight: 600; letter-spacing: .075em; text-transform: uppercase;
  color: var(--text-label);
}
.field-input, .field-select, textarea.field-input {
  min-height: 46px; padding: 11px 12px;
  background: var(--surface-flat); border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  font-family: var(--font); font-size: 14px; color: var(--text);
}
.field-input:focus, .field-select:focus { outline: none; border-color: var(--accent); }
.field-input--locked { background: var(--surface-flat-2); color: var(--text-muted); }
.field-hint { font-size: 11.5px; color: var(--text-dim); }
.field-select {
  appearance: none; -webkit-appearance: none; padding-right: 34px;
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23A19B91' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
}

/* The bottom action bar — one near-black primary, edge to edge. */
.nav-bar {
  background: var(--bg-0); border-top: 1px solid var(--border);
  backdrop-filter: none; -webkit-backdrop-filter: none;
  padding: 10px 14px calc(12px + env(safe-area-inset-bottom, 0px));
}
.nav-bar .rail-actions { max-width: 560px; margin: 0 auto; }
.btn-next, .btn-submit {
  height: 50px; background: var(--ink); border: 1px solid var(--ink); color: var(--on-ink);
  border-radius: var(--r-md); font-family: var(--font); font-size: 14.5px; font-weight: 600;
}
.btn-next:hover, .btn-submit:hover { background: var(--ink-hover); border-color: var(--ink-hover); }
.btn-next:disabled, .btn-submit:disabled { opacity: .5; }
.btn-back {
  height: 50px; background: var(--surface-flat); border: 1px solid var(--border-strong);
  color: var(--text-2); border-radius: var(--r-md); font-size: 14px; font-weight: 600;
}

/* ── Checked ≠ pending ───────────────────────────────────────────────────── */
/* Every checkbox, tailgate item, radio and FLRA preset painted itself with the
   OLD accent as a gradient wash when ticked — literal rgba(248,144,16,…), so
   the token layer could not reach it, and a screen of ticked items read as a
   screen of warnings. Ticked means CONFIRMED here: the box fills with ink, the
   label goes to full contrast, the card stays white. No gradients, no lift. */
.checkbox-item, .tailgate-checkbox-item, .radio-item, .flra-preset-item {
  border-color: var(--border-strong); background: var(--surface-flat);
  transition: border-color var(--t-fast), background var(--t-fast);
}
.checkbox-item:active, .radio-item:active, .flra-preset-item.included { transform: none; }
.checkbox-item:has(input:checked),
.tailgate-checkbox-item:has(input:checked),
.radio-item:has(input:checked),
.flra-preset-item.included {
  border-color: var(--ink); background: var(--surface-flat); color: var(--text);
  font-weight: 600;
}
.checkbox-item input[type="checkbox"], .radio-item input[type="radio"], .flra-preset-cb {
  accent-color: var(--ink);
}
.tailgate-checkbox-item:has(input:checked) .tg-box {
  background: var(--ink); border-color: var(--ink);
}
.tg-box { color: var(--on-ink); }
.tg-label { font-size: 13px; color: var(--text-muted); }
.tailgate-checkbox-item:has(input:checked) .tg-label { color: var(--text); font-weight: 600; }

/* Checklist section heads: the label tier, a mono count, no accent rail. A
   completed section used to fill its pill with accent — the same colour the
   rest of the app uses for "still owed". */
.tailgate-section-title {
  font-size: 11px; font-weight: 600; letter-spacing: .075em; text-transform: uppercase;
  color: var(--text-label); border-left: 0; padding-left: 0; background: none;
}
.tailgate-section-head { padding: 6px 0; min-height: 44px; }
.tailgate-section-progress {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 11px; font-weight: 600; color: var(--text-muted);
  background: none; border: 1px solid var(--border-inner); border-radius: var(--r-pill);
}
.tailgate-section-progress.complete {
  background: var(--success-soft); border-color: #CFE3D9; color: var(--success-ink);
}
.tailgate-allok-btn {
  border-radius: var(--r-sm); border-color: var(--border-strong);
  background: var(--surface-flat); font-size: 11.5px; color: var(--text-2);
}
.tailgate-allok-btn:active { transform: none; }
.tailgate-checkbox-list { grid-template-columns: 1fr; }

/* ── The daily inspection grid ───────────────────────────────────────────── */
/* The mock draws the two answers as SOLID circles — filled green for pass,
   filled red for fail, plain white for untouched. The gradient washes this had
   were the old web green/red and read as two shades of the same "maybe". */
.insp-toggle {
  width: 36px; height: 36px; border: 1.5px solid var(--border-strong);
  background: var(--surface-flat); color: var(--text-dim); font-weight: 600;
}
.insp-toggle:active { transform: none; }
.insp-toggle.ok { background: var(--success); border-color: var(--success); color: #fff; }
.insp-toggle.x  { background: var(--error);   border-color: var(--error);   color: #fff; }
.insp-ok-eg, .insp-x-eg { background: none; }
.insp-ok-eg { border: 1.5px solid var(--success); color: var(--success); }
.insp-x-eg  { border: 1.5px solid var(--error);   color: var(--error); }
.insp-section-header {
  background: none; border-bottom: 1px solid var(--border-subtle);
  font-size: 11px; font-weight: 600; letter-spacing: .075em; text-transform: uppercase;
  color: var(--text-label); padding: 0 2px 7px; border-radius: 0;
}
.insp-section-body { border: 1px solid var(--border-inner); border-radius: var(--r-md); }
.insp-item-row { border-bottom: 1px solid var(--border-subtle); min-height: 52px; }
.insp-item-text { font-size: 13px; color: var(--text); }
.insp-row-alt { background: none; }
.insp-notice, .qaqc-notice {
  background: var(--surface-flat-2); border: 1px solid var(--border-inner);
  border-radius: var(--r-md); font-size: 12px; color: var(--text-muted);
  backdrop-filter: none; -webkit-backdrop-filter: none;
}

/* ── The timesheet ───────────────────────────────────────────────────────── */
/* Accent was doing three jobs here that are not "pending": marking the weekend
   columns, tinting the O/T chip and tinting the TOTAL chip. Numbers are mono,
   the total is ink, and the weekend is a slightly deeper paper — not a colour. */
.ts-day-label {
  font-size: 9px; background: var(--surface-flat-2); border-color: var(--border-inner);
  color: var(--text-label); border-radius: var(--r-sm);
}
.ts-day-col:nth-child(6) .ts-day-label,
.ts-day-col:nth-child(7) .ts-day-label {
  background: var(--surface-flat-3); border-color: var(--border-strong);
  color: var(--text-muted);
}
.ts-hours-input { font-family: var(--font-mono); font-weight: 600 !important; }
.ts-ot-input { color: var(--text) !important; }
.ts-total-chip {
  font-size: 10.5px; font-weight: 600; letter-spacing: .075em;
  background: var(--surface-flat-2); border-color: var(--border-inner); color: var(--text-label);
}
.ts-total-chip strong {
  font-family: var(--font-mono); font-size: 17px; font-weight: 600; color: var(--text);
}
.ts-total-chip.reg   { background: var(--surface-flat-2); border-color: var(--border-inner); color: var(--text-label); }
.ts-total-chip.ot    { background: var(--surface-flat-2); border-color: var(--border-inner); color: var(--text-label); }
.ts-total-chip.total { background: var(--surface-flat-3); border-color: var(--border-strong); color: var(--text-label); }
.ts-total-chip.sick  { background: var(--error-soft); border-color: #F0D4D1; color: var(--error-ink); }
.ts-total-chip.sick strong { color: var(--error-ink); }
.ts-sick-btn { border-radius: var(--r-sm); border-color: var(--border-inner); color: var(--text-label); }
.ts-sick-btn.active { background: var(--error-soft); border-color: #F0D4D1; color: var(--error-ink); }
.ts-grand-total { border-color: var(--border-inner); border-radius: var(--r-lg); }
.ts-grand-total-lbl {
  font-size: 11px; font-weight: 600; letter-spacing: .075em; color: var(--text-label);
}
.ts-grand-total-val {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 20px; font-weight: 600; letter-spacing: 0; color: var(--text);
}
.ts-employee-card { border-color: var(--border-inner); border-radius: var(--r-lg); }
.ts-avatar { background: var(--avatar-soft); color: var(--avatar-ink); }

/* ── The Done screen ─────────────────────────────────────────────────────── */
/* The one moment the app gets to celebrate — so it stays quiet and certain:
   the ring closes in the system's green, the headline is ink at the page's own
   scale, and the filename chip is paper, not accent. */
.success-title {
  font-family: var(--font); font-size: 24px; font-weight: 700; letter-spacing: -.02em;
  color: var(--text);
}
.success-msg { font-size: 13.5px; color: var(--text-muted); }
.success-meta { font-size: 12px; color: var(--text-dim); }
.success-ring-base { stroke: var(--success-soft); }
.success-icon { color: var(--success); }
.success-screen--offline .success-icon,
.success-screen--offline .success-title { color: var(--text); }
.success-filed {
  background: var(--surface-flat-2); border: 1px solid var(--border-inner);
  border-radius: var(--r-md); font-size: 12.5px; color: var(--text-muted);
}
.success-filed b { font-family: var(--font-mono); font-weight: 600; color: var(--text); }
/* The label must not wrap to two lines when the filename is long — it is two
   words and it was breaking as "Filed / as" beside a name that had room. */
.filed-chip-label, .success-filed { white-space: nowrap; }
.success-filed b { white-space: normal; overflow-wrap: anywhere; }

/* ── Site Photos ─────────────────────────────────────────────────────────── */
/* The camera button is the one action on this screen and it is where you tap
   to add work — near-black, like every other primary. */
.sp-cam-btn {
  width: 48px; height: 48px; border-radius: var(--r-md);
  background: var(--ink); color: var(--on-ink); border: 1px solid var(--ink);
}
.sp-cam-btn:hover { background: var(--ink-hover); }
.sp-cam-btn:active { transform: none; opacity: 1; }
.sp-cap-input {
  height: 48px; border-radius: var(--r-md); border: 1px solid var(--border-strong);
  font-size: 13.5px;
}
.sp-cap-input:focus { border-color: var(--accent); outline: none; }
.sp-empty { font-size: 12.5px; color: var(--text-dim); padding: 18px 0 10px; }
.sp-photo-item { border-color: var(--border-inner); border-radius: var(--r-lg); }
.sp-thumb { border-radius: var(--r-sm); }

/* ── Form sections (Employee Hours, Crew Sign-In, …) ─────────────────────── */
/* Same label tier as every other section in the app, so a form reads as one
   document instead of a stack of little titled boxes. */
.section-header {
  background: none; border: 0; border-bottom: 1px solid var(--border-subtle);
  border-radius: 0; padding: 0 2px 7px; margin-top: 4px;
  font-size: 11px; font-weight: 600; letter-spacing: .075em; text-transform: uppercase;
  color: var(--text-label);
}
.section-body {
  border: 1px solid var(--border-inner); border-radius: var(--r-lg);
  padding: 12px; margin-top: 8px;
}
.crew-card, .flra-preset-item, .ts-employee-card { border-radius: var(--r-md); }
.crew-num { background: var(--avatar-soft); color: var(--avatar-ink); }
.crew-sig-wrap { border: 1px dashed var(--border-hover); border-radius: var(--r-md); }
.crew-sig-hint, .signature-hint { color: var(--text-dim); }

/* ── The draft strip ─────────────────────────────────────────────────────── */
/* The mock's version of the app's own auto-save promise: what it does, when it
   last did it, and the two buttons. Quiet — it is a status line, not an alert. */
.draft-banner {
  background: var(--surface-flat-2); border: 1px solid var(--border-inner);
  border-radius: var(--r-md); padding: 9px 12px; margin: 0; gap: 8px;
}
.draft-banner-msg { font-size: 11.5px; color: var(--text-muted); }
.draft-banner-msg #draftSavedAt { color: var(--text-dim); }
.draft-save-btn, .draft-clear-btn {
  min-height: 40px; padding: 0 12px; border-radius: var(--r-sm);
  font-family: var(--font); font-size: 11.5px; font-weight: 600;
  background: var(--surface-flat); border: 1px solid var(--border-strong);
  color: var(--text); cursor: pointer;
}
.draft-save-btn:hover { background: var(--surface-flat-2); opacity: 1; }
.draft-clear-btn { color: var(--text-muted); }
.draft-clear-btn:hover { border-color: #E0B6B1; color: var(--error-ink); }

/* ── Photos ──────────────────────────────────────────────────────────────── */
.photo-section { margin-top: 0; }
.photo-section-title {
  font-size: 11px; font-weight: 600; letter-spacing: .075em; text-transform: uppercase;
  color: var(--text-label); margin-bottom: 7px;
}
.photo-drop-zone {
  border: 1.5px dashed var(--border-hover); border-radius: var(--r-lg);
  background: var(--surface-flat-2); padding: 20px 14px; min-height: 88px;
}
.photo-drop-zone:hover, .photo-drop-zone.drag-over {
  border-color: var(--accent); background: var(--accent-soft);
}
.photo-drop-icon { display: none; }
.photo-drop-text { font-size: 13px; font-weight: 600; color: var(--text-2); margin-bottom: 3px; }
.photo-drop-hint { font-size: 11.5px; color: var(--text-dim); }
.photo-count { font-size: 11.5px; color: var(--text-dim); margin-top: 6px; }

/* ── Risk pills — one hue, one meaning, no gradients ─────────────────────── */
.flra-risk-pill {
  font-size: 10.5px; font-weight: 600; letter-spacing: .04em; padding: 3px 9px;
  border: 1px solid transparent; background: none;
}
.flra-risk-pill.low    { background: var(--success-soft); color: var(--success-ink); border-color: #CFE3D9; }
.flra-risk-pill.medium { background: var(--warning-soft); color: var(--warning-ink); border-color: var(--warning-border); }
.flra-risk-pill.high   { background: var(--error-soft);   color: var(--error-ink);   border-color: #F0D4D1; }

/* ── Signature ───────────────────────────────────────────────────────────── */
.signature-wrap {
  border: 1.5px dashed var(--border-hover); border-radius: var(--r-lg);
  background: var(--surface-flat-2); overflow: hidden;
}
.signature-canvas { background: var(--surface-flat); }
.signature-clear-btn {
  min-height: 40px; padding: 0 12px; border-radius: var(--r-sm);
  border: 1px solid var(--border-strong); background: var(--surface-flat);
  font-size: 11.5px; font-weight: 600; color: var(--text-muted);
}
.signature-hint { font-size: 11.5px; color: var(--text-dim); }

/* ── Review & sign ───────────────────────────────────────────────────────── */
.review-card {
  background: var(--surface-flat); border: 1px solid var(--border-inner);
  border-radius: var(--r-lg); overflow: hidden;
}
.review-card-header {
  font-size: 11px; font-weight: 600; letter-spacing: .075em; text-transform: uppercase;
  color: var(--text-label); background: var(--surface-flat-2);
  border-bottom: 1px solid var(--border-inner); padding: 9px 13px;
}
/* Three cells in a two-column grid left a grey block where the fourth would
   be — the grid painted its 1px-gap colour across the empty track. Hairlines
   are borders on the cells now, so the empty track is just paper. */
.review-grid { gap: 0; background: var(--surface-flat); }
.review-cell {
  padding: 11px 13px;
  border-right: 1px solid var(--border-inner);
  border-bottom: 1px solid var(--border-inner);
}
.review-cell:nth-child(2n) { border-right: 0; }
.review-cell-label {
  font-size: 11px; font-weight: 600; letter-spacing: .075em; text-transform: uppercase;
  color: var(--text-label); margin-bottom: 3px;
}
.review-cell-value { font-size: 13.5px; font-weight: 600; color: var(--text); }
.filed-chip {
  display: flex; align-items: center; gap: 10px;
  background: var(--surface-flat-2); border: 1px solid var(--border-inner);
  border-radius: var(--r-md); padding: 10px 12px;
}
.filed-chip-label {
  font-size: 11px; font-weight: 600; letter-spacing: .075em; text-transform: uppercase;
  color: var(--text-label);
}
.filed-chip-name {
  font-family: var(--font-mono); font-size: 12px; color: var(--text-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════════════════════
   PART D3 — the inner pages (submissions · actions · equipment · certs ·
   documents · delivery). One header shape for all six.
   ═══════════════════════════════════════════════════════════════════════════ */

.inner-page { background: var(--bg-0); }
.inner-page-header {
  gap: 10px; padding: 12px 14px;
  padding-top: calc(12px + env(safe-area-inset-top, 0px));
  background: var(--bg-0); border-bottom: 1px solid var(--border);
  backdrop-filter: none; -webkit-backdrop-filter: none;
}
.inner-page-back {
  width: 44px; height: 44px; padding: 0; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat); color: transparent;
  font-size: 0; cursor: pointer; position: relative;
}
/* The label was the string "← Back" inside the button; at 44px square the
   arrow is the whole control, so it is drawn here and the text is hidden
   without losing the accessible name. */
.inner-page-back::before {
  content: ''; position: absolute; inset: 0;
  background: no-repeat center/16px url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%234A463F' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 6l-6 6 6 6'/%3E%3C/svg%3E");
}
.inner-page-back:hover { background: var(--surface-flat-2); border-color: var(--border-hover); }
.inner-page-title {
  font-family: var(--font); font-size: 15px; font-weight: 700; letter-spacing: -.01em;
  color: var(--text); display: flex; align-items: center; gap: 8px;
}
.inner-page-subtitle {
  font-size: 11px !important; font-weight: 600; letter-spacing: .075em;
  text-transform: uppercase; color: var(--text-label); opacity: 1 !important;
}
.inner-page-body { padding: 14px; max-width: 560px; }
.inner-page-footer { background: var(--bg-0); border-top: 1px solid var(--border); }
.docs-loading { font-size: 12.5px; color: var(--text-dim); padding: 18px 2px; }
.ip-ic { display: inline-flex; color: var(--text-dim); }
.ip-ic svg { width: 16px; height: 16px; }

/* ── My submissions ──────────────────────────────────────────────────────── */
.fx-row--static { cursor: default; }
.fx-row--static:hover { border-color: var(--border-subtle); }
.fx-dayhead {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  font-size: 11px; font-weight: 600; letter-spacing: .075em; text-transform: uppercase;
  color: var(--text-label); margin: 14px 2px 7px;
}
.fx-dayhead:first-child { margin-top: 0; }
.fx-dayhead-n { font-family: var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: 0; }
.fp-pdf-btn {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 40px; padding: 0 12px; flex: none;
  background: var(--surface-flat); border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  font-family: var(--font); font-size: 11.5px; font-weight: 600; color: var(--text);
  cursor: pointer;
}
.fp-pdf-btn:hover { background: var(--surface-flat-2); border-color: var(--border-hover); }
.fp-pdf-btn:disabled { opacity: .45; cursor: not-allowed; }
.fp-lock { color: var(--text-dim); }

/* ── My actions ──────────────────────────────────────────────────────────── */
.fp-action-card {
  background: var(--surface-flat); border: 1px solid var(--border-inner);
  border-radius: var(--r-lg); padding: 12px 13px; margin-bottom: 8px;
}
.fp-action-card--overdue {
  background: var(--error-row); border-color: #F0D4D1; border-left: 3px solid var(--error);
  padding-left: 10px;
}
.fp-action-head { display: flex; align-items: flex-start; gap: 8px; flex-wrap: wrap; }
.fp-action-pr {
  width: 9px; height: 9px; border-radius: 50%; flex: none; margin-top: 5px;
  background: var(--warning-ink);
}
.fp-action-card--high .fp-action-pr { background: var(--error); }
.fp-action-card--low  .fp-action-pr { background: var(--success); }
.fp-action-desc { flex: 1; min-width: 170px; font-size: 14px; font-weight: 600; line-height: 1.35; }
.fp-action-meta { font-size: 12px; color: var(--text-dim); margin-top: 6px; }
.fp-overdue-pill {
  font-size: 10.5px; font-weight: 600; padding: 2px 8px; border-radius: var(--r-pill);
  background: var(--error-soft); color: var(--error-ink); border: 0; flex: none;
}
.fp-closed-line { font-size: 12px; color: var(--success-ink); margin-top: 6px; display: flex; gap: 6px; }
/* The close button IS accent-filled: closing an action is the one thing this
   screen exists for, and accent means "pending" — which is what it is. */
.fx-actbtn {
  margin-top: 10px; min-height: 44px; padding: 0 15px;
  background: var(--accent); border: 0; border-radius: var(--r-sm);
  font-family: var(--font); font-size: 13px; font-weight: 700; color: var(--on-accent);
  cursor: pointer;
}
.fx-actbtn:hover { background: var(--accent-2); color: #fff; }
.fx-actbtn--full { width: 100%; min-height: 48px; margin-top: 2px; }
.fx-more { margin-top: 14px; }
.fx-more > summary {
  cursor: pointer; list-style: none; min-height: 44px;
  display: flex; align-items: center; gap: 7px;
  font-size: 12.5px; font-weight: 600; color: var(--text-muted);
}
.fx-more > summary::-webkit-details-marker { display: none; }
.fx-more > summary::before {
  content: ''; width: 12px; height: 12px; flex: none;
  background: no-repeat center/12px url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%236E6A63' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 6l6 6-6 6'/%3E%3C/svg%3E");
}
.fx-more[open] > summary::before { transform: rotate(90deg); }
.fx-more-body { margin-top: 8px; opacity: .8; }

/* ── Empty and error states ──────────────────────────────────────────────── */
.fx-empty { text-align: center; padding: 34px 16px; color: var(--text-muted); }
.fx-empty-t { font-size: 14px; font-weight: 600; color: var(--text); margin-bottom: 5px; }
.fx-empty-s { font-size: 12.5px; color: var(--text-dim); }
.fx-empty .fp-empty-ic { color: var(--text-faint); margin-bottom: 10px; display: block; }
.fx-retry {
  margin-top: 12px; min-height: 44px; padding: 0 16px; width: auto;
  background: var(--surface-flat); border: 1px solid var(--border-strong);
  border-radius: var(--r-sm); font-family: var(--font); font-size: 13px; font-weight: 600;
  color: var(--text); cursor: pointer;
}

/* ── Equipment ───────────────────────────────────────────────────────────── */
/* A selected filter is not "pending" — it is the current state, so it reads as
   ink, and accent stays reserved. */
.feq-cat-pill {
  min-height: 40px; padding: 0 13px; border-radius: var(--r-pill);
  border: 1px solid var(--border-strong); background: var(--surface-flat);
  font-size: 12.5px; font-weight: 600; color: var(--text-2);
}
.feq-cat-pill.active {
  background: var(--ink); border-color: var(--ink); color: var(--on-ink);
}
.feq-cat-pill.active svg { color: var(--on-ink); }
.feq-section-header {
  background: none; border: 0; border-bottom: 1px solid var(--border-subtle);
  padding: 0 2px 7px; margin-bottom: 8px; gap: 7px;
}
.feq-section-icon { color: var(--text-dim); }
.feq-section-icon svg { width: 15px; height: 15px; }
.feq-section-title {
  font-size: 11px; font-weight: 600; letter-spacing: .075em; text-transform: uppercase;
  color: var(--text-label);
}
.feq-section-count {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 11px; color: var(--text-label); background: none; padding: 0;
}
.feq-card {
  background: var(--surface-flat); border: 1px solid var(--border-inner);
  border-radius: var(--r-lg); padding: 12px 13px;
}
.feq-card-name { font-size: 13.5px; font-weight: 600; color: var(--text); }
.feq-card-total {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 12px; font-weight: 600; color: var(--text-2);
}
.feq-loc-chip {
  background: var(--surface-flat-2); border: 1px solid var(--border-inner);
  border-radius: var(--r-pill); padding: 3px 10px; gap: 5px;
}
.feq-loc-qty {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 11.5px; font-weight: 600; color: var(--text);
}
.feq-loc-name { font-size: 11px; color: var(--text-muted); }
.feq-card-transfer-btn {
  min-height: 44px; border-radius: var(--r-sm);
  background: var(--surface-flat); border: 1px solid var(--border-strong);
  color: var(--text); font-family: var(--font); font-size: 12.5px; font-weight: 600;
  display: flex; align-items: center; justify-content: center; gap: 7px;
}
.feq-card-transfer-btn i { width: 14px; height: 14px; color: var(--text-dim); }
/* A <select> that carries .field-input (the transfer dialog's two) had no
   arrow at all — appearance is stripped app-wide and only .field-select was
   given one back. */
select.field-input {
  appearance: none; -webkit-appearance: none; padding-right: 34px;
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23A19B91' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
}
.feq-card-transfer-btn:hover { background: var(--surface-flat-2); border-color: var(--border-hover); }
.feq-loading, .feq-empty { font-size: 12.5px; color: var(--text-dim); }

/* ── Chips: one hue, one meaning, everywhere in the field app ────────────── */
.fx-chip, .cert-badge {
  display: inline-flex; align-items: center; flex: none;
  padding: 3px 9px; border-radius: var(--r-pill);
  font-size: 10.5px; font-weight: 600; letter-spacing: .02em;
  background: var(--chrome-surface); color: var(--text-muted);
}
.fx-chip--ok,   .cert-badge.valid    { background: var(--success-soft); color: var(--success-ink); }
.fx-chip--warn, .cert-badge.expiring { background: var(--warning-soft); color: var(--warning-ink); }
.fx-chip--err,  .cert-badge.expired  { background: var(--error-soft);   color: var(--error-ink); }
.fx-chip--mut,  .cert-badge.unknown  { background: var(--chrome-surface); color: var(--text-muted); }
.docs-empty { font-size: 12.5px; color: var(--text-dim); padding: 18px 2px; }

/* ── The job list ────────────────────────────────────────────────────────── */
#fieldJobListScreen .dash-wrap { max-width: 560px; padding: 14px 14px 40px; }
#fieldJobListScreen .dash-header { margin-bottom: 16px; }
.dash-greeting {
  font-family: var(--font); font-size: 19px; font-weight: 700; letter-spacing: -.02em;
  color: var(--text);
}
.field-joblist-sub { font-size: 12.5px; color: var(--text-muted); margin: 3px 0 14px; }
.field-joblist-items { gap: 6px; }
.field-joblist-empty { font-size: 12.5px; color: var(--text-dim); padding: 18px 2px; }

/* ── Project documents ───────────────────────────────────────────────────── */
.fdoc-section { margin-bottom: 18px; }
.fdoc-section-hdr {
  display: flex; align-items: center; gap: 7px;
  background: none; border: 0; border-bottom: 1px solid var(--border-subtle);
  padding: 0 2px 7px; margin-bottom: 8px;
}
.fdoc-section-ic { display: inline-flex; color: var(--text-dim); }
.fdoc-section-ic svg { width: 15px; height: 15px; }
.fdoc-section-title {
  font-size: 11px; font-weight: 600; letter-spacing: .075em; text-transform: uppercase;
  color: var(--text-label); flex: 1;
}
.fdoc-count {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 11px; font-weight: 600; color: var(--text-label);
  background: none; border: 0; padding: 0; min-width: 0; border-radius: 0;
}
.fdoc-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 48px; padding: 8px 12px; margin-bottom: 6px;
  background: var(--surface-flat); border: 1px solid var(--border-subtle);
  border-radius: var(--r-md); cursor: pointer; text-align: left;
}
.fdoc-row:hover { border-color: var(--border-strong); }
.fdoc-row-info { flex: 1; min-width: 0; }
.fdoc-row-title { font-size: 13.5px; font-weight: 600; color: var(--text); }
.fdoc-row-notes { font-size: 11.5px; color: var(--text-dim); margin-top: 1px; }
.fdoc-row-date {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 11px; color: var(--text-label); flex: none;
}
.fdoc-row-arrow { display: flex; color: var(--text-label); flex: none; }
.fdoc-row-arrow svg { width: 15px; height: 15px; }
.fdoc-photo-card {
  border: 1px solid var(--border-inner); border-radius: var(--r-md);
  background: var(--surface-flat); overflow: hidden;
}
.fdoc-photo-cap { font-size: 11.5px; color: var(--text-muted); padding: 7px 9px; }

/* ── The photo folder (owner request, 2026-08-14) ──────────────────────────
   Site photos used to be the FIRST section on both Documents screens, and
   every tile pointed at the ORIGINAL file: 133 photos, 3.6 MB each, 471 MB to
   open a page whose point is the drawings. They live behind this row now.
   Closed it costs nothing — no signing round trip, no image bytes. It reads
   like a folder because that is what it is. */
.fdoc-folder {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 56px; padding: 10px 12px;
  background: var(--surface-flat-2); border: 1px solid var(--border);
  border-radius: var(--r-md); cursor: pointer; text-align: left;
}
.fdoc-folder:hover { border-color: var(--border-strong); }
.fdoc-folder[aria-expanded="true"] { border-radius: var(--r-md) var(--r-md) 0 0; }
.fdoc-folder-txt   { flex: 1; min-width: 0; }
.fdoc-folder-title { font-size: 13.5px; font-weight: 600; color: var(--text); }
.fdoc-folder-sub   { display: block; font-size: 11.5px; color: var(--text-2); margin-top: 1px; }
.fdoc-folder[aria-expanded="true"] .fdoc-row-arrow { transform: rotate(180deg); }
#fdocPhotoGrid[hidden] { display: none; }

/* Admin side — same idea, the wider chrome that tab already uses. */
.doc-folder {
  display: flex; align-items: center; gap: 12px; width: 100%;
  min-height: 60px; padding: 12px 16px;
  background: var(--surface-flat-2); border: 1px solid var(--border);
  border-radius: var(--r-lg); cursor: pointer; text-align: left;
}
.doc-folder:hover { border-color: var(--border-strong); background: var(--surface-flat); }
.doc-folder[aria-expanded="true"] { border-radius: var(--r-lg) var(--r-lg) 0 0; }
.doc-folder-ic {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; flex: none;
  border-radius: var(--r-sm);
  background: var(--chrome-surface-2); color: var(--text-muted);
}
.doc-folder-ic svg { width: 18px; height: 18px; }
.doc-folder-txt   { flex: 1; min-width: 0; }
.doc-folder-title { display: block; font-size: 14px; font-weight: 600; color: var(--text); }
.doc-folder-sub   { display: block; font-size: 12px; color: var(--text-2); margin-top: 1px; }
.doc-folder-cta {
  display: inline-flex; align-items: center; gap: 5px; flex: none;
  font-size: 12.5px; font-weight: 600; color: var(--text-muted);
}
.doc-folder-cta svg { width: 15px; height: 15px; }
.doc-photofolder .doc-photo-grid { margin-top: 0; }
#docPhotoGrid[hidden] { display: none; }

/* ── The 44px floor ──────────────────────────────────────────────────────── */
/* The field runs this in gloves. Everything tappable clears 44px — measured
   across all nine screens, these were the four that did not. */
.fx-appbar .dash-avatar { width: 44px; height: 44px; }
.user-menu-item { min-height: 44px; }
.fp-pdf-btn, .feq-cat-pill, .draft-save-btn, .draft-clear-btn,
.signature-clear-btn, .fx-retry { min-height: 44px; }
.dsc-qty, .delivery-extra-qty { min-height: 44px; }
/* Inside the fill step: remove-a-worker, clear-a-signature and the voice
   button were 25px, 22px and 36px. The hidden 20px checkboxes are NOT in this
   list on purpose — they sit under a 44px+ row that is the real target. */
.crew-remove { width: 44px; height: 44px; }
.crew-sig-clear, .signature-clear-btn { min-height: 40px; padding: 0 12px; }
.textarea-mic { width: 40px; height: 40px; }
.flra-preset-header { min-height: 48px; }
.risk-btn { min-height: 40px; padding: 0 12px; }
/* The seven SICK toggles sit in a 7-column week grid — a 44px box would blow
   the grid apart, so they get the invisible 44px hit area instead, the same
   trick .dinsp-round already uses for its 34px circles. */
.ts-sick-btn { position: relative; }
.ts-sick-btn::after { content: ''; position: absolute; inset: -12px 0; }

/* ── The desktop rail ────────────────────────────────────────────────────── */
/* Same badge as the phone's: a count of things you owe is an exception, and
   the exception colour in this system is red — accent means pending work in
   general, which is what the rest of the rail already is. */
.fd-side-badge {
  background: var(--error-soft); color: var(--error-ink);
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.fd-side-btn.active { background: var(--accent-soft); border-left-color: var(--accent); }

/* ── Field dialogs (close action, cert detail, change password, transfer,
   PDF preview) — the admin's dialog layer, said once for the phone. ─────── */
.delivery-modal-overlay { background: rgba(26, 24, 21, .45); }
.delivery-modal {
  border: 1px solid var(--border); border-radius: 18px 18px 0 0;
  box-shadow: none;
}
@media (min-width: 520px) { .delivery-modal { border-radius: var(--r-lg); } }
.delivery-modal-header {
  padding: 14px 16px; border-bottom: 1px solid var(--border-inner);
  font-size: 15px; font-weight: 700; letter-spacing: -.01em;
}
.delivery-modal-close {
  width: 44px; height: 44px; border-radius: var(--r-sm);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 17px; color: var(--text-muted);
}
.delivery-modal-close:hover { background: var(--surface-flat-2); }
.delivery-modal-body { padding: 14px 16px; display: flex; flex-direction: column; gap: 12px; }
/* The dialog's own button row: near-black primary, outlined secondary. */
.delivery-modal .btn { min-height: 46px; border-radius: var(--r-sm); font-size: 13.5px; font-weight: 600; }
.fx-dlg-foot {
  display: flex; gap: 8px; justify-content: flex-end;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--border-inner);
}
.fx-dlg-foot--split { justify-content: space-between; align-items: center; }
.fx-err { color: var(--error-ink); font-size: 12.5px; min-height: 18px; margin-top: 2px; }
.fx-ok  { color: var(--success-ink); font-size: 12.5px; min-height: 18px; }

/* ── A worker's tickets, inside the cert dialog ──────────────────────────── */
.cert-item {
  background: var(--surface-flat); border: 1px solid var(--border-inner);
  border-radius: var(--r-md); padding: 11px 12px; margin-bottom: 6px;
}
.cert-item-type { font-size: 13.5px; font-weight: 600; }
.cert-item-meta { font-size: 11.5px; color: var(--text-dim); }
.cert-item-notes { font-size: 11.5px; color: var(--text-muted); margin-top: 4px; }
.cert-item-none { font-size: 12.5px; color: var(--text-dim); padding: 4px 0 10px; }
.cert-item-doc {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 40px; padding: 0 10px; margin-top: 6px;
  background: var(--surface-flat); border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  font-family: var(--font); font-size: 11.5px; font-weight: 600; color: var(--text);
  cursor: pointer;
}
.cert-item-doc:hover { background: var(--surface-flat-2); border-color: var(--border-hover); }
.cert-item-doc i { width: 14px; height: 14px; }
.cert-drop-zone {
  border: 1.5px dashed var(--border-hover); border-radius: var(--r-md);
  background: var(--surface-flat-2); min-height: 52px;
}
.cert-drop-zone:hover { border-color: var(--accent); background: var(--accent-soft); }
.cert-drop-label { font-size: 12.5px; color: var(--text-muted); }

/* ── First-run profile screen ────────────────────────────────────────────── */
#profileSetupScreen {
  min-height: 100dvh; display: none; align-items: center; justify-content: center;
  padding: calc(24px + env(safe-area-inset-top, 0px)) 14px 24px;
}
#profileSetupScreen[style*="block"], #profileSetupScreen[style*="flex"] { display: flex !important; }
.login-card { border-color: var(--border); border-radius: var(--r-lg); box-shadow: none; padding: 24px 20px; }
.login-title { font-family: var(--font); font-size: 19px; font-weight: 700; letter-spacing: -.02em; }
.login-subtitle { font-size: 13px; }
.login-error { font-size: 12.5px; }

/* ── Toast ───────────────────────────────────────────────────────────────── */
.toast { border-radius: var(--r-md); font-size: 13px; box-shadow: none; border: 1px solid var(--border-strong); }

/* ── Desktop: the rail owns the destinations ─────────────────────────────── */
@media (min-width: 1024px) {
  .fx-wrap { max-width: 720px; }
  /* The whole "Go to" section steps aside — every one of its six buttons is a
     rail item at this width, and a grid that repeats the rail one row lower is
     the definition of a screen saying the same thing twice. */
  #dashGoSec { display: none; }
  /* The rail carries the brand and the account here, so the app bar goes —
     the same call styles.css already made for .dash-header (this rule has to
     repeat it because .fx-appbar sets display:flex from a later file). */
  .fx-appbar { display: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   TEXT THAT SITS DIRECTLY ON THE CANVAS
   ═══════════════════════════════════════════════════════════════════════════
   --text-muted (2.71:1) and --text-dim (1.85:1) were calibrated to live INSIDE
   a white card. Once the canvas went grey, every piece of secondary text
   OUTSIDE a card started failing. Inside a card those ramps still hold — which
   is why the fix is per class rather than darkening the tokens, which would
   have thickened text across the whole app for no reason.
   Measured: 9 spots across the 9 field screens, none left over.
   ═══════════════════════════════════════════════════════════════════════════ */
.fx-hello,                    /* greeting + date, top of Today */
.field-joblist-sub,           /* "Pick a job to start." */
.fill-sub,                    /* "Step 2 of 4 · <job>" */
.fx-more > summary,           /* "Closed (7)" on My actions */
.fdoc-row-notes {             /* a document's own note */
  color: var(--text-2);
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE SITE'S ORANGE BECOMES THE ACTION  (owner's decision, 2026-08-14)
   ═══════════════════════════════════════════════════════════════════════════
   The customer buys on an orange site (ordinex.ca's "Start free trial") and
   was handed an app with black buttons. The change of product was felt. From
   here on:

     FILLED with orange = the primary action on that screen
     TINTED with orange = pending (a 7px dot, a 3px rail, a pale row wash)
     TEXT #9A4C00       = a link
     FILLED with ink    = a secondary action that is still a button
                          (Resume, Cancel)

   Shape keeps the two roles apart: a button is 50px tall and fully coloured; a
   state is a dot or a stripe. It is the rule the marketing site already
   follows — there, orange appears only on the button it wants you to press.

   DARK ink on the orange, never white: #0a0b0e gives 8.42:1, white gives
   2.34:1 and fails. The site does it this way too.
   ═══════════════════════════════════════════════════════════════════════════ */
.admin-btn-primary,
.fx-cta,
.nav-bar .btn-next, .nav-bar .btn-submit,
.btn.btn-next, .btn.btn-submit,
.sp-cam-btn,
.cw-btn-dark {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}
.admin-btn-primary:hover,
.fx-cta:hover,
.nav-bar .btn-next:hover, .nav-bar .btn-submit:hover,
.btn.btn-next:hover, .btn.btn-submit:hover,
.sp-cam-btn:hover,
.cw-btn-dark:hover {
  background: var(--accent-2);
  border-color: var(--accent-2);
  color: #FFFFFF;
}
/* Resume continua tinta: é a ação secundária dentro de uma linha, e duas
   cores cheias na mesma linha brigariam. */
.fx-row-go { background: var(--ink); color: var(--on-ink); }

/* ── she-: sheet editor — the PDF-replica editing surface ─────────────────────
   The sheet mirrors js/pdf/style.js in mm via --she-mm (1mm on paper = 3.6px
   on screen → letter width 215.9mm ≈ 777px). Colors inside .she-page are the
   PDF's own palette (js/pdf/tokens.js: INK #0A0B0E, BODY #344054, MUTED
   #667085, MUTED2 #5F6673, HAIR #E4E7EC, HAIR_LT #F2F4F7, STRIP #F5F6F8,
   SIG_LINE #D0D5DD, ORDINEX #F89010) — the sheet IS the document, so the
   admin tokens-only rule stops at its border. Type sizes are print pt × 1.27
   (pt→mm→--she-mm); the 11px admin floor applies to chrome, not to a scaled
   print replica. */
:root { --she-mm: 3.6px; }
.she-sheet-stack { display: flex; flex-direction: column; gap: 26px; }
.she-sheet-stack > .she-page { margin-inline: auto; }
.she-probe { position: absolute; left: -9999px; top: 0; visibility: hidden; pointer-events: none; }
.she-page {
  width: calc(215.9 * var(--she-mm)); min-height: calc(279.4 * var(--she-mm));
  background: #FFFFFF; border: 1px solid var(--border); position: relative;
  display: flex; flex-direction: column; font-family: var(--font); color: #0A0B0E;
  flex-shrink: 0;
}

/* v2 substrate: the real generated PDF page as canvas + hotspot overlay */
.she-page--pdf { min-height: 0; display: block; }
.she-page--pdf canvas { display: block; }
.she-ov { position: absolute; inset: 0; }
.she-ov .she-blk { position: absolute; }
.she-line { position: absolute; }
/* Every mapped line carries data-she-edit, and the blanket
   `[data-she-edit] { cursor: text }` further down matches at the same weight
   and later in the file — the id is what makes the resting state stick. */
#sheBody .she-line { cursor: default; }
#sheBody .she-line--live { cursor: text; }
.she-regen .she-page--pdf { opacity: .55; transition: opacity .15s ease-out .25s; }
.she-err-detail {
  font-family: var(--font-mono); font-size: 11px; color: var(--text-muted);
  max-width: 520px; margin: 10px auto 14px; overflow-wrap: break-word;
}

/* floating inline editor over the printed pixels */
.she-float {
  position: fixed; z-index: 45; max-width: 640px;
  background: #FFFFFF; color: #0A0B0E; font-size: 13px; line-height: 1.4;
  border: 1.5px solid var(--accent); border-radius: 6px;
  padding: 4px 8px; outline: none;
}
.she-float--multi { white-space: pre-wrap; min-height: 64px; min-width: 240px; }

/* context strip under the selected block */
.she-strip { position: absolute; z-index: 8; display: flex; gap: 6px; }
.she-strip-btn {
  display: inline-flex; align-items: center; gap: 5px;
  border: 1px dashed var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-flat); color: var(--text-muted); cursor: pointer;
  font-size: 11.5px; padding: 3px 10px;
}
.she-strip-btn:hover { border-color: var(--accent); color: var(--accent-ink); background: var(--accent-soft); }
.she-strip-btn span { font-size: 13px; line-height: 1; }

/* line chrome (× on mapped lines) + absolute seam/dropline on the overlay */
/* _sheLineChrome only creates these on the SELECTED field's lines, so
   existence is the visibility rule. Double class beats the base
   `.she-x { display:none }` regardless of source order. */
.she-x.she-x--line {
  display: none; position: absolute; right: 2px; top: 50%; transform: translateY(-50%);
  background: var(--surface-flat); border: 1px solid var(--border-subtle);
}
/* quiet paper: the remove chrome surfaces only over the line under the cursor */
.she-line:hover .she-x.she-x--line { display: inline-flex; }
/* per-section add pill lives in the page margin, never over the ink */
.she-add.she-add--ov {
  display: inline-flex; align-items: center; justify-content: center;
  position: absolute; z-index: 6; margin: 0;
  width: 22px; height: 22px; padding: 0; border-radius: 999px;
}
.she-add.she-add--ov span { margin: 0; }
.she-line { z-index: 2; }
/* A freshly added line announces itself: the repaint is correct but silent,
   and a list that grows below the fold reads as nothing having happened. */
.she-line--new {
  background: var(--accent-soft);
  box-shadow: 0 0 0 2px var(--accent);
  border-radius: 3px;
  animation: she-flash 1.4s ease-out;
}
@keyframes she-flash { 0% { background: var(--accent); } 100% { background: var(--accent-soft); } }
.she-seam--abs { position: absolute; height: 0; z-index: 6; }
.she-dropline--abs { position: absolute; height: 3px; margin: 0; z-index: 6; }
.she-pop--wide { width: 400px; }
.she-pop--wide .cw-card { border: 1px solid var(--border-subtle); border-radius: var(--r-md); }
.she-microlabel {
  font-family: var(--font-mono); font-size: 9px; letter-spacing: .07em;
  text-transform: uppercase; color: #667085; line-height: 1.5;
}

/* header band */
.she-band { display: flex; align-items: center; gap: calc(4.2 * var(--she-mm)); padding: 0 calc(11.6 * var(--she-mm)); }
.she-logochip {
  height: calc(12.7 * var(--she-mm)); min-width: calc(12.7 * var(--she-mm));
  background: #FFFFFF; border-radius: 6px; display: flex; align-items: center; justify-content: center;
  padding: 3px 7px;
}
.she-logochip img { max-height: 100%; max-width: calc(30 * var(--she-mm)); display: block; }
.she-monogram { font-family: var(--font-mono); font-size: 14px; font-weight: 600; color: #1A1815; }
.she-band-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.she-eyebrow {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .4px;
  text-transform: uppercase; color: rgba(255,255,255,.75);
}
.she-doctitle { font-size: 20px; font-weight: 700; color: #FFFFFF; letter-spacing: -.01em; line-height: 1.15; }
.she-band-right { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.she-wordmark { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .66px; color: rgba(255,255,255,.9); }
.she-datechip {
  font-family: var(--font-mono); font-size: 13px; color: #FFFFFF;
  border: 1px solid rgba(255,255,255,.4); border-radius: 999px;
  padding: 2px 10px; font-variant-numeric: tabular-nums;
}
.she-fillet { height: calc(0.8 * var(--she-mm)); background: #F89010; flex-shrink: 0; }

/* meta strip */
.she-meta { display: flex; background: #F5F6F8; border-bottom: 1px solid #E4E7EC; padding: calc(2.2 * var(--she-mm)) calc(11.6 * var(--she-mm)); gap: calc(5.3 * var(--she-mm)); }
.she-meta-cell { flex: 1; min-width: 0; }
.she-meta-cell .she-microlabel { color: #5F6673; }
.she-meta-val { font-size: 12.5px; font-weight: 600; color: #0A0B0E; margin-top: 1px; }

/* continuation header (pages 2+) */
.she-cont { display: flex; justify-content: space-between; padding: calc(6 * var(--she-mm)) calc(11.6 * var(--she-mm)) calc(2 * var(--she-mm)); border-bottom: 1px solid #E4E7EC; font-family: var(--font-mono); font-size: 9px; color: #5F6673; }

/* body + rows */
.she-body { flex: 1; padding: calc(7 * var(--she-mm)) calc(11.6 * var(--she-mm)); display: flex; flex-direction: column; }
.she-row { display: grid; }
.she-blk { position: relative; min-width: 0; }

/* primitives */
.she-secbar { display: flex; align-items: center; gap: 6px; padding: calc(2 * var(--she-mm)) 0 calc(1.2 * var(--she-mm)); border-bottom: 1px solid #E4E7EC; margin-bottom: calc(2 * var(--she-mm)); font-size: 11.5px; font-weight: 700; letter-spacing: .32px; text-transform: uppercase; color: #0A0B0E; }
.she-secbar-sq { width: calc(2.1 * var(--she-mm)); height: calc(2.1 * var(--she-mm)); background: #F89010; }
.she-subsec { font-size: 12px; font-weight: 600; color: #0A0B0E; padding: calc(2 * var(--she-mm)) 0 calc(1 * var(--she-mm)); }
.she-fcell { padding: calc(1 * var(--she-mm)) calc(1.5 * var(--she-mm)) calc(1.6 * var(--she-mm)) 0; border-bottom: 1px solid #F2F4F7; }
.she-fval { font-size: 12.5px; font-weight: 600; color: #0A0B0E; margin-top: 2px; overflow-wrap: break-word; }
.she-fval--mu { color: #667085; }
.she-comment { padding: calc(1 * var(--she-mm)) 0 calc(1.6 * var(--she-mm)); }
.she-comment-body { font-size: 12px; color: #344054; line-height: 1.55; margin-top: 2px; overflow-wrap: break-word; }
.she-status { display: flex; flex-direction: column; }
.she-status-row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; padding: calc(1.4 * var(--she-mm)) 0; border-bottom: 1px solid #F2F4F7; }
.she-status-item { font-size: 12px; color: #344054; flex: 1; min-width: 0; }
.she-status-opts { display: flex; gap: 12px; flex-shrink: 0; }
.she-status-opt { display: flex; align-items: center; gap: 5px; font-size: 11px; color: #475467; }
.she-checkbox { width: 11px; height: 11px; border: 1.2px solid #667085; border-radius: 2px; display: inline-block; position: relative; flex-shrink: 0; }
.she-checkbox--on { border-color: #0A0B0E; }
.she-checkbox--on::after { content: ''; position: absolute; inset: 1.5px; background: #0A0B0E; border-radius: 1px; }
.she-tablewrap { padding-bottom: calc(1.6 * var(--she-mm)); }
.she-table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.she-table th { background: #F5F6F8; font-size: 9.5px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; color: #475467; text-align: left; padding: calc(1.8 * var(--she-mm)) 6px; }
.she-table td { font-size: 11.5px; color: #344054; padding: calc(1.6 * var(--she-mm)) 6px; border-bottom: 1px solid #E4E7EC; }
.she-table tbody tr:nth-child(odd) td { background: #FCFCFD; }
.she-td-num { font-family: var(--font-mono); }
.she-photos { padding-bottom: calc(2 * var(--she-mm)); }
.she-photo-grid { display: grid; grid-template-columns: 1fr 1fr; gap: calc(2 * var(--she-mm)); }
.she-photo-cell { height: calc(42 * var(--she-mm)); border: 1px dashed #D0D5DD; display: flex; align-items: center; justify-content: center; }
.she-photo-cap { font-family: var(--font-mono); font-size: 8.5px; letter-spacing: .08em; color: #667085; }
.she-certbox { background: #F5F6F8; border: 1px solid #E4E7EC; padding: calc(3.7 * var(--she-mm)) calc(4.8 * var(--she-mm)); font-size: 11.5px; color: #344054; line-height: 1.5; }
.she-certbox b { color: #0A0B0E; }
.she-sigblock { padding-top: calc(4 * var(--she-mm)); }
.she-sig-idrow { display: flex; justify-content: space-between; align-items: baseline; }
.she-sig-name { font-size: 12.5px; font-weight: 600; color: #0A0B0E; }
.she-sig-date { font-family: var(--font-mono); font-size: 11px; color: #475467; font-variant-numeric: tabular-nums; }
.she-sig-lab { margin-top: calc(3 * var(--she-mm)); }
.she-sig-rule { width: calc(60 * var(--she-mm)); border-bottom: 1px solid #D0D5DD; height: calc(6 * var(--she-mm)); }
.she-crew-row { display: flex; align-items: flex-end; gap: calc(3.7 * var(--she-mm)); padding: calc(1.6 * var(--she-mm)) 0; }
.she-crew-n { font-family: var(--font-mono); font-size: 10.5px; color: #5F6673; width: calc(4.8 * var(--she-mm)); }
.she-crew-name { font-size: 12.5px; color: #0A0B0E; width: calc(74 * var(--she-mm)); }
.she-crew-rule { flex: 1; border-bottom: 1px solid #D0D5DD; height: calc(5 * var(--she-mm)); }
.she-crew-tag { font-size: 8.5px; }
.she-tg-item { display: flex; align-items: center; gap: 7px; font-size: 12px; color: #344054; padding: calc(1 * var(--she-mm)) 0; }
.she-tg-more { font-size: 11px; color: #667085; font-style: italic; padding-top: calc(1 * var(--she-mm)); }
.she-note { font-size: 10.5px; color: #667085; font-style: italic; padding-top: calc(1.2 * var(--she-mm)); }

/* FLRA task pattern — mirrors the PDF's referencia-2b .task block */
.she-flra-task { padding: calc(2.6 * var(--she-mm)) 0 calc(2 * var(--she-mm)); border-bottom: 1px solid #F2F4F7; }
.she-flra-task:last-child { border-bottom: 0; }
.she-flra-head { display: flex; align-items: baseline; gap: 10px; }
.she-flra-no { font-family: var(--font-mono); font-size: 10.5px; color: #5F6673; flex-shrink: 0; }
.she-flra-title { font-size: 13px; font-weight: 600; color: #0A0B0E; flex: 1; min-width: 0; }
.she-pill {
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .04em;
  padding: 2px 9px; border-radius: 999px; flex-shrink: 0;
  border: 1px solid transparent;
}
/* BADGE palette from js/pdf/tokens.js — document colors, not admin tokens */
.she-pill--low    { background: #E4F8EC; color: #15803D; border-color: #A7E8BF; }
.she-pill--medium { background: #FEF1DD; color: #B45309; border-color: #FBD391; }
.she-pill--high   { background: #FDE9E9; color: #B91C1C; border-color: #F9B4B4; }
.she-hpair { display: grid; grid-template-columns: 1fr 1fr; gap: calc(4 * var(--she-mm)); padding-top: calc(1.6 * var(--she-mm)); }
.she-hpair-col { min-width: 0; }
.she-hpair-line { font-size: 12px; color: #344054; line-height: 1.5; padding: 1px 0; overflow-wrap: break-word; }

/* footer */
.she-foot { display: flex; justify-content: space-between; align-items: center; padding: calc(2 * var(--she-mm)) calc(11.6 * var(--she-mm)); border-top: 1px solid #E4E7EC; font-size: 9.5px; color: #667085; margin-top: auto; }
.she-foot-c { display: flex; align-items: center; gap: 5px; }
.she-foot-sq { width: 7px; height: 7px; background: #F89010; display: inline-block; }
.she-foot-r { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ── editor chrome (admin tokens resume here — this is chrome, not document) */
body.she-open { overflow: hidden; }
.she-root {
  position: fixed; inset: 0; z-index: 300;
  background: var(--page-bg);
  display: flex; flex-direction: column;
  outline: none;
}
.she-bar {
  height: 48px; flex-shrink: 0;
  display: flex; align-items: center; gap: 16px;
  background: var(--chrome-bg); border-bottom: 1px solid var(--chrome-border-strong);
  padding: 0 14px;
}
.she-bar-l { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; }
.she-bar-c { display: flex; align-items: center; gap: 4px; }
.she-bar-r { display: flex; align-items: center; gap: 7px; flex: 1; justify-content: flex-end; }
.she-back {
  width: 30px; height: 30px; border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--bg-2); color: var(--text-2); display: flex; align-items: center; justify-content: center;
  cursor: pointer;
}
.she-back:hover { border-color: var(--border-hover); color: var(--text); }
.she-back svg { width: 15px; height: 15px; }
.she-bar-title { display: flex; align-items: center; gap: 8px; min-width: 0; }
.she-bar-name { font-size: var(--text-title); font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.she-iconbtn {
  width: 28px; height: 28px; border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--bg-2); color: var(--text-2); display: flex; align-items: center; justify-content: center;
  cursor: pointer;
}
.she-iconbtn:hover:not(:disabled) { border-color: var(--border-hover); color: var(--text); }
.she-iconbtn:disabled { opacity: .38; cursor: default; }
.she-iconbtn svg { width: 14px; height: 14px; }
.she-editor-body { flex: 1; overflow: auto; padding: 30px 24px 90px; }
.she-groupsel {
  height: 28px; border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--bg-2); color: var(--text-2); font-size: 12.5px; padding: 0 6px;
}
.she-groupsel:hover { border-color: var(--border-hover); color: var(--text); }
.she-mailtog { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-2); cursor: pointer; }
.she-mailtog input { accent-color: var(--accent); }

/* history drawer */
.she-drawer {
  position: absolute; top: 48px; right: 0; bottom: 0; width: 480px; max-width: 92vw;
  background: var(--surface-flat); border-left: 1px solid var(--border);
  display: flex; flex-direction: column; z-index: 10;
}
.she-drawer-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px var(--row-pad-x); border-bottom: 1px solid var(--border-inner);
  font-size: 11px; font-weight: 600; letter-spacing: .075em; text-transform: uppercase; color: var(--text-label);
}
.she-drawer-main { flex: 1; overflow: auto; padding: 8px var(--row-pad-x) 20px; }

/* real-PDF overlay */
.she-pdfbox { position: absolute; inset: 0; z-index: 38; background: var(--page-bg); display: flex; flex-direction: column; }
.she-pdfbox-bar {
  height: 48px; flex-shrink: 0; display: flex; align-items: center; justify-content: space-between;
  background: var(--chrome-bg); border-bottom: 1px solid var(--chrome-border-strong); padding: 0 14px;
}
.she-pdfbox-main { flex: 1; overflow: auto; display: flex; justify-content: center; padding: 24px; }
.she-pdfbox-main iframe { width: 820px; max-width: 100%; height: 100%; border: 1px solid var(--border-strong); background: #FFFFFF; }
.she-pdfbox-load { align-self: center; font-size: 13px; color: var(--text-muted); }

/* selection + inline edit affordances (chrome layered over the paper) */
#sheBody .she-blk { cursor: default; }
#sheBody .she-blk:hover { outline: 1.5px solid var(--focus-ring); outline-offset: 3px; border-radius: 2px; }
#sheBody .she-blk--sel, #sheBody .she-blk--sel:hover { outline: 1.5px solid var(--accent); outline-offset: 3px; border-radius: 2px; }
/* The toolbar rides the page's RIGHT MARGIN — the one vertical strip of the
   sheet that is blank by construction (the printed band ends at 204.3mm).
   _sheGutterTools places it. Anchored on the block it covered the ink it
   belongs to, and on anything shorter than ~54px it sat on top of the width
   handle and swallowed its clicks. */
.she-tools {
  position: absolute; z-index: 8;  /* above seam (6) and handles (7) */
  display: flex; flex-direction: column; gap: 2px; padding: 2px;
  background: var(--surface-flat); border: 1px solid var(--border); border-radius: var(--r-sm);
}
.she-tool {
  width: 24px; height: 24px; border: 0; border-radius: 6px; background: transparent;
  color: var(--text-2); display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.she-tool:hover { background: var(--surface-flat-2); color: var(--text); }
.she-tool--del:hover { background: var(--error-soft); color: var(--error); }
.she-tool--lock { color: var(--text-dim); cursor: default; }
.she-tool svg { width: 13px; height: 13px; }
[data-she-edit] { cursor: text; }
.she-inline {
  outline: none; background: var(--accent-soft);
  box-shadow: inset 0 -1.5px 0 var(--accent);
}
.she-toast {
  position: absolute; bottom: 26px; left: 50%; transform: translateX(-50%);
  background: var(--ink); color: var(--on-ink); font-size: 13px;
  padding: 8px 16px; border-radius: var(--r-sm); z-index: 20;
}

/* drag reorder + row joining */
#sheBody .she-blk[draggable="true"] { cursor: grab; }
#sheBody .she-blk[draggable="true"] [data-she-edit] { cursor: text; }
#sheBody .she-dragging { opacity: .4; }
.she-dropline { height: 3px; background: var(--accent); border-radius: 2px; margin: 2px 0; }
.she-join-l::before, .she-join-r::before {
  content: ''; position: absolute; top: 2px; bottom: 2px; width: 3px;
  background: var(--accent); border-radius: 2px; z-index: 3;
}
.she-join-l::before { left: -2px; }
.she-join-r::before { right: -2px; }

/* insert seam + palette */
.she-seam { position: relative; height: 0; z-index: 6; }
.she-seam-btn {
  position: absolute; left: 50%; top: -12px; transform: translateX(-50%);
  width: 24px; height: 24px; border-radius: 999px;
  background: var(--accent); color: var(--on-accent); border: 0;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.she-seam-btn:hover { background: var(--accent-2); color: #FFFFFF; }
.she-seam-btn svg { width: 13px; height: 13px; }
.she-seam::before {
  content: ''; position: absolute; left: 0; right: 0; top: -1px;
  border-top: 2px dashed var(--accent); opacity: .45;
}
.she-pal {
  position: absolute; left: 50%; top: 16px; transform: translateX(-50%);
  display: grid; grid-template-columns: repeat(3, 118px); gap: 1px;
  background: var(--border-subtle); border: 1px solid var(--border); border-radius: var(--r-md);
  overflow: hidden; z-index: 30;
}
.she-pal-i {
  display: flex; align-items: center; gap: 8px; padding: 9px 11px;
  background: var(--surface-flat); border: 0; cursor: pointer;
  font-size: 12.5px; color: var(--text-2); text-align: left;
}
.she-pal-i:hover { background: var(--surface-flat-2); color: var(--text); }
.she-pal-g {
  width: 22px; height: 22px; border-radius: 6px; background: var(--surface-flat-3);
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; color: var(--text-2); flex-shrink: 0;
}

/* resize handles + live tag — z above the seam (7 > 6): both live on block
   edges and the handle must win the hit-test or a resize grab starts a drag */
.she-h { position: absolute; z-index: 7; touch-action: none; }
.she-h-e {
  right: -5px; top: 50%; transform: translateY(-50%);
  width: 9px; height: 26px; cursor: ew-resize;
  background: var(--accent); border-radius: 999px; border: 2px solid var(--surface-flat);
}
.she-h-s {
  bottom: -5px; left: 50%; transform: translateX(-50%);
  height: 9px; width: 26px; cursor: ns-resize;
  background: var(--accent); border-radius: 999px; border: 2px solid var(--surface-flat);
}
.she-h-w {
  left: -5px; top: 50%; transform: translateY(-50%);
  width: 9px; height: 26px; cursor: ew-resize;
  background: var(--accent); border-radius: 999px; border: 2px solid var(--surface-flat);
}
.she-h-n {
  top: -5px; left: 50%; transform: translateX(-50%);
  height: 9px; width: 26px; cursor: ns-resize;
  background: var(--accent); border-radius: 999px; border: 2px solid var(--surface-flat);
}
/* insert points: always offered on the selected block, never a hover hunt */
.she-ins {
  position: absolute; z-index: 9; width: 22px; height: 22px; padding: 0;
  border-radius: 999px; border: 1px dashed var(--border-strong);
  background: var(--surface-flat); color: var(--text-muted);
  font-size: 14px; line-height: 1; cursor: pointer;
}
.she-ins:hover { border-style: solid; border-color: var(--accent); background: var(--accent); color: var(--on-accent); }
.she-tag {
  position: fixed; z-index: 40; pointer-events: none;
  background: var(--ink); color: var(--on-ink);
  font-family: var(--font-mono); font-size: 11.5px; font-variant-numeric: tabular-nums;
  padding: 3px 8px; border-radius: 6px;
}

/* field-settings popover (phone-only props: help, placeholder, show-if…) */
.she-pop {
  position: fixed; width: 300px; max-height: 70vh; overflow-y: auto; z-index: 35;
  background: var(--surface-flat); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 4px 0 10px;
}
.she-pop .fbe-props { padding: 8px 16px 0; }

/* on-sheet structural affordances — chrome revealed only on the selected
   block, so the resting sheet reads as clean paper */
.she-x {
  width: 16px; height: 16px; border: 0; border-radius: 4px; padding: 0;
  background: transparent; color: var(--text-dim); cursor: pointer;
  display: none; align-items: center; justify-content: center; flex-shrink: 0;
}
.she-x svg { width: 9px; height: 9px; }
.she-x:hover { background: var(--error-soft); color: var(--error); }
.she-add {
  display: none; align-items: center; gap: 6px; align-self: flex-start;
  border: 1px dashed var(--border-strong); border-radius: var(--r-sm);
  background: transparent; color: var(--text-muted); cursor: pointer;
  font-size: 11.5px; padding: 3px 10px; margin: 4px 0 2px;
}
.she-add:hover { border-color: var(--accent); color: var(--accent-ink); background: var(--accent-soft); }
.she-add span { font-size: 13px; line-height: 1; }
.she-blk--sel .she-x { display: inline-flex; }
.she-blk--sel .she-add { display: inline-flex; }
.she-actbox { cursor: pointer; }
.she-req { color: var(--accent-ink); font-weight: 700; }
.she-tool--req { font-size: 15px; font-weight: 700; line-height: 1; }
.she-tool--on { background: var(--accent-soft); color: var(--accent-ink); }
.she-pill--unset { display: none; background: transparent; color: var(--text-dim); border: 1px dashed var(--border-strong); cursor: pointer; }
.she-blk--sel .she-pill--unset { display: inline-block; }
.she-blk--sel .she-pill { cursor: pointer; }
.she-tg-sec { display: flex; align-items: center; gap: 6px; }
.she-hpair-row { display: flex; align-items: baseline; gap: 4px; }
.she-hpair-row .she-hpair-line { flex: 1; min-width: 0; }
.she-th { white-space: nowrap; }
.she-th .she-x { vertical-align: middle; margin-left: 4px; }
.she-th-add { width: 1%; background: #FFFFFF !important; }
.she-th-add .she-add { margin: 0; padding: 2px 8px; }

/* choice fields — blank-form option boxes */
.she-choice { padding: calc(1 * var(--she-mm)) 0 calc(1.6 * var(--she-mm)); }
.she-choice-row { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: calc(1.2 * var(--she-mm)); align-items: center; }
.she-choice-opt { display: flex; align-items: center; gap: 6px; font-size: 12px; color: #344054; }
.she-choice-opt .she-add { margin: 0; }
.she-checkbox--round { border-radius: 999px; }
.she-choice .she-add { margin: 0; }

/* keyboard reach: these controls sit on white paper as often as on the admin
   surface, so the ring is drawn rather than borrowed from the UA */
.she-tool:focus-visible, .she-strip-btn:focus-visible, .she-pal-i:focus-visible,
.she-seam-btn:focus-visible, .she-x:focus-visible, .she-add:focus-visible,
.she-iconbtn:focus-visible, .she-back:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}
.she-insp-ch {
  font-size: 11px; font-weight: 600; letter-spacing: .075em; text-transform: uppercase;
  color: var(--text-label); padding: 10px 16px 4px;
}
@media (prefers-reduced-motion: reduce) {
  .she-regen .she-page--pdf { transition: none; }
}
