/* FoamSignal's one stylesheet. Every screen inherits the tokens and the controls below.
   The rules it is held to (test/style.test.ts, scripts/demo-r8):
   - FoamSignal's brand (docs/BRAND.md): navy bars and navy-leaning neutrals, and signal yellow as the ONE accent
     (--accent), always a fill with navy words on it and never the colour of words. ONE alarm (--alarm). Green, amber
     and red say a status and nothing else, and amber leans to orange so it is never taken for the yellow.
   - Every colour is a token: the dark set under prefers-color-scheme swaps them all, so nothing below names a colour.
   - Text on its background is WCAG AA (4.5:1) in both sets; a control's edge is 3:1.
   - Spacing steps by 8px (4px only inside a control). Tappable things are 48px high, 56px and more on crew screens.
   - Motion is a 120ms fade of colour only, and none at all under prefers-reduced-motion. */
:root {
  color-scheme: light dark;

  /* Neutrals: the brand's off-white and midnight navy, and greys that lean to the navy. */
  --bg: #f5f7fa;
  --card: #ffffff;
  --ink: #0b1420;
  --muted: #4a5a6b;
  --line: #d7dee6;
  /* The edge of a control, in the brand's pencil blue: 3:1 against the card and the page. A line, never words. */
  --edge: #5d7a94;
  --well: #e8edf2;

  /* The top bar and the sign-in band: industrial navy in both sets, under the lockup made for dark backgrounds. */
  --bar: #1b2a3a;
  --bar-ink: #f5f7fa;
  --bar-muted: #b9c5d1;
  --bar-well: #0b1420;

  /* The one accent, signal yellow: what to tap next. A fill with navy words on it, never the colour of words (yellow
     on white is 1.4:1). Where the accent has to be a line on the page (a ticked box, the step he is on) it is
     --accent-line: navy here, yellow in the dark set. */
  --accent: #ffd343;
  --accent-ink: #0b1420;
  --accent-line: #1b2a3a;
  /* Focus: a yellow band, and outside it a line that is 3:1 on the page. */
  --focus: #ffd343;
  --focus-edge: #0b1420;

  /* The one alarm: do not spray, and what failed. */
  --alarm: #b3261e;
  --alarm-ink: #ffffff;

  /* Status, as words on a tint (flags, pills)... Amber is an orange amber, a clear step from the brand's yellow. */
  --ok: #146c2e;
  --ok-bg: #e2f3e6;
  --warn: #7a3b00;
  --warn-bg: #fde6cf;
  --err: #b3261e;
  --err-bg: #fce9e7;
  /* ...and as a solid chip that reads at arm's length. */
  --good-chip: #146c2e;
  --good-chip-ink: #ffffff;
  --marginal-chip: #f28c0f;
  --marginal-chip-ink: #0b1420;
  --marginal-chip-edge: #7a3b00;
  --none-chip: #b3261e;
  --none-chip-ink: #ffffff;

  /* The plan viewer is a dark room in both sets: a drawing is read against the midnight navy. */
  --viewer-bg: #0b1420;
  --viewer-stage: #1b2a3a;
  --viewer-ink: #ffffff;
  /* A sheet of paper stays white in both sets: thumbnails, signatures, the logo. */
  --paper: #ffffff;
  --paper-ink: #0b1420;

  /* Words are in the phone's own font. Archivo 900, the face of the brand, is for the big numbers only; the word
     FoamSignal is never set in it, it is always the lockup picture. */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-num: "Archivo", var(--font);

  /* The 8px grid. */
  --s1: 8px;
  --s2: 16px;
  --s3: 24px;
  --s4: 32px;
  --s5: 48px;

  /* Comfortable height for the main controls, and the least anything tappable may be. */
  --tap: 48px;
  --tap-min: 44px;
  /* Crew screens: a gloved thumb. */
  --tap-crew: 56px;
  --tap-big: 64px;
  --radius: 16px;
  --radius-control: 12px;
  --fade: 120ms;
  --tabbar-h: 64px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0b1420;
    --card: #1b2a3a;
    --ink: #f5f7fa;
    --muted: #b3c0cd;
    --line: #31455a;
    --edge: #7f99b0;
    --well: #263a4f;

    --bar: #1b2a3a;
    --bar-ink: #f5f7fa;
    --bar-muted: #b9c5d1;
    --bar-well: #0b1420;

    --accent: #ffd343;
    --accent-ink: #0b1420;
    --accent-line: #ffd343;
    --focus: #ffd343;
    --focus-edge: #ffd343;

    --alarm: #c62828;
    --alarm-ink: #ffffff;

    --ok: #7fdc93;
    --ok-bg: #12301a;
    --warn: #ffb561;
    --warn-bg: #3d2408;
    --err: #ffb4ab;
    --err-bg: #451815;
    --good-chip: #4cd47a;
    --good-chip-ink: #0b1420;
    --marginal-chip: #ff9f2e;
    --marginal-chip-ink: #0b1420;
    --marginal-chip-edge: #ff9f2e;
    --none-chip: #ff7b6e;
    --none-chip-ink: #0b1420;
  }
}

/* The one font the app carries: Archivo 900, latin, SIL Open Font License 1.1 (public/fonts/LICENSE-archivo.txt). */
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url("/fonts/archivo-latin-900-normal.woff2") format("woff2");
}

* { box-sizing: border-box; }
/* A hidden element stays hidden whatever its class lays it out as. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font: 17px/1.45 var(--font);
  color: var(--ink);
  background: var(--bg);
  /* A web address or part number longer than the phone is wide breaks instead of pushing the page sideways. */
  overflow-wrap: break-word;
}

body.no-scroll { overflow: hidden; }

/* The page one turn of the router draws into (src/ui/main.ts). It takes no box: its children lay out as .app's own. */
.screen { display: contents; }

.app {
  max-width: 560px;
  margin: 0 auto;
  padding: 0 calc(var(--s2) + env(safe-area-inset-right)) calc(136px + env(safe-area-inset-bottom)) calc(var(--s2) + env(safe-area-inset-left));
}

h1 { font-size: 1.5rem; line-height: 1.2; letter-spacing: -0.01em; margin: 0 0 var(--s1); }
h2 { font-size: 1.15rem; line-height: 1.25; margin: 0 0 var(--s1); }
h3 { font-size: 1rem; margin: var(--s2) 0 var(--s1); }
p { margin: 0 0 var(--s1); }
a { color: var(--ink); text-underline-offset: 3px; }

.muted { color: var(--muted); }
.small { font-size: 0.85rem; }
.pad { padding: var(--s2) 0; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* Colour fades and nothing moves; with reduced motion asked for, not even that. */
a, button, input, select, textarea, summary, .btn, .seg, .chip, .row, .crm-row, .step {
  transition: background-color var(--fade) ease, border-color var(--fade) ease, color var(--fade) ease, opacity var(--fade) ease;
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; scroll-behavior: auto !important; }
}

