/* ============================================================
   DRAPTO — Design tokens
   Aesthetic: "clinical ledger" — the precision of a hospital chart
   crossed with the tabular discipline of a finance ledger. Cool
   paper background, deep trust-blue for revenue, ochre for
   risk/alerts. Serif for headers (chart-like authority), mono for
   every number (tabular alignment, ledger feel).
   ============================================================ */
:root {
  /* ══════════════════════════════════════════════════════════════════════
     ONE TOKEN BLOCK
     
     There were five :root blocks in this file, defining 20 tokens at
     conflicting values. --accent was #2563eb at line 9, #0f5f52 at 1868 and
     var(--g-700) at 2256; --sp-1 was a colour in one and 6px in another.
     
     The browser resolved all of it by last-wins, so the product looked
     consistent and was one reordering away from not being. A palette that
     depends on the order of a 4,000-line file is not a palette.
     
     Every value below is the one that was already winning, so nothing on
     screen changes. The dark theme under prefers-color-scheme keeps its own
     overrides and is untouched.
     ══════════════════════════════════════════════════════════════════════ */

  /* ══ DRAPTO BRAND ══════════════════════════════════════════════════════
     The palette, named for what each colour MEANS rather than what it is.

     A token called --brand can be recoloured once and every screen follows.
     A token called --blue cannot, because the day the blue becomes green the
     name is a lie and somebody has to touch four hundred rules.

     Deep and Brand are the navy spine — headers, the sidebar, anything that
     should read as the product itself. Accent is the green that means
     resolved: a settled claim, a paid invoice, a closed task. Deduction is
     the rust that means money left the building, and it is deliberately NOT
     red — a deduction is a fact of the business, not an error, and red makes
     routine arithmetic look like a fault.
     ══════════════════════════════════════════════════════════════════════ */
  --deep:         #08192B;
  --brand:        #0B3A5E;
  --brand-2:      #12608F;
  --brand-accent: #0F6E5A;
  --brand-accent-light: #1E9877;
  --settled:      #0F6E5A;
  --deduction:    #B04A2F;
  --ground:       #F7F9FA;

  --ink: var(--n-900);
  --ink-soft: var(--n-600);
  /* Between --ink and --ink-soft. --ink-soft (#6b7280) is right for a
     caption beside a heading and too faint for a navigation label somebody
     reads forty times a day. */
  --accent-soft: var(--brand-accent-light);
  --ink-mid: #4b5563;
  --ink-faint: var(--n-400);
  --paper: var(--ground);
  /* A literal, and it must stay one. A sweep replacing #fff with
     var(--surface) ran over this block too and turned this line into
     `--surface: var(--surface)`; --n-0 below then pointed back here and the
     pair resolved to nothing. 115 rules paint with this — headers,
     sidebars, cards, popovers — so all of them lost their background at
     once, which is what "everything is transparent" looks like.
     verify-design now fails on a token that cannot reach a literal. */
  --surface: #ffffff;
  --surface-raised: var(--n-25);
  --line: var(--n-200);
  --line-strong: var(--n-300);
  --primary: var(--brand);
  --primary-hover: var(--deep);
  --on-primary: #ffffff;
  --accent: var(--g-700);
  --accent-tint: var(--g-50);
  --critical: var(--bad);
  --critical-ink: #991b1b;
  --critical-tint: #fef2f2;
  --major: #f97316;
  --major-ink: #9a3412;
  --major-tint: #fff7ed;
  --minor: #fbbf24;
  --minor-ink: #92400e;
  --minor-tint: #fffbeb;
  --normal: #22c55e;
  --normal-ink: #166534;
  --normal-tint: #f0fdf4;
  --teal: var(--brand-accent);
  --teal-strong: #000000;
  --teal-tint: #f5f3ef;
  --amber: var(--minor-ink);
  --amber-tint: var(--minor-tint);
  --rose: var(--critical-ink);
  --rose-tint: var(--critical-tint);
  --font-display: "Source Serif 4", "Iowan Old Style", Georgia, serif;
  --font-body: "IBM Plex Sans", "Inter", -apple-system, sans-serif;
  --font-mono: "IBM Plex Mono", "JetBrains Mono", ui-monospace, monospace;
  --radius: 10px;
  --radius-sm: 7px;
  --radius-pill: 999px;
  --shadow-card: 0 1px 2px rgba(10,10,10,0.04), 0 1px 3px rgba(10,10,10,0.03);
  --accent-hover: var(--g-800);
  --warn: var(--deduction);
  --warn-tint: #fdf6e9;
  --g-50: #eaf3f0;            /* tint of --brand-accent */
  --g-100: #d6ebe6;
  --g-200: #aed7ce;
  --g-300: #7fbfb1;
  --g-400: #4fa392;
  --g-500: #2b8574;
  --g-600: #16705f;
  --g-700: var(--brand-accent);
  --g-800: #0b4a40;
  --g-900: #07332c;
  --g-950: #04211c;
  --b-50: #eef3fb;
  --b-100: #d9e5f6;
  --b-200: #b5cbec;
  --b-300: #86a9de;
  --b-400: #5885cd;
  --b-500: #3767b5;
  --b-600: #2a5296;
  --b-700: #21417a;
  --b-800: #1a3260;
  --b-900: #142543;
  --ok-bg: #e7f4ec;
  --ok: #17643c;
  --ok-line: #b9ddc8;
  --warn-bg: #fdf3e3;
  --warn-line: #edd8ae;
  --bad-bg: #fbeeeb;
  --bad: #a33a22;
  --bad-line: #edc8be;
  --info-bg: #eef3fb;
  --info: #21417a;
  --info-line: #c6d6ee;
  --n-0: var(--surface);
  --n-25: #fcfcfb;
  --n-50: #f8f8f6;
  --n-100: #f1f1ee;
  --n-200: #e6e6e1;
  --n-300: #d3d3cc;
  --n-400: #a8a8a0;
  --n-500: #7a7a72;
  --n-600: #56564f;
  --n-700: #3a3a35;
  --n-800: #232320;
  --n-900: #121210;
  --e-0: none;
  --e-1: 0 1px 2px rgba(18,18,16,.04), 0 1px 3px rgba(18,18,16,.06);
  --e-2: 0 1px 2px rgba(18,18,16,.05), 0 6px 16px -4px rgba(18,18,16,.10);
  --e-3: 0 2px 4px rgba(18,18,16,.06), 0 16px 32px -8px rgba(18,18,16,.14);
  --e-4: 0 4px 8px rgba(18,18,16,.07), 0 28px 56px -12px rgba(18,18,16,.20);
  --spec-1: #2b8574;
  --spec-1-bg: #e6f2ef;
  --spec-2: #3767b5;
  --spec-2-bg: #e9eff9;
  --spec-3: #8a5a94;
  --spec-3-bg: #f2ecf4;
  --spec-4: #a8624a;
  --spec-4-bg: #f7eeea;
  --spec-5: #4a7a3a;
  --spec-5-bg: #eaf2e7;
  --spec-6: #2f7a86;
  --spec-6-bg: #e6f1f3;
  --spec-7: #8a6f2b;
  --spec-7-bg: #f4f0e3;
  --spec-8: #6a5aa8;
  --spec-8-bg: #eeecf6;
  --t-display: 30px;
  --t-section: 19px;
  --t-body: 15px;
  --t-small: 13px;
  --t-label: 11.5px;
  --sp-1: 6px;
  --sp-2: 12px;
  --sp-3: 18px;
  --sp-4: 24px;
  --sp-6: 36px;
  --sp-8: 48px;
  --bg: var(--paper);
  --danger: var(--critical);
  --line-2: var(--line-strong);
  --line-soft: var(--line);
  --pt-accent: var(--accent);
  --od-planned: var(--ink-faint);
  --od-finding: var(--warn);
  --od-done: var(--teal);
}


* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; }

.num, .tabular {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

/* ══════════════════════════════════════════════════════════════════════
   TOP BAR

   Twenty-five links in one sidebar column put the last group below the fold
   on a laptop. People do not scroll menus — they conclude the feature is
   not there. So the six groups moved to a row across the top and the
   sidebar now shows only the current group.

   Deliberately NOT position:fixed. A fixed bar sits above the page and
   covers whatever scrolls under it, which is exactly the kind of overlap
   that makes an interface feel broken. This one is part of the flow: it
   takes its own height and the rest of the page starts below it.
   ══════════════════════════════════════════════════════════════════════ */
/* .topbar was declared HERE and again further down, and the second
   declaration set every single property this one did — so this block was
   dead and had been for a while. Dead in a dangerous way: it read as the
   definition of the bar, so a change made here (the height, most obviously)
   silently did nothing, and the two copies disagreed about the height for
   long enough to leave the sidebar 4px out. Consolidated into the single
   declaration in the app-bar section below. Do not reintroduce a second one.
   Verified by rendering after removal: top bar 1440x52, sidebar 232,
   main 1208. */

.top-brand {
  font-weight: 600;
  font-size: 15px;
  color: var(--ink);
  text-decoration: none;
  letter-spacing: -.01em;
  white-space: nowrap;
}

.top-nav {
  display: flex;
  gap: 2px;
  flex: 1;
  min-width: 0;
  /* Scrolls horizontally on a narrow screen instead of wrapping onto a
     second line, which would change the page height and push content down
     unpredictably. */
  overflow-x: auto;
  scrollbar-width: none;
}
.top-nav::-webkit-scrollbar { display: none; }

.top-link {
  padding: 7px 13px;
  border-radius: 7px;
  font-size: 13px;
  color: var(--ink-soft);
  text-decoration: none;
  white-space: nowrap;
  transition: background .12s, color .12s;
}
.top-link:hover { background: var(--teal-tint); color: var(--ink); }
.top-link.active { background: var(--teal-tint); color: var(--ink); font-weight: 600; }

.top-right {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 13px;
  color: var(--ink-soft);
  white-space: nowrap;
}
.top-right .logout-link { cursor: pointer; }

@media (max-width: 720px) {
  .topbar { gap: 12px; padding: 0 12px; }
  .top-right .who { display: none; }
}

/* ---------- App shell ---------- */
.app-shell {
  display: grid;
  grid-template-columns: 232px 1fr;
  /* The bar takes 52px, so the shell fills what is left rather than adding
     a scrollbar for the difference. */
  min-height: calc(100vh - 52px);
}

.sidebar {
  background: var(--surface);
  color: var(--ink-soft);
  padding: 26px 18px;
  display: flex;
  flex-direction: column;
  gap: 26px;
  border-right: 1px solid var(--line);
  overflow-y: auto;
  /* Sticks below the top bar. With only one group in it there is rarely
     anything to scroll, but a long group still behaves. */
  position: sticky;
  top: 52px;
  height: calc(100vh - 52px);
}
.sidebar::-webkit-scrollbar { width: 6px; }
.sidebar::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 3px; }

.brand {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: 0.01em;
}
.brand small {
  display: block;
  font-family: var(--font-body);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-top: 4px;
  font-weight: 500;
}

.nav-group { display: flex; flex-direction: column; gap: 2px; }
/* A section heading that is fainter than the links under it inverts the
   hierarchy — the eye lands on the items and has to hunt back up for the
   group. Darker and heavier than the links, not lighter. */
.nav-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-weight: 700;
  color: var(--ink-mid);
  margin: 14px 0 6px 10px;
}
/* ── THE SIDEBAR HAD TO BE SQUINTED AT ──
 *
 * 13px at --ink-soft (#6b7280) on a near-white panel is about 4.8:1 — it
 * scrapes AA for body text and fails it for anything smaller, and this is a
 * list of forty items somebody scans all day under clinic lighting.
 *
 * The fix is contrast and weight, not size: --ink-mid at 500 reads as a
 * deliberate label rather than a disabled one, and the active item no longer
 * has to shout to be found because its neighbours are legible.
 *
 * Line-height too. Forty links at 1.2 is a wall; 1.35 lets the eye find a
 * row without counting. */
.nav-link {
  padding: 9px 10px;
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--ink-mid);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.35;
  display: flex;
  align-items: center;
  gap: 9px;
  transition: background 0.12s ease, color 0.12s ease;
}
.nav-link:hover { background: var(--teal-tint); color: var(--ink); }
.nav-link.active { background: var(--teal-tint); color: var(--ink); font-weight: 600;
  box-shadow: inset 3px 0 0 var(--primary); }

.sidebar-footer {
  margin-top: auto;
  border-top: 1px solid var(--line);
  padding-top: 16px;
  font-size: 12px;
  color: var(--ink-faint);
}
/* Was #eef2f9 and #7fb0f5 — a pale blue and a link blue left from an
   earlier palette, sitting in a footer on a product whose accent is green.
   Nobody chose them here; they were carried over. */
.sidebar-footer .who { color: var(--n-50); font-weight: 600; font-size: 13px; }
.logout-link { color: var(--accent-soft); cursor: pointer; text-decoration: none; }
.logout-link:hover { text-decoration: underline; }

/* ---------- Main content ---------- */
.main {
  padding: 30px 40px 60px;
  max-width: 1320px;
  /* ── A FLEX/GRID CHILD DEFAULTS TO min-width: auto ──
   *
   * Which means it refuses to shrink below its content, so a wide child —
   * the appointment calendar with eighteen doctor columns — stretches this
   * container and pushes the whole document sideways. Measured at 390px:
   * appointments overflowed by 930px, patients by 27.
   *
   * min-width: 0 lets the container hold its ground; the calendar then
   * scrolls inside its own box, which is where a wide grid belongs. */
  min-width: 0;
  overflow-x: hidden;
}

.page-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 26px;
  border-bottom: 1px solid var(--line-strong);
  padding-bottom: 16px;
}
.page-header h1 {
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 600;
  margin: 0;
}
.page-header .subtitle {
  color: var(--ink-soft);
  font-size: 13px;
  margin-top: 4px;
}
.page-header .as-of {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-soft);
  text-align: right;
}

/* ---------- Ledger strip (signature element) ---------- */
.ledger-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  background: var(--ink);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: 28px;
  box-shadow: var(--shadow-card);
}
.ledger-cell {
  padding: 18px 22px;
  border-right: 1px solid rgba(255,255,255,0.09);
  position: relative;
}
.ledger-cell:last-child { border-right: none; }
.ledger-cell .label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: #86a89d;
  margin-bottom: 8px;
}
.ledger-cell .value {
  font-family: var(--font-mono);
  font-size: 22px;
  font-weight: 500;
  color: var(--surface);
  font-variant-numeric: tabular-nums;
}
.ledger-cell .delta {
  font-family: var(--font-mono);
  font-size: 12px;
  margin-top: 6px;
}
.delta.up { color: #6fcf9e; }
.delta.down { color: #e3947a; }

/* ---------- Cards / grid ---------- */
.grid { display: grid; gap: 16px; }
.grid-2 { grid-template-columns: 1fr 1fr; }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px 20px;
  box-shadow: var(--shadow-card);
}
.card h3 {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 600;
  margin: 0 0 14px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}
.card .kpi {
  font-family: var(--font-mono);
  font-size: 30px;
  font-weight: 500;
  color: var(--teal-strong);
}
.card .kpi-label {
  font-size: 12px;
  color: var(--ink-soft);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: 6px;
}

/* ---------- Tables (ledger-style, ruled) ---------- */
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th {
  text-align: left;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  padding: 8px 10px;
  border-bottom: 1.5px solid var(--line-strong);
  font-weight: 600;
}
td {
  padding: 9px 10px;
  border-bottom: 1px solid var(--line);
}
tr:last-child td { border-bottom: none; }
td.num, th.num { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

.rank-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px; height: 20px;
  background: var(--teal-tint);
  color: var(--teal-strong);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  border-radius: 2px;
}

/* ---------- Badges / pills ---------- */
.pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 600;
  font-family: var(--font-body);
}
.pill.severity-high, .pill.severity-critical { background: var(--rose-tint); color: var(--rose); }
.pill.severity-medium { background: var(--amber-tint); color: var(--amber); }
.pill.severity-low { background: var(--teal-tint); color: var(--teal-strong); }

/* ---------- Alerts list ---------- */
.alert-row {
  display: flex;
  gap: 12px;
  padding: 11px 0;
  border-bottom: 1px solid var(--line);
  align-items: flex-start;
}
.alert-row:last-child { border-bottom: none; }
.alert-row .dot {
  width: 7px; height: 7px; border-radius: 50%;
  margin-top: 6px; flex-shrink: 0;
}
.dot.severity-high, .dot.severity-critical { background: var(--rose); }
.dot.severity-medium { background: var(--amber); }
.dot.severity-low { background: var(--teal); }
.alert-row .msg { font-size: 13px; }
.alert-row .meta { font-size: 11px; color: var(--ink-soft); margin-top: 2px; }

/* ---------- Chart (hand-rolled SVG bars) ---------- */
.trend-chart { width: 100%; height: 160px; }
.trend-chart .bar { fill: var(--teal); opacity: 0.85; }
.trend-chart .bar:hover { opacity: 1; }
/* An SVG axis label. Chart furniture, not text somebody reads in sequence,
   so the text scale does not apply. */
.trend-chart .axis-label { font-family: var(--font-mono); font-size: 9.5px; fill: var(--ink-soft); }

/* ---------- Login page ---------- */
.login-shell {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 1fr 420px;
  background: var(--ink);
}
.login-brand-panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 60px 70px;
  color: #eef1ec;
  position: relative;
  overflow: hidden;
}
.login-brand-panel .mark {
  font-family: var(--font-display);
  font-size: 46px;
  font-weight: 600;
  color: var(--surface);
  margin-bottom: 14px;
}
.login-brand-panel .tagline {
  font-size: 15px;
  color: #9fb8ae;
  max-width: 380px;
  line-height: 1.6;
}
.login-brand-panel .ledger-decor {
  margin-top: 48px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: #587a6e;
  border-top: 1px solid rgba(255,255,255,0.1);
  padding-top: 18px;
  display: grid;
  gap: 6px;
}

.login-form-panel {
  background: var(--paper);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 56px;
}
.login-form-panel h2 {
  font-family: var(--font-display);
  font-size: 22px;
  margin: 0 0 6px;
}
.login-form-panel .hint { color: var(--ink-soft); font-size: 13px; margin-bottom: 26px; }

.field { margin-bottom: 16px; }
.field label {
  display: block;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  margin-bottom: 6px;
}
.field input {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--ink);
}
.field input:focus {
  outline: none;
  border-color: var(--teal);
  box-shadow: 0 0 0 3px var(--teal-tint);
}

/* Scoped to the login panel, where full width is the design. Written as a
   bare `.btn` this rule reached every button in the application — the later
   .btn block resets display, padding and colour but never width, so the
   100% survived the cascade and every action in every panel rendered as a
   full-width bar. The rota screen made it obvious: "Add a market" as a
   banner, Pause and Remove stacked in a table cell. */
.login-form-panel .btn {
  width: 100%;
  padding: 11px 16px;
  background: var(--teal-strong);
  color: var(--surface);
  border: none;
  border-radius: var(--radius);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s ease;
  font-family: var(--font-body);
}
.login-form-panel .btn:hover { background: var(--teal); }
.login-form-panel .btn:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }
.login-form-panel .btn:disabled { opacity: 0.6; cursor: not-allowed; }

.error-banner {
  background: var(--rose-tint);
  color: var(--rose);
  padding: 10px 12px;
  border-radius: var(--radius);
  font-size: 13px;
  margin-bottom: 16px;
  display: none;
}
.error-banner.visible { display: block; }

.demo-creds {
  margin-top: 22px;
  font-size: 12px;
  color: var(--ink-soft);
  background: var(--surface-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 14px;
}
.demo-creds strong { color: var(--ink); }
.demo-creds .row { display: flex; justify-content: space-between; padding: 3px 0; font-family: var(--font-mono); font-size: 12px; }

/* ---------- Loading / empty states ---------- */
.skeleton {
  background: linear-gradient(90deg, var(--line) 25%, var(--surface-raised) 50%, var(--line) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.4s infinite;
  border-radius: var(--radius);
  height: 14px;
}
@keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }

.empty-state {
  text-align: center;
  padding: 40px 20px;
  color: var(--ink-soft);
  font-size: 13px;
}

/* ---------- Doctor list / profile ---------- */
.doctor-card-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 14px 4px;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  transition: background 0.1s ease;
}
.doctor-card-row:hover { background: var(--surface-raised); }
.doctor-card-row:last-child { border-bottom: none; }
.doctor-card-row .name { font-weight: 600; font-size: 13px; }
.doctor-card-row .dept { font-size: 12px; color: var(--ink-soft); }
.doctor-card-row .rev { font-family: var(--font-mono); font-size: 13px; color: var(--teal-strong); }

.score-ring {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px; height: 64px;
  border-radius: 50%;
  border: 4px solid var(--teal-tint);
  font-family: var(--font-mono);
  font-size: 19px;
  font-weight: 600;
  color: var(--teal-strong);
}

@media (max-width: 900px) {
  .app-shell { grid-template-columns: 1fr; }
  .sidebar { display: none; }
  .grid-3, .grid-4 { grid-template-columns: 1fr 1fr; }
  .login-shell { grid-template-columns: 1fr; }
  .login-brand-panel { display: none; }
}

/* ============================================================
   v2 ADDITIVE STYLES — enterprise depth for the six modules.
   Same tokens, same clinical-ledger aesthetic. Nothing above
   this line changed.
   ============================================================ */

/* ---------- Toolbar: period selector + export ---------- */
.toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
.seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: var(--radius); overflow: hidden; background: var(--surface); }
.seg button {
  border: none; background: transparent; padding: 7px 14px; cursor: pointer;
  font-family: var(--font-body); font-size: 12px; color: var(--ink-soft);
  border-right: 1px solid var(--line);
}
.seg button:last-child { border-right: none; }
.seg button.active { background: var(--teal); color: var(--surface); font-weight: 600; }

.btn {
  display: inline-block; border: 1px solid var(--line-strong); background: var(--surface);
  color: var(--ink); border-radius: var(--radius); padding: 7px 14px; font-size: 12px;
  font-family: var(--font-body); cursor: pointer; text-decoration: none;
  /* Stated, not assumed. The login section's .btn set width:100% and this
     block silently inherited it for months because it never said otherwise. */
  width: auto;
}
.btn:hover { border-color: var(--teal); color: var(--teal-strong); }
.btn-primary { background: var(--teal); border-color: var(--teal); color: var(--surface); font-weight: 600; }
.btn-primary:hover { background: var(--teal-strong); color: var(--surface); }
.export-links { display: flex; gap: 8px; flex-wrap: wrap; }

/* ---------- Quick Entry modal ---------- */
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(22,36,31,0.45);
  display: flex; align-items: center; justify-content: center; z-index: 100;
  /* Padding, so a tall modal on a short window has somewhere to breathe
     rather than butting against both edges. */
  padding: 24px 16px;
  overflow-y: auto;
}
/* ══════════════════════════════════════════════════════════════════════════
   POPUPS

   ── WHAT WAS WRONG ──

   420px wide, no max-height and no scroll. A form longer than the viewport
   ran off the bottom of the screen with the Save button below the fold and
   no way to reach it — which is what "the save button is not working" looks
   like from the outside. On a laptop at 768px tall, any modal with more than
   about six fields was unfinishable.

   ── THE FIX IS THE LAYOUT, NOT THE HEIGHT ──

   A grid of three rows: a header that stays, a body that scrolls, and an
   action bar that stays. Growing the box would only move the cliff; making
   the middle the only scrolling part means the button a person is looking
   for is always on screen however long the form gets.
   ══════════════════════════════════════════════════════════════════════════ */
.modal {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: 0 8px 40px rgba(22,36,31,0.25);
  border-top: 3px solid var(--teal);

  /* Wider. 420px is a phone-sized column shown on a desktop, and every
     multi-line field inside it was three words per line. */
  width: 560px;
  max-width: calc(100vw - 32px);

  /* The whole point: never taller than the window, and the middle scrolls. */
  max-height: calc(100vh - 48px);
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: 0;
}
.modal > h3,
.modal > .hint { padding-left: 24px; padding-right: 24px; }
.modal > h3 { padding-top: 22px; }
.modal-body {
  overflow-y: auto;
  padding: 4px 24px 4px;
  /* Momentum scrolling on iOS, and a scrollbar that does not overlay the
     last field on Windows. */
  -webkit-overflow-scrolling: touch;
  scrollbar-gutter: stable;
}
.modal > .modal-actions {
  padding: 14px 24px 20px;
  border-top: 1px solid var(--line);
  background: var(--surface);
  /* Rounded with the box, or the bar corners square off against it. */
  border-radius: 0 0 var(--radius) var(--radius);
}
.modal h3 { margin: 0 0 4px; font-family: var(--font-display); font-size: 19px; }
.modal .hint { font-size: 12px; color: var(--ink-soft); margin-bottom: 16px; }
.field { margin-bottom: 12px; }
/* 13px, not uppercase. Tracked capitals at 12px are the least legible
   shape a label can take, and these name the thing somebody is typing. */
.field label { display: block; font-size: 13px; font-weight: 600;
  color: var(--ink-soft); margin-bottom: 5px; }
/* textarea was missing from this rule, so every multi-line box in the
   product fell back to the browser default: a ~2-row box in the browser's
   own monospace-ish font, unstyled and far too small for the paragraph
   somebody was being asked to write. */
.field input, .field select, .field textarea {
  width: 100%; padding: 9px 11px; border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  font-family: var(--font-body);
  /* 16, not 15. Safari on iOS zooms on focus below 16px and the person has
     to pinch back out to read what they typed. */
  font-size: 16px;
  background: var(--surface-raised); color: var(--ink);
  box-sizing: border-box;
}
.field textarea {
  /* Six rows before it scrolls, and draggable taller. A note, an address or
     a reason is not a one-line answer. */
  min-height: 132px;
  line-height: 1.55;
  resize: vertical;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent);
}
.field input:focus, .field select:focus { outline: 2px solid var(--teal-tint); border-color: var(--teal); }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px; }
.modal .success { color: var(--teal-strong); font-size: 13px; font-weight: 600; }

/* ---------- First-run activation checklist ---------- */
.checklist-card { max-width: 560px; margin: 32px auto; }
.check-item {
  display: flex; align-items: center; gap: 12px; padding: 13px 4px;
  border-bottom: 1px solid var(--line); font-size: 13px;
}
.check-item:last-child { border-bottom: none; }
.check-box {
  width: 20px; height: 20px; border-radius: 50%; border: 2px solid var(--line-strong);
  display: flex; align-items: center; justify-content: center; font-size: 12px; flex-shrink: 0;
}
.check-item.done .check-box { background: var(--teal); border-color: var(--teal); color: var(--surface); }
.check-item.done { color: var(--ink-soft); }
.check-item .act { margin-left: auto; }

/* ---------- Onboarding wizard ---------- */
.wizard-steps { display: flex; gap: 8px; margin-bottom: 22px; }
.step-dot { flex: 1; height: 4px; background: var(--line); border-radius: 2px; }
.step-dot.active { background: var(--teal); }
.wizard-title { font-family: var(--font-display); font-size: 22px; margin: 0 0 4px; }
.wizard-sub { color: var(--ink-soft); font-size: 13px; margin-bottom: 20px; }
.goal-option {
  display: flex; align-items: center; gap: 10px; border: 1px solid var(--line-strong);
  border-radius: var(--radius); padding: 11px 14px; margin-bottom: 8px; cursor: pointer; font-size: 13px;
  background: var(--surface-raised);
}
.goal-option.selected { border-color: var(--teal); background: var(--teal-tint); font-weight: 600; }

/* ---------- Business health / goal progress ---------- */
.health-ring {
  width: 74px; height: 74px; border-radius: 50%; border: 5px solid var(--teal);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: 22px; font-weight: 600; color: var(--teal-strong);
}
.health-ring.fair { border-color: var(--amber); color: var(--amber); }
.health-ring.needs_attention { border-color: var(--rose); color: var(--rose); }
.progress { height: 7px; background: var(--line); border-radius: 4px; overflow: hidden; margin-top: 5px; }
.progress > span { display: block; height: 100%; background: var(--teal); }
.progress.over > span { background: var(--amber); }

/* ---------- Misc ---------- */
.badge-verified { background: var(--teal-tint); color: var(--teal-strong); font-size: 11px; padding: 2px 8px; border-radius: 10px; font-weight: 600; }
.badge-pending  { background: var(--amber-tint); color: var(--amber); font-size: 11px; padding: 2px 8px; border-radius: 10px; font-weight: 600; }
.table-scroll { overflow-x: auto; }
.table-scroll table { min-width: 640px; }
.subnote { font-size: 11px; color: var(--ink-soft); margin-top: 8px; }

/* ============================================================
   ENTERPRISE UI FRAMEWORK — density, hierarchy, states
   ============================================================ */
.sec-head { display:flex; justify-content:space-between; align-items:flex-end; gap:12px;
  border-bottom:1px solid var(--line); padding-bottom:8px; margin:26px 0 14px; }
.sec-head h2 { font-family:var(--font-display); font-size: 17px; color:var(--ink); margin:0; }
.sec-head .sec-desc { font-size: 12px; color:var(--ink-soft); margin-top:2px; }
.sec-head .sec-meta { font-size: 11px; color:var(--ink-soft); font-family:var(--font-mono); white-space:nowrap; }

.kpi-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(158px,1fr)); gap:10px; }
.kpi-card { background:var(--surface); border:1px solid var(--line); border-radius:var(--radius);
  padding:10px 12px; box-shadow:var(--shadow-card); }
.kpi-card .k-label { font-size: 11px; text-transform:uppercase; letter-spacing:.07em; color:var(--ink-soft); }
.kpi-card .k-value { font-family:var(--font-mono); font-size: 19px; font-weight:600; color:var(--ink); margin:2px 0; }
.kpi-card .k-sub { font-size: 11px; color:var(--ink-soft); display:flex; justify-content:space-between; }
.kpi-card .k-trend.up { color:var(--normal-ink); } .kpi-card .k-trend.down { color:var(--critical-ink); }
.kpi-card.k-alert { border-left:3px solid var(--critical-ink); }
.kpi-card.k-good { border-left:3px solid var(--normal-ink); }

.health-bar { height:7px; background:var(--teal-tint); border-radius:4px; overflow:hidden; }
.health-bar i { display:block; height:100%; background:var(--teal); border-radius:4px; }
.health-row { display:flex; align-items:center; gap:10px; padding:7px 0; border-bottom:1px solid var(--line); font-size: 13px; }
.health-row .h-name { flex:1; }
.health-row .h-score { font-family:var(--font-mono); font-weight:600; width:34px; text-align:right; }
.health-row .health-bar { width:130px; }

.alert-line { display:flex; gap:9px; padding:8px 10px; border-radius:var(--radius); font-size: 13px;
  margin-bottom:6px; border:1px solid var(--line); background:var(--surface); }
