/* The approved portal design (UI_Designs/click-inspection-portal-mockup.html),
   as three static files with no build step and no framework — which is what
   keeps the hosting decision (brief §11.2) open.

   FONTS ARE THE SYSTEM STACK, not the mockup's Google Fonts. A portal that
   shows other clients' premises should not announce every page load to a third
   party, and a font that fails to load on a site with restricted egress must
   not take the layout with it. The type scale and weights follow the mockup. */

:root {
  --bg-main: #131519;
  --bg-card: #1c1f24;
  --bg-card-alt: #22262c;
  --border: #24282e;
  --text-primary: #ffffff;
  --text-secondary: #a0a3a8;
  --text-tertiary: #82858a;
  --flow: #35c77a;
  --flow-light: #1f3630;
  --copper: #e0a03a;
  --copper-light: #373127;
  --alert: #ff6b70;
  --sidebar-bg: #16181c;
  --sidebar-active: #22262c;
  /* ⚠ USED IN NINE PLACES AND NEVER DEFINED until 2026-09-09 — the search
     pill, the bell, the map's zoom control and the segmented buttons all
     said `background: var(--surface)` with NO FALLBACK, which is invalid
     at computed-value time and paints nothing. They were transparent
     boxes with a border, which is why the top bar read as unfinished. */
  --surface: #22262c;
  /* ⚠ REFERENCED IN FOUR PLACES AND NEVER DEFINED until 2026-09-10 — the same
     fault as `--surface` above, and with a worse symptom.

     `--ok` was written as `var(--ok, #4ade80)` in three rules, so every one of
     them was living off the FALLBACK. Harmless by luck: the fallback is a
     green and green is what those rules wanted.

     `--warn` never existed at all, and the chip that needed it said
     `var(--flow, #fbbf24)` — reaching for a token that DOES exist and is this
     product's GREEN. The fallback amber was therefore unreachable, and the one
     caller ("3 exceptions" on a condition group) rendered in the same green as
     its opposite ("✓ All as expected"). Measured on the palette validator the
     two were ΔE 6.7 apart in NORMAL vision — below the floor where a reader
     with full colour vision can separate them at all.

     `--ok` is declared as the colour those three rules already rendered, so
     defining it changes no pixel. ⚠ It is a DIFFERENT green from `--flow`
     (#35c77a) and that inconsistency is left alone deliberately: unifying them
     would repaint the type-box borders and the progress fill, which nobody
     asked for. Worth doing one day, on purpose. */
  --ok: #4ade80;
  --warn: var(--copper);
  --radius: 14px;
  --sans: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, 'Cascadia Mono', Consolas, monospace;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* `hidden` is a presentation-level default, so ANY class that sets `display`
   silently beats it. That is not theoretical: the sign-in pane sets
   `display:flex` to centre itself, and after signing in it stayed on the page
   underneath the dashboard — visible in the accessibility tree with
   `hidden === true`. The page hides panes by attribute, so the attribute wins. */
[hidden] { display: none !important; }

body {
  font-family: var(--sans);
  background: var(--bg-main);
  color: var(--text-primary);
  display: flex;
  min-height: 100vh;
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
}

/* ⚠ A FORM CONTROL DOES NOT INHERIT THE PAGE'S FONT, and this rule is the
   whole answer to "the fonts in the report box, those buttons, look different"
   (assessor, 2026-09-09). `button`, `input`, `select` and `textarea` are drawn
   by the browser in ITS font at ITS size unless told otherwise — on Windows
   that is a different face at about 13.3px next to this page's 14px system
   stack, which is close enough to look like a mistake rather than a choice.

   Most of this file's controls already said `font-family: inherit` one rule at
   a time; the ones that did not were the map's Map/Satellite pair, the kit
   filter chips, the route-planner boxes and the site-notes addendum. Said once
   here, so a control added tomorrow cannot miss it. */
button, input, select, textarea, optgroup { font-family: inherit; font-size: inherit; }

/* ⚠ NUMBERS ARE IN THE PAGE'S OWN FACE NOW, NOT A MONOSPACE ONE (assessor,
   2026-09-09: "the numbers appear to be different to the font which is used
   for the subtitles and the welcome and assessor's name — please change this
   to suit this font").

   `tabular-nums` is what is kept, and it is what the monospace face was
   actually being used FOR: it makes every digit the same width, so a column of
   figures still lines up and a count that ticks from 9 to 10 does not shift
   the text beside it. That is the whole benefit; the different letterforms
   were a side effect nobody asked for.

   `--mono` survives for the two things that genuinely are code — the device
   token box and `<code>` in an explanation — where a monospace face is telling
   the reader "this is a literal string, character for character". */
.mono { font-variant-numeric: tabular-nums; }

/* ⚠ THE PAGE IS DARK, AND THE BROWSER HAS TO BE TOLD (assessor, 2026-08-30:
   "the white background and black text field still show, keep all fields
   consistent in design").

   The previous pass styled every box a person types in and the boxes went grey
   — but a control has parts CSS cannot reach: the popup list a `<select>` opens,
   its `<option>` rows, the calendar a date input drops down, the scrollbars,
   the autofill highlight. Those are painted by the browser from `color-scheme`,
   which defaults to `normal` — meaning the operating system's light theme —
   so a grey box still opened a white list of black text.

   One declaration at the root turns all of them dark. It has to be here rather
   than on each control: `color-scheme` is what the browser reads for the
   scrollbars and the form-control chrome of the whole document. */
:root { color-scheme: dark; }

/* A TICK IS GREEN, EVERYWHERE (assessor, 2026-08-30: "Pre site checklist blue
   tick boxes change to same green colour").

   Green is this project's SELECTED state (2026-08-13) and has been since the
   answering screen was written; the browser's default accent is the operating
   system's blue, which on this page read as a second meaning nobody had
   defined. Stated once for every checkbox rather than per screen — the accept
   box on the answering screen already carried its own copy of this line, which
   is exactly how the checklist came to miss it. */
input[type='checkbox'], input[type='radio'] { accent-color: var(--flow); }

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

.sidebar {
  width: 264px;
  flex-shrink: 0;
  background: var(--sidebar-bg);
  padding: 22px 16px 16px;
  display: flex;
  flex-direction: column;
  height: 100vh;
  position: sticky;
  top: 0;
  border-right: 1px solid var(--border);
}

.brand { display: flex; align-items: center; gap: 10px; padding: 4px 6px 18px; }
/* ⚠ NO TILE BEHIND IT ANY MORE. The stand-in was a white bolt on a green
   gradient chip, which is what you draw when you have no logo. The real mark is
   line art with a glow of its own and a plate under it fights both — the flare
   loses its ground and the strokes gain a border they were not drawn with. */
.brand-mark {
  width: 34px; height: 34px; flex-shrink: 0; object-fit: contain;
}
.brand-name { font-weight: 600; font-size: 15.5px; line-height: 1.15; }
.brand-sub {
  font-size: 10.5px; color: var(--text-tertiary);
  letter-spacing: 0.04em; text-transform: uppercase; margin-top: 1px;
}

nav { flex: 1; overflow-y: auto; }
.nav-label {
  font-size: 10.5px; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--text-tertiary); padding: 14px 10px 7px;
  display: flex; align-items: center; justify-content: space-between;
}
.req-pill {
  font-size: 9px; padding: 1px 6px; border-radius: 20px;
  background: var(--copper); color: #0a0b0d; font-weight: 600;
}
.nav-item {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 8px 10px; border-radius: 9px; color: var(--text-secondary);
  font-size: 13px; cursor: pointer; border: none; background: transparent;
  width: 100%; text-align: left; font-family: inherit;
}
.nav-item:hover { color: var(--text-primary); background: #1a1d21; }
.nav-item.active { background: var(--sidebar-active); color: var(--text-primary); font-weight: 500; }
.nav-item .count {
  font-variant-numeric: tabular-nums; font-size: 11px; color: var(--text-tertiary);
}
/* A screen with nothing behind it is dimmed in the nav, not hidden: the
   design is the agreed shape of the product, and pretending a section does
   not exist would misrepresent it as much as filling it with invented rows. */
.nav-item.empty { color: var(--nav-empty, #5c5e62); }
.nav-item.empty:hover { color: var(--text-secondary); }

.sidebar-foot {
  display: flex; align-items: center; gap: 10px;
  padding-top: 14px; border-top: 1px solid var(--border);
}
.avatar {
  width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0;
  background: linear-gradient(155deg, #3a3f49, #22262c);
}
.who { flex: 1; min-width: 0; }
.who-name { font-size: 13px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Now carries the person, where a session has one. It can be long, so it wraps
   rather than pushing Password and Sign out off the end of the sidebar. */
.who-role {
  font-size: 10.5px; color: var(--text-tertiary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Two buttons where there was one; stacked, because side by side at this width
   they would each be three characters wide. */
.who-actions { display: flex; flex-direction: column; align-items: flex-end; flex: none; }
.who-actions .link { padding: 2px 0; white-space: nowrap; }

/* ---------- main ---------- */

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.pane.centred { flex: 1; display: flex; align-items: center; justify-content: center; padding: 24px; }

.topbar {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  padding: 26px 32px 18px;
}
.screen-title { font-size: 21px; font-weight: 600; letter-spacing: -0.01em; }
.screen-sub { font-size: 13px; color: var(--text-secondary); margin-top: 3px; }
/* `.pill` and `.pill.writes` were the top bar's surface chip and came out with
   it on 2026-09-09. `.req-pill` in the sidebar is a different rule and stays. */

/* The creation form. `.primary` matches the sign-in submit rather than
   inventing a second green: two greens on one page read as two meanings. */
.primary {
  padding: 9px 16px; border-radius: 10px; border: none;
  background: var(--flow); color: #0a0b0d; font-weight: 600; font-size: 13px;
  cursor: pointer; font-family: inherit;
}
.primary:disabled { opacity: .5; cursor: default; }

/* ⚠ `.secondary` WAS USED IN THREE PLACES AND NEVER DEFINED (found
   2026-09-09). The two bulk buttons on every condition group and the map's
   "Save this view as an image" carried it, so all three drew as the BROWSER'S
   DEFAULT BUTTON — a light grey chip with black text, in the middle of a dark
   page. That is most of what "these buttons look different" was about.

   Defined as the quiet pill the answering screen already used for "Not
   recorded" (`.seg`), because that is the shape the assessor pointed at:
   "designed like the not recorded button". `.seg` and `.secondary` are now
   deliberately the same thing under two names — one is a choice among
   answers, the other is an action, and they are told apart by where they sit
   rather than by colour. */
.secondary {
  padding: 7px 14px; border-radius: 9px; font-size: 13px; cursor: pointer;
  background: var(--bg-card-alt); color: var(--text-secondary);
  border: 1px solid var(--border); font-family: inherit; line-height: 1.2;
}
.secondary:hover:not(:disabled) { color: var(--text-primary); border-color: var(--text-tertiary); }
.secondary:disabled { opacity: .5; cursor: default; }
.secondary.on { border-color: var(--flow); color: var(--flow); }
.req-mark { color: var(--flow); }
/* A subheading inside a panel: the pre-site categories, and the site record's
   own groups on the correction screen. */
.presite-cat, .group-head {
  margin: 18px 0 6px; font-size: 12px; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-tertiary);
}
.presite-item {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 8px 0; border-top: 1px solid var(--border); cursor: pointer;
}
.presite-item input { margin-top: 3px; flex: none; }
.presite-title { flex: 1; font-size: 13px; color: var(--text-secondary); }
.form-actions { display: flex; gap: 12px; align-items: center; margin: 20px 0 40px; }

#screen { padding: 0 32px 40px; }

/* ---------- cards, tiles, tables ---------- */

.kpi-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px; margin-bottom: 22px;
}
.kpi-card {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 16px 18px;
}
.kpi-label {
  font-size: 11px; letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--text-tertiary);
}
.kpi-value { font-variant-numeric: tabular-nums; font-size: 27px; font-weight: 600; margin-top: 6px; }
.kpi-note { font-size: 11.5px; color: var(--text-secondary); margin-top: 4px; }

.panel {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius); margin-bottom: 18px; overflow: hidden;
}
.panel-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 15px 18px; border-bottom: 1px solid var(--border);
}
.panel-head h2 { font-size: 14px; font-weight: 600; }
.panel-body { padding: 16px 18px; }

/* ---------- a panel that folds (assessor, 2026-09-09) ----------
   Same box, with a hinge: `foldPanel` builds a <details> whose <summary>
   carries `.panel-head`, so a folding panel and a fixed one are indis-
   tinguishable until you click one. */
.fold-panel > .panel-head {
  cursor: pointer; list-style: none;
  /* The head's own bottom border belongs to the open state. Shut, the box is
     one bar and a rule under it would read as an empty body. */
  border-bottom: none;
}
.fold-panel[open] > .panel-head { border-bottom: 1px solid var(--border); }
.fold-panel > .panel-head::-webkit-details-marker { display: none; }
.fold-panel > .panel-head:hover .fold-caret { color: var(--flow); }
.fold-title { display: flex; align-items: center; gap: 10px; min-width: 0; }
/* A rotating chevron rather than the browser's triangle: the triangle is
   drawn in the operating system's colour and sits outside the padding. */
.fold-caret {
  display: inline-block; flex: none; width: 12px; text-align: center;
  color: var(--text-tertiary); font-size: 16px; line-height: 1;
  transform: rotate(0deg); transition: transform .12s ease-out;
}
.fold-panel[open] > .panel-head .fold-caret { transform: rotate(90deg); }

/* The next box to fill in (assessor 2026-09-11). Green on the TITLE TEXT and
   the caret — never a filled chip, because on this page a filled green chip
   means a finished state and this box has not been started. The mark is
   removed the moment the box is opened; see `markNextFold`. */
.fold-panel.fold-next > .panel-head h2 { color: var(--ok); }
.fold-panel.fold-next > .panel-head .fold-caret { color: var(--ok); }
@media (prefers-reduced-motion: no-preference) {
  /* One pulse, so a heading that changes colour below the fold is still
     noticed when the page scrolls to it. It settles on the colour rather than
     returning, because the hint has to persist until the box is opened. */
  .fold-panel.fold-next > .panel-head h2 { animation: fold-next-in 420ms ease-out; }
  @keyframes fold-next-in {
    from { opacity: 0.45; }
    to { opacity: 1; }
  }
}
/* The way back off a screen, on the same plate as Create inspection
   (assessor, 2026-09-09). It sits in its own row rather than inline, so the
   first panel below it does not read as something the button opens. */
.back-row { margin: 0 0 18px; }
.back-button { padding: 10px 18px; font-size: 13.5px; }

.fold-foot { margin: 18px 0 4px; }
.fold-head-right { display: flex; align-items: center; gap: 12px; flex: none; }
.fold-sterling { font-size: 12px; color: var(--text-tertiary); }
/* The default toggle reads as a STATE when it is on, not as a button to press
   again — so it takes the flow colour rather than the green plate. A filled
   green chip beside a fixed one would have looked like the primary action of
   the box, which it is not. */
.default-toggle { padding: 5px 12px; font-size: 12px; }
.default-toggle.on { border-color: var(--flow); color: var(--flow); background: var(--flow-light); }
.fold-note { margin: 0; }

table { width: 100%; border-collapse: collapse; }
th {
  text-align: left; font-size: 10.5px; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-tertiary);
  padding: 11px 18px; border-bottom: 1px solid var(--border); font-weight: 500;
}
td { padding: 13px 18px; border-bottom: 1px solid var(--border); font-size: 13px; vertical-align: top; }
tr:last-child td { border-bottom: none; }
tbody tr.clickable:hover { background: var(--bg-card-alt); cursor: pointer; }
td.num { font-variant-numeric: tabular-nums; }

/* A blank and a zero are different answers and must look different — the same
   rule the app follows. An em dash is "not recorded"; a 0 is a measurement. */
.blank { color: var(--blank-ink, #7a7d82); }

.tag {
  display: inline-block; font-size: 10.5px; padding: 3px 8px; border-radius: 20px;
  background: var(--bg-card-alt); color: var(--text-secondary); border: 1px solid var(--border);
}
.tag.ok { background: var(--flow-light); color: var(--flow); border-color: #245139; }
.tag.warn { background: var(--copper-light); color: var(--copper); border-color: #4a3d22; }
.tag.alert { background: #3a2326; color: var(--alert); border-color: #5c2f33; }

.derived {
  font-size: 11.5px; color: var(--text-tertiary); margin-top: 10px; line-height: 1.5;
}

/* An honest empty state. Says what is missing and what would fill it. */
.unbuilt { max-width: 640px; }
.unbuilt h3 { font-size: 15px; font-weight: 600; margin-bottom: 8px; }
.unbuilt p { font-size: 13px; color: var(--text-secondary); line-height: 1.6; margin-bottom: 10px; }
.unbuilt ul { margin: 0 0 10px 18px; font-size: 13px; color: var(--text-secondary); line-height: 1.7; }
.unbuilt code {
  font-family: var(--mono); font-size: 12px; background: var(--bg-card-alt);
  padding: 1px 5px; border-radius: 5px; color: var(--text-primary);
}

.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 18px; }

.kv { display: grid; grid-template-columns: 190px 1fr; gap: 8px 16px; font-size: 13px; }
.kv dt { color: var(--text-tertiary); }
.kv dd { color: var(--text-primary); }

.thumbs { display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: 10px; }
.thumb {
  border: 1px solid var(--border); border-radius: 10px; overflow: hidden;
  background: var(--bg-card-alt); aspect-ratio: 4 / 3; display: block;
}
.thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.thumb-missing {
  display: flex; align-items: center; justify-content: center; height: 100%;
  font-size: 11px; color: var(--text-tertiary); text-align: center; padding: 8px;
}

.section-text { font-size: 13px; line-height: 1.7; color: var(--text-secondary); white-space: pre-wrap; }

/* ---------- sign in ---------- */

.signin-card {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 30px; width: 100%; max-width: 420px;
}
.signin-card h1 { font-size: 19px; font-weight: 600; margin-bottom: 8px; }
/* The lockup, which replaced the heading that used to set the name in type.
   Centred in a block of its own so the card still reads as a card. */
.signin-logo { display: block; margin: 2px auto 20px; width: 188px; height: auto; }

/* THE SIGN-IN CARD'S THREE DOORS (2026-08-29). One credential per line, each
   with its label above it — a password form is the one place a bare box with a
   placeholder is not enough, because the placeholder disappears the moment
   somebody starts typing and half these fields look alike. */
.field-label {
  display: block; font-size: 11.5px; color: var(--text-secondary);
  margin: 12px 0 5px; letter-spacing: 0.01em;
}
.field-label:first-child { margin-top: 0; }
input[type='text'], input[type='password'] {
  width: 100%; padding: 11px 13px; border-radius: 10px;
  border: 1px solid var(--field-edge, #3a3f49); background: var(--bg-main);
  color: var(--text-primary); font-size: 13px; font-family: inherit;
}
/* The token is an opaque string rather than something anybody reads, so it
   keeps the monospace it always had. */
#token { font-family: var(--mono); }
.signin-alt {
  display: flex; flex-wrap: wrap; gap: 4px 16px;
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border);
}
.signin-alt .link { padding: 2px 0; }
.password-form { display: block; max-width: 340px; }
.password-form button { margin-top: 16px; }
.lede { font-size: 13px; color: var(--text-secondary); line-height: 1.6; margin-bottom: 18px; }
/* ⚠ THE PASSWORD RULE THAT USED TO LIVE HERE IS GONE, folded into the shared
   one above. It set `font-family: var(--mono)` because the only password box in
   the portal was a device token; leaving it would have put every password and
   the username that is now beside them into monospace, which reads as a
   credential to be transcribed rather than one to be remembered. The token box
   keeps it, by id. */
button[type='submit'] {
  margin-top: 12px; width: 100%; padding: 11px; border-radius: 10px; border: none;
  background: var(--flow); color: #0a0b0d; font-weight: 600; font-size: 13px;
  cursor: pointer; font-family: inherit;
}
.link {
  background: none; border: none; color: var(--text-secondary);
  font-size: 12px; cursor: pointer; padding: 4px; font-family: inherit;
}
.link:hover { color: var(--text-primary); }
.error { color: var(--alert); font-size: 12.5px; margin-top: 10px; }
.empty { color: var(--text-tertiary); font-size: 13px; }

@media (max-width: 860px) {
  body { display: block; }
  .sidebar { width: 100%; height: auto; position: static; border-right: none; border-bottom: 1px solid var(--border); }
  .topbar, #screen { padding-left: 18px; padding-right: 18px; }
}

/* The one action in the portal that produces a document. A link, not a
   button, because it opens a page — and a middle-click should work. */
.btn-open {
  display: inline-block; padding: 9px 14px; border-radius: 9px;
  background: var(--flow); color: #0a0b0d; font-weight: 600;
  font-size: 13px; text-decoration: none;
}
.btn-open:hover { filter: brightness(1.06); }

/* --- answering an asset ---------------------------------------------------
   Green is the SELECTED state throughout this project (2026-08-13), not a
   decoration, so it marks the chosen side of a Yes/No and nothing else. */

.asset-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.asset-head h3 { margin: 14px 0 6px; }

.q-row { padding: 14px 0; border-bottom: 1px solid var(--border); }
.q-row:last-child { border-bottom: none; }
.q-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.q-title { font-size: 13.5px; color: var(--text-primary); line-height: 1.45; }
.q-gid { font-size: 11px; color: var(--text-tertiary); white-space: nowrap; }
.q-hint { font-size: 12px; color: var(--text-tertiary); margin: 4px 0 0; }
/* What the export would send if this box stays empty (2026-09-09). In the
   caution colour rather than the flow colour, deliberately: it is a fallback
   that is about to be lodged, not a value anybody has confirmed. */
.q-carried {
  font-size: 12px; color: var(--text-tertiary); margin: 6px 0 0; line-height: 1.5;
}
.q-carried-value { color: var(--copper); font-weight: 600; }
.q-readonly { margin-top: 6px; font-size: 13px; color: var(--text-secondary); }

.q-control { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 8px; }

/* ONE LOOK FOR EVERY BOX A PERSON TYPES OR CHOOSES IN (assessor, 2026-08-30:
   "White question background fields not a good look, change to … a grey
   background and white text like other dropdown fields").

   The selects and textareas were styled and the plain `<input>`s were not, so
   a date, a time, a number and a lookup each fell back to the browser's own
   white-on-black-text control — on a dark screen, next to a grey dropdown
   asking the same kind of question. Written as ONE selector list rather than a
   rule per control precisely because that is how the inputs came to be missed:
   a new control type gets the look by sitting inside `.q-control`, not by
   somebody remembering to add a line here.

   ⚠ Checkboxes are excluded deliberately — a tick box has no background to
   grey and `accent-color` is what colours it (see the global rule above). */
.q-control textarea, .q-extra textarea, .q-control select,
.q-control input:not([type='checkbox']), .q-extra input:not([type='checkbox']) {
  width: 100%; background: var(--bg-card-alt); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: 9px; padding: 8px 10px;
  font-family: inherit; font-size: 13px; resize: vertical;
}
.q-control textarea:focus, .q-extra textarea:focus, .q-control select:focus,
.q-control input:focus, .q-extra input:focus {
  outline: none; border-color: var(--flow);
}
.q-control input::placeholder { color: var(--text-tertiary); opacity: .7; }

/* The date and time glyphs came from the per-control `color-scheme` that used
   to sit here. The root declaration above covers them and everything else the
   browser paints, so this is no longer needed. */

/* A DERIVED BOX IS NOT A BROKEN ONE. `valid_until` is disabled because the
   export computes it, so it must read as "filled in for you" rather than as a
   control that has failed: full-strength text, a flatter background, and the
   cursor a reader gets over a label rather than the "no" symbol. */
.q-control input:disabled {
  background: var(--bg-card); color: var(--text-primary);
  opacity: 1; cursor: default;
}
/* Three states, because "not recorded" is a different answer from "No" and
   the two must never be able to look alike. Every state carries a border of
   the same width, so selecting one costs no layout.

   ⚠ THE UNSELECTED BORDER IS VISIBLE RATHER THAN TRANSPARENT since 2026-09-09,
   and that is a correction rather than a change of mind: a second `.seg` rule
   340 lines down (the map's Map/Satellite container, now `.seg-group`) had
   been overriding this one with `border: 1px solid var(--border)` on every
   pill on the page. The look here is what was actually shipping; it is now
   what this rule says. */
.seg {
  padding: 7px 14px; border-radius: 9px; font-size: 13px; cursor: pointer;
  background: var(--bg-card-alt); color: var(--text-secondary);
  border: 1px solid var(--border); font-family: inherit; line-height: 1.2;
}
.seg:hover { color: var(--text-primary); }
/* Two ways into one set of records, above the panel they switch. */
/* ⚠ NO SIDE MARGIN. `#screen` already pads 32px, so `margin: 0 32px` put the
   tabs 64px in while every panel below them sat at 32 — a visible step down
   the left edge of the Projects screen since the day the Clients tab arrived. */
.tab-row { display: flex; gap: 8px; margin: 0 0 16px; }
.seg.on { border-color: var(--flow); color: var(--flow); }

.q-extras { margin-top: 8px; }
.q-extras summary {
  font-size: 12px; color: var(--text-tertiary); cursor: pointer; padding: 2px 0;
}
.q-extras summary:hover { color: var(--text-secondary); }
.q-extra { margin-top: 6px; }
.q-extra-label { display: block; font-size: 11.5px; color: var(--text-tertiary); margin-bottom: 3px; }

.q-foot {
  margin-top: 9px; display: flex; align-items: center; gap: 14px;
  flex-wrap: wrap; font-size: 12px; color: var(--text-tertiary);
}
.q-accept { display: flex; align-items: center; gap: 6px; cursor: pointer; }
.provenance { font-variant-numeric: tabular-nums; }

/* Saving must never be silent in either direction: a failed write that looked
   like a success is the worst thing this screen could do. */
.saved { margin-left: auto; font-size: 11.5px; }
.saved.pending { color: var(--text-tertiary); }
.saved.ok { color: var(--flow); }
.saved.failed { color: var(--alert); font-weight: 600; }

/* --- filing a document (official certificate, report, risk assessment) -----
   No drop zone and no progress bar. An upload here is one file chosen once,
   and the only states worth showing are the two that can go wrong: what is
   filed, and what a refusal said about the file. */

.doc-kind { padding: 14px 0; border-bottom: 1px solid var(--border); }
.doc-kind:last-child { border-bottom: none; }
.doc-kind:first-child { padding-top: 0; }
.doc-title { font-size: 13.5px; margin: 0 0 4px; color: var(--text-primary); }
.doc-blurb { font-size: 12.5px; color: var(--text-tertiary); margin: 0 0 10px; line-height: 1.5; }
.doc-none { font-size: 12.5px; color: var(--copper); margin: 0 0 10px; }

/* What the export refused, listed rather than summarised. Empty until the XML
   button is pressed and the assembly says no, so it takes no room otherwise. */
.action-refusal:not(:empty) { margin-top: 14px; }
.action-refusal ul { margin: 0 0 0 18px; font-size: 13px; line-height: 1.7; color: var(--text-secondary); }

.doc-file {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  padding: 8px 10px; margin-bottom: 6px; border-radius: 9px;
  background: var(--bg-card-alt);
}
.doc-name { color: var(--text-primary); font-size: 13px; text-decoration: none; }
a.doc-name:hover { color: var(--flow); }
.doc-meta {
  font-size: 11.5px; color: var(--text-tertiary);
  font-variant-numeric: tabular-nums; margin-left: auto;
}
.doc-choose { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 12.5px; color: var(--text-secondary); }
.doc-choose input[type='file'] { font-family: inherit; font-size: 12px; color: var(--text-tertiary); max-width: 100%; }
.doc-choose input[type='file']::file-selector-button {
  padding: 6px 12px; margin-right: 10px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--bg-card-alt); color: var(--text-primary); font-family: inherit;
  font-size: 12px; cursor: pointer;
}
.doc-choose input[type='file']::file-selector-button:hover { border-color: var(--flow); color: var(--flow); }

/* --- the assessor's own record (§9b.2) -------------------------------------
   A label, a box and a save state per line. No form, no Save button: the
   answering screen already established that a field saves as you leave it and
   says so, and a second convention for the same act would be a second thing to
   learn. */

.kv-edit {
  display: grid; grid-template-columns: 200px minmax(0, 1fr) auto;
  align-items: center; gap: 12px; padding: 7px 0;
}
.kv-label { font-size: 12.5px; color: var(--text-tertiary); }
.kv-input {
  width: 100%; padding: 8px 10px; border-radius: 9px;
  border: 1px solid var(--border); background: var(--bg-card-alt);
  color: var(--text-primary); font-family: inherit; font-size: 13px;
}
.kv-input:focus { outline: none; border-color: var(--flow); }
.kv-input::placeholder { color: var(--text-tertiary); opacity: .7; }
.kv-edit .saved { min-width: 60px; text-align: right; }

@media (max-width: 720px) {
  .kv-edit { grid-template-columns: 1fr; gap: 4px; }
  .kv-edit .saved { text-align: left; }
}

/* The accreditation strip. Copper while there is time to act, alert once the
   date has passed — the same two meanings those colours carry everywhere else
   in this portal. */
.banner {
  padding: 12px 16px; border-radius: 12px; margin-bottom: 16px;
  border: 1px solid var(--copper); background: var(--copper-light);
  color: var(--text-primary); font-size: 13px; line-height: 1.5;
}
.banner span { color: var(--text-secondary); }
.banner.lapsed { border-color: var(--alert); background: #35232a; }

/* --- answers that disagree (§9b.22) ----------------------------------------
   Both sides drawn in full and side by side. Not a diff: the assessor is
   choosing between two observations about a machine, and showing only what
   changed would be this portal's opinion about which half mattered. */

.sides { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 10px 0 4px; }
.side {
  padding: 12px 14px; border-radius: 12px;
  border: 1px solid var(--border); background: var(--bg-card-alt);
}
.side-head {
  font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-tertiary); margin-bottom: 6px;
}
.side-value { font-size: 15px; color: var(--text-primary); line-height: 1.4; }
.side-value.blank { color: var(--text-tertiary); font-style: italic; }
.side-note { font-size: 12.5px; color: var(--text-secondary); margin-top: 6px; line-height: 1.45; }
.side-meta { font-size: 11.5px; color: var(--text-tertiary); margin-top: 8px; }

/* The tile is a worklist, so it carries the alert colour the four states use
   for "somebody has to look at this". */
.kpi-card.alert { border-color: var(--alert); }
.kpi-card.clickable { cursor: pointer; }
.kpi-card.clickable:hover { border-color: var(--flow); }

@media (max-width: 720px) {
  .sides { grid-template-columns: 1fr; }
}

/* A corrected field on the site/inspection panels. The control is the
   answering screen's own row; only the save state is new, and it sits under
   the control rather than beside it because these rows are narrow. */
.panel-body > .q-row > .saved { display: block; margin-top: 6px; font-size: 11.5px; }

/* What this site pays for electricity (schema v39).

   THE TWO STATES ARE THE DOCUMENT'S OWN. Section 007 prints a reviewed
   assumption in its accent colour and an unreviewed one in a caution colour,
   and this panel is where somebody decides which the report will carry — so it
   shows the same two, in this design's palette rather than the document's. A
   band chosen from the site's own consumption is deliberately the CAUTION
   colour: a real improvement on the all-consumer average, and still not the
   rate the client is billed. */
.q-help {
  font-size: 11.5px; color: var(--text-tertiary); line-height: 1.5;
  margin-top: 6px; max-width: 62ch;
}
.cite {
  font-size: 11.5px; color: var(--text-tertiary); line-height: 1.55;
  margin-top: 6px; max-width: 78ch;
}
.tariff-set { color: var(--flow); font-size: 15px; }
.tariff-unset { color: var(--copper); font-size: 15px; }

/* The answering screen's standard-phrase pickers and lookup boxes (2026-08-29).

   ⚠ SINCE 2026-09-09 THE PICKER IS INSIDE THE FIELD, not under it (assessor:
   "this drop-down box needs to be in the note fields"). `.q-combo` draws the
   border and the background that the textarea used to draw for itself; the
   textarea goes transparent and borderless inside it, and the select sits
   flush along the bottom edge with one rule between them. The result is one
   box with a list attached, which is what the ask describes — and it is still
   a textarea, so a note the phrase bank does not hold can still be typed.

   The focus ring moves to the wrapper for the same reason: focusing the box
   should light the whole control, not a rectangle inside it. */
.q-combo {
  border: 1px solid var(--border); border-radius: 9px;
  background: var(--bg-card-alt); overflow: hidden;
}
.q-combo:focus-within { border-color: var(--flow); }
.q-combo textarea {
  display: block; width: 100%; border: 0; background: none; border-radius: 0;
  padding: 8px 10px; color: var(--text-primary); font-size: 13px;
  line-height: 1.5; resize: vertical;
}
.q-combo textarea:focus { outline: none; }
.q-combo textarea::placeholder { color: var(--text-tertiary); opacity: .7; }
.q-phrase {
  display: block; width: 100%; font-size: 12px; margin: 0;
  padding: 7px 10px; border: 0; border-top: 1px solid var(--border);
  border-radius: 0; background: var(--bg-card);
  color: var(--text-secondary); cursor: pointer;
}
.q-phrase:hover:not(:disabled) { color: var(--text-primary); }
/* Still in place, not hidden — see the note beside `sync()`: a control that
   disappears when the question is unanswered makes the row jump as it is
   answered, on a screen the assessor already called overwhelming. */
.q-phrase:disabled { opacity: .55; cursor: default; }
.q-lookup { width: 100%; }

/* "All as expected" / "All as exception" at the head of a condition group. */
.bulk-bar {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  padding: 0 0 14px; margin-bottom: 6px;
  border-bottom: 1px solid var(--border);
}
.bulk-bar .saved { font-size: 12px; }

/* Condition groups, collapsed (assessor 2026-08-29: the screen was
   "very overwhelming"). One row per group with a status chip; the questions
   are behind it. */
.section-lead {
  margin: 22px 0 10px; font-size: 12px; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-tertiary); max-width: 62ch;
}
.cond-group {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; margin-bottom: 10px;
}
.cond-head {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 18px 20px; cursor: pointer; list-style: none;
}
.cond-head::-webkit-details-marker { display: none; }
.cond-label { font-size: 16px; font-weight: 650; color: var(--text-primary); }
.cond-group[open] .cond-head { border-bottom: 1px solid var(--border); }
.cond-body { padding: 16px 20px 4px; }

/* --- the totals across the top of an inspection (assessor 2026-08-30) ------
   Seven figures, and they are NOT all the same kind of number. Three are sums
   of what was observed, one is derived from two of those, two are modelled by
   the Asset Management engine, and one is not captured at all. The basis is
   printed on every tile because a modelled cost set in the same type as a
   measured charge is how an estimate becomes a quoted figure in somebody
   else's document. Colour carries none of that meaning on its own — the word
   is always there. */
.totals-slot:empty { display: none; }
.totals { margin-bottom: 20px; }
.totals-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px;
}
.total {
  display: flex; flex-direction: column; gap: 6px; padding: 16px 18px;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: 12px;
}
.total-label {
  font-size: 11.5px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-tertiary);
}
.total-value {
  font-variant-numeric: tabular-nums; font-size: 24px; font-weight: 600; line-height: 1.1;
  color: var(--text-primary);
}
/* A missing figure is an em dash in TERTIARY, never a zero and never the same
   weight as a real one. The sentence beneath it says why. */
.total-value.none { color: var(--text-tertiary); font-weight: 500; }
.total-unit { font-size: 13px; font-weight: 500; color: var(--text-secondary); }
.total-basis {
  align-self: flex-start; font-size: 10.5px; letter-spacing: .05em;
  text-transform: uppercase; padding: 2px 7px; border-radius: 20px;
  border: 1px solid var(--border); color: var(--text-tertiary);
}
.basis-observed { color: var(--flow); border-color: #245139; background: var(--flow-light); }
.basis-derived  { color: var(--text-secondary); }
.basis-modelled { color: var(--copper); border-color: #4a3d22; background: var(--copper-light); }
.total-why { font-size: 11.5px; color: var(--text-tertiary); line-height: 1.5; }

/* --- a recommendation, on the report-assembly screen ----------------------- */
.rec { padding: 14px 0; border-bottom: 1px solid var(--border); }
.rec:last-child { border-bottom: none; }
.rec-text { font-size: 13.5px; line-height: 1.55; color: var(--text-primary); }
.rec-meta { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 8px; }
.rec-meta-cell { display: flex; gap: 6px; font-size: 11.5px; }
.rec-meta-label { color: var(--text-tertiary); }
.rec-meta-value { color: var(--text-secondary); }

/* THE CARDS ARE EDITABLE NOW (assessor ruling, 2026-08-31), so a `.rec` holds
   `.q-row`s. The save chip is placed the way the site screen places it:
   `.saved` positions itself with `margin-left: auto`, which needs a flex parent
   and `.q-row` is not one, so left alone it sits jammed against the box it
   belongs to. Same rule as `.panel-body > .q-row > .saved`, one level deeper. */
.rec > .q-row > .saved { display: block; margin-top: 6px; font-size: 11.5px; }

/* An executive summary is paragraphs, so the box is tall enough to read one in
   before scrolling. `resize: vertical` comes from `.q-control textarea`, so
   somebody writing a long section can pull it further down. */
.q-prose { min-height: 96px; line-height: 1.6; }

/* THE REVIEW GATE, set apart from the wording boxes on purpose: every other
   control on the card edits a draft, and this one decides what is lodged. */
.accept-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 10px 0 4px;
}

/* Generate, in the panel head beside the title — the slot `panel(title, right)`
   already offers, and where the "All inspections" link sits on the dashboard. */
.panel-action { display: flex; align-items: center; gap: 10px; }
.panel-action .saved { margin-left: 0; }

/* --- the map (brief §9b.5) -------------------------------------------------
   Leaflet's own stylesheet is vendored and loaded first; everything here is
   this portal's chrome around it. */
.map-holder { margin-bottom: 12px; }
.map-canvas {
  height: 420px; width: 100%; border-radius: 12px;
  border: 1px solid var(--border); overflow: hidden;
  /* Leaflet paints tiles onto a transparent container; without a ground of our
     own the gaps between tiles show the page through them. */
  background: var(--bg-card-alt);
}

/* THE DASHBOARD'S MAP. Short enough to sit beside Current inspection without
   pushing Tasks off the first screen, tall enough that two pins thirty
   kilometres apart are still two pins. */
.map-canvas.compact { height: 240px; }
/* The legend sits in a slot of its own in that panel, filled in after the
   fetch, so it is styled through the slot rather than as a sibling of a canvas
   it is not a sibling of. */
.map-legend-slot .map-legend { margin: 10px 0 6px; }
/* Leaflet's controls and attribution are light-themed by default, which on this
   screen is a white box in the corner of a dark map. */
.map-canvas .leaflet-control-attribution {
  background: rgba(19, 21, 25, .82); color: var(--text-tertiary); font-size: 11px;
}
.map-canvas .leaflet-control-attribution a { color: var(--text-secondary); }
.map-canvas .leaflet-bar a {
  background: var(--bg-card-alt); color: var(--text-primary); border-color: var(--border);
}
.map-canvas .leaflet-bar a:hover { background: var(--surface); }
.map-canvas .leaflet-tooltip {
  background: var(--surface); color: var(--text-primary);
  border: 1px solid var(--border); box-shadow: none;
}

/* A refused tile set, said once. Amber rather than red: the configuration is
   wrong, the survey data is not. */
.map-tile-error {
  margin: 8px 0 0; padding: 9px 12px; font-size: 12px; line-height: 1.5;
  color: var(--flow); background: var(--copper-light);
  border: 1px solid #4a3d22; border-radius: 9px;
}

.map-legend { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-bottom: 10px; }
.map-legend-item { display: flex; align-items: center; gap: 7px; font-size: 11.5px; color: var(--text-secondary); }
.map-dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }

.map-list { display: flex; flex-direction: column; }
.map-row {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 0; border-bottom: 1px solid var(--border);
}
.map-row:last-child { border-bottom: none; }
.map-row .map-dot { margin-top: 5px; }
.map-row-body { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.map-row-name { text-align: left; padding: 0; font-size: 13.5px; }
.map-row-where { font-size: 11.5px; color: var(--text-tertiary); }
/* Why a site is not on the map. Amber rather than red: an address that would
   not resolve is a thing to correct, not a fault. */
.map-row-why { font-size: 11.5px; color: var(--flow); }
.map-row-go { flex: none; font-size: 12px; }
.map-note { font-size: 11.5px; color: var(--text-tertiary); }

/* --- the map's own toolbar (assessor 2026-09-07) --------------------------
   Above the canvas rather than floating on it: this strip carries the layer
   choice and the export, and both are decisions about the picture rather than
   controls for moving around inside it. Leaflet's corner is for panning. */
.map-tools {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 10px;
}
.map-tools .map-note { flex: 1 1 200px; min-width: 0; }

/* A segmented pair. One control with two states, so it cannot read as two
   buttons of which both might be pressed. */
/* ⚠ RENAMED FROM `.seg` ON 2026-09-09. This is the map's Map/Satellite
   CONTAINER, and it shared a class name with the pill button 340 lines above
   — so `display: inline-flex`, a visible border and `overflow: hidden` were
   landing on every Yes / No / Not recorded segment and every tab on the page.
   Two different things must not answer to one selector. */
.seg-group { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.seg-btn {
  font-size: 12.5px; padding: 6px 14px; border: none; cursor: pointer;
  background: var(--bg-card-alt); color: var(--text-secondary);
}
.seg-btn + .seg-btn { border-left: 1px solid var(--border); }
.seg-btn:hover { color: var(--text-primary); }
.seg-btn.on { background: var(--surface); color: var(--flow); }

/* --- the day route (assessor 2026-09-06, decided 2026-09-07) -------------- */
.route-controls { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }

/* --- System Information (assessor, 2026-09-09) --------------------------- */
.sysinfo-box { flex: 1 1 320px; }
.sysinfo-out { margin-top: 4px; }
/* The results take a panel of their own so the table gets its own ground and
   its own rounded edge, rather than running to the edge of the search box. */
.sysinfo-results { margin: 12px 0 0; }
.sysinfo-hit { margin-left: 8px; }
/* The caveats are prose about the table above them, so they read at prose
   width rather than at table width. */
.sysinfo-caveats { margin-top: 18px; }
.sysinfo-caveats .q-help { max-width: 78ch; margin-top: 8px; }
.sysinfo-caveats strong { color: var(--text-secondary); }
.route-day, .route-start {
  font: inherit; font-size: 13px; padding: 7px 10px; border-radius: 8px;
  background: var(--bg-card-alt); color: var(--text-primary); border: 1px solid var(--border);
}
.route-start { flex: 1 1 140px; min-width: 0; }
.route-list { list-style: decimal; margin: 0; padding-left: 22px; }
.route-leg {
  display: flex; align-items: baseline; gap: 10px;
  padding: 9px 0; border-bottom: 1px solid var(--border);
}
.route-leg:last-child { border-bottom: none; }
.route-name { font-size: 13.5px; color: var(--text-primary); }
.route-address { flex: 1; min-width: 0; font-size: 11.5px; color: var(--text-tertiary); }
/* Tabular figures so a column of distances lines up on the decimal point —
   a list of legs is read down, not across. */
.route-miles {
  flex: none; font-size: 12.5px; color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.route-total { margin: 12px 0 4px; font-size: 13px; color: var(--text-secondary); }
.route-total strong { color: var(--text-primary); }

/* --- the site notes (assessor 2026-09-07) --------------------------------- */
.sn-label { font-size: 12.5px; color: var(--text-secondary); align-self: center; }
.sn-addendum {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 13px; line-height: 1.5;
  padding: 9px 11px; border-radius: 8px; margin: 4px 0 10px; resize: vertical;
  background: var(--bg-card-alt); color: var(--text-primary); border: 1px solid var(--border);
}
.sn-sign-wrap { margin-top: 18px; padding-top: 4px; border-top: 1px solid var(--border); }
/* ⚠ WHITE, ALWAYS, IN A DARK PORTAL. The pad is a piece of paper: the mark is
   drawn dark on white because that is what lands in the document, and a pad
   that matched the surrounding theme would have somebody signing in a colour
   the printed page cannot show. `touch-action: none` is what lets a finger
   draw on it instead of scrolling the page underneath. */
.sn-pad {
  display: block; width: 100%; max-width: 600px; height: 180px;
  background: #fff; border: 1px solid var(--border); border-radius: 8px;
  touch-action: none; cursor: crosshair; margin-bottom: 10px;
}

@media (max-width: 720px) {
  .map-canvas { height: 300px; }
  .map-canvas.compact { height: 220px; }
  .map-row { flex-wrap: wrap; }
  .route-leg { flex-wrap: wrap; }
}

/* THE LIBRARY PICKER'S KIT FILTER (assessor, 2026-08-31: the recommendations
   should match the app's "dropdown lists, filters, equipment"). Chips rather
   than a select, as on the phone: five options that are read at a glance and
   switched often, where a dropdown would hide four of them behind a click. */
/* ⚠ RENAMED FROM `.kit-row` ON 2026-09-09. This is the row of FILTER CHIPS
   above the recommendation library; sixty lines below, `.kit-row` is the
   tappable equipment row. Two unrelated things answered to one selector and
   the second definition won, so this rule's `flex-wrap` and margin were being
   applied to every equipment row and its own chips got none of it. */
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 14px; }
.kit-chip {
  font-size: 12.5px; padding: 6px 12px; border-radius: 999px;
  background: var(--bg-card-alt); color: var(--text-secondary);
  border: 1px solid var(--border); cursor: pointer;
}
.kit-chip:hover { color: var(--text-primary); }
.kit-chip.on { border-color: var(--flow); color: var(--flow); }

.library-lists { display: flex; flex-direction: column; }
.library > .saved { margin: 6px 0 0; }

/* The saved sets, above the lists they are a shortcut past. */
.template-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 14px;
}
.template-bar select {
  background: var(--bg-card-alt); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: 9px; padding: 8px 10px;
  font-family: inherit; font-size: 13px; min-width: 240px;
}
.template-bar .derived { flex-basis: 100%; margin: 0; }

/* The chip says whether the group needs opening. */
.chip {
  font-size: 13px; font-weight: 600; white-space: nowrap;
  padding: 6px 12px; border-radius: 999px;
}
/* ⚠ EACH TINT IS MIXED FROM THE CHIP'S OWN COLOUR rather than hard-coded as an
   rgba() beside it. That is how the warn chip came to disagree with itself: its
   background was amber at 14% and its text was green, and nothing tied the two
   together so nothing caught it.

   ⚠ AND THE COLOUR IS NEVER THE ONLY DIFFERENCE. Green vs amber is the hardest
   pair there is for deuteranopia — the validator puts these at ΔE 7.2, inside
   the band where colour is permitted ONLY alongside a second encoding — so
   every chip carries its own words: "✓ All as expected", "3 exceptions",
   "5 to answer". Do not reduce one of these to a coloured dot. */
.chip.ok   { color: var(--ok);    background: color-mix(in srgb, var(--ok) 13%, transparent); }
.chip.warn { color: var(--warn);  background: color-mix(in srgb, var(--warn) 16%, transparent); }
.chip.bad  { color: var(--alert); background: color-mix(in srgb, var(--alert) 15%, transparent); }
.chip.todo { color: var(--text-tertiary); background: rgba(148, 163, 184, .12); }

/* The four equipment types as BOXES (assessor 2026-08-29), with the selected
   one listing its assets underneath — the app's own Zone screen. */
.type-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px; margin-bottom: 20px;
}
.type-box {
  display: flex; flex-direction: column; gap: 8px; align-items: flex-start;
  padding: 22px 20px; min-height: 96px; cursor: pointer; text-align: left;
  background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
  color: inherit;
}
.type-box:hover { border-color: var(--text-tertiary); }
/* The selected one, as the app marks it. */
.type-box.on { border-color: var(--ok); box-shadow: inset 0 0 0 1px var(--ok); }
.type-name { font-size: 15px; font-weight: 650; color: var(--text-primary); }
.type-count { font-size: 26px; font-weight: 700; color: var(--text-primary); line-height: 1; }
.type-count.none { font-size: 15px; font-weight: 500; color: var(--text-tertiary); }
/* WHAT THE TAP WILL DO. Since 2026-09-09 every box does the same thing — it
   lists its units below — so this line says how many there are to choose from
   rather than which of two behaviours is about to happen. See the note beside
   the click handler for why the one-unit shortcut came out. */
.type-does { font-size: 12px; color: var(--text-tertiary); }
.type-box:hover .type-does { color: var(--text-secondary); }
/* The app's own drawing of the kind of unit (assessor, 2026-09-28), rendered
   from its components — see `unitArt` in app.js. */
.type-art {
  width: 100%; max-width: 132px; height: auto; aspect-ratio: 380 / 268;
  align-self: center; pointer-events: none;
}
/* The Sub-System box has no machine to draw, so it keeps a drawing's space
   empty: every name in the row then starts at the same height. */
.type-art-none { display: block; }
.type-assets { min-height: 40px; }

.kit-row {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  width: 100%; padding: 13px 2px; background: none; border: 0;
  border-bottom: 1px solid var(--border); cursor: pointer; text-align: left;
}
.kit-row:hover { background: rgba(148, 163, 184, .06); }
/* The condition photograph on an equipment row (assessor, 2026-09-09). Fixed
   box and `object-fit: cover`, so a portrait shot and a landscape one make the
   same shape and the list does not step in and out as it scrolls. */
.kit-row-shot {
  width: 62px; height: 46px; flex: none; border-radius: 8px;
  object-fit: cover; display: block; background: var(--bg-card-alt);
  border: 1px solid var(--border);
}
/* The same footprint when there is no picture, so a list with one photograph
   in it does not have one row indented further than the rest. */
.kit-row-shot-none {
  display: flex; align-items: center; justify-content: center;
  color: var(--text-tertiary); font-size: 15px;
}
/* ⚠ `flex: 1` SINCE THE THUMBNAIL ARRIVED (2026-09-09). `.kit-row` is
   `justify-content: space-between`, which with two children put the text hard
   left and the chevron hard right. A third child — the photograph — turned
   that into three evenly spread items, so the unit's name drifted into the
   middle of the row. The text takes the slack instead. */
.kit-row-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.kit-row-name { font-size: 14px; color: var(--text-primary); }
.kit-row-sub { font-size: 12px; color: var(--text-tertiary); }
.kit-row-go { font-size: 20px; color: var(--text-tertiary); flex: none; }
.kit-empty { font-size: 13px; color: var(--text-tertiary); padding: 10px 2px 0; }

/* --- the walk-round, in the equipment box (assessor, 2026-09-09) ----------
   A candidate is NOT a tappable row: there are no answers behind it until the
   inspector promotes it on site. So it takes the same shape as an asset row
   and none of its affordances — no pointer, no hover, no chevron — and
   carries a tag saying what it is. Looking clickable and doing nothing is the
   one thing this row must not do. */
.candidate-row { cursor: default; align-items: flex-start; }
.candidate-row:hover { background: none; }
.candidate-row .kit-row-shot-none { margin-top: 2px; }
.candidate-plate { margin-top: 6px; gap: 4px 14px; }
.candidate-tag { flex: none; align-self: center; }
/* The way a candidate becomes answerable. Quiet rather than green: it is one
   row's action, not the point of the screen, and a plate of green on every
   waiting unit would drown the list it sits in. */
.candidate-add { flex: none; align-self: center; padding: 6px 12px; font-size: 12px; }
/* A borrowed name, marked as borrowed. Quiet: it is a caveat on the row's
   title, not a status of the machine. */
.kit-row-borrowed {
  margin-left: 8px; font-size: 11px; color: var(--text-tertiary);
  border: 1px solid var(--border); border-radius: 999px; padding: 1px 7px;
}

/* The Add button sits under whatever the list holds, with its note beneath —
   including under an empty list, where it is the only thing on offer. */
.add-candidate { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); }
.add-candidate .derived { margin: 8px 0 0; max-width: 68ch; }