/* Until the first screen is drawn: the mark on navy (public/index.html). */
.splash { position: fixed; inset: 0; z-index: 40; display: grid; place-items: center; background: var(--bar); }
.splash img { display: block; }

/* Chrome. The top bar is FoamSignal's navy from one edge of the screen to the other, in the light set and the dark. */
.topbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--s1);
  margin: 0 0 var(--s2);
  padding: calc(var(--s1) + env(safe-area-inset-top)) 0 var(--s1);
  background: var(--bar); color: var(--bar-ink);
  /* The bar's colour carried past the column to both edges, without making the page any wider. */
  border-image: conic-gradient(var(--bar) 0 0) fill 0 // 0 100vmax;
}
/* The strip above already clears the notch when it is showing. */
.sync-strip:not([hidden]) + .app .topbar { padding-top: var(--s1); }
.brand { display: inline-flex; align-items: center; justify-content: center; min-width: var(--tap-min); min-height: var(--tap-min); border-radius: var(--s1); }
/* The lockup is one picture and scales as one, never under 140px wide; the file carries its own clear space. On a
   phone too narrow for it beside the Office / Crew switch the mark stands alone (layout.ts names both files). */
.brand img { display: block; width: clamp(140px, calc(100vw - 220px), 207px); height: auto; }
@media (max-width: 359px) {
  .brand img { width: 36px; height: 36px; }
}
.topbar-right { flex: 1; min-width: 0; display: flex; align-items: center; justify-content: flex-end; gap: var(--s1); }
/* The job's name gets its own line, so a long one wraps instead of being cut. */
.topbar-job { flex: 1 1 100%; color: var(--bar-muted); font-size: 0.9rem; padding: 0 0 var(--s1); }

/* Office or Crew: which home this phone opens on. */
.mode { display: inline-flex; padding: 2px; border-radius: 999px; background: var(--bar-well); }
.mode a {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--tap-min); padding: 0 var(--s2);
  border-radius: 999px; font-weight: 600; font-size: 0.95rem; color: var(--bar-muted); text-decoration: none;
}
.mode a[aria-current="page"] { background: var(--bar-ink); color: var(--bar); }

/* Sign in: the lockup on a navy band from edge to edge, the box for the code under it. */
.signin-band {
  display: grid; place-items: center;
  margin: 0 0 var(--s3);
  padding: calc(var(--s5) + env(safe-area-inset-top)) 0 var(--s5);
  background: var(--bar);
  border-image: conic-gradient(var(--bar) 0 0) fill 0 // 0 100vmax;
}
.signin-band img { display: block; width: min(280px, 78vw); height: auto; }

.draft-banner {
  margin: 0 0 var(--s2);
  padding: var(--s1) var(--s2);
  border-radius: var(--radius-control);
  background: var(--warn-bg);
  color: var(--warn);
  font-weight: 700;
  text-align: center;
}

.steps { display: flex; gap: 4px; margin: 0 0 var(--s2); }
.step {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-height: var(--tap); padding: var(--s1) 2px;
  font-size: 0.78rem; color: var(--muted); text-decoration: none;
  border-bottom: 3px solid var(--line);
}
.step-num {
  width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--well); color: var(--ink); font-weight: 700; font-size: 0.75rem;
}
.step.done { color: var(--ink); border-color: var(--ink); }
.step.done .step-num { background: var(--ink); color: var(--card); }
.step.current { color: var(--ink); font-weight: 700; border-color: var(--accent-line); }
.step.current .step-num { background: var(--accent); color: var(--accent-ink); }

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--s3);
  margin: 0 0 var(--s2);
}
.card > :last-child { margin-bottom: 0; }

.footnote { color: var(--muted); font-size: 0.85rem; text-align: center; margin: var(--s2) var(--s1); }
.app-footer { text-align: center; color: var(--muted); font-size: 0.75rem; padding: 0 var(--s2) calc(112px + env(safe-area-inset-bottom)); }
.app-footer a { color: var(--muted); }
.app-footer a, .pad a { display: inline-flex; align-items: center; min-height: var(--tap-min); padding: 0 var(--s1); }

/* Controls */
label, .label { display: block; font-weight: 600; margin: var(--s2) 0 var(--s1); font-size: 0.95rem; }
.unit { font-weight: 400; color: var(--muted); }