.alert-line.critical { border-left:3px solid var(--critical-ink); }
.alert-line.warning { border-left:3px solid var(--amber); }
.alert-line.info { border-left:3px solid var(--teal); }

.skeleton { position:relative; overflow:hidden; background:var(--teal-tint); border-radius:var(--radius); min-height:14px; }
.skeleton::after { content:''; position:absolute; inset:0;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.65),transparent);
  animation:shimmer 1.2s infinite; }
@keyframes shimmer { from { transform:translateX(-100%);} to { transform:translateX(100%);} }

.empty-state { text-align:center; padding:26px 16px; color:var(--ink-soft); font-size: 13px; }
.empty-state .e-icon { font-size: 22px; margin-bottom:6px; opacity:.55; }
.empty-state .e-title { font-weight:600; color:var(--ink); font-size: 13px; }
.empty-state .e-hint { font-size: 12px; margin-top:3px; }
.empty-state .btn { margin-top:10px; }

.filter-bar { display:flex; gap:8px; flex-wrap:wrap; align-items:center; margin-bottom:12px; }
.filter-bar .input { width:auto; min-width:130px; }
.pager { display:flex; gap:8px; align-items:center; justify-content:flex-end; margin-top:10px; font-size: 12px; color:var(--ink-soft); }

.settings-layout { display:grid; grid-template-columns:200px 1fr; gap:18px; align-items:start; }
.settings-nav { position:sticky; top:14px; display:flex; flex-direction:column; gap:2px; }
.settings-nav a { padding:8px 11px; border-radius:var(--radius); font-size: 13px; color:var(--ink-soft); cursor:pointer; }
.settings-nav a.active, .settings-nav a:hover { background:var(--teal-tint); color:var(--teal-strong); font-weight:600; }
.form-row { display:grid; grid-template-columns:200px 1fr; gap:12px; align-items:center;
  padding:9px 0; border-bottom:1px solid var(--line); }
.form-row label { font-size: 13px; font-weight:600; }
.form-row .f-help { grid-column:2; font-size: 12px; color:var(--ink-soft); margin-top:-6px; }
.toggle { position:relative; width:36px; height:20px; background:var(--line-strong); border-radius:12px;
  cursor:pointer; transition:.15s; border:none; }
.toggle.on { background:var(--teal); }
.toggle::after { content:''; position:absolute; top:2px; left:2px; width:16px; height:16px;
  border-radius:50%; background:var(--surface); transition:.15s; }
.toggle.on::after { left:18px; }
.chip { display:inline-block; background:var(--teal-tint); color:var(--teal-strong); border-radius:10px;
  padding:2px 9px; font-size: 12px; font-weight:600; margin:2px 3px 2px 0; }
.chip .x { margin-left:5px; cursor:pointer; opacity:.6; }
@media (max-width: 860px) { .settings-layout { grid-template-columns:1fr; } .settings-nav { position:static; flex-direction:row; overflow-x:auto; } .form-row { grid-template-columns:1fr; } }

/* ============================================================
   ENTERPRISE MICRO-UX
   ============================================================ */
/* Banners (success / error / info) */
.banner-stack { position:fixed; top:14px; right:14px; z-index:2000; display:flex; flex-direction:column; gap:8px; max-width:360px; }
.banner { display:flex; gap:10px; align-items:flex-start; padding:11px 13px; border-radius:var(--radius);
  box-shadow:0 6px 24px rgba(15,23,42,.14); font-size: 13px; background:var(--surface); border:1px solid var(--line);
  animation:banner-in .22s ease; }
@keyframes banner-in { from { opacity:0; transform:translateX(20px);} }
.banner.success { border-left:3px solid var(--normal-ink); } .banner.success .b-ic { color:var(--normal-ink); }
.banner.error   { border-left:3px solid var(--critical-ink); } .banner.error .b-ic   { color:var(--critical-ink); }
.banner.info    { border-left:3px solid var(--teal); } .banner.info .b-ic { color:var(--teal); }
.banner .b-body { flex:1; } .banner .b-title { font-weight:600; }
.banner .b-act { background:none; border:1px solid var(--line); border-radius:6px; padding:2px 9px; cursor:pointer; font:inherit; font-size: 12px; }
.banner .b-x { background:none; border:none; cursor:pointer; font-size: 15px; color:var(--ink-soft); }

/* Confirm dialog */
.modal-scrim { position:fixed; inset:0; background:rgba(15,23,42,.42); z-index:2100; display:flex; align-items:center; justify-content:center; animation:banner-in .15s; }
/* The second modal system in this file. Kept because things use it, and
   given the same height and scroll behaviour so a popup does not depend on
   which one a screen happened to reach for. */
.modal-box { background:var(--surface); border-radius:8px; padding:22px;
  width: 520px; max-width: calc(100vw - 32px);
  max-height: calc(100vh - 48px); overflow-y: auto;
  box-shadow:0 20px 60px rgba(15,23,42,.3); }
.modal-box h3 { font-family:var(--font-display); margin-bottom:8px; }
.modal-box p { color:var(--ink-soft); font-size: 13px; margin-bottom:16px; }
.modal-actions { display:flex; gap:8px; justify-content:flex-end; }

/* Sticky table headers + action bars */
.table-scroll { max-height:none; }
table thead th { position:sticky; top:0; background:var(--surface); z-index:1; box-shadow:inset 0 -1px 0 var(--line); }
.sticky-actions { position:sticky; bottom:0; background:var(--surface); border-top:1px solid var(--line);
  padding:10px 0; display:flex; gap:8px; justify-content:flex-end; z-index:2; }
tbody tr { transition:background .1s; }
tbody tr:hover { background:var(--teal-tint); }

/* Pagination */
.pager { display:flex; gap:6px; align-items:center; justify-content:flex-end; margin-top:12px; font-size: 13px; color:var(--ink-soft); }
.pager button { border:1px solid var(--line); background:var(--surface); border-radius:6px; padding:5px 10px; cursor:pointer; font:inherit; }
.pager button:disabled { opacity:.4; cursor:default; }
.pager .p-cur { font-weight:600; color:var(--ink); }

/* Keyboard shortcut hint */
kbd { font-family:var(--font-mono); font-size: 11px; background:var(--paper); border:1px solid var(--line-strong);
  border-bottom-width:2px; border-radius:4px; padding:1px 5px; color:var(--ink-soft); }
.shortcut-sheet { position:fixed; inset:0; background:rgba(15,23,42,.42); z-index:2100; display:flex; align-items:center; justify-content:center; }
.shortcut-sheet .modal-box { max-width:440px; }
.shortcut-row { display:flex; justify-content:space-between; padding:6px 0; border-bottom:1px solid var(--line); font-size: 13px; }

/* Empty-state illustration */
.empty-illus { display:flex; flex-direction:column; align-items:center; gap:6px; padding:32px 16px; }
.empty-illus svg { width:72px; height:72px; opacity:.5; }

/* Freshness line */
.freshness { font-size: 12px; color:var(--ink-faint); font-family:var(--font-mono); }

/* Funnel */
.funnel-stage { display:flex; align-items:center; gap:12px; margin:0 0 3px; }
.funnel-bar { height:38px; border-radius:6px; background:linear-gradient(90deg,var(--teal),var(--teal-strong));
  display:flex; align-items:center; padding:0 12px; color:var(--surface); font-weight:600; font-size: 13px; min-width:60px; transition:width .4s; }
.funnel-meta { font-size: 12px; color:var(--ink-soft); white-space:nowrap; }
.funnel-drop { font-size: 11px; color:var(--critical-ink); }

/* ---------- Global filter bar ---------- */
#global-filters { margin: -10px 0 20px; }
.gf-bar { display:flex; align-items:center; gap:8px; flex-wrap:wrap;
  background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); padding:8px 10px; }
.gf-select, .gf-date {
  font:inherit; font-size: 13px; padding:5px 8px; border:1px solid var(--line-strong);
  border-radius:6px; background:var(--surface); color:var(--ink); cursor:pointer; }
.gf-select:hover, .gf-date:hover { border-color:var(--teal); }
.gf-select:focus, .gf-date:focus { outline:2px solid var(--teal-tint); border-color:var(--teal); }
.gf-sep { color:var(--ink-faint); font-size: 12px; }
.gf-summary { margin-left:auto; font-size: 12px; color:var(--ink-soft); font-family:var(--font-mono); }
.gf-clear { font:inherit; font-size: 12px; padding:4px 10px; border:1px solid var(--line-strong);
  background:var(--paper); border-radius:6px; cursor:pointer; color:var(--ink-soft); }
.gf-clear:hover { border-color:var(--critical-ink); color:var(--critical-ink); }

/* ---------- Drillable affordance ---------- */
.drillable { cursor:pointer; position:relative; transition:transform .1s, box-shadow .1s; }
.drillable:hover { transform:translateY(-1px); box-shadow:0 4px 14px rgba(29,78,216,.13); }
.drillable::after { content:'⤢'; position:absolute; top:8px; right:9px; font-size: 11px;
  color:var(--ink-faint); opacity:0; transition:opacity .12s; }
.drillable:hover::after { opacity:1; }
tr.drillable:hover { background:var(--teal-tint); }

/* ---------- Drill-down modal ---------- */
.dd-box { max-width:1000px; width:94vw; max-height:86vh; display:flex; flex-direction:column; }
.dd-head { display:flex; justify-content:space-between; align-items:flex-start; gap:12px; margin-bottom:12px; }
.dd-head h3 { margin-bottom:2px; }
.dd-desc { font-family:var(--font-mono); font-size: 12px; }
.dd-body { overflow:auto; flex:1; }
.dd-scroll { max-height:56vh; overflow:auto; }
.dd-scroll table { font-size: 12px; }
.dd-scroll th { position:sticky; top:0; background:var(--surface); z-index:1; }

/* ---------- Front-desk popups ---------- */
.fd-box { max-width:720px; width:94vw; max-height:88vh; display:flex; flex-direction:column; }
.fd-wide { max-width:860px; }
.fd-body { overflow:auto; flex:1; padding-right:4px; }
.fd-tabs { display:flex; gap:6px; margin-bottom:14px; }
.fd-tab { font:inherit; font-size: 13px; padding:7px 14px; border:1px solid var(--line-strong);
  background:var(--paper); border-radius:7px; cursor:pointer; color:var(--ink-soft); }
.fd-tab.on { background:var(--teal); color:var(--surface); border-color:var(--teal); font-weight:600; }
.fd-sep { font-size: 11px; text-transform:uppercase; letter-spacing:.08em; color:var(--ink-faint);
  margin:18px 0 10px; padding-bottom:5px; border-bottom:1px solid var(--line); font-weight:700; }
.fd-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(210px,1fr)); gap:10px 12px; }
.fd-f { display:flex; flex-direction:column; gap:4px; margin-bottom:8px; }
.fd-f > span { font-size: 12px; font-weight:600; color:var(--ink-soft); }
.fd-f input, .fd-f select { font:inherit; font-size: 13px; padding:8px 10px;
  border:1px solid var(--line-strong); border-radius:7px; background:var(--surface); color:var(--ink); width:100%; }
.fd-f input:focus, .fd-f select:focus { outline:2px solid var(--teal-tint); border-color:var(--teal); }
.fd-f em { font-size: 11px; font-style:normal; }
.fd-results { max-height:190px; overflow:auto; border:1px solid var(--line); border-radius:8px; margin-top:-4px; }
.fd-results:empty { display:none; }
.fd-res { padding:9px 11px; cursor:pointer; border-bottom:1px solid var(--line); }
.fd-res:last-child { border-bottom:0; }
.fd-res:hover { background:var(--teal-tint); }
.fd-chip { display:flex; justify-content:space-between; align-items:center; gap:12px;
  background:var(--teal-tint); border:1px solid var(--teal); border-radius:8px; padding:10px 12px; margin-top:6px; }
.fd-warn { background:var(--minor-tint); border:1px solid var(--minor); color:var(--minor-ink);
  padding:9px 11px; border-radius:7px; font-size: 12px; margin-top:8px; }
.fd-totals { margin-top:16px; background:var(--paper); border:1px solid var(--line);
  border-radius:9px; padding:12px 14px; }
.fd-t { display:flex; justify-content:space-between; padding:4px 0; font-size: 13px; color:var(--ink-soft); }
.fd-t.big { font-size: 15px; color:var(--ink); font-weight:700; border-top:1px solid var(--line); margin-top:5px; padding-top:8px; }
.fd-t.warn b { color:var(--minor-ink); }
.fd-status { margin-top:9px; text-align:center; font-size: 12px; font-weight:700; padding:6px;
  border-radius:6px; text-transform:uppercase; letter-spacing:.05em; }
.fd-status.ok { background:var(--normal-tint); color:var(--normal-ink); }
.fd-status.mid { background:var(--minor-tint); color:var(--minor-ink); }
.fd-status.bad { background:var(--critical-tint); color:var(--critical-ink); }
.fd-summary { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:12px;
  background:var(--paper); border:1px solid var(--line); border-radius:9px; padding:13px 15px; }
.fd-summary > div > span { display:block; font-size: 11px; color:var(--ink-faint); text-transform:uppercase; letter-spacing:.05em; }
.fd-summary strong { font-size: 15px; }
.big-out { color:var(--minor-ink); font-size: 19px !important; }
.fd-wo { margin-top:16px; border:1px solid var(--line); border-radius:8px; padding:10px 12px; }
.fd-wo summary { cursor:pointer; font-size: 12px; color:var(--ink-soft); font-weight:600; }
.fd-actions { display:flex; justify-content:flex-end; gap:8px; margin-top:18px;
  padding-top:14px; border-top:1px solid var(--line); }
.fd-actions button { font:inherit; font-size: 13px; padding:9px 18px; border-radius:8px; cursor:pointer; border:1px solid var(--line-strong); }
.btn-primary { background:var(--teal); color:var(--surface); border-color:var(--teal); font-weight:600; }
.btn-primary:hover { filter:brightness(1.08); }
.btn-ghost { background:var(--surface); color:var(--ink-soft); }
.btn-ghost.danger { color:var(--critical-ink); border-color:var(--critical-ink); }
.fd-actions button:disabled { opacity:.55; cursor:not-allowed; }

/* ---------- Icon system ---------- */
.dic { flex-shrink:0; vertical-align:-3px; }
.nav-link.has-icon { display:flex; align-items:center; gap:10px; }
.nav-link.has-icon .dic { opacity:.72; transition:opacity .15s; }
.nav-link.has-icon:hover .dic,
.nav-link.has-icon.active .dic { opacity:1; }
.empty-state .e-icon .dic { opacity:.4; }
.btn .dic, button .dic { vertical-align:-4px; margin-right:5px; }
.k-label .dic { opacity:.5; margin-right:5px; }

/* ---------- Live queue board ---------- */
.q-pill { display:inline-block; padding:3px 9px; border-radius:20px; font-size: 12px; font-weight:700;
  letter-spacing:.02em; white-space:nowrap; }
.q-grey  { background:var(--line); color:var(--ink-soft); }
.q-blue  { background:var(--accent-tint); color:var(--accent); }
.q-amber { background:var(--minor-tint); color:var(--minor-ink); }
.q-green { background:var(--normal-tint); color:var(--normal-ink); }
.q-red   { background:var(--critical-tint); color:var(--critical-ink); }
.q-actions { display:flex; gap:5px; flex-wrap:wrap; align-items:center; }
.q-btn { font:inherit; font-size: 12px; padding:5px 9px; border:1px solid var(--line-strong);
  background:var(--surface); border-radius:6px; cursor:pointer; color:var(--ink-soft);
  display:inline-flex; align-items:center; gap:4px; white-space:nowrap; }
.q-btn:hover { border-color:var(--teal); color:var(--teal); }
.q-btn.primary { background:var(--teal); color:var(--surface); border-color:var(--teal); font-weight:600; }
.q-btn.primary:hover { filter:brightness(1.08); color:var(--surface); }
.q-btn.danger:hover { border-color:var(--critical-ink); color:var(--critical-ink); }
.q-late { margin-top:12px; background:var(--minor-tint); border:1px solid var(--minor); color:var(--minor-ink);
  padding:9px 12px; border-radius:8px; font-size: 13px; display:flex; align-items:center; gap:8px; }
tr.q-emg { background:var(--critical-tint); }
.q-timeline { display:flex; flex-direction:column; gap:2px; }
.q-ev { display:flex; gap:11px; align-items:flex-start; padding:7px 0;
  border-left:2px solid var(--line); margin-left:6px; padding-left:14px; position:relative; }
.q-dot { position:absolute; left:-6px; top:11px; width:10px; height:10px; border-radius:50%;
  background:var(--line-strong); border:2px solid var(--surface); }
.q-dot.q-green { background:var(--normal); } .q-dot.q-amber { background:var(--minor); }
.q-dot.q-red { background:var(--critical); } .q-dot.q-blue { background:var(--accent); }

/* ============================================================
   SEVERITY SYSTEM — four tiers from the Cent reference.
   A vivid badge, a pale tinted card, and a matching left accent.

   One deliberate deviation: badge backgrounds use the deeper tone
   (#d97706 amber rather than #fbbf24) because white text on the
   lighter yellow falls below readable contrast. The card tints keep
   the reference's lightness exactly.
   ============================================================ */