/* --- the dashboard, to the assessor's wireframe (2026-08-29) -------------- */

/* Date · who · one live fact. No weather: there is no provider for it. */
.greeting {
  display: flex; gap: 28px; align-items: center; flex-wrap: wrap;
  margin: 0 32px 20px; padding: 14px 20px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
}
/* Larger (assessor, 2026-09-28: "make the greeting and date tile font
   larger") — the greeting reads as a heading now, the date beside it. */
.greet-date { font-size: 17px; font-weight: 600; color: var(--text-secondary); }
.greet-who  { font-size: 22px; font-weight: 700; color: var(--text-primary); }
.greet-meta { font-size: 14px; color: var(--text-tertiary); margin-left: auto; }

/* Current inspection and the Map, side by side; they stack when it is tight.
   THE TWO ARE ONE HEIGHT (assessor 2026-09-04: *"In the portal dashboard size
   the current inspection box the same as the map"*). They were `align-items:
   start`, so each took its natural height and the pair sat as two boxes with
   a ragged foot — which reads as one panel being unfinished rather than as
   one panel having less to say. Stretching is done here and not with a fixed
   height, because the map's own canvas is what sets the height and the other
   panel should follow it wherever it goes. */
.dash-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 18px; align-items: stretch;
  /* ⚠ THE GRID CARRIED NO BOTTOM MARGIN AND ITS CHILDREN HAD THEIRS ZEROED
     (assessor, 2026-09-09: "needs a clear space between those and the
     Calendar below"). `.panel` has `margin-bottom: 18px`, but the rule below
     sets it to 0 inside the grid so the two boxes align — which also removed
     the gap between the grid and whatever followed it, so the calendar sat
     flush against the pair above. The space belongs to the grid, not to the
     panels inside it. */
  margin-bottom: 26px;
}
.dash-grid > .panel { display: flex; flex-direction: column; margin-bottom: 0; }
.dash-grid > .panel > .panel-body { flex: 1; display: flex; flex-direction: column; }
/* The closing note sits on the floor of the taller box rather than leaving a
   gap under it. `auto` on the top margin, so it only moves when there IS
   slack. */