input, select, textarea {
  width: 100%;
  min-height: var(--tap);
  padding: var(--s1) 12px;
  font: inherit;
  border: 1px solid var(--edge);
  border-radius: var(--radius-control);
  background: var(--card);
  color: var(--ink);
}
input::placeholder, textarea::placeholder { color: var(--muted); opacity: 1; }
input:focus, select:focus, textarea:focus, .btn:focus-visible, .chip:focus-visible, .seg:focus-visible, a:focus-visible, summary:focus-visible, .crm-row:focus-visible {
  outline: 2px solid var(--focus-edge); outline-offset: 3px; box-shadow: 0 0 0 3px var(--focus);
}
/* On the navy bar the outer line is the bar's own off-white. */
.topbar a:focus-visible { outline-color: var(--bar-ink); }
input[aria-invalid="true"] { border-color: var(--err); background: var(--err-bg); }
progress { display: block; width: 100%; height: var(--s1); accent-color: var(--accent-line); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s1);
  min-height: var(--tap); min-width: var(--tap);
  padding: var(--s1) var(--s2);
  font: inherit; font-weight: 700;
  color: var(--ink);
  background: var(--card);
  border: 2px solid var(--ink);
  border-radius: var(--radius-control);
  cursor: pointer;
  text-decoration: none;
  touch-action: manipulation;
}
.btn.block { display: flex; width: 100%; margin-top: var(--s2); }
/* Yellow with navy words; the navy edge is what says where the button ends on a white card. */
.btn.primary { background: var(--accent); border-color: var(--accent-line); color: var(--accent-ink); }
.btn.ghost { border-color: var(--edge); border-width: 1px; }
.btn.small { min-height: var(--tap-min); padding: 4px 12px; font-size: 0.9rem; }
.btn.icon { padding: 0; font-size: 1.4rem; background: transparent; color: var(--viewer-ink); border-color: var(--edge); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn.danger { background: var(--alarm); border-color: var(--alarm); color: var(--alarm-ink); }

.segmented { display: flex; gap: var(--s1); }
.seg {
  flex: 1; min-height: var(--tap);
  font: inherit; font-weight: 600;
  border: 1px solid var(--edge); border-radius: var(--radius-control); background: var(--card); color: var(--ink);
  touch-action: manipulation; cursor: pointer;
}
.seg.on { border-color: var(--ink); background: var(--ink); color: var(--card); }

.file-row { display: grid; gap: 0; }
.file-name { color: var(--muted); font-size: 0.9rem; margin-top: var(--s1); text-align: center; }
.photo-rows { list-style: none; padding: 0; margin: var(--s2) 0 0; display: grid; gap: var(--s1); }
.photo-rows li { display: flex; justify-content: space-between; align-items: center; gap: var(--s1); }

.pill {
  display: inline-block; padding: 2px 12px; border-radius: 999px;
  background: var(--well); color: var(--ink); font-size: 0.8rem; font-weight: 600;
}
.pill.alt { background: var(--warn-bg); color: var(--warn); }
.pill.ok { background: var(--ok-bg); color: var(--ok); }

.error {
  margin: var(--s2) 0; padding: var(--s2); border-radius: var(--radius-control);
  background: var(--err-bg); color: var(--err);
}
.error ul { margin: var(--s1) 0 0; padding-left: 20px; }

.job-list { list-style: none; margin: 0; padding: 0; }
/* A row's buttons drop under its name when there is no room beside it (three of them on a phone). */
.job-list li { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 0 var(--s1); border-bottom: 1px solid var(--line); }
.job-list li:last-child { border-bottom: 0; }
.job-list li > .btn { margin: var(--s1) 0; }
.job-row {
  flex: 1 1 14em; min-width: 0; display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 4px var(--s1);
  min-height: var(--tap); padding: var(--s1) 0; text-decoration: none;
}
.job-name { flex: 1 1 8em; min-width: 0; font-weight: 600; overflow-wrap: anywhere; }
/* On a phone the name has the row to itself and its buttons share the next one evenly. */
@media (max-width: 640px) {
  .job-row { flex-basis: 100%; padding-bottom: 0; }
  .job-list li { padding-bottom: var(--s1); }
  .job-list li > .btn { flex: 1 1 0; margin: 0; }
}

/* What is only on this phone (src/ui/sync-strip.ts), above every screen */
.sync-strip {
  position: sticky; top: 0; z-index: 4;
  padding: calc(4px + env(safe-area-inset-top)) calc(var(--s2) + env(safe-area-inset-right)) 4px calc(var(--s2) + env(safe-area-inset-left));
  background: var(--warn-bg); color: var(--warn);
  border-bottom: 1px solid var(--line);
  font-size: 0.9rem;
}
.sync-strip > * { max-width: 528px; margin: 0 auto; }
.sync-line { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 4px var(--s1); padding: 2px 0; }
p.sync-line { display: block; }
.sync-badge {
  min-height: var(--tap-min); padding: 4px 12px;
  font: inherit; font-weight: 700; color: var(--warn);
  background: var(--card); border: 2px solid var(--warn); border-radius: 999px;
  cursor: pointer; touch-action: manipulation;
}
.sync-list { padding: 0 0 0 20px; }
.sync-list li { overflow-wrap: anywhere; }
.sync-notices { display: flex; align-items: flex-start; gap: var(--s1); padding: var(--s1) 0; }
.sync-notices ul { flex: 1; min-width: 0; margin: 0; padding-left: 20px; overflow-wrap: anywhere; }
.install-slot { max-width: 560px; margin: 0 auto; padding: 0 var(--s2); text-align: center; }
.install-slot:empty { display: none; }

/* CRM and connector pieces (src/ui/crm) */
.crm-picker h3:first-child, .crm-progress h3 { margin-top: var(--s2); }
.crm-rows { display: grid; gap: var(--s1); margin-top: var(--s1); }
.crm-rows:empty { display: none; }
.crm-rows p { margin: 0; }
.crm-row {
  display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 2px;
  min-height: var(--tap-crew); padding: var(--s1) var(--s2);
  font: inherit; text-align: left; overflow-wrap: anywhere;
  color: var(--ink); background: var(--card); border: 1px solid var(--edge); border-radius: var(--radius-control);
  cursor: pointer; touch-action: manipulation;
}
.crm-row[aria-pressed="true"] { border-color: var(--ink); background: var(--ink); color: var(--card); }
.crm-row[aria-pressed="true"] .muted { color: var(--card); }
.crm-picked { display: flex; align-items: center; justify-content: space-between; gap: var(--s1); }
.crm-picked strong { min-width: 0; overflow-wrap: anywhere; }
.crm-actions { display: flex; flex-wrap: wrap; gap: var(--s1); margin-top: var(--s1); }
.crm-actions .btn { flex: 1; }
.crm-stages { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s1); }
.crm-pushes { margin: 0 0 var(--s1); }
.crm-push { padding: var(--s1) 0; border-bottom: 1px solid var(--line); }
.crm-push.failed { color: var(--err); }
.crm-secret input { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 16px; }
.crm-embed { margin-top: var(--s3); }

/* Bottom action bar: the one thing to do next, under the thumb */
.action-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 5;
  padding: var(--s1) var(--s2) calc(var(--s1) + env(safe-area-inset-bottom));
  background: var(--card);
  border-top: 1px solid var(--line);
}
.action-bar > * { max-width: 528px; margin-left: auto; margin-right: auto; }
.action-bar .btn.block { margin-top: var(--s1); }
.action-bar p { margin: 0; }
.summary { font-weight: 600; font-size: 0.95rem; }

/* Sheet picker */
.sheet-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: var(--s1); }
.sheet {
  background: var(--card); border: 2px solid var(--line); border-radius: var(--radius-control);
  padding: var(--s1); display: flex; flex-direction: column; gap: var(--s1);
}
.sheet.on { border-color: var(--accent-line); box-shadow: 0 0 0 2px var(--accent-line) inset; }
.sheet-pick { margin: 0; cursor: pointer; font-weight: 400; }
.thumb { aspect-ratio: 1224 / 792; background: var(--paper); border-radius: 6px; overflow: hidden; display: grid; place-items: center; }
.thumb canvas { width: 100%; height: auto; display: block; }
.sheet-meta { display: flex; align-items: center; gap: var(--s1); flex-wrap: wrap; margin-top: var(--s1); min-height: 36px; }
.sheet-meta input { width: 26px; min-height: 26px; height: 26px; margin: 0; accent-color: var(--accent-line); }
.sheet-page { font-weight: 700; font-size: 0.9rem; }
.sheet-tag { font-size: 0.78rem; color: var(--muted); }
.sheet-tag.useful { color: var(--ok); font-weight: 700; }