.sev-badge {
  display:inline-block; padding:4px 11px; border-radius:var(--radius-pill);
  font-size: 12px; font-weight:700; letter-spacing:.01em; color:var(--surface); white-space:nowrap;
}
.sev-badge.critical { background:#e02d22; }
.sev-badge.major    { background:#c2410c; }
.sev-badge.minor    { background:#b45309; }
.sev-badge.normal   { background:#15803d; }

.sev-card {
  border:1px solid var(--line); border-radius:var(--radius);
  padding:18px 20px; background:var(--surface); position:relative; overflow:hidden;
  transition:transform .12s, box-shadow .12s;
}
.sev-card:hover { transform:translateY(-1px); box-shadow:0 6px 18px rgba(10,10,10,.06); }
.sev-card.critical { background:linear-gradient(120deg, var(--critical-tint) 0%, var(--surface) 62%); }
.sev-card.major    { background:linear-gradient(120deg, var(--major-tint) 0%, var(--surface) 62%); }
.sev-card.minor    { background:linear-gradient(120deg, var(--minor-tint) 0%, var(--surface) 62%); }
.sev-card.normal   { background:linear-gradient(120deg, var(--normal-tint) 0%, var(--surface) 62%); }
.sev-card h4 { font-size: 17px; font-weight:650; margin:11px 0 5px; color:var(--ink); }
.sev-card .sev-meta { font-size: 13px; color:var(--ink-soft); }
.sev-card .sev-note { font-size: 12px; color:var(--ink-faint); margin-top:3px; }
.sev-card .sev-icon { position:absolute; right:16px; top:16px; opacity:.13; }
.sev-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); gap:14px; }

/* Pill buttons, matching the reference's black / outlined pair */
.pill-dark, .pill-light {
  font:inherit; font-size: 13px; padding:10px 22px; border-radius:var(--radius-pill);
  cursor:pointer; font-weight:550; transition:filter .12s, border-color .12s;
}
.pill-dark  { background:var(--primary); color:var(--on-primary); border:1px solid var(--primary); }
.pill-dark:hover { background:var(--primary-hover); }
.pill-light { background:var(--surface); color:var(--ink); border:1px solid var(--line-strong); }
.pill-light:hover { border-color:var(--ink); }

/* Existing status pills remapped onto the new tiers */
.q-grey  { background:var(--line); color:var(--ink-soft); }
.q-blue  { background:var(--accent-tint); color:var(--accent); }
.q-amber { background:var(--minor-tint); color:var(--minor-ink); }
.q-green { background:var(--normal-tint); color:var(--normal-ink); }
.q-red   { background:var(--critical-tint); color:var(--critical-ink); }
.severity-high   { background:var(--critical-tint); color:var(--critical-ink); }
.severity-medium { background:var(--minor-tint);    color:var(--minor-ink); }
.severity-low    { background:var(--normal-tint);   color:var(--normal-ink); }
.fd-status.ok  { background:var(--normal-tint);   color:var(--normal-ink); }
.fd-status.mid { background:var(--minor-tint);    color:var(--minor-ink); }
.fd-status.bad { background:var(--critical-tint); color:var(--critical-ink); }

/* Primary buttons follow the new near-black action colour */
.btn-primary, .q-btn.primary { background:var(--primary); border-color:var(--primary); color:var(--on-primary); }
.btn-primary:hover, .q-btn.primary:hover { background:var(--primary-hover); filter:none; }
.gf-select:hover, .gf-date:hover, .q-btn:hover { border-color:var(--ink); color:var(--ink); }
.drillable:hover { box-shadow:0 4px 14px rgba(10,10,10,.08); }

/* AI narrative block */
.ai-note { font-size: 13px; line-height:1.62; color:var(--ink); background:var(--paper);
  border-left:3px solid var(--primary); border-radius:var(--radius-sm); padding:14px 16px; }
button.is-disabled, button:disabled { opacity:.5; cursor:not-allowed; }

/* ── Claim rejection risk ──
   A bar rather than a number alone. Scanning twenty-five claims for the
   dangerous ones is a shape-recognition task, and a column of percentages
   makes it a reading task. */
.risk-bar { height:6px; border-radius:3px; background:var(--line-soft); overflow:hidden; }
.risk-bar span { display:block; height:100%; border-radius:3px; }
.risk-low span { background:var(--ok); }
.risk-moderate span { background:var(--warn); }
.risk-high span { background:var(--critical); }

/* ── Revenue integrity chain ── */
.chain-row { display:flex; align-items:stretch; gap:4px; margin-top:14px;
  overflow-x:auto; padding-bottom:4px; }
.chain-stage { flex:1 1 0; min-width:104px; padding:10px 8px; border-radius:8px;
  border:1px solid var(--line); background:var(--surface); }
.chain-stage .cs-label { font-size: 11px; text-transform:uppercase;
  letter-spacing:.06em; color:var(--ink-soft); }
.chain-stage .cs-value { font-size: 17px; font-weight:600; margin-top:3px; }
.chain-stage .cs-health { font-size: 11px; color:var(--ink-soft); margin-top:2px; }
.chain-good { border-color:var(--ok-bg); } .chain-good .cs-health { color:var(--ok); }
.chain-warn { border-color:var(--warn-tint); } .chain-warn .cs-health { color:var(--warn); }
.chain-bad  { border-color:var(--critical-tint); } .chain-bad  .cs-health { color:var(--critical); }
.chain-arrow { align-self:center; color:var(--ink-soft); font-size: 13px; flex:none; }

.break-callout { margin-top:14px; padding:13px 15px; border-radius:9px;
  border:1px solid var(--critical-tint); background:rgba(198,40,40,.05); }
.break-callout.bc-ok { border-color:var(--ok-bg); background:rgba(46,125,50,.05); }
.break-callout .bc-tag { font-size: 11px; text-transform:uppercase;
  letter-spacing:.06em; color:var(--critical); display:flex; align-items:center; gap:5px; }
.break-callout.bc-ok .bc-tag { color:var(--ok); }
.break-callout .bc-stage { font-size: 17px; font-weight:600; margin-top:4px; }
.break-callout .bc-floor { font-weight:400; color:var(--ink-soft); font-size: 13px; }
.break-callout .bc-why { font-size: 13px; color:var(--ink-soft); margin-top:4px; }
.break-callout .bc-do { font-size: 13px; margin-top:7px; display:flex;
  align-items:center; gap:6px; }
.break-callout .bc-also { font-size: 11px; color:var(--ink-soft); margin-top:7px;
  padding-top:7px; border-top:1px solid var(--line-soft); }

/* ── Pre-authorisation clock ──
   Time, not money, is the sort key here — so time gets the colour. */
.pa-clock { display:inline-flex; align-items:center; gap:5px; font-size: 13px;
  font-weight:600; }
.pa-normal   { color:var(--ink-soft); font-weight:500; }
.pa-urgent   { color:var(--warn); }
.pa-critical { color:var(--critical); }
.pa-breached { color:var(--surface); background:var(--critical); padding:2px 7px; border-radius:5px; }
.pa-gaps { display:flex; flex-wrap:wrap; gap:4px; }
.pa-gap { font-size: 11px; padding:1px 6px; border-radius:4px;
  border:1px dashed var(--warn-tint); color:var(--warn); cursor:help; }
td.neg strong { color:var(--critical); }

/* ── Discharge summary quality ── */
.ds-bar { height:6px; border-radius:3px; background:var(--line-soft); overflow:hidden; }
.ds-bar span { display:block; height:100%; border-radius:3px; }
.ds-good span { background:var(--ok); }
.ds-thin span { background:var(--warn); }
.ds-poor span { background:var(--critical); }
.ds-stale { color:var(--critical); font-weight:500; }

/* ── Room upgrade calculator ── */
.tw-calc { padding:16px; }
.tw-row { display:flex; gap:12px; flex-wrap:wrap; margin-bottom:10px; }
.tw-row label { flex:1 1 180px; font-size: 12px; color:var(--ink-soft);
  display:flex; flex-direction:column; gap:4px; margin:0; }
.tw-row .input { width:100%; }

/* ── Recovery ── */
.rec-gap { color:var(--critical); }
#rec-drawer:not(:empty) { border-top:1px solid var(--line); margin-top:8px; }

/* ── Room check ── */
.rc-form { padding:16px; }
.rc-row { display:flex; gap:12px; flex-wrap:wrap; margin-bottom:10px; }
.rc-row label { flex:1 1 190px; font-size: 12px; color:var(--ink-soft);
  display:flex; flex-direction:column; gap:4px; margin:0; position:relative; }
.rc-row .input { width:100%; }
.rc-results { position:absolute; top:100%; left:0; right:0; z-index:20;
  background:var(--surface); border:1px solid var(--line); border-radius:7px;
  overflow:hidden; }
.rc-results:empty { display:none; }
.rc-hit { padding:7px 10px; cursor:pointer; font-size: 13px; color:var(--ink); }
.rc-hit:hover { background:var(--line-soft); }
.rc-over td { background:rgba(198,40,40,.035); }
.rc-muted td { opacity:.6; }
.rc-real { color:var(--critical); }
.rc-reco { margin-top:14px; padding:14px 16px; border-radius:9px;
  border:1px solid var(--ok-bg); background:rgba(46,125,50,.05);
  display:flex; align-items:center; gap:16px; flex-wrap:wrap; }
.rc-reco-tag { font-size: 11px; text-transform:uppercase; letter-spacing:.06em;
  color:var(--ok); }
.rc-reco-name { font-size: 17px; font-weight:600; flex:1; }

/* ── Setup ── */
.su-features { display:flex; flex-direction:column; gap:10px; margin-top:14px; }
.su-feature { padding:13px 15px; border-radius:9px; border:1px solid var(--line);
  background:var(--surface); }
.su-feature.su-dark { border-color:var(--critical-tint); background:rgba(198,40,40,.04); }
.su-feature.su-ok   { border-color:var(--ok-bg); background:rgba(46,125,50,.04); }
.su-head { display:flex; align-items:center; gap:9px; flex-wrap:wrap; }
.su-dot { width:9px; height:9px; border-radius:50%; background:var(--ink-soft); flex:none; }
.su-dark .su-dot { background:var(--critical); } .su-ok .su-dot { background:var(--ok); }
.su-state { font-size: 11px; text-transform:uppercase; letter-spacing:.06em;
  color:var(--ink-soft); }
.su-value { margin-left:auto; font-size: 13px; font-weight:600; color:var(--critical); }
.su-missing { margin:8px 0 0 0; padding-left:18px; font-size: 13px; color:var(--ink-soft); }
.su-fix { font-size: 13px; margin-top:7px; display:flex; align-items:center; gap:6px; }
.su-form { padding:16px; margin-top:14px; }
.su-row { display:flex; gap:12px; flex-wrap:wrap; margin-bottom:10px; }
.su-row label { flex:1 1 190px; font-size: 12px; color:var(--ink-soft);
  display:flex; flex-direction:column; gap:4px; margin:0; }
.su-row .input { width:100%; }
.su-check { flex:2 1 320px !important; flex-direction:row !important;
  align-items:flex-start; gap:8px !important; }
.su-check input { margin-top:2px; }

.rec-post { padding:16px; }
.rec-row { display:flex; gap:12px; flex-wrap:wrap; margin-bottom:10px; }
.rec-row label { flex:1 1 220px; font-size: 12px; color:var(--ink-soft);
  display:flex; flex-direction:column; gap:4px; margin:0; }
.rec-row .input { width:100%; }
.su-warn { font-size: 11px; color:var(--warn); margin-top:3px; }

/* ══════════════════════════════════════════════════════════════════════
   NADI

   A side panel, not a takeover. Somebody asking "who has not paid" is
   usually looking at something else and wants the answer beside it.

   Fixed here is correct — it is an overlay by intent, it announces itself,
   and Escape closes it. That is different from a header that silently sits
   on top of content nobody asked it to cover.
   ══════════════════════════════════════════════════════════════════════ */
.nadi-open {
  border: 1px solid var(--line);
  background: var(--teal-tint);
  color: var(--ink);
  border-radius: 7px;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.nadi-open:hover { border-color: var(--ink-faint); }

.nadi-panel {
  position: fixed;
  right: 16px; bottom: 16px;
  width: 380px; max-width: calc(100vw - 32px);
  max-height: min(620px, calc(100vh - 90px));
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 12px 40px rgba(10,10,10,.16);
  z-index: 90;
}
.nadi-panel[hidden] { display: none; }

.nadi-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-bottom: 1px solid var(--line-soft);
}
.nadi-sub { font-size: 12px; color: var(--ink-soft); margin-left: 8px; }
.nadi-x {
  border: none; background: none; font-size: 19px; line-height: 1;
  color: var(--ink-soft); cursor: pointer; padding: 0 4px;
}

.nadi-body { flex: 1; overflow-y: auto; padding: 12px 14px; }
.nadi-hint { font-size: 13px; color: var(--ink-soft); line-height: 1.55; }

.nadi-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.nadi-chip {
  border: 1px solid var(--line); background: none; border-radius: 99px;
  padding: 5px 10px; font-size: 12px; color: var(--ink-soft);
  cursor: pointer; text-align: left;
}
.nadi-chip:hover { background: var(--teal-tint); color: var(--ink); }

.nadi-msg { margin-bottom: 12px; font-size: 13px; line-height: 1.55; }
.nadi-you { color: var(--ink-soft); }
.nadi-you::before { content: 'You  '; font-size: 11px; letter-spacing: .04em; }
.nadi-nadi { color: var(--ink); }
.nadi-urgent { border-left: 3px solid var(--critical); padding-left: 10px; }

/* The provenance line. Small, but it is the difference between a number
   and a guess, and it should never be styled away. */
.nadi-meta {
  font-size: 11px; color: var(--ink-faint); margin-top: 4px;
  text-transform: lowercase; letter-spacing: .02em;
}

.nadi-list { margin: 8px 0 0; padding-left: 18px; }
.nadi-list li { margin-bottom: 5px; }
.nadi-table { width: 100%; margin-top: 8px; font-size: 12px; border-collapse: collapse; }
.nadi-table td { padding: 4px 6px; border-bottom: 1px solid var(--line-soft); }
.nadi-link { display: inline-block; margin-top: 8px; font-size: 12px; }

.nadi-foot {
  display: flex; gap: 8px; padding: 10px 12px;
  border-top: 1px solid var(--line-soft);
}
.nadi-input {
  flex: 1; border: 1px solid var(--line); border-radius: 7px;
  padding: 8px 10px; font-size: 13px; font-family: inherit;
}
.nadi-dots { color: var(--ink-faint); }

@media (max-width: 480px) {
  .nadi-panel { right: 8px; left: 8px; bottom: 8px; width: auto; }
}

/* ── BRAND ──
   The mark beside the wordmark, not instead of it. A logo alone in a top bar
   is a guessing game for anybody who has not seen it before, and this
   product is new to everybody using it. */
.top-brand { display: flex; align-items: center; gap: 8px; }
.top-mark { display: block; height: 26px; width: auto; }
@media (max-width: 560px) { .top-brand span { display: none; } }

/* The confirm step. Given room rather than tucked away — this is the moment
   somebody is about to message real patients. */
.nadi-confirm { margin-top: 10px; display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.nadi-warn { width: 100%; font-size: 12px; color: var(--critical); margin-bottom: 6px; }

/* ══════════════════════════════════════════════════════════════════════════
   REACT APP

   Classes the React screens use that the old page set never had. Appended
   rather than kept in a separate file so both frontends load one stylesheet
   and cannot drift apart on colours.
   ══════════════════════════════════════════════════════════════════════════ */

.plan-pill {
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
  margin: 10px 12px 4px; padding: 8px 11px;
  border: 1px solid var(--line); border-radius: 8px;
  font-size: 12px; background: transparent; color: inherit;
}
.plan-pill.is-urgent { border-color: var(--danger); }
.plan-name { font-weight: 600; }
.plan-sub { opacity: .7; font-size: 12px; }
.plan-pill.is-urgent .plan-sub { color: var(--danger); opacity: 1; }

.tabs {
  display: flex; gap: 2px; flex-wrap: wrap;
  border-bottom: 1px solid var(--line);
}
.tabs .tab {
  appearance: none; background: none; border: 0; cursor: pointer;
  font: inherit; font-size: 13px; color: var(--ink-soft);
  padding: 9px 14px; border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.tabs .tab:hover { color: var(--ink); }
.tabs .tab.is-active {
  color: var(--ink); font-weight: 600;
  border-bottom-color: var(--teal);
}

/* Sign-in, centred and narrow. Nothing else is on the page, so nothing
   competes with it. */
.auth-wrap {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  padding: 24px; background: var(--bg);
}
.auth-card {
  width: 100%; max-width: 360px; padding: 28px;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 2px 20px rgba(22, 36, 31, .06);
}
.auth-title {
  font-family: Georgia, "Times New Roman", serif; font-weight: 400;
  font-size: 30px; margin: 0 0 18px; text-align: center;
}

/* ── SIGNING UP IS NOT SIGNING IN ──
 *
 * Sign-in is one field and a password: a narrow centred card is right, and
 * nothing should compete with it.
 *
 * Signing up is five fields, and the same 360px column turns that into a
 * tall thin stack that reads as a form to endure rather than a product to
 * join. Worse, there is nothing on the page saying what is on the other
 * side — the moment somebody is deciding whether to bother is the one moment
 * the product says nothing at all.
 *
 * So signup gets a second panel. Same card, wider, split. */
.auth-card.auth-wide { max-width: 760px; padding: 0; overflow: hidden; }
.auth-split { display: grid; grid-template-columns: 1fr 1fr; }
.auth-split > form { padding: 28px; }
.auth-side {
  padding: 28px; background: linear-gradient(160deg, var(--deep, #08192B), var(--brand, #0B3A5E));
  color: #eaf3f7; display: flex; flex-direction: column; gap: 14px;
}
.auth-side h2 {
  font-family: Georgia, "Times New Roman", serif; font-weight: 400;
  font-size: 22px; margin: 0; line-height: 1.35;
}
.auth-side p { margin: 0; font-size: 13px; line-height: 1.65; opacity: .88; }
.auth-side ul { margin: 0; padding-left: 18px; display: grid; gap: 8px; }
.auth-side li { font-size: 13px; line-height: 1.55; opacity: .92; }
.auth-side .auth-side-foot {
  margin-top: auto; padding-top: 14px; border-top: 1px solid rgba(255,255,255,.18);
  font-size: 13px; opacity: .75;
}

/* On a phone the second panel goes BELOW the form, not above it. Somebody
   who tapped "create an account" has already decided; making them scroll
   past a pitch to reach the first field is the opposite of helpful. */
@media (max-width: 720px) {
  .auth-card.auth-wide { max-width: 420px; }
  .auth-split { grid-template-columns: 1fr; }
  .auth-side { order: 2; }
}

.nav-out {
  appearance: none; background: none; border: 0; cursor: pointer;
  font: inherit; text-align: left; width: 100%; margin-top: auto;
}

/* ══════════════════════════════════════════════════════════════════════════
   MOBILE NAVIGATION

   The sidebar is hidden below 900px and nothing replaced it — on a phone the
   application had no navigation at all. A doctor checking tomorrow's list on
   the way to work is the commonest use of this software.

   The topbar is hidden on desktop and the drawer only exists when open, so
   neither costs anything on a large screen.
   ══════════════════════════════════════════════════════════════════════════ */

/* Was mobile-only: `display:none` above 900px, with a hamburger and a brand
   label below it. There was no top bar on a desktop at all, which is why
   nothing told you which clinic you were signed into and the only sign-out
   sat at the bottom of a sixty-eight item sidebar.

   It is on everywhere now. The hamburger stays hidden above the breakpoint,
   where the sidebar is already visible. */
.topbar {
  display: flex; align-items: center; gap: 16px;
  /* NEVER WRAP. The bar now carries the six group tabs as well, and a second
     line here is not a cosmetic problem: .app-shell and .sidebar are both
     sized with calc(100vh - 52px), so a taller bar reflows every page in the
     product and leaves the sidebar overhanging its own container by exactly
     the height that was added. `height` rather than `min-height` for the
     same reason — overflow cannot push it. */
  flex-wrap: nowrap;
  /* ── NOWRAP MEANS IT MUST SCROLL, NOT SPILL ──
   *
   * The bar cannot wrap — the comment above explains why, and it is right.
   * But nowrap with nothing else pushes the whole document sideways instead:
   * measured on a 390px phone, every screen sat 25–27px past the viewport
   * and the appointment calendar 930px past it.
   *
   * A horizontal scrollbar on the BAR is a bar you swipe. A horizontal
   * scrollbar on the DOCUMENT is a page that feels broken on every screen. */
  /* ── overflow-y MUST STAY VISIBLE ──
   *
   * overflow-x: auto with overflow-y: hidden does NOT give you one axis —
   * CSS computes a non-visible overflow-y as `auto` too, so the user menu
   * that hangs 40px below the bar was clipped and the avatar appeared to do
   * nothing. Reported, and my own change caused it.
   *
   * clip with overflow-clip-margin keeps the horizontal scroll and lets the
   * dropdown escape downward. */
  overflow-x: auto;
  overflow-y: visible;
  max-width: 100vw;
  scrollbar-width: none;
  position: sticky; top: 0; z-index: 40;
  height: 52px; padding: 0 18px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);

  /* ── grid-column MUST STAY ──────────────────────────────────────────────
     Chrome.jsx renders <TopBar> as a direct child of .app-shell, which is
     `display: grid; grid-template-columns: 232px 1fr`. `position: sticky`
     does NOT take an element out of normal flow — unlike `fixed` — so the
     bar is still a grid item and, without this, it occupies cell (1,1): the
     232px navigation column. The sidebar is then pushed into column 2 and
     .main wraps onto row 2 in column 1. Measured at 1440x900 that produced
         sidebarWidth 1208   mainWidth 232
     i.e. the columns effectively swapped — navigation filling the page and
     the actual screen squeezed into a 232px strip. Spanning every column
     puts the bar back across the top where it belongs.

     The height is 52px, not 56px, deliberately: .app-shell and .sidebar
     both size themselves with calc(100vh - 52px), so 56px here made the
     sidebar 4px taller than its own container. */
  grid-column: 1 / -1;
}
.topbar-menu { display: none; }

.tb-org { display: flex; align-items: baseline; gap: 9px; min-width: 0; flex: none; }
.tb-org-name {
  font-weight: 600; font-size: 13px; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 260px;
}
.tb-branch {
  font-size: 12px; color: var(--ink-soft); white-space: nowrap;
  padding: 2px 8px; border: 1px solid var(--line); border-radius: 20px;
}

/* ══ THE GROUP TABS ══
   The first level of the navigation. Six of them for a clinic, four for a
   doctor, two for a company, and none at all when a shell has only one
   group — see the comment in TopBar.jsx.

   `flex: none` is deliberate: the tabs do not shrink. Search shrinks
   instead, because a search box at 200px is still a search box and a tab
   strip squeezed to 200px is six unreadable slivers. */
.tb-tabs { display: flex; align-items: center; gap: 2px; flex: none; }
.tb-tab {
  display: inline-flex; align-items: center; gap: 7px;
  /* 40, not 32: this is the primary navigation and a target people miss is
     a control they do not have. It also sits inside a 52px bar without
     touching either edge. */
  height: 40px; padding: 0 11px;
  background: none; border: 0; border-radius: 8px;
  font: inherit; font-size: 13px; color: var(--ink-soft);
  white-space: nowrap; cursor: pointer;
}
.tb-tab:hover { background: var(--teal-tint); color: var(--ink); }
/* Filled AND underlined. The tint is two shades off the bar's own white,
   which reads on the screen it was picked on and does not read on a clinic's
   old monitor at an angle; the 2px rule is unambiguous at any angle. */
.tb-tab.is-active {
  background: var(--teal-tint);
  color: var(--ink);
  font-weight: 600;
  box-shadow: inset 0 -2px 0 var(--primary);
}
.tb-tab:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
/* Sized here rather than on the element, so one rule moves every icon. */
.nav-ico { width: 17px; height: 17px; flex: none; }

/* ── BETWEEN 900 AND 1200: ICONS, NO TEXT ──
   Measured at 1440: a 260px clinic name, six labelled tabs at ~90px, a
   460px search, a bell and an avatar come to about 1150px and fit with room
   to spare. At 1024 they do not, and something has to give. Dropping the
   labels takes the strip from ~540px to ~240px and gives it back — every
   tab is still there, still clickable, still 40px, and still names itself
   to a screen reader and on hover. Nothing is removed and, critically,
   nothing wraps: the bar's height cannot change. */
@media (max-width: 1199px) {
  .tb-tab { padding: 0 10px; }
  .tb-tab-text { display: none; }
}

/* Takes the middle, because finding a patient is the thing done from every
   screen and it was previously only possible from two of them.
   min-width:0 lets it shrink past the input's intrinsic width, which is what
   keeps the tabs at full size on a 1200px laptop instead of overflowing. */
.tb-search { position: relative; flex: 1 1 0; min-width: 0; max-width: 460px; margin: 0 auto; }
.tb-input {
  width: 100%; height: 34px; padding: 0 12px; font: inherit; font-size: 13px;
  background: var(--bg); color: inherit;
  border: 1px solid var(--line); border-radius: 8px;
}
.tb-input:focus { outline: 2px solid var(--teal); outline-offset: -1px; }
.tb-results {
  position: absolute; top: 40px; left: 0; right: 0; z-index: 60;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 10px; box-shadow: 0 8px 28px rgba(0,0,0,.10); overflow: hidden;
}
.tb-result {
  display: flex; justify-content: space-between; gap: 12px; width: 100%;
  padding: 10px 13px; background: none; border: 0; border-bottom: 1px solid var(--line);
  font: inherit; text-align: left; cursor: pointer;
}
.tb-result:last-child { border-bottom: 0; }
.tb-result:hover { background: var(--teal-tint); }
.tb-empty { padding: 12px 13px; font-size: 13px; color: var(--ink-soft); }

.tb-bell {
  position: relative; margin-left: auto; width: 40px; height: 40px;
  background: none; border: 0; cursor: pointer; font-size: 17px; line-height: 1;
  border-radius: 8px;
}
.tb-bell:hover { background: var(--teal-tint); }
.tb-badge {
  position: absolute; top: 2px; right: 0; min-width: 17px; height: 17px;
  padding: 0 4px; border-radius: 9px; background: var(--danger);
  color: var(--surface); font-size: 11px; font-weight: 700; line-height: 17px; text-align: center;
}

.topbar::-webkit-scrollbar { display: none; }
.tb-user { position: relative; flex: none; }
/* 40px, not 32. The user menu is where sign out lives, and a target people
   miss on a phone is a control they do not have. */
.tb-userbtn {
  width: 40px; height: 40px; border-radius: 50%; cursor: pointer;
  background: var(--teal); color: var(--surface); border: 0;
  font-weight: 600; font-size: 13px;
}
.tb-menu {
  position: absolute; top: 40px; right: 0; z-index: 60; min-width: 210px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 10px; box-shadow: 0 8px 28px rgba(0,0,0,.10); overflow: hidden;
}
.tb-menu-who {
  display: flex; flex-direction: column; gap: 2px; padding: 11px 13px;
  border-bottom: 1px solid var(--line); font-size: 13px;
}
.tb-menu-item {
  display: block; width: 100%; padding: 10px 13px; background: none; border: 0;
  font: inherit; font-size: 13px; text-align: left; cursor: pointer;
}
.tb-menu-item:hover { background: var(--teal-tint); }
.tb-menu-out { color: var(--danger); border-top: 1px solid var(--line); }

/* ── WHAT WAS HERE: .nav-title AND .nav-caret ──
   The collapsible group header and its +/− caret. Both are gone with the
   accordion they belonged to: the six groups are tabs in the bar above, and
   the sidebar shows one group's screens flat. Deleted rather than left in
   place, because dead CSS for a control that no longer exists is how
   `.nav-link.has-icon .dic` came to be in this file describing an icon
   system nothing has ever rendered. */

/* The group heading, in the MOBILE DRAWER only. The drawer shows the whole
   two-level tree — the tabs that would otherwise name each group are hidden
   at that width — so without these six groups run into one 58-item list.
   The desktop sidebar has no heading: the lit tab directly above it is the
   heading. */
.nav-head {
  display: flex; align-items: center; gap: 8px;
  margin: 14px 0 2px; padding: 0 18px;
  font-size: 11px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-faint);
}

/* ── THE ACTIVE SCREEN ──
   `.nav-link.active` was declared near the top of this file and never
   matched anything: the React shell passes a className FUNCTION to NavLink,
   which replaces react-router's default `active` class with `is-active`. So
   no sidebar link has been highlighted since the shell was written — you
   could not tell from the rail which screen you were on. It matters more now
   that the rail is the only list on screen, so the class the app actually
   emits is styled here. The old rule is left where it is; it costs nothing
   and the marketing pages still use `.active` on their own links. */
.nav-link.is-active {
  background: var(--teal-tint); color: var(--ink);
  font-weight: 600; box-shadow: inset 3px 0 0 var(--primary);
}

@media (max-width: 900px) {
  .topbar { gap: 10px; height: 52px; padding: 0 10px; }
  /* Six tabs cannot fit beside a clinic name, a bell and an avatar on a
     390px screen, and they must not wrap. They are hidden here and the
     hamburger drawer shows the full two-level tree instead — every group
     headed, every screen under it, nothing collapsed. A horizontally
     scrollable strip was the alternative and was not chosen: it hides
     destinations off the right edge with no affordance saying they are
     there, and it would still need the drawer for the second level. */
  .tb-tabs { display: none; }
  /* Below the breakpoint the sidebar is hidden, so the menu button is the
     only way to navigate and has to come back. */
  .topbar-menu { display: flex; }
  /* The clinic name and the bell stay; search collapses, because a 200px
     input beside them is unusable and the Patients screen has its own. */
  .tb-search { display: none; }
  .tb-org-name { max-width: 150px; }
  .topbar-brand {
    font-family: Georgia, "Times New Roman", serif; font-size: 19px;
    flex: 1; text-align: center;
  }
  /* 44px, because a smaller tap target on a phone is a target people miss. */
  .topbar-menu {
    width: 44px; height: 44px; display: flex; flex-direction: column;
    justify-content: center; gap: 5px; padding: 0 11px;
    background: none; border: 0; cursor: pointer;
  }
  .topbar-menu span {
    display: block; height: 2px; border-radius: 2px;
    background: var(--ink);
  }
  .topbar-out {
    background: none; border: 0; cursor: pointer; font: inherit;
    font-size: 13px; color: var(--ink-soft); padding: 8px;
  }

  .drawer-scrim {
    position: fixed; inset: 0; z-index: 50;
    background: rgba(22, 36, 31, .35);
  }
  .drawer {
    position: fixed; top: 0; left: 0; bottom: 0; z-index: 51;
    width: min(84vw, 300px);
    background: var(--surface);
    border-right: 1px solid var(--line);
    /* The nav is long. Momentum scrolling, and padding at the bottom so the
       last item is not under a phone's home indicator. */
    overflow-y: auto; -webkit-overflow-scrolling: touch;
    padding: 14px 0 40px;
  }
  .drawer .nav-link { padding: 11px 18px; }

  /* Room for the sticky topbar, and less wasted margin on a narrow screen. */
  .main { padding: 16px 14px 40px; }
  .wrap { padding: 0; }
  h1 { font-size: 22px; }
}

/* ── TABLES ON A PHONE ──

   A table with six columns cannot be made narrow. It scrolls sideways
   instead, which is honest — squeezing columns to fit produces a table
   nobody can read either way. */
@media (max-width: 900px) {
  .card > .tbl, .tbl { font-size: 13px; }
  .tbl th, .tbl td { padding: 9px 8px; white-space: nowrap; }
  .card { border-radius: 10px; }
}

@media (max-width: 560px) {
  /* Figures stack rather than shrinking to three per row. */
  .plan-pill { margin: 10px 14px 4px; }
  /* Width and height only. overflow-y: auto here made the whole modal
     scroll, including the header and the button bar, which is the behaviour
     the grid exists to replace — on a phone the buttons scrolled away
     exactly as they did on a laptop. The body scrolls; the box does not. */
  .modal { width: calc(100vw - 24px) !important; max-height: calc(100vh - 24px); }
  .tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .tabs .tab { white-space: nowrap; }
}

/* ══════════════════════════════════════════════════════════════════════════
   DARK MODE — PATIENT PAGES

   Somebody reading a prescription at two in the morning gets a white flash
   otherwise, and two in the morning is exactly when people read them.

   Only the tokens are redefined. Every rule in the stylesheet already uses
   them, so nothing else changes and nothing can drift out of step.

   Applied to the public pages only. The clinic application is used in
   daylight on a desk, and inverting a screen full of clinical tables
   introduces contrast problems nobody asked for.
   ══════════════════════════════════════════════════════════════════════════ */
@media (prefers-color-scheme: dark) {
  .patient-page {
    --bg: #12100e;
    --surface: #1c1a18;
    --ink: #f2efe9;
    --ink-soft: #b9b3a8;
    --ink-faint: #8d867b;
    --line: #33302c;
    --accent: #4fb3a3;
    --accent-tint: #1e2c29;
    --danger: #f08a86;
    --warn: #f0a860;
    color-scheme: dark;
  }

  /* An image on a dark page at full brightness is a torch in the face. */
  .patient-page img { filter: brightness(.9); }
}

/* ══════════════════════════════════════════════════════════════════════════
   NADI — THE COMMAND BAR

   Sits above everything, reachable from every screen with Ctrl-K. A chat
   window asks somebody to have a conversation; a command bar asks them to
   say one thing and get on with their day.
   ══════════════════════════════════════════════════════════════════════════ */

.nadi-fab {
  position: fixed; right: 20px; bottom: 20px; z-index: 30;
  display: flex; align-items: center; gap: 9px;
  padding: 11px 16px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 13px; font-weight: 600;
  background: var(--ink); color: var(--surface); border: 0;
  box-shadow: 0 3px 14px rgba(22, 36, 31, .22);
}
.nadi-fab:hover { transform: translateY(-1px); }

.nadi-key {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 11px; opacity: .6;
  padding: 2px 6px; border: 1px solid currentColor; border-radius: 4px;
}

.nadi-scrim {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(22, 36, 31, .3);
  display: flex; align-items: flex-start; justify-content: center;
  /* Near the top, not centred — somebody typing looks up, and a box that
     jumps around as its content grows is disorienting. */
  padding: 12vh 16px 16px;
}

.nadi-bar {
  width: 100%; max-width: 620px;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 12px 44px rgba(22, 36, 31, .18);
  display: flex; flex-direction: column; max-height: 74vh; overflow: hidden;
}

.nadi-input-row {
  display: flex; align-items: center; gap: 10px;
  padding: 4px 16px; border-bottom: 1px solid var(--line);
}
.nadi-input {
  flex: 1; border: 0; outline: 0; background: none;
  font: inherit; font-size: 17px; padding: 16px 0;
  color: var(--ink);
}
.nadi-input::placeholder { color: var(--ink-faint); }

/* ── THE MICROPHONE ──
   Sits in the input row next to the box, not replacing it: somebody
   mid-consultation dictates, somebody at a desk types, and the product
   should not make that choice for them.

   The live state pulses rather than only changing colour. A recording
   indicator that relies on colour alone is one a colour-blind user cannot
   distinguish from the idle state, and "am I still recording" is exactly the
   question it exists to answer. */
.nadi-mic {
  flex: 0 0 auto;
  width: 38px; height: 38px;
  border: 1px solid var(--line); border-radius: 50%;
  background: none; cursor: pointer;
  font-size: 16px; line-height: 1;
  color: var(--ink-soft);
  display: grid; place-items: center;
  transition: border-color .15s, background .15s, color .15s;
}
.nadi-mic:hover:not(:disabled) { border-color: var(--ink-faint); color: var(--ink); }
.nadi-mic:disabled { opacity: .45; cursor: default; }
.nadi-mic:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

.nadi-mic.is-live {
  border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
  color: var(--danger);
  animation: nadi-mic-pulse 1.4s ease-in-out infinite;
}
@keyframes nadi-mic-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--danger) 40%, transparent); }
  50%      { box-shadow: 0 0 0 6px color-mix(in srgb, var(--danger) 0%, transparent); }
}
/* Honoured, like every other motion in this sheet. A pulsing control is
   exactly the kind somebody with vestibular sensitivity has turned motion
   off to avoid — the colour and border still carry the state. */
@media (prefers-reduced-motion: reduce) {
  .nadi-mic.is-live { animation: none; }
}

.nadi-body { overflow-y: auto; padding: 10px 8px 12px; }

.nadi-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-faint); padding: 6px 10px 4px;
}
.nadi-suggestion {
  display: block; width: 100%; text-align: left;
  background: none; border: 0; cursor: pointer; font: inherit; font-size: 13px;
  padding: 9px 10px; border-radius: 8px; color: var(--ink);
}
.nadi-suggestion:hover { background: var(--accent-tint); }

.nadi-answer { padding: 12px 10px 6px; font-size: 15px; }
.nadi-again {
  display: block; margin-top: 14px;
  background: none; border: 0; cursor: pointer; font: inherit;
  font-size: 13px; color: var(--ink-soft); padding: 0;
}
.nadi-again:hover { color: var(--ink); }

.nadi-foot {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  padding: 10px 16px; border-top: 1px solid var(--line);
  font-size: 12px; color: var(--ink-faint);
}

