/* Aval Nalam field register — design system.
 *
 * Lifted from the approved mockup at docs/mockups/index.html so the built application is
 * visually identical to what the client signed off on. Rose-plum accent for the programme
 * identity; semantic green/amber/red reserved for record state, never for branding.
 *
 * Hand-written rather than generated: the whole file is smaller than a utility framework's
 * runtime, and this project ships to tablets on 2G.
 */
html, body { margin: 0; padding: 0; }
  :root {
    /* Page measure and the two gaps every page is built from. */
    --measure: 1180px;
    /* Overwritten with the real content width by app.js; 100vw is the fallback. */
    --vw: 100vw;
    /* Height of the horizontal nav, which the sticky page head has to clear. */
    --nav-h: 47px;
    --gap-page: 20px;
    --gap-card: 18px;

    --ground: #F8F4F6;
    --surface: #FFFFFF;
    --surface-2: #F0E9EC;
    --ink: #201823;
    --ink-2: #5A4E58;
    --ink-3: #8A7C85;
    --line: #E0D6DB;
    --line-strong: #C9BBC2;
    --accent: #8E2F5B;
    --accent-ink: #74254A;
    --accent-soft: #F7E4EC;
    --clay: #7A4A96;
    --clay-soft: #EFE6F5;
    --ok: #2C7551;
    --ok-soft: #DFEDE5;
    --warn: #96660F;
    --warn-soft: #F5EAD3;
    --crit: #A93725;
    --crit-soft: #F7E2DD;
    --shadow: 0 1px 2px rgba(32,24,35,.06), 0 8px 24px -12px rgba(32,24,35,.20);
    --radius: 6px;
    --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
    --mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      --ground: #141017;
      --surface: #1C161F;
      --surface-2: #251E28;
      --ink: #EDE6EB;
      --ink-2: #ADA0AA;
      --ink-3: #837783;
      --line: #322A36;
      --line-strong: #443A48;
      --accent: #E58BB2;
      --accent-ink: #F0AECA;
      --accent-soft: #3A1C2A;
      --clay: #BC96D8;
      --clay-soft: #271D30;
      --ok: #5CBB8C;
      --ok-soft: #16291F;
      --warn: #D3A143;
      --warn-soft: #2B2417;
      --crit: #DE7361;
      --crit-soft: #2E1B18;
      --shadow: 0 1px 2px rgba(0,0,0,.5), 0 10px 28px -14px rgba(0,0,0,.7);
    }
  }
  :root[data-theme="dark"] {
    --ground: #141017;
    --surface: #1C161F;
    --surface-2: #251E28;
    --ink: #EDE6EB;
    --ink-2: #ADA0AA;
    --ink-3: #837783;
    --line: #322A36;
    --line-strong: #443A48;
    --accent: #E58BB2;
    --accent-ink: #F0AECA;
    --accent-soft: #3A1C2A;
    --clay: #BC96D8;
    --clay-soft: #271D30;
    --ok: #5CBB8C;
    --ok-soft: #16291F;
    --warn: #D3A143;
    --warn-soft: #2B2417;
    --crit: #DE7361;
    --crit-soft: #2E1B18;
    --shadow: 0 1px 2px rgba(0,0,0,.5), 0 10px 28px -14px rgba(0,0,0,.7);
  }

  * { box-sizing: border-box; }
  body {
    margin: 0;
    background: var(--ground);
    color: var(--ink);
    font-family: var(--sans);
    font-size: 14px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
  }
  h1, h2, h3, h4 { margin: 0; text-wrap: balance; font-weight: 600; }
  p { margin: 0; }
  button { font: inherit; color: inherit; }
  code, .mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }

  /* ---------- App shell ---------- */
  .app { display: grid; grid-template-columns: 248px 1fr; min-height: 100vh; }

  .rail {
    background: var(--surface);
    border-right: 1px solid var(--line);
    display: flex; flex-direction: column;
    position: sticky; top: 0; height: 100vh; overflow-y: auto;
  }
  .brand { padding: 20px 18px 16px; border-bottom: 1px solid var(--line); }
  .brand .mark {
    font-family: var(--serif); font-size: 19px; letter-spacing: .01em; line-height: 1.15;
  }
  .brand .mark em { font-style: normal; color: var(--accent); }
  .brand .sub {
    margin-top: 4px; font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase;
    color: var(--ink-3);
  }

  .role-box { padding: 14px 18px; border-bottom: 1px solid var(--line); background: var(--surface-2); }
  .field-label {
    display: block; font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase;
    color: var(--ink-3); margin-bottom: 6px; font-weight: 600;
  }
  select,
  input[type="text"], input[type="tel"], input[type="number"],
  input[type="date"], input[type="email"], input[type="password"], input[type="search"],
  textarea {
    width: 100%; padding: 7px 9px; background: var(--surface); color: var(--ink);
    border: 1px solid var(--line-strong); border-radius: var(--radius);
    font: inherit;
  }
  select:focus-visible, input:focus-visible, textarea:focus-visible, button:focus-visible, .navlink:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 1px;
  }
  .scope-note {
    margin-top: 8px; font-size: 11.5px; color: var(--ink-2); line-height: 1.4;
  }
  .scope-note strong { color: var(--ink); font-weight: 600; }

  nav.menu { padding: 8px 10px 24px; display: flex; flex-direction: column; gap: 2px; }
  .menu-group {
    font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
    padding: 15px 8px 6px; font-weight: 700;
  }
  .navlink {
    position: relative;
    display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
    padding: 8px 10px; border: 0; background: none; border-radius: 7px;
    cursor: pointer; color: var(--ink-2);
  }
  .navlink:hover { background: var(--surface-2); color: var(--ink); }
  .navlink .ico { width: 17px; height: 17px; flex: none; color: var(--ink-3); }
  .navlink .txt { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
  .navlink .t1 { font-size: 13.5px; font-weight: 500; }
  .navlink .t2 { font-size: 10px; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-3); margin-top: 1px; }
  .navlink .badge {
    margin-left: auto; flex: none; min-width: 20px; text-align: center;
    font-family: var(--mono); font-size: 10.5px; font-weight: 700;
    padding: 1px 6px; border-radius: 100px;
    background: var(--surface-2); color: var(--ink-2);
  }
  .navlink .badge.hot { background: var(--crit-soft); color: var(--crit); }
  .navlink:hover .badge { background: var(--surface); }
  .navlink[aria-current="true"] {
    background: var(--accent-soft); color: var(--accent-ink); font-weight: 600;
  }
  .navlink[aria-current="true"]::before {
    content: ""; position: absolute; left: 0; top: 7px; bottom: 7px;
    width: 3px; border-radius: 0 3px 3px 0; background: var(--accent);
  }
  .navlink[aria-current="true"] .ico,
  .navlink[aria-current="true"] .t2 { color: var(--accent); }
  .navlink[aria-current="true"] .t1 { font-weight: 600; }
  .navlink[data-locked="true"] { opacity: .42; cursor: not-allowed; }
  .navlink[data-gated="true"] .ico { color: var(--warn); }
  /* class-level display would otherwise beat the UA [hidden] rule */
  .navlink[hidden], .menu-group[hidden] { display: none; }

  /* ---------- Main ---------- */
  main { min-width: 0; }
  .topbar {
    display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
    padding: 12px 28px; border-bottom: 1px solid var(--line);
    background: var(--surface); position: sticky; top: 0; z-index: 5;
  }
  .breadcrumb { font-size: 12px; color: var(--ink-3); }
  .breadcrumb b { color: var(--ink); font-weight: 600; }
  .topbar .spacer { flex: 1; }
  .camp-chip {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 4px 10px; border: 1px solid var(--line-strong); border-radius: 100px;
    font-size: 12px; background: var(--ground);
  }
  .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); flex: none; }

  /* Canvas, page head and card rhythm all live in one place further down, so the page
     measure cannot be set twice with two different answers. */
  .page-head h1 { font-family: var(--serif); font-size: 25px; letter-spacing: -.01em; }
  .page-head .lede { margin-top: 6px; color: var(--ink-2); max-width: 68ch;display:none; }

  .card {
    background: var(--surface); border: 1px solid var(--line); border-radius: 8px;
    box-shadow: var(--shadow);
    /* Not `overflow: hidden` — that clips any dropdown panel opening near the card edge.
       The scrolling table below clips itself instead. */
  }
  .card + .card { margin-top: 18px; }
  .card-head {
    padding: 13px 18px; border-bottom: 1px solid var(--line);
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  }
  .card-head h2 { font-size: 14px; letter-spacing: .01em; }
  .card-head .hint { font-size: 12px; color: var(--ink-3); }
  .card-head .spacer { flex: 1; }
  .card-body { padding: 18px; }

  .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px 18px; }
  .grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px 18px; }
  .stack { display: flex; flex-direction: column; gap: 14px; }
  .row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

  .fld { display: flex; flex-direction: column; }
  .fld .help { margin-top: 4px; font-size: 11.5px; color: var(--ink-3); }
  .fld.system input, .fld.system .fake {
    background: var(--surface-2); color: var(--ink-2); font-family: var(--mono);
  }
  .fake {
    padding: 7px 9px; border: 1px dashed var(--line-strong); border-radius: var(--radius);
    font-size: 13px;
  }

  /* skip-logic reveal */
  .skip {
    border-left: 2px solid var(--accent); padding-left: 12px; margin-left: 2px;
    display: none;
  }
  .skip.on { display: block; animation: reveal .18s ease-out; }
  .skip-grid { display: none; }
  .skip-grid.on { display: grid; animation: reveal .18s ease-out; }
  @keyframes reveal { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; transform: none; } }
  @media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } }

  .skip-tag {
    display: inline-flex; align-items: center; gap: 5px; font-size: 10.5px;
    letter-spacing: .06em; text-transform: uppercase; font-weight: 600;
    color: var(--accent-ink); background: var(--accent-soft);
    padding: 2px 7px; border-radius: 100px;
  }

  /* pills */
  .pill {
    display: inline-flex; align-items: center; gap: 5px; padding: 2px 9px;
    border-radius: 100px; font-size: 11.5px; font-weight: 600; white-space: nowrap;
  }
  .pill.ok { background: var(--ok-soft); color: var(--ok); }
  .pill.warn { background: var(--warn-soft); color: var(--warn); }
  .pill.crit { background: var(--crit-soft); color: var(--crit); }
  .pill.neutral { background: var(--surface-2); color: var(--ink-2); }
  .pill.accent { background: var(--accent-soft); color: var(--accent-ink); }
  .pill.clay { background: var(--clay-soft); color: var(--clay); }

  /* buttons */
  .btn {display: inline-flex; align-items: center; gap: 7px; padding: 7px 13px; border-radius: var(--radius); border: 1px solid var(--line-strong); background: var(--surface); cursor: pointer; font-size: 13px;font-weight:500; text-decoration: none;
  }
  .btn:hover { border-color: var(--ink-3); }
  .btn.primary { background: var(--accent); border-color: var(--accent); color: #FFFFFF; }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .btn.primary { color: #2A0F1C; }
  }
  :root[data-theme="dark"] .btn.primary { color: #2A0F1C; }
  .btn.primary:hover { filter: brightness(1.06); }
  .btn.ghost { background: none; border-color: transparent; color: var(--ink-2); }
  .btn.danger { border-color: var(--crit); color: var(--crit); }

  /* tables */
  .tbl-wrap { overflow-x: auto; }
  table { border-collapse: collapse; width: 100%; font-size: 13px; }
  th, td { text-align: left; padding: 9px 14px; border-bottom: 1px solid var(--line); vertical-align: top; }
  th {
    font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
    color: var(--ink-3); font-weight: 600; white-space: nowrap;
    background: var(--surface-2); position: sticky; top: 0;
  }
  tbody tr:hover { background: var(--surface-2); }
  td.mono { font-variant-numeric: tabular-nums; }

  /* consent module cards */
  .modules { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
  .module {
    border: 1px solid var(--line); border-radius: 8px; padding: 14px;
    display: flex; flex-direction: column; gap: 9px; background: var(--ground);
  }
  .module[data-on="true"] { border-color: var(--ok); background: var(--ok-soft); }
  .module .m-top { display: flex; align-items: baseline; gap: 8px; }
  .module .m-num {
    font-family: var(--mono); font-size: 11px; color: var(--ink-3);
  }
  .module h3 { font-size: 13.5px; }
  .module p { font-size: 12px; color: var(--ink-2); }
  .module .unlocks { font-size: 11.5px; color: var(--ink-3); }
  .switch { display: flex; gap: 6px; }
  .switch button {
    flex: 1; padding: 5px 0; border: 1px solid var(--line-strong); background: var(--surface);
    border-radius: var(--radius); cursor: pointer; font-size: 12.5px; font-weight: 600;
  }
  .switch button[aria-pressed="true"] { background: var(--ok); border-color: var(--ok); color: #fff; }
  .switch button.no[aria-pressed="true"] { background: var(--ink-2); border-color: var(--ink-2); color: var(--surface); }

  .callout {
    border-left: 3px solid var(--clay); background: var(--clay-soft);
    padding: 12px 14px; border-radius: 0 var(--radius) var(--radius) 0; font-size: 12.5px;
    color: var(--ink); display: flex; gap: 10px;
  }
  .callout.accent { border-left-color: var(--accent); background: var(--accent-soft); }
  .callout.crit { border-left-color: var(--crit); background: var(--crit-soft); }
  .callout b { font-weight: 600; }

  /* KPI tiles */
  .kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
  .kpi { background: var(--surface); border: 1px solid var(--line); border-radius: 8px; padding: 14px; }
  .kpi .k-label { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); font-weight: 600; }
  .kpi .k-val { font-family: var(--serif); font-size: 27px; line-height: 1.15; margin-top: 6px; font-variant-numeric: tabular-nums; }
  .kpi .k-sub { font-size: 11.5px; color: var(--ink-2); margin-top: 2px; }
  .meter { height: 4px; background: var(--surface-2); border-radius: 2px; margin-top: 9px; overflow: hidden; }
  .meter span { display: block; height: 100%; background: var(--accent); }
  .meter span.ok { background: var(--ok); }
  .meter span.warn { background: var(--warn); }

  /* funnel */
  .funnel { display: flex; flex-direction: column; gap: 6px; }
  .frow { display: grid; grid-template-columns: 190px 1fr 76px; align-items: center; gap: 12px; font-size: 12.5px; }
  .fbar { height: 20px; background: var(--accent-soft); border-radius: 3px; position: relative; }
  .fbar i { display: block; height: 100%; background: var(--accent); border-radius: 3px; }
  .fbar i.clay { background: var(--clay); }
  .fbar i.ok { background: var(--ok); }
  .frow .n { text-align: right; font-family: var(--mono); font-size: 12.5px; }

  /* search result */
  .hit {
    display: flex; align-items: center; gap: 14px; padding: 12px 14px;
    border: 1px solid var(--ok); background: var(--ok-soft); border-radius: var(--radius);
  }
  .hit .who { flex: 1; }
  .hit .who b { display: block; }
  .hit .who span { font-size: 12px; color: var(--ink-2); }

  /* modal */
  .scrim {
    position: fixed; inset: 0; background: rgba(10,16,15,.55); display: none;
    align-items: center; justify-content: center; padding: 20px; z-index: 40;
  }
  .scrim.on { display: flex; }
  .modal {
    background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
    max-width: 460px; width: 100%; box-shadow: var(--shadow); overflow: hidden;
  }
  .modal-head { padding: 16px 18px 0; display: flex; gap: 12px; align-items: flex-start; }
  .modal-head h3 { font-size: 15px; }
  .modal-body { padding: 12px 18px 18px; display: flex; flex-direction: column; gap: 12px; }
  .modal-foot { padding: 13px 18px; border-top: 1px solid var(--line); display: flex; gap: 8px; justify-content: flex-end; background: var(--surface-2); }

  /* rbac matrix */
  .matrix td.c { text-align: center; font-family: var(--mono); font-size: 13px; }
  .matrix td.c.full { color: var(--ok); font-weight: 700; }
  .matrix td.c.read { color: var(--accent); }
  .matrix td.c.none { color: var(--ink-3); opacity: .5; }
  .matrix th.rot { text-align: center; }
  .legend { display: flex; gap: 16px; flex-wrap: wrap; font-size: 12px; color: var(--ink-2); }
  .legend b { font-family: var(--mono); }

  .masked {
    font-family: var(--mono); background: var(--surface-2); color: var(--ink-3);
    padding: 7px 9px; border-radius: var(--radius); border: 1px solid var(--line);
    letter-spacing: .08em;
  }

  .footnote { margin-top: 22px; font-size: 12px; color: var(--ink-3); max-width: 72ch; }

  @media (max-width: 900px) {
    .app { grid-template-columns: 1fr; }
    .rail { position: static; height: auto; border-right: 0; border-bottom: 1px solid var(--line); }
    nav.menu { flex-direction: row; flex-wrap: wrap; }
    .menu-group { width: 100%; padding-bottom: 0; }
    .canvas { padding: 20px 16px 60px; }
    .topbar { padding: 12px 16px; }
    .grid-2, .grid-3, .modules, .kpis { grid-template-columns: 1fr; }
    .frow { grid-template-columns: 120px 1fr 60px; }
  }

/* ---------------------------------------------------------------- application additions */

/* Flash + validation */
.alert { padding: 11px 14px; border-radius: var(--radius); font-size: 13px; margin-bottom: 14px; }
.alert.ok { background: var(--ok-soft); color: var(--ok); border: 1px solid var(--ok); }
.alert.err { background: var(--crit-soft); color: var(--crit); border: 1px solid var(--crit); }
.alert.warn { background: var(--warn-soft); color: var(--warn); border: 1px solid var(--warn); }
.field-error { color: var(--crit); font-size: 11.5px; margin-top: 4px; }
input.invalid, select.invalid, textarea.invalid { border-color: var(--crit); }

/* Auth screen */
.auth-wrap { min-height: 100vh; display: grid; place-items: center; padding: 24px; background: var(--ground); }
.auth-card { width: 100%; max-width: 380px; }
.auth-card .brand { padding: 0 0 18px; border: 0; text-align: center; }

/* Gate notice when a form is closed by consent */
.gate {
  border: 1px dashed var(--line-strong); border-radius: 8px; padding: 22px;
  text-align: center; color: var(--ink-2); font-size: 13px; background: var(--ground);
}
.gate strong { display: block; color: var(--ink); font-size: 14px; margin-bottom: 5px; }

/* Woman header strip shown above every form */
.subject {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 12px 16px; background: var(--surface); border: 1px solid var(--line);
  border-radius: 8px; margin-bottom: 16px;
}
.subject .who b { font-size: 14px; }
.subject .who span { display: block; font-size: 12px; color: var(--ink-2); }
.subject .spacer { flex: 1; }

/* Cascade strip */
.cascade { display: flex; gap: 6px; flex-wrap: wrap; }
.cascade a, .cascade span {
  font-size: 11.5px; padding: 3px 9px; border-radius: 100px; text-decoration: none;
  border: 1px solid var(--line-strong); color: var(--ink-2); background: var(--surface);
}
.cascade a:hover { border-color: var(--accent); color: var(--accent-ink); }
.cascade .on { background: var(--accent-soft); color: var(--accent-ink); border-color: var(--accent); font-weight: 600; }
.cascade .shut { opacity: .45; }

.actions { display: flex; gap: 9px; align-items: center; margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); }
.actions .spacer { flex: 1; }

a { color: var(--accent-ink); }
.muted { color: var(--ink-3); font-size: 12px; }
[wire\\:loading] { opacity: .6; }

/* ---------------------------------------------------------------- horizontal shell
 * Replaces the mockup's left rail. The identity bar carries who you are and which camp
 * is running; the nav row below it is the section switcher. Both are sticky, because at
 * a busy camp desk the current camp is the thing people re-check most often.
 */

.app { display: block; min-height: 100vh; }

.masthead {
    display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
    padding: 10px 24px;
    background: var(--surface); border-bottom: 1px solid var(--line);
}
.masthead .spacer { flex: 1; }
.masthead .brand {
    padding: 0; border: 0; text-decoration: none; color: inherit;
    display: flex; flex-direction: column; line-height: 1.2;
}
.masthead .brand .mark { font-family: var(--serif); font-size: 17px; }
.masthead .brand .mark em { font-style: normal; color: var(--accent); }
.masthead .brand .sub {
    font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
}
.whoami { display: flex; flex-direction: column; line-height: 1.25; text-align: right; }
.whoami b { font-size: 13px; font-weight: 600; }
.whoami span { font-size: 11px; color: var(--ink-3); }

.mainnav {
    position: sticky; top: 0; z-index: 10;
    background: var(--surface); border-bottom: 1px solid var(--line);
    overflow-x: auto; overflow-y: hidden;
    -webkit-overflow-scrolling: touch; scrollbar-width: thin;
}
.mainnav-inner {
    display: flex; align-items: stretch; gap: 2px;
    padding: 0 24px; min-width: max-content;
}
.navsep { width: 1px; background: var(--line); margin: 10px 8px; flex: none; }

/* Tabs, not list rows. Anchors, so the browser's text underline is cleared explicitly;
 * the active section is marked by the bar under the tab, not by underlined text. */
.mainnav .navlink, .mainnav .navlink:hover { text-decoration: none; }
.mainnav .navlink {
    width: auto; flex: none; gap: 8px;
    padding: 12px 13px 11px; border-radius: 0;
    border-bottom: 2px solid transparent;
    white-space: nowrap; font-size: 13.5px;
}
.mainnav .navlink:hover { background: var(--surface-2); color: var(--ink); }
.mainnav .navlink .t1 { font-size: 13.5px; font-weight: 500; }
.mainnav .navlink[aria-current="true"] {
    background: none; color: var(--accent-ink);
    border-bottom-color: var(--accent); font-weight: 600;
}
/* The rail's active-state left bar has no meaning in a tab strip. */
.mainnav .navlink[aria-current="true"]::before { content: none; }
.mainnav .navlink .badge { margin-left: 2px; }

/* ---------------------------------------------------------------- quality floor
   One focus ring for the whole application, motion honoured, and the horizontal nav scrolling
   without a scrollbar parked under it. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}
/* The nav is the element that scrolls, so it is the one whose scrollbar is hidden. A permanent
   grey bar under the navigation read as a broken page rather than as an affordance; the row still
   scrolls by wheel, touch and keyboard. */
.mainnav { scrollbar-width: none; }
.mainnav::-webkit-scrollbar { height: 0; }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ---------------------------------------------------------------- page rhythm
   One measure, one set of gaps. Every page is head → cards, and the spacing between them is
   the same whether the page is a list, a form or a record. */
main { min-width: 0; }
.canvas {
    padding: 26px 24px 80px; max-width: var(--measure); margin: 0 auto;
    /* `clip`, not `hidden`: hidden would make this a scroll container and break the sticky
       footer inside it. This only contains the footer's full-bleed side margins. */
    overflow-x: clip;
}
/* The page head stays in view while a long form scrolls.
   Its actions are the same ones the footer carries, and the nav above it is already sticky and
   demonstrably works on the machines where a pinned footer did not — so this is the mechanism
   the save button gets to depend on. `top` clears the nav rather than sliding under it. */
.page-head {
    position: sticky; top: var(--nav-h); z-index: 7;
    margin-bottom: var(--gap-page);
    padding: 10px 0;
    background: var(--ground);
}
/* Its own hairline appears only once it has something scrolling beneath it. */
.page-head::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: 0;
    border-bottom: 1px solid var(--line);
    opacity: 0; transition: opacity .15s ease;
}
.page-head.is-stuck::after { opacity: 1; }
/* Page rhythm.
   `.card + .card` alone left two gaps unhandled: a grid of cards following a card had no space
   above it (they touched), and inside a grid the rule pushed the second column down so the two
   cards no longer lined up. Spacing belongs to whatever sits at page level, card or not. */