/* Confirmation */
.assembly { border-left: 6px solid var(--line); }
.assembly.confirmed { border-left-color: var(--ok); }
.assembly.excluded { border-left-color: var(--edge); opacity: 0.8; }
.assembly.pending { border-left-color: var(--accent-line); }
.assembly-head { display: flex; align-items: center; gap: var(--s1); flex-wrap: wrap; }
.kind { font-size: 0.8rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.label-input { font-weight: 700; font-size: 1.05rem; margin-top: var(--s1); }
.fields { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--s1); align-items: end; }
/* Two wide boxes (a phone number and an email address) stay two across on a wide screen, where .fields goes to four. */
.fields.pair { grid-template-columns: 1fr 1fr; }
.field label { margin-top: var(--s1); }
.area-line { margin: var(--s2) 0 4px; }
.area { font-size: 1.15rem; }
.formula { color: var(--muted); font-size: 0.9rem; }
.dims .label { margin-top: var(--s1); font-size: 0.85rem; color: var(--muted); }
.chips { display: flex; flex-wrap: wrap; gap: var(--s1); }
.chip {
  display: inline-flex; align-items: center; gap: var(--s1);
  min-height: var(--tap-min); padding: 4px 12px;
  font: inherit; font-size: 0.95rem; font-weight: 600;
  border: 1px solid var(--edge); border-radius: 999px; background: var(--card); color: var(--ink);
  touch-action: manipulation; cursor: pointer;
}
.chip.ok { background: var(--ok-bg); border-color: var(--ok); }
.chip.warn { background: var(--warn-bg); border-color: var(--warn); }
.chip.on { background: var(--ink); color: var(--card); border-color: var(--ink); }
.chip-icon { font-weight: 800; }
.chip.ok .chip-icon { color: var(--ok); }
.chip.warn .chip-icon { color: var(--warn); }
.chip.on .chip-icon { color: inherit; }
.chip-page { color: var(--muted); font-weight: 500; font-size: 0.8rem; }
.chip.on .chip-page { color: inherit; }
.flags { list-style: none; margin: var(--s1) 0 0; padding: 0; display: grid; gap: var(--s1); }
.flag { padding: var(--s1) 12px; border-radius: var(--s1); font-size: 0.9rem; margin: var(--s1) 0 0; }
.flag.warn { background: var(--warn-bg); color: var(--warn); }
.flag.info { background: var(--well); }
.flag.ok { background: var(--ok-bg); color: var(--ok); }
.flag a { color: inherit; }
.notes { font-size: 0.9rem; color: var(--muted); margin: var(--s1) 0 0; }
.decision { display: grid; grid-template-columns: 2fr 1fr; gap: var(--s1); margin-top: var(--s2); }
.btn.confirm { border-color: var(--ok); color: var(--ok); }
.btn.confirm.on { background: var(--ok); color: var(--card); }
.btn.exclude { border-color: var(--edge); color: var(--muted); }
.btn.exclude.on { background: var(--muted); border-color: var(--muted); color: var(--card); }
.add-row { display: grid; grid-template-columns: 1fr auto; gap: var(--s1); }
details summary { min-height: var(--tap); display: flex; align-items: center; font-weight: 600; cursor: pointer; }
ul.plain { list-style: none; padding: 0; }

