/* theme.css: shared look for every page (docs/DEMO-REDESIGN.md, section 10).
   Cascade: tokens.css -> app.css (legacy, frozen) -> theme.css -> page css.
   v5: Instrument Sans, warm paper, navy ink, one flat blue accent (--green is its frozen name),
   1px borders instead of shadows, no gradients, one yellow for the demo strip, one green for success.
   Motion (entrances, bar fills, the tab underline) runs only under html.motion, which ui.js
   sets when the visitor has not asked for reduced motion. */

/* ---------- Re-point app.css legacy variables at the tokens ----------
   app.css redeclares these on :root after tokens.css, so set them again here. */
:root {
  --bg: var(--paper);
  --surface: var(--surface-1);
  --surface-2: var(--surface-sunk);
  --ink: var(--ink-1);
  --ink-2: #3a4354;
  --muted: var(--ink-soft);
  --line: var(--hairline);
  --line-strong: var(--hairline-strong);
  --brand: var(--green);
  --brand-strong: var(--green-deep);
  --brand-soft: var(--green-tint);
  --radius: var(--r-md);
  --radius-lg: var(--r-lg);
  --shadow: var(--shadow-card);
  --font: var(--font-text);
  --mono: var(--font-mono);

  --bad: #b42318; --bad-bg: #fdf0ef;
  --info: #1d4ed8; --info-bg: #eef3fd;
  --ok: var(--success); --ok-bg: var(--success-bg);
  --warn: var(--notice-ink); --warn-bg: var(--notice-bg); --warn-line: var(--notice-line);
  --demo: var(--notice-ink); --demo-bg: var(--notice-bg);
  --leaf: var(--green);
  --focus: 0 0 0 2px #fff, 0 0 0 4px var(--focus-ring);
}

/* ---------- Base ---------- */
html { scroll-padding-top: calc(var(--rl-header-h, 56px) + 56px); }
/* A non-visible overflow on html stops body's value from moving to the viewport, so body itself
   clips the full-bleed bands below. clip (not hidden) keeps the sticky header and tabs working. */
html { overflow-x: hidden; }
@supports (overflow: clip) { html { overflow-x: clip; } }
body {
  /* Page column for the chrome (strip, header, tabs, footer). Wide pages use 1400px below. */
  --page-col: 1100px;
  background: var(--paper);
  /* Belt and braces for anything that pokes past the column; clip keeps sticky headers working. */
  overflow-x: clip;
  color: var(--ink-1);
  font-family: var(--font-text);
  font-size: 1rem;
  line-height: 1.5;
}
::selection { background: var(--green-tint); color: var(--ink-1); }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -.005em;
  line-height: 1.3;
  color: var(--ink-1);
}
h1 { font-size: 2rem; font-weight: 600; line-height: 1.2; letter-spacing: -.01em; }
h2 { font-size: 1.25rem; letter-spacing: -.01em; }
h3 { font-size: 1.0625rem; }
h4 { font-size: 1rem; margin: 0 0 .5rem; }
@media (max-width: 560px) {
  h1 { font-size: 1.625rem; }
}
p { text-wrap: pretty; }
strong, b { font-weight: 600; }

a {
  color: var(--green);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  transition: color var(--dur-fast);
}
a:hover { color: var(--green-deep); }

:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; box-shadow: none; }