.dash-grid > .panel > .panel-body > :last-child { margin-bottom: 0; }
.dash-grid .panel-body > .derived:last-child { margin-top: auto; padding-top: 12px; }
.current-site { margin: 0 0 12px; font-size: 18px; color: var(--text-primary); }
/* Open this inspection sat directly under "Last synced" with nothing between
   them (assessor, 2026-09-09) — a definition list has no bottom margin of its
   own, so the button read as one more row of the table above it. */
.current-facts { margin-bottom: 18px; }

/* One task: a dot, a line, and what to do about it. */
.task {
  display: flex; flex-direction: column; gap: 4px; width: 100%;
  padding: 12px 2px; text-align: left; background: none; border: 0;
  border-bottom: 1px solid var(--border);
}
.task.clickable { cursor: pointer; }
.task.clickable:hover { background: rgba(148, 163, 184, .06); }
.task-line { display: flex; align-items: center; gap: 10px; }
.task-text { font-size: 14px; color: var(--text-primary); }
.task-detail { font-size: 12px; color: var(--text-tertiary); padding-left: 20px; }
.dot {
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--text-tertiary);
}
/* ⚠ THE SAME FAULT `.chip.warn` HAD, and worse here: this dot is an EMPTY span
   (`el('span', 'dot warn', '')`), so its colour is the only thing it carries.
   Rendered green it said "fine" about a task flagged as needing attention.
   It is only legitimate at all because the task's own words sit beside it —
   that text is the second encoding, so do not use this dot on its own. */