/* Estimate */
.line-head { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px var(--s1); margin-bottom: var(--s1); }
.line-label { font-weight: 700; }
.depth-row { display: grid; grid-template-columns: 1fr; }
.depth-row .chips { margin-top: var(--s1); }
.bf-line { margin: var(--s1) 0 0; }
/* min-width: a fieldset is as wide as its widest content unless told otherwise, which pushes a phone screen sideways. */
fieldset { min-width: 0; border: 1px solid var(--line); border-radius: var(--radius-control); margin: var(--s2) 0; padding: 4px var(--s2) var(--s2); }
legend { font-weight: 700; padding: 0 var(--s1); }
.results { border: 2px solid var(--ink); }
.price-range { font-family: var(--font-num); font-size: 2rem; line-height: 1.15; font-weight: 900; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; margin: 4px 0 var(--s1); }
.price-range .label { margin: 0; font-family: var(--font); font-size: 0.85rem; color: var(--muted); font-weight: 600; letter-spacing: 0; }
.totals { display: grid; grid-template-columns: 1fr auto; gap: var(--s1) var(--s2); margin: var(--s2) 0; }
.totals dt { color: var(--muted); }
.totals dd { margin: 0; text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }
.totals dd.big { font-size: 1.15rem; }
.sensitivity { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.sensitivity th, .sensitivity td { padding: var(--s1) 4px; border-bottom: 1px solid var(--line); text-align: right; vertical-align: top; }
.sensitivity th:first-child { text-align: left; }
.sensitivity tr.expected { background: var(--well); font-weight: 700; }

/* Viewer */
.viewer {
  position: fixed; inset: 0; z-index: 20;
  display: grid; grid-template-rows: auto 1fr auto;
  background: var(--viewer-bg); color: var(--viewer-ink);
}
.viewer-bar { display: flex; align-items: center; gap: var(--s1); padding: var(--s1) calc(var(--s1) + env(safe-area-inset-right)) var(--s1) var(--s2); padding-top: calc(var(--s1) + env(safe-area-inset-top)); }
.viewer-title { flex: 1; font-weight: 600; font-size: 0.9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.viewer-stage { position: relative; overflow: hidden; touch-action: none; background: var(--viewer-stage); }
.viewer-sheet { position: absolute; left: 0; top: 0; transform-origin: 0 0; will-change: transform; }
.viewer-sheet canvas { display: block; }
.viewer-mark {
  position: absolute; transform-origin: 4px calc(100% - 4px);
  border: 4px solid var(--alarm); border-radius: 6px; background: color-mix(in srgb, var(--alarm) 12%, transparent);
  pointer-events: none;
}
.viewer-status { margin: 0; padding: var(--s1) var(--s2) calc(var(--s1) + env(safe-area-inset-bottom)); font-size: 0.9rem; }

/* Crew screens: one hand, a gloved thumb, read in the sun. Everything tappable is 56px and more, the words are
   ink on the page (no grey for anything that must be read), and the one thing to do next is the biggest thing. */
.btn.big { min-height: var(--tap-big); font-size: 1.15rem; border-radius: var(--radius); }
.crew .btn, .crew .seg, .crew .chip, .crew input, .crew select, .crew textarea, .crew details summary { min-height: var(--tap-crew); }
.crew .btn.big { min-height: var(--tap-big); }
/* On the crew's screens the top bar and the footer link are held to the same thumb size as the work itself. */
.crew .brand, .crew .mode a, .crew .sync-badge, .crew .app-footer a { min-height: var(--tap-crew); }
/* Under the owner's tabs the top bar keeps the shell's size too (docs/SHELL-SCREENS.md, rule 2). */
body.has-tabs .brand, body.has-tabs .mode a, body.has-tabs .app-footer a { min-height: var(--tap-crew); }
/* The mark alone on a small phone is still a full thumb wide. */
.crew .brand { min-width: var(--tap-crew); }
.crew input[type="checkbox"], .crew input[type="radio"] { min-height: 0; }
/* A box inside its label: 16 px so an iPhone does not zoom the page when it is tapped, and not in the label's bold. */
.crew label input[type="text"], .crew label textarea, label.field > input, label.field > select { display: block; margin-top: var(--s1); font-size: 1rem; font-weight: 400; }
.crew-back { margin: var(--s1) 0 4px; }
.crew-back a { display: inline-flex; align-items: center; min-width: var(--tap-crew); min-height: var(--tap-crew); font-weight: 600; text-decoration: none; }
.crew-rows { list-style: none; margin: 0; padding: 0; }
.crew-rows > li { border-bottom: 1px solid var(--line); }
.crew-rows > li:last-child { border-bottom: 0; }
.crew-row { display: flex; align-items: center; justify-content: space-between; gap: var(--s1); min-height: var(--tap-big); padding: var(--s1) 0; color: var(--ink); text-decoration: none; }
.crew-row-main { display: grid; gap: 2px; min-width: 0; overflow-wrap: anywhere; }
.crew-row .pill, .crew-row .status, .crew-row .btn { flex: none; }
/* The crew's home: one card a job. The name and the window chip lead; the three numbers read at arm's length. */
.crew-jobs { display: grid; gap: var(--s2); list-style: none; margin: 0; padding: 0; }
.crew-job { margin: 0; }
.crew-job-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s1); }
.crew-job-head h2 { margin: 0; font-size: 1.35rem; overflow-wrap: anywhere; }
.crew-job .fact { padding: var(--s1); }
.crew-job > p { margin: var(--s1) 0 0; }
.fact-detail { display: block; font-size: 0.8rem; font-weight: 600; color: var(--muted); }
.crew-drum { padding: 4px 0 var(--s2); }
.crew-add { display: grid; grid-template-columns: 1fr auto; gap: var(--s1); align-items: end; }
.crew-photos { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s1); margin-top: var(--s2); }
.crew-photo { margin: 0; min-width: 0; }
.crew-photo img, .crew-photo-away { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--s1); background: var(--well); }
.crew-photo-away { display: grid; place-items: center; padding: var(--s1); text-align: center; }
.crew-photo figcaption { display: flex; flex-wrap: wrap; gap: 4px var(--s1); align-items: center; font-size: 0.85rem; margin: 4px 0; }
.crew-summary { margin: 0; font: inherit; font-size: 0.9rem; white-space: pre-wrap; overflow-wrap: anywhere; }
/* The daily jobsite record: the crew's form (one answer a tap, a source under each filled box) and the owner's list of days. */
.record-days { display: flex; flex-wrap: wrap; gap: var(--s1); margin: var(--s1) 0; }
/* A source sits on its own line under its value, clear of the box above it. */
.record .src { display: block; width: fit-content; margin: 4px 0 0; }
.record-safety { padding: 0 0 var(--s2); margin: 0 0 var(--s2); border-bottom: 1px solid var(--line); }
.record-safety > .label { margin-top: 0; font-size: 1rem; }
.records-list { list-style: none; margin: var(--s1) 0 0; padding: 0; }
.records-list > li { display: flex; align-items: center; justify-content: space-between; gap: var(--s1); min-height: var(--tap); padding: var(--s1) 0; border-bottom: 1px solid var(--line); }
.records-day { display: grid; gap: 4px; justify-items: start; min-width: 0; }
.signature-pad { display: block; width: 100%; height: auto; border: 2px solid var(--ink); border-radius: var(--radius-control); background: var(--paper); touch-action: none; }
.signature { display: block; width: 100%; max-width: 280px; height: auto; margin-top: var(--s1); border: 1px solid var(--line); border-radius: var(--s1); background: var(--paper); }
.flag p { margin: 0 0 4px; }
/* "DO NOT SPRAY": the one thing on the crew screen that must not be missed. Solid alarm, white words. */
.stop { margin: var(--s2) 0; padding: var(--s2); border-radius: var(--radius-control); background: var(--alarm); color: var(--alarm-ink); }
.stop-head { margin: 0 0 var(--s1); font-size: 1.5rem; font-weight: 800; letter-spacing: 0.02em; }
.stop ul { margin: 0 0 var(--s1); padding-left: 20px; }
.stop p.small { margin: 0; }
.pill.stop { background: var(--alarm); color: var(--alarm-ink); margin: 0; padding: 2px 12px; }
.logo-preview { display: block; max-width: 220px; max-height: 120px; margin: var(--s1) 0; border: 1px solid var(--line); border-radius: var(--s1); background: var(--paper); }

/* Stock screen (src/ui/screens/stock.ts) */
.stock-place { margin-top: var(--s2); border-top: 1px solid var(--line); }
.stock-place h3 { margin-bottom: 2px; }
.stock-place > p { margin: 0; }
.stock-lines, .stock-rigs, .stock-ledger { list-style: none; margin: var(--s1) 0 0; padding: 0; }
.stock-line { padding: var(--s2) 0; border-bottom: 1px solid var(--line); }
.stock-line:last-child { border-bottom: 0; padding-bottom: 0; }
.stock-line-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s1); }
.stock-line-head strong { min-width: 0; overflow-wrap: anywhere; }
.stock-line-sets { flex: none; font-weight: 700; font-size: 1.05rem; font-variant-numeric: tabular-nums; }
.stock-line[data-state="empty"] .stock-line-sets { color: var(--muted); }
.stock-line[data-state="short"] .stock-line-sets { color: var(--err); }
.stock-line-lot { margin: 2px 0 0; overflow-wrap: anywhere; }
.stock-line-date { margin: 4px 0 0; }
.stock-line-date.flag { display: inline-block; padding: 4px var(--s1); }
.stock-line-actions { display: flex; flex-wrap: wrap; gap: var(--s1); margin-top: var(--s1); }
.stock-form { margin-top: var(--s2); padding: 0 var(--s2) var(--s2); border: 1px solid var(--line); border-radius: var(--radius-control); background: var(--bg); }
.stock-form h3 { margin-top: var(--s2); }
.stock-rigs > li { display: flex; align-items: center; justify-content: space-between; gap: var(--s1); min-height: var(--tap-min); padding: 4px 0; border-bottom: 1px solid var(--line); overflow-wrap: anywhere; }
.stock-ledger > li { display: grid; gap: 2px; padding: var(--s1) 0; border-bottom: 1px solid var(--line); font-size: 0.95rem; overflow-wrap: anywhere; }
.stock-rigs > li:last-child, .stock-ledger > li:last-child { border-bottom: 0; }