.card + .card { margin-top: var(--gap-card); }
/* Blade pages put their blocks straight into .canvas; Livewire pages wrap them in the component
   root, and forms nest one level deeper again. All three need the same rhythm.
   Wrapped in :where() so the rule carries no specificity of its own — otherwise it outweighs the
   grid rules below and pushes every column but the first out of line, which is exactly what it
   did to the KPI row. */
:where(.canvas, .canvas > div, .canvas > div > form) > * + * { margin-top: var(--gap-card); }

/* Columns are placed by the grid's own gap, never by a sibling margin. */
.grid-2 > * + *, .grid-3 > * + *, .kpis > * + *,
.grid-2 > .card + .card, .grid-3 > .card + .card { margin-top: 0; }

/* The footer that carries pagination, so it is not a card-body pretending to be one. */
.card-foot {
    padding: 12px 18px; border-top: 1px solid var(--line);
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.card-foot nav[role="navigation"] { font-size: 13px; }

@media (max-width: 760px) {
    .masthead { padding: 10px 16px; gap: 10px; }
    .masthead .camp-chip { order: 3; width: 100%; }
    .whoami { text-align: left; }
    .mainnav-inner { padding: 0 12px; }
    .canvas { padding: 20px 16px 60px; }
}

/* ---------------------------------------------------------------- searchable select
 * One control for every closed response set in the specification. Long lists (employers,
 * habitations, migrant status) get a filter box; short ones do not, because opening and
 * picking is quicker than reaching for a keyboard.
 */

[x-cloak] { display: none !important; }

.sselect { position: relative; }

.sselect-trigger {
    width: 100%; display: flex; align-items: center; gap: 8px;
    padding: 7px 9px; text-align: left; cursor: pointer;
    background: var(--surface); color: var(--ink);
    border: 1px solid var(--line-strong); border-radius: var(--radius);
    font: inherit;
}
.sselect-trigger:hover { border-color: var(--ink-3); }
.sselect-trigger.invalid { border-color: var(--crit); }
.sselect-trigger > span:first-child {
    flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sselect-placeholder { color: var(--ink-3); }
.sselect-caret { width: 15px; height: 15px; flex: none; color: var(--ink-3); }

.sselect-panel {
    /* Positioned in JS as `fixed` on open, so a modal's own scrolling cannot clip it. The values
       here are the pre-open defaults and the fallback if scripting is unavailable. */
    position: absolute; z-index: 90; top: calc(100% + 5px); left: 0;
    display: flex; flex-direction: column;
    /* At least as wide as the field, wider if a label needs it, never wider than the
       viewport — long camp names used to force a horizontal scrollbar. */
    min-width: 100%; width: max-content; max-width: min(420px, calc(100vw - 48px));
    background: var(--surface); border: 1px solid var(--line-strong);
    border-radius: 8px; overflow: hidden;
    /* Deeper than a card's shadow so the panel reads as floating above it rather than
       colliding with the card border underneath. */
    box-shadow: 0 4px 10px -4px rgba(32, 24, 35, .18), 0 14px 34px -12px rgba(32, 24, 35, .32);
}
:root[data-theme="dark"] .sselect-panel,
:root:not([data-theme="light"]) .sselect-panel {
    box-shadow: 0 4px 10px -4px rgba(0, 0, 0, .6), 0 16px 38px -12px rgba(0, 0, 0, .75);
}
.sselect-search {
    width: 100%; border: 0; border-bottom: 1px solid var(--line);
    border-radius: 0; padding: 8px 10px; font-size: 13px;
    background: var(--surface-2); color: var(--ink);
}
.sselect-search:focus-visible { outline: none; border-bottom-color: var(--accent); }

.sselect-list {
    margin: 0; padding: 4px; list-style: none;
    /* The panel carries the height cap once open, so the list simply fills what it is given. */
    flex: 1; min-height: 0; max-height: 260px; overflow-y: auto; overflow-x: hidden;
}
.sselect-list li {
    padding: 7px 9px; border-radius: 5px; cursor: pointer; font-size: 13px;
    line-height: 1.35;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sselect-list li:hover { background: var(--surface-2); }
.sselect-list li.is-selected {
    background: var(--accent-soft); color: var(--accent-ink); font-weight: 600;
}
.sselect-empty { color: var(--ink-3); cursor: default; font-style: italic; }
.sselect-empty:hover { background: none; }

/* ---------------------------------------------------------------- camp-first chooser
   Camp, then day, then woman: one row of three steps, so the order is visible rather than
   implied by the reading order. Numbered because it is a sequence — the woman list does not
   exist until the camp above it is answered. */
.chooser {
    display: grid; grid-template-columns: minmax(0, 1.5fr) auto minmax(0, 1.3fr);
    /* Wide enough that the three steps read as separate questions rather than one crowded row. */
    gap: 28px; align-items: start;
}
/* Named apart from .step, which is the unrelated .stepper component further down. */
.chooser-step { min-width: 0; }
/* A hairline between steps, so step three cannot look like it belongs to step two. */
.chooser-step + .chooser-step { border-left: 1px solid var(--line); padding-left: 28px; }
@media (max-width: 980px) {
    .chooser-step + .chooser-step { border-left: 0; padding-left: 0; padding-top: 4px; }
}
@media (max-width: 980px) {
    .chooser { grid-template-columns: 1fr; }
}

/* The step number sits on the label line, so it costs no vertical space. */
.chooser-step > .lbl { display: flex; align-items: baseline; gap: 7px; margin-bottom: 6px; }
.chooser-step > .lbl .n {
    flex: none; width: 15px; height: 15px; border-radius: 50%;
    background: var(--surface-2); color: var(--ink-3);
    font-size: 9.5px; font-weight: 700; display: grid; place-items: center;
    align-self: center;
}
.chooser-step > .lbl.done .n { background: var(--accent); color: #FFFFFF; }
.chooser-step > .lbl .field-label { margin: 0; }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .chooser-step > .lbl.done .n { color: #2A0F1C; }
}
/* The controls carry their own label markup, so the component's is suppressed here. */
.chooser-step > .fld > .field-label { display: none; }
/* One line, muted, with only the action underlined. */
.chooser-step .help a { color: var(--accent-ink); }

/* Day chooser: a toggle between the days of one camp, not a set of actions. */
.seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: var(--radius); overflow: hidden; }
.seg button {
    border: 0; border-left: 1px solid var(--line); background: var(--surface);
    padding: 8px 12px; font-size: 13px; font-weight: 500; cursor: pointer; color: var(--ink);
    display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
}
.seg button:first-child { border-left: 0; }
.seg button:hover { background: var(--surface-2); }
.seg button[aria-pressed="true"] { background: var(--accent); color: #FFFFFF; }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .seg button[aria-pressed="true"] { color: #2A0F1C; }
}
.seg .n {
    font-size: 10.5px; font-variant-numeric: tabular-nums; padding: 1px 6px; border-radius: 999px;
    background: var(--surface-2); color: var(--ink-3);
}
.seg button[aria-pressed="true"] .n { background: rgba(255, 255, 255, .22); color: inherit; }

/* Multi-select. Same panel as the single select, plus a tick column and the chips that
   show who is currently picked — a count alone cannot be checked before saving. */
.msel .sselect-list li { display: flex; gap: 7px; align-items: baseline; }
.msel-tick { flex: none; width: 11px; color: var(--accent); font-weight: 700; }

.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.chip {
    display: inline-flex; align-items: center; gap: 6px;
    background: var(--accent-soft); color: var(--accent-ink);
    border-radius: 999px; padding: 4px 6px 4px 10px; font-size: 12px;
}
.chip-x {
    border: 0; background: none; cursor: pointer; color: inherit;
    font-size: 15px; line-height: 1; padding: 0 4px; border-radius: 999px; opacity: .65;
}
.chip-x:hover { opacity: 1; background: rgba(0, 0, 0, .08); }

/* Wide tables still clip to the card's rounded corners without the card doing it. */
.tbl-wrap { border-radius: 0 0 8px 8px; }
.card-head { border-radius: 8px 8px 0 0; }

/* An open dropdown must sit above every later card, and above the sticky nav's siblings. */
.sselect { position: relative; }
.fld:has(.sselect-panel:not([style*="display: none"])) { position: relative; z-index: 40; }

/* Required marker. Colour alone never carries the meaning — the asterisk is the signal and
   a screen reader hears the word. */
.field-label .req { color: var(--crit); margin-left: 3px; font-weight: 700; }
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* ---------------------------------------------------------------- register table
 * A filter row inside the header, so the control sits directly under the column it acts on.
 */
.th-sort {
    background: none; border: 0; padding: 0; cursor: pointer;
    font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;
    display: inline-flex; align-items: center; gap: 4px;
}
.th-sort:hover { color: var(--accent-ink); }
.sort-caret { font-size: 8px; color: var(--accent); }

.filter-row th {
    background: var(--surface); border-bottom: 1px solid var(--line-strong);
    padding: 6px 10px; position: static;
}
.filter-row input, .filter-row select {
    width: 100%; min-width: 90px; padding: 5px 7px; font-size: 12.5px;
    text-transform: none; letter-spacing: 0; font-weight: 400;
}
.filter-row input::placeholder { color: var(--ink-3); }

/* Pagination, styled to match the rest rather than the framework default. */
.card-body nav[role="navigation"] { font-size: 13px; }
.card-body nav[role="navigation"] svg { width: 15px; height: 15px; }

/* Number inputs: drop the spinners. Counts here are typed from a house-listing sheet, not
   nudged one at a time, and the arrows made the field a different height from its neighbours. */
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* ---------------------------------------------------------------- date picker
 * Native date inputs render differently in every browser and show the American order in
 * some locales. Everything in this project is read as dd/mm/yyyy, so the picker is ours.
 */
.dpick { position: relative; }
.dpick-trigger {
    width: 100%; display: flex; align-items: center; gap: 8px;
    padding: 7px 9px; text-align: left; cursor: pointer; font: inherit;
    background: var(--surface); color: var(--ink);
    border: 1px solid var(--line-strong); border-radius: var(--radius);
}
.dpick-trigger:hover { border-color: var(--ink-3); }
.dpick-trigger.invalid { border-color: var(--crit); }
.dpick-trigger > span:first-child { flex: 1; font-variant-numeric: tabular-nums; }
.dpick-placeholder { color: var(--ink-3); }
.dpick-icon { width: 15px; height: 15px; flex: none; color: var(--ink-3); }

.dpick-panel {
    /* Also positioned in JS as `fixed` on open — same reason as the select panel. */
    position: absolute; z-index: 90; top: calc(100% + 5px); left: 0;
    width: 268px; padding: 10px; overflow: auto;
    background: var(--surface); border: 1px solid var(--line-strong); border-radius: 8px;
    box-shadow: 0 4px 10px -4px rgba(32,24,35,.18), 0 14px 34px -12px rgba(32,24,35,.32);
}
:root[data-theme="dark"] .dpick-panel,
:root:not([data-theme="light"]) .dpick-panel {
    box-shadow: 0 4px 10px -4px rgba(0,0,0,.6), 0 16px 38px -12px rgba(0,0,0,.75);
}

.dpick-head { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
.dpick-head .dpick-month { flex: 1; text-align: center; font-size: 13px; font-weight: 600; }
.dpick-nav {
    width: 26px; height: 26px; display: grid; place-items: center;
    border: 1px solid var(--line); border-radius: 5px; background: var(--surface);
    cursor: pointer; color: var(--ink-2);
}
.dpick-nav:hover { border-color: var(--accent); color: var(--accent-ink); }

.dpick-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.dpick-dow {
    text-align: center; font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
    color: var(--ink-3); font-weight: 700; padding-bottom: 4px;
}
.dpick-day {
    aspect-ratio: 1; border: 0; border-radius: 5px; cursor: pointer;
    background: none; color: var(--ink); font: inherit; font-size: 12.5px;
    font-variant-numeric: tabular-nums;
}
.dpick-day:hover:not(:disabled) { background: var(--surface-2); }
/* Today is marked in the accent, not in the faintest line colour it used to use — and it stays
   marked when it is also the chosen day, with a dot under the number, because "today" and
   "selected" are two different facts about the same square. */
.dpick-day.is-today {
    box-shadow: inset 0 0 0 1.5px var(--accent);
    color: var(--accent-ink); font-weight: 600;
}
.dpick-day.is-selected { background: var(--accent); color: #fff; font-weight: 700; }
.dpick-day.is-today.is-selected { color: #fff; position: relative; }
.dpick-day.is-today.is-selected::after {
    content: ""; position: absolute; left: 50%; bottom: 3px; translate: -50% 0;
    width: 4px; height: 4px; border-radius: 50%; background: currentColor;
}
:root[data-theme="dark"] .dpick-day.is-selected,
:root:not([data-theme="light"]) .dpick-day.is-selected { color: #2A0F1C; }
.dpick-day:disabled { opacity: .3; cursor: not-allowed; }
.dpick-nav:disabled { opacity: .25; cursor: not-allowed; }
.dpick-nav:disabled:hover { background: none; }
.dpick-foot button:disabled { opacity: .45; cursor: not-allowed; }
.dpick-day.is-blank { visibility: hidden; }

.dpick-foot {
    display: flex; gap: 6px; margin-top: 9px; padding-top: 8px;
    border-top: 1px solid var(--line);
}
.dpick-foot button {
    flex: 1; padding: 5px 0; font-size: 12px; cursor: pointer;
    border: 1px solid var(--line-strong); border-radius: 5px;
    background: var(--surface); color: var(--ink-2);
}
.dpick-foot button:hover { border-color: var(--accent); color: var(--accent-ink); }

/* In a filter cell the picker sits in tight space. */
.filter-row .dpick-trigger { padding: 5px 7px; font-size: 12.5px; }

/* ================================================================ polish pass
 * Craft within the existing palette rather than a new one: clearer table hierarchy,
 * empty states that tell you what to do, and one signature piece — the cascade.
 */

/* ---------------------------------------------------------------- page head */
.page-head-row { display: flex; align-items: flex-start; gap: 20px; flex-wrap: wrap; }
.page-head-row > div:first-child { flex: 1; min-width: 260px; }
.page-actions { display: flex; gap: 8px; align-items: center; padding-top: 4px; }

/* ---------------------------------------------------------------- tables */
/* The header stays put while a long register scrolls. */
.tbl-wrap { max-height: none; }
thead th { position: sticky; top: 0; z-index: 2; }
.filter-row th { top: 34px; z-index: 1; }

tbody tr { transition: background-color .12s ease; }
tbody tr:hover { background: var(--surface-2); }
tbody td { vertical-align: middle; }

/* Counts and identifiers line up in columns; prose does not. */
td.mono, th.mono { font-variant-numeric: tabular-nums; }

/* Row actions.
   They used to fade to 55% until the row was hovered, which read as disabled rather than as
   quiet — a nurse tapping a tablet has no hover at all. They are compact and right-aligned
   instead: small enough that a dense table still reads as data, solid enough to look pressable.
   View is the quiet default; Edit is outlined, because it is the one that changes something. */
/* The wrapper keeps the buttons on one line. This was `tbody td:last-child { nowrap }`, which
   also caught the empty-state cell — the only cell in its row, and therefore the last one — so an
   empty list forced its explanatory paragraph onto a single line and scrolled the whole page
   sideways. Never style a table cell by its position when the position means two different things. */
.actions-cell { display: flex; gap: 6px; justify-content: flex-end; flex-wrap: nowrap; white-space: nowrap; }

/* A filter the clerk switches on, not an action — so it reads as pressed rather than as a
   button that did something, and it sits on the label line beside the question it qualifies. */
.btn.xs {
    padding: 2px 9px; font-size: 11px; border-radius: 999px; font-weight: 500;
    align-self: center; gap: 5px;
}
.btn.xs[aria-pressed="false"] { background: none; border-color: var(--line); color: var(--ink-3); }
.btn.xs[aria-pressed="false"]:hover { border-color: var(--ink-3); color: var(--ink-2); }
.btn.xs[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-ink); }
.btn.xs[aria-pressed="true"]::before { content: "\2713"; font-weight: 700; }

.actions-cell .btn,
.btn.sm {
    padding: 4px 10px; font-size: 12px; border-radius: 6px; font-weight: 500;
}
.actions-cell .btn { background: var(--surface-2); border-color: transparent; color: var(--ink-2); }
.actions-cell .btn:hover { background: var(--accent-soft); color: var(--accent-ink); border-color: transparent; }
.actions-cell .btn.edit { background: transparent; border-color: var(--line-strong); color: var(--ink); }
.actions-cell .btn.edit:hover { border-color: var(--accent); color: var(--accent-ink); background: var(--accent-soft); }

/* Identifiers never wrap. A Woman ID broken across two lines makes every row taller than the
   data needs and cannot be read back to a woman at the desk. */
td.mono, th.mono, .mono.nowrap { white-space: nowrap; }

/* A scrollable table says so at its right edge instead of hiding the overflow. */
.tbl-wrap { background:
    linear-gradient(to right, var(--surface) 30%, transparent),
    linear-gradient(to left, var(--surface) 30%, transparent),
    linear-gradient(to right, rgba(32,24,35,.10), transparent 12px),
    linear-gradient(to left, rgba(32,24,35,.10), transparent 12px);
    background-repeat: no-repeat;
    background-size: 40px 100%, 40px 100%, 14px 100%, 14px 100%;
    background-position: 0 0, 100% 0, 0 0, 100% 0;
    background-attachment: local, local, scroll, scroll;
}

/* KPI strips sit above a card and share the card gap, rather than carrying their own margin
   inline on each page that uses them. */
.kpis { margin-bottom: 0; }

/* A woman in a table cell: who she is on one line, the quieter identifier under it. */
.woman-cell { display: block; }
.woman-cell .muted { display: block; }

/* Filter cells fill their column, so a long option label is not clipped mid-word. */
.filter-row select, .filter-row input[type="text"] { width: 100%; }

/* The lab's scan strip: a bordered band between the card head and the worklist, so the button
   does not sit flush on the table's header row. */
.scan-bar {
    padding: 14px 18px; border-bottom: 1px solid var(--line); background: var(--surface-2);
}
.scan-bar .fld { margin: 0; }

/* A panel inherits from wherever it is anchored, and a table header is uppercase and
   letter-spaced — so filter dropdowns opened with SHOUTING OPTION LABELS. Panels set their own
   typography rather than trusting their surroundings. */
.sselect-panel, .dpick-panel {
    text-transform: none; letter-spacing: normal; font-size: 13px;
    font-weight: 400; color: var(--ink); text-align: left;
}

/* Compact select, for a table's filter row. */
.fld-compact { margin: 0; }
.sselect-compact .sselect-trigger {
    padding: 5px 8px; font-size: 12px; border-radius: 6px; min-height: 0;
    background: var(--surface);
}
.sselect-compact .sselect-caret { width: 13px; height: 13px; }
/* The panel is sized by its content, not by the narrow cell it hangs from. */
.sselect-compact .sselect-panel { min-width: max(100%, 190px); }

/* ---------------------------------------------------------------- record facts
   The context strip at the top of a record: whose it is, which camp, which day, whether it can
   still be corrected. Values are set as text, not in the dashed boxes the forms use for
   system-generated fields — on a read-only page those read as inputs waiting to be filled. */
.facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px 26px; }
.fact .field-label { margin-bottom: 3px; }
.fact-value { font-size: 13px; font-weight: 500; }
.fact-value .muted { display: block; font-weight: 400; }

/* ---------------------------------------------------------------- recorded answers
   Question and answer, on one measure across every record page. */
.answers { display: grid; gap: 0; }
.answer {
    display: grid; grid-template-columns: minmax(200px, 300px) 1fr; gap: 18px;
    padding: 9px 0; border-top: 1px solid var(--line); align-items: baseline;
}
.answer:first-child { border-top: 0; }
.answers dt { color: var(--ink-2); font-size: 13px; }
.answers dd { font-size: 13px; font-weight: 500; }
/* A skipped field reads as skipped, not as an answer nobody gave. */
.answers dd.skipped { color: var(--ink-3); font-weight: 400; font-style: italic; }
@media (max-width: 620px) {
    .answer { grid-template-columns: 1fr; gap: 2px; }
}

/* ---------------------------------------------------------------- empty states */
.empty { padding: 34px 20px; text-align: center; }
.empty-icon {
    width: 40px; height: 40px; margin: 0 auto 12px;
    color: var(--ink-3); opacity: .8;
}
.empty-icon svg { width: 100%; height: 100%; }
.empty-title { font-size: 14px; font-weight: 600; color: var(--ink); }
.empty-body {
    margin-top: 6px; font-size: 13px; color: var(--ink-2);
    max-width: 46ch; margin-left: auto; margin-right: auto;
}
.empty-body .row { justify-content: center; margin-top: 12px; }

/* ---------------------------------------------------------------- validation summary */
.error-list { margin: 6px 0 0 18px; padding: 0; }
.error-list li { margin-top: 2px; }
.error-jump {
    background: none; border: 0; padding: 0; cursor: pointer; font: inherit;
    color: inherit; text-align: left;
    text-decoration: underline; text-underline-offset: 2px;
}
.error-jump:hover { text-decoration-thickness: 2px; }

/* ---------------------------------------------------------------- form footers */
/* The bar that finishes a form, pinned to the bottom of the window while the form scrolls.
   It must be a direct child of the <form>: sticky pins inside its containing block, so while it
   lived in a card of its own it could only pin within that card — which is why it appeared to sit
   at the end of the form and nowhere else. */
.form-foot {
    position: sticky; bottom: 0; z-index: 7;
    display: flex; align-items: center; gap: 9px;
    margin-top: 18px;
    /*
     * Full bleed while staying a child of the <form>, which it has to be for sticky to pin across
     * the whole form. The negative side margins reach back out to the window edges; the padding
     * then brings the buttons back in line with the form's own measure, so they sit under the
     * fields rather than out at the window edge. `.canvas` clips the overflow this creates.
     */
    margin-left: calc(var(--vw) / -2 + 50%);
    margin-right: calc(var(--vw) / -2 + 50%);
    /* 24px of canvas padding plus 18px of card padding, so the buttons line up under the fields
       rather than under the card's border. */
    padding: 13px max(24px, calc((var(--vw) - var(--measure)) / 2 + 42px));
    padding-bottom: max(13px, env(safe-area-inset-bottom, 0px));
    background: var(--surface);
    border: 0; border-top: 1px solid var(--line); border-radius: 0;
    box-shadow: 0 -8px 20px -16px rgba(32, 24, 35, .45);
}
.form-foot .spacer { flex: 1; }
.form-foot .btn { min-width: 104px; justify-content: center; }
.form-foot .btn.ghost { min-width: 0; border-color: transparent; }
.form-foot .btn.ghost:hover { border-color: var(--line-strong); }
.form-foot .dirty-note { font-size: 12px; color: var(--warn); }

@media (max-width: 640px) {
    .form-foot .btn { flex: 1; }
}

/* The buttons that finish a form live in a card footer — the same structure as a list's
   pagination, which is plain, static and has never failed to render. Three positioning schemes
   were tried before this (sticky to the document, fixed to the viewport, static in a bar of its
   own) and one field machine showed none of them, so this drops the separate element entirely.
   Every long form also carries its primary action in the page head. */
.card-foot .btn { min-width: 104px; justify-content: center; }
.card-foot .btn.ghost { min-width: 0; border-color: transparent; }
.card-foot .btn.ghost:hover { border-color: var(--line-strong); }
.card-foot .spacer { flex: 1; }
.card-foot .dirty-note { font-size: 12px; color: var(--warn); }

@media (max-width: 640px) {
    .card-foot .btn { flex: 1; }
}

/* ---------------------------------------------------------------- loading feedback */
/* Filters run against the database, so say when a result is in flight. */
[wire\:loading] { opacity: .55; }
.card-head .spinner, .working {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 11.5px; color: var(--ink-3);
}
.working::before {
    content: ""; width: 11px; height: 11px; border-radius: 50%;
    border: 2px solid var(--line-strong); border-top-color: var(--accent);
    animation: spin .6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------------------------------------------------------------- flash messages */
.alert { display: flex; gap: 10px; align-items: flex-start; }
.alert-icon { flex: none; width: 16px; height: 16px; margin-top: 1px; }
.alert-body { flex: 1; }
.alert-close {
    flex: none; background: none; border: 0; cursor: pointer; color: inherit;
    opacity: .6; font-size: 16px; line-height: 1; padding: 0 2px;
}
.alert-close:hover { opacity: 1; }

/* ---------------------------------------------------------------- cascade stepper
 * The signature piece. Eight forms in a real sequence, each one gated by a consent
 * decision, so the numbering encodes something true rather than decorating a list.
 */
.stepper { display: flex; flex-wrap: wrap; gap: 0; }
.step {
    position: relative; flex: 1 1 130px; min-width: 130px;
    padding: 12px 12px 12px 16px;
    border: 1px solid var(--line); border-right: 0;
    background: var(--surface); text-decoration: none; color: inherit;
    display: block;
}
.step:first-child { border-radius: 8px 0 0 8px; }
.step:last-child { border-right: 1px solid var(--line); border-radius: 0 8px 8px 0; }
.step-num {
    font-family: var(--mono); font-size: 10px; letter-spacing: .08em;
    color: var(--ink-3);
}
.step-name { display: block; font-size: 12.5px; font-weight: 600; margin-top: 3px; }
.step-state { display: block; font-size: 11px; color: var(--ink-3); margin-top: 2px; }

.step.is-open { border-top: 2px solid var(--accent); }
.step.is-open .step-num, .step.is-open .step-name { color: var(--accent-ink); }
.step.is-open:hover { background: var(--accent-soft); }
.step.is-done { border-top: 2px solid var(--ok); }
.step.is-done .step-num { color: var(--ok); }
.step.is-shut { background: var(--ground); border-top: 2px solid var(--line-strong); }
.step.is-shut .step-name, .step.is-shut .step-num { color: var(--ink-3); }
.step:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; z-index: 1; }

@media (max-width: 860px) {
    .step { flex-basis: 50%; border-right: 1px solid var(--line); border-radius: 0 !important; }
}

/* Missing answers as chips: scannable, and each one moves to its field. */
.error-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.error-chip {
    font: inherit; font-size: 12px; cursor: pointer;
    padding: 3px 9px; border-radius: 100px;
    border: 1px solid currentColor; background: none; color: inherit;
    opacity: .85;
}
.error-chip:hover { opacity: 1; background: rgba(0, 0, 0, .04); }
:root[data-theme="dark"] .error-chip:hover,
:root:not([data-theme="light"]) .error-chip:hover { background: rgba(255, 255, 255, .07); }
.error-list.spaced { margin-top: 8px; }

/* Her other forms, from wherever you are. Quiet by default: it is navigation, not the task. */
.subject-forms { display: flex; gap: 4px; flex-wrap: wrap; }
.subject-forms a {
    font-size: 12px; padding: 4px 10px; border-radius: 100px; text-decoration: none;
    border: 1px solid var(--line-strong); color: var(--ink-2); background: var(--surface);
}
.subject-forms a:hover { border-color: var(--accent); color: var(--accent-ink); }
.subject-forms a.on { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-ink); font-weight: 600; }

/* ---------------------------------------------------------------- modal forms
 * Result entry happens over the list, not below it: one task at a time, with the queue still
 * visible behind as context.
 */
.scrim { position: fixed; inset: 0; z-index: 60; background: rgba(32, 24, 35, .55); }
:root[data-theme="dark"] .scrim,
:root:not([data-theme="light"]) .scrim { background: rgba(0, 0, 0, .68); }

.modal { max-width: 560px; max-height: min(88vh, 900px); display: flex; flex-direction: column; }
.modal-wide { max-width: 860px; }

/* Long forms scroll inside the modal so the heading and the actions stay put. */
.modal-scroll { overflow-y: auto; padding: 0; }
.modal-scroll .card { border: 0; box-shadow: none; margin: 0; }
.modal-scroll .card-body { padding: 14px 18px; }

/* The action bar sticks to the bottom of the modal rather than the page. */
/* The modal's footer.
   It sits inside a padded card body, so it has to reach back out to the modal's own edges — an
   inset bar with its own rounded corners read as a card floating inside a card. Full bleed, one
   hairline, and the primary action on the right where a dialog's confirm belongs. */
/* The modal's footer: the same card footer, flush with the modal's edges and reversed so the
   confirm action sits in the bottom-right corner a dialog puts it in. */
.modal-scroll .card-foot {
    position: sticky; bottom: 0; z-index: 9;
    margin: 0 -18px -14px; padding: 13px 18px;
    border-top: 1px solid var(--line); border-radius: 0 0 10px 10px;
    background: var(--surface);
    box-shadow: 0 -10px 22px -16px rgba(32, 24, 35, .4);
    flex-direction: row-reverse;
}
.modal-scroll .card-foot .spacer { flex: 0; }
.modal-scroll .card-foot::after { content: ""; flex: 1; }
.modal-scroll .card-foot .btn { min-width: 96px; }

@media (max-width: 640px) {
    .scrim { padding: 0; align-items: flex-end; }
    .modal { max-width: 100%; max-height: 92vh; border-radius: 12px 12px 0 0; }
}