.dot.warn { background: var(--warn); }

/* --- the calendar (assessor 2026-09-04) ------------------------------------
   It replaced the Tasks panel and keeps its full width: a month is seven
   columns, and at half width the cells are too small to hit on a laptop
   trackpad. */
.cal-nav { display: flex; align-items: center; gap: 10px; }
.cal-month { font-size: 13px; color: var(--text-secondary); min-width: 118px; text-align: center; }
.cal-step {
  width: 26px; height: 26px; border-radius: 8px; cursor: pointer;
  background: var(--bg-card-alt); color: var(--text-secondary);
  border: 1px solid var(--border); font-family: inherit; font-size: 14px; line-height: 1;
}
.cal-step:hover { color: var(--text-primary); }

.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.cal-dow {
  font-size: 10.5px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-tertiary); text-align: center; padding-bottom: 4px;
}
.cal-pad { min-height: 46px; }
.cal-day {
  position: relative; min-height: 46px; padding: 6px 8px; cursor: pointer;
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  background: var(--bg-card-alt); border: 1px solid transparent; border-radius: 9px;
  color: var(--text-secondary); font-family: inherit;
}
.cal-day:hover { color: var(--text-primary); border-color: var(--border); }
.cal-num { font-size: 12.5px; }
/* TODAY IS AN OUTLINE, A BOOKED DAY IS A COUNT, AND A SELECTED DAY IS THE
   FLOW COLOUR. Three different facts, so three different marks — a day can be
   all three at once and each has to still be readable. */
.cal-day.today { border-color: var(--text-tertiary); }
.cal-day.today .cal-num { color: var(--text-primary); font-weight: 650; }
.cal-day.on { border-color: var(--flow); color: var(--flow); }
.cal-count {
  min-width: 17px; height: 17px; padding: 0 5px; border-radius: 999px;
  font-size: 11px; line-height: 17px; text-align: center;
  background: rgba(148, 163, 184, .16); color: var(--text-secondary);
}
/* Ahead of today is what the panel is FOR, so those days carry the accent. */
/* ⚠ ITS TEXT AND ITS OWN BACKGROUND USED TO DISAGREE — an amber ground with
   green type, from the same `var(--flow, #fbbf24)` fault as the chip. Both come
   off one token now so they cannot drift apart again.

   `--copper` RATHER THAN `--warn`, though today they are the same colour. A day
   ahead with work booked is a HIGHLIGHT, not a warning, and naming it `--warn`
   would tie an ordinary accent to the warning token — so the day somebody
   changes what a warning looks like, the calendar would change with it for no
   reason. */
.cal-day.ahead .cal-count {
  background: color-mix(in srgb, var(--copper) 18%, transparent);
  color: var(--copper);
}

.cal-chosen { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); }
.cal-chosen-head { font-size: 14px; font-weight: 650; margin-bottom: 8px; }
.cal-row {
  display: flex; flex-direction: column; gap: 3px; width: 100%;
  padding: 9px 2px; text-align: left; background: none; border: 0; cursor: pointer;
  border-bottom: 1px solid var(--border); font-family: inherit;
}
.cal-row:hover { background: rgba(148, 163, 184, .06); }
.cal-row-name { font-size: 14px; color: var(--text-primary); }
.cal-row-meta { font-size: 12px; color: var(--text-tertiary); }
.cal-chosen .primary { margin-top: 12px; }

/* The bell's list, folded away. Closed unless it is opened — see
   `waitingBlock` for why it is here at all. */
.waiting { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); }
.waiting > summary {
  font-size: 12.5px; color: var(--text-secondary); cursor: pointer; padding: 2px 0;
}
.waiting > summary:hover { color: var(--text-primary); }

/* Search and the bell, in the top bar.

   ⚠ `.top-actions` HAD NEVER BEEN STYLED, which is the whole of why the bell
   sat under the search box (assessor, 2026-09-09). A `<div>` is a block, so
   its three children — search, bell, surface pill — each took a line of their
   own down the right-hand side. One row, baseline-aligned, wrapping only if
   the window is genuinely too narrow. */
.top-actions { display: flex; align-items: center; justify-content: flex-end; gap: 10px; flex-wrap: wrap; }

.search {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 12px; border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface); color: var(--text-tertiary);
}
.search svg { width: 15px; height: 15px; flex: none; }
.search input {
  border: 0; background: none; outline: none; width: 170px;
  color: var(--text-primary); font-size: 13px;
}
.search input::placeholder { color: var(--text-tertiary); }
.bell {
  position: relative; display: flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--border); background: var(--surface);
  color: var(--text-secondary); cursor: pointer;
}
.bell:hover { color: var(--text-primary); }
.bell svg { width: 17px; height: 17px; }
.bell-count {
  position: absolute; top: -5px; right: -5px; min-width: 17px; height: 17px;
  padding: 0 4px; border-radius: 999px; background: var(--flow);
  color: #0A0B0D; font-size: 11px; font-weight: 700; line-height: 17px;
  text-align: center;
}

/* --- the inspection hub (assessor's wireframes, 2026-08-29) --------------- */

/* Four segments, one per section, each counting its own rows. There is no
   blended score: see `progressBar`. */
.progress { margin: 4px 0 22px; }
.progress-bar { display: flex; gap: 4px; height: 10px; }
.progress-seg {
  flex: 1; background: rgba(148, 163, 184, .14);
  border-radius: 999px; overflow: hidden;
}
.progress-fill { height: 100%; background: var(--flow); border-radius: 999px; }
.progress-fill.done { background: var(--ok); }
.progress-legend {
  display: flex; gap: 4px; margin-top: 8px;
}
.progress-item {
  flex: 1; display: flex; justify-content: space-between; gap: 8px;
  font-size: 12px; color: var(--text-tertiary);
}
.progress-num { color: var(--text-secondary); }

/* The tiles the wireframe is built from. */
/* ⚠ TWO COLUMNS, STATED (assessor, 2026-08-31: the four section tiles "side by
   side"). It was `repeat(auto-fit, minmax(240px, 1fr))`, which decides the
   column count from the width available — fine while three of the five tiles
   were full-width and only two ever shared a row, and wrong the moment four
   equal tiles have to pair up: on a wide screen auto-fit would put all four on
   ONE row of four, and at some in-between width three on one row and one
   orphaned below. Neither is "side by side" in pairs.

   One column below 720px, where two 240px tiles plus the gap stop fitting. */
.tile-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px; margin-bottom: 16px;
}
@media (max-width: 720px) {
  .tile-grid { grid-template-columns: minmax(0, 1fr); }
}
.tile {
  display: flex; flex-direction: column; gap: 6px; align-items: flex-start;
  padding: 26px 22px; min-height: 108px; text-align: left; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
  color: inherit;
}
.tile:hover { border-color: var(--text-tertiary); background: rgba(148, 163, 184, .06); }
.tile.wide { grid-column: 1 / -1; min-height: 84px; }
.tile-title { font-size: 18px; font-weight: 650; color: var(--text-primary); }
.tile-sub { font-size: 13px; color: var(--text-tertiary); }
/* The icon across from the words (assessor, 2026-09-28). Room is kept for it on
   the right, so a long line never runs underneath it. */
.tile.has-ic { padding-right: 84px; }
.tile-ic {
  position: absolute; right: 24px; top: 50%; transform: translateY(-50%);
  width: 42px; height: 42px; color: var(--flow); opacity: .85; pointer-events: none;
}
.tile:hover .tile-ic { opacity: 1; }

/* The report actions along the bottom of the first wireframe. */
.action-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px;
}
.action {
  display: flex; flex-direction: column; gap: 4px; align-items: flex-start;
  padding: 14px 16px; text-align: left; text-decoration: none; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
  color: inherit;
}
.action:hover:not(:disabled) { border-color: var(--text-tertiary); }
.action:disabled { opacity: .45; cursor: default; }
.action-name { font-size: 14px; font-weight: 650; color: var(--text-primary); }
.action-sub { font-size: 12px; color: var(--text-tertiary); }

/* THE XML IS READY (assessor, 2026-09-28: *"a green flash with the boarder then
   having a continuous green light circle the boarder"*). The light is drawn on
   the button's own chrome edge — the `::before` ring every box here already
   has — so it is the edge that lights rather than a second border beside it:
   one flash of the whole edge, then two points of light running round it for
   as long as it stays ready. The same two lights as the app's ReadyRing. */