/* Rig data screen (src/ui/screens/rigs.ts) and a job's rig report (src/ui/screens/job-rig.ts) */
.rig-drop { display: grid; gap: var(--s1); justify-items: center; margin: var(--s2) 0 0; padding: var(--s3) var(--s2); border: 2px dashed var(--edge); border-radius: var(--radius-control); background: var(--bg); text-align: center; cursor: pointer; }
.rig-drop.over { border-color: var(--accent-line); }
.rig-list { list-style: none; margin: var(--s1) 0 0; padding: 0; }
.rig-list > li { padding: var(--s2) 0; border-bottom: 1px solid var(--line); overflow-wrap: anywhere; }
.rig-list > li:last-child { border-bottom: 0; padding-bottom: 0; }
.rig-list h3, .rig-list p { margin: 0 0 4px; }
.rig-mail-text { white-space: pre-wrap; font-size: 0.95rem; }
.rig-address { margin: var(--s1) 0; padding: var(--s1) var(--s2); border: 1px solid var(--line); border-radius: var(--radius-control); background: var(--bg); font-weight: 600; overflow-wrap: anywhere; user-select: all; }
.rig-facts { display: grid; gap: var(--s1); margin: var(--s2) 0 0; }
.rig-facts dt { font-size: 0.9rem; color: var(--muted); }
.rig-facts dd { display: grid; gap: 2px; margin: 0; padding-bottom: var(--s1); border-bottom: 1px solid var(--line); overflow-wrap: anywhere; }
.rig-facts dd:last-child { border-bottom: 0; }

/* Job report: tables scroll sideways inside their own box, so the page itself never does. */
.report-block { margin-top: var(--s3); }
.report-block h2 { margin-bottom: 4px; }
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; border: 1px solid var(--line); border-radius: var(--s1); margin-top: var(--s1); }
.table-scroll:focus-visible { outline: 2px solid var(--focus-edge); outline-offset: 3px; box-shadow: 0 0 0 3px var(--focus); }
.report-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; font-variant-numeric: tabular-nums; }
.report-table th, .report-table td { padding: var(--s1) 12px; text-align: right; vertical-align: top; border-bottom: 1px solid var(--line); white-space: nowrap; }
.report-table th:first-child { text-align: left; white-space: normal; min-width: 9rem; }
.report-table thead th { background: var(--bg); color: var(--muted); font-size: 0.8rem; }
.report-table tbody th { font-weight: 600; }
.report-table tbody tr:last-child > * { border-bottom: 0; }
.report-table.has-total tbody tr:last-child > *, .report-table .lead-row > * { font-weight: 700; background: var(--bg); }
.plain-list { list-style: none; margin: var(--s1) 0; padding: 0; display: grid; gap: 4px; font-size: 0.95rem; }
label.check { display: flex; align-items: center; gap: var(--s1); min-height: var(--tap-min); margin: 0; font-weight: 400; }
label.check input { flex: none; width: 24px; min-height: 24px; height: 24px; padding: 0; accent-color: var(--accent-line); }

/* Dashboard screen (src/ui/screens/dashboard.ts) */
.dash-presets { display: flex; flex-wrap: wrap; gap: var(--s1); }
.dash-presets .seg { flex: 1 1 auto; padding: 0 12px; }
/* Two date boxes side by side where there is room; a date box cannot shrink below its own picker, so on a narrow phone they stack. */
.dash-dates { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 0 var(--s1); }
.dash-dates .field { min-width: 0; }
.dash-range { margin: var(--s2) 0 4px; font-weight: 700; }
.dash-charts { display: grid; gap: var(--s2); margin-top: var(--s2); }
.dash-chart { margin: 0; min-width: 0; }
.dash-chart figcaption { display: flex; flex-wrap: wrap; align-items: center; gap: 4px var(--s2); font-size: 0.9rem; }
.dash-key { display: inline-flex; align-items: center; gap: var(--s1); color: var(--muted); }
.dash-key::before { content: ""; width: 24px; border-top: 3px solid var(--ink); }
.dash-key.real.open::before { border-top-color: var(--edge); }
.dash-key.bid::before { border-top: 2px dashed var(--muted); }
.dash-chart-svg { display: block; width: 100%; height: auto; margin-top: var(--s1); }
.dash-grid { stroke: var(--line); stroke-width: 1; }
.dash-tick { fill: var(--muted); font-size: 13px; }
.dash-line { fill: none; stroke-width: 3; stroke-linejoin: round; stroke-linecap: round; }
.dash-line.real { stroke: var(--ink); }
.dash-line.real.open { stroke: var(--edge); }
.dash-line.bid { stroke: var(--muted); stroke-width: 2; stroke-dasharray: 6 5; }
.dash-dot.real { fill: var(--ink); }
.dash-dot.real.open { fill: var(--edge); }
.dash-dot.bid { fill: var(--card); stroke: var(--muted); stroke-width: 2; }

/* Forecast (src/ui/forecast, src/ui/screens/forecast.ts): a day's window as a chip, the day hour by hour as a strip */
.forecast-days { list-style: none; margin: var(--s1) 0 0; padding: 0; }
.forecast-day { padding: var(--s1) 0; border-bottom: 1px solid var(--line); }
.forecast-day.booked { margin: 0 calc(-1 * var(--s1)); padding: var(--s1); border: 2px solid var(--ink); border-radius: var(--radius-control); }
.forecast-day p, .brief-job p { margin: 4px 0 0; }
.forecast-day-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 4px var(--s1); }
.forecast-day-head strong { flex: 1 1 8em; min-width: 0; overflow-wrap: anywhere; }
.forecast-day-head .pill, .forecast-day-head .status { flex: none; margin: 0; }
.hour-strip { display: grid; grid-template-columns: repeat(24, 1fr); gap: 1px; margin: var(--s1) 0 2px; }
.hr { display: block; height: 16px; border-radius: 2px; background: transparent; }
.hr.off { background: var(--line); }
.hr.good { background: var(--good-chip); }
.hr.marginal { background: var(--marginal-chip); }
.hr.bad { background: var(--none-chip); }
.hour-legend { display: flex; flex-wrap: wrap; gap: 2px var(--s1); margin: var(--s1) 0; }
.hour-key { display: inline-flex; align-items: center; gap: 4px; }
.hour-key .hr { width: 12px; height: 12px; }
.site-date { display: grid; grid-template-columns: 1fr auto; gap: var(--s1); align-items: end; }
.brief-job { padding: var(--s1) 0; }
.crew-rows > .brief-job.this { margin: 0 calc(-1 * var(--s1)); padding: var(--s1); border: 2px solid var(--ink); border-radius: var(--radius-control); }

/* ---------------------------------------------------------------------------------------------------------------
   Round 8: the pieces the three main screens are built from (owner home, crew home, new estimate). Any screen
   may use them. */

/* One number per screen. Nothing else on the screen is this big: Archivo 900, on a bar of the brand's yellow. The
   yellow is under the figures, never behind them, so it reads the same on the light page and the dark one. */