@media (max-width: 560px) {
  .nadi-scrim { padding: 8vh 10px 10px; }
  .nadi-input { font-size: 17px; }   /* 16px, or iOS zooms the page on focus */
  .nadi-fab { right: 14px; bottom: 14px; padding: 10px 14px; }
  .nadi-fab .nadi-key { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   WHO ARE YOU

   One form asked a hospital owner, a visiting consultant and a patient the
   same questions, which suited none of them.
   ══════════════════════════════════════════════════════════════════════════ */

.auth-card-wide { max-width: 680px; }

.who-grid { display: grid; gap: 12px; margin-top: 18px; }

.who-option {
  display: block; width: 100%; text-align: left; cursor: pointer;
  font: inherit; color: inherit;
  padding: 18px; border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
}
.who-option:hover {
  border-color: var(--teal);
  box-shadow: 0 2px 12px rgba(22, 36, 31, .07);
}
.who-cta { font-size: 13px; font-weight: 600; color: var(--teal); }

@media (max-width: 560px) { .who-option { padding: 15px; } }

/* ══════════════════════════════════════════════════════════════════════════
   WHO ARE YOU

   Three cards, not a dropdown. A dropdown asks somebody to know what the
   options mean before they can read them.
   ══════════════════════════════════════════════════════════════════════════ */

.auth-card-wide { max-width: 780px; }

.who-grid {
  display: grid; gap: 12px; margin-top: 18px;
  grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
}

.who-option {
  text-align: left; cursor: pointer; font: inherit;
  padding: 18px; border-radius: 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  display: flex; flex-direction: column;
  color: inherit;
}
.who-option:hover {
  border-color: var(--teal);
  box-shadow: 0 2px 12px rgba(22, 36, 31, .08);
}
.who-option:focus-visible {
  outline: 2px solid var(--teal); outline-offset: 2px;
}

.who-cta {
  margin-top: auto; font-size: 13px; font-weight: 600;
  color: var(--teal);
}

@media (max-width: 560px) {
  /* One per row on a phone. Three cards side by side at 380px is three
     unreadable cards. */
  .who-grid { grid-template-columns: 1fr; }
  .who-option { padding: 15px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   A PATIENT'S OWN PAGE

   Read on a ₹6,000 phone, at eleven at night, on two bars. Everything below
   assumes that first and a desktop second, because the person most likely to
   be checking a lab result late is the person this has to be fastest for.
   ══════════════════════════════════════════════════════════════════════════ */

.pt-accent { --pt-accent: var(--teal); }

#portal-app { --pt-accent: var(--teal); max-width: 1040px; margin: 0 auto; }

.pt-top {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 16px; flex-wrap: wrap; padding: 26px 0 18px;
  border-bottom: 1px solid var(--line);
}
.pt-eb {
  margin: 0; font-size: 12px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-faint);
}
.pt-name { margin: 3px 0 0; font-size: 30px; line-height: 1.15; }
.pt-uhid { margin: 3px 0 0; font-size: 12px; color: var(--ink-faint); }

.pt-call {
  padding: 9px 15px; border-radius: 999px; font-size: 13px; font-weight: 600;
  border: 1px solid var(--pt-accent); color: var(--pt-accent); text-decoration: none;
  /* 44px of target. A phone number on a phone should not need aiming at. */
  min-height: 44px; display: inline-flex; align-items: center;
}

/* One sentence, chosen. Six panels of equal weight is a page nobody reads
   past the first. */
.pt-headline {
  margin: 20px 0 22px; padding: 22px;
  border-radius: 14px; border-left: 3px solid var(--pt-accent);
  background: var(--accent-tint);
}
.pt-headline-t { margin: 4px 0 14px; font-size: 19px; line-height: 1.35; font-weight: 600; }

.pt-btn {
  display: inline-flex; align-items: center; min-height: 44px;
  padding: 0 18px; border-radius: 999px; text-decoration: none;
  font-size: 13px; font-weight: 600;
  background: var(--pt-accent); color: var(--surface);
}
.pt-ghost { background: none; color: var(--pt-accent); border: 1px solid var(--pt-accent); }

.pt-grid {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
.pt-card {
  padding: 22px; border-radius: 14px;
  border: 1px solid var(--line); background: var(--surface);
}
.pt-h { margin: 0 0 12px; font-size: 17px; }

.pt-l { margin: 0; padding: 0; list-style: none; }
.pt-l li {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px;
  padding: 11px 0; border-bottom: 1px solid var(--line-soft);
  line-height: 1.55;
}
.pt-l li:last-child { border-bottom: 0; }
.pt-l li b { font-size: 13px; }
.pt-l li span { font-size: 13px; color: var(--ink-soft); }
.pt-l li a {
  margin-left: auto; font-size: 13px; font-weight: 600;
  color: var(--pt-accent); text-decoration: none;
  /* Its own row on a narrow screen rather than a tap target crushed against
     the edge. */
  min-height: 32px; display: inline-flex; align-items: center;
}
.pt-past b, .pt-past span { color: var(--ink-faint); }
.pt-tag {
  font-size: 12px; text-transform: uppercase; letter-spacing: .05em;
}

.pt-empty { margin: 0; color: var(--ink-faint); font-size: 13px; }
.pt-note {
  margin: 12px 0 0; font-size: 12px; line-height: 1.6;
  color: var(--ink-faint);
}

.pt-emergency {
  margin: 26px 0 40px; padding: 16px 18px;
  border-radius: 12px; border: 1px solid var(--line);
  font-size: 13px; line-height: 1.6; color: var(--ink-soft);
}

@media (max-width: 620px) {
  .pt-top { padding: 18px 0 14px; }
  .pt-name { font-size: 22px; }
  .pt-headline { padding: 18px; margin: 16px 0 18px; }
  .pt-headline-t { font-size: 19px; }
  .pt-card { padding: 18px; }
  .pt-btn, .pt-call { width: 100%; justify-content: center; }
  /* The link drops below rather than being squeezed against the edge. */
  .pt-l li a { margin-left: 0; width: 100%; }
}

/* Quiet, at the foot of the navigation. Whose product this is belongs
   somewhere findable, not somewhere loud. */
.nav-made {
  margin: 22px 12px 8px; padding-top: 14px;
  border-top: 1px solid var(--line-soft);
  font-size: 12px; letter-spacing: .04em;
  color: var(--ink-faint);
}

.made-by {
  max-width: 1040px; margin: 32px auto 24px; padding: 0 20px;
  font-size: 12px; letter-spacing: .04em;
  color: var(--ink-faint);
}

/* ══════════════════════════════════════════════════════════════════════════
   ONE PRODUCT, NOT TWO

   The marketing site settled on a single deep-green accent. The app was
   still on the blue every health SaaS uses. A clinic that clicks "Start
   free" and lands somewhere that looks like a different company has been
   given a reason to wonder, at exactly the wrong moment.

   Only the accent and its supporting shades move. Ink, surfaces and the
   critical red are already right and are left alone — a wholesale token swap
   would restyle 72 screens nobody has looked at.
   ══════════════════════════════════════════════════════════════════════════ */



/* Anything that hardcoded the old blue rather than using the token. */
a { color: var(--accent); }
a:hover { color: var(--accent-hover); }
.btn-primary, .btn.btn-primary {
  background: var(--accent); border-color: var(--accent); color: var(--surface);
}
.btn-primary:hover, .btn.btn-primary:hover {
  background: var(--accent-hover); border-color: var(--accent-hover);
}
.inp:focus, input:focus, select:focus, textarea:focus {
  outline-color: var(--accent);
}

/* ══════════════════════════════════════════════════════════════════════════
   LOADING

   These pages are rendered on the server, so the content is there before any
   JavaScript runs — there is nothing to wait for. What DOES take a moment is
   anything the page fetches after load: a booking calendar, a directory
   filter, a community list.

   So this is a skeleton for those, not a spinner over the whole page. A
   spinner hiding content that has already arrived is a page made slower to
   look busy.
   ══════════════════════════════════════════════════════════════════════════ */

.skel {
  border-radius: 8px;
  background: linear-gradient(90deg,
    var(--line-soft) 25%,
    var(--line) 37%,
    var(--line-soft) 63%);
  background-size: 400% 100%;
  animation: skel 1.3s ease-in-out infinite;
}
@keyframes skel { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

.skel-line { height: 13px; margin-bottom: 9px; }
.skel-line:last-child { width: 62%; margin-bottom: 0; }
.skel-title { height: 21px; width: 45%; margin-bottom: 14px; }
.skel-card {
  padding: 20px; border-radius: 12px;
  border: 1px solid var(--line); margin-bottom: 12px;
}
.skel-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

/* A quiet bar at the very top, for a fetch that has no obvious place on the
   page to show progress. */
.loadbar {
  position: fixed; inset: 0 auto auto 0; height: 2px; width: 100%;
  z-index: 2000; transform-origin: 0 50%;
  background: var(--accent);
  animation: loadbar 1.4s ease-in-out infinite;
}
@keyframes loadbar {
  0%   { transform: scaleX(0);   opacity: 1; }
  60%  { transform: scaleX(.85); opacity: 1; }
  100% { transform: scaleX(1);   opacity: 0; }
}

/* Somebody who asked for less motion gets a static bar rather than none —
   removing the only signal that something is happening is not an
   improvement. */
@media (prefers-reduced-motion: reduce) {
  .skel { animation: none; background: var(--line-soft); }
  .loadbar { animation: none; opacity: .6; }
}

/* ══════════════════════════════════════════════════════════════════════════
   THE COMMUNITY SUBMENU

   On every community page, so a cardiologist who lands on the paediatrics
   page is one click from theirs rather than back at the index. It scrolls
   sideways rather than wrapping — twenty specialities on four lines is a
   menu people scroll past.
   ══════════════════════════════════════════════════════════════════════════ */

.csub {
  display: flex; gap: 8px; margin: 22px 0 26px;
  overflow-x: auto; scrollbar-width: none; padding-bottom: 4px;
}
.csub::-webkit-scrollbar { display: none; }
.csub a {
  flex: 0 0 auto; padding: 7px 14px; border-radius: 999px;
  font-size: 13px; font-weight: 500; text-decoration: none;
  border: 1px solid var(--line);
  color: var(--ink-soft); background: var(--surface);
}
.csub a:hover {
  border-color: var(--accent); color: var(--accent);
  background: var(--accent-tint);
}

/* ══════════════════════════════════════════════════════════════════════════
   NADI — THE PAGE

   Conversations down the left, the exchange in the middle. On a phone the
   list collapses to a horizontal strip, because a sidebar taking half a
   390px screen is a sidebar nobody keeps open.
   ══════════════════════════════════════════════════════════════════════════ */

/* min-height, not height.
   `height: calc(100vh - 190px)` hard-codes how much is above it — a title,
   a lead line and nothing else. Adding the AI key panel above pushed the
   total past the viewport, and the page heading ended up drawn over the top
   bar. Any future addition to this screen would have done the same.

   min-height keeps the conversation column tall on an empty screen, which
   is what the fixed height was for, without asserting what else is on the
   page. */
.nadi-wrap {
  display: grid; grid-template-columns: 250px 1fr; gap: 20px;
  min-height: min(calc(100vh - 190px), 620px);
}
.nadi-side {
  display: flex; flex-direction: column; gap: 6px;
  overflow-y: auto; padding-right: 4px;
}
.nadi-new { width: 100%; margin-bottom: 8px; }
.nadi-thread {
  text-align: left; width: 100%; padding: 10px 12px; border-radius: 10px;
  border: 1px solid transparent; background: none; cursor: pointer; font: inherit;
}
.nadi-thread:hover { background: var(--surface-raised); }
.nadi-thread.is-on {
  background: var(--accent-tint); border-color: var(--accent);
}
.nadi-thread b {
  display: block; font-size: 13px; line-height: 1.35; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nadi-thread span { display: block; margin-top: 2px; font-size: 12px;
  color: var(--ink-faint); }

.nadi-main {
  display: flex; flex-direction: column; min-height: 0;
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--surface); overflow: hidden;
}
.nadi-log { flex: 1; overflow-y: auto; padding: 20px; }

.nadi-empty { max-width: 520px; margin: 40px auto; text-align: center; }
.nadi-empty p { font-size: 13px; line-height: 1.65; color: var(--ink-soft); }
.nadi-chips { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center;
  margin-top: 18px; }
.nadi-chip {
  padding: 8px 14px; border-radius: 999px; cursor: pointer; font: inherit;
  font-size: 13px; background: var(--surface);
  border: 1px solid var(--line); color: var(--accent);
}
.nadi-chip:hover { border-color: var(--accent);
  background: var(--accent-tint); }

.nadi-turn { margin-bottom: 16px; }
.nadi-bubble {
  display: inline-block; max-width: 88%; padding: 11px 15px;
  border-radius: 14px; font-size: 13px; line-height: 1.6;
  white-space: pre-wrap; word-break: break-word;
}
.nadi-user { text-align: right; }
.nadi-user .nadi-bubble {
  background: var(--accent); color: var(--surface); border-bottom-right-radius: 5px;
}
.nadi-nadi .nadi-bubble {
  background: var(--surface-raised); border: 1px solid var(--line);
  border-bottom-left-radius: 5px;
}
.nadi-turn.is-err .nadi-bubble {
  background: var(--critical-tint); border-color: #e5c9bf; color: #b04a2f;
}
.nadi-wait { color: var(--ink-faint); }
.nadi-src { margin: 5px 0 0 2px; font-size: 12px; color: var(--ink-faint); }
.nadi-rows { margin-top: 10px; font-size: 13px; width: 100%; }
.nadi-rows td { padding: 5px 8px; border-bottom: 1px solid var(--line); }

.nadi-ask {
  display: flex; gap: 8px; padding: 12px;
  border-top: 1px solid var(--line);
}
.nadi-ask input {
  flex: 1; min-height: 44px; padding: 0 14px; font: inherit; font-size: 13px;
  border: 1px solid var(--line); border-radius: 11px; min-width: 0;
}
.nadi-ask input:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.nadi-foot {
  margin: 0; padding: 0 12px 12px; font-size: 12px;
  color: var(--ink-faint);
}

@media (max-width: 780px) {
  .nadi-wrap { grid-template-columns: 1fr; height: auto; }
  /* A sidebar taking half a 390px screen is a sidebar nobody keeps open. */
  .nadi-side { flex-direction: row; overflow-x: auto; padding-bottom: 6px; }
  .nadi-new { width: auto; flex: 0 0 auto; margin: 0; }
  .nadi-thread { flex: 0 0 190px; border: 1px solid var(--line); }
  .nadi-main { height: 62vh; }
}

.nadi-search {
  width: 100%; min-height: 38px; padding: 0 12px; margin-bottom: 8px;
  font: inherit; font-size: 13px;
  border: 1px solid var(--line); border-radius: 10px;
}
.nadi-search:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
/* The line that matched, so somebody sees why a thread came back. */
.nadi-thread em {
  display: block; margin-top: 3px; font-size: 12px; font-style: normal;
  color: var(--accent); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── THE PUBLIC HEADER ──
   Shared by every surface reached from a link we sent: /me, /my, /hr,
   /checkup, /rx, /referral, /appointment, the communities and the public
   clinic pages. Quiet on purpose — it orients and offers a way out, and
   must never compete with the clinic's own name on the page below it. */
.pub-top {
  display: flex;
  align-items: center;
  gap: 14px;
  height: 52px;
  padding: 0 22px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  /* Sticky for the same reason the app bar is: on a phone, a record you
     scroll through should never leave you without a way home. */
  position: sticky;
  top: 0;
  z-index: 40;
}
.pub-top-in {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  max-width: 1080px;
  margin: 0 auto;
}
.pub-mark {
  font-family: var(--font-display, Georgia, serif);
  font-weight: 600;
  font-size: 17px;
  letter-spacing: -.01em;
  color: var(--ink);
  text-decoration: none;
  flex: 0 0 auto;
}
.pub-mark:hover { color: var(--accent); }
.pub-mark:hover { text-decoration: underline; }
.pub-context {
  display: flex; align-items: baseline; gap: 8px; min-width: 0;
  font-size: 13px; color: var(--ink-soft);
}
/* Before the name, so it reads as "Drapto — for <clinic>" rather than two
   unrelated words sitting beside each other. */
.pub-context::before { content: '—'; color: var(--ink-faint); }
.pub-context-name {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-soft);
  padding-left: 14px;
  border-left: 1px solid var(--line);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pub-context-sub {
  font-size: 12px;
  color: var(--ink-faint);
  margin-left: auto;
  flex: 0 0 auto;
}


/* ══════════════════════════════════════════════════════════════════════════
   READABILITY ON A TOKEN PAGE

   These pages are read by a patient on a phone, often an older one, often
   in a hurry. They were inheriting the app's 14px body — right for a dense
   clinic screen somebody uses all day, wrong for a prescription somebody
   reads once and must not misread.
   ══════════════════════════════════════════════════════════════════════════ */

.patient-page {
  font-size: 17px;
  line-height: 1.65;
}
.patient-page .wrap,
.patient-page main {
  max-width: 680px;
  margin: 0 auto;
  padding: 26px 22px 60px;
}
.patient-page h1 {
  font-size: clamp(24px, 4.5vw, 32px);
  line-height: 1.15;
  margin: 0 0 6px;
}
.patient-page h2 {
  font-size: clamp(18px, 3vw, 22px);
  line-height: 1.25;
  margin: 32px 0 10px;
}
.patient-page p { margin: 0 0 14px; }
/* A dose instruction is the one line that must not be misread. */
.patient-page .rx-dose,
.patient-page .dose {
  font-size: 17px;
  font-weight: 600;
  line-height: 1.5;
}
.patient-page a { text-decoration: underline; text-underline-offset: 3px; }
/* Anything tappable clears the 44px minimum without being asked. */
.patient-page button,
.patient-page .btn,
.patient-page input,
.patient-page select {
  min-height: 46px;
  font-size: 17px;
}

@media (max-width: 560px) {
  .pub-top { padding: 0 16px; gap: 10px; }
  .pub-context-sub { display: none; }
  .patient-page .wrap, .patient-page main { padding: 20px 16px 48px; }
}

/* The way out of a token page. Quiet — it is not the reason they opened the
   link, but it should be there when they finish reading. */
.pub-onward {
  margin-left: auto;
  flex: 0 0 auto;
  font-size: 13px;
  font-weight: 500;
  color: var(--accent);
  text-decoration: none;
  padding: 7px 13px;
  border-radius: 999px;
  border: 1px solid var(--line);
  white-space: nowrap;
}
.pub-onward:hover {
  border-color: var(--accent);
  background: var(--accent-tint);
}
/* The context sub already claims margin-left:auto; when both are present the
   onward link must still sit last. */
.pub-context-sub + .pub-onward { margin-left: 12px; }

@media (max-width: 560px) {
  .pub-onward { padding: 6px 10px; font-size: 12px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   THE COLOUR SYSTEM

   Twenty-five colours with no relationship to each other is not a palette,
   it is an accumulation. This is a ramp per hue, so a hover state or a
   disabled state is a step on a scale rather than a colour somebody picked.

   ── WHY GREEN AND NOT GOOGLE BLUE ──

   The marketing site is deep green. A patient who books at drapto.com and
   opens their record in the app should not feel they changed companies. So
   green stays the brand, and blue does the job it does best — carrying
   information without implying success or danger.

   ── AND WHY THIS IS NOT AUSTERE ──

   Black text on white is correct for a clinical record. It is wrong for
   everything around it. The colour lives in surfaces, status and the
   accents on things a person is meant to act on.
   ══════════════════════════════════════════════════════════════════════════ */



/* ══════════════════════════════════════════════════════════════════════════
   THE DAY GRID

   The appointments screen was a list. A list answers "what is booked"; a
   front desk needs "where is the gap" — and a gap is invisible in a list
   because nothing is there to render.

   So: time down the side, doctors across the top, and empty space that is
   actually empty. The thing a receptionist is looking for is the white.
   ══════════════════════════════════════════════════════════════════════════ */

.cal { display: flex; flex-direction: column; height: calc(100vh - 190px);
  min-height: 480px; border: 1px solid var(--line); border-radius: 14px;
  background: var(--surface); overflow: hidden; }

.cal-top {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; border-bottom: 1px solid var(--line);
  background: var(--n-25); flex-wrap: wrap;
}
.cal-date { font-family: var(--font-display, Georgia, serif); font-size: 17px;
  font-weight: 600; }
.cal-nav { display: flex; gap: 4px; }
.cal-nav button {
  min-width: 34px; height: 34px; border-radius: 9px; cursor: pointer;
  border: 1px solid var(--line); background: var(--surface);
  font: inherit; font-size: 13px; color: var(--ink-soft);
}
.cal-nav button:hover { border-color: var(--accent); color: var(--accent); }
.cal-today { padding: 0 12px !important; }
.cal-count { margin-left: auto; font-size: 13px; color: var(--ink-soft); }
.cal-count b { color: var(--ink); }

/* ── THE GRID ── */
.cal-scroll { flex: 1; overflow: auto; }
/* The wide thing scrolls itself, with the time column pinned — a
   receptionist scanning eighteen doctors needs to keep 09:00 in view. */
.cal-grid { overflow-x: auto; max-width: 100%; display: grid; min-width: max-content; }
.cal-head {
  position: sticky; top: 0; z-index: 3;
  background: var(--surface); border-bottom: 1px solid var(--line);
  padding: 10px 12px; font-size: 13px; font-weight: 600;
  display: flex; align-items: center; gap: 8px; white-space: nowrap;
}
.cal-head span { font-weight: 400; font-size: 12px; color: var(--ink-faint); }
/* A dot per doctor, from the speciality ramp — eight bookings in one colour
   is a grid nobody can read at a glance. */
.cal-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }

.cal-time {
  position: sticky; left: 0; z-index: 2;
  background: var(--surface); border-right: 1px solid var(--line);
  padding: 6px 10px; font-size: 12px; color: var(--ink-faint);
  font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap;
}
.cal-corner { position: sticky; left: 0; top: 0; z-index: 4;
  background: var(--surface); border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line); }

.cal-cell {
  border-bottom: 1px solid var(--n-100); border-right: 1px solid var(--n-100);
  min-height: 44px; padding: 3px; position: relative;
}
/* A free slot is clickable and says so on hover — the fastest booking is the
   one made by clicking the gap you were already looking at. */
.cal-cell.is-free { cursor: pointer; }
.cal-cell.is-free:hover { background: var(--g-50); }
.cal-cell.is-free:hover::after {
  content: '+ Book'; position: absolute; inset: 3px;
  display: grid; place-items: center;
  font-size: 12px; font-weight: 600; color: var(--accent);
  border: 1px dashed var(--g-300); border-radius: 7px;
}
/* Outside the doctor's hours — not bookable, and visibly not a gap. */
.cal-cell.is-closed {
  background: repeating-linear-gradient(-45deg, var(--n-50) 0 6px,
    var(--n-100) 6px 12px);
}
/* The line for right now. A front desk reads the day from this point. */
.cal-now { position: absolute; left: 0; right: 0; height: 2px;
  background: var(--bad); z-index: 1; pointer-events: none; }
.cal-now::before { content: ''; position: absolute; left: -4px; top: -3px;
  width: 8px; height: 8px; border-radius: 50%; background: var(--bad); }

/* ── A BOOKING ── */
.cal-appt {
  display: block; width: 100%; text-align: left; cursor: pointer;
  border: 0; border-left: 3px solid; border-radius: 6px;
  padding: 5px 8px; font: inherit; font-size: 12px; line-height: 1.35;
  height: 100%; overflow: hidden;
}
.cal-appt b { display: block; font-weight: 600; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.cal-appt span { display: block; font-size: 11px; opacity: .75; }
.cal-appt:hover { box-shadow: var(--e-2); }

/* Status reads before the name does. A front desk scanning the grid is
   looking for who has not arrived, not for who is booked. */
.cal-appt.st-booked   { background: var(--n-50);   border-color: var(--n-400); }
.cal-appt.st-arrived  { background: var(--ok-bg);  border-color: var(--ok);   color: var(--ok); }
.cal-appt.st-late     { background: var(--warn-bg);border-color: var(--warn); color: var(--warn); }
.cal-appt.st-noshow   { background: var(--bad-bg); border-color: var(--bad);  color: var(--bad); }
.cal-appt.st-done     { background: var(--n-25);   border-color: var(--n-300); color: var(--ink-faint); }
.cal-appt.st-done b   { text-decoration: line-through; }

.cal-legend { display: flex; gap: 14px; flex-wrap: wrap; padding: 10px 16px;
  border-top: 1px solid var(--line); background: var(--n-25);
  font-size: 12px; color: var(--ink-soft); }
.cal-legend i { display: inline-block; width: 10px; height: 10px;
  border-radius: 3px; margin-right: 5px; vertical-align: -1px; }

@media (max-width: 820px) {
  /* A seven-column grid on a phone is seven unreadable columns. One doctor
     at a time, chosen from a strip. */
  .cal { height: auto; }
  .cal-scroll { max-height: 62vh; }
  .cal-count { width: 100%; margin-left: 0; }
}

/* ══════════════════════════════════════════════════════════════════════════
   ONBOARDING

   Twenty-six endpoints existed and four were called. A hospital created an
   account and landed on an empty dashboard with no idea what to do next —
   which is the moment most software loses the customer it just won.

   The Tempus shape, and the reason it works: one question per screen, the
   progress visible, and every step producing something the person can see
   was worth doing. Not a nine-field form with a Submit button.
   ══════════════════════════════════════════════════════════════════════════ */

.ob { min-height: 100vh; display: flex; flex-direction: column;
  background: var(--n-50); }

.ob-top { display: flex; align-items: center; gap: 16px;
  padding: 18px 24px; background: var(--surface);
  border-bottom: 1px solid var(--line); }
.ob-mark { font-family: var(--font-display, Georgia, serif); font-size: 17px;
  font-weight: 600; }
/* A count, not a percentage — "step 2 of 5" tells somebody how much is left
   in a way "40%" does not. */
.ob-count { margin-left: auto; font-size: 13px; color: var(--ink-soft); }

.ob-rail { display: flex; gap: 4px; padding: 0 24px 16px;
  background: var(--surface); border-bottom: 1px solid var(--line); }
.ob-seg { flex: 1; height: 3px; border-radius: 2px; background: var(--n-200); }
.ob-seg.is-done { background: var(--g-500); }
.ob-seg.is-now { background: var(--g-700); }

.ob-body { flex: 1; display: grid; place-items: start center;
  padding: 48px 24px 80px; }
/* ── THE ONBOARDING PAGE HAD NO WRAPPER STYLE ──
 *
 * .ob-wrap is on every onboarding screen and had no rule at all, so the card
 * sat against the edge of the viewport. Measured on a 390px phone: the card
 * was 390px wide, zero side margin, text touching the glass.
 *
 * Centred with real padding, and a comfortable reading measure on a wide
 * screen rather than a 520px column stranded on the left of 1400px. */
.ob-wrap { min-height: 100vh; display: flex; flex-direction: column;
  align-items: center; justify-content: flex-start;
  padding: 40px 20px 64px; gap: 18px; }
@media (max-width: 640px) { .ob-wrap { padding: 24px 16px 48px; } }

/* 520 was tight for a step that asks several things at once — the fields
   below run full width, so a wider card is a wider field, not a longer line
   of prose. */
.ob-card { width: 100%; max-width: 620px; }
.ob-top { width: 100%; max-width: 620px; }

.ob-eyebrow { font-size: 12px; font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--accent); margin: 0 0 10px; }
.ob-h { font-family: var(--font-display, Georgia, serif);
  font-size: clamp(25px, 4vw, 34px); line-height: 1.14; margin: 0 0 10px;
  letter-spacing: -.015em; }
.ob-lead { font-size: 15px; line-height: 1.6; color: var(--ink-soft);
  margin: 0 0 28px; }

.ob-field { margin-bottom: 18px; }
.ob-field label { display: block; font-size: 13px; font-weight: 500;
  margin-bottom: 6px; }
.ob-field input, .ob-field select {
  width: 100%; min-height: 50px; padding: 0 15px; font: inherit; font-size: 17px;
  border: 1px solid var(--line-strong); border-radius: 11px;
  background: var(--surface);
}
.ob-field input:focus, .ob-field select:focus {
  outline: 2px solid var(--accent); outline-offset: -1px; border-color: transparent;
}
.ob-hint { margin: 6px 0 0; font-size: 12px; color: var(--ink-faint);
  line-height: 1.5; }

/* ── PICK ONE OR MANY ── a tile is easier to hit than a checkbox and shows
   what it means without a label doing all the work ── */
.ob-picks { display: grid; gap: 10px; margin-bottom: 24px;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.ob-pick {
  text-align: left; padding: 15px 16px; border-radius: 13px; cursor: pointer;
  border: 1.5px solid var(--line-strong); background: var(--surface);
  font: inherit; transition: border-color .14s, background .14s, transform .14s;
}
.ob-pick:hover { border-color: var(--g-400); transform: translateY(-1px); }
.ob-pick.is-on { border-color: var(--accent); background: var(--g-50); }
.ob-pick b { display: block; font-size: 13px; margin-bottom: 3px; }
.ob-pick span { display: block; font-size: 12px; line-height: 1.5;
  color: var(--ink-soft); }

.ob-actions { display: flex; gap: 10px; align-items: center; margin-top: 30px; }
.ob-next {
  min-height: 50px; padding: 0 26px; border: 0; border-radius: 12px;
  background: var(--accent); color: var(--surface); font: inherit; font-size: 15px;
  font-weight: 600; cursor: pointer;
}
.ob-next:hover { background: var(--accent-hover); }
.ob-next:disabled { background: var(--n-300); cursor: not-allowed; }
.ob-skip { background: none; border: 0; font: inherit; font-size: 13px;
  color: var(--ink-soft); cursor: pointer; text-decoration: underline;
  text-underline-offset: 3px; }

/* ── WHAT IT PRODUCED ── the reason a step felt worth doing ── */
.ob-made { margin-top: 26px; padding: 16px 18px; border-radius: 13px;
  background: var(--ok-bg); border: 1px solid var(--ok-line); }
.ob-made b { display: block; font-size: 13px; color: var(--ok);
  margin-bottom: 4px; }
.ob-made p { margin: 0; font-size: 13px; line-height: 1.55; color: var(--ink-soft); }
.ob-made code { font-family: var(--font-mono, monospace); font-size: 12px;
  background: var(--surface); padding: 2px 6px; border-radius: 5px; }

.ob-err { margin-top: 14px; padding: 12px 15px; border-radius: 11px;
  background: var(--bad-bg); border: 1px solid var(--bad-line);
  color: var(--bad); font-size: 13px; line-height: 1.55; }

@media (max-width: 560px) {
  .ob-body { padding: 30px 18px 60px; }
  .ob-picks { grid-template-columns: 1fr; }
  .ob-actions { flex-direction: column-reverse; align-items: stretch; }
  .ob-next { width: 100%; }
}

/* ══════════════════════════════════════════════════════════════════════════
   CHARTS

   Hand-drawn SVG rather than a library: recharts is 400KB before anything
   renders, and here a chart is a supporting element rather than the
   interface. These weigh nothing and print correctly, which matters because
   somebody will put one in a board pack.
   ══════════════════════════════════════════════════════════════════════════ */

.ch { margin-bottom: 18px; }
.ch-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 8px; }
.ch-head b { font-size: 13px; }
.ch-up { color: var(--ok); font-size: 13px; font-weight: 600; }
.ch-down { color: var(--warn); font-size: 13px; font-weight: 600; }

.ch-svg { width: 100%; height: auto; display: block; }
.ch-grid { stroke: var(--line-2); stroke-width: 1; }
.ch-line { fill: none; stroke: var(--accent); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round; }
.ch-area { fill: var(--accent); opacity: .07; }
.ch-dot { fill: var(--surface); stroke: var(--accent); stroke-width: 1.5; }
.ch-max, .ch-lab { font-size: 11px; fill: var(--ink-faint); }
.ch-end { text-anchor: end; }

.ch-bars { display: flex; align-items: flex-end; gap: 6px; padding-top: 20px; }
.ch-bar { flex: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: flex-end; height: 100%; min-width: 0; }
/* min-height so a value that rounds to under a pixel is still a visible
   sliver rather than nothing — "₹200 next to ₹96,000" should read as small,
   not absent. */
.ch-bar-fill { width: 100%; max-width: 46px; border-radius: 5px 5px 0 0;
  background: var(--accent); opacity: .85; transition: opacity .14s;
  min-height: 3px; }
.ch-bar:hover .ch-bar-fill { opacity: 1; }
.ch-bar-v { font-size: 11px; font-weight: 600; margin-bottom: 4px;
  font-variant-numeric: tabular-nums; }
.ch-bar-l { font-size: 11px; color: var(--ink-faint); margin-top: 6px;
  text-align: center; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; max-width: 100%; }

.ch-stat { padding: 14px 16px; border-radius: 12px; background: var(--surface);
  border: 1px solid var(--line); }
.ch-stat-l { display: block; font-size: 12px; color: var(--ink-soft); }
.ch-stat-v { display: block; font-size: 30px; line-height: 1.15; margin: 4px 0 2px;
  font-family: var(--font-display, Georgia, serif); font-variant-numeric: tabular-nums; }
.ch-stat-d { display: block; font-size: 12px; }
.ch-stat-n { display: block; font-size: 12px; color: var(--ink-faint); margin-top: 3px; }

.ch-split { display: flex; height: 12px; border-radius: 6px; overflow: hidden;
  background: var(--line-2); }
.ch-split-seg { height: 100%; }
.ch-split-key { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 10px;
  font-size: 12px; color: var(--ink-soft); }
.ch-split-key i { display: inline-block; width: 9px; height: 9px;
  border-radius: 2px; margin-right: 5px; }

.ch-empty { padding: 30px 20px; text-align: center; font-size: 13px;
  line-height: 1.6; color: var(--ink-faint); background: var(--n-25);
  border: 1px dashed var(--line); border-radius: 12px; }

.ch-grid-2 { display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.ch-stats { display: grid; gap: 12px; margin-bottom: 18px;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }

@media print {
  /* Somebody will put these in a board pack. */
  .ch { break-inside: avoid; }
  .ch-area { opacity: .12; }
}

/* ══════════════════════════════════════════════════════════════════════════
   VISUALISATIONS

   The same shapes the marketing site uses, so a hospital that read the site
   and then signed in is looking at one product rather than two.
   ══════════════════════════════════════════════════════════════════════════ */

.viz { margin: 14px 0 4px; }
.viz-svg { display: block; width: 100%; height: auto; }

.viz-lab { font-size: 12px; fill: var(--ink); font-weight: 500; }
.viz-num { font-size: 12px; fill: var(--ink-soft);
  font-variant-numeric: tabular-nums; }
.viz-tick { font-size: 11px; fill: var(--ink-faint); }
.viz-bar { fill: var(--g-500); }
/* The step with the biggest drop, in the signal colour — an owner should
   see where it breaks before reading a single number. */
.viz-bar-warn { fill: var(--warn); }
.viz-drop { font-size: 12px; fill: var(--warn); font-weight: 600;
  font-variant-numeric: tabular-nums; }

.viz-area { fill: var(--g-100); opacity: .55; }
.viz-line { fill: none; stroke: var(--g-700); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round; }
.viz-dot { fill: var(--surface); stroke: var(--g-700);
  stroke-width: 2; }

.viz-rank { margin: 12px 0 0; }
.viz-row { display: grid; align-items: center; gap: 10px;
  grid-template-columns: minmax(120px, 1.4fr) 2fr 46px 84px;
  padding: 5px 0; font-size: 13px; }
.viz-row-lab { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.viz-row-bar { height: 8px; border-radius: 4px;
  background: var(--n-100); overflow: hidden; }
.viz-row-bar i { display: block; height: 100%; background: var(--g-500); }
.viz-row-n { text-align: right; font-variant-numeric: tabular-nums;
  color: var(--ink-soft); }
.viz-row-2 { font-size: 12px; color: var(--ink-faint);
  text-align: right; }

.viz-split { display: flex; height: 26px; border-radius: 7px; overflow: hidden;
  background: var(--n-100); }
.viz-seg { display: block; }
.viz-seg-a { background: var(--g-600); }
.viz-seg-b { background: var(--b-400); }
.viz-seg-c { background: var(--warn); }
.viz-seg-d { background: var(--bad); }
.viz-key { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 10px;
  font-size: 12px; color: var(--ink-soft); }
.viz-key-item i { display: inline-block; width: 10px; height: 10px;
  border-radius: 3px; margin-right: 5px; vertical-align: -1px; }

@media (max-width: 640px) {
  .viz-row { grid-template-columns: minmax(90px, 1fr) 1.4fr 38px;
    font-size: 12px; }
  .viz-row-2 { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   ANIMATED CHARTS

   Motion that carries meaning, not decoration. A funnel bar growing from
   zero shows the drop happening; a line drawing left to right shows a trend
   arriving in order. Both make the shape easier to read than a static image.

   ── AND IT RUNS ONCE ──

   A chart that re-animates on every render is a chart nobody can read,
   because the numbers move while you are looking at them. These play on
   mount and then stay still.

   ── AND IT RESPECTS THE SETTING ──

   prefers-reduced-motion is not a preference to work around. For somebody
   with vestibular sensitivity, animation is nausea, not polish.
   ══════════════════════════════════════════════════════════════════════════ */

@keyframes viz-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes viz-rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes viz-draw { to { stroke-dashoffset: 0; } }
@keyframes viz-pop  { from { opacity: 0; transform: scale(.4); } to { opacity: 1; transform: none; } }

/* Bars grow from the left, so the eye follows the length rather than
   watching a rectangle fade in. */
.viz-bar, .viz-row-bar i {
  transform-origin: left center;
  animation: viz-grow .5s cubic-bezier(.22, 1, .36, 1) both;
}
/* Staggered, so the drop between steps is visible as it happens rather than
   all five arriving at once. */
.viz-svg g:nth-child(2) .viz-bar { animation-delay: .00s; }
.viz-svg g:nth-child(3) .viz-bar { animation-delay: .06s; }
.viz-svg g:nth-child(4) .viz-bar { animation-delay: .12s; }
.viz-svg g:nth-child(5) .viz-bar { animation-delay: .18s; }
.viz-svg g:nth-child(6) .viz-bar { animation-delay: .24s; }

.viz-num, .viz-drop { animation: viz-rise .4s ease-out both; animation-delay: .28s; }

/* The line draws left to right — a trend arrives in order, and seeing it
   arrive is what makes the direction obvious. */
.viz-line {
  stroke-dasharray: 2000;
  stroke-dashoffset: 2000;
  animation: viz-draw 1s cubic-bezier(.4, 0, .2, 1) both;
}
.viz-area { animation: viz-rise .7s ease-out both; animation-delay: .35s; }
.viz-dot { animation: viz-pop .3s cubic-bezier(.34, 1.56, .64, 1) both; }
.viz-dot:nth-of-type(1) { animation-delay: .30s; }
.viz-dot:nth-of-type(2) { animation-delay: .38s; }
.viz-dot:nth-of-type(3) { animation-delay: .46s; }
.viz-dot:nth-of-type(4) { animation-delay: .54s; }
.viz-dot:nth-of-type(5) { animation-delay: .62s; }
.viz-dot:nth-of-type(6) { animation-delay: .70s; }
.viz-dot:nth-of-type(n+7) { animation-delay: .78s; }

.viz-row { animation: viz-rise .35s ease-out both; }
.viz-row:nth-child(1) { animation-delay: .02s; }
.viz-row:nth-child(2) { animation-delay: .06s; }
.viz-row:nth-child(3) { animation-delay: .10s; }
.viz-row:nth-child(4) { animation-delay: .14s; }
.viz-row:nth-child(5) { animation-delay: .18s; }
.viz-row:nth-child(n+6) { animation-delay: .22s; }

.viz-seg {
  transform-origin: left center;
  animation: viz-grow .55s cubic-bezier(.22, 1, .36, 1) both;
}
.viz-seg:nth-child(2) { animation-delay: .10s; }
.viz-seg:nth-child(3) { animation-delay: .20s; }

/* Hover reads the value without a tooltip library. */
.viz-row:hover .viz-row-bar i { filter: brightness(1.12); }
.viz-seg:hover { filter: brightness(1.1); }

/* ── AND OFF, PROPERLY ──
   Not shortened. Off. */
@media (prefers-reduced-motion: reduce) {
  .viz-bar, .viz-row-bar i, .viz-num, .viz-drop, .viz-line, .viz-area,
  .viz-dot, .viz-row, .viz-seg {
    animation: none !important;
    stroke-dashoffset: 0 !important;
    opacity: 1 !important;
    transform: none !important;
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   THE EMPLOYEE MAP

   An employee opens their benefit link and sees a list of entitlements —
   which is how HR thinks about it, and not how anybody uses it. The
   question in their head is "what can I actually do, and does it cost me
   anything", and a list answers neither.

   So: their name in the middle, what they are entitled to radiating out,
   and each branch coloured by whether it is used, available, or gone. The
   shape carries the answer before any of it is read.
   ══════════════════════════════════════════════════════════════════════════ */

.emap { position: relative; padding: 20px 0 8px; }
.emap svg { display: block; width: 100%; height: auto; overflow: visible; }

.emap-link { fill: none; stroke: var(--line-strong); stroke-width: 1.5; }
.emap-link.is-used { stroke: var(--ok); }
.emap-link.is-gone { stroke-dasharray: 4 4; opacity: .5; }

.emap-core { fill: var(--g-700); }
.emap-core-t { fill: var(--surface); font-size: 13px; font-weight: 600; text-anchor: middle; }
.emap-core-s { fill: rgba(255,255,255,.75); font-size: 11px; text-anchor: middle; }

.emap-node { fill: var(--surface); stroke: var(--line-strong);
  stroke-width: 1.5; }
.emap-node.is-used { fill: var(--ok-bg); stroke: var(--ok); }
.emap-node.is-open { fill: var(--accent-tint); stroke: var(--accent); }
.emap-node.is-gone { fill: var(--n-50); stroke: var(--n-300); }

.emap-lab { font-size: 12px; font-weight: 600; fill: var(--ink); }
.emap-sub { font-size: 11px; fill: var(--ink-soft); }
.emap-node-g.is-gone .emap-lab { fill: var(--ink-faint); }

/* Tappable, because the whole point is that a branch leads somewhere. */
.emap-node-g { cursor: pointer; }
.emap-node-g:hover .emap-node { stroke-width: 2.5; }

.emap-key { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 14px;
  font-size: 12px; color: var(--ink-soft); }
.emap-key i { display: inline-block; width: 11px; height: 11px;
  border-radius: 50%; margin-right: 6px; vertical-align: -1px;
  border: 1.5px solid; }
.emap-key .k-used { background: var(--ok-bg); border-color: var(--ok); }
.emap-key .k-open { background: var(--accent-tint); border-color: var(--accent); }
.emap-key .k-gone { background: var(--n-50); border-color: var(--n-300); }

@media (max-width: 640px) {
  /* A radial map at 390px is unreadable. Below this it becomes a stack,
     which loses the shape but keeps the answer. */
  .emap-radial { display: none; }
  .emap-stack { display: block; }
}
.emap-stack { display: none; }
.emap-stack a {
  display: flex; align-items: center; gap: 12px; padding: 14px 16px;
  border: 1.5px solid var(--line-strong); border-radius: 13px;
  margin-bottom: 10px; text-decoration: none; color: inherit;
}
.emap-stack a.is-used { background: var(--ok-bg); border-color: var(--ok); }
.emap-stack a.is-open { background: var(--accent-tint); border-color: var(--accent); }
.emap-stack a.is-gone { opacity: .6; }
.emap-stack b { display: block; font-size: 15px; }
.emap-stack span { display: block; font-size: 12px; color: var(--ink-soft); }

/* ══════════════════════════════════════════════════════════════════════════
   THE EMPLOYER'S NUMBERS

   An HR manager renewing is answering one question to their own board: is
   this being used. A table of visit counts does not answer it; a line that
   goes up or does not, does.

   Same shapes as the platform console and the marketing site, because a
   company that read drapto.com and then signed in should be looking at one
   product.
   ══════════════════════════════════════════════════════════════════════════ */

.cviz { margin: 16px 0; }
.cviz svg { display: block; width: 100%; height: auto; }

/* ── UPTAKE ── one number, drawn, because it is the whole conversation ── */
.cv-ring { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.cv-ring svg { width: 132px; height: 132px; flex: 0 0 auto; }
.cv-track { fill: none; stroke: var(--n-200); stroke-width: 13; }
.cv-fill { fill: none; stroke-width: 13; stroke-linecap: round;
  transform: rotate(-90deg); transform-origin: 50% 50%; }
.cv-fill.is-low { stroke: var(--warn); }
.cv-fill.is-ok { stroke: var(--g-500); }
.cv-fill.is-good { stroke: var(--ok); }
.cv-pct { font-size: 30px; font-weight: 600; text-anchor: middle;
  fill: var(--ink); font-family: var(--font-display, Georgia, serif); }
.cv-of { font-size: 11px; text-anchor: middle; fill: var(--ink-faint); }
.cv-say { flex: 1; min-width: 240px; font-size: 13px; line-height: 1.6;
  color: var(--ink-soft); }

/* ── MONTHS ── bars, because a month is a bucket and not a point ── */
.cv-bars { display: flex; align-items: flex-end; gap: 5px; height: 130px;
  padding-top: 8px; }
.cv-bar { flex: 1; display: flex; flex-direction: column;
  justify-content: flex-end; align-items: center; gap: 5px; min-width: 0; }
.cv-bar i { display: block; width: 100%; border-radius: 4px 4px 0 0;
  background: var(--g-500); min-height: 2px; }
.cv-bar.is-now i { background: var(--g-700); }
.cv-bar span { font-size: 11px; color: var(--ink-faint);
  white-space: nowrap; }
.cv-bar b { font-size: 11px; font-variant-numeric: tabular-nums;
  color: var(--ink-soft); }

.cv-stats { display: grid; gap: 12px; margin-top: 16px;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.cv-stat { padding: 15px 17px; border-radius: 13px; background: var(--n-25);
  border: 1px solid var(--line); }
.cv-stat b { display: block; font-size: 30px; line-height: 1.1; font-weight: 600;
  font-family: var(--font-display, Georgia, serif);
  font-variant-numeric: tabular-nums; }
.cv-stat span { display: block; margin-top: 3px; font-size: 12px; line-height: 1.5;
  color: var(--ink-soft); }

/* The promise, on the screen it is about. */
.cv-privacy { margin-top: 18px; padding: 14px 16px; border-radius: 12px;
  background: var(--accent-tint); border: 1px solid var(--accent);
  font-size: 13px; line-height: 1.6; color: var(--ink); }

.cv-offer { padding: 16px 18px; border-radius: 13px; margin-bottom: 10px;
  background: var(--b-50); border: 1px solid var(--b-200); }
.cv-offer b { display: block; font-size: 15px; margin-bottom: 4px; }
.cv-offer p { margin: 0 0 10px; font-size: 13px; line-height: 1.6;
  color: var(--ink-soft); }

@media (max-width: 560px) {
  .cv-bars { height: 100px; gap: 3px; }
  .cv-bar b { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   THE DASHBOARDS ON A PHONE

   A clinic owner checks the day's numbers on a phone at seven in the
   morning, and an HR manager opens the scheme dashboard between meetings.
   Neither is at a desk, and a dashboard that needs one is a dashboard
   nobody reads.

   Every rule here is about a screen the verifier was not checking — the
   charts, the calendar header and the tile rows all shipped without one.
   ══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 640px) {
  /* A three-part split bar at 340px gives each segment about a hundred
     pixels, which is legible. Below that the labels are the problem, not
     the bar, so the key stacks instead. */
  .viz-key { flex-direction: column; gap: 7px; }
  .viz-key-item { display: flex; align-items: center; }
  .viz-split { height: 22px; }

  /* The calendar header wraps rather than pushing the count off-screen. */
  .cal-top { gap: 8px; padding: 10px 12px; }
  .cal-date { font-size: 15px; width: 100%; }
  .cal-count { margin-left: 0; }
  /* And the grid keeps its column width and scrolls sideways — squeezing
     eight doctors into 360px would make every one unreadable. */
  .cal-grid { min-width: max-content; }
  .cal-scroll { -webkit-overflow-scrolling: touch; }

  /* Quick tiles: one per row. Two at 360px leaves 150px each, which is not
     enough for a label and a sub-label. */
  .quick { grid-template-columns: 1fr; gap: 8px; }
  .qt { padding: 14px 15px; }

  /* Figures stack rather than shrinking to unreadable. */
  .fig b, .viz-svg .viz-lab { font-size: 13px; }
}

@media (max-width: 420px) {
  /* The smallest phone anybody actually uses. Nothing here is about
     elegance — it is about the numbers still being readable. */
  .viz-row { grid-template-columns: 1fr 34px; row-gap: 2px; }
  .viz-row-bar { grid-column: 1 / -1; }
  .cal-appt { font-size: 12px; padding: 4px 6px; }
  .ob-card { max-width: none; }
}

/* Two the grid check found that I had not: a four-column ledger strip and a
   two-column form grid, both fixed since long before today. Four columns at
   360px is ninety pixels each, which is a number nobody can read. */
@media (max-width: 720px) {
  .ledger-strip { grid-template-columns: repeat(2, 1fr); }
  .grid-2 { grid-template-columns: 1fr; }
}
@media (max-width: 420px) {
  .ledger-strip { grid-template-columns: 1fr; }
}

/* ══════════════════════════════════════════════════════════════════════════
   WAITING — spinner, skeleton stacks, busy buttons
   Paired with app/src/components/Loading.jsx. Class names start skel-/spin-
   so no-motion.css already strips the animation for reduced-motion users.
   ══════════════════════════════════════════════════════════════════════════ */

.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; }

.skel-stack { display:grid; gap:9px; }
.skel-line  { height:12px; }
.skel-table { display:grid; gap:11px; }
.skel-row   { display:flex; gap:14px; align-items:center; }
.skel-cell  { height:12px; }

/* The spinner is a ring with one quarter left open, not a chasing dot —
   at 13px inside a button a dot is a single flickering pixel. */
.spin {
  display:inline-block; vertical-align:-2px; flex:none;
  border:2px solid var(--line-strong);
  border-top-color: var(--accent);
  border-radius:50%;
  animation: spin-turn .62s linear infinite;
}
@keyframes spin-turn { to { transform: rotate(360deg); } }

.btn.is-busy { opacity:.72; cursor:progress; }
.btn.is-busy .spin { margin-right:7px; border-top-color: currentColor; }

/* 300ms before it appears. Most calls finish faster than that, and a
   spinner that flashes and vanishes reads as a page that broke. */
.page-loading {
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:12px; padding:56px 20px; opacity:0;
  animation: page-loading-in .2s ease-out .3s forwards;
}
.page-loading .hint { margin:0; }
@keyframes page-loading-in { to { opacity:1; } }

.nav-badge {
  margin-left:auto; font-size: 11px; line-height:1; letter-spacing:.04em;
  text-transform:uppercase; padding:3px 6px; border-radius:999px;
  background:var(--accent-tint); color:var(--accent);
}

@media (prefers-reduced-motion: reduce) {
  .spin { animation-duration: 1.6s; }
  .page-loading { animation:none; opacity:1; }
}

/* Locked navigation — a feature the plan does not include. Readable, muted,
   and it goes to /plans. Not display:none, because a customer cannot buy
   what the product never mentions. */
.nav-link.is-locked { opacity:.55; }
.nav-link.is-locked:hover { opacity:.8; }
.nav-lock {
  margin-left:auto; font-size:9.5px; line-height:1; letter-spacing:.05em;
  text-transform:uppercase; padding:3px 6px; border-radius:999px;
  background:var(--minor-tint); color:var(--minor-ink); white-space:nowrap;
}
.card-title { font-size: 15px; margin:0 0 10px; font-family:var(--font-display); }
.ws-list { list-style:none; margin:6px 0 0; padding:0; display:grid; gap:8px; }
.ws-row { display:flex; align-items:center; justify-content:space-between;
  gap:12px; padding:10px 12px; border:1px solid var(--line); border-radius:var(--radius-sm); }
.ws-add { margin-top:18px; padding-top:16px; border-top:1px solid var(--line); }
.ws-add-row { display:flex; gap:8px; flex-wrap:wrap; }
.ws-add-row .inp { flex:1 1 160px; }

/* ══════════════════════════════════════════════════════════════════════════
   CLASSES THAT WERE RENDERED BUT NEVER DECLARED

   An audit of className= against this file found 24 classes with no rule
   behind them. A missing rule is not a missing style — the element still
   renders, just with the browser default, which is why none of this showed
   up as an error anywhere. It showed up as a form whose labels sat diagonally
   beside their own inputs.

   Measured before these rules existed, at 1440x900:
     .btn-sm      1092px wide   (a "small" button spanning the whole card)
     .cn-area      161px wide   inline-block textareas, staggered down the page
     .dp-item-ttl  inline       title, reason and fix concatenated into one
                                unreadable run-on sentence
   ══════════════════════════════════════════════════════════════════════════ */

/* ── .btn-sm ──
   .btn is declared TWICE in this file: the block at the top sets
   `width: 100%`, and the later block that redefines padding and font-size
   never overrides it. So .btn is full-width everywhere, and .btn-sm — which
   exists precisely to opt out of that — did nothing at all. Declared last so
   it wins on source order against both. */
.btn-sm {
  width: auto;
  padding: 5px 11px;
  font-size: 12px;
}

/* ── .mono ──
   Used on figures. Without it they render in the body sans, so digits are
   proportionally spaced and columns of money do not line up — which is the
   one thing a ledger interface has to get right. tabular-nums keeps the
   digits on a fixed advance even inside the mono face. */
.mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* ── Account: .form-grid / .lbl ──
   .lbl WRAPS its input rather than pointing at it with `for`, so the label
   text and the field are siblings inside one element. Left as the default
   `display: inline` that put the caption of one field on the same line as
   the box of the previous one. */
.form-grid { display: grid; gap: 14px; }
.lbl {
  display: grid;
  gap: 5px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-soft);
}
.lbl .inp { width: 100%; }

/* ── Consultation note: .cn-* ── */
.cn-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: 20px;
  align-items: start;
}
.cn-main, .cn-side { min-width: 0; }

.cn-lab {
  display: block;
  margin: 16px 0 5px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-soft);
}
/* The first control in the card should not be pushed off its own top edge. */
.cn-main .cn-lab:first-child { margin-top: 0; }

.cn-in {
  width: 100%;
  padding: 10px 13px;
  font: inherit;
  /* Was 13px. A doctor writes the longest text in the product here. */
  font-size: 16px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
}
.cn-in:focus-visible { outline: 2px solid var(--teal); outline-offset: -1px; }
.cn-area { min-height: 88px; line-height: 1.6; resize: vertical; }

.cn-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
/* .btn is width:100%; inside a button row that would stack them full-width. */
.cn-actions .btn { width: auto; }

.cn-confirm {
  margin-top: 16px;
  padding: 14px 16px;
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
}
.cn-err { margin: 12px 0 0; font-size: 13px; color: var(--critical-ink); }

/* ── Documentation prompts: .dp-* ──
   Every one of these was inline, so a prompt's title, the money it cites,
   the reason and the fix ran together as a single sentence. They are four
   separate statements and have to read as four. */
.dp {
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.dp-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
}
.dp-ttl {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.dp-busy { color: var(--ink-faint); }

.dp-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.dp-item {
  display: grid;
  gap: 4px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
.dp-item:last-child { padding-bottom: 0; border-bottom: none; }
.dp-item-ttl { font-size: 13px; font-weight: 600; color: var(--ink); }
.dp-ev {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  color: var(--critical-ink);
}
.dp-why { font-size: 13px; line-height: 1.6; color: var(--ink-soft); }
.dp-fix { font-size: 13px; line-height: 1.6; color: var(--ink); }
.dp-src { margin: 14px 0 0; font-size: 12px; line-height: 1.6; color: var(--ink-faint); }

/* The side panel goes under the note on a narrow screen rather than being
   squeezed to a column too thin to read. Same 900px breakpoint the shell
   uses, so the two never disagree about what "narrow" means. */
@media (max-width: 900px) {
  .cn-wrap { grid-template-columns: 1fr; }
}

/* ── Verification screen ── */
.code-inp {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 30px; letter-spacing: .34em; text-align: center;
  padding: 12px 10px;
}
.btn-block { width: 100%; justify-content: center; margin-top: 14px; }
.auth-err { color: var(--bad); font-size: 13px; margin: 12px 0 0; }
.auth-alt { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line);
  display: grid; gap: 10px; justify-items: center; }
.btn-link { background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--accent); font-size: 13px; text-decoration: underline; }

/* Chip rows used as a single-choice control (join policy, clinic size).
   .chip existed as a static tag; without .is-on the selected one looked
   identical to the rest, so the control told you nothing about its state. */
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.chip-row .chip { cursor: pointer; border: 1px solid transparent; font-size: 13px;
  padding: 7px 12px; background: var(--surface); color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--line); }
.chip-row .chip:hover { box-shadow: inset 0 0 0 1px var(--line-strong); }
.chip-row .chip.is-on { background: var(--teal-tint); color: var(--teal-strong);
  box-shadow: inset 0 0 0 1.5px var(--accent); font-weight: 600; }

/* ══════════════════════════════════════════════════════════════════════════
   ODONTOGRAM
   Each tooth is a five-surface box, drawn as a dentist draws it on paper.
   The grid is the whole point: buccal and lingual on the horizontal edges,
   mesial and distal on the vertical ones, occlusal in the middle. Colour
   carries state and nothing else — this screen has one job.
   ══════════════════════════════════════════════════════════════════════════ */

.od { --od-finding: #b3261e; --od-planned: var(--warn); --od-done: var(--brand-accent); }

.od-head { display:flex; align-items:center; justify-content:space-between;
  gap:14px; margin-bottom:14px; flex-wrap:wrap; }
.od-key { display:flex; gap:16px; font-size: 12px; color:var(--ink-soft); }
.od-key span { display:flex; align-items:center; gap:6px; }
.od-dot { width:9px; height:9px; border-radius:2px; display:inline-block;
  background:var(--line-strong); flex:none; }
.od-dot.is-finding { background:var(--od-finding); }
.od-dot.is-planned { background:var(--od-planned); }
.od-dot.is-done    { background:var(--od-done); }

/* Sixteen teeth at a fixed 34px is 544px of arch. On a 360px phone that
   overflowed the page with nowhere to go — justify-content:center simply
   clipped both ends, so the molars were unreachable rather than off-screen.
   The arch scrolls; the tooth does not. A tooth that reflows is a tooth you
   click wrong, and the distal surface is 8px wide. */
.od-arch { display:flex; align-items:flex-end; justify-content:center; gap:0;
  overflow-x:auto; -webkit-overflow-scrolling:touch; }
@media (max-width: 900px) {
  /* flex-start, not center: centred content inside a scroll container
     starts the viewport in the middle of the arch, which looks like the
     first eight teeth are missing. */
  .od-arch { justify-content:flex-start; }
}
.od-arch.od-lower { margin-top:10px; align-items:flex-start; }
/* The midline. A hairline, because it is a reference not a feature. */
.od-mid { width:1px; align-self:stretch; background:var(--line-strong); margin:0 10px; }
.od-quad { display:flex; gap:5px; }

.od-tooth { display:flex; flex-direction:column; align-items:center; gap:3px; }
.od-lower .od-tooth { flex-direction:column-reverse; }

/* 3×3 grid, five cells used. The corners stay empty on purpose: a tooth has
   five surfaces and drawing eight invites clicks that mean nothing. */
.od-box { display:grid; width:34px; height:34px;
  grid-template-columns:8px 1fr 8px; grid-template-rows:8px 1fr 8px;
  border:1px solid var(--line-strong); border-radius:3px; overflow:hidden;
  background:var(--surface); }
.od-s { border:0; padding:0; cursor:pointer; background:transparent;
  transition:background .12s ease; }
.od-s:hover { background:var(--line); }
.od-s:focus-visible { outline:2px solid var(--accent); outline-offset:-2px; }
.od-lingual  { grid-area:3 / 2 / 4 / 3; }
.od-buccal   { grid-area:1 / 2 / 2 / 3; }
.od-mesial   { grid-area:2 / 1 / 3 / 2; }
.od-distal   { grid-area:2 / 3 / 3 / 4; }
.od-occlusal { grid-area:2 / 2 / 3 / 3; }
/* Upper arch: buccal is drawn on top, lingual below — swapped by the
   component, so these rules only need to place the named faces. */
.od-arch:not(.od-lower) .od-buccal  { grid-area:1 / 2 / 2 / 3; }
.od-arch:not(.od-lower) .od-lingual { grid-area:3 / 2 / 4 / 3; }

.od-s.is-finding { background:var(--od-finding); }
.od-s.is-planned { background:var(--od-planned); }
.od-s.is-done    { background:var(--od-done); }

.od-num { border:0; background:none; cursor:pointer; font-size: 11px;
  color:var(--ink-soft); font-variant-numeric:tabular-nums; padding:1px 3px;
  border-radius:3px; }
.od-num:hover { background:var(--line); color:var(--ink); }
.od-tooth.is-sel .od-box { box-shadow:0 0 0 2px var(--accent); }
.od-tooth.is-sel .od-num { color:var(--accent); font-weight:600; }

/* A whole-tooth entry — extraction, missing — marks the frame, not a face. */
.od-tooth.whole-finding .od-box { border-color:var(--od-finding); }
.od-tooth.whole-planned .od-box { border-color:var(--od-planned); }
.od-tooth.whole-done    .od-box { border-color:var(--od-done); border-style:dashed; }

.od-entry { margin-top:18px; padding-top:16px; border-top:1px solid var(--line); }
.od-entry-head { display:flex; align-items:center; justify-content:space-between; }
.od-hist { list-style:none; margin:10px 0 0; padding:0; display:grid; gap:5px;
  font-size: 13px; color:var(--ink-soft); }
.od-hist li { display:flex; align-items:center; gap:7px; }
.od-fields { display:flex; gap:10px; margin-top:10px; }
.od-fields .lbl { flex:1 1 120px; }
.od-plan { margin-top:16px; padding-top:14px; border-top:1px solid var(--line);
  display:flex; align-items:baseline; gap:10px; }

@media (max-width: 900px) {
  /* Two arches side by side will not fit; let the chart scroll rather than
     shrink the teeth to a size nobody can hit with a finger. */
  .od-arch { overflow-x:auto; justify-content:flex-start; padding-bottom:4px; }
}

/* ══ BADGES ══
   State, not rank. Quiet by default — a badge that shouts is an
   advertisement, and these are meant to be read once and believed. */
.badges { list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap; gap:7px; }
.badge { display:inline-flex; align-items:center; gap:5px; font-size: 12px;
  line-height:1; padding:5px 9px; border-radius:999px; white-space:nowrap;
  border:1px solid var(--line); background:var(--surface); color:var(--ink-soft); }
.badge .nav-ico { width:13px; height:13px; flex:none; }
/* "New on Drapto" is the one that has to read as neutral-positive rather
   than as a warning: new is not lesser. Green, not amber. */
.badge.tone-fresh { border-color:var(--ok-bg); background:var(--ok-bg); color:var(--brand-accent); }
.badge.tone-good  { border-color:#cfe0f5; background:#f2f7fd; color:#14508f; }
.badges-sm .badge { font-size: 11px; padding:4px 7px; }

/* ══ CORPORATE CLIENTS ON A PUBLIC PAGE ══
   Names only, set quietly. A logo wall shouts; a line of names reads as a
   fact. Placed under the badges because it is the strongest thing a NEW
   hospital has to say and the badges above it are the shortest. */
.bk-clients { margin: 10px 0 2px; }
.bk-clients-lead { display: block; font-size: 12px; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-soft); }
.bk-clients-names { display: block; margin-top: 3px; font-size: 13px;
  line-height: 1.55; color: var(--ink); }

/* ══════════════════════════════════════════════════════════════════════════
   TYPE SCALE AND HIERARCHY

   ── WHAT WAS WRONG ──

   Measured in the browser, not guessed: h1 rendered at 30px/45px in IBM
   Plex Sans 700, body at 15px/22.5px in the same face. Two sizes, one
   family, one weight of emphasis. Every card carried the identical 1px
   border and the same 1px shadow, so a ₹1.3L headline and a settings row
   had exactly the same visual weight.

   That is the whole "it looks basic" complaint, and it is not a colour
   problem. Nothing on the screen said what to look at first.

   ── THE THREE CHANGES ──

   1. The display serif reaches page titles at all (see ui.jsx — the rule
      existed and matched nothing).
   2. A real scale, so a heading, a section and a label are visibly three
      different things rather than three sizes of the same thing.
   3. Two card weights instead of one. The primary figure on a screen sits
      on paper with no border; everything else keeps the hairline. Removing
      a border to create emphasis costs nothing and reads as deliberate,
      where adding a heavier shadow reads as a mistake.

   Restraint on purpose: no new colours, no gradients, no elevation ladder.
   The palette was already fine.
   ══════════════════════════════════════════════════════════════════════════ */



/* Page titles: the serif, set tight. 45px leading on a 30px heading is
   paragraph spacing applied to a title — it made every screen open with a
   heading that floated away from its own subtitle. */
/* Both selectors, because three screens — Dashboard, Patients, Recovery —
   hand-roll their own markup instead of using the shared Page component, so
   their <h1> sits directly in .wrap and .page-header never matches it.
   Styling the bare heading covers both without touching three files, and
   without a fourth screen inventing a fourth way next week. */
.page-header h1,
.wrap > h1,
.wrap > div > h1 {
  font-family: var(--font-display);
  font-size: var(--t-display);
  line-height: 1.15;
  letter-spacing: -0.012em;
  font-weight: 600;
}
.page-header .hint { margin-top: var(--sp-1); }

/* A section heading is the serif too, so the two headings on a screen are
   the same voice at two sizes rather than two different typefaces. */
.card-title, .sec-title {
  font-family: var(--font-display);
  font-size: var(--t-section);
  line-height: 1.25;
  font-weight: 600;
  margin: 0 0 var(--sp-2);
}

/* Labels and column heads. Tracked uppercase at a small size reads as
   structure; the same words in sentence case read as content. */
.tbl th, .lbl, .stat-label, .eyebrow {
  font-size: var(--t-label);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
  font-weight: 600;
}

/* ── THE FIGURE THAT MATTERS ──
   One card per screen may carry .is-lead. No border, no shadow, sitting
   directly on the paper — which reads as "this is the surface, everything
   else is a card on it" rather than as a card that lost its outline. */
.card.is-lead {
  border-color: transparent;
  box-shadow: none;
  background: transparent;
  padding-left: 0;
  padding-right: 0;
}
.card.is-lead .stat-value,
/* A figure, not text: it is read as a quantity at a glance and the
   type scale does not govern numerals used as graphics. */
.card.is-lead .figure { font-size: 38px; line-height: 1.05; }

/* Numbers line up. Tabular figures in every money and count context, so a
   column of rupees is readable as a column rather than as ragged text. */
.mono, .tbl td.mono, .stat-value, .figure {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* Tables: more air between rows than inside them, which is what makes a
   long list scannable. */
.tbl td { padding-top: 11px; padding-bottom: 11px; }
.tbl th { padding-bottom: 8px; }

/* ── Speciality examination form ── */
.ex { margin: 18px 0; padding: 16px; border: 1px solid var(--line);
  border-radius: var(--radius-sm); background: var(--surface); }
.ex-head { display: grid; gap: 4px; margin-bottom: 14px; }
.ex-group { margin-top: 16px; }
.ex-group:first-of-type { margin-top: 0; }
.ex-group-h { font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-faint); margin: 0 0 8px; font-weight: 700; }
/* wrap, so a repeating row on a phone stacks instead of scrolling sideways */
.ex-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end;
  padding: 8px 0; border-bottom: 1px dashed var(--line); }
.ex-row:last-child { border-bottom: 0; }
@media (max-width: 640px) { .ex-row .lbl { flex: 1 1 100%; } }

/* The prepared treatment plan, ready to send. */
.od-share { flex-basis: 100%; margin-top: 10px; padding-top: 12px;
  border-top: 1px solid var(--line); }
.od-share .inp { font-size: 13px; }

/* My day — counts and names, read at speed between patients. */
.md-list { list-style:none; margin:0; padding:0; display:grid; gap:8px; }
.md-list li { font-size: 13px; line-height:1.5; padding-bottom:8px;
  border-bottom:1px solid var(--line); }
.md-list li:last-child { border-bottom:0; padding-bottom:0; }

/* Leave form — three fields on one line on a desktop, stacked on a phone. */
.to-form { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 4px; }
.to-form .lbl { flex: 1 1 200px; }

/* ══ ALLERGIES ══
   Severity carries colour because it carries consequence: severe blocks a
   prescription, moderate warns. Read at a glance beside a patient's name. */
.alg-head { display:flex; align-items:center; justify-content:space-between;
  gap:12px; margin-bottom:10px; }
.alg-list { list-style:none; margin:0; padding:0; display:grid; gap:7px; }
.alg-list li { font-size: 13px; padding:8px 11px; border-radius:var(--radius-sm);
  border:1px solid var(--line); background:var(--surface); }
.alg-list li.alg-severe { border-color:var(--critical-tint); background:var(--critical-tint); }
.alg-list li.alg-moderate { border-color:var(--warn-tint); background:var(--warn-tint); }
.alg-sev { margin-left:8px; font-size: 11px; text-transform:uppercase;
  letter-spacing:.05em; color:var(--ink-soft); }
.alg-severe .alg-sev { color:#a33228; font-weight:700; }

.alg-form { margin-top:12px; }
.alg-sevs { display:grid; gap:8px; margin-top:8px; }
.alg-pick { text-align:left; border:1px solid var(--line); background:var(--surface);
  border-radius:var(--radius-sm); padding:10px 12px; cursor:pointer; display:grid; gap:2px; }
.alg-pick span { font-size: 12px; color:var(--ink-soft); }
.alg-pick.is-on { box-shadow:inset 0 0 0 1.5px var(--accent); border-color:transparent; }

/* ══ PRESCRIBING ══
   The two refusals look different on purpose. A severe allergy is a stop;
   a moderate one is a check. One amber box for both would turn a hard stop
   into a speed bump, which is the only thing this gate exists to prevent. */
.rx-block { margin-top: 14px; padding: 14px; border-radius: var(--radius-sm);
  border: 1.5px solid #d99b93; background: var(--critical-tint); }
.rx-warn { margin-top: 14px; padding: 12px 14px; border-radius: var(--radius-sm);
  border: 1px solid var(--warn-tint); background: var(--warn-tint); }

/* ══ OFFER TEMPLATES ══
   The caution reads as loudly as the offer, because an offer a clinic does
   not understand is one they cancel in a month. */
.tpl-list { display: grid; gap: 10px; margin-top: 14px; }
.tpl { display: flex; gap: 16px; align-items: flex-start; justify-content: space-between;
  padding: 14px 16px; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); }
.tpl-main { flex: 1 1 auto; }
.tpl-main .hint { margin: 5px 0 0; line-height: 1.6; }
.tpl-watch { color: var(--ink-soft); }
.tpl-side { flex: none; text-align: right; display: grid; gap: 8px; justify-items: end; }
.tpl-val { font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 700px) {
  .tpl { flex-direction: column; }
  .tpl-side { justify-items: start; text-align: left; }
}

/* A button inside a flex row keeps its own width. Two full-bleed buttons
   side by side read as banners, not as actions. */
.tpl-list, .wrap > div > .btn { flex: none; }
.wrap div[style*="display: flex"] > .btn { flex: 0 0 auto; }

/* Migration counts — three numbers a clinic reads before committing. */
.mig-counts { display: flex; gap: 28px; flex-wrap: wrap; margin: 4px 0 14px; }
.mig-counts div { display: flex; flex-direction: column; }
.mig-counts b { font-size: 30px; line-height: 1.1; font-variant-numeric: tabular-nums; }
.mig-counts span { font-size: 12px; color: var(--ink-soft); }

/* Learned denial rules — the money is the headline, the evidence sits under it. */
.pr-head { display:flex; align-items:baseline; justify-content:space-between; gap:14px; }
.pr-lost { font-size: 19px; color:var(--danger); }
.pr-actions { display:flex; align-items:flex-end; gap:10px; margin-top:14px; flex-wrap:wrap; }

/* A row that opens something says so before it is clicked. */
.tbl tr.row-open { cursor: pointer; }
.tbl tr.row-open:hover { background: var(--line); }

/* Actions on a patient record — what a clinician does next, without searching again. */
.pt-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }

/* ══ PRESCRIBING ══
   A blocking warning is the first thing on the screen, in the one colour
   this product uses to mean stop. */
.rx-item { padding: 12px 0; border-bottom: 1px solid var(--line); }
.rx-row { display: flex; gap: 10px; flex-wrap: wrap; }
.rx-row .lbl { margin-top: 8px; }
.rx-block { border: 1px solid var(--critical-tint); background: var(--critical-tint); color: #7a241c;
  border-radius: var(--radius-sm); padding: 12px 14px; margin-bottom: 14px; }
.rx-warn { border: 1px solid var(--warn-tint); background: var(--warn-tint); border-radius: var(--radius-sm);
  padding: 12px 14px; margin-top: 14px; }

/* ══════════════════════════════════════════════════════════════════════════
   THE DIRECTORY

   Was three underlined lines per clinic in a 560px column. A patient
   choosing where to go looks at a photograph, the area, then the price.
   Cards, wide, image first.
   ══════════════════════════════════════════════════════════════════════════ */
body:has(.cl-grid) .bk, body:has(.cl-card) .bk { max-width: 1120px; }
#f-out { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 16px; margin-top: 18px; }
.cl-card { display: flex; flex-direction: column; text-decoration: none;
  color: inherit; border: 1px solid var(--line); border-radius: 12px;
  overflow: hidden; background: var(--surface); transition: box-shadow .15s ease; }
.cl-card:hover { box-shadow: 0 4px 18px rgba(10,10,10,.09); }
.cl-shot { aspect-ratio: 3 / 2; background: var(--line); display: flex;
  align-items: center; justify-content: center; overflow: hidden; }
.cl-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cl-initial { font-family: var(--font-display, Georgia, serif); font-size: 46px;
  color: var(--accent); }
.cl-body { padding: 14px 16px 16px; display: flex; flex-direction: column; gap: 6px; }
.cl-name { font-weight: 600; font-size: 17px; line-height: 1.3; }
.cl-meta { font-size: 13px; color: var(--ink-soft); }
.cl-specs { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 2px; }
.cl-specs span { font-size: 12px; border: 1px solid var(--line);
  border-radius: 999px; padding: 3px 9px; color: var(--ink-soft); }
.cl-foot { display: flex; align-items: center; gap: 10px; margin-top: 8px;
  padding-top: 10px; border-top: 1px solid var(--line); font-size: 13px;
  color: var(--ink-soft); }
.cl-fee { font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 600; }
.cl-go { margin-left: auto; color: var(--accent); font-weight: 600; }

/* Cards are one link. Underlining the text inside them makes every line
   look separately clickable, which is how the old directory read.

   Written as `.patient-page a.cl-card` to beat `.patient-page a`, which
   underlines every link on these pages — correct for prose, wrong for a
   card whose whole surface is the link. Specificity, not !important. */
.patient-page a.cl-card,
.patient-page a.cl-card *,
.patient-page a.hp-book,
.patient-page a.hp-docbook,
.patient-page a.hp-call { text-decoration: none; }

/* ══ CLINIC PHOTOGRAPH MANAGEMENT ══ */
.ph-grid { list-style:none; margin:14px 0 0; padding:0;
  display:grid; grid-template-columns:repeat(auto-fill, minmax(200px,1fr)); gap:14px; }
.ph-item { position:relative; border:1px solid var(--line); border-radius:10px;
  padding:10px; background:var(--surface); }
.ph-item img { width:100%; aspect-ratio:3/2; object-fit:cover;
  border-radius:7px; display:block; background:var(--line); }
/* Named, because "the first one" is invisible in a grid. */
.ph-main { position:absolute; top:16px; left:16px; background:var(--accent);
  color:var(--surface); font-size: 11px; font-weight:600; padding:3px 8px; border-radius:5px; }
.ph-cap { margin-top:8px; font-size: 13px; }
.ph-acts { display:flex; gap:6px; margin-top:8px; flex-wrap:wrap; }

/* ══ MANAGING PHOTOGRAPHS ══ */
.ph-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 16px; }
.ph-item { border: 1px solid var(--line); border-radius: 12px; padding: 12px;
  background: var(--surface); display: flex; flex-direction: column; gap: 9px; }
.ph-shot { position: relative; }
.ph-shot img { width: 100%; height: 160px; object-fit: cover;
  border-radius: 8px; display: block; background: var(--line); }
/* Named, because "first" is not obvious from position alone once a grid
   wraps onto a second row. */
.ph-first { position: absolute; left: 8px; bottom: 8px; background: var(--accent);
  color: var(--surface); font-size: 11px; font-weight: 600; padding: 4px 9px;
  border-radius: 999px; }
.ph-acts { display: flex; gap: 6px; align-items: center; }

/* A doctor's photograph, edited in the row it belongs to. */
.dp { display:inline-block; }
.dp-shot { position:relative; display:block; width:44px; height:44px;
  border-radius:50%; overflow:hidden; cursor:pointer; background:var(--line); }
.dp-shot img { width:100%; height:100%; object-fit:cover; display:block; }
.dp-initial { display:flex; align-items:center; justify-content:center;
  width:100%; height:100%; background:var(--accent); color:var(--surface);
  font-weight:600; font-size: 17px; }
/* The affordance only appears on hover — a row of "Add" labels reads as an
   error state rather than an option. */
.dp-edit { position:absolute; inset:auto 0 0 0; background:rgba(0,0,0,.62);
  color:var(--surface); font-size:9.5px; text-align:center; padding:2px 0; opacity:0;
  transition:opacity .12s; }
.dp-shot:hover .dp-edit { opacity:1; }
.dp-err { display:block; font-size: 11px; color:var(--danger); }

/* Upload control in a table cell — a label wrapping a hidden input, so the
   whole thing is the click target without a second button. */
.dp-up { display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 12px; color: var(--accent); font-weight: 600; }
.dp-up:hover { text-decoration: underline; }

/* ══════════════════════════════════════════════════════════════════════════
   A PUBLIC COMMUNITY PAGE

   Two halves, and the split is the point. What doctors publish FOR patients
   is open and free to read. What they say TO EACH OTHER is blurred — the
   titles visible so the group does not look dead, not one word of the body.
   ══════════════════════════════════════════════════════════════════════════ */
.cm { max-width: 820px; margin: 0 auto; padding: 0 20px 60px; }
body:has(.cm) .bk { max-width: 880px; }
.cm-head h1 { font-family: var(--font-display, Georgia, serif); font-size: 30px;
  line-height: 1.15; margin: 0; }
.cm-spec { font-size: 13px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-soft); margin: 6px 0 0; }
.cm-intro { font-size: 17px; line-height: 1.65; margin: 12px 0 0; }
.cm-count { font-size: 13px; color: var(--ink-soft); margin: 12px 0 0; }
.cm-sec { margin-top: 34px; padding-top: 26px; border-top: 1px solid var(--line); }
.cm-sec h2 { font-family: var(--font-display, Georgia, serif); font-size: 22px; margin: 0 0 6px; }
.cm-note { font-size: 13px; color: var(--ink-soft); line-height: 1.6; margin: 0 0 16px; }

.cm-arts { display: grid; gap: 10px; }
.cm-art { display: grid; gap: 4px; padding: 14px 16px; border: 1px solid var(--line);
  border-radius: 10px; background: var(--surface); text-decoration: none; color: inherit; }
.cm-art:hover { box-shadow: 0 3px 14px rgba(10,10,10,.07); }
.cm-art b { font-size: 15px; }
.cm-art span { font-size: 13px; color: var(--ink-soft); line-height: 1.55; }
.cm-art em { font-size: 12px; color: var(--ink-soft); font-style: normal; }

/* The blur is real, not a low-opacity trick: the text must not be
   selectable, copyable or readable by zooming in. */
.cm-locked { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.cm-locked li { display: flex; align-items: center; justify-content: space-between;
  gap: 14px; padding: 12px 14px; border: 1px solid var(--line);
  border-radius: 10px; background: var(--surface); }
.cm-blur { filter: blur(5px); user-select: none; pointer-events: none;
  color: var(--ink); font-size: 15px; }
.cm-locked em { font-size: 12px; color: var(--ink-soft); font-style: normal;
  white-space: nowrap; }

.cm-gate { margin-top: 18px; padding: 20px; border-radius: 12px;
  background: var(--accent-tint); border: 1px solid var(--ok-bg); }
.cm-gate b { display: block; font-size: 15px; }
.cm-gate p { font-size: 13px; line-height: 1.6; margin: 6px 0 14px; }
.cm-join { display: inline-block; background: var(--accent); color: var(--surface);
  text-decoration: none; font-weight: 600; padding: 11px 20px; border-radius: 8px; }
.cm-gate > span { display: block; margin-top: 10px; font-size: 13px; color: var(--ink-soft); }
.cm-all { margin-top: 30px; font-size: 13px; }
.patient-page a.cm-art, .patient-page a.cm-join { text-decoration: none; }

/* ══════════════════════════════════════════════════════════════════════════
   80mm THERMAL RECEIPT

   72mm printable inside an 80mm roll. Monospace throughout: thermal heads
   are low-resolution and proportional faces smear at this size.

   Hidden on screen, shown only when printing — no popup window, because a
   blocker eating window.open at a busy desk means a receipt that silently
   never appears.
   ══════════════════════════════════════════════════════════════════════════ */
.rcpt { display: none; }

@media print {
  /* ── HIDDEN AND OUT OF THE FLOW ──
     visibility:hidden alone leaves every element occupying its space, so a
     sidebar and top bar that cannot be seen still push the page down and a
     72mm receipt can spill onto a second slip of an 80mm roll. Measured
     under print emulation: three chrome elements still had layout.
     The receipt is positioned absolutely so it lands top-left regardless,
     and everything else is taken out of the flow entirely. */
  /* The receipt is rendered inside the app tree, not at body level, so
     display:none on body children would hide it too. Instead: nothing has
     layout except the receipt, which is positioned absolutely at the top
     left of the page. */
  body * { visibility: hidden !important; }
  .topbar, .sidebar, .drawer, .drawer-scrim,
  .page-header, .tabs, .nav-group { display: none !important; }
  .rcpt, .rcpt * { visibility: visible !important; }
  .rcpt {
    display: block !important;
    position: absolute; left: 0; top: 0;
    width: 72mm;
    font-family: var(--font-mono, ui-monospace, "Courier New", monospace);
    font-size: 11px; line-height: 1.45; color: #000;
  }
  @page { size: 80mm auto; margin: 3mm; }

  .rcpt-head { text-align: center; display: grid; gap: 1px; margin-bottom: 6px; }
  .rcpt-head b { font-size: 13px; }
  .rcpt-head span { font-size: 11px; }
  /* Dashes, not a border: a 1px rule can fall between print-head dots and
     vanish entirely on a cheap roll. */
  .rcpt-rule { border-top: 1px dashed #000; margin: 6px 0; }
  .rcpt-title { text-align: center; font-weight: 700; letter-spacing: .08em;
    text-transform: uppercase; margin-bottom: 6px; }
  .rcpt-kv { display: flex; justify-content: space-between; gap: 8px; }
  .rcpt-kv > span:last-child { text-align: right; white-space: nowrap; }
  .rcpt-total { font-weight: 700; font-size: 13px; }
  .rcpt-due { font-weight: 700; }
  .rcpt-foot { text-align: center; font-size: 11px; margin-top: 10px; }
}

/* ══ RADIOGRAPHS ══
   Dark thumbnails: a radiograph on a white card looks washed out, and the
   whole point is being able to read it. */
.rx-wrap { margin-top: 4px; }
.rx-head { display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 10px; }
.rx-form { border: 1px solid var(--line); border-radius: 10px; padding: 14px;
  margin-bottom: 12px; background: var(--surface); }
.rx-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 10px; }
.rx-item { border: 1px solid var(--line); border-radius: 8px; padding: 0;
  overflow: hidden; background: #111; cursor: pointer; text-align: left; }
.rx-item img { width: 100%; height: 110px; object-fit: cover; display: block; }
.rx-item span { display: block; padding: 7px 9px; background: var(--surface);
  font-size: 12px; color: var(--ink-soft); }
.rx-item b { display: block; color: var(--ink); font-size: 12px; }
.rx-zoom { position: fixed; inset: 0; background: rgba(0,0,0,.94); z-index: 200;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; cursor: zoom-out; padding: 20px; }
.rx-zoom img { max-width: 96vw; max-height: 80vh; object-fit: contain; }
.rx-zoom-bar { color: #eee; font-size: 13px; display: flex; gap: 16px;
  align-items: baseline; flex-wrap: wrap; justify-content: center; }
.rx-zoom-bar b { color: var(--surface); font-size: 15px; }
.rx-zoom-bar .hint { color: #888; }
/* While the bytes are being fetched — a grey block, not a broken frame. */
.rx-loading { display: block; width: 100%; height: 110px; background: #1a1a1a; }
.rx-zoom .rx-loading { width: 60vw; height: 60vh; }

/* ══ A SHARED POST, SEEN BY A STRANGER ══ */
.pp { max-width: 640px; margin: 0 auto; padding: 0 20px 60px; }
body:has(.pp) .bk { max-width: 700px; }
.pp-group { display: inline-block; font-size: 12px; text-transform: uppercase;
  letter-spacing: .07em; color: var(--accent); text-decoration: none; }
.pp h1 { font-family: var(--font-display, Georgia, serif); font-size: 30px;
  line-height: 1.2; margin: 8px 0 0; }
.pp-by { font-size: 13px; color: var(--ink-soft); margin: 8px 0 0; }
.pp-excerpt { font-size: 17px; line-height: 1.7; margin: 18px 0 0; }

/* The fade is four grey bars that dissolve — it says a discussion
   continues without pretending to show a word of it. */
.pp-gate { margin-top: 4px; }
.pp-fade { display: grid; gap: 9px; margin-bottom: 18px; }
.pp-fade span { height: 13px; border-radius: 4px; background: var(--line); }
.pp-fade span:nth-child(1) { width: 100%; opacity: .85; }
.pp-fade span:nth-child(2) { width: 94%; opacity: .55; }
.pp-fade span:nth-child(3) { width: 88%; opacity: .3; }
.pp-fade span:nth-child(4) { width: 60%; opacity: .14; }

.pp-gate b { display: block; font-size: 17px; }
.pp-gate p { font-size: 13px; line-height: 1.65; margin: 8px 0 16px; }
.pp-join { display: inline-block; background: var(--accent); color: var(--surface);
  text-decoration: none; font-weight: 600; padding: 13px 24px; border-radius: 9px; }
.pp-gate > span { display: block; margin-top: 12px; font-size: 13px;
  color: var(--ink-soft); }
.pp-all { margin-top: 34px; padding-top: 18px; border-top: 1px solid var(--line);
  font-size: 13px; color: var(--ink-soft); }
.patient-page a.pp-join, .patient-page a.pp-group { text-decoration: none; }

/* ══════════════════════════════════════════════════════════════════════════
   THE APPLICATION IS A LIGHT INTERFACE, AND MUST SAY SO

   ── WHAT WENT WRONG ──

   Nothing in this file declares `color-scheme`, and no rule sets a
   background on an input. On a Mac in dark mode the browser therefore
   paints every form control with its own dark chrome — dark field, light
   placeholder — while the CSS keeps the text near-black.

   Dark text on a dark field. Every input, select, textarea and dropdown on
   every screen, unreadable, and nothing in the stylesheet looks wrong
   because the offending colour was never written down.

   Scrollbars, date pickers and the native select menu do the same thing.

   ── WHY DECLARING LIGHT RATHER THAN BUILDING DARK ──

   A real dark theme for a clinical interface is a serious piece of work:
   every chart colour, every status tone, every red-for-danger has to be
   re-derived, and a half-finished one is worse than none because a
   clinician cannot tell an amber warning from a grey label. Declaring the
   interface light is honest and takes effect immediately; a dark theme can
   come later as a deliberate build.

   The public patient pages already have a real dark theme, and they keep it
   — .patient-page is untouched by this.
   ══════════════════════════════════════════════════════════════════════════ */

/* Everything except the patient-facing pages renders light, so the browser
   stops second-guessing form controls and scrollbars. */

body:not(.patient-page) { color-scheme: light; }

/* And the fields say what colour they are, rather than leaving it to the
   user agent. A control with no declared background is a control whose
   colour is decided by the operating system. */
/* ── FIELDS BIG ENOUGH TO READ AND TYPE IN ──
 *
 * This rule set colours and nothing else, so every field in the product fell
 * back to the browser's own sizing. Measured: 34px tall at 13px in one place,
 * 39px at 15px in another, 58px at 17px in a third — on the same screen.
 *
 * Two rules now, and both matter in India:
 *
 *   16px minimum. Safari on iOS zooms the page when a field under 16px takes
 *   focus, and the person then has to pinch back out to see what they typed.
 *   It is the single commonest "the form is broken on my phone" report.
 *
 *   44px minimum height. That is the smallest target a fingertip hits
 *   reliably, and a front desk is tapping between fields with a patient
 *   waiting.
 *
 * font: inherit first, so a field uses the product's typeface rather than
 * the browser's — Chrome defaults to 13.3px Arial inside inputs regardless
 * of what the page says. */
.inp,
input[type="text"], input[type="email"], input[type="tel"],
input[type="password"], input[type="number"], input[type="search"],
input[type="date"], input[type="time"], input[type="datetime-local"],
input[type="file"], select, textarea {
  font: inherit;
  font-size: 16px;
  line-height: 1.45;
  min-height: 44px;
  padding: 10px 13px;
  width: 100%;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
}
/* A visible focus ring. A field somebody cannot tell they are in is a field
   they type the previous answer into. */
.inp:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
  border-color: var(--accent);
}
textarea { min-height: 88px; resize: vertical; }
/* Not stretched to the full row — a date is a known width and a full-width
   date box reads as an error. */
input[type="date"], input[type="time"], input[type="datetime-local"] { width: auto; }
/* ── MULTI-LINE FIELDS WERE NEVER SIZED ──
   The rule above sets colours only, so every textarea in the product used
   the browser default: about two rows, in the browser's own font, at
   whatever size it fancied. Somebody asked for an address, a clinical note
   or a reason got a box smaller than the sentence they were writing.
   Sized here rather than per screen, so it reaches all of them. */
textarea, textarea.inp {
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.55;
  padding: 10px 12px;
  min-height: 128px;
  /* Vertical only. Horizontal dragging breaks the column a form sits in. */
  resize: vertical;
  box-sizing: border-box;
}

.inp::placeholder, input::placeholder, textarea::placeholder {
  color: var(--ink-faint);
  opacity: 1;   /* Firefox dims placeholders again on top of the colour. */
}
/* A disabled field must still be legible — greyed is not the same as
   invisible, and a form full of pre-filled disabled fields is common here. */
.inp:disabled, input:disabled, select:disabled, textarea:disabled {
  background: var(--surface-raised);
  color: var(--ink-soft);
  -webkit-text-fill-color: var(--ink-soft);
  opacity: 1;
}

/* The patient pages keep their real dark theme. */
@media (prefers-color-scheme: dark) {
  .patient-page .inp,
  .patient-page input, .patient-page select, .patient-page textarea {
    background: var(--surface);
    color: var(--ink);
    border-color: var(--line);
  }
}

/* ── Diagnosis entry on the consultation note ──
   The suggestion list is a plain <ul> of buttons rather than a combobox: a
   clinician tabbing through it gets real focus order and a screen reader
   announces each option as what it is. A div with a click handler does
   neither. */
.cn-dx-list { list-style: none; padding: 0; margin: 4px 0 10px; }
.cn-dx-list li { padding: 6px 0; border-bottom: 1px solid var(--line); font-size: 13px; }
.cn-dx-code { font-family: ui-monospace, monospace; font-size: 12px; color: var(--accent); }
/* Named, not hidden: an uncoded diagnosis is the one a payer queries. */
.cn-dx-uncoded { font-size: 12px; color: var(--critical-ink); }
.cn-dx-hits { list-style: none; padding: 0; margin: 6px 0 8px;
  border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.cn-dx-hits li + li { border-top: 1px solid var(--line); }
.cn-dx-hits button { display: block; width: 100%; text-align: left; padding: 9px 11px;
  background: none; border: 0; font: inherit; font-size: 13px; cursor: pointer; }
.cn-dx-hits button:hover, .cn-dx-hits button:focus-visible { background: var(--surface-raised); }
.cn-dx-hits b { font-family: ui-monospace, monospace; margin-right: 8px; }
.cn-dx-hits em { font-style: normal; color: var(--critical-ink); font-size: 12px; }

/* ── Patient picker ──
   A <ul> of buttons rather than a div with click handlers: real focus order,
   and a screen reader announces each result as a control. */
.pp { position: relative; }
.pp-list { list-style: none; margin: 4px 0 0; padding: 0; position: absolute; z-index: 20;
  left: 0; right: 0; background: var(--surface); border: 1px solid var(--line);
  border-radius: 10px; overflow: hidden; box-shadow: 0 12px 28px -18px rgba(7, 33, 28, .5); }
.pp-list li + li { border-top: 1px solid var(--line); }
.pp-list button { display: block; width: 100%; text-align: left; padding: 9px 12px;
  background: none; border: 0; font: inherit; cursor: pointer; }
.pp-list button:hover, .pp-list button:focus-visible { background: var(--surface-raised); }
/* Phone and UHID always visible: two patients sharing a name is ordinary. */
.pp-meta { display: block; font-size: 12px; color: var(--ink-soft); margin-top: 2px; }
.pp-hint { padding: 9px 12px; font-size: 13px; color: var(--ink-faint); }
.pp-chosen { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 9px 12px; border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface-raised); }

/* ── What is waiting ──
   Each row is a link, not a card with a button inside it: the whole row is
   the target, which is what somebody expects and what a keyboard reaches. */
.wl-row { display: flex; align-items: center; gap: 16px; padding: 14px 16px;
  border: 1px solid var(--line); border-radius: 12px; margin-bottom: 10px;
  text-decoration: none; color: inherit; background: var(--surface); transition: border-color .15s, transform .15s; }
.wl-row:hover { border-color: var(--accent); transform: translateY(-1px); }
.wl-n { font-size: 30px; font-weight: 700; color: var(--accent);
  min-width: 56px; text-align: right; font-variant-numeric: tabular-nums; }
.wl-body { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.wl-why { font-size: 12px; color: var(--ink-soft); }
/* Only rendered when non-zero, so its presence is itself the signal. */
.wl-urgent { font-size: 12px; font-weight: 600; color: var(--critical-ink);
  background: var(--critical-tint); padding: 5px 10px; border-radius: 999px; white-space: nowrap; }

/* ══ NADI, DOCKED ══
   A right-hand column rather than a modal over the page. The brief has to be
   visible when the day starts, and a morning brief behind a scrim is one
   nobody reads. */
.nadi-dock { position: fixed; top: 0; right: 0; bottom: 0; width: 340px; z-index: 40;
  background: var(--surface); border-left: 1px solid var(--line);
  display: flex; flex-direction: column; overflow-y: auto;
  box-shadow: -18px 0 40px -34px rgba(7, 33, 28, .5); }
.nadi-dock-head { display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px; border-bottom: 1px solid var(--line); position: sticky; top: 0;
  background: var(--surface); z-index: 1; }
.nadi-min { border: 0; background: none; font-size: 22px; line-height: 1; cursor: pointer;
  color: var(--ink-soft); padding: 0 6px; border-radius: 6px; }
.nadi-min:hover { background: var(--surface-raised); }

/* Collapsed to a rail, not hidden. A panel somebody can see is one they
   remember they have. */
.nadi-rail { position: fixed; top: 50%; right: 0; transform: translateY(-50%); z-index: 40;
  border: 1px solid var(--line); border-right: 0; background: var(--surface); cursor: pointer;
  padding: 14px 8px; border-radius: 12px 0 0 12px; display: flex; flex-direction: column;
  align-items: center; gap: 8px; font: inherit; }
.nadi-rail:hover { background: var(--surface-raised); }
.nadi-rail-mark { width: 26px; height: 26px; border-radius: 8px; display: grid;
  place-items: center; background: var(--accent); color: var(--surface); font-weight: 700; }
.nadi-rail-text { writing-mode: vertical-rl; font-size: 12px; letter-spacing: .08em;
  color: var(--ink-soft); }

/* The page gives up the width only when the dock is open, so a collapsed
   Nadi costs nothing. */
@media (min-width: 1200px) {
  body:has(.nadi-dock) .main { padding-right: 356px; }
}
/* Below that the dock overlays rather than squeezing a layout that has no
   room to give. */
@media (max-width: 1199px) {
  .nadi-dock { width: min(340px, 88vw); }
}

/* ══ THE BRIEF ══ */
.nb { padding: 14px 16px; border-bottom: 1px solid var(--line); }
.nb-h { margin: 0 0 10px; font-size: 12px; font-weight: 800; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-faint);
  display: flex; justify-content: space-between; align-items: baseline; }
.nb-seen { font-weight: 600; letter-spacing: 0; text-transform: none; font-size: 12px; }
.nb-clear { margin: 0; font-size: 13px; color: var(--ink-soft); line-height: 1.6; }
.nb-row { display: flex; align-items: baseline; gap: 10px; padding: 7px 0;
  text-decoration: none; color: inherit; border-bottom: 1px solid var(--surface-raised); }
.nb-row:last-of-type { border-bottom: 0; }
.nb-row b { font-size: 19px; min-width: 30px; text-align: right;
  color: var(--accent); font-variant-numeric: tabular-nums; }
/* Only the abnormal-result row carries this. If everything were coloured,
   nothing would be. */
.nb-row.is-urgent b { color: var(--critical-ink); }
.nb-row span { font-size: 13px; line-height: 1.4; }
.nb-row em { display: block; font-style: normal; font-size: 12px; color: var(--ink-faint); }
.nb-attn { margin: 10px 0 0; padding: 9px 11px; list-style: none;
  background: var(--critical-tint); border-radius: 8px; font-size: 12px; line-height: 1.6;
  color: var(--critical-ink); }

/* ── Guardian ──
   Status is carried by a left border and a word, never by colour alone: a
   red dot and a green dot are the same dot to about one man in twelve. */
.gd-row { display: grid; grid-template-columns: 260px 1fr; gap: 14px; align-items: start;
  padding: 11px 14px; border-left: 3px solid var(--line); margin-bottom: 8px;
  background: var(--surface-raised); border-radius: 0 8px 8px 0; font-size: 13px; }
.gd-row b { font-weight: 600; }
.gd-row span { color: var(--ink-soft); }
.gd-pass { border-left-color: var(--accent); }
.gd-warn { border-left-color: var(--warn); background: var(--warn-tint); }
.gd-fail { border-left-color: var(--critical-ink); background: var(--critical-tint); }
@media (max-width: 720px) { .gd-row { grid-template-columns: 1fr; gap: 4px; } }

/* ── Profile section blocks (editor) ──
   The grip is decorative; the arrows beside it are the real control. A drag
   handle alone locks out anybody without a mouse. */
.ps-block { background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  margin-bottom: 10px; }
.ps-block[draggable="true"] { cursor: grab; }
.ps-dragging { opacity: .45; border-style: dashed; }
.ps-head { display: flex; align-items: center; gap: 8px; padding: 12px 14px; flex-wrap: wrap; }
.ps-grip { color: var(--ink-faint); font-size: 17px; letter-spacing: -2px; }
.ps-kind { font-size: 11px; text-transform: uppercase; letter-spacing: .6px;
  color: var(--ink-faint); }
.ps-hidden { font-size: 11px; font-weight: 700; color: var(--critical-ink);
  background: var(--critical-tint); padding: 2px 8px; border-radius: 999px; }
.ps-edit { padding: 0 14px 14px; display: flex; flex-direction: column; gap: 8px; }
.ps-row { display: flex; gap: 8px; align-items: center; }
.ps-row-col { flex-direction: column; align-items: stretch; }
.ps-kinds { display: grid; grid-template-columns: repeat(auto-fill, minmax(215px, 1fr));
  gap: 10px; margin-top: 10px; }
.ps-kind-btn { text-align: left; padding: 12px; border-radius: 10px; background: var(--surface);
  border: 1px solid var(--line); cursor: pointer; font: inherit; }
.ps-kind-btn:hover { border-color: var(--accent); }
.ps-kind-btn b { display: block; font-size: 13px; margin-bottom: 3px; }
.ps-kind-btn span { font-size: 12px; color: var(--ink-soft); line-height: 1.4; }

/* ── Profile section blocks (public page) ── */
.pf-sec { margin: 26px 0; }
.pf-sec h2 { font-size: 19px; margin: 0 0 10px; }
.pf-sec-list, .pf-sec-steps, .pf-sec-time { margin: 0; padding-left: 20px; line-height: 1.7; }
.pf-sec-facts { display: grid; grid-template-columns: minmax(120px, 34%) 1fr; gap: 6px 16px; margin: 0; }
.pf-sec-facts dt { font-weight: 600; color: var(--ink-soft); }
.pf-sec-facts dd { margin: 0; }
.pf-sec-qa { margin-bottom: 14px; }
.pf-sec-qa h3 { font-size: 15px; margin: 0 0 3px; }
.pf-sec-qa p { margin: 0; color: var(--ink-soft); }
.pf-sec-quote { margin: 0; padding: 14px 16px; border-left: 3px solid var(--accent);
  background: var(--surface-raised); border-radius: 0 10px 10px 0; }
.pf-sec-quote cite { display: block; margin-top: 6px; font-style: normal; font-size: 13px;
  color: var(--ink-faint); }
@media (max-width: 600px) { .pf-sec-facts { grid-template-columns: 1fr; gap: 2px 0; }
  .pf-sec-facts dd { margin-bottom: 8px; } }

/* ── "Something wrong with this page?" ──
   Deliberately quiet. A prominent report button on a clinical profile invites
   idle clicks and reads as an accusation the page is making about its own
   subject. It has to be findable, not loud. */
.pf-report { margin-top: 34px; padding-top: 14px; border-top: 1px solid var(--line);
  font-size: 12px; color: var(--ink-faint); line-height: 1.6; }
.pf-report a { color: var(--ink-soft); }

/* ── Terms acceptance ──
   Quiet. This is a thing to do once, not a warning to live beside. */
.terms-gate { margin: 12px 0; padding: 14px; border: 1px solid var(--line);
  border-radius: 12px; background: var(--surface); }
.terms-tick { display: flex; gap: 9px; align-items: flex-start; font-size: 13px;
  line-height: 1.5; margin-bottom: 10px; cursor: pointer; }
.terms-tick input { margin-top: 2px; }
.terms-body { margin: 10px 0 12px; padding: 12px 14px; background: var(--paper);
  border-radius: 10px; max-height: 320px; overflow-y: auto; }
.terms-sec { margin-bottom: 12px; }
.terms-sec b { display: block; font-size: 13px; margin-bottom: 2px; }
.terms-sec p { margin: 0; font-size: 13px; line-height: 1.6; color: var(--ink-soft); }
.lnk { background: none; border: 0; padding: 0; font: inherit; color: var(--accent);
  text-decoration: underline; cursor: pointer; }

/* ── Public page blocks ──
   Design lives here, not in the data. A clinic chooses "three cards" and gets
   three well-set cards; it never chooses a colour, a font or a margin, so no
   clinic can make its own page unreadable and every page still looks like
   the same product. */
.pf-lead { font-size: 17px; line-height: 1.6; color: var(--ink-soft); }
.pf-check { list-style: none; padding-left: 0; }
.pf-check li { padding-left: 22px; position: relative; line-height: 1.7; }
.pf-check li::before { content: "✓"; position: absolute; left: 0; color: var(--accent); font-weight: 700; }
.pf-callout { padding: 14px 16px; border-radius: 10px; border-left: 3px solid var(--accent);
  background: var(--accent-tint); }
.pf-callout p { margin: 0; }
.pf-callout-warn { border-left-color: var(--warn); background: var(--warn-tint); }
.pf-callout-good { border-left-color: var(--ok); background: var(--ok-bg); }
.pf-acc { border-bottom: 1px solid var(--line); padding: 10px 0; }
.pf-acc summary { cursor: pointer; font-weight: 600; font-size: 15px; }
.pf-acc p { margin: 8px 0 0; color: var(--ink-soft); }

.pf-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 16px; }
.pf-stat b { display: block; font-family: var(--font-display); font-size: 30px; line-height: 1.1;
  color: var(--accent); }
.pf-stat span { display: block; font-size: 13px; color: var(--ink-soft); margin-top: 3px; }
.pf-stat em { display: block; font-style: normal; font-size: 12px; color: var(--ink-faint); }

.pf-tw { overflow-x: auto; }
.pf-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.pf-table th, .pf-table td { text-align: left; padding: 9px 12px; border-bottom: 1px solid var(--line); }
.pf-table th { font-size: 12px; text-transform: uppercase; letter-spacing: .5px; color: var(--ink-faint); }

.pf-prices { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; }
.pf-price { border: 1px solid var(--line); border-radius: 12px; padding: 14px; }
.pf-price b { display: block; font-size: 13px; }
.pf-amt { display: block; font-family: var(--font-display); font-size: 22px; color: var(--accent); margin: 4px 0; }
.pf-price em { font-style: normal; font-size: 12px; color: var(--ink-soft); }
.pf-foot { font-size: 12px; color: var(--ink-faint); margin-top: 10px; }

.pf-hours { display: grid; grid-template-columns: minmax(90px, 30%) 1fr; gap: 5px 16px; margin: 0; }
.pf-hours dt { font-weight: 600; color: var(--ink-soft); }
.pf-hours dd { margin: 0; }
.pf-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.pf-chip { font-size: 13px; padding: 5px 11px; border-radius: 999px; background: var(--surface-raised);
  border: 1px solid var(--line); }

.pf-team { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 18px; }
.pf-member b { display: block; margin-top: 8px; font-size: 13px; }
.pf-member span { display: block; font-size: 13px; color: var(--ink-soft); }
.pf-member em { display: block; font-style: normal; font-size: 12px; color: var(--ink-faint); margin-top: 3px; }
.pf-pcard { display: flex; gap: 16px; align-items: flex-start; }
.pf-pcard .pf-img { width: 108px; border-radius: 12px; }
.pf-quotes { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px; }
.pf-badges { display: flex; flex-wrap: wrap; gap: 10px; }
.pf-badge { border: 1px solid var(--line); border-radius: 10px; padding: 10px 14px; }
.pf-badge b { display: block; font-size: 13px; }
.pf-badge span { font-size: 12px; color: var(--ink-soft); }
.pf-locs { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; }
.pf-loc { border: 1px solid var(--line); border-radius: 12px; padding: 14px; }
.pf-loc b, .pf-loc span, .pf-loc a { display: block; }
.pf-loc span { font-size: 13px; color: var(--ink-soft); margin: 4px 0; }

.pf-img { display: block; width: 100%; height: auto; border-radius: 12px; }
.pf-fig { margin: 0; }
.pf-fig-inline { max-width: 340px; }
.pf-fig figcaption, .pf-gallery figcaption { font-size: 12px; color: var(--ink-faint); margin-top: 6px; }
.pf-imgtext { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: center; }
.pf-side-right { direction: rtl; } .pf-side-right > * { direction: ltr; }
.pf-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 12px; }
.pf-gallery figure { margin: 0; }
.pf-ba { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.pf-ba figure { margin: 0; }
.pf-ba figcaption { font-size: 12px; text-transform: uppercase; letter-spacing: .6px;
  color: var(--ink-faint); margin-top: 6px; }
.pf-banner { position: relative; border-radius: 14px; overflow: hidden; }
.pf-banner p { margin: 0; padding: 14px 16px; background: var(--surface-raised); font-size: 15px; }
.pf-video a { display: inline-block; padding: 11px 16px; border: 1px solid var(--line);
  border-radius: 10px; text-decoration: none; }

.pf-process { list-style: none; counter-reset: s; padding-left: 0; }
.pf-process li { counter-increment: s; padding-left: 40px; position: relative; margin-bottom: 14px; }
.pf-process li::before { content: counter(s); position: absolute; left: 0; top: 0;
  width: 26px; height: 26px; border-radius: 50%; background: var(--accent-tint);
  color: var(--accent); font-weight: 700; font-size: 13px; display: grid; place-items: center; }
.pf-process b { display: block; }
.pf-process span { color: var(--ink-soft); }
.pf-cards { display: grid; gap: 14px; }
.pf-cards-2 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.pf-cards-3 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.pf-card { border: 1px solid var(--line); border-radius: 12px; padding: 16px; }
.pf-card b { display: block; margin-bottom: 5px; }
.pf-card p { margin: 0; color: var(--ink-soft); font-size: 13px; }
.pf-icons { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 16px; }
.pf-icon { display: flex; gap: 11px; }
.pf-icon > span { font-size: 19px; line-height: 1.2; }
.pf-icon p { margin: 2px 0 0; font-size: 13px; color: var(--ink-soft); }
.pf-tabsec { margin-bottom: 14px; }
.pf-tabsec b { display: block; margin-bottom: 3px; }

.pf-hr { border: 0; border-top: 1px solid var(--line); margin: 0; }
.pf-spacer-small { height: 12px; } .pf-spacer-medium { height: 28px; } .pf-spacer-large { height: 52px; }
.pf-cta { text-align: center; padding: 22px; border-radius: 14px; background: var(--accent-tint); }
.pf-cta p { margin: 0 0 12px; font-size: 17px; }
.pf-cta-btn { display: inline-block; padding: 13px 26px; border-radius: 10px;
  background: var(--accent); color: var(--on-primary); text-decoration: none; font-weight: 600; }
.pf-contact { display: flex; flex-wrap: wrap; gap: 8px 20px; font-size: 15px; }
.pf-maplink a { font-size: 15px; }

@media (max-width: 620px) {
  .pf-imgtext, .pf-ba { grid-template-columns: 1fr; }
  .pf-side-right { direction: ltr; }
  .pf-hours { grid-template-columns: 1fr; gap: 2px 0; }
  .pf-hours dd { margin-bottom: 8px; }
}
/* A heading block is a title and a hairline — it opens a part of the page. */
.pf-sec-heading h2 { font-size: 22px; margin-bottom: 8px; }
.pf-headrule { height: 2px; width: 44px; background: var(--accent); border-radius: 2px; }
/* A grouped picker: forty-four buttons in one list is a list nobody reads to
   the end of. Somebody adding a photograph looks under Pictures. */
.ps-group { margin-top: 14px; }
.ps-group-name { display: block; font-size: 11px; text-transform: uppercase;
  letter-spacing: .7px; color: var(--ink-faint); margin-bottom: 7px; }

/* ── Consulting hours ──
   A week, one row per day. The controls only appear on days that are ticked:
   seven rows of disabled time pickers is a wall, and a clinic open three
   days should see three rows of controls. */
.ch-row { display: flex; align-items: center; gap: 10px; padding: 9px 0;
  border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.ch-day { display: flex; align-items: center; gap: 8px; min-width: 130px;
  font-size: 15px; cursor: pointer; }
.ch-row .inp { width: auto; }
.ch-slot { min-width: 130px; }
.ch-to { color: var(--ink-faint); font-size: 13px; }
.ch-off { color: var(--ink-faint); font-size: 13px; }
.ch-bad { color: var(--critical-ink); font-size: 13px; font-weight: 600; }
@media (max-width: 560px) { .ch-day { min-width: 100%; } }
/* Booking dialog — sits inside the existing .modal-box rather than beside it. */
.bk-modal-body { max-height: 62vh; overflow-y: auto; }
.bk-modal-foot { display: flex; gap: 8px; margin-top: 16px; padding-top: 14px;
  border-top: 1px solid var(--line); }
.fld-label { display: block; font-size: 13px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .6px; color: var(--ink-faint); margin-bottom: 6px; }
/* A stat that leads somewhere says so on hover — quietly, because a
   dashboard of eight cards all lifting at once is a fairground. */
.stat-link { transition: border-color .12s ease, transform .12s ease; }
.stat-link:hover { border-color: var(--accent); transform: translateY(-1px); }
.stat-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── The welcome ──
   Sits over the app while it loads and leaves on the first touch. It does not
   block: the console renders behind it and the data is already on its way, so
   dismissing early costs nothing. */
.wlc { position: fixed; inset: 0; z-index: 300; display: grid; place-items: center;
  background: var(--paper); animation: wlc-in .3s ease both; }
.wlc-out { animation: wlc-fade .32s ease forwards; }
@keyframes wlc-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes wlc-fade { to { opacity: 0; visibility: hidden; } }
.wlc-inner { text-align: center; }
.wlc-mark { color: var(--accent); display: inline-block; }
.wlc-ring { stroke-dasharray: 170; stroke-dashoffset: 170;
  animation: wlc-draw .85s cubic-bezier(.4,0,.2,1) .1s forwards; }
.wlc-tick { stroke-dasharray: 46; stroke-dashoffset: 46;
  animation: wlc-draw .45s cubic-bezier(.4,0,.2,1) .7s forwards; }
@keyframes wlc-draw { to { stroke-dashoffset: 0; } }
.wlc-hello { font-family: var(--font-display); font-size: 30px; margin: 18px 0 0;
  animation: wlc-rise .5s ease .35s both; }
.wlc-sub { font-size: 13px; color: var(--ink-faint); margin: 6px 0 0;
  animation: wlc-rise .5s ease .5s both; }
@keyframes wlc-rise { from { opacity: 0; transform: translateY(7px); } to { opacity: 1; transform: none; } }

/* Somebody who has asked not to see movement gets the greeting with none.
   A splash is exactly the kind of thing that triggers vestibular symptoms. */
@media (prefers-reduced-motion: reduce) {
  .wlc, .wlc-hello, .wlc-sub { animation: none; }
  .wlc-ring, .wlc-tick { stroke-dashoffset: 0; animation: none; }
}

/* ── Where do you want to go ── */
.goto { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 12px; margin-top: 4px; }
.goto-card { text-align: left; padding: 17px; border: 1px solid var(--line);
  border-radius: 13px; background: var(--surface); cursor: pointer; font: inherit;
  transition: border-color .12s ease, transform .12s ease; }
.goto-card:hover { border-color: var(--accent); transform: translateY(-2px); }
.goto-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.goto-card b { display: block; font-family: var(--font-display); font-size: 19px; }
.goto-card span { display: block; font-size: 13px; color: var(--ink-soft);
  margin-top: 5px; line-height: 1.5; }

/* ── The HR head's console ──
   A rail and a work list. The rail is a rail, not tabs: six destinations that
   will each grow their own screen, and tabs stop reading as navigation once
   there are more than four. */
.hrc { display: grid; grid-template-columns: 190px 1fr; gap: 0;
  border: 1px solid var(--line); border-radius: 14px; overflow: hidden;
  background: var(--surface); }
.hrc-nav { display: flex; flex-direction: column; padding: 12px 0;
  border-right: 1px solid var(--line); background: var(--paper); }
/* Kept: the class is gone from the app (the corporate console now uses the
   shared <Tabs>), but removing dead CSS and dead markup in one change makes
   a regression impossible to bisect. It goes on its own. */
.hrc-nav-item { text-align: left; padding: 11px 18px; border: 0; background: none;
  font: inherit; font-size: 15px; font-weight: 500; color: var(--ink-mid);
  cursor: pointer; border-left: 3px solid transparent; }
.hrc-nav-item:hover { color: var(--ink); }
.hrc-nav-item.is-on { color: var(--accent); font-weight: 600;
  border-left-color: var(--accent); background: var(--surface); }
.hrc-main { padding: 22px; }

.hrc-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px; }
.hrc-fig { border: 1px solid var(--line); border-radius: 12px; padding: 16px; }
.hrc-fig-label { display: block; font-size: 11px; text-transform: uppercase;
  letter-spacing: .08em; font-weight: 600; color: var(--ink-faint); }
.hrc-fig-value { display: block; font-family: var(--font-display); font-size: 30px;
  line-height: 1.15; margin-top: 8px; }
.hrc-fig-money { color: var(--accent); }
.hrc-fig-warn { color: var(--warn); }

.hrc-eyebrow { font-size: 11px; text-transform: uppercase; letter-spacing: .09em;
  font-weight: 600; color: var(--ink-faint); margin: 26px 0 10px; }

/* flex-wrap, because a row with buttons on the right overflows a 390px
   phone otherwise — measured at 91px past the viewport on the Atlas console.
   Shared by every screen that uses this row, so all of them get it. */
.hrc-row { display: flex; align-items: center; gap: 14px; padding: 15px 16px;
  flex-wrap: wrap;
  border: 1px solid var(--line); border-radius: 12px; margin-bottom: 9px; }
/* The label keeps a sensible floor so it wraps rather than being squeezed to
   a single character column when the buttons drop below it. */
.hrc-label { min-width: 55%; }
/* min-width, not width. A count of 38 wrapped to two lines and an amount was
   cut off mid-figure because this was sized for a single digit. */
.hrc-count { min-width: 62px; padding: 5px 10px; text-align: center;
  border-radius: 8px; background: var(--surface-raised); font-family: var(--font-mono);
  font-size: 13px; white-space: nowrap; }
.hrc-label { flex: 1; font-size: 15px; }
.hrc-verb { font-family: var(--font-mono); font-size: 13px; color: var(--ink-faint);
  white-space: nowrap; }
.hrc-warn .hrc-count { background: var(--warn-tint); color: var(--warn); }
.hrc-bad .hrc-count { background: var(--critical-tint); color: var(--critical-ink); }
.hrc-good .hrc-count { background: var(--ok-bg); color: var(--ok); }

@media (max-width: 700px) {
  .hrc { grid-template-columns: 1fr; }
  .hrc-nav { flex-direction: row; overflow-x: auto; border-right: 0;
    border-bottom: 1px solid var(--line); }
  .hrc-nav-item { border-left: 0; border-bottom: 3px solid transparent; white-space: nowrap; }
  .hrc-nav-item.is-on { border-bottom-color: var(--accent); }
}
/* The reason a row is flagged, under the name. In a tooltip it would be
   invisible to anybody working through the list quickly, which is everybody. */
.hrc-why { display: block; font-size: 13px; font-weight: 400; color: var(--ink-soft);
  margin-top: 3px; line-height: 1.45; }

/* ── Plan and billing ──
   Not a pricing page. This is opened by somebody who has already chosen
   Drapto and wants three answers: what am I on, what does it cost, what
   happens when the trial ends. So the current plan is the largest thing. */
.pb-now { display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; padding: 22px; border: 1px solid var(--line); border-radius: 14px;
  background: var(--surface); }
.pb-now-over { border-color: var(--warn); background: var(--warn-tint); }
.pb-eyebrow { display: block; font-size: 11px; text-transform: uppercase;
  letter-spacing: .08em; font-weight: 600; color: var(--ink-faint); }
.pb-plan { display: block; font-family: var(--font-display); font-size: 30px;
  line-height: 1.15; margin-top: 6px; }
.pb-note { margin: 6px 0 0; font-size: 15px; color: var(--ink-soft); }
.pb-pill { padding: 6px 13px; border-radius: 999px; background: var(--accent-tint);
  color: var(--accent); font-size: 13px; font-weight: 600; white-space: nowrap; }
.pb-pill-over { background: var(--critical-tint); color: var(--critical-ink); }

.pb-cycle { display: flex; align-items: center; gap: 8px; margin: 22px 0 12px; }
.pb-cycle-btn { padding: 8px 17px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface); font: inherit; font-size: 13px; cursor: pointer;
  color: var(--ink-mid); }
.pb-cycle-btn.is-on { background: var(--accent); border-color: var(--accent);
  color: var(--on-primary); font-weight: 600; }

.pb-plans { display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
  gap: 13px; }
.pb-card { border: 1px solid var(--line); border-radius: 14px; padding: 19px;
  display: flex; flex-direction: column; gap: 7px; background: var(--surface); }
.pb-card.is-mine { border-color: var(--accent); border-width: 2px; }
.pb-card-name { font-family: var(--font-display); font-size: 19px; }
.pb-card-who { font-size: 13px; color: var(--ink-soft); line-height: 1.45; min-height: 38px; }
.pb-price { font-family: var(--font-display); font-size: 30px; line-height: 1.1; margin-top: 4px; }
.pb-price span { font-family: var(--font-body); font-size: 13px; color: var(--ink-faint); }
/* Shown, not buried. A hospital that meets a ₹15,000 setup fee at the payment
   sheet does not complete the payment. */
.pb-setup { font-size: 12px; color: var(--ink-faint); }
.pb-mine { font-size: 13px; font-weight: 600; color: var(--accent); margin-top: auto;
  padding-top: 8px; }
.pb-card .btn { margin-top: auto; }

.pb-inv { display: flex; align-items: center; gap: 14px; padding: 12px 15px;
  border: 1px solid var(--line); border-radius: 11px; margin-bottom: 8px; }
.pb-inv-no { font-family: var(--font-mono); font-size: 13px; min-width: 110px; }
.pb-inv b { flex: 1; }
.pb-quoted { font-family: var(--font-body); font-size: 15px; color: var(--ink-soft); }

/* ── Import column mapping ──
   One row per column, scrollable. A 360-column export has to be workable,
   which means the list scrolls and the page does not. */
.mig-map { max-height: 460px; overflow-y: auto; border: 1px solid var(--line);
  border-radius: 12px; padding: 8px; }
.mig-row { display: flex; align-items: center; gap: 11px; padding: 9px 10px;
  border-bottom: 1px solid var(--line); }
.mig-row:last-child { border-bottom: 0; }
.mig-row.is-off { opacity: .5; }
.mig-col { flex: 1; min-width: 0; }
.mig-col b { display: block; font-size: 13px; }
/* Sample values, so a column called "F1" is identifiable. Truncated rather
   than wrapped — a long address would push every row out of alignment. */
.mig-col span { display: block; font-size: 12px; color: var(--ink-faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mig-to { max-width: 210px; }
.mig-name { max-width: 175px; }
@media (max-width: 640px) {
  .mig-row { flex-wrap: wrap; }
  .mig-to, .mig-name { max-width: none; flex: 1 1 100%; }
}

/* ── Imported columns on a patient record ──
   Context for reading the record rather than part of it, so it sits quietly:
   smaller than the clinical content and above it. */
.pt-custom { display: flex; flex-wrap: wrap; gap: 7px 22px; margin: 11px 0 0; }
.pt-custom > div { min-width: 0; }
.pt-custom dt { font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-faint); font-weight: 600; }
.pt-custom dd { margin: 1px 0 0; font-size: 13px; }

/* ── Imported columns, in settings ── */
.cf-row { display: flex; align-items: center; gap: 12px; padding: 11px 13px;
  border: 1px solid var(--line); border-radius: 11px; margin-bottom: 8px; }
.cf-row.is-off { opacity: .55; }
.cf-label { flex: 1; min-width: 130px; }
/* The stored name. Visible so nobody thinks the screen is broken, muted so
   nobody thinks it is the thing to edit. */
.cf-key { font-family: var(--font-mono); font-size: 12px; color: var(--ink-faint);
  white-space: nowrap; }
.cf-count { font-size: 12px; color: var(--ink-faint); white-space: nowrap; }
.cf-show { display: flex; align-items: center; gap: 6px; font-size: 13px;
  white-space: nowrap; }
@media (max-width: 700px) { .cf-row { flex-wrap: wrap; } .cf-label { flex: 1 1 100%; } }

/* ── Did they come back ── */
.ob-row { display: flex; align-items: center; gap: 14px; padding: 12px 15px;
  border: 1px solid var(--line); border-radius: 11px; margin-bottom: 8px; }
.ob-who { flex: 1; min-width: 0; font-size: 15px; }
.ob-why { display: block; font-size: 13px; font-weight: 400; color: var(--ink-soft);
  margin-top: 2px; }
.ob-late { font-size: 13px; color: var(--warn); white-space: nowrap; }

/* ── A doctor's usual prescriptions ──
   Above the drug rows, because it is a shortcut to filling them in rather
   than another field to fill. */
.rx-favs { display: flex; flex-wrap: wrap; align-items: center; gap: 7px;
  margin-bottom: 12px; }
.rx-favs-label { font-size: 11px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-faint); font-weight: 600; margin-right: 3px; }
/* How often it has been used. A doctor with twenty favourites needs to see
   which four are the real ones. */
.rx-favs-n { margin-left: 6px; font-size: 11px; color: var(--ink-faint); }
/* The diagnosis it was written for, so a doctor can tell at a glance whether
   last time is the right thing to repeat. */
.rx-favs-dx { font-size: 12px; color: var(--ink-faint); }

/* ── The record pack ── */
.pk-gaps { margin: 8px 0 0; padding-left: 19px; }
.pk-gaps li { font-size: 13px; line-height: 1.6; margin-bottom: 4px; }
.pk-chain { margin: 6px 0 0; font-size: 15px; line-height: 1.6; }
.pk-ev { display: flex; gap: 13px; padding: 8px 0; border-bottom: 1px solid var(--line); }
.pk-ev:last-child { border-bottom: 0; }
.pk-when { font-family: var(--font-mono); font-size: 12px; color: var(--ink-faint);
  min-width: 96px; white-space: nowrap; }
.pk-what { flex: 1; font-size: 13px; }
.pk-who { font-size: 12px; color: var(--ink-faint); white-space: nowrap; }
/* A revoked or expired link, still listed so the record is complete. */
.hrc-off { opacity: .55; }

/* ── Consultation hours ──
   A week, not a list of rows: the week is the unit people think in. */
.ch-box { max-width: 620px; }
.ch-row { display: flex; align-items: center; gap: 9px; padding: 7px 0;
  border-bottom: 1px solid var(--line); }
.ch-row:last-of-type { border-bottom: 0; }
.ch-row.is-off { opacity: .5; }
.ch-day { display: flex; align-items: center; gap: 7px; min-width: 122px;
  font-size: 13px; }
.ch-t { max-width: 116px; }
.ch-s { max-width: 132px; }
@media (max-width: 620px) {
  .ch-row { flex-wrap: wrap; }
  .ch-day { flex: 1 1 100%; }
}

/* ── Taking a payment ──
   The outstanding figure is the largest thing in the dialog: it is what the
   person at the desk is reading off to the patient. */
.tp-box { max-width: 430px; }
.tp-due { display: flex; align-items: baseline; justify-content: space-between;
  padding: 12px 14px; border-radius: 11px; background: var(--surface-raised);
  margin-top: 6px; }
.tp-due span { font-size: 13px; color: var(--ink-faint); }
.tp-due b { font-family: var(--font-display); font-size: 22px; }
.tp-methods { display: flex; flex-wrap: wrap; gap: 6px; }

/* ── Free slots ──
   A grid of times. One tap, and the times that exist are the only ones
   offered — so 11:07 on a day the doctor does not sit cannot be booked. */
.ba-slots { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 10px; }
.ba-slot { min-height: 44px; padding: 0 15px; border: 1px solid var(--line-strong);
  border-radius: 9px; background: var(--surface); font: inherit; font-size: 15px;
  cursor: pointer; color: var(--ink); }
.ba-slot:hover:not(:disabled) { border-color: var(--accent); }
.ba-slot.is-on { background: var(--accent); border-color: var(--accent);
  color: var(--on-primary); font-weight: 600; }
/* Shown, not hidden. A desk seeing 11:30 struck through knows the doctor is
   there and busy, which is different from not being there at all. */
.ba-slot.is-taken { opacity: .38; text-decoration: line-through; cursor: not-allowed; }

/* ── Billing ──
   The total at the size of the question being asked. Four buckets and no
   total was the old shape, and it made somebody add up in their head. */
.bl-head { padding: 20px 22px; border: 1px solid var(--line); border-radius: 14px;
  background: var(--surface); }
.bl-eyebrow { display: block; font-size: 11px; text-transform: uppercase;
  letter-spacing: .08em; font-weight: 600; color: var(--ink-faint); }
.bl-total { display: block; font-family: var(--font-display); font-size: 30px;
  line-height: 1.15; margin-top: 6px; }
.bl-sub { margin: 4px 0 0; font-size: 13px; color: var(--ink-soft); }

/* Tappable, because the ages are how somebody decides who to ring. */
.bl-buckets { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px; margin-top: 12px; }
.bl-bucket { text-align: left; padding: 14px 16px; border: 1px solid var(--line);
  border-radius: 12px; background: var(--surface); cursor: pointer; font: inherit; }
.bl-bucket:hover { border-color: var(--accent); }
.bl-bucket.is-on { border-color: var(--accent); border-width: 2px; padding: 13px 15px; }
.bl-bucket-label { display: block; font-size: 12px; color: var(--ink-faint); }
.bl-bucket-value { display: block; font-family: var(--font-display); font-size: 22px;
  margin-top: 5px; }
.bl-warn .bl-bucket-value { color: var(--warn); }
.bl-bad .bl-bucket-value { color: var(--critical); }

.bl-bar { display: flex; gap: 10px; align-items: center; margin: 22px 0 12px;
  flex-wrap: wrap; }
.bl-bar .inp { max-width: 320px; }

/* Rows, not a seven-column table. Two of those columns had no heading at
   all, which is a table admitting it is a layout. */
.bl-list { display: flex; flex-direction: column; gap: 8px; }
.bl-row { display: flex; align-items: center; gap: 16px; padding: 13px 16px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--surface); }
.bl-row.is-owed { border-left: 3px solid var(--warn); }
.bl-who { flex: 1; min-width: 0; }
.bl-who b { display: block; font-size: 15px; }
.bl-who span { display: block; font-size: 12px; color: var(--ink-faint); margin-top: 2px; }
.bl-money { text-align: right; white-space: nowrap; }
.bl-money b { display: block; font-family: var(--font-mono); font-size: 15px; }
.bl-owed { font-size: 12px; color: var(--warn); font-weight: 600; }
.bl-paid { font-size: 12px; color: var(--ink-faint); }
.bl-acts { display: flex; gap: 7px; white-space: nowrap; }
@media (max-width: 640px) {
  .bl-row { flex-wrap: wrap; }
  .bl-who { flex: 1 1 100%; }
}

/* ── Trend chart ──
   The motion is one thing: the line writes itself left to right, the
   direction time runs, so the eye follows the shape rather than being handed
   it. Once on mount. A chart that replays on every hover is a chart somebody
   waits for, forty times a day. */
.tc { border: 1px solid var(--line); border-radius: 14px; padding: 18px;
  background: var(--surface);
  /* --k is the per-series colour, set inline on each series group. Declared
     here so it is never undefined: an undefined colour draws nothing, and a
     chart that renders blank because one prop was missing is worse than one
     that renders in the wrong colour. verify-design caught it. */
  --k: var(--accent); }
.tc-title { font-size: 13px; font-weight: 600; color: var(--ink-faint);
  text-transform: uppercase; letter-spacing: .07em; margin-bottom: 12px; }
.tc-empty { border: 1px solid var(--line); border-radius: 14px; padding: 30px;
  text-align: center; color: var(--ink-faint); font-size: 13px; }

/* The legend IS the reading. Toggle and current value in one control. */
.tc-keys { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 14px; }
.tc-key { text-align: left; min-height: 44px; padding: 8px 15px; border-radius: 11px;
  border: 1px solid var(--line); background: var(--surface); cursor: pointer;
  font: inherit; opacity: .45; transition: opacity .18s ease, border-color .18s ease; }
.tc-key.is-on { opacity: 1; border-color: var(--k); border-left: 3px solid var(--k); }
.tc-key-label { display: block; font-size: 11px; text-transform: uppercase;
  letter-spacing: .06em; color: var(--ink-faint); }
.tc-key-value { display: block; font-family: var(--font-display); font-size: 19px;
  margin-top: 2px; color: var(--k); }

.tc-svg { width: 100%; height: auto; display: block; overflow: visible; }
.tc-grid { stroke: var(--line); stroke-width: 1; }
.tc-ylab, .tc-xlab { font-size: 11px; fill: var(--ink-faint); }
.tc-ylab { text-anchor: end; }

/* Dashed, because a target is not a measurement. */
.tc-target { stroke: var(--ink-faint); stroke-width: 1.5; stroke-dasharray: 5 4; }
.tc-target-lab { font-size: 11px; fill: var(--ink-faint); }

.tc-line { fill: none; stroke: var(--k); stroke-width: 2.5; stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 2400; stroke-dashoffset: 2400; }
.tc-line.is-in { transition: stroke-dashoffset 1.1s cubic-bezier(.22,.61,.36,1);
  stroke-dashoffset: 0; }
.tc-area { fill: var(--k); opacity: 0; }
.tc-area.is-in { transition: opacity .9s ease .25s; opacity: .09; }

.tc-cross { stroke: var(--ink-faint); stroke-width: 1; stroke-dasharray: 3 3; }
.tc-dot { fill: var(--surface); stroke: var(--k); stroke-width: 2.5; }
.tc-foot { margin-top: 10px; font-size: 13px; color: var(--ink-soft); min-height: 19px; }

@media (prefers-reduced-motion: reduce) {
  .tc-line, .tc-line.is-in { stroke-dashoffset: 0; transition: none; }
  .tc-area, .tc-area.is-in { opacity: .09; transition: none; }
  .tc-key { transition: none; }
}

/* ── Reordering blocks ──
   The grip is the handle. Making the whole card draggable meant selecting a
   title started a drag, so editing text fought the card. */
.ps-grip { cursor: grab; padding: 2px 6px; border-radius: 6px;
  color: var(--ink-faint); user-select: none; }
.ps-grip:active { cursor: grabbing; background: var(--surface-raised); }
.ps-dragging { opacity: .45; }
/* Where it will land. Dragging with no target shown is guesswork. */
.ps-over { box-shadow: 0 -3px 0 var(--accent); }

/* ── Doctors waiting to be verified ── */
.vet-row { display: flex; align-items: flex-start; gap: 13px; padding: 13px 15px;
  border: 1px solid var(--line); border-radius: 12px; margin-bottom: 9px; }
.vet-critical { border-left: 3px solid var(--critical); }
.vet-warn { border-left: 3px solid var(--warn); }
.vet-main { flex: 1; min-width: 0; }
.vet-meta { display: block; font-size: 13px; color: var(--ink-soft); margin-top: 2px; }
/* Each reason on its own line. Joined into a sentence they stop being read. */
.vet-signal { display: block; font-size: 13px; color: var(--ink-mid); margin-top: 4px; }
.vet-signal::before { content: '· '; color: var(--ink-faint); }
.vet-band { font-size: 12px; color: var(--ink-faint); white-space: nowrap; }

/* ── A run of links inside a group ──
   Seventeen undifferentiated links is a wall; people stop reading at about
   seven. Quieter than the group heading above it, so the hierarchy reads
   top-down rather than competing. */
.nav-sub { font-size: 11px; text-transform: uppercase; letter-spacing: .1em;
  font-weight: 600; color: var(--ink-faint); margin: 14px 0 4px 10px; }
.nav-group > div:first-child .nav-sub { margin-top: 4px; }

/* ── When the money arrives ──
   A grid, not a scatter plot: seven rows of opening hours is a table, and a
   table is legible at a glance. One hue at varying opacity rather than a
   colour ramp — readable without colour vision, and the system has one
   accent rather than a scale. */
.hm { display: grid; gap: 2px; margin-top: 10px; }
.hm-hr { font-size: 11px; color: var(--ink-faint); text-align: center; }
.hm-day { font-size: 12px; color: var(--ink-soft); line-height: 20px; }
.hm-cell { height: 20px; border-radius: 4px; background: var(--accent);
  border: 1px solid var(--line); }

/* ── This period against the last ── */
.cmp-row { display: flex; align-items: baseline; gap: 11px; padding: 9px 0;
  border-bottom: 1px solid var(--line); }
.cmp-row:last-child { border-bottom: 0; }
.cmp-label { min-width: 106px; font-size: 13px; color: var(--ink-soft); }
.cmp-now { font-family: var(--font-display); font-size: 17px; }
.cmp-then { font-size: 13px; color: var(--ink-faint); }
.cmp-pct { margin-left: auto; font-size: 13px; font-weight: 600; }

/* ── The canvas ──
   A faithful preview, not the public page. Sticky so it stays beside the
   list while somebody scrolls a long set of sections. */
.ps-split { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr);
  gap: 22px; align-items: start; }
.pv-wrap { position: sticky; top: 16px; }
.pv-bar { display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
.pv-widths { display: flex; gap: 6px; }
.pv-canvas { border: 1px solid var(--line); border-radius: 13px;
  background: var(--surface); padding: 22px; max-height: 74vh; overflow-y: auto; }
.pv-canvas.pv-phone { max-width: 390px; margin: 0 auto; padding: 17px; }
.pv-sec { padding: 13px 0; border-bottom: 1px solid var(--line); }
.pv-sec:last-child { border-bottom: 0; }
.pv-sec.pv-hidden { opacity: .42; }
.pv-tag { font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-faint); }
.pv-h { font-family: var(--font-display); font-size: 17px; margin: 0 0 7px; }
.pv-p { margin: 0; line-height: 1.65; font-size: 15px; }
.pv-empty { color: var(--ink-faint); font-style: italic; }
.pv-quote { margin: 0; padding-left: 13px; border-left: 3px solid var(--line);
  font-size: 15px; line-height: 1.65; }
.pv-cite { display: block; margin-top: 6px; font-size: 13px; color: var(--ink-faint);
  font-style: normal; }
.pv-callout { padding: 11px 13px; border-radius: 9px; font-size: 15px; line-height: 1.6;
  background: var(--surface-raised); }
.pv-callout.pv-warn { background: var(--warn-bg); }
/* --ok-bg. My first two guesses — --good-bg then --good-tint — were both
   undefined, and both had a fallback that would have hidden the mistake.
   verify-design catches an undefined token precisely because it draws
   nothing rather than erroring. */
.pv-callout.pv-good { background: var(--ok-bg); }
.pv-list { margin: 0; padding-left: 20px; line-height: 1.8; font-size: 15px; }
.pv-qa { padding: 7px 0; font-size: 15px; }
.pv-a { color: var(--ink-mid); line-height: 1.6; margin-top: 3px; }
.pv-dl { margin: 0; }
.pv-dl-row { display: flex; gap: 11px; padding: 5px 0; font-size: 15px; }
.pv-dl-row dt { min-width: 145px; color: var(--ink-faint); }
.pv-dl-row dd { margin: 0; }
.pv-stats { display: flex; flex-wrap: wrap; gap: 22px; }
.pv-stat b { display: block; font-family: var(--font-display); font-size: 22px; }
.pv-stat span { font-size: 13px; color: var(--ink-faint); }
.pv-stat em { display: block; font-size: 12px; color: var(--ink-faint); font-style: normal; }
.pv-rows { display: flex; flex-direction: column; }
.pv-row { display: flex; justify-content: space-between; gap: 13px; padding: 6px 0;
  border-bottom: 1px solid var(--line); font-size: 15px; }
.pv-row:last-child { border-bottom: 0; }
.pv-note { color: var(--ink-faint); font-style: normal; font-size: 13px; }
.pv-foot { margin: 9px 0 0; font-size: 13px; color: var(--ink-faint); }
.pv-steps { margin: 0; padding-left: 20px; line-height: 1.65; font-size: 15px; }
@media (max-width: 980px) {
  .ps-split { grid-template-columns: 1fr; }
  .pv-wrap { position: static; }
}

/* ── Corporate spend chart ──
   Bars, not a line: discrete months, and a line between them would imply a
   rate of change that does not exist. */
.cbar { margin-top: 18px; }
.cbar-head { display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin-bottom: 9px; }
.cbar-plot { display: flex; align-items: flex-end; gap: 5px; height: 132px;
  padding: 0 2px; border-bottom: 1px solid var(--line); }
.cbar-col { flex: 1; display: flex; flex-direction: column; justify-content: flex-end;
  align-items: center; height: 100%; position: relative; }
.cbar-fill { width: 100%; max-width: 34px; border-radius: 4px 4px 0 0;
  background: var(--accent); min-height: 2px; }
.cbar-x { position: absolute; bottom: -19px; font-size: 11px; color: var(--ink-faint); }
.cbar { padding-bottom: 22px; }

/* ── Who are you ──
   A mark to recognise, then a title, then one line. Somebody here has not
   decided anything yet and is scanning to find themselves. */
.who-icon { width: 26px; height: 26px; display: block; margin-bottom: 10px;
  fill: var(--accent); }

/* ── A long exam that opens short ──
   <details> rather than a state toggle: keyboard and screen reader behaviour
   for free, and it prints expanded — these notes get printed. */
.ex-group > summary { cursor: pointer; list-style: none; display: flex;
  align-items: center; justify-content: space-between; gap: 9px; }
.ex-group > summary::-webkit-details-marker { display: none; }
.ex-group > summary::after { content: '▾'; color: var(--ink-faint); font-size: 13px;
  transition: transform .12s; }
.ex-group[open] > summary::after { transform: rotate(180deg); }
.ex-count { font-size: 11px; color: var(--ink-faint); font-weight: 400; }
@media print { .ex-group > summary::after { display: none; } }

/* ── Badges ──
   Unearned ones are dimmed, not hidden: a locked badge that states its rule
   is a target, and hiding it makes the list look complete when it is not. */
.bdg { display: flex; gap: 11px; padding: 9px 0; border-bottom: 1px solid var(--line);
  align-items: flex-start; }
.bdg:last-child { border-bottom: 0; }
.bdg:not(.is-on) { opacity: .55; }
.bdg-mark { width: 20px; text-align: center; color: var(--ink-faint); flex: none;
  font-size: 15px; }
.bdg.is-on .bdg-mark { color: var(--ok); }
.bdg-detail { color: var(--ink-faint); font-size: 13px; }
.bdg-tier { font-family: var(--font-display); font-size: 19px; display: block; }

/* ── The appointment filter row ──
   Only rendered for a clinic big enough to need it, so it never has to
   justify its space on a two-doctor screen. Wraps, because a hospital with
   twenty doctors would otherwise push the calendar off a phone. */
.cal-filters { display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
  padding: 12px 0 4px; border-bottom: 1px solid var(--line); margin-bottom: 10px; }
/* min-width 170 pushed a 390px phone 25px past the viewport once the select
   sat beside anything. Measured. Full width below 640, where there is no
   room to put two controls side by side anyway. */
.cal-filters .inp { width: auto; min-width: 170px; max-width: 100%; }
@media (max-width: 640px) {
  .cal-filters .inp { flex: 1 1 100%; min-width: 0; }
}
.cal-filters .chip-row { flex: 1 1 100%; }

/* ── The registration warning ──
   Amber, not red: this is a consequence to understand before typing, not an
   error somebody has already made. Beside the field it applies to, because a
   warning three pages away is one nobody reads. */
.ob-warn { border-left: 3px solid var(--warn); background: var(--surface-raised);
  padding: 12px 14px; border-radius: 8px; margin: 14px 0 10px; font-size: 13px;
  line-height: 1.6; }
.ob-warn p { margin: 0 0 6px; }
.ob-warn p:last-child { margin-bottom: 0; }
.ob-agree { display: flex; gap: 10px; align-items: flex-start; font-size: 13px;
  line-height: 1.55; margin: 4px 0 12px; cursor: pointer; }
.ob-agree input { margin-top: 3px; width: 18px; height: 18px; flex: none; }

/* ── THE WAY OUT OF ONBOARDING ──
   Quiet by design. It has to be findable by somebody who wants to stop, and
   must not compete with the button that finishes the step — a prominent
   "sign out" next to "Continue" is one somebody presses by accident on a
   phone, and they lose the session rather than the step. */
.ob-exit {
  display: block; margin: 22px auto 8px;
  background: none; border: 0; padding: 6px 10px;
  font: inherit; font-size: 13px;
  color: var(--ink-faint); cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.ob-exit:hover { color: var(--ink-soft); }
.ob-exit:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; border-radius: 4px; }

/* Confirmation sits inline rather than in a modal: a dialog over a form is
   how somebody loses their place, and the sentence is the whole point —
   people do not know their answers are already saved. */
.ob-exit-ask {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  justify-content: center; text-align: center;
  margin: 22px auto 8px; padding: 12px 14px;
  max-width: 460px;
  border: 1px solid var(--line); border-radius: 10px;
  font-size: 13px; color: var(--ink-soft);
}
.ob-exit-ask span { flex: 1 1 100%; }

/* ══════════════════════════════════════════════════════════════════════════
   A DOCTOR'S DAY — time canvas beside a sticky patient rail

   ── WHY A CANVAS AND NOT A TABLE ──

   A table sorted by time hides the twenty minutes free at eleven and the
   fact that four o'clock is triple-booked. Both are things a doctor changes
   their behaviour over, and neither survives a list. Height is proportional
   to duration here, so an empty hour looks empty.

   ── AND WHY THE RAIL IS STICKY ──

   The allergy and the current medicines have to be in the doctor's eye at
   the moment they call somebody in — not behind a click into a record they
   will open after the consultation has already started.

   Every colour is an existing token. styles.css previously carried five
   :root blocks defining twenty tokens at conflicting values; a new screen
   inventing its own palette would put the second one back.
   ══════════════════════════════════════════════════════════════════════════ */
.dd { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 22px; align-items: start; }

.dd-canvas { min-width: 0; }
.dd-strip {
  position: relative; margin-left: 54px;
  border-left: 1px solid var(--line);
}
.dd-hour { position: absolute; left: 0; right: 0; border-top: 1px solid var(--line); }
.dd-hour-label {
  position: absolute; left: -54px; top: -8px;
  font-size: 11px; font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
}

/* Where the day actually is. Without it somebody reads the clock and then
   reads the grid. */
.dd-now { position: absolute; left: 0; right: 0; border-top: 2px solid var(--critical); }
.dd-now span {
  position: absolute; left: -46px; top: -9px;
  font-size: 11px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--critical);
}

.dd-slot {
  position: absolute; left: 8px; right: 6px;
  display: flex; flex-direction: column; justify-content: center; gap: 1px;
  padding: 5px 10px; overflow: hidden;
  text-align: left; cursor: pointer;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 7px;
  font: inherit;
  transition: border-color .12s, box-shadow .12s;
}
.dd-slot:hover { border-color: var(--line-strong); }
.dd-slot:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
/* The selected slot and the rail are the same subject; the tint says so
   without a second colour. */
.dd-slot.is-on { background: var(--accent-tint); border-color: var(--accent); }

.dd-slot-time {
  font-size: 11px; font-variant-numeric: tabular-nums; color: var(--ink-faint);
}
.dd-slot-name {
  font-size: 13px; font-weight: 600; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dd-slot-meta { font-size: 11px; color: var(--ink-faint); }

.dd-rail { min-width: 0; }
.dd-rail-inner { position: sticky; top: 16px; display: grid; gap: 12px; }
.dd-rail-head {
  font-size: 11px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-faint); margin-bottom: 6px;
}
.dd-rail-row {
  display: flex; justify-content: space-between; gap: 10px;
  padding: 3px 0; font-size: 13px; line-height: 1.4;
}
.dd-rail-actions { display: flex; gap: 8px; }
.dd-counts { display: flex; gap: 14px; flex-wrap: wrap; font-size: 13px; color: var(--ink-soft); }

/* Below a laptop the rail stops being a rail: a sticky column on a phone
   covers the thing it is meant to annotate. */
@media (max-width: 900px) {
  .dd { grid-template-columns: 1fr; }
  .dd-rail-inner { position: static; }
}

/* ══════════════════════════════════════════════════════════════════════════
   THE DENTAL CHART

   ── THE ORIENTATION IS THE WHOLE THING ──

   A dentist reads the chart as if looking at the patient, so the upper-right
   quadrant sits on the viewer's LEFT. The layout comes out of the service in
   drawing order and is rendered in that order; nothing here reverses with
   flex-direction or row-reverse, because that is exactly how a mouth gets
   mirrored without anybody noticing.

   ── AND COLOUR IS NEVER ALONE ──

   Each tooth carries a mark as well as a tint. A chart that says "caries" in
   red only is a chart a colour-blind dentist reads as "nothing here".
   ══════════════════════════════════════════════════════════════════════════ */
.odo { display: grid; gap: 6px; padding: 4px 0; }
.odo-row { display: flex; align-items: center; justify-content: center; gap: 0; }
.odo-quad { display: flex; gap: 3px; }
/* The midline. A chart without it makes 11 and 21 look like one run. */
.odo-mid { width: 1px; align-self: stretch; background: var(--line-strong); margin: 0 8px; }
.odo-line { height: 1px; background: var(--line-strong); margin: 2px 0; }

.odo-tooth {
  width: 34px; height: 44px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px; padding: 0;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: 5px;
  font: inherit; cursor: pointer;
  transition: border-color .12s, transform .08s;
}
.odo-tooth:hover { border-color: var(--line-strong); }
.odo-tooth:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
.odo-tooth.is-on { border-color: var(--primary); border-width: 2px; }

.odo-num { font-size: 11px; font-variant-numeric: tabular-nums; color: var(--ink-soft); }
.odo-mark { font-size: 13px; font-weight: 700; line-height: 1; min-height: 13px; }

.odo-key { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; margin-top: 12px; font-size: 12px; color: var(--ink-soft); }
.odo-key i { display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-right: 5px; vertical-align: middle; }

/* On a phone a full arch does not fit. Scrolled rather than wrapped —
   wrapping a quadrant onto two lines breaks the anatomy the chart is. */
@media (max-width: 720px) {
  .odo-row { justify-content: flex-start; overflow-x: auto; }
  .odo-tooth { width: 30px; height: 40px; flex: 0 0 auto; }
}

/* ── COMPARING PLANS ──
   Columns of equal width so the eye reads down a tier rather than across a
   row; the current plan is marked by border rather than fill, because a
   filled column reads as the recommended one and the recommendation belongs
   to the customer. */
.cmp-heads { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
.cmp-head {
  padding: 12px; border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface);
}
.cmp-head.is-on { border-color: var(--primary); border-width: 2px; padding: 11px; }
.cmp-price { font-size: 19px; font-weight: 700; margin: 4px 0 2px; }

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

/* ══════════════════════════════════════════════════════════════════════════
   TOASTS

   Bottom-left, not bottom-right: the right side is where a phone's thumb
   sits and where most floating action buttons live, and a toast that covers
   the button somebody is reaching for is worse than no toast.

   Fixed max-width rather than full-bleed, so a long error does not become a
   wall across a 27-inch reception monitor.
   ══════════════════════════════════════════════════════════════════════════ */
.toast-wrap {
  position: fixed; left: 18px; bottom: 18px; z-index: 3000;
  display: flex; flex-direction: column-reverse; gap: 8px;
  max-width: min(420px, calc(100vw - 36px));
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 12px 11px 14px;
  border-radius: var(--radius-sm, 8px);
  border: 1px solid var(--line-strong);
  background: var(--paper);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .13);  /* shadow, not a colour token */
  font-size: 15px; line-height: 1.5; color: var(--ink);
  animation: toast-in .16s ease-out;
}
@keyframes toast-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* Colour is carried on a left bar, never on the background: coloured
   backgrounds behind body text fail contrast at the edges of a theme, and
   this has to stay legible in both. */
.toast-ok    { border-left: 3px solid var(--ok); }
.toast-error { border-left: 3px solid var(--danger); }
.toast-info  { border-left: 3px solid var(--ink-mid); }

.toast-msg { flex: 1; }
.toast-action {
  flex: none; border: 0; background: none; padding: 0;
  font: inherit; font-weight: 600; color: var(--accent);
  cursor: pointer; text-decoration: underline;
}
.toast-x {
  flex: none; border: 0; background: none; cursor: pointer;
  font-size: 17px; line-height: 1; padding: 0 2px;
  color: var(--ink-faint);
}
.toast-x:hover { color: var(--ink); }

@media (max-width: 560px) {
  .toast-wrap { left: 10px; right: 10px; bottom: 10px; max-width: none; }
}

/* ── "Saved 40 seconds ago" ── */
.saved-at { font-size: 13px; color: var(--ink-faint); }
.saved-err { color: var(--danger); }

/* ── NOT OPEN HERE YET ─────────────────────────────────────────────────────
   Deliberately not the error palette. A country capability refusal is an
   accurate answer, not a fault, and red would tell somebody their software
   is broken when it is working exactly as intended. */
.nhy {
  border: 1px solid var(--line-strong);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: 20px 22px;
  background: var(--paper);
  max-width: 62ch;
}
.nhy-head h3 { margin: 0 0 2px; font-size: 17px; }
.nhy-regime {
  margin: 0 0 16px; font-family: var(--font-mono);
  font-size: 12px; color: var(--ink-faint); text-transform: uppercase;
  letter-spacing: .06em;
}
.nhy-label {
  margin: 0 0 6px; font-size: 12px; font-weight: 600;
  color: var(--ink-faint); text-transform: uppercase; letter-spacing: .05em;
}
.nhy-works { margin-bottom: 18px; }
.nhy-works ul { margin: 0; padding-left: 18px; }
.nhy-works li { margin-bottom: 4px; line-height: 1.55; }
.nhy-needs { padding-top: 14px; border-top: 1px solid var(--line-soft); }
.nhy-needs p:last-child { margin: 0; line-height: 1.6; }
.nhy-foot {
  margin: 18px 0 0; padding-top: 14px;
  border-top: 1px solid var(--line-soft);
  font-size: 13px; color: var(--ink-faint); line-height: 1.6;
}

/* ══════════════════════════════════════════════════════════════════════════
   ATLAS PANELS

   The rota, the runs and the budget were rendered from generic Stat and
   Table primitives, which made the screen truthful and shapeless: a run's
   status was a word, a budget was a number, and the difference between a
   healthy morning and a dead provider was something the owner had to read
   for rather than see. These give the panel its own vocabulary — status
   carries a colour, budget carries a bar, zero carries less ink than one.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── RUN STATUS ──
   Four states, four tones. 'exhausted' is amber, not red: it means the
   market may hold more and the quota resets tomorrow. 'failed' is red
   because nothing heals it except a person. */
.atlas-run-status {
  display: inline-block; padding: 2px 9px; border-radius: 20px;
  font-size: 11px; font-weight: 600; font-family: var(--font-body);
  text-transform: lowercase; letter-spacing: 0.01em;
}
.atlas-run-status.is-ok        { background: var(--normal-tint);   color: var(--normal-ink); }
.atlas-run-status.is-exhausted { background: var(--minor-tint);    color: var(--minor-ink); }
.atlas-run-status.is-failed    { background: var(--critical-tint); color: var(--critical-ink); }
.atlas-run-status.is-no_provider { background: var(--n-100); color: var(--ink-soft); }

/* ── HEALTH BANNER ──
   When the most recent run failed, the fact goes at the top of the panel in
   the fault's own words — not at the bottom of a table the owner has to
   scroll to. A rota that died three days ago and a screen that opens on
   "Nothing found yet" is how a fault survives a week. */
.atlas-health {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 12px 14px; border-radius: var(--radius);
  font-size: 13px; line-height: 1.55; margin-bottom: 14px;
}
.atlas-health.is-failed {
  background: var(--critical-tint); color: var(--critical-ink);
  border: 1px solid color-mix(in srgb, var(--critical-ink) 22%, transparent);
}
.atlas-health.is-exhausted {
  background: var(--minor-tint); color: var(--minor-ink);
  border: 1px solid color-mix(in srgb, var(--minor-ink) 22%, transparent);
}
.atlas-health b { font-weight: 600; }

/* ── BUDGET METER ──
   A number ("80 usable") answers how much; a bar answers how the day is
   going. Fill runs left to right as the quota is SPENT, so a full bar means
   a spent day — the mental model of a fuel gauge in reverse, chosen because
   the interesting event is exhaustion, and an emptying bar hides it. */
.atlas-budget { display: flex; gap: 12px; flex-wrap: wrap; }
.atlas-budget-item {
  flex: 1 1 200px; min-width: 180px;
  padding: 12px 14px; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--surface);
}
.atlas-budget-head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 8px;
}
.atlas-budget-name {
  font-size: 12px; font-weight: 600; color: var(--ink);
  text-transform: capitalize;
}
.atlas-budget-nums {
  font-family: var(--font-mono); font-size: 12px; color: var(--ink-soft);
}
.atlas-budget-track {
  height: 6px; border-radius: 4px; background: var(--n-100);
  overflow: hidden;
}
.atlas-budget-fill {
  height: 100%; border-radius: 4px; background: var(--teal);
  transition: width 0.25s ease;
}
.atlas-budget-item.is-spent .atlas-budget-fill { background: var(--minor); }
.atlas-budget-sub {
  margin-top: 7px; font-size: 12px; color: var(--ink-soft); line-height: 1.5;
}

/* ── TOOLBARS AND ROW ACTIONS ──
   Actions sit in a row and take the width their label needs. The primary
   action is first and filled; everything else is quiet. */
.atlas-toolbar {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.atlas-toolbar .hint { flex-basis: 100%; margin: 4px 0 0; }
.atlas-row-actions {
  display: flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap;
}
.atlas-row-actions .btn { font-size: 12px; padding: 5px 11px; }
.atlas-row-actions .btn.is-quiet {
  border-color: transparent; color: var(--ink-soft);
}
.atlas-row-actions .btn.is-quiet:hover {
  border-color: var(--line-strong); color: var(--ink);
}

/* ── FILTER ROW ──
   Two selects that each filled the card width read as two form fields.
   Labelled and inline, they read as what they are: a filter. */
.atlas-filters {
  display: flex; gap: 14px; align-items: center; flex-wrap: wrap;
}
.atlas-filters label {
  display: flex; gap: 7px; align-items: center;
  font-size: 12px; color: var(--ink-soft);
}
.atlas-filters select {
  width: auto; padding: 6px 28px 6px 10px; font-size: 13px;
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--surface); color: var(--ink); font-family: var(--font-body);
}

/* ── QUIET ZEROS ──
   In a run table most cells are 0 on a healthy quiet day. Zero at full ink
   weight looks like data; muted, it reads as the absence it is, and the one
   row with a 7 in it is the row the eye lands on. */
.atlas-zero { color: var(--ink-faint); }

/* ── SCORE ──
   The attack score, banded. The bands match scoring.js: 70 is where the
   research budget doubles, 40 is where it stops being a maybe. */
.atlas-score {
  display: inline-block; min-width: 34px; text-align: center;
  padding: 2px 8px; border-radius: 6px;
  font-family: var(--font-mono); font-size: 12px; font-weight: 600;
}
.atlas-score.is-hot  { background: var(--teal-tint); color: var(--teal-strong); }
.atlas-score.is-warm { background: var(--minor-tint); color: var(--minor-ink); }
.atlas-score.is-cold { background: var(--n-100); color: var(--ink-soft); }

/* ── PAYER CHIPS ──
   CGHS / ECHS / PMJAY / NABH on the account row. Small caps in the mono
   face, because a scheme code is an identifier, not a word — and quiet,
   because the chip is context for the score beside it, not a second score. */
.atlas-chip {
  display: inline-block; padding: 1px 7px; margin-right: 4px;
  border: 1px solid var(--line-strong); border-radius: 5px;
  font-family: var(--font-mono); font-size: 11px; font-weight: 600;
  letter-spacing: 0.04em; color: var(--ink-mid); background: var(--surface);
  vertical-align: 1px;
}
.atlas-chip.is-nabh { border-color: var(--teal); color: var(--teal-strong); }

/* ── DICTATION ON A CLINICAL NOTE ──
   Sits above the SOAP fields because a doctor speaks a consultation in one
   go. A mic inside Subjective would mean dictating four times, or everything
   landing in the wrong box.

   Tokens checked against the ones this stylesheet actually defines. I wrote
   --surface-2 and --muted from habit; neither exists here, and an undefined
   custom property does not error — the rule is simply dropped, so the block
   renders unstyled and nothing anywhere says why. */
.cn-dictate { display:flex; align-items:center; gap:12px; margin:0 0 14px;
  padding:10px 12px; border:1px solid var(--line); border-radius:8px;
  background:var(--surface); }
.cn-dictate-hint { font-size:.8rem; color:var(--ink-mid); line-height:1.45; max-width:44ch; }

/* Collapsed by default: the transcript matters when a line looks wrong, not
   on every consultation. */
.cn-transcript { margin:0 0 14px; font-size:.82rem; }
.cn-transcript summary { cursor:pointer; color:var(--ink-mid); }
.cn-transcript p { margin:8px 0 0; color:var(--ink-mid); line-height:1.55; }
.cn-warn { color:var(--warn); }