@property --ready-turn { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
.action.xml-ready { animation: xml-ready-flash .9s ease-out 1; }
.action.xml-ready::before,
.action.xml-ready:hover:not(:disabled)::before {
  padding: 2px;
  background: conic-gradient(from var(--ready-turn),
    var(--ok) 0deg,
    color-mix(in srgb, var(--ok) 35%, transparent) 30deg 150deg,
    var(--ok) 180deg,
    color-mix(in srgb, var(--ok) 35%, transparent) 210deg 330deg,
    var(--ok) 360deg);
  animation: xml-ready-turn 2.6s linear infinite;
}
.action.xml-ready .action-sub { color: var(--ok); }
@keyframes xml-ready-turn { to { --ready-turn: 360deg; } }
@keyframes xml-ready-flash {
  from {
    box-shadow: var(--glass-shadow), 0 0 0 2px var(--ok),
      0 0 22px 4px color-mix(in srgb, var(--ok) 55%, transparent);
  }
  to { box-shadow: var(--glass-shadow); }
}
/* Still lit, no longer moving: the state is shown, only the motion goes. */
@media (prefers-reduced-motion: reduce) {
  .action.xml-ready, .action.xml-ready::before { animation: none; }
  .action.xml-ready::before { background: var(--ok); }
}

/* ---------- the estate dashboard (Client Portal Access, 2026-09-10) ------- */

/* ⚠ THE STATUS COLOURS HERE ARE THE PRODUCT'S OWN, and they are declared once
   because two of them must never be confused: `seg-lapsed` is "this site is out
   of compliance" and `seg-due` is "renew it this quarter". The palette
   validator separates them by only ΔE 6.6 under deuteranopia, which is inside
   the band where colour is allowed ONLY with a second encoding — so every
   segment and every chip that uses these also carries its word and its number.
   If you ever draw one of these as colour alone, that is the bug. */
.seg-lapsed  { --seg: var(--alert); }
.seg-due     { --seg: var(--copper); }
.seg-soon    { --seg: #c9b458; }
.seg-current { --seg: var(--flow); }
.seg-unknown { --seg: var(--text-tertiary); }

.chart { margin: 2px 0 4px; }
.chart-svg { display: block; max-width: 100%; overflow: visible; }
.chart-label { font-size: 12px; font-family: var(--sans); }
.chart-value { font-size: 12px; font-family: var(--sans); font-weight: 600; }
.chart-ref { font-size: 10px; font-family: var(--sans); }
.chart-bar { transition: opacity .12s ease; }
.chart-bar.pickable { cursor: pointer; }
.chart-bar:hover { opacity: .82; }
.chart-hit { cursor: crosshair; }
.chart-note { color: var(--text-tertiary); font-size: 12px; margin: 8px 0 0; }
.chart-empty { color: var(--text-secondary); font-size: 13px; margin: 6px 0; }

/* The compliance bar. A 2px gap between fills so two adjacent bands never read
   as one continuous block. */
.compliance-bar {
  display: flex;
  gap: 2px;
  height: 14px;
  margin: 4px 0 14px;
}
.compliance-seg {
  background: var(--seg);
  border-radius: 4px;
  min-width: 6px;
}
.compliance-key {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 20px;
  margin-bottom: 12px;
}
.compliance-key-item { display: flex; align-items: baseline; gap: 7px; }
.compliance-key-item.none { opacity: .45; }
.key-dot {
  width: 9px;
  height: 9px;
  border-radius: 3px;
  background: var(--seg);
  flex-shrink: 0;
  align-self: center;
}
.key-count { font-size: 15px; font-weight: 650; color: var(--text-primary); }
.key-label { font-size: 12px; color: var(--text-secondary); }

/* Its own class rather than `.chip`, and NOT because that one is broken — it
   was, and it is fixed above. This is keyed to the compliance bar's own five
   states (`seg-lapsed` … `seg-unknown`), one of which — `seg-soon` — has no
   equivalent among ok/warn/todo. A chip and its bar segment must not be able to
   disagree about what amber means on the same panel. */
.cert-chip {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--seg);
  background: color-mix(in srgb, var(--seg) 15%, transparent);
  white-space: nowrap;
}

/* Tables. Wide ones scroll inside their own box rather than pushing the page
   sideways — a dashboard that scrolls horizontally has lost its layout. */
.estate-table {
  width: 100%;
  border-collapse: collapse;
  margin: 14px 0 6px;
  display: block;
  overflow-x: auto;
  white-space: nowrap;
}
.estate-table th {
  text-align: left;
  font-size: 10.5px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  font-weight: 600;
  padding: 0 16px 7px 0;
  border-bottom: 1px solid var(--border);
}
.estate-table td {
  padding: 8px 16px 8px 0;
  font-size: 13px;
  color: var(--text-primary);
  border-bottom: 1px solid var(--border);
}
.estate-table tr:last-child td { border-bottom: none; }
.estate-table td.mono { font-family: var(--mono); font-size: 12px; color: var(--text-secondary); }

.client-select {
  background: var(--surface);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 9px 12px;
  font: inherit;
  font-size: 14px;
  min-width: 320px;
  max-width: 100%;
}

/* The rate card. The only inputs on a read-only screen, and they are not survey
   data — see the panel's own note. */
.rate-card {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 18px;
  margin: 14px 0 4px;
}
.rate-row { display: flex; align-items: center; gap: 9px; }
.rate-class { font-size: 12.5px; color: var(--text-secondary); display: flex; gap: 7px; align-items: baseline; }
/* Which classes this estate actually contains. The card lists all seven so a
   rate can be set before the client who needs it exists — this is what stops
   seven boxes reading as seven equally urgent boxes. */
.rate-row.in-use .rate-class { color: var(--text-primary); }
.rate-here {
  font-size: 10px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--flow); background: color-mix(in srgb, var(--flow) 13%, transparent);
  padding: 2px 6px; border-radius: 999px; white-space: nowrap;
}
.rate-input {
  width: 110px;
  background: var(--surface);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 7px 10px;
  font: inherit;
  font-size: 13px;
}
.rate-input:focus { outline: 2px solid var(--flow); outline-offset: 1px; }
.rate-to { font-size: 11.5px; color: var(--text-tertiary); }
/* A row whose net present value straddles zero — worth doing at the cheaper
   quote and not at the dearer one. Marked because a reader scanning a column of
   ranges will not spot the sign change on their own. */
.npv-turns {
  margin-left: 7px; font-size: 10px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--warn); background: color-mix(in srgb, var(--warn) 15%, transparent);
  padding: 2px 6px; border-radius: 999px;
}


/* An archived inspection, shown only when "Show archived" is on. Dimmed and
   marked with a rule rather than a colour: archived is not a WARNING, it is a
   record put aside, and the traffic light on this page is spoken for. */