.hero { padding: var(--s3) 0 var(--s2); }
.hero-label { margin: 0; font-size: 0.95rem; font-weight: 600; color: var(--muted); }
.hero-num {
  width: fit-content; max-width: 100%;
  margin: 0; padding: 0 0 4px; border-bottom: var(--s1) solid var(--accent);
  font-family: var(--font-num); font-size: clamp(3rem, 15vw, 4.5rem); line-height: 1.05; font-weight: 900;
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums; overflow-wrap: normal;
}
.hero-num.loss { color: var(--err); }
/* The trend, in words beside an arrow: colour is never the only thing that says which way it went. */
.trend { display: inline-flex; align-items: center; gap: 4px; margin: var(--s1) 0 0; font-weight: 700; }
.trend.up { color: var(--ok); }
.trend.down { color: var(--err); }
.trend.flat { color: var(--muted); }
/* A verdict: the chart, said in a sentence. */
.verdict { margin: var(--s1) 0 0; font-size: 1.1rem; line-height: 1.4; }
.badge {
  display: inline-flex; align-items: center; gap: var(--s1); margin: var(--s2) 0 0; padding: 4px 12px;
  border: 1px solid var(--line); border-radius: 999px; background: var(--card);
  font-size: 0.9rem; font-weight: 600;
}

/* A status, as a solid chip that reads at arm's length: green good, amber marginal, red none. The word is always
   there too. */
.status {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  min-height: var(--s4); padding: 2px 12px; border: 2px solid transparent; border-radius: 999px;
  background: var(--well); color: var(--ink);
  font-size: 0.95rem; font-weight: 800; line-height: 1.2; white-space: nowrap; font-variant-numeric: tabular-nums;
}
.status.good { background: var(--good-chip); color: var(--good-chip-ink); }
.status.marginal { background: var(--marginal-chip); color: var(--marginal-chip-ink); border-color: var(--marginal-chip-edge); }
.status.none { background: var(--none-chip); color: var(--none-chip-ink); }
.status.unknown { border-color: var(--edge); color: var(--muted); }
.status.big { min-height: var(--s5); padding: 4px var(--s2); font-size: 1.25rem; }

/* A list of things to open: each row is one tap, as high as a thumb. */
.rows { list-style: none; margin: 0; padding: 0; }
.rows > li { border-bottom: 1px solid var(--line); }
.rows > li:last-child { border-bottom: 0; }
.row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s2);
  min-height: var(--tap-crew); padding: var(--s1) 0; color: var(--ink); text-decoration: none;
}
.row-main { flex: 1; display: grid; gap: 2px; min-width: 0; overflow-wrap: anywhere; }
.row-title { font-weight: 700; }
.row-sub { color: var(--muted); font-size: 0.9rem; }
.row-main .flag { display: block; margin: 4px 0 0; font-size: 0.9rem; }
.row-day { flex: none; width: 3.5em; font-weight: 700; font-variant-numeric: tabular-nums; }

/* What needs attention: three sentences at most, each one a tap to where it is put right. */
.attention { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s1); }
.attention a, .attention span {
  display: flex; align-items: center; gap: 12px; min-height: var(--tap-crew); padding: var(--s1) var(--s2);
  border-radius: var(--radius-control); background: var(--well); color: var(--ink); text-decoration: none; font-weight: 600;
}
.attention [data-level]::before { content: ""; flex: none; width: 12px; height: 12px; border-radius: 50%; background: var(--edge); }
.attention [data-level="alarm"]::before { background: var(--none-chip); }
.attention [data-level="warn"]::before { background: var(--marginal-chip); box-shadow: 0 0 0 1px var(--marginal-chip-edge); }
.attention [data-level="ok"]::before { background: var(--good-chip); }

/* A figure that is not there yet says what unlocks it and how far along he is. Never a made-up number. */
.unlock { display: grid; gap: var(--s2); margin: 0; padding: 0; list-style: none; }
.unlock-item { display: grid; gap: var(--s1); }
.unlock-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s1); }
.unlock-title { font-weight: 700; }
.unlock-count { flex: none; color: var(--muted); font-size: 0.9rem; font-variant-numeric: tabular-nums; }

/* Three numbers a crew plans the day around: wind, rain, low and high. */
.facts { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s1); margin: var(--s2) 0 0; }
.fact { display: grid; gap: 2px; padding: var(--s1) 12px; border-radius: var(--radius-control); background: var(--well); min-width: 0; }
.fact-label { font-size: 0.8rem; font-weight: 600; color: var(--muted); }
.fact-value { margin: 0; font-size: 1.25rem; font-weight: 800; line-height: 1.2; font-variant-numeric: tabular-nums; }

/* Where a number that was filled in for him came from: "from your CRM", "from your last 6 jobs". */
.src { display: inline-block; margin: 4px 0 0; padding: 0 var(--s1); border-radius: 4px; background: var(--well); color: var(--muted); font-size: 0.8rem; font-weight: 600; }
label .src, .label .src { margin: 0 0 0 var(--s1); }
/* What was filled in, read back as label and value before he goes on; each is his to change. */
.filled { display: grid; gap: var(--s1); margin: var(--s2) 0 0; }
.filled > div { display: grid; gap: 2px; padding: 0 0 var(--s1); border-bottom: 1px solid var(--line); }
.filled > div:last-child { border-bottom: 0; padding-bottom: 0; }
.filled dt { font-size: 0.85rem; font-weight: 600; color: var(--muted); }
.filled dd { margin: 0; font-weight: 600; overflow-wrap: anywhere; }

/* Quiet links under a screen: where the rest lives. */
.links { display: flex; flex-wrap: wrap; justify-content: center; gap: 0 var(--s1); margin: var(--s3) 0 0; }
.links a { display: inline-flex; align-items: center; min-height: var(--tap); padding: 0 12px; font-weight: 600; color: var(--muted); }
.stack { display: grid; gap: var(--s2); }
.stack > .card { margin: 0; }

@media (max-width: 399px) {
  /* A small phone: less air at the edges, the same sizes to tap. */
  .app { padding-left: calc(12px + env(safe-area-inset-left)); padding-right: calc(12px + env(safe-area-inset-right)); }
  .card { padding: var(--s2); }
  .mode a { padding: 0 12px; }
  .facts { gap: 4px; }
  .fact { padding: var(--s1); }
  .fact-value { font-size: 1.1rem; }
}

@media (min-width: 700px) {
  .sheet-grid { grid-template-columns: 1fr 1fr 1fr; }
}