.muted { color: var(--ink-soft); }
.small { font-size: .875rem; }
.lead { font-size: 1.0625rem; line-height: 1.5; color: var(--ink-2); max-width: 68ch; }
.eyebrow {
  font-family: var(--font-text); font-size: .875rem; font-weight: 400; line-height: 1.4;
  text-transform: none; letter-spacing: 0; color: var(--ink-soft); margin: 0 0 4px;
}
.page-title { margin: 0 0 1rem; }
.mono, code, kbd { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
code, kbd {
  font-size: .875em; background: var(--surface-sunk); color: var(--ink-1);
  border: 1px solid var(--hairline); border-radius: var(--r-sm); padding: 1px 3px;
}

.skip-link {
  background: var(--night); color: var(--on-night); border-radius: var(--r-md);
  padding: 8px 12px; font-weight: 500; text-decoration: none;
}
.skip-link:hover { color: var(--on-night); }

/* ---------- Page header: h1, optional lede, optional actions on a full-bleed flat paper band ----------
   The band is a border-image outset 100vw to each side: it paints edge to edge but, unlike a wide
   pseudo-element, adds no scrollable overflow. main's 32px top padding is pulled back so the band
   starts right under the header or tabs. --grad-band is flat paper with a 1px hairline at the bottom. */
.page-head {
  position: relative; isolation: isolate;
  padding: 32px 0 24px;
  margin: -32px 0 28px;
  border-image: var(--grad-band) fill 0 // 0 100vw;
}
.page-head::before {
  content: ""; position: absolute; z-index: -1; inset: 0; pointer-events: none;
  background: var(--glow-band);
}
@media (max-width: 560px) {
  .page-head { padding: 24px 0 20px; margin-bottom: 20px; }
}
.page-head h1, .page-head .page-title { margin: 0; }
.page-head .eyebrow { margin: 0 0 4px; color: var(--ink-soft); }
.page-head .lead, .page-head > p { margin: 6px 0 0; max-width: 68ch; color: var(--ink-2); }
.page-head-actions { margin-top: 12px; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

/* ---------- Demo strip: plain notice line, aligned with the header column ---------- */
.demo-banner {
  display: block;
  background: var(--notice-bg); color: var(--notice-ink);
  border-bottom: 1px solid var(--notice-line);
  font-family: var(--font-text); font-size: .875rem; font-weight: 400; line-height: 1.4;
  letter-spacing: 0; text-align: left;
  padding: 8px max(1rem, calc((100% - var(--page-col)) / 2 + 1rem));
}
.demo-banner strong {
  display: inline; background: none; color: inherit; font-weight: 600;
  font-size: inherit; letter-spacing: 0; padding: 0; border: 0; border-radius: 0;
  margin: 0; /* the markup already has a space after </strong> */
}
.demo-banner strong::before { content: none; }

/* ---------- Site header: white, sticky, hairline ---------- */
.site-header {
  position: sticky; top: 0; z-index: 30;
  min-height: 56px;
  padding: 10px max(1rem, calc((100% - var(--page-col)) / 2 + 1rem));
  background: var(--surface-1);
  border-bottom: 1px solid var(--hairline);
  flex-wrap: wrap; column-gap: 12px; row-gap: 8px;
}
.wordmark { gap: 8px; color: var(--ink-1); border-radius: var(--r-sm); }
.wordmark:hover { color: var(--ink-1); }
.wordmark-text {
  font-family: var(--font-text); font-weight: 600; font-size: 1.0625rem; letter-spacing: -.01em;
  line-height: 1.25; color: var(--ink-1);
}
/* The logo is text only: a small blue square before "Repair Lab". No icon box. */
.wordmark-text::before {
  content: ""; display: inline-block; width: 6px; height: 6px; margin-right: 8px;
  background: var(--green); vertical-align: middle; position: relative; top: -1px;
}
.wordmark-text span { color: inherit; }
.tag-proto {
  font-family: var(--font-text); font-size: .8125rem; font-weight: 400; line-height: 1.25;
  text-transform: none; letter-spacing: 0; color: var(--ink-soft);
  background: none; border: 0; border-left: 1px solid var(--hairline-strong); border-radius: 0;
  padding: 0 0 0 10px; margin-left: 2px;
}
.header-actions { margin-left: auto; }
.whoami {
  font-size: .875rem; font-weight: 400; color: var(--ink-soft);
  padding: 0; border-radius: 0; background: none;
  max-width: 34ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (min-width: 900px) {
  .whoami { max-width: 56ch; }
}
@media (max-width: 560px) {
  .tag-proto { font-size: .8125rem; }
}

main { padding: 32px 16px 24px; }

/* ---------- Tabs: plain 2px blue underline, sticky under the header ----------
   Tab text lines up with the wordmark: container inset + tab padding = column edge. */
.tabs {
  top: var(--rl-header-h, 56px); z-index: 25;
  gap: 0;
  padding: 0 max(4px, calc((100% - var(--page-col)) / 2 + 4px));
  background: var(--surface-1);
  border-bottom: 1px solid var(--hairline);
  overflow-x: auto; scrollbar-width: none; scroll-padding-inline: 16px;
  -webkit-mask-image: none; mask-image: none;
}
.tabs::-webkit-scrollbar { display: none; }
/* Wide pages (kiosk, teacher, staff, badges) use main.wide (1400px): line the chrome up with it. */
body:has(main.wide) .demo-banner { padding-inline: max(1rem, calc((100% - 1400px) / 2 + 1rem)); }
body:has(main.wide) .site-header { padding-inline: max(1rem, calc((100% - 1400px) / 2 + 1rem)); }
body:has(main.wide) .tabs { padding-inline: max(4px, calc((100% - 1400px) / 2 + 4px)); }
body:has(main.wide) .site-footer { max-width: none; padding-inline: max(1rem, calc((100% - 1400px) / 2 + 1rem)); }
.tab {
  position: relative; flex: none; white-space: nowrap;
  font-family: var(--font-text); font-size: .9375rem; font-weight: 500; line-height: 1.5;
  color: var(--ink-soft); background: transparent;
  padding: 12px 12px 10px; min-height: 44px;
  border: 0; border-bottom: 2px solid transparent; border-radius: 0;
  transition: color var(--dur-fast), border-color var(--dur-fast);
}
.tab:hover { color: var(--ink-1); background: transparent; }
.tab[aria-selected="true"] { color: var(--ink-1); font-weight: 600; border-bottom-color: var(--green); }
.tab:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; box-shadow: none; border-radius: 0; }
/* ui.js adds .has-indicator and one .tab-indicator that slides to the selected tab.
   The static underline above is the no-JS fallback. */
.tabs.has-indicator .tab[aria-selected="true"] { border-bottom-color: transparent; }
.tab-indicator {
  position: absolute; left: 0; bottom: 0; height: 2px; width: 1px;
  background: var(--green); border-radius: 0;
  transform-origin: 0 50%; pointer-events: none;
  transform: translateX(var(--x, 0)) scaleX(var(--w, 0));
}
html.motion .tabs.indicator-ready .tab-indicator { transition: transform var(--dur-med) var(--ease-out); }
@media (max-width: 560px) {
  .tabs, body:has(main.wide) .tabs { padding-inline: 6px; }
  .tab { padding: 10px 10px 8px; font-size: .875rem; }
}

/* ---------- Cards ---------- */
.card {
  background: var(--surface-1); border: 1px solid var(--hairline); border-radius: var(--r-lg);
  padding: 20px; box-shadow: none; margin-bottom: 16px;
}
.grid { gap: 16px; margin-bottom: 16px; }
.card-head { align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
.card-head > h2, .card-head > h3 { margin: 0; }
/* Interactive cards only darken their border on hover: no lift, no shadow. */
a.card, button.card, .card.is-interactive, .item-card.is-interactive {
  transition: border-color var(--dur-fast);
}
a.card { color: var(--ink-1); text-decoration: none; }
a.card:hover, button.card:hover, .card.is-interactive:hover, .item-card.is-interactive:hover {
  border-color: var(--hairline-strong); box-shadow: none;
}
details.card > summary { cursor: pointer; font-weight: 600; }

/* ---------- Disclosures: one small chevron for every <details> on every page ----------
   Replaces the browser's black triangle. Points right when closed, down when open.
   staff.css keeps its own scoped copy for the flex-layout summaries on dashboards. */
details > summary { list-style: none; cursor: pointer; }
details > summary::-webkit-details-marker { display: none; }
details > summary::marker { content: ""; }
details > summary::before {
  content: ""; display: inline-block; width: 6px; height: 6px; margin: 0 8px 0 2px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg); vertical-align: 2px;
}
details[open] > summary::before { transform: rotate(45deg); vertical-align: 3px; }
@media (max-width: 560px) {
  .card { padding: 16px; }
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 40px; padding: 4px 16px; border-radius: var(--r-md);
  font-family: var(--font-text); font-size: .9375rem; font-weight: 600; line-height: 1.2;
  letter-spacing: -.005em; text-decoration: none;
  background: var(--green); border: 1px solid var(--green); color: #fff;
  box-shadow: none;
  transition: background-color var(--dur-fast), border-color var(--dur-fast), color var(--dur-fast);
}
.btn:not(:disabled):not([aria-disabled="true"]):hover {
  background: var(--green-deep); border-color: var(--green-deep); color: #fff;
}
.btn:disabled, .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }
.btn[aria-busy="true"] { cursor: progress; }

.btn-secondary {
  background: var(--surface-1); color: var(--ink-1); border-color: var(--hairline-strong);
  box-shadow: none;
}
.btn-secondary:not(:disabled):not([aria-disabled="true"]):hover {
  background: var(--surface-sunk); color: var(--ink-1); border-color: var(--hairline-strong);
}
.btn-ghost { background: transparent; color: var(--ink-2); border-color: transparent; box-shadow: none; }
.btn-ghost:not(:disabled):not([aria-disabled="true"]):hover {
  background: var(--surface-sunk); color: var(--ink-1); border-color: transparent;
}
.btn-danger { background: var(--bad); border-color: var(--bad); color: #fff; box-shadow: none; }
.btn-danger:not(:disabled):not([aria-disabled="true"]):hover {
  background: #8f1c13; border-color: #8f1c13; color: #fff;
}
/* Disabled buttons do not react to hover (app.css :hover rules would otherwise still apply). */
.btn:is(:disabled, [aria-disabled="true"]):hover { background: var(--green); border-color: var(--green); color: #fff; }
.btn-secondary:is(:disabled, [aria-disabled="true"]):hover { background: var(--surface-1); border-color: var(--hairline-strong); color: var(--ink-1); }
.btn-ghost:is(:disabled, [aria-disabled="true"]):hover { background: transparent; border-color: transparent; color: var(--ink-2); }
.btn-danger:is(:disabled, [aria-disabled="true"]):hover { background: var(--bad); border-color: var(--bad); color: #fff; }
.btn:is(:disabled, [aria-disabled="true"]):not([aria-busy="true"]),
.btn:is(:disabled, [aria-disabled="true"]):not([aria-busy="true"]):hover {
  opacity: 1; background: var(--surface-sunk); border-color: var(--hairline); color: var(--ink-soft); box-shadow: none;
}

.btn-small { min-height: 32px; padding: 2px 12px; font-size: .875rem; }
.btn-big { min-height: 48px; padding: 6px 20px; font-size: 1rem; }
.btn-block { width: 100%; }

/* ---------- Forms ---------- */
.field { gap: 6px; margin-bottom: 16px; }
.field label, .label { font-size: .875rem; font-weight: 500; color: var(--ink-1); }
.hint { font-size: .8125rem; color: var(--ink-soft); }
input[type="text"], input[type="password"], input[type="number"], input[type="date"], input[type="time"],
input[type="datetime-local"], input[type="search"], input[type="email"], select, textarea {
  min-height: 40px; padding: 8px 12px; border-radius: var(--r-md);
  border: 1px solid var(--input-line, #7a7f8a); background-color: var(--surface-1); color: var(--ink-1);
  font-family: var(--font-text); font-size: 1rem; line-height: 1.25;
  box-shadow: none;
  transition: border-color var(--dur-fast);
}
textarea { line-height: 1.5; }
input:not([type="radio"]):not([type="checkbox"]):hover, select:hover, textarea:hover { border-color: var(--ink-soft); }
input:not([type="radio"]):not([type="checkbox"]):focus, select:focus, textarea:focus {
  border-color: var(--focus-ring); border-radius: var(--r-md); box-shadow: none;
  outline: 2px solid color-mix(in srgb, var(--focus-ring) 35%, transparent); outline-offset: 0;
}
input[aria-invalid="true"], input[aria-invalid="true"]:not([type="radio"]):not([type="checkbox"]):focus {
  border-color: var(--bad); box-shadow: none;
}
input[aria-invalid="true"]:not([type="radio"]):not([type="checkbox"]):focus {
  outline-color: color-mix(in srgb, var(--bad) 35%, transparent);
}
select {
  -webkit-appearance: none; appearance: none; padding-right: 36px;
  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='%235a6272' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center; background-size: 12px 8px;
}
/* input.input-code (0,1,1), later in source, beats the generic input[type="text"] rules here and in app.css. */
.input-code, input.input-code { font-family: var(--font-mono); font-size: 1.125rem; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; }
input.input-code { min-height: 48px; }
fieldset { border: 0; border-radius: 0; padding: 0; margin: 0 0 16px; min-width: 0; }
legend { font-family: var(--font-text); font-size: 1rem; font-weight: 600; line-height: 1.4; color: var(--ink-1); }

.check, .radio {
  border: 1px solid var(--hairline-strong); border-radius: var(--r-md); padding: 10px 12px;
  background: var(--surface-1);
  transition: border-color var(--dur-fast), background-color var(--dur-fast);
}
.check:hover, .radio:hover { border-color: var(--ink-soft); }
.check input, .radio input { accent-color: var(--green); }
.radio:has(input:checked), .check:has(input:checked) { border-color: var(--green); background: var(--green-tint); }
.radio:has(input:focus-visible), .check:has(input:focus-visible) {
  outline: 2px solid var(--focus-ring); outline-offset: 2px; box-shadow: none;
}
/* The option card carries the ring, so the box inside it does not draw a second one. */
.radio:has(input:focus-visible) input, .check:has(input:focus-visible) input { outline: none; }

/* Switch: app.css mechanics. The 1px inset edge keeps the off state visible (3:1). */
.switch input {
  background: var(--hairline-strong); box-shadow: inset 0 0 0 1px var(--ink-soft);
  transition: background-color var(--dur-fast), box-shadow var(--dur-fast);
}
.switch input::after { box-shadow: 0 1px 1px rgba(28, 36, 51, .2); transition: transform 120ms ease-out; }
.switch input:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; box-shadow: inset 0 0 0 1px var(--ink-soft); }
.switch input:checked { background: var(--green); box-shadow: inset 0 0 0 1px var(--green); }

/* ---------- Messages: 1px border in the matching line colour ---------- */
.msg {
  border: 1px solid var(--hairline); border-radius: var(--r-md);
  padding: 10px 14px; line-height: 1.5;
}
.msg-ok { background: var(--success-bg); border-color: var(--success-line); color: var(--success); }
.msg-warn { background: var(--notice-bg); border-color: var(--notice-line); color: var(--notice-ink); }
.msg-bad { background: var(--bad-bg); border-color: var(--bad-line); color: var(--bad); }
.msg-info { background: var(--info-bg); border-color: var(--info-line); color: var(--info); }

/* ---------- Chips: small 4px-radius status labels ---------- */
.chip {
  display: inline-flex; align-items: center; gap: 4px;
  font-family: var(--font-text); font-size: .8125rem; font-weight: 500; line-height: 1.4;
  letter-spacing: 0; text-transform: none;
  padding: 2px 8px; border-radius: var(--r-sm); border: 1px solid var(--hairline);
}
.chip-ok::before, .chip-warn::before, .chip-bad::before, .chip-info::before { content: none; }
.chip-ok { color: var(--success); background: var(--success-bg); border-color: var(--success-line); }
.chip-warn { color: var(--notice-ink); background: var(--notice-bg); border-color: var(--notice-line); }
.chip-bad { color: var(--bad); background: var(--bad-bg); border-color: var(--bad-line); }
.chip-info { color: var(--info); background: var(--info-bg); border-color: var(--info-line); }
.chip-neutral { color: var(--ink-2); background: var(--surface-sunk); border-color: var(--hairline); }
.chip-demo { color: var(--notice-ink); background: var(--notice-bg); border-color: var(--notice-line); }

.empty {
  text-align: center; color: var(--ink-soft); padding: 24px 16px;
  border: 1px dashed var(--hairline-strong); border-radius: var(--r-lg); background: none;
}
.loading { color: var(--ink-soft); }
.loading::before {
  content: ""; display: inline-block; width: .8em; height: .8em; margin-right: .5em; vertical-align: -.05em;
  border-radius: 50%; border: 2px solid var(--hairline-strong); border-top-color: var(--green);
}
html.motion .loading::before { animation: rl-spin .8s linear infinite; }

/* ---------- Tables ---------- */
.table-wrap {
  border: 1px solid var(--hairline); border-radius: var(--r-lg); background: var(--surface-1);
  box-shadow: none; overflow: auto;
}
table { font-size: .9375rem; }
th, td { padding: 10px 12px; border-bottom: 1px solid var(--hairline); }
th {
  background: var(--surface-sunk); font-family: var(--font-text); font-size: .8125rem; font-weight: 500;
  text-transform: none; letter-spacing: 0; color: var(--ink-soft); padding: 8px 12px;
}
tbody th {
  background: transparent; font-size: .9375rem; font-weight: 500; color: var(--ink-1);
  text-transform: none; letter-spacing: 0; padding: 10px 12px;
}
caption {
  caption-side: top; text-align: left; font-size: .875rem; font-weight: 500;
  color: var(--ink-soft); padding: 8px 12px;
}
tbody tr { transition: background-color var(--dur-fast); }
tbody tr:hover > td, tbody tr:hover > th { background: var(--paper); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
/* Opt-in sticky header: give the wrapper a max height so it scrolls. */
.table-wrap.is-tall { max-height: 70vh; overflow: auto; }
.table-wrap.is-tall thead th { position: sticky; top: 0; z-index: 1; }

/* ---------- Progress: thin flat bars, hatched pending ---------- */
.hours-bar {
  height: 8px; border: 0; border-radius: 4px; background: var(--surface-sunk); gap: 2px;
  box-shadow: inset 0 0 0 1px var(--hairline);
}
.hours-bar .seg { border-radius: 0; transform-origin: 0 50%; }
.hours-bar .seg-verified { background: var(--green); }
.hours-bar .seg-pending, .sw-pending {
  background: repeating-linear-gradient(-45deg, var(--orange) 0 4px, var(--orange-tint) 4px 8px);
}
.legend { gap: 8px 20px; font-size: .875rem; color: var(--ink-2); margin-top: 12px; }
.legend .sw, .sw { width: 10px; height: 10px; border-radius: 2px; }
.legend .sw { margin-right: 6px; vertical-align: 0; }
.sw-verified { background: var(--green); }
.sw-left { background: var(--surface-sunk); border: 1px solid var(--hairline-strong); }
.sw-target { background: var(--ink-1); }
.seat-meter { height: 6px; border-radius: 3px; background: var(--surface-sunk); box-shadow: none; }
.seat-meter span { background: var(--green); border-radius: 3px; transform-origin: 0 50%; }
.target-bar { height: 6px; border-radius: 3px; background: var(--surface-sunk); box-shadow: none; }
.target-bar .fill { background: var(--green); border-radius: 3px; transform-origin: 0 50%; }
.target-bar .mark {
  background: var(--ink-1); width: 2px; top: -4px; bottom: -4px; border-radius: 0;
  left: calc(min(var(--tpct, 100), 100) * 1% - 1px);
}
.target-bar .mark-label { top: 12px; color: var(--ink-soft); }

.big-number, .metric-value, .score-ring {
  font-family: var(--font-text); font-weight: 600; letter-spacing: 0;
  font-variant-numeric: tabular-nums; line-height: 1.1;
}
.score-ring { font-size: 2.25rem; }
.big-number small, .metric-value small {
  font-family: var(--font-text); font-size: .875rem; font-weight: 400; letter-spacing: 0; color: var(--ink-soft);
}

/* ---------- Checklist ---------- */
.gates li { gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--hairline); align-items: flex-start; }
.gate-icon {
  width: 22px; height: 22px; margin-top: 1px; border-radius: 50%;
  font-family: var(--font-text); font-size: .8125rem; font-weight: 600; letter-spacing: 0;
}
.gate-icon svg { width: 12px; height: 12px; display: block; }
.gate-icon.ok { background: var(--success); color: #fff; border: 1px solid var(--success); box-shadow: none; }
.gate-icon.no { background: var(--warn-bg); color: var(--warn); border: 1px solid var(--warn-line); }

/* ---------- Lists ---------- */
.list { gap: 12px; }
.item-card {
  background: var(--surface-1); border: 1px solid var(--hairline); border-radius: var(--r-lg);
  padding: 16px; gap: 8px; box-shadow: none;
}
.item-card.is-mine { border-color: var(--green); box-shadow: none; }
.item-title { font-family: var(--font-text); font-size: 1rem; font-weight: 600; letter-spacing: 0; }
.item-card form.card {
  background: var(--surface-sunk); border: 1px solid var(--hairline); box-shadow: none; padding: 16px;
}

/* ---------- Dialog: never set display on dialog itself ---------- */
dialog {
  border: 1px solid var(--hairline); border-radius: var(--r-xl); background: var(--surface-1);
  box-shadow: var(--shadow-pop); color: var(--ink-1); padding: 0;
}
dialog::backdrop { background: rgba(28, 36, 51, .4); }
.dialog-body { padding: 20px 20px 16px; }
.dialog-body h2 { font-size: 1.125rem; margin-bottom: 8px; }
.dialog-actions { gap: 8px; padding: 0 20px 20px; }

/* ---------- Misc shared bits ---------- */
.definition, .key-points {
  background: var(--surface-sunk); border: 1px solid var(--hairline); border-radius: var(--r-md);
}
.definition { padding: 8px 12px; font-size: .875rem; color: var(--ink-2); }
.key-points { padding: 10px 14px; }
.key-points h4, .key-points h3 {
  font-size: .875rem; font-weight: 600; color: var(--ink-1);
  text-transform: none; letter-spacing: 0; margin: 0 0 4px;
}
.code-reveal {
  background: var(--surface-sunk); border: 1px solid var(--hairline); border-radius: var(--r-md);
  padding: 12px 16px; gap: 8px;
}
.code-reveal .badge-code {
  font-family: var(--font-mono); font-size: 1.125rem; font-weight: 500; letter-spacing: .08em;
  background: var(--surface-1); border: 1px solid var(--hairline); border-radius: var(--r-md);
  padding: 8px 12px; margin: 0;
}
.kv dt { font-size: .875rem; font-weight: 500; color: var(--ink-soft); }
.kv dd { color: var(--ink-1); }
.quiz-q .topic {
  font-size: .8125rem; font-weight: 500; text-transform: none; letter-spacing: 0; color: var(--ink-soft);
}

/* ---------- Footer: light, paper with a hairline on top, same column as the header ---------- */
.site-footer {
  max-width: none; margin: 48px auto 0; background: var(--paper);
  padding: 16px max(1rem, calc((100% - var(--page-col)) / 2 + 1rem));
  border-top: 1px solid var(--hairline); color: var(--ink-soft); font-size: .8125rem;
  display: flex; flex-wrap: wrap; gap: 4px 16px; align-items: baseline;
}

/* ---------- Defensive floor for legacy app.css rules (page css refines) ----------
   app.css sets weights of 700 to 800, negative tracking and uppercase labels on these.
   Selectors repeat app.css specificity so they win. */
.gate-icon, .verified-stamp, .record-total,
.sb-icon, .sb-title, .scan-banner .sb-icon, .scan-banner .sb-title,
.role-name, .role-btn .role-name, .badge-name, .badge-card .bc-name, .unit-counts dd, .mini-chart .val,
.quiz-q legend, .bc-demo, .badge-card .bc-demo {
  font-weight: 600; letter-spacing: 0;
}
/* Codes keep a little tracking so they are easy to read aloud. */
.badge-code, .bc-code, .badge-card .bc-code { font-weight: 500; letter-spacing: .08em; }
.roster-group-title, .badge-card .bc-org { text-transform: none; letter-spacing: 0; font-weight: 600; }
.notice { font-weight: 500; }

/* ---------- v7 layer: calm and neutral ----------
   One blue accent, Instrument Sans, 8px buttons, cards with a border and a hairline shadow,
   white page headers. Later rules win. */
:root {
  --grad-band: linear-gradient(180deg, #fff calc(100% - 1px), var(--hairline) calc(100% - 1px));
}
h1, h2, h3 { font-family: var(--font-display); font-weight: 600; letter-spacing: -.02em; }
h1 { font-size: clamp(1.75rem, 1.4rem + 1.2vw, 2.25rem); line-height: 1.1; }
h2 { font-size: 1.3rem; }
h4, legend, .item-title, .card-head > h3 { font-family: var(--font-text); letter-spacing: -.005em; }

/* Logo: violet tile with a wrench (img/logo-mark.svg) before "Repair Lab" */
.site-header {
  background: rgba(255, 255, 255, .92);
  -webkit-backdrop-filter: saturate(1.4) blur(12px); backdrop-filter: saturate(1.4) blur(12px);
  border-bottom-color: var(--hairline);
}
.wordmark { gap: 10px; }
.wordmark-text {
  display: inline-flex; align-items: center; gap: 0; white-space: pre;
  font-family: var(--font-display); font-weight: 600; font-size: 1.125rem; letter-spacing: -.02em;
}
.wordmark-text::before {
  width: 26px; height: 26px; margin: 0 10px 0 0; top: 0; flex: none;
  background: url("../img/logo-mark.svg") center / contain no-repeat;
  border-radius: 9px;
}
.wordmark-text span { color: inherit; }
.tag-proto {
  border: 1px solid var(--hairline); padding: 2px 8px; margin: 0; border-radius: var(--r-pill);
  background: var(--surface-1); color: var(--ink-soft); font-size: .75rem; font-weight: 500;
}

/* Tabs: violet text and a rounded 3px underline on the selected tab */
.tabs { background: rgba(255, 255, 255, .86); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); }
.tab[aria-selected="true"] { color: var(--ink-1); }
.tab-indicator { height: 2px; border-radius: 0; }

/* Cards: big radius and a soft shadow */
.card, .item-card, .table-wrap {
  border-color: var(--hairline); border-radius: var(--r-lg); box-shadow: var(--shadow-card);
}
.card { padding: 24px; }
a.card, button.card, .card.is-interactive, .item-card.is-interactive {
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast), border-color var(--dur-fast);
}
a.card:hover, button.card:hover, .card.is-interactive:hover, .item-card.is-interactive:hover {
  box-shadow: var(--shadow-lift); border-color: var(--hairline-strong);
}
.item-card form.card { box-shadow: none; border-radius: var(--r-md); }
@media (max-width: 560px) { .card { padding: 18px; } }

/* Buttons: pills. Primary is violet with a soft violet shadow. */
.btn {
  border-radius: var(--r-md); padding: 4px 16px; min-height: 40px;
  box-shadow: 0 1px 2px rgba(24, 24, 27, .08);
  transition: background-color var(--dur-fast), border-color var(--dur-fast), color var(--dur-fast),
    transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast);
}
.btn:not(:disabled):not([aria-disabled="true"]):hover { box-shadow: 0 1px 2px rgba(24, 24, 27, .08); }
.btn-secondary { box-shadow: 0 1px 2px rgba(27, 24, 56, .06); border-color: var(--hairline-strong); }
.btn-secondary:not(:disabled):not([aria-disabled="true"]):hover {
  background: var(--surface-sunk); border-color: var(--hairline-strong); color: var(--ink-1); box-shadow: 0 1px 2px rgba(24, 24, 27, .06);
}
.btn-ghost, .btn-ghost:not(:disabled):not([aria-disabled="true"]):hover { box-shadow: none; transform: none; }
.btn-danger { box-shadow: none; }
.btn-small { min-height: 34px; padding: 2px 12px; }
.btn-big { min-height: 48px; padding: 6px 22px; font-size: 1rem; }
.btn:is(:disabled, [aria-disabled="true"]):not([aria-busy="true"]) { transform: none; }

/* Inputs, choices, messages, chips */
input[type="text"], input[type="password"], input[type="number"], input[type="date"], input[type="time"],
input[type="datetime-local"], input[type="search"], input[type="email"], select, textarea { border-radius: var(--r-md); }
.check, .radio { border-radius: var(--r-md); }
.msg { border-radius: var(--r-md); }
.chip { border-radius: var(--r-pill); padding-inline: 10px; }
.definition, .key-points, .code-reveal { border-radius: var(--r-md); }
.code-reveal .badge-code { border-radius: var(--r-sm); }
.empty { border-radius: var(--r-lg); }

/* Progress: thick rounded bars */
.hours-bar { height: 10px; border-radius: var(--r-pill); box-shadow: none; overflow: hidden; }
.hours-bar .seg:first-child { border-radius: var(--r-pill) 0 0 var(--r-pill); }
.hours-bar .seg-verified { background: var(--green); }
.seat-meter, .target-bar { height: 8px; border-radius: var(--r-pill); }
.seat-meter span, .target-bar .fill { border-radius: var(--r-pill); }
.legend .sw, .sw { border-radius: 50%; }

.big-number, .metric-value, .score-ring { font-family: var(--font-display); font-weight: 600; letter-spacing: -.02em; }
.gate-icon.ok { background: var(--success); border-color: var(--success); }

dialog { border-radius: var(--r-xl); }
.site-footer { background: transparent; }

/* ---------- Print ---------- */
@media print {
  /* Restate app.css's print body: the screen body rule above would otherwise win. */
  body { background: #fff; color: #000; font-size: 11pt; }
  .reveal, .card { opacity: 1 !important; transform: none !important; }
  .card { border: 0; box-shadow: none; padding: 0; }
  main { padding: 0; }
  .page-head { margin: 0 0 16px; padding: 0 0 12px; border-image: none; border-bottom: 1px solid #000; }
  .page-head::before { display: none; }
  .btn { box-shadow: none; }
  .site-header, .tabs, .site-footer { display: none !important; }
  .site-header { position: static; }
  .tab-indicator { display: none !important; }
  .demo-banner { display: block; background: #fff; color: #000; border: 2px solid #000; }
  .demo-banner strong { color: #000; }
  .demo-banner strong::before { display: none; }
  .msg, .chip { animation: none; }
}

/* ---------- Motion: only under html.motion (ui.js), never for reduced motion ----------
   Panels rise in when shown (tab switches re-run it), bars fill from the left once.
   Data transforms (scaleX(var(--p)) etc.) are the end state, so the bars still show the right value. */
@keyframes rl-spin { to { transform: rotate(360deg); } }
@keyframes rl-rise { from { opacity: 0; transform: translateY(14px); } }
@keyframes rl-fade { from { opacity: 0; } }
@keyframes rl-grow { from { transform: scaleX(0); } }
html.motion .page-head > *, html.motion .hero > * { animation: rl-rise var(--dur-slow) var(--ease-out) backwards; }
html.motion .page-head > :nth-child(2), html.motion .hero > :nth-child(2) { animation-delay: 60ms; }
html.motion .page-head > :nth-child(n+3), html.motion .hero > :nth-child(n+3) { animation-delay: 120ms; }
html.motion:not(.settled) main :is(.card, .table-wrap, .item-card) {
  animation: rl-rise var(--dur-slow) var(--ease-out) 120ms backwards;
}
html.motion:not(.settled) main .grid > :nth-child(2) { animation-delay: 180ms; }
html.motion:not(.settled) main .grid > :nth-child(3) { animation-delay: 240ms; }
html.motion:not(.settled) main .grid > :nth-child(n+4) { animation-delay: 300ms; }
html.motion .tab-panel.is-entering { animation: rl-rise var(--dur-med) var(--ease-out); }
html.motion:not(.settled) :is(.hours-bar .seg, .seat-meter span, .target-bar .fill) {
  animation: rl-grow 1s var(--ease-out) 300ms backwards;
}
html.motion:not(.settled) .hours-bar .seg-pending { animation-delay: 600ms; }
html.motion .msg-ok, html.motion .msg-warn, html.motion .msg-bad, html.motion .msg-info {
  animation: rl-fade var(--dur-med) var(--ease-out) backwards;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0s !important; animation: none !important; }
}