tr.archived td { opacity: 0.62; }
tr.archived td:first-child { border-left: 2px solid var(--muted, #6b7178); padding-left: 10px; }

/* The line under the panel head while archiving is armed. `derived` gives it
   the muted tone every other explanatory line on this page has; this adds the
   room, which `derived` alone does not because it is normally inline. */
.archive-hint { display: block; padding: 0 16px 10px; }

/* The account controls in the sidebar foot (assessor 2026-09-11). The icon is
   decorative — the word beside it is the label, and `aria-hidden` on the svg
   keeps a screen reader hearing "Password", not "Password Password". */
.who-actions .link { display: inline-flex; align-items: center; gap: 6px; }
.act-ic { width: 14px; height: 14px; flex: none; opacity: 0.85; }
.who-actions .link:hover .act-ic { opacity: 1; }

/* A hundred-per-cent stacked bar. The 2px gaps are STRUCTURAL, not decoration:
   they are the secondary encoding that keeps two segments apart for a reader
   who cannot separate the hues, which is what lets the palette sit in the
   6-8 ΔE CVD band at all. */
.share-bar {
  display: flex; gap: 2px; height: 22px; border-radius: 5px; overflow: hidden;
  background: var(--bg-card-alt); margin-bottom: 10px;
}
.share-seg { min-width: 3px; }
.share-key { display: flex; flex-wrap: wrap; gap: 6px 18px; }
.share-key-item { display: inline-flex; align-items: baseline; gap: 6px; font-size: 12px; }
.share-dot { width: 9px; height: 9px; border-radius: 2px; flex: none; align-self: center; }
/* Text wears text tokens, never the series colour — the dot beside it carries
   the identity. */
.share-pct { font-weight: 600; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.share-label { color: var(--text-secondary); }

/* Undoing an answer is an action, not a third answer, so it does not wear the
   selected state the Yes/No segments do — it sits apart and reads as a verb. */
.q-control .q-clear { margin-left: 8px; color: var(--text-tertiary); }
.q-control .q-clear:hover { color: var(--text-primary); }

/* ======================================================================
   CHROME GLASS (assessor, 2026-09-24: "I like the chrome look in the boxes").
   References: UI_Designs/IMG_0521.PNG and IMG_0522.PNG — dark glass cards
   with a bright bevelled edge, floating over soft coloured light.

   ONE LAYER, APPENDED, OVERRIDING. Nothing above was rewritten: every rule
   above still says what a box is, and this block only says what it is made
   of. Deleting from here to the end of the file restores the flat look
   exactly, which is the cheapest possible undo for a taste decision.

   How the chrome is built, because it is not a border colour:
   - The FILL is a faint white gradient, so the light behind the page shows
     through as tint. ⚠ THERE IS NO backdrop-filter, ON PURPOSE: the only
     thing behind a card is a smooth radial gradient, and blurring a smooth
     gradient changes no pixel — while a dozen blurred boxes on the
     inspection hub made the page slow enough to composite that a browser
     screenshot timed out. Add blur back only if something with DETAIL ever
     sits behind the glass.
   - The EDGE is a ::before ring painted with a metallic gradient — bright
     at the top-left where the light is, dark along the middle, a second
     catch-light at the bottom-right — and masked down to 1px. A plain
     `border-image` cannot follow a border-radius; the mask can.
   - An inset 1px highlight along the top is the lip of the bevel.
   The light sources are the brand's own two colours (flow green, copper)
   plus one cool steel, so the glass tints toward the product and not
   toward someone else's palette.
   ====================================================================== */

:root {
  --bg-main: #0c0e11;
  --border: rgba(255, 255, 255, 0.075);
  --bg-card-alt: rgba(255, 255, 255, 0.045);
  --surface: rgba(255, 255, 255, 0.05);
  --glass-fill: linear-gradient(160deg,
    rgba(255, 255, 255, 0.085) 0%,
    rgba(255, 255, 255, 0.03) 42%,
    rgba(255, 255, 255, 0.02) 70%,
    rgba(255, 255, 255, 0.045) 100%);
  --glass-well: linear-gradient(170deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.025));
  --chrome-edge: linear-gradient(145deg,
    rgba(255, 255, 255, 0.55) 0%,
    rgba(255, 255, 255, 0.16) 18%,
    rgba(255, 255, 255, 0.035) 45%,
    rgba(255, 255, 255, 0.06) 72%,
    rgba(255, 255, 255, 0.26) 100%);
  --chrome-edge-soft: linear-gradient(145deg,
    rgba(255, 255, 255, 0.26) 0%,
    rgba(255, 255, 255, 0.06) 30%,
    rgba(255, 255, 255, 0.03) 65%,
    rgba(255, 255, 255, 0.14) 100%);
  --glass-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    0 24px 48px -24px rgba(0, 0, 0, 0.75),
    0 2px 8px rgba(0, 0, 0, 0.25);
}

/* The light behind the glass. Fixed, so it stays put while the cards scroll
   over it — that parallax is most of what makes glass read as glass.
   The amber pool in the bottom-right corner came out on 2026-09-25 (assessor:
   "a little distracting"); the sign-in card's smaller amber glow with it. */
body {
  background:
    radial-gradient(1000px 600px at 42% -10%, rgba(53, 199, 122, 0.40), transparent 64%),
    radial-gradient(760px 560px at 6% 22%, rgba(160, 210, 90, 0.15), transparent 62%),
    radial-gradient(860px 620px at 28% 104%, rgba(70, 180, 190, 0.22), transparent 64%),
    radial-gradient(760px 560px at 80% 30%, rgba(110, 150, 210, 0.14), transparent 66%),
    var(--bg-main);
  background-attachment: fixed;
}

/* --- the boxes ------------------------------------------------------------ */

.panel, .kpi-card, .signin-card, .greeting,
.tile, .action, .type-box, .total {
  position: relative;
  background: var(--glass-fill);
  border: 1px solid transparent;
  box-shadow: var(--glass-shadow);
}
.panel, .kpi-card, .signin-card { border-radius: 18px; }

.panel::before, .kpi-card::before, .signin-card::before, .greeting::before,
.tile::before, .action::before, .type-box::before, .total::before {
  content: '';
  position: absolute; inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: var(--chrome-edge);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  pointer-events: none;
  z-index: 1;
}
/* Smaller things get a quieter edge, or a grid of them glitters. */
.tile::before, .action::before, .type-box::before, .total::before, .greeting::before {
  background: var(--chrome-edge-soft);
}

/* A box's hover is the edge brightening — the light catching it — rather than
   the grey fill the flat design used. */
.tile, .action, .type-box { transition: box-shadow .18s ease, background-color .18s ease; }
.tile:hover, .action:hover:not(:disabled), .type-box:hover {
  background: var(--glass-fill), var(--glass-hover-wash, rgba(255, 255, 255, 0.025));
  border-color: transparent;
  box-shadow: var(--glass-shadow-hover, inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 28px 50px -24px rgba(0, 0, 0, 0.8));
}
.tile:hover::before, .action:hover:not(:disabled)::before, .type-box:hover::before {
  background: var(--chrome-edge);
}
.type-box.on { border-color: transparent; box-shadow: var(--glass-shadow), 0 0 0 1px var(--ok); }

/* Dividers inside a panel are etched, not drawn. */
.panel-head { border-bottom-color: var(--etch, rgba(255, 255, 255, 0.06)); }

.kpi-value { letter-spacing: -0.02em; }

/* --- wells: the recessed boxes inside a card ------------------------------ */
/* The reference's inner stat block and schedule cards are darker than the
   card they sit in, with a thin top highlight — a recess, not a second card. */
input[type='text'], input[type='search'], input[type='email'], input[type='password'],
input[type='number'], input[type='date'], input:not([type]), select, textarea {
  box-shadow: var(--field-inset, inset 0 1px 2px rgba(0, 0, 0, 0.35));
}
.search input { box-shadow: none; }
/* A native list opened from a translucent control would draw see-through, and
   on Windows the popup does not blur. The rows get a solid ground. */
option, optgroup { background: #1a1d22; color: var(--text-primary); }

.secondary, .seg {
  background: var(--glass-well);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}

/* --- the green, polished ---------------------------------------------------- */
/* Same hue, same text colour, same meaning — lit from above like the
   reference's pill chips, so it belongs to the glass rather than sitting on it. */
.primary, button[type='submit'], .btn-open {
  background: linear-gradient(180deg, #52dd96 0%, #35c77a 55%, #2cb36c 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.4),
    inset 0 -1px 0 rgba(0, 0, 0, 0.15),
    0 8px 20px -8px rgba(53, 199, 122, 0.55);
}
.primary:hover:not(:disabled), button[type='submit']:hover, .btn-open:hover { filter: brightness(1.05); }

/* --- sidebar and top bar ---------------------------------------------------- */

.sidebar {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.015));
  border-right: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.35);
}
.nav-item:hover { background: var(--nav-hover, rgba(255, 255, 255, 0.04)); }
/* The selected item is a small chrome pill, as the reference's top nav marks
   "Dashboard". */
.nav-item.active {
  position: relative;
  background: var(--glass-well);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 4px 12px -6px rgba(0, 0, 0, 0.6);
}
.nav-item.active::before {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1px;
  background: var(--chrome-edge-soft);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  pointer-events: none;
}
.sidebar-foot { border-top-color: rgba(255, 255, 255, 0.07); }
.avatar {
  background: linear-gradient(155deg, #5a616d, #22262c 60%, #3a3f49);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 0 0 1px rgba(255, 255, 255, 0.08);
}

.search, .bell {
  background: var(--glass-well);
  border-color: rgba(255, 255, 255, 0.1);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

tbody tr.clickable:hover { background: rgba(255, 255, 255, 0.035); }

/* The calendar's days are wells in the calendar card, like the reference's
   schedule tiles — recessed, with a lip of light along the top. */
.cal-day {
  background: var(--glass-well);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.cal-day:hover { background: var(--glass-well), rgba(255, 255, 255, 0.03); }
.cal-row:hover { background: rgba(255, 255, 255, 0.04); }

/* --- where glass is the wrong answer --------------------------------------- */

/* A reader who has asked the system for less transparency gets solid cards
   with the same chrome edge — the edge is shape, the blur is decoration. */
@media (prefers-reduced-transparency: reduce) {
  .panel, .kpi-card, .signin-card, .greeting, .tile, .action, .type-box, .total,
  .sidebar, .search, .bell {
    background: var(--glass-solid, #1a1d22);
  }
}
@media (prefers-reduced-motion: reduce) {
  .tile, .action, .type-box { transition: none; }
}
/* Print is paper: no blur, no light, no edge. */
@media print {
  body { background: #fff; }
  .panel::before, .kpi-card::before, .tile::before, .action::before,
  .type-box::before, .total::before, .greeting::before { display: none; }
}

/* ======================================================================
   THE SIDEBAR IS A RAIL OF ICONS THAT OPENS ON HOVER (assessor, 2026-09-24:
   "default its collapsed with Icons to suit each title, but when the user
   hovers over the side bar with the mouse the side bar opens up showing the
   titles").

   ⚠ IT OPENS OVER THE PAGE, NOT BESIDE IT. The sidebar is `position: fixed`
   and `.main` keeps a permanent 72px margin, so opening it never reflows the
   screen underneath — a table that re-wrapped every time the mouse crossed
   the left edge would be worse than no rail at all. Because it now sits over
   real content, the OPEN sidebar is the one place in this file with a
   backdrop blur (one element; the cost note at the top of this layer is
   about a dozen).

   - Opens on :hover AND :focus-within, so a keyboard user tabbing into the
     nav gets the titles too.
   - A 120ms delay on opening only — crossing the rail on the way to
     something else does not flash it open; leaving closes at once.
   - Nothing moves vertically between the two states: the group headings keep
     their height and become a hairline when closed, so an icon is under the
     pointer in the same place before and after the rail opens.
   - Titles are faded, not removed: a screen reader reads them either way.
   - Only where there is a mouse and room. On touch, or under 861px, the
     sidebar is the full one it always was — a hover a finger cannot make
     would lock the titles away.
   ====================================================================== */

.nav-item { justify-content: flex-start; white-space: nowrap; }
.nav-ic { width: 19px; height: 19px; flex: none; opacity: .8; }
.nav-item:hover .nav-ic, .nav-item.active .nav-ic { opacity: 1; }
.nav-item.active .nav-ic { color: var(--flow); }
.nav-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

@media (hover: hover) and (min-width: 861px) {
  .sidebar {
    position: fixed; left: 0; top: 0; bottom: 0; z-index: 40;
    width: 72px; overflow: hidden;
    transition: width .22s cubic-bezier(.2, .8, .2, 1), box-shadow .22s ease, background-color .22s ease;
  }
  .sidebar:hover, .sidebar:focus-within {
    width: 264px;
    transition-delay: .12s;
    background-color: rgba(14, 16, 20, 0.78);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    backdrop-filter: blur(18px) saturate(140%);
    box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.35), 24px 0 48px -12px rgba(0, 0, 0, 0.65);
  }
  .main { margin-left: 72px; }
  /* Signed out there is no sidebar, so the sign-in card centres on the page. */
  body:has(> .sidebar[hidden]) .main { margin-left: 0; }

  /* Everything that is words, faded out on the rail. Kept to one width so
     nothing wraps mid-animation. */
  .brand { padding-left: 3px; white-space: nowrap; }
  .sidebar nav { overflow-x: hidden; }
  .sidebar .brand > div, .sidebar .nav-text, .sidebar .nav-item .count,
  .sidebar .nav-label > span, .sidebar .who, .sidebar .who-actions {
    opacity: 0; visibility: hidden;
    transition: opacity .12s ease, visibility 0s linear .12s;
  }
  .sidebar:hover .brand > div, .sidebar:hover .nav-text, .sidebar:hover .nav-item .count,
  .sidebar:hover .nav-label > span, .sidebar:hover .who, .sidebar:hover .who-actions,
  .sidebar:focus-within .brand > div, .sidebar:focus-within .nav-text,
  .sidebar:focus-within .nav-item .count, .sidebar:focus-within .nav-label > span,
  .sidebar:focus-within .who, .sidebar:focus-within .who-actions {
    opacity: 1; visibility: visible;
    transition: opacity .18s ease .2s, visibility 0s linear 0s;
  }

  /* A group heading on the rail is a hairline, so the groups still read as
     groups. */
  .nav-label { position: relative; white-space: nowrap; }
  .nav-label::after {
    content: ''; position: absolute; left: 12px; width: 24px; top: 50%;
    height: 1px; background: rgba(255, 255, 255, 0.14);
    transition: opacity .12s ease;
  }
  .sidebar:hover .nav-label::after, .sidebar:focus-within .nav-label::after { opacity: 0; }

  .sidebar-foot { padding-left: 4px; white-space: nowrap; }
}
@media (hover: hover) and (min-width: 861px) and (prefers-reduced-motion: reduce) {
  .sidebar, .sidebar:hover, .sidebar:focus-within { transition: none; }
}

/* ======================================================================
   SECOND DESIGN PASS (assessor, 2026-09-24): the top bar as one floating
   glass pill, big-number stat tiles on the dashboard, lit progress bars and
   chart bars, and the equipment Add button under the selected tile.
   ====================================================================== */

/* The gradient's home in the document (see index.html). Out of flow and
   invisible; it exists only to be pointed at. */
.svg-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* --- the top bar: one floating glass pill ---------------------------------
   Sticky, so the title and the search stay in reach down a long answering
   screen — and because content now scrolls UNDER it, this is the second (and
   last) place a backdrop blur earns its cost. */
.topbar {
  position: sticky; top: 12px; z-index: 30;
  align-items: center;
  margin: 14px 32px 18px;
  padding: 12px 14px 12px 22px;
  border-radius: 22px;
  background: var(--glass-fill), rgba(16, 19, 23, 0.62);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  backdrop-filter: blur(18px) saturate(140%);
  box-shadow: var(--glass-shadow);
}
.topbar::before {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1px;
  background: var(--chrome-edge);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  pointer-events: none;
}
.screen-title { font-size: 19px; }
.screen-sub { margin-top: 1px; font-size: 12.5px; }
/* Inside the pill, the search and the bell are pills of their own — the
   reference's nested segments. */
.topbar .search { padding: 8px 14px; }
.topbar .bell { width: 36px; height: 36px; }
@media (max-width: 860px) {
  .topbar { margin: 12px 18px 16px; position: static; }
}

/* --- stat tiles ------------------------------------------------------------ */

.stat-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px; margin-bottom: 18px;
}
.stat-tile {
  --tone: 53, 199, 122;
  position: relative; display: flex; flex-direction: column; align-items: flex-start;
  gap: 4px; padding: 16px 18px 15px; text-align: left; color: inherit;
  border: 1px solid transparent; border-radius: 18px;
  /* A wash of the tile's own colour in the top-right corner, where the
     reference lights its numerals. */
  background:
    radial-gradient(220px 130px at 100% 0%, rgba(var(--tone), 0.20), transparent 70%),
    var(--glass-fill);
  box-shadow: var(--glass-shadow);
  font-family: inherit;
}
.stat-tile::before {
  content: ''; position: absolute; inset: -1px; border-radius: inherit; padding: 1px;
  background: var(--chrome-edge);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  pointer-events: none;
}
button.stat-tile { cursor: pointer; transition: box-shadow .18s ease; }
button.stat-tile:hover {
  box-shadow: var(--glass-shadow-hover, inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 28px 50px -24px rgba(0, 0, 0, 0.8)),
    0 0 0 1px rgba(var(--tone), 0.35);
}
.tone-flow { --tone: 53, 199, 122; }
.tone-steel { --tone: 122, 162, 227; }
.tone-copper { --tone: 224, 160, 58; }
.tone-teal { --tone: 63, 193, 201; }
.stat-top { display: flex; align-items: center; gap: 8px; }
.stat-dot {
  width: 9px; height: 9px; border-radius: 50%; flex: none;
  background: rgb(var(--tone));
  box-shadow: 0 0 10px rgba(var(--tone), 0.8);
}
.stat-label {
  font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-secondary);
}
/* The colour is on the dot and the wash; the numeral stays white, so a tile is
   read by its label rather than by a hue a reader might not separate. */
.stat-value {
  font-size: 40px; font-weight: 600; line-height: 1.05; letter-spacing: -0.035em;
  color: var(--text-primary); margin-top: 6px;
}
.stat-sub { font-size: 12px; color: var(--text-tertiary); }

/* --- progress: a recessed track, a lit fill, and segment ticks ------------ */

.progress-bar { height: 12px; }
.progress-seg {
  position: relative;
  background: var(--glass-well);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.45), inset 0 0 0 1px rgba(255, 255, 255, 0.05);
}
.progress-fill {
  background: linear-gradient(90deg, #2cb36c, #5ae39d);
  box-shadow: 0 0 14px rgba(53, 199, 122, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.35);
}
.progress-fill.done { background: linear-gradient(90deg, #3fcf7a, #7cf0a8); }
/* Twenty segments, cut by a hairline of the page colour every 5%. Drawn over
   the fill, so the fill reads as filled segments rather than a gauge. */
.progress-seg::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: repeating-linear-gradient(90deg,
    transparent 0 calc(5% - 2px), rgba(12, 14, 17, 0.9) calc(5% - 2px) 5%);
}
.progress-item { align-items: baseline; }
.progress-num {
  font-size: 20px; font-weight: 650; letter-spacing: -0.02em;
  color: var(--text-primary); font-variant-numeric: tabular-nums;
}

/* --- charts ---------------------------------------------------------------- */

/* CSS beats the `fill` attribute the chart code writes, so every bar takes the
   lit gradient without the chart code changing. One colour still — the rule
   that length carries magnitude and colour does not is untouched. */
.chart-bar { fill: url(#barGlass); filter: drop-shadow(0 0 6px rgba(53, 199, 122, 0.35)); }
.share-bar { box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.45); }
.share-seg { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), inset 0 -1px 0 rgba(0, 0, 0, 0.2); }

/* --- the equipment Add button, under the selected tile -------------------- */

.type-col { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.type-col > .type-box { flex: 1 0 auto; }
/* Every slot keeps the button's height, so choosing a tile never moves the row. */
.type-add { min-height: 38px; }
.type-add .add-candidate {
  display: flex; flex-direction: column; gap: 6px;
  margin: 0; padding: 0; border: 0;
  animation: add-in .2s cubic-bezier(.2, .8, .2, 1);
}
.type-add .primary { width: 100%; padding: 10px 12px; }
.type-add .saved { margin: 0; font-size: 12px; }
.type-add-note { grid-column: 1 / -1; margin: 0; max-width: 90ch; }
@keyframes add-in {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .type-add .add-candidate { animation: none; }
}

/* ======================================================================
   PILLS AND BADGES (assessor, 2026-09-24: "Pill chips and status badges").

   One material for every small label in the portal: a tinted glass capsule,
   lit along its top edge, with a faint glow in its own colour — the
   references' "Beginners" / "Advanced" chips. `--tone` is the SAME variable
   the stat tiles use (`.tone-flow`, `.tone-steel`, …, defined with them), so
   a green pill and a green tile are one green.

   What wears it:
   - `.pill` — new: inspection status, level and recommendation priority
     (`statusPill`, `levelPill`, `priorityPill` in app.js).
   - `.tag` and `.chip` — existing, restyled here without touching a caller.
   - `.req-pill` — the sidebar's Private+ / Corporate badges, polished solid.

   ⚠ EVERY ONE CARRIES WORDS. Colour is never the only difference; see the
   note on `.chip` above for the ΔE figures that make that a rule.
   ====================================================================== */

.tone-alert { --tone: 255, 107, 112; }
.tone-neutral { --tone: 160, 166, 176; }

.pill, .tag, .chip {
  --tone: 160, 166, 176;
  display: inline-flex; align-items: center; gap: 6px;
  white-space: nowrap; vertical-align: middle;
  border-radius: 999px;
  color: color-mix(in srgb, rgb(var(--tone)) 78%, white);
  background: linear-gradient(180deg, rgba(var(--tone), 0.24), rgba(var(--tone), 0.10));
  border: 1px solid rgba(var(--tone), 0.38);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.14),
    0 0 14px -6px rgba(var(--tone), 0.7);
}
.pill { font-size: 11.5px; font-weight: 600; padding: 3px 10px 3px 8px; line-height: 1.3; }
.pill.tone-flow, .tag.ok, .chip.ok { --tone: 53, 199, 122; }
.pill.tone-teal { --tone: 63, 193, 201; }
.pill.tone-steel { --tone: 122, 162, 227; }
.pill.tone-copper, .tag.warn, .chip.warn { --tone: 224, 160, 58; }
.pill.tone-alert, .tag.alert, .chip.bad { --tone: 255, 107, 112; }
.chip.todo { --tone: 160, 166, 176; }
.pill-dot {
  width: 6px; height: 6px; border-radius: 50%; flex: none;
  background: rgb(var(--tone));
  box-shadow: 0 0 6px rgba(var(--tone), 0.9);
}
/* A category rather than a state: clear glass with a chrome rim, no colour. */
.pill.tone-outline {
  padding: 3px 10px;
  color: var(--text-primary);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.02));
  border-color: rgba(255, 255, 255, 0.22);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16);
}
/* The existing classes keep their own sizes; only the material changed. The
   .chip rule above set its size and weight, and still does. */
.tag { padding: 3px 9px; }

/* The sidebar's plan badges: SOLID, like the reference's yellow chip, because
   they name a tier rather than a state. */
.req-pill {
  background: linear-gradient(180deg, #f5c46a 0%, #e0a03a 60%, #c98a2a 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), 0 0 10px -3px rgba(224, 160, 58, 0.7);
  padding: 2px 7px; letter-spacing: 0.04em;
}

/* Pills in a line of facts. */
.cal-row-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.rec .asset-head { align-items: flex-start; }
.rec .asset-head .pill { margin-top: 2px; }
td .pill { margin: -2px 0; }

/* ======================================================================
   THE ANSWERING SCREEN, DENSE (assessor, 2026-09-24: "there is a lot of
   wasted space on the screen, change it so questions can be viewed without
   scrolling down the screen").

   Measured before the change, one cooling plant at 1440×900: 4,085px tall —
   five closed condition groups stacked one per row, then five panels whose
   fields each took the full 1,300px width for a box that holds a model
   number. The Data plate panel alone was 1,096px.

   Scoped to `.answering` (the wrapper `openAsset` draws into), so no other
   screen moves. Nothing is hidden or folded that was not folded before —
   every question is where it was, in the same order; it is only packed.

   - Closed condition groups sit THREE ACROSS. An open one takes the whole
     row, because its questions need the width — and closing it puts it back.
   - Fields in a panel flow into columns (~300px each: four across at 1440,
     two on a laptop). A field whose note is open spans the row, so the note
     is never typed into a 300px box.
   - Condition questions go two across inside an open group.
   - The welcome strip is not drawn here. It is 70px of the same greeting on
     every screen, and this is the one screen where 70px is a question.
   ====================================================================== */

.main:has(.answering) .greeting { display: none; }

.answering {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px 14px;
  align-items: start;
}
.answering > * { grid-column: 1 / -1; margin-bottom: 0; }
.answering > .back-row { margin: 0; }
.answering > .section-lead { margin: 6px 0 -4px; max-width: none; }

/* Closed groups: one cell each. */
.answering > .cond-group:not([open]) { grid-column: auto; }
.answering .cond-group {
  margin: 0;
  background: var(--glass-well);
  border-color: rgba(255, 255, 255, 0.08);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.answering .cond-head { padding: 13px 16px; }
.answering .cond-label { font-size: 14.5px; }

/* Fields in columns. */
.answering .panel > .panel-body {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: 0 22px;
  padding: 12px 18px 14px;
}
.answering .panel > .panel-body > :not(.q-row) { grid-column: 1 / -1; }
.answering .panel > .panel-body > .derived { margin: 0 0 4px; }
.answering .panel-head { padding: 12px 18px; }

.answering .q-row { padding: 10px 0; }
/* In a grid every row is someone's last in its column, so the rule is drawn
   on all of them and the panel's own edge covers the bottom one. */
.answering .panel-body > .q-row:last-child { border-bottom: 1px solid var(--border); }
.answering .q-control { margin-top: 6px; }
.answering .q-extras { margin-top: 6px; }
.answering .q-foot { margin-top: 5px; }
.answering .q-foot:not(:has(:not(:empty))) { display: none; }
/* Only in the ~290px panel columns: a condition question's column is 420px+,
   wide enough for its note, and every answered question opens its note — so
   spanning there would put an answered group back to one column. */
.answering .panel-body > .q-row:has(> .q-extras[open]) { grid-column: 1 / -1; }

/* Condition questions: two across inside an open group. */
.answering .cond-body {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(420px, 1fr));
  gap: 0 26px;
  padding: 12px 18px 6px;
}
.answering .cond-body > :not(.q-row) { grid-column: 1 / -1; }
.answering .cond-body > .bulk-bar { padding-bottom: 10px; margin-bottom: 0; }

@media (max-width: 1100px) {
  .answering { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ======================================================================
   UPCOMING AND ACTIVITY (assessor, 2026-09-24 — the references' "My
   schedule" cards and "Activity" columns).

   ⚠ NO WIDE ROW ANY MORE (owner, 2026-10-02: "change the Current inspection
   box and Upcoming box so that they are sized the same"). The top row was a
   2fr/1fr `.dash-grid-wide`; it is now a plain `.dash-grid`, the same equal
   halves as Activity and Map below it, so the two rows line up as well.
   ====================================================================== */

.derived-inline { font-size: 12px; color: var(--text-tertiary); }

.sched-row {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 10px;
}
.sched-card {
  position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: 5px;
  padding: 12px 13px; text-align: left; cursor: pointer; color: inherit; font-family: inherit;
  border: 1px solid transparent; border-radius: 14px;
  background: var(--glass-well);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 10px 24px -14px rgba(0, 0, 0, 0.7);
  transition: box-shadow .18s ease;
}
.sched-card::before {
  content: ''; position: absolute; inset: -1px; border-radius: inherit; padding: 1px;
  background: var(--chrome-edge-soft);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  pointer-events: none;
}
.sched-card:hover { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 16px 30px -14px rgba(0, 0, 0, 0.8); }
.sched-card:hover::before { background: var(--chrome-edge); }
.sched-top { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; width: 100%; }
.sched-date { font-size: 12px; font-weight: 600; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.sched-when { font-size: 11px; color: var(--text-tertiary); }
.sched-when.soon { color: var(--flow); }
.sched-site { font-size: 14.5px; font-weight: 650; color: var(--text-primary); line-height: 1.25; margin-top: 2px; }
.sched-client { font-size: 12px; color: var(--text-tertiary); }
.sched-pills { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }

.act-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.act-total { font-size: 34px; font-weight: 600; letter-spacing: -0.03em; line-height: 1; }
.act-unit { font-size: 11.5px; color: var(--text-tertiary); white-space: pre-line; line-height: 1.3; }
.act-chart { display: flex; align-items: stretch; gap: 8px; height: 150px; }
.act-col { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; min-width: 0; }
/* The track is the column's full height, recessed; the bar grows from its
   floor. Both fully rounded — the reference's capsule columns. */
.act-track {
  position: relative; flex: 1; width: 100%; max-width: 40px;
  display: flex; align-items: flex-end;
  border-radius: 999px;
  background: var(--glass-well);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.4);
}
.act-bar {
  position: relative; width: 100%; min-height: 4px; border-radius: 999px;
  background: var(--act-bar-fill, linear-gradient(180deg, rgba(255, 255, 255, 0.28), rgba(255, 255, 255, 0.10)));
  box-shadow: var(--act-bar-lip, inset 0 1px 0 rgba(255, 255, 255, 0.35));
}
/* This month, lit — the one column the eye should land on. */
.act-col.now .act-bar {
  background: linear-gradient(180deg, #7cf0a8, #35c77a);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5), 0 0 16px rgba(53, 199, 122, 0.55);
}
.act-val {
  position: absolute; top: -20px; left: 50%; transform: translateX(-50%);
  font-size: 11.5px; font-weight: 600; color: var(--text-secondary);
}
.act-col.now .act-val { color: var(--flow); }
.act-label { font-size: 11px; color: var(--text-tertiary); }
.act-col.now .act-label { color: var(--text-primary); font-weight: 600; }

/* ======================================================================
   SIGN-IN (assessor, 2026-09-24). The card already wore the glass; what it
   lacked was a place to stand. A pool of the brand's green behind it, a
   larger, softer card, and fields that are wells like the rest of the
   portal — the first screen anyone sees should be the same material as the
   ones after it.
   ====================================================================== */

.signin-card {
  max-width: 440px;
  padding: 36px 34px 26px;
  border-radius: 26px;
  background: var(--glass-fill), rgba(14, 17, 21, 0.55);
  /* NO DROP SHADOW here, unlike every other card: the card sits in its own
     light, and a shadow drew a dark box between the two that read as a
     smudge. The lip of the bevel stays. */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.09);
}
/* The light behind the card: brand green, pooled under it and a little above,
   as though the card were lit from the logo. Behind the card (z-index -1
   inside a card that makes no stacking context), and never over its text. */
.signin-card::after {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  inset: -140px -200px -80px;
  background:
    radial-gradient(closest-side at 50% 42%, rgba(53, 199, 122, 0.5), rgba(53, 199, 122, 0.14) 55%, transparent 78%);
}
.signin-logo { margin-bottom: 24px; filter: drop-shadow(0 0 18px rgba(53, 199, 122, 0.35)); }
.signin-card .lede { text-align: center; margin-bottom: 20px; }
.signin-card input[type='text'], .signin-card input[type='password'] {
  padding: 12px 14px; border-radius: 12px;
  background: var(--glass-well);
  border: 1px solid var(--well-edge, rgba(255, 255, 255, 0.1));
  box-shadow: var(--field-inset, inset 0 1px 2px rgba(0, 0, 0, 0.4));
  transition: border-color .15s ease, box-shadow .15s ease;
}
.signin-card input[type='text']:focus, .signin-card input[type='password']:focus {
  outline: none; border-color: rgba(53, 199, 122, 0.7);
  box-shadow: var(--field-inset, inset 0 1px 2px rgba(0, 0, 0, 0.4)), 0 0 0 3px rgba(53, 199, 122, 0.18);
}
.signin-card button[type='submit'] { margin-top: 20px; padding: 13px; border-radius: 12px; font-size: 14px; }
.signin-alt { justify-content: center; margin-top: 18px; padding-top: 14px; border-top-color: rgba(255, 255, 255, 0.07); }
@media (prefers-reduced-motion: reduce) {
  .signin-card input { transition: none; }
}
@media (max-width: 700px) {
  .answering { grid-template-columns: minmax(0, 1fr); }
  .answering .cond-body { grid-template-columns: minmax(0, 1fr); }
}

/* ======================================================================
   ASSESSOR'S LIST OF 2026-09-24 (evening)
   ====================================================================== */

/* --- exceptions are RED, like the app ------------------------------------- */

/* "All as exception": the green plate's shape in the alert colour. */
.primary.danger {
  background: linear-gradient(180deg, #ff9a9d 0%, #ff6b70 55%, #e2545a 100%);
  color: #1c0607;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.4),
    inset 0 -1px 0 rgba(0, 0, 0, 0.15),
    0 8px 20px -8px rgba(255, 107, 112, 0.55);
}

/* The selected answer on an exception row: red border and text where an
   expected answer is green, and the row washed red — the app's `stateBad` and
   `rowException`. Which stored value IS the exception is on the row
   (`data-exception`, from the server), so this never decides it; it only
   compares the two attributes, and both polarities are written out.
   Colour is not the only difference: the group's chip already says
   "N exceptions" in words. */
.q-row[data-exception='False'] .seg.on[data-stored='False'],
.q-row[data-exception='True'] .seg.on[data-stored='True'] {
  border-color: var(--alert); color: var(--alert);
  background: rgba(255, 107, 112, 0.12);
}
.q-row:has(.seg.on[data-stored='False'])[data-exception='False'],
.q-row:has(.seg.on[data-stored='True'])[data-exception='True'] {
  background: linear-gradient(90deg, rgba(255, 107, 112, 0.10), rgba(255, 107, 112, 0.02));
  box-shadow: inset 3px 0 0 var(--alert);
  border-radius: 8px;
  padding-left: 12px; padding-right: 8px;
}

/* --- the three folding boxes on the answering screen ---------------------
   Closed, they sit three across like the closed condition groups; open, the
   box takes the whole row. */
.answering > .fold-panel:not([open]) { grid-column: auto; }
.answering > .fold-panel > .panel-head { padding: 12px 16px; }

/* --- the map stays UNDER the sidebar and the top bar ---------------------
   Leaflet stacks its own panes at z-index 400–1000, and they were competing
   with the page's: the sidebar opening on hover (40) and the sticky top bar
   (30) both went under the map. `isolation` makes the map one layer of its
   own, so everything inside it is ordered only against itself. */
.map-canvas { position: relative; z-index: 0; isolation: isolate; }

/* ======================================================================
   ASSESSOR'S LIST OF 2026-09-24 (night)
   ====================================================================== */

/* --- the progress bar: one lit fill, no segments --------------------------
   (assessor: "The progress bar keep it fill no sections"). The twenty ticks
   are gone; the recessed track and the glowing fill stay. */
.progress-seg::after { content: none; }

/* --- Note & recommendation: closed, and obviously a thing to click --------
   A pill with a caret that turns, and a state chip saying whether there is
   anything inside — so a closed one still tells the reader a note exists. */
.q-extras > summary.q-extras-toggle {
  display: inline-flex; align-items: center; gap: 8px;
  list-style: none; cursor: pointer; user-select: none;
  padding: 5px 12px 5px 10px; border-radius: 999px;
  font-size: 12px; font-weight: 600; color: var(--text-secondary);
  background: var(--glass-well);
  border: 1px solid var(--well-edge, rgba(255, 255, 255, 0.14));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
  transition: border-color .15s ease, color .15s ease;
}
.q-extras > summary.q-extras-toggle::-webkit-details-marker { display: none; }
.q-extras > summary.q-extras-toggle:hover,
.q-extras > summary.q-extras-toggle:focus-visible {
  color: var(--text-primary); border-color: rgba(53, 199, 122, 0.6); outline: none;
}
.q-extras-caret { display: inline-block; font-size: 15px; line-height: 1; transition: transform .15s ease; }
.q-extras[open] > summary .q-extras-caret { transform: rotate(90deg); }
.q-extras-state {
  font-size: 10.5px; font-weight: 600; padding: 1px 7px; border-radius: 999px;
  color: var(--text-tertiary); background: var(--well-tint, rgba(255, 255, 255, 0.06));
}
.q-extras-state.on { color: var(--flow); background: rgba(53, 199, 122, 0.14); }
.q-extras[open] > summary.q-extras-toggle { color: var(--text-primary); border-color: rgba(53, 199, 122, 0.5); }
.q-extras[open] > .q-extra:first-of-type { margin-top: 10px; }
@media (prefers-reduced-motion: reduce) {
  .q-extras-caret, .q-extras > summary.q-extras-toggle { transition: none; }
}

/* --- group templates, at the far end of the bulk bar ---------------------- */
.bulk-bar .bulk-template { margin-left: auto; }
.template-tray {
  display: grid; gap: 8px; margin: 0 0 12px; padding: 12px;
  border-radius: 12px; background: var(--glass-well);
  border: 1px solid rgba(255, 255, 255, 0.08);
}
.template-tray .template-bar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.template-tray select, .template-tray input[type='text'] {
  flex: 1 1 240px; min-width: 0; padding: 8px 10px; border-radius: 9px;
  background: var(--bg-card-alt); color: var(--text-primary); border: 1px solid var(--border);
}
.answering .cond-body > .template-tray { grid-column: 1 / -1; }

/* --- the operating schedule table ----------------------------------------- */
.sched-table { display: grid; gap: 10px; }
.sched-switch { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-secondary); cursor: pointer; }
.sched-grid {
  display: grid; grid-template-columns: minmax(90px, 140px) minmax(110px, 160px) minmax(110px, 160px);
  gap: 6px 12px; align-items: center;
}
.sched-head {
  font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--text-tertiary);
}
.sched-day { font-size: 13.5px; color: var(--text-primary); }
.sched-grid input[type='time'] {
  padding: 7px 9px; border-radius: 9px; background: var(--bg-card-alt);
  color: var(--text-primary); border: 1px solid var(--border); font-size: 13px;
}
/* The two span switches, directly under Monday and across the whole row. */
.sched-spans {
  grid-column: 1 / -1; display: grid; gap: 6px;
  margin: 2px 0 8px; padding: 8px 10px; border-radius: 10px;
  background: rgba(53, 199, 122, 0.06); border: 1px solid rgba(53, 199, 122, 0.18);
}
.sched-spans .q-hint { margin: 0; }

/* --- the editable pre-site checklist -------------------------------------- */
label.presite-item { align-items: center; }
label.presite-item .saved { margin-left: auto; font-size: 11.5px; }

/* Upcoming is half width: four cards as a 2×2, not 3 + 1. */
.dash-grid .sched-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* --- the source groups wear the condition group's head (2026-09-24) -------
   Same box, same bold label, no caret — so "Inspector Input" and "Condition &
   Housekeeping" read as one kind of thing. The body keeps the narrower
   field columns the panels had. */
.answering .source-group > .panel-body {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: 0 22px;
  padding: 12px 18px 14px;
}
.answering .source-group > .panel-body > :not(.q-row) { grid-column: 1 / -1; }
.answering .source-group > .panel-body > .derived { margin: 0 0 4px; }

/* --- the Sub-System tile (2026-09-24) ------------------------------------
   One card per system, its units grouped by kind, a Move control on each. */
.type-add .area-input input { width: 100%; }
.area-input { display: inline-flex; min-width: 0; }
.area-input[hidden] { display: none; }
.sub-card {
  margin-bottom: 12px; padding: 12px 16px 6px;
  background: var(--glass-well, var(--surface));
  border: 1px solid var(--border); border-radius: 12px;
}
.sub-card-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; padding-bottom: 6px; }
.sub-card-name { font-size: 15px; font-weight: 650; color: var(--text-primary); }
.sub-card-area { font-size: 13px; color: var(--text-secondary); }
.sub-card .group-head { margin: 10px 0 2px; }
.sub-unit { display: flex; align-items: center; gap: 12px; }
.sub-unit .sub-unit-open { flex: 1 1 auto; min-width: 0; }
.sub-move { flex: none; max-width: 240px; }
.sub-unit .saved { flex: none; font-size: 12px; }

/* The chooser a walk-round unit opens under its row: which sub-system, or a
   new one named by its area. In the page, never a prompt box. */
.promote-pick {
  margin: 4px 0 12px; padding: 12px 14px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--glass-well, var(--surface));
}
.promote-line { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.promote-q { font-weight: 600; color: var(--text-primary); }
.promote-line .area-input input { min-width: 240px; }
.promote-pick .derived { margin: 8px 0 0; }

/* --- the System Control's controller box and g127's SFP calculator -------
   (2026-09-25). The controller box is a source group that starts open and
   takes the whole row; the calculator folds under its question like the
   Note & recommendation toggle it sits beside. */
.answering > .controller-group { grid-column: 1 / -1; }
.controller-body .controller-field { display: flex; flex-direction: column; gap: 6px; }
.controller-body .controller-field[hidden] { display: none; }
.controller-body .sched-table { grid-column: 1 / -1; }
.controller-body > .saved { grid-column: 1 / -1; }
.sfp-calc { margin-top: 6px; }
.sfp-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 10px 14px; margin-top: 10px;
}
.sfp-field { display: flex; flex-direction: column; gap: 4px; }
.sfp-field input { width: 100%; }
.sfp-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 10px; }
.sfp-result { margin: 0; font-weight: 650; color: var(--text-primary); }

/* --- weeks per year under the schedule table (2026-09-25) ----------------- */
.sched-weeks { display: grid; gap: 6px; max-width: 280px; }
.sched-weeks input {
  background: var(--bg-card-alt); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: 10px; padding: 8px 10px;
}
.warn-text { color: var(--alert); }

/* --- rounded dropdowns in the Controller box (2026-09-25) -----------------
   Assessor: "can the dropdown buttons be the same rounded style as other
   buttons". They sat outside `.q-control`, so they fell back to the browser's
   own square select. Same well, same 10px corner and same inset highlight as
   the secondary buttons, with a drawn chevron in place of the native arrow. */
.controller-body select,
.controller-body input[type='time'] {
  width: 100%; -webkit-appearance: none; appearance: none;
  background-color: var(--glass-well); color: var(--text-primary);
  border: 1px solid var(--well-edge, rgba(255, 255, 255, 0.1)); border-radius: 10px;
  padding: 9px 12px; font-size: 13px; font-family: inherit;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.controller-body select {
  padding-right: 36px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%239aa3ad' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 13px center; background-size: 12px 8px;
}
.controller-body select:hover { border-color: var(--well-edge-hover, rgba(255, 255, 255, 0.2)); }
.controller-body select:focus,
.controller-body input[type='time']:focus { outline: none; border-color: var(--flow); }

/* --- "Move to…" wears the green of "+ New sub-system" (2026-09-25) --------
   Still a native select underneath — the list of systems is the browser's —
   drawn as the primary button, with a dark chevron on the green. */
.sub-move {
  -webkit-appearance: none; appearance: none; border: none; border-radius: 10px;
  padding: 9px 34px 9px 14px; font-family: inherit; font-size: 13px; font-weight: 600;
  color: #0a0b0d; cursor: pointer; max-width: 260px;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%230a0b0d' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right 12px center / 12px 8px,
    linear-gradient(180deg, #52dd96 0%, #35c77a 55%, #2cb36c 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.4),
    inset 0 -1px 0 rgba(0, 0, 0, 0.15),
    0 8px 20px -8px rgba(53, 199, 122, 0.55);
}
.sub-move:hover:not(:disabled) { filter: brightness(1.05); }
.sub-move:disabled { opacity: .5; cursor: default; }
.sub-move option { color: var(--text-primary); background: #1a1d22; font-weight: 400; }

/* --- System Information: Manufacturer and Model (2026-09-25) -------------- */
.sysinfo-bar { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px; }
.sysinfo-field { display: flex; flex-direction: column; gap: 6px; flex: 1 1 260px; min-width: 0; }
.sysinfo-label { font-size: 11.5px; letter-spacing: .04em; text-transform: uppercase; color: var(--text-tertiary); }
.sysinfo-field select, .sysinfo-field input {
  width: 100%; -webkit-appearance: none; appearance: none;
  background-color: var(--glass-well); color: var(--text-primary);
  border: 1px solid var(--well-edge, rgba(255, 255, 255, 0.1)); border-radius: 10px;
  padding: 10px 12px; font-size: 13.5px; font-family: inherit;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.sysinfo-field select {
  padding-right: 36px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%239aa3ad' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 13px center; background-size: 12px 8px;
}
.sysinfo-field select:focus, .sysinfo-field input:focus { outline: none; border-color: var(--flow); }
.sysinfo-field input:disabled { opacity: .55; }
.sysinfo-bar > .primary { flex: none; }

/* --- site photographs under the questions (2026-09-25) -------------------- */
.answering > .unit-photos { grid-column: 1 / -1; }
.unit-photos-body { display: grid; gap: 14px; }
.unit-photos-block .group-head { margin: 0 0 8px; }
.unit-photos-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.unit-photo {
  display: flex; flex-direction: column; gap: 6px; text-decoration: none;
  color: var(--text-secondary); font-size: 12px;
}
.unit-photo img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 10px;
  border: 1px solid var(--well-edge, rgba(255, 255, 255, 0.1)); background: var(--glass-well);
}
.unit-photo:hover img { border-color: var(--flow); }
.unit-photo-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* --- a walk-round unit's details, from a desk (2026-09-25) ---------------- */
.walk-screen { display: grid; gap: 12px; }
.walk-screen > .back-row { margin: 0; }
.walk-lead, .walk-foot { margin: 0; max-width: 90ch; }
.walk-notice { margin: 0; }
.walk-group {
  margin: 0; background: var(--glass-well);
  border-color: rgba(255, 255, 255, 0.08);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.walk-group .cond-head { padding: 13px 16px; }
.walk-group .cond-label { font-size: 14.5px; }
.walk-body {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: 12px 22px; padding: 14px 18px 16px;
}
.walk-body > .derived, .walk-body > .empty, .walk-body > .walk-shot-note { grid-column: 1 / -1; margin: 0; }
.walk-field { display: flex; flex-direction: column; gap: 6px; padding: 0; border: 0; }
.walk-field input, .walk-field select {
  width: 100%; -webkit-appearance: none; appearance: none;
  background-color: var(--bg-card-alt); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: 10px; padding: 9px 12px;
  font-family: inherit; font-size: 13px;
}
.walk-field select {
  padding-right: 36px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%239aa3ad' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 13px center; background-size: 12px 8px;
}
.walk-field input:focus, .walk-field select:focus { outline: none; border-color: var(--flow); }
.walk-field input:disabled, .walk-field select:disabled { opacity: .6; }
.walk-field .saved { font-size: 12px; margin: 0; }
.walk-new-area { display: flex; gap: 8px; }
.walk-new-area input { flex: 1 1 auto; min-width: 0; }

.walk-shot { display: flex; gap: 12px; align-items: center; }
.walk-shot-img {
  flex: none; width: 116px; height: 87px; border-radius: 10px; overflow: hidden;
  border: 1px solid var(--well-edge, rgba(255, 255, 255, 0.1)); background: var(--bg-card-alt);
  display: flex; align-items: center; justify-content: center;
}
.walk-shot-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.walk-shot-empty { color: var(--text-tertiary); font-size: 22px; border-style: dashed; }
.walk-shot-text { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; min-width: 0; }
.walk-shot-name { font-weight: 600; color: var(--text-primary); }
.walk-upload { display: inline-flex; align-items: center; }
.candidate-details { margin-left: 8px; }
/* The plate's AI analysis on the walk-round details (v55 phase B). A note is a
   sentence to act on, so it is the alert colour at reading size; the Analyse
   row sits under it with its own saved mark. Both read the theme's tokens. */
.plate-flag { color: var(--alert); font-weight: 600; font-size: 13px; line-height: 1.45; margin: 6px 0; }
.plate-analyse { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 8px 0 12px; }
/* Both span the box's whole grid, like the sentences beside them. */
.walk-body > .plate-flag, .walk-body > .plate-analyse { grid-column: 1 / -1; }
.plate-analyse .derived { flex-basis: 100%; margin: 0; }
/* A unit's own plate on its page (v56): the walk-round's row, with its notes
   across the full width like the sentences beside them. */
.unit-plate .plate-flag { flex-basis: 100%; margin: 0; }

/* The area box a new sub-system is named from — under the Sub-System tile and
   in the walk-round unit's chooser — drawn like every other typed box. */
.area-input input {
  width: 100%; background: var(--bg-card-alt); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: 10px; padding: 9px 12px;
  font-family: inherit; font-size: 13px;
}
.area-input input:focus { outline: none; border-color: var(--flow); }
.area-input input::placeholder { color: var(--text-tertiary); }
/* The old one-box search sized itself with `flex: 1 1 320px`, which inside the
   new column-wise field became a 320px HEIGHT. Sized by its field now. */
.sysinfo-field .sysinfo-box { flex: none; }

/* --- the Asset Capture page (2026-09-26) ----------------------------------
   The app's walk-round list at a desk. Built from the parts every other
   screen uses — `kit-row` rows with the photograph, `type-box` tiles for
   "capture what?", the primary and secondary buttons — so it reads as the
   same portal rather than a new one. */
.capture-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 6px;
}
.capture-count { font-size: 13px; color: var(--text-secondary); }
.capture-bar-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.capture-choose {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px; margin: 12px 0 4px;
}
.capture-choose[hidden] { display: none; }
.type-box.dim { opacity: .5; }
.type-box.dim:hover { opacity: .8; }
.capture-said { margin: 6px 0 0; }
.capture-said:empty { display: none; }
.capture-group { margin-top: 20px; }
.capture-group-note { margin: 2px 0 6px; }
.capture-row {
  display: flex; align-items: center; gap: 12px;
  border-bottom: 1px solid var(--border);
}
.capture-row > .capture-open { flex: 1 1 auto; min-width: 0; border-bottom: 0; }
.capture-actions { display: flex; gap: 8px; flex: none; }
.capture-tag { margin-left: 8px; }
.kit-row-text .candidate-plate { margin-top: 6px; }
.kit-empty-wrap { display: grid; gap: 10px; justify-items: start; padding: 6px 0; }
.kit-empty-wrap .kit-empty { margin: 0; }
.walk-foot-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
@media (max-width: 720px) {
  .capture-row { flex-wrap: wrap; }
  .capture-actions { padding: 0 0 12px 76px; }
}

/* ======================================================================
   LIGHT MODE (assessor, 2026-09-26: "if possible make a light mode for the
   portal"). Off by default; the top bar's sun and moon switch it, and
   theme.js applies a saved choice before the first paint.

   ONE LAYER, APPENDED, KEYED OFF ONE ATTRIBUTE — the same shape as the glass
   layer above, for the same reason: dark is exactly what it was, and deleting
   from here down removes light mode whole. The only edits above are rules
   that now read a token with their old dark value as its fallback (see the
   note in the token block), which with the token unset is the same value.

   THE VALUES ARE THE APP'S LIGHT PALETTE, not new ones (src/components/
   inspector/theme.ts, LIGHT): the same canvas, the same inks, the same
   status colours, and the same four pools of light at the strengths the app's
   tests hold its page text to. An inspector who moves from the phone to the
   desk sees one product in both places.

   ⚠ `--flow` BECOMES A TEXT GREEN HERE. On a dark page the brand green is
   both the fill of a button and the colour of words; on a pale one it cannot
   be both — #35c77a on white is 2.2:1, which is not a colour, it is a smudge.
   So `--flow` takes the app's legible light green, and everything that FILLS
   with the brand green already names it outright (the buttons' gradient,
   the progress bars, the bell's count), so the brand is unchanged where it is
   a surface and readable where it is a word.

   ⚠ THE WHITE ALPHAS ABOVE ARE LIGHT FALLING ON DARK GLASS; here the same
   jobs are done by the ink at an alpha — an edge on a pale card is a shade,
   not a highlight. The one white that stays white is the 1px lip along the
   top of a card: the light still comes from above.
   ====================================================================== */

:root[data-theme='light'] {
  color-scheme: light;
  --bg-main: #f7f9fb;
  --bg-card: #ffffff;
  --bg-card-alt: rgba(20, 23, 28, 0.04);
  --border: rgba(20, 23, 28, 0.1);
  --text-primary: #14171c;
  --text-secondary: #4e545c;
  --text-tertiary: #5f666e;
  --flow: #067940;
  --flow-light: #e2f3e9;
  --copper: #a25407;
  --copper-light: #faecdc;
  --alert: #cd2127;
  --sidebar-bg: #eef1f5;
  --sidebar-active: rgba(20, 23, 28, 0.05);
  --surface: rgba(20, 23, 28, 0.04);
  --ok: #067940;
  --glass-fill: linear-gradient(160deg,
    rgba(255, 255, 255, 0.94) 0%,
    rgba(255, 255, 255, 0.8) 42%,
    rgba(255, 255, 255, 0.76) 70%,
    rgba(255, 255, 255, 0.88) 100%);
  --glass-well: linear-gradient(170deg, rgba(20, 23, 28, 0.05), rgba(20, 23, 28, 0.025));
  /* Lit from the top left, as in the dark set: white there, a shade along the
     edges turned away from it. */
  --chrome-edge: linear-gradient(145deg,
    rgba(255, 255, 255, 1) 0%,
    rgba(20, 23, 28, 0.06) 22%,
    rgba(20, 23, 28, 0.1) 55%,
    rgba(20, 23, 28, 0.16) 100%);
  --chrome-edge-soft: linear-gradient(145deg,
    rgba(255, 255, 255, 1) 0%,
    rgba(20, 23, 28, 0.05) 30%,
    rgba(20, 23, 28, 0.08) 65%,
    rgba(20, 23, 28, 0.12) 100%);
  --glass-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    0 18px 36px -22px rgba(20, 23, 28, 0.3),
    0 2px 6px rgba(20, 23, 28, 0.06);

  /* ⚠ A COLOUR THAT A STATE DRAWS OVER IS A TOKEN, NEVER AN OVERRIDE BELOW.
     `:root[data-theme='light']` adds two to the specificity of whatever it
     prefixes, so an override here outranks every hover, focus, open and
     selected rule above it. The first pass did exactly that: a light
     `input[type='text']` border beat `.q-control input:focus` and the focus
     ring vanished; a light `.act-bar` beat `.act-col.now .act-bar` and this
     month went grey. So the base rules read these — `var(--field-edge,
     #3a3f49)` — and the states above still win in both themes. Unset, as
     they are in dark, each falls back to the value its rule always had.
     The few overrides below that DO have a state over them (the sidebar
     opening, a schedule card's hover) restate that state beside them. */
  --field-edge: #b9c1ca;                                    /* a text box's border */
  --field-inset: inset 0 1px 2px rgba(20, 23, 28, 0.06);    /* and its recess */
  --well-edge: rgba(20, 23, 28, 0.14);        /* a control's or photo's edge in glass */
  --well-edge-hover: rgba(20, 23, 28, 0.24);
  --well-tint: rgba(20, 23, 28, 0.06);        /* an unlit chip's fill */
  --etch: rgba(20, 23, 28, 0.07);             /* a divider inside a panel */
  --nav-hover: rgba(20, 23, 28, 0.04);
  --nav-empty: #8a9099;                       /* a nav row with nothing behind it */
  --blank-ink: #666d75;                       /* the dash of a value not given */
  --glass-hover-wash: rgba(20, 23, 28, 0.02);
  --glass-shadow-hover: inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 22px 40px -22px rgba(20, 23, 28, 0.3);
  --act-bar-fill: linear-gradient(180deg, rgba(20, 23, 28, 0.22), rgba(20, 23, 28, 0.1));
  --act-bar-lip: inset 0 1px 0 rgba(255, 255, 255, 0.5);
  --glass-solid: #ffffff;                     /* glass, for reduced transparency */
}

/* The light behind the glass: the portal's four pools where they always were,
   at the app's light strengths (theme.ts, GLOWS.light). */
:root[data-theme='light'] body {
  background:
    radial-gradient(1000px 600px at 42% -10%, rgba(53, 199, 122, 0.2), transparent 64%),
    radial-gradient(760px 560px at 6% 22%, rgba(160, 210, 90, 0.075), transparent 62%),
    radial-gradient(860px 620px at 28% 104%, rgba(70, 180, 190, 0.11), transparent 64%),
    radial-gradient(760px 560px at 80% 30%, rgba(110, 150, 210, 0.07), transparent 66%),
    var(--bg-main);
  background-attachment: fixed;
}

/* The logo in the ink that reads on the page in use. Both are in the page;
   one is always out of it. */
:root:not([data-theme='light']) .on-light,
:root[data-theme='light'] .on-dark { display: none; }

/* The switch: a sun while dark, a moon while light. */
.theme-toggle .ic-moon { display: none; }
:root[data-theme='light'] .theme-toggle .ic-sun { display: none; }
:root[data-theme='light'] .theme-toggle .ic-moon { display: block; }

/* --- the base design's own literal colours -------------------------------- */

:root[data-theme='light'] .tag.ok,
:root[data-theme='light'] .basis-observed { border-color: #b3dcc3; }
:root[data-theme='light'] .tag.warn,
:root[data-theme='light'] .basis-modelled,
:root[data-theme='light'] .map-tile-error { border-color: #efd2ac; }
:root[data-theme='light'] .tag.alert { background: #fbe8e9; border-color: #f2c1c3; }
:root[data-theme='light'] .banner.lapsed { background: #fbe8e9; }
:root[data-theme='light'] .map-canvas .leaflet-control-attribution { background: rgba(255, 255, 255, 0.85); }
/* The count on the bell FILLS with the brand green, so it names it. */
:root[data-theme='light'] .bell-count { background: #35c77a; }

/* --- the glass layer's white alphas, as shade ----------------------------- */

:root[data-theme='light'] option,
:root[data-theme='light'] optgroup,
:root[data-theme='light'] .sub-move option { background: #ffffff; color: var(--text-primary); }
:root[data-theme='light'] .secondary,
:root[data-theme='light'] .seg { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7); }
:root[data-theme='light'] .sidebar {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.72), rgba(255, 255, 255, 0.5));
  border-right: 1px solid rgba(20, 23, 28, 0.08);
  box-shadow: none;
}
:root[data-theme='light'] .nav-item.active {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 4px 12px -6px rgba(20, 23, 28, 0.2);
}
:root[data-theme='light'] .sidebar-foot { border-top-color: rgba(20, 23, 28, 0.07); }
:root[data-theme='light'] .avatar {
  background: linear-gradient(155deg, #ffffff, #dfe5eb 60%, #eef1f5);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 0 0 1px rgba(20, 23, 28, 0.1);
}
:root[data-theme='light'] .search,
:root[data-theme='light'] .bell {
  border-color: rgba(20, 23, 28, 0.1);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8);
}
:root[data-theme='light'] tbody tr.clickable:hover { background: rgba(20, 23, 28, 0.035); }
:root[data-theme='light'] .cal-day { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7); }
:root[data-theme='light'] .cal-day:hover { background: var(--glass-well), rgba(20, 23, 28, 0.03); }
:root[data-theme='light'] .cal-row:hover { background: rgba(20, 23, 28, 0.04); }
/* Solid for a reader who asked for less transparency: the rest take
   `--glass-solid`; these two are overridden above, so they are restated. */
@media (prefers-reduced-transparency: reduce) {
  :root[data-theme='light'] .sidebar,
  :root[data-theme='light'] .signin-card { background: #ffffff; }
}
@media (hover: hover) and (min-width: 861px) {
  :root[data-theme='light'] .sidebar:hover,
  :root[data-theme='light'] .sidebar:focus-within {
    background-color: rgba(247, 249, 251, 0.9);
    box-shadow: inset -1px 0 0 rgba(20, 23, 28, 0.08), 24px 0 48px -12px rgba(20, 23, 28, 0.18);
  }
  :root[data-theme='light'] .nav-label::after { background: rgba(20, 23, 28, 0.14); }
}
:root[data-theme='light'] .topbar { background: var(--glass-fill), rgba(255, 255, 255, 0.6); }
:root[data-theme='light'] .progress-seg {
  box-shadow: inset 0 1px 2px rgba(20, 23, 28, 0.12), inset 0 0 0 1px rgba(20, 23, 28, 0.05);
}
:root[data-theme='light'] .share-bar { box-shadow: inset 0 1px 2px rgba(20, 23, 28, 0.12); }

/* Pills: the same tinted capsule, with its words darkened into the tone
   rather than lightened out of it. Half and half, not 55%: at 55% the green
   and teal words measured 4.5:1 on their own tint over white and 4.3:1 where
   the page's green light sits behind the glass — under AA for 11.5px text.
   At 50% the lowest of the six tones is 4.8:1 in that same worst place. */
:root[data-theme='light'] .pill,
:root[data-theme='light'] .tag,
:root[data-theme='light'] .chip {
  color: color-mix(in srgb, rgb(var(--tone)) 50%, #14171c);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.6), 0 0 12px -6px rgba(var(--tone), 0.5);
}
:root[data-theme='light'] .pill.tone-outline {
  color: var(--text-primary);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.95), rgba(255, 255, 255, 0.7));
  border-color: rgba(20, 23, 28, 0.16);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 1);
}

/* --- the screens added since ------------------------------------------------ */

:root[data-theme='light'] .answering .cond-group,
:root[data-theme='light'] .walk-group { border-color: rgba(20, 23, 28, 0.08); }
:root[data-theme='light'] .sched-card {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 10px 24px -14px rgba(20, 23, 28, 0.25);
}
:root[data-theme='light'] .sched-card:hover {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 16px 30px -14px rgba(20, 23, 28, 0.3);
}
:root[data-theme='light'] .act-track { box-shadow: inset 0 1px 2px rgba(20, 23, 28, 0.12); }
:root[data-theme='light'] .signin-card { background: var(--glass-fill), rgba(255, 255, 255, 0.6); }
:root[data-theme='light'] .signin-alt { border-top-color: rgba(20, 23, 28, 0.08); }
:root[data-theme='light'] .template-tray { border-color: rgba(20, 23, 28, 0.1); }
/* The drawn chevron on the rounded selects, in an ink that reads on a pale
   well: the dark set's #9aa3ad is 2.2:1 here, a hint rather than a mark;
   this is 5:1. */
:root[data-theme='light'] .controller-body select,
:root[data-theme='light'] .sysinfo-field select,
:root[data-theme='light'] .walk-field select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%235f666e' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