@media (min-width: 1000px) {
  /* A desk screen: a wider column, still one a thumb-sized layout reads well in. */
  .app { max-width: 760px; }
  .action-bar > *, .sync-strip > * { max-width: 728px; }
  .install-slot { max-width: 760px; }
  .sheet-grid { grid-template-columns: repeat(4, 1fr); }
  .fields { grid-template-columns: repeat(4, 1fr); }
  /* The dashboard's tables have more columns than that column holds: on a desk screen it gets the room to show the
     margin beside the job without scrolling the table, and the two foams' charts side by side. The owner's home
     takes the same width: the number on the left, the week and what needs him on the right. */
  .app.wide { max-width: 960px; }
  .app.wide .dash-charts { grid-template-columns: 1fr 1fr; }
  .home-grid { display: grid; grid-template-columns: 5fr 6fr; gap: var(--s4); align-items: start; }
  .home-grid .hero { padding-top: var(--s4); }
}

/* The owner's tab bar (docs/SHELL-SCREENS.md, "The shell"): single-word tabs, 64px tall plus the phone's bottom
   safe area, fixed under every office screen. A tab only moves him. The current tab is a yellow fill, never a line. */
.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 6;
  padding: 0 env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  background: var(--card);
  border-top: 1px solid var(--line);
}
.tabbar[hidden] { display: none; }
.tabs { display: flex; max-width: 560px; height: var(--tabbar-h); margin: 0 auto; }
.tab {
  flex: 1;
  display: flex; align-items: center; justify-content: center;
  min-height: var(--tap-crew);
  color: var(--ink);
  font-weight: 700;
  text-decoration: none;
}
.tab[aria-current="page"] { background: var(--accent); color: var(--accent-ink); }

/* The footer and the action bar make room for the tab bar. */
body.has-tabs .app-footer { padding-bottom: calc(112px + var(--tabbar-h) + env(safe-area-inset-bottom)); }
body.has-tabs .action-bar { bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom)); padding-bottom: var(--s1); }

/* The quiet links at the foot of Jobs: what is set up once (profile, stock, rigs, settings). */
.jobs-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 var(--s1);
  margin: var(--s3) 0 var(--s1);
  padding: var(--s2) 0;
  border-top: 1px solid var(--line);
}
.jobs-links a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-crew);
  padding: 0 var(--s2);
  font-weight: 600;
  color: var(--muted);
}

/* Chat (docs/SHELL-SCREENS.md, 2). The page is the conversation, newest at the bottom, and it ends at the message
   box, which stays above the tab bar. The owner's words are navy bubbles on the right, the assistant's are white
   on the left. A draft is a card with one yellow button. Everything tapped here is 56px or more. */
body.chat-open .app { display: flex; flex-direction: column; min-height: 100dvh; padding-bottom: 0; }
body.chat-open.has-tabs .app { padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom)); }
body.chat-open .app-footer, body.chat-open .install-slot { display: none; }
.chat { flex: 1; display: flex; flex-direction: column; }
.chat-log { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; gap: var(--s1); padding-bottom: var(--s2); }
.chat-day, .draft-line { align-self: center; margin: var(--s1) 0 0; color: var(--muted); font-size: 0.85rem; font-weight: 600; text-align: center; }
.draft-line.with-button { display: flex; align-items: center; gap: var(--s2); }
.chat-older { align-self: center; }
.bubble { max-width: 88%; padding: var(--s1) var(--s2); border-radius: var(--radius); }
.bubble p { margin: 0; }
.bubble.assistant { align-self: flex-start; background: var(--card); border: 1px solid var(--line); }
.bubble.owner { align-self: flex-end; background: var(--bar); color: var(--bar-ink); }
.chat-words { white-space: pre-wrap; }
.chat-state, .chat-quiet { color: var(--bar-muted); font-size: 0.85rem; }
.chat-voice { display: flex; align-items: center; gap: var(--s1); }
.chat-length { font-weight: 700; font-variant-numeric: tabular-nums; }
.chat-play {
  display: grid; place-items: center;
  width: var(--tap-crew); height: var(--tap-crew); padding: 0;
  color: inherit; background: transparent;
  border: 1px solid var(--bar-muted); border-radius: 50%;
  cursor: pointer;
}
.chat-photo { display: block; max-width: 100%; max-height: 320px; margin: 4px 0; border-radius: var(--radius-control); }
.chat-again { margin-top: var(--s1); }

.card.draft { align-self: stretch; margin: 0; }
.draft-to { font-size: 1rem; }
.draft-words { padding: var(--s1) var(--s2); background: var(--well); border-radius: var(--radius-control); white-space: pre-wrap; }
.draft-reason { font-weight: 600; }
.draft-buttons { display: flex; gap: var(--s1); margin-top: var(--s2); }
.draft-buttons .btn { flex: 1; min-height: var(--tap-big); }
.draft-buttons .draft-main { flex: 2; }
.draft-line .btn, .chat-again, .chat-older, .chat-banner .btn, .chat-row .btn { min-height: var(--tap-crew); }

.chat-foot {
  position: sticky; bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom)); z-index: 4;
  padding: var(--s1) 0;
  background: var(--card);
  /* The box's ground carried to both edges of the screen, as the top bar's is. */
  border-image: conic-gradient(var(--card) 0 0) fill 0 // 0 100vmax;
}
body:not(.has-tabs) .chat-foot { bottom: env(safe-area-inset-bottom); }
.chat-lines:empty { display: none; }
.chat-line { margin: 0 0 var(--s1); color: var(--muted); font-size: 0.9rem; font-weight: 600; }
.chat-line.error { color: var(--err); }
.chat-banner { display: flex; align-items: center; justify-content: space-between; gap: var(--s1); padding-bottom: var(--s1); font-weight: 600; }
.chat-banner[hidden], .chat-box[hidden], .chat-recording[hidden] { display: none; }
.chat-row { display: flex; align-items: flex-end; gap: var(--s1); }
.chat-slot { display: flex; }
.chat-slot:empty { display: none; }
.chat-box { flex: 1; min-height: var(--tap-crew); max-height: 160px; padding: 14px var(--s2); border-width: 2px; border-radius: 28px; resize: none; }
.chat-recording { flex: 1; align-self: center; margin: 0; font-weight: 700; }
.chat-clock { font-variant-numeric: tabular-nums; }
.chat-tool {
  display: grid; place-items: center;
  min-width: var(--tap-crew); height: var(--tap-crew); padding: 0;
  font: inherit; font-weight: 700;
  color: var(--ink); background: var(--card);
  border: 2px solid var(--edge); border-radius: 28px;
  cursor: pointer; touch-action: manipulation;
}
.chat-tool.words { padding: 0 var(--s2); }
.chat-tool.main { background: var(--accent); border-color: var(--accent-line); color: var(--accent-ink); }
.chat-tool:focus-visible, .chat-play:focus-visible { outline: 2px solid var(--focus-edge); outline-offset: 3px; box-shadow: 0 0 0 3px var(--focus); }
.icon { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.icon-play, .icon-stop { fill: currentColor; stroke: none; }
