/* Roan application layer.
   ─────────────────────────────────────────────────────────────────────────
   Sits on top of modernist.css, which owns type, colour ramps, buttons, inputs
   and tables. This file adds only what the product needs beyond the design
   system: the four semantic states, the layout metrics, and the components that
   are specific to running a veterinary practice — presence, offline, the diary
   grid, the SOAP note stack and the command line.

   Rules from docs/design/DESIGN_RULES.md that this file exists to enforce:
     · a small radius (2–6px) on controls, none on rows and regions
     · the coat is the frame — header, rail, footer — and nothing else
     · 2px rules between regions, 1px between rows — softened, never dropped
     · exactly four semantic states, never colour alone
     · 34px per 15 minutes in the diary
     · 36px minimum hit target, nothing below 12px type

   The class vocabulary is documented in docs/design/COMPONENTS.md. A screen
   uses what is here; it does not add a rule of its own.
   ───────────────────────────────────────────────────────────────────────── */

:root {
  /* The four states on a cool sheet: the act-now red is a brick rather
     than a signal red, the attention amber is an ochre, the settled green
     is a clean bottle green with no mulberry in it so it never reads as
     the brand, and the information blue is a slate a step lighter than
     the coat so it never reads as chrome. Ink is for text and icons; fill
     tints rows and chips and is never used for text. Measured, ink on its
     own fill: act 5.40, attention 5.80, settled 5.32, info 5.68; ink on
     --color-bg: 6.32, 6.47, 6.15, 6.70; on --color-surface: 5.78, 5.92,
     5.63, 6.13. Adding a fifth state is a design error — DESIGN_RULES.md §2. */
  --state-act-ink:       #9f2f20;
  --state-act-fill:      #f8ded7;
  --state-attention-ink: #7d5200;
  --state-attention-fill:#faebcf;
  --state-settled-ink:   #1c6b45;
  --state-settled-fill:  #d8eedf;
  --state-info-ink:      #2a5b8c;
  --state-info-fill:     #dce8f4;

  /* The one pure white in the product: the field being typed into, on a
     near-white ground — DESIGN_RULES.md §3. The sheet is a shade off
     white so the one field that is white reads as the lit one. Text on
     it 17.10:1; the accent on it 8.81:1. */
  --color-surface-editing: #ffffff;

  /* Four sizes that sit off the type scale in modernist.css, each because the
     product asks for something the system's ramp does not carry. They are
     declared rather than written into the rules so the exceptions can be
     counted; a fifth needs a reason of the same kind. */
  --text-clinical: 14.5px;  /* clinical prose — §4 sets this at 13.5–15px */
  --text-dense:    12.5px;  /* a diary appointment: one line inside 34px */
  --text-figure:     22px;  /* a headline number */
  --text-name:       28px;  /* a patient's name, the largest type on a screen */

  /* Layout metrics, from the handoff. Named so a screen cannot quietly drift. */
  --workspace-width: 248px;
  --workspace-compact: 64px;
  --workspace-surface: color-mix(in srgb, var(--color-bg) 60%, var(--color-surface));
  --workspace-selected: color-mix(in srgb, var(--color-text) 8%, var(--workspace-surface));
  --workspace-search-width: 560px;
  --rail-side-min: 284px;   /* narrow side rail (history column) */
  --rail-side:     296px;   /* standard side rail (diary right rail, record) */
  --rail-side-max: 360px;   /* wide side rail (stock, group ops) */
  --gutter-time:    52px;   /* diary time gutter */
  --slot-15:        34px;   /* one 15-minute module */
  --slot-hour:      68px;   /* hour label block */
  --hit-touch:      44px;   /* handheld controls, without increasing desktop density */
  --hit-min:        36px;   /* minimum interactive height */
  --shell-gutter:   24px;   /* one alignment for page headings and work regions */
  --footer-offset: calc(52px + var(--inset-bottom));
  --chrome-height:  52px;   /* the header, for a screen that fills the rest */
  --rule-region: 2px solid var(--color-divider-strong);
  --rule-row:    1px solid var(--color-divider);

  /* Breakpoints. Two, and only two, in the whole product: a screen is either
     wide enough for the rails or it is a phone, and a phone is either upright
     or on its side. Every media query in this file quotes one of these two
     numbers — CSS cannot yet interpolate a custom property into a media
     query, so the numbers are written out and these declarations are what
     they must match. tests/test_responsive_shell.py holds them to it. */
  --bp-wide-header:  1200px;  /* below this the compact header omits the redundant area trail */
  --bp-handheld:      680px;  /* narrower than this: one column, no rails */
  --bp-short-height:  480px;  /* shorter than this: nothing sticks */
  --bp-header-wrap:   950px;  /* narrower than this the header takes two rows,
                                 so nothing may hang from --chrome-height */

  /* The device's own edges. Installed to a home screen with
     viewport-fit=cover, the page runs under the notch and the home
     indicator; these are what the browser reports is covered, and 0 in a
     tab. The coat carries them: the header adds the top inset, the footer
     and the sticky action bar the bottom, the rail and both bars the sides
     when a phone is on its side. */
  --inset-top:    env(safe-area-inset-top, 0px);
  --inset-right:  env(safe-area-inset-right, 0px);
  --inset-bottom: env(safe-area-inset-bottom, 0px);
  --inset-left:   env(safe-area-inset-left, 0px);
}

/* The hidden attribute wins over any display a class sets. The browser's own
   [hidden] rule is weaker than a class, so a `.btn` marked hidden — the
   install button, the offline bar's sync button — was still drawn. */
[hidden] { display: none !important; }

/* ── Type roles ──────────────────────────────────────────────────────────
   12px is metadata only; clinical prose is 13.5-15px. */
.t-meta { font-size: var(--text-xs); }
.t-small { font-size: var(--text-sm); }
.t-label { font-size: var(--text-2xs);     letter-spacing: .08em; text-transform: uppercase;
            color: var(--color-muted); font-weight: var(--font-medium-weight); }
.t-body { font-size: var(--text-md); }
.t-clin { font-size: var(--text-clinical); line-height: 1.6; }
.t-strong { font-weight: var(--font-strong-weight); }
.t-name { font-size: var(--text-name);    font-family: var(--font-heading); font-weight: var(--font-heading-weight);
            letter-spacing: -.015em; line-height: 1.05; }
/* A headline figure: mono and tabular, so a column of them lines up. */
.t-num { font-size: var(--text-figure);  font-family: var(--font-mono); font-weight: var(--font-strong-weight);
            font-variant-numeric: tabular-nums; letter-spacing: -.02em; line-height: 1.1; }
/* Mono for a figure inside prose-sized text: a code, a batch, a time. */
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.roan-wordmark {
  --roan-word-size: 22px;
  --roan-word-color: currentColor;
  --roan-square-color: var(--color-accent);
  display: inline-flex;
  align-items: baseline;
  gap: calc(var(--roan-word-size) * .1);
  min-width: 0;
  color: var(--roan-word-color);
  line-height: 1;
  text-decoration: none;
}
.roan-wordmark__text {
  font-family: Archivo, "Arial Black", var(--font-heading);
  font-size: var(--roan-word-size);
  font-weight: 800;
  letter-spacing: -.055em;
  line-height: .72;
}
.roan-wordmark__period {
  width: calc(var(--roan-word-size) * .12);
  height: calc(var(--roan-word-size) * .12);
  flex: 0 0 auto;
  background: var(--roan-square-color);
  transform: translateY(-.01em);
}
/* Prose that keeps its own line breaks: a history summary, a note version,
   a rationale typed with paragraphs. Wraps; never scrolls. */
.t-prewrap { white-space: pre-wrap; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden;
            clip: rect(0 0 0 0); white-space: nowrap; }

/* ── State on the system's controls ──────────────────────────────────────
   The one dangerous button, and the field that is wrong. Both are states,
   so they are declared here rather than in the system sheet. */
.btn-danger { color: var(--state-act-ink); border-color: var(--state-act-ink); background: var(--color-bg); }
.btn-danger:hover { background: var(--state-act-fill); }
.btn-danger:active { background: color-mix(in srgb, var(--state-act-ink) 22%, transparent); }
.field__error { color: var(--state-act-ink); }
.input[aria-invalid="true"], .field[data-invalid="true"] .input { border-color: var(--state-act-ink); }
.field[data-invalid="true"] > label { color: var(--state-act-ink); }
/* The field being typed into is the only white surface on the screen and
   carries the accent bar: where you are is the brand, not a state. The
   next one to fill is dashed. */
.input:focus-visible, .field[data-status="editing"] .input {
  background: var(--color-surface-editing);
}
.field[data-status="editing"] .input { border-color: var(--color-accent); box-shadow: inset 3px 0 0 var(--color-accent); }
.field[data-status="editing"] > label { color: var(--color-accent); }
.field[data-status="next"] .input { border-style: dashed; }

/* ── State chips ─────────────────────────────────────────────────────────
   Every chip carries a word. The data-state attribute only tints it. */

.chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px var(--space-2); font-size: var(--text-xs); font-weight: var(--font-medium-weight);
  white-space: nowrap;              /* labels must not wrap — §5 */
  line-height: 1.35; border-radius: var(--radius-sm);
  background: var(--color-neutral-200); color: var(--color-neutral-900);
  text-decoration: none;
}
.chip svg { width: 13px; height: 13px; flex: none; }
.chip--outline { background: transparent; box-shadow: inset 0 0 0 1px currentColor; color: var(--color-muted); }
/* A chip that is a filter: pressed means chosen. Not a state — a chosen
   filter is not urgent — so it takes the accent wash, never a state fill. */
a.chip, button.chip { cursor: pointer; min-height: 26px; }
.chip[aria-pressed="true"] {
  background: var(--wash-accent); color: var(--color-accent);
  box-shadow: inset 0 0 0 1px var(--color-accent);
}
a.chip:hover, button.chip:hover { box-shadow: inset 0 0 0 1px var(--color-divider-strong); }
.chip[data-state="act"] { background: var(--state-act-fill);       color: var(--state-act-ink); }
.chip[data-state="attention"] { background: var(--state-attention-fill); color: var(--state-attention-ink); }
.chip[data-state="settled"] { background: var(--state-settled-fill);   color: var(--state-settled-ink); }
.chip[data-state="info"] { background: var(--state-info-fill);      color: var(--state-info-ink); }

tr[data-state="act"]       > td { background: var(--state-act-fill); }
tr[data-state="attention"] > td { background: var(--state-attention-fill); }
tr[data-state="settled"]   > td { background: var(--state-settled-fill); }
tr[data-state="info"]      > td { background: var(--state-info-fill); }
/* Today's row on a record is not urgent; it is where you are. Accent wash. */
tr[data-today="true"]      > td { background: var(--wash-accent); }
/* A chip sitting on the fill of its own state would vanish into it. */
tr[data-state] .chip[data-state], [data-state] > .chip[data-state] { box-shadow: inset 0 0 0 1px currentColor; }

/* A list of things needing attention: count, what, state. A list rather
   than a table, because on a phone the three parts wrap instead of
   scrolling and the count stays beside the state. */
.attention-list { margin: 0; padding: 0; list-style: none; }
.attention-row {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-2) var(--space-3-5); border-bottom: var(--rule-row);
}
.attention-row[data-state="act"] { background: var(--state-act-fill); }
.attention-row[data-state="attention"] { background: var(--state-attention-fill); }
.attention-row__count { flex: 0 0 2.5rem; }
.attention-row__count[data-empty="true"] { color: var(--color-muted-softer); }
.attention-row__main { flex: 1 1 200px; min-width: 0; }
.attention-row .chip { margin-left: auto; }

/* An alert banner that is read and worked around, not acknowledged. The
   title and the word share a line; the detail takes the next. */
.alert-row {
  display: flex; align-items: baseline; gap: var(--space-1) var(--space-2-5); flex-wrap: wrap;
  padding: 7px var(--space-3-5); border-bottom: var(--rule-row);
  background: var(--color-surface);
}
.alert-row[data-state="act"] { background: var(--state-act-fill); }
.alert-row[data-state="attention"] { background: var(--state-attention-fill); }
.alert-row[data-state="info"] { background: var(--state-info-fill); }
.alert-row__title { font-size: var(--text-md); font-weight: var(--font-strong-weight); }
.alert-row__detail { flex: 1 1 100%; margin: 0; font-size: var(--text-sm); }
.alert-row__meta { margin-left: auto; }

/* An alert that gates the screen: nothing below it renders until a named
   person says they have read it. Always act-now, always with its button. */
.alert-gate__row {
  display: flex; align-items: flex-start; gap: var(--space-3); flex-wrap: wrap;
  padding: var(--space-3) var(--space-3-5);
  border-bottom: var(--rule-region); border-left: 3px solid var(--state-act-ink);
  background: var(--state-act-fill); color: var(--state-act-ink);
}
.alert-gate__main { flex: 1 1 240px; min-width: 0; }
.alert-gate__title { font-size: var(--text-md); font-weight: var(--font-strong-weight); }
.alert-gate__row form { flex: none; }
.alert-gate__note { padding: var(--space-2) var(--space-3-5); margin: 0; }

/* ── Offline ──────────────────────────────────────────────────────────────
   The single most important piece of state in the product. Not dismissible,
   states the count, and says what will happen. "Did that save?" is the question
   that makes people stop trusting a practice system. */

.app-header {
  position: sticky; top: 0; z-index: 60;
  background: var(--color-coat);
  padding: var(--inset-top) var(--inset-right) 0 var(--inset-left);
}

.offline-bar {
  display: none; align-items: center; gap: var(--space-2-5); flex-wrap: wrap;
  min-height: var(--hit-min); padding: var(--space-1-5) var(--space-3-5);
  font-size: var(--text-sm); font-weight: var(--font-strong-weight);
  border-bottom: var(--rule-region);
  background: var(--state-attention-fill); color: var(--state-attention-ink);
}
body[data-connection="offline"] .offline-bar, body[data-connection="syncing"] .offline-bar { display: flex; }
body[data-connection="syncing"] .offline-bar {
  background: var(--state-info-fill); color: var(--state-info-ink);
}
/* A new release is installed and waiting. The bar shows so the person can
   choose the moment to reload; connection.js adds the line and the button. */
body[data-update="ready"] .offline-bar { display: flex; }
body[data-update="ready"][data-connection="online"] .offline-bar {
  background: var(--state-info-fill); color: var(--state-info-ink);
}
body[data-update="ready"][data-connection="online"] .offline-bar > [data-offline-message] { display: none; }
/* .btn sets its own display, which would beat the hidden attribute on the
   sync button the moment the bar shows while online. */
.offline-bar > [hidden] { display: none; }
.offline-bar__dot {
  width: 8px; height: 8px; flex: none; background: currentColor; border-radius: 50%;
  animation: roan-pulse 1.8s ease-in-out infinite;
}
@keyframes roan-pulse { 0%, 100% { opacity: 1 } 50% { opacity: .3 } }
@media (prefers-reduced-motion: reduce) { .offline-bar__dot { animation: none } }

/* A field whose value has not reached the server yet. Subtle, permanent until
   it syncs, and never a spinner — a spinner implies something is happening. */
[data-unsynced="true"] { box-shadow: inset 3px 0 0 var(--state-attention-ink); }

/* ── Presence ─────────────────────────────────────────────────────────────
   Ambient awareness first, blocking second. Avatars say who is here; the lock
   banner says who is holding the pen and offers a way to take it. */

.presence { display: inline-flex; align-items: center; }
.presence__avatar {
  width: 26px; height: 26px; margin-left: -6px;
  display: grid; place-items: center;
  font-size: var(--text-3xs); font-weight: var(--font-heading-weight); color: var(--color-bg);
  background: var(--color-neutral-700); border-radius: 50%;
  outline: 2px solid var(--color-bg);
}
.presence__avatar:first-child { margin-left: 0; }
.presence__avatar[data-intent="editing"] { outline-color: var(--state-info-ink); }
.presence__avatar[data-offline="true"] { opacity: .45; filter: grayscale(1); }
.presence-block__names { margin: 0; }

.lock-banner {
  display: flex; align-items: center; gap: var(--space-2-5); flex-wrap: wrap;
  min-height: var(--hit-min); padding: 7px var(--space-3-5); font-size: var(--text-sm);
  background: var(--state-info-fill); color: var(--state-info-ink);
  border-left: 3px solid var(--state-info-ink); border-bottom: var(--rule-row);
}
.lock-banner[data-severity="blocked"] {
  background: var(--state-attention-fill); color: var(--state-attention-ink);
  border-left-color: var(--state-attention-ink);
}
.lock-banner__actions { margin-left: auto; display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }

/* A section someone else holds. Read-only, visibly so, never silently. */
[data-locked="true"] :is(input, textarea, select, button:not([data-lock-action])) {
  pointer-events: none; opacity: .55;
}

/* ── Layout shells ────────────────────────────────────────────────────────
   Three navigation models: icon rail (most screens), no rail (consult, the
   sign-in), horizontal tabs (group operations). */

/* The page is a column: coat, sheet, coat. The sheet takes the spare
   height, so on a short page (sign-in, an empty listing) the footer's coat
   sits along the bottom of the window rather than a third of the way up,
   and a screen that fills its shell still fills it. */
/* 100dvh is the height the page really has once a phone's browser chrome
   has slid away; 100vh is the line before it for a browser without it. */
body { display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh; }
html { scroll-padding-bottom: var(--footer-offset); }
.roan-main { flex: 1 0 auto; display: flex; flex-direction: column; }
.roan-main > * { flex: 0 0 auto; }
.roan-main > .shell { flex: 1 0 auto; }
.shell { display: grid; min-height: calc(100vh - var(--chrome-height) * 2); min-height: calc(100dvh - var(--chrome-height) * 2); }


.shell--plain { grid-template-columns: 1fr; }












































/* The screen's top bar: title (with its context), the search, the actions,
   and one primary action. */
.topbar {
  display: flex; align-items: center; gap: var(--space-3);
  /* The bar wraps as a row of whole parts rather than squeezing any one of
     them: a title does not fold under itself, a section switcher does not
     break into two rows, and the primary action stays beside the others.
     When a long title and the switcher cannot share the line, the switcher
     and what follows it take the next one. A part wider than the whole line
     (the switcher on a phone) still shrinks and wraps inside itself. */
  flex-wrap: wrap;
  min-height: calc(var(--hit-min) + var(--space-6)); padding: var(--space-3) var(--shell-gutter);
  border-bottom: var(--rule-row); background: var(--color-bg);
}
.topbar__heading { display: flex; flex-direction: column; min-width: 0; }
.topbar__title { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: var(--text-2xl); letter-spacing: -.015em; margin: 0; }
.topbar__search { flex: 1; min-width: 0; max-width: 640px; }
.topbar__meta { font-size: var(--text-sm); color: var(--color-muted-soft); }
.topbar__actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; margin-left: auto; }
.topbar .btn { white-space: nowrap; }
.topbar .nav-context { color: inherit; text-decoration: none; }

.date-stepper { display: flex; gap: 0; }
.date-stepper > * + * { border-left: 0; }
.date-stepper > :first-child { border-radius: var(--radius-md) 0 0 var(--radius-md); }
.date-stepper > :last-child { border-radius: 0 var(--radius-md) var(--radius-md) 0; }
.date-stepper__date { border-radius: 0; cursor: default; font-variant-numeric: tabular-nums; }

/* ── The chrome ───────────────────────────────────────────────────────────
   The top bar is the coat. The customer's identity leads: monogram in the
   brand mulberry, practice name, site. Roan is the small mark in the
   account corner and the line in the footer — §7. Everything written on
   the coat is --color-coat-text or --color-coat-soft; the only colour on
   it is the monogram and the current section's underline. */
.nav {
  background: var(--color-coat); color: var(--color-coat-text);
  border-bottom: 0; padding: var(--space-2) var(--space-3-5); min-height: var(--chrome-height);
}
.nav a, .nav a:hover { color: inherit; text-decoration: none; }
.nav :focus-visible { outline-color: var(--color-coat-text); }
.nav-brand { display: flex; align-items: center; gap: var(--space-2-5); text-decoration: none; }
.nav-monogram {
  display: grid; place-items: center; width: 32px; height: 32px; flex: none;
  background: var(--color-accent); color: var(--color-coat-text);
  font-weight: var(--font-heading-weight); font-size: var(--text-sm); letter-spacing: .02em;
  border-radius: var(--radius-md);
}
/* Where you are working. On the sheet (a screen's own top bar) it is
   ruled and muted in the sheet's ink; on the coat, in the coat's. */
.nav-context {
  display: flex; flex-direction: column; justify-content: center;
  min-height: var(--hit-min); padding: var(--space-0-5) var(--space-2-5);
  border-left: var(--rule-row);
}
.nav-context__label {
  font-size: var(--text-3xs); line-height: 1.2; letter-spacing: .08em;
  text-transform: uppercase; color: var(--color-muted-soft);
}
.nav-context__value { font-weight: var(--font-strong-weight); white-space: nowrap; }
.nav .nav-context { border-left: 1px solid var(--color-coat-divider); }
.nav .nav-context__label { color: var(--color-coat-soft); }
.nav .nav-context .text-muted { color: var(--color-coat-soft); }

.nav-account { display: flex; align-items: center; gap: var(--space-2-5); margin-left: auto; }
.nav-account__who {
  display: flex; flex-direction: column; justify-content: center; line-height: 1.2;
  min-height: var(--hit-min); text-decoration: none;
  align-items: flex-end; text-align: right;
}
.nav-account__name { font-weight: var(--font-strong-weight); font-size: var(--text-md); }
.nav-account form { display: inline; }
/* The account corner folded behind the person's initials, for a phone. A
   native details: no script, a real disclosure for the reader, and the
   toggle is the mirror of the monogram at the other end of the band — a
   coat-ruled square with the person's initials where the practice's square
   holds the practice's. Not drawn at all at a desk; the handheld block
   turns it on as `display: contents`, so the toggle sits in the band as a
   flex item of its own and the body takes the next row of the coat. Open, it
   pushes the sheet down rather than covering it: nothing opens over
   anything (§9), and the band above it — with the site name — stays. */
.nav-menu { display: none; }
.nav-menu__toggle {
  display: grid; place-items: center; width: var(--hit-min); height: var(--hit-min);
  min-height: 0; padding: 0; margin-left: auto; flex: none;
  border: 1px solid var(--color-coat-divider); border-radius: var(--radius-md);
  color: var(--color-coat-text); font-size: var(--text-sm); letter-spacing: .02em;
  transition: background-color var(--motion-fast) var(--motion-ease),
              color var(--motion-fast) var(--motion-ease);
}
.nav-menu__toggle::before { content: none; }
.nav-menu__toggle:hover { color: var(--color-coat-text); background: var(--wash-coat); }
.nav-menu[open] > .nav-menu__toggle { background: var(--color-coat-text); color: var(--color-coat); }
.nav-menu__body {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-1);
  flex: 1 1 100%; padding: var(--space-1-5) 0 var(--space-1);
  border-top: 1px solid var(--color-coat-divider);
}
.nav-menu__who { display: flex; flex-direction: column; justify-content: center; min-height: var(--hit-min); line-height: 1.3; }
.nav-menu__name { font-weight: var(--font-strong-weight); font-size: var(--text-base); }
.nav-menu__practice { font-size: var(--text-sm); color: var(--color-coat-soft); }
.nav-menu__link {
  display: inline-flex; align-items: center; min-height: var(--hit-min);
  font-weight: var(--font-medium-weight); color: var(--color-coat-soft);
}
.nav-menu__link:hover { color: var(--color-coat-text); }
.nav-menu__link[aria-current="page"] { color: var(--color-coat-text); box-shadow: inset 0 -2px 0 var(--color-coat-accent); }
.nav-menu__body form { display: flex; }
.nav-menu__body .nav-mark { min-height: var(--hit-min); }
/* A secondary button on the coat: the fleck's rule, the fleck's ink. */
.nav .btn-secondary { background: transparent; color: var(--color-coat-text); border-color: var(--color-coat-divider); }
.nav .btn-secondary:hover { background: var(--wash-coat); border-color: var(--color-coat-soft); }
/* The Add to Home Screen line, on the coat, at the end of the header: one
   sentence in the coat's quiet ink and a Hide button. Shown by install.js on
   iOS Safari only; a full row, so it never squeezes the account corner. */
.nav-install {
  display: flex; align-items: center; gap: var(--space-2-5); flex-wrap: wrap;
  flex: 1 1 100%; order: 3; padding-top: var(--space-1);
  border-top: 1px solid var(--color-coat-divider);
  font-size: var(--text-sm); color: var(--color-coat-soft);
}
.nav-install .btn { margin-left: auto; }
.nav:has(.nav-install:not([hidden])) { flex-wrap: wrap; }
/* The Roan mark, once, small — 16px so the flecks read as a mark. On the
   coat the flecks are cut from the coat itself. */
.nav-mark { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--color-coat-soft); --roan-word-size: 16px; --roan-word-color: var(--color-coat-text); --roan-square-color: var(--color-coat-accent); }
.nav-mark svg { width: 16px; height: 16px; display: block; }
/* Before anyone has signed in there is no practice to name, so the bar
   carries only the mark, in the brand, and the word. */
.nav--bare .nav-brand { --roan-word-size: 24px; --roan-word-color: var(--color-coat-text); --roan-square-color: var(--color-coat-accent); }
.nav--bare .nav-mark { color: var(--color-coat-accent); }
.nav--bare .nav-mark svg { width: 22px; height: 22px; }

.app-footer {
  position: sticky; bottom: 0; z-index: 20; flex-shrink: 0;
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  min-height: var(--hit-touch);
  padding: var(--space-3) calc(var(--space-5) + var(--inset-right)) calc(var(--space-3) + var(--inset-bottom)) calc(var(--space-5) + var(--inset-left));
  border-top: var(--rule-row);
  font-size: var(--text-xs); color: var(--color-muted); background: var(--workspace-surface);
}
.app-footer__identity { display: inline-flex; align-items: center; gap: var(--space-2-5); --roan-word-size: 18px; --roan-word-color: var(--color-text); --roan-square-color: var(--color-accent); }
.app-footer__version { padding: var(--space-0-5) var(--space-1-5); border: var(--rule-row); border-radius: var(--radius-sm); font-variant-numeric: tabular-nums; }
.app-footer__context { min-width: 0; overflow-wrap: anywhere; }
.app-footer__shortcut { display: inline-flex; align-items: center; gap: var(--space-2); margin-left: auto; }
.app-footer a { color: inherit; }
.app-footer :focus-visible { outline-color: var(--color-accent); }
.app-footer .kbd { color: inherit; background: var(--color-bg); border-color: var(--color-divider); }
@media (max-width: 680px) {
  .app-footer { gap: var(--space-2) var(--space-3); }
  .app-footer__shortcut { display: none; }
}

/* A screen with no rail and one thing on it: sign-in, an error, a code.
   Narrow, centred, on the ground. */
.page-narrow { width: min(26rem, 100%); margin: var(--space-8) auto; padding: 0 var(--space-4); }
.page-narrow--wide { width: min(38rem, 100%); }
.page-narrow h1 { font-size: var(--text-2xl); margin-bottom: var(--space-1); }
.page-narrow > p { margin-bottom: var(--space-4); }

/* Workspaces: the main column and its rails. */
.workspace { display: grid; min-height: 0; flex: 1; }
.workspace--with-rail { grid-template-columns: minmax(0, 1fr) var(--rail-side); }
.workspace--wide-rail { grid-template-columns: minmax(0, 1fr) var(--rail-side-max); }
.workspace--rail-left { grid-template-columns: var(--rail-side) minmax(0, 1fr); }
.workspace--record { grid-template-columns: var(--rail-side) minmax(0, 1fr); }
.workspace--record:has(.record-sidebar:not([open])) { grid-template-columns: 56px minmax(0, 1fr); }
.workspace--consult { grid-template-columns: var(--rail-side-min) minmax(0, 1fr) 326px; }
.workspace > * + * { border-left: var(--rule-region); }

/* A panel is a column of the screen: a head, then a body that scrolls if it
   must. A lane is a panel that opened beside another on the same canvas. */
.panel { display: flex; flex-direction: column; min-width: 0; }
.panel__head {
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
  padding: var(--space-3) var(--space-4); border-bottom: var(--rule-row);
  font-size: var(--text-2xs); letter-spacing: .08em; text-transform: uppercase;
  color: var(--color-muted); font-weight: var(--font-medium-weight);
}
/* A count or a note at the end of a head, in the head's own voice but not
   its case: "1 of 4 open". */
.panel__count {
  margin-left: auto; font-size: var(--text-xs); font-weight: 400;
  text-transform: none; letter-spacing: 0; color: var(--color-muted-soft);
  font-variant-numeric: tabular-nums; min-width: 0; max-width: 100%;
}
.panel__body { overflow: auto; min-height: 0; }
.panel .section + .panel__head, .panel .alert-row + .panel__head { border-top: var(--rule-region); }
/* A live region that would otherwise push everything under it down: the
   consult's transcript. Scrolls in its own box, never the page. */
.transcript { max-height: 30vh; overflow: auto; }
.panel + .panel { border-top: var(--rule-region); }
.lane { display: flex; flex-direction: column; min-width: 0; }
.lane__head { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
                padding: var(--space-2) var(--space-3-5); border-bottom: var(--rule-region); }

/* A region of a screen: padded, ruled underneath. --row for a row rule,
   --flush for none. This is what every "padding:11px 14px;border-bottom"
   used to be. */
.region { padding: var(--space-4) var(--shell-gutter); border-bottom: var(--rule-region); }
.region--row { border-bottom: var(--rule-row); }
.region--flush { border-bottom: 0; }
.region--tight { padding: var(--space-2) var(--space-3-5); }
/* A side column's sections: tighter, ruled by rows, a region rule where a
   new subject starts. The head carries a label and, at the end, a count. */
.section { padding: var(--space-2-5) var(--space-3); border-bottom: var(--rule-row); }
.section--major { border-top: var(--rule-region); }
.section__head { display: flex; align-items: baseline; gap: var(--space-2); }
.section__head .panel__count { margin-left: auto; }
.section__title { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: var(--text-2xl); line-height: 1.1; }
.record-sidebar { min-width: 0; }
.record-sidebar > summary {
  display: flex; align-items: center; gap: var(--space-2); min-height: var(--hit-min);
  padding: var(--space-2) var(--space-3); border-bottom: var(--rule-region);
  cursor: pointer; list-style: none;
}
.record-sidebar > summary::-webkit-details-marker { display: none; }
.record-sidebar__summary > span:first-child {
  display: flex; flex-direction: column; min-width: 0;
}
.record-sidebar__summary b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.record-sidebar__meta { margin-left: auto; color: var(--color-muted); font-size: var(--text-xs); white-space: nowrap; }
.record-sidebar__toggle {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 28px; padding: 0 var(--space-2); border: var(--rule-row);
  border-radius: var(--radius-lg); color: var(--color-muted); font-size: var(--text-xs);
}
.record-sidebar__closed { display: none; }
.record-sidebar:not([open]) { overflow: hidden; }
.record-sidebar:not([open]) > summary {
  writing-mode: vertical-rl; align-items: center; justify-content: flex-start;
  height: 100%; padding: var(--space-3) var(--space-1); border-bottom: 0;
}
.record-sidebar:not([open]) .record-sidebar__summary > span:first-child, .record-sidebar:not([open]) .record-sidebar__meta { display: none; }
.record-sidebar:not([open]) .record-sidebar__open { display: none; }
.record-sidebar:not([open]) .record-sidebar__closed { display: inline; }
.record-sidebar:not([open]) .record-sidebar__toggle {
  writing-mode: vertical-rl; padding: var(--space-2) 0; min-width: var(--hit-min);
}
.record-cta {
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
  padding: var(--space-2) var(--space-3-5); border-bottom: var(--rule-region);
  background: var(--color-bg);
}
.record-cta__main {
  display: flex; flex-direction: column; min-width: min(260px, 100%);
  margin-right: auto;
}
.record-cta__main strong { font-size: var(--text-lg); line-height: 1.2; }
.record-cta form { margin: 0; }
.record-cta--secondary {
  background: var(--color-surface);
  border-bottom: var(--rule-row);
}
.record-cta--secondary .btn { min-height: 32px; }
.record-cta__more[open] { flex-basis: 100%; }
/* Equal cells across a band, each ruled on its right. */
/* A pet card in the household column. The active one takes the accent wash
   and a 3px bar; a deceased animal stays on the record at 55%. */
.pet-card[data-active="true"] { background: var(--wash-accent); box-shadow: inset 3px 0 0 var(--color-accent); }
.pet-card[data-deceased="true"] { opacity: .55; }
.cells { display: flex; border-bottom: var(--rule-region); }
.cell { flex: 1 1 0; min-width: 0; padding: 11px var(--space-3-5); border-right: var(--rule-row); }
.cell:last-child { border-right: 0; }

/* Overflow is always explicit. Nothing clips silently — §5. */
.overflow-note {
  padding: var(--space-1-5) var(--space-2-5); font-size: var(--text-xs); border-top: var(--rule-row);
  color: var(--color-muted); margin: 0;
}

/* Figures: a strip of headline numbers, each printed with its label and a
   note. The number is mono and tabular, so a row of them lines up. */
.figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); border-bottom: var(--rule-region); }
.figure { padding: var(--space-3) var(--space-3-5); border-right: var(--rule-row); min-width: 0; }
.figure:last-child { border-right: 0; }
.figure__value { font-size: var(--text-figure); font-family: var(--font-mono);
                 font-weight: var(--font-strong-weight); font-variant-numeric: tabular-nums;
                 letter-spacing: -.02em; line-height: 1.2; margin-top: var(--space-0-5); }
.figure__note { font-size: var(--text-sm); color: var(--color-muted-soft); }
/* The same figure on its own in a side rail: the value of a key, an
   approvals count. Wraps a long value rather than widening the rail. */
.rail-figure {
  font-family: var(--font-mono); font-size: var(--text-figure); font-weight: var(--font-strong-weight);
  font-variant-numeric: tabular-nums; line-height: 1.2; overflow-wrap: anywhere;
}
.figure[data-state="act"]       .figure__value { color: var(--state-act-ink); }
.figure[data-state="attention"] .figure__value { color: var(--state-attention-ink); }
.figure[data-state="settled"]   .figure__value { color: var(--state-settled-ink); }
.figure[data-state="info"]      .figure__value { color: var(--state-info-ink); }

/* An empty state says what would be here and what to do about it: a title,
   one sentence, one action. Centred, no tile, no card. */
.empty-state {
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--space-2);
  padding: var(--space-8) var(--space-4); border-bottom: var(--rule-row);
  color: var(--color-muted);
}
.empty-state > strong { font-size: var(--text-lg); font-weight: var(--font-strong-weight); color: var(--color-text); }
.empty-state > p, .empty-state > span { max-width: 44ch; margin: 0; font-size: var(--text-md); }
.empty-state__actions { display: flex; gap: var(--space-2); flex-wrap: wrap; justify-content: center; margin-top: var(--space-1); }
.empty-state .btn { margin-top: var(--space-1); }

/* Before a search: what to type, with examples that are themselves searches. */
.search-guide { padding: var(--space-6) var(--space-3-5); border-bottom: var(--rule-row); max-width: 62ch; }
.search-guide > strong { font-size: var(--text-lg); }
.search-guide__examples { display: flex; flex-wrap: wrap; gap: var(--space-1-5); margin-top: var(--space-3); }

/* Search results: one household per row. At a desk the parts sit in
   columns; on a phone the name takes a line and the pets the next, so
   nothing needs a scroll box. */
.hit-list { margin: 0; padding: 0; list-style: none; }
.hit {
  display: grid; align-items: baseline; gap: var(--space-1) var(--space-3);
  grid-template-columns: minmax(0, 2fr) minmax(0, 2fr) minmax(0, 3fr) auto auto;
  padding: var(--space-2) var(--space-3-5); border-bottom: var(--rule-row);
}
.hit:hover { background: var(--wash-hover); }
.hit__name { display: flex; align-items: center; gap: var(--space-1-5); flex-wrap: wrap; min-width: 0; }
.hit__name a { font-weight: var(--font-strong-weight); }
.hit__pets, .hit__where { min-width: 0; overflow-wrap: anywhere; }
.hit__where { font-size: var(--text-sm); color: var(--color-muted); }
.hit__account { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-muted); }

/* A catalogue of choices (permissions, scopes, sites): as many columns as
   fit a side-rail width, one on a phone. Each choice is a .check with its
   key printed under the label. */
.check-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--rail-side-min), 1fr)); gap: var(--space-0-5) var(--space-3-5); }
.check-grid .check { align-items: flex-start; padding-block: var(--space-1); }
.check-grid .check .box { margin-top: var(--space-1); }

/* A ledger: a history read as a book of entries. The reference is the
   first column and is set as a figure; the newest entry sits on top and
   carries the accent bar so "where we are" is obvious. A closing line is
   ruled off and strong. */
.ledger tr[data-head="true"] > td:first-child { box-shadow: inset 3px 0 0 var(--color-accent); }
.ledger__ref { font-family: var(--font-mono); font-weight: var(--font-strong-weight); font-variant-numeric: tabular-nums; white-space: nowrap; }
.ledger tfoot td { border-top: var(--rule-region); font-weight: var(--font-strong-weight); }
/* Any listing that closes with totals. A single closing line is ruled off
   from the rows with the region rule and set strong. A totals band of
   several lines reads as an arithmetic column: the working lines (net, VAT,
   benefit, paid) sit tight and quiet, and the lines that matter carry
   data-total — "sum" for the invoice total, "due" for the balance the client
   is asked for, which is also set one step larger. */
.table tfoot td { border-top: var(--rule-region); border-bottom: 0; font-weight: var(--font-strong-weight); }
.table tfoot tr + tr td { border-top: 0; padding-top: 0; }
.table tfoot tr:not(:only-child):not([data-total]) td { font-weight: 400; color: var(--color-muted); }
.table tfoot tr[data-total] + tr td, .table tfoot tr + tr[data-total] td { border-top: var(--rule-row); padding-top: var(--space-2); }
.table tfoot tr[data-total="due"] td { font-size: var(--text-lg); }

/* ── Command line ─────────────────────────────────────────────────────────
   Primary input on every screen. Always reachable by pointer too — there is no
   keyboard-only action anywhere in Roan. */

.cmd {
  display: flex; align-items: center; gap: var(--space-2);
  min-height: var(--hit-min); padding: 0 var(--space-1) 0 var(--space-2-5);
  background: var(--color-bg); border: 1px solid var(--color-divider-strong);
  border-radius: var(--radius-md);
  transition: border-color var(--motion-fast) var(--motion-ease),
              background-color var(--motion-fast) var(--motion-ease);
}
.cmd:focus-within { border-color: var(--color-accent); box-shadow: inset 0 0 0 1px var(--color-accent);
                    background: var(--color-surface-editing); }
.cmd .btn { padding-block: 0; }
.cmd > svg { width: 15px; height: 15px; flex: none; color: var(--color-muted-soft); }
.cmd__input {
  flex: 1; min-width: 0; min-height: var(--hit-min); padding: 0; font: inherit; font-size: var(--text-md);
  background: transparent; border: 0; outline: none;
  caret-color: var(--color-accent);
}
.cmd__input::placeholder { color: var(--color-muted-soft); }
.cmd__input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.cmd__hint {
  font-size: var(--text-2xs); letter-spacing: .04em;
  color: var(--color-muted-soft);
}
.cmd__resolved { font-weight: var(--font-strong-weight); color: var(--state-info-ink); }

/* ── Diary grid ───────────────────────────────────────────────────────────
   34px per 15 minutes. A 15-minute appointment holds exactly one line of text;
   if the content needs two, the slot is wrong or the content is. */

.diary-screen { height: calc(100vh - var(--chrome-height)); height: calc(100dvh - var(--chrome-height)); }
.diary-workspace { display: grid; grid-template-columns: minmax(0, 1fr) var(--rail-side); min-height: 0; flex: 1; }
.diary-main { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.diary-resource-head {
  position: sticky; top: 0; z-index: 5;
  display: grid; grid-template-columns: var(--gutter-time) repeat(var(--diary-columns), minmax(180px, 1fr));
  min-width: calc(var(--gutter-time) + var(--diary-columns) * 180px);
  border-bottom: var(--rule-region); background: var(--color-bg);
}
.diary-resource-head__cell { min-width: 0; padding: 7px 9px; border-left: var(--rule-row); overflow-wrap: anywhere; }
.diary-resource-head__cell > span { display: block; }
.diary-scroll { overflow: auto; min-height: 0; }
.diary-grid {
  display: grid; grid-template-columns: var(--gutter-time) repeat(var(--diary-columns), minmax(180px, 1fr));
  min-width: calc(var(--gutter-time) + var(--diary-columns) * 180px);
}
.diary-gutter { height: var(--diary-height); }
/* The time gutter is figures, so it is mono. */
.diary-gutter__label { height: var(--slot-hour); padding: 3px 7px 0 0; text-align: right;
                       font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--color-muted); }
.diary-column { position: relative; border-left: var(--rule-row); height: var(--diary-height); }
/* Each half hour is ruled; the quarter inside it is dotted, so a 15-minute
   slot can be found without counting pixels. */
.diary-half-hour {
  height: var(--slot-hour); border-bottom: var(--rule-row);
  background: linear-gradient(to right, var(--color-divider) 50%, transparent 50%) 0 50% / 6px 1px repeat-x;
}
.diary-column .appt {
  left: calc((100% * var(--overlap-index, 0) / var(--overlap-count, 1)) + 2px);
  right: auto;
  width: calc((100% / var(--overlap-count, 1)) - 4px);
  text-decoration: none; color: inherit;
}
.appt > span:not(.appt__chips) { display: block; margin-top: var(--space-0-5); }
.appt__chips { display: flex; gap: 3px; margin-top: var(--space-1); }
.appt--blocked { background: repeating-linear-gradient(135deg, var(--color-surface) 0 6px, transparent 6px 12px); }
.diary-now { position: absolute; left: 0; right: 0; z-index: 4; border-top: 3px solid var(--state-act-ink); pointer-events: none; }
.diary-now::before { content: ""; position: absolute; left: -3px; top: -4px; width: 6px; height: 6px; background: var(--state-act-ink); }
.diary-now[hidden] { display: none; }
.diary-now__time { position: absolute; left: 0; bottom: 3px; padding: 1px 5px; background: var(--state-act-ink); color: var(--color-bg); font-size: var(--text-2xs); line-height: 16px; font-variant-numeric: tabular-nums; }
.diary-now__time:empty { display: none; }
.diary-side { min-height: 0; overflow: auto; border-left: var(--rule-region); }
.diary-side__row { padding: var(--space-2) var(--space-2-5); border-bottom: var(--rule-row); }
.diary-side__row[data-state="act"] { background: var(--state-act-fill); }
.diary-side .panel__head + .panel__head, .diary-side__row + .panel__head { border-top: var(--rule-region); }

.diary { display: grid; grid-template-columns: var(--gutter-time) repeat(var(--diary-columns, 5), 1fr); }
.diary__gutter { border-right: var(--rule-region); }
.diary__hour { height: var(--slot-hour); padding: var(--space-0-5) var(--space-1-5); font-size: var(--text-2xs);
                  border-bottom: var(--rule-row); font-family: var(--font-mono);
                  color: var(--color-muted); }
.diary__column { position: relative; border-right: var(--rule-row); }
.diary__slot { height: var(--slot-15); border-bottom: 1px dotted
                  color-mix(in srgb, var(--color-text) 15%, transparent); }

.appt {
  position: absolute; left: 2px; right: 2px;
  padding: var(--space-1) var(--space-1-5) var(--space-1) 9px; overflow: hidden;
  font-size: var(--text-dense); line-height: 1.25;
  background: var(--color-surface);
  border: 1px solid var(--color-divider-strong);
  border-left: 3px solid var(--color-neutral-600);
  border-radius: var(--radius-sm);
}
.appt:hover { border-color: var(--color-neutral-600); }
.appt:focus-visible { outline: 2px solid var(--color-accent); outline-offset: -2px; z-index: 2; }
.appt strong { font-weight: var(--font-strong-weight); }
.appt[data-state="act"] { border-left-color: var(--state-act-ink);       background: var(--state-act-fill); }
.appt[data-state="attention"] { border-left-color: var(--state-attention-ink); background: var(--state-attention-fill); }
.appt[data-state="settled"] { border-left-color: var(--state-settled-ink);   background: var(--state-settled-fill); }
.appt[data-state="info"] { border-left-color: var(--state-info-ink);      background: var(--state-info-fill); }
.appt__name { font-weight: var(--font-strong-weight); white-space: nowrap; text-overflow: ellipsis; overflow: hidden; }
/* Each line in a block is one line: a subtitle too long for a narrow lane is
   cut with an ellipsis rather than wrapping into a third line the slot has
   no room for. The service decides how many lines a block may carry. */
.appt > strong, .appt > span:not(.appt__chips) { white-space: nowrap; text-overflow: ellipsis; overflow: hidden; }

/* Blocked time: 135deg stripes, 6px on 12px. */
.diary__blocked {
  position: absolute; left: 0; right: 0;
  background: repeating-linear-gradient(135deg,
    color-mix(in srgb, var(--color-text) 12%, transparent) 0 6px,
    transparent 6px 12px);
}

/* The now line. The only red on the grid unless something is genuinely urgent. */
.diary__now { position: absolute; left: 0; right: 0; height: 3px;
              background: var(--state-act-ink); z-index: 3; }
.diary__now::before { content: ""; position: absolute; left: -6px; top: -1.5px;
                      width: 6px; height: 6px; background: var(--state-act-ink); }

/* ── SOAP note stack ──────────────────────────────────────────────────────
   Each section is its own field. The one being typed into is the only white
   surface on the screen; the next is a dashed outline; completed sections are
   plain. That is the whole navigation model for the consult. */

.note-field { padding: var(--space-2-5) var(--space-3); border-bottom: var(--rule-row); background: transparent; }
.note-field__label {
  display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-1);
  font-size: var(--text-2xs); letter-spacing: .08em; text-transform: uppercase;
  color: var(--color-muted);
}
.note-field__input {
  width: 100%; min-height: var(--hit-min); padding: 0; font: inherit; font-size: var(--text-clinical);
  line-height: 1.6; background: transparent; border: 0; outline: none; resize: vertical;
}
.note-field[data-status="editing"] {
  background: var(--color-surface-editing); box-shadow: inset 3px 0 0 var(--color-accent);
}
.note-field[data-status="editing"] .note-field__label { color: var(--color-accent); }
.note-field[data-status="next"] {
  outline: 1px dashed color-mix(in srgb, var(--color-text) 35%, transparent);
  outline-offset: -1px;
}

/* An AI suggestion. Visibly not what a human wrote, with accept and reject
   always present as buttons as well as keystrokes. It is a decision waiting
   for a named person, so it wears the attention state, never act-now: a
   suggestion is not an emergency. A rejected suggestion never silently
   reappears — that is enforced in JS, not here. */
.note-field[data-source="suggested"] {
  background: var(--state-attention-fill);
  box-shadow: inset 3px 0 0 var(--state-attention-ink);
}
.suggestion__controls {
  display: flex; align-items: center; gap: var(--space-1-5); margin-top: var(--space-1-5);
  font-size: var(--text-xs); color: var(--state-attention-ink);
}

/* ── Consequence statement ────────────────────────────────────────────────
   Any primary action that fans out says what it will do, in words, beside the
   button. Not a tooltip, not a confirmation dialog. */

.action-bar {
  display: flex; align-items: center; gap: var(--space-3-5); flex-wrap: wrap;
  padding: var(--space-2-5) var(--space-3-5); border-top: var(--rule-region); background: var(--color-surface);
  font-size: var(--text-sm);
}
.action-bar--plain { background: transparent; padding-inline: 0; }
.action-bar__consequence {
  font-size: var(--text-dense); color: var(--color-muted-strong);
}
.action-bar__spacer { margin-left: auto; }
/* "On payment, Roan will…": a plain list of what the primary action does,
   when one sentence would not hold it. */
.consequence-list { margin: var(--space-1) 0 0; padding-left: var(--space-4); font-size: var(--text-sm); color: var(--color-muted-strong); }
.consequence-list li + li { margin-top: var(--space-0-5); }

/* ── Tender pad ───────────────────────────────────────────────────────────
   The ways to pay on the checkout: a 2×2 grid, the chosen one filled with
   the accent (selected is not urgent — DESIGN_RULES §2). Works as radios;
   the native input is kept for the keyboard and the reader. */
.tender-pad { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); border-bottom: var(--rule-row); }
.tender {
  position: relative; display: flex; flex-direction: column; gap: var(--space-0-5);
  min-height: var(--hit-min); padding: var(--space-2-5) var(--space-3); cursor: pointer;
  border-right: var(--rule-row); border-bottom: var(--rule-row); font-size: var(--text-md);
}
.tender:nth-child(2n) { border-right: 0; }
.tender input { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; }
.tender:hover { background: var(--wash-hover); }
.tender:has(input:checked) { background: var(--color-accent); color: var(--color-bg); }
.tender:has(input:checked) .t-meta { color: inherit; }
.tender:has(input:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: -2px; }

/* ── Meters ───────────────────────────────────────────────────────────────
   Capacity, plan usage, stock. The number is always printed — the grid must
   read with colour removed entirely (§2). */

.meter { display: grid; grid-template-columns: 1fr auto; gap: var(--space-1-5); align-items: center; }
.meter__track { height: 8px; background: var(--color-neutral-300); border-radius: var(--radius-sm); overflow: hidden; }
.meter__fill { height: 100%; background: var(--state-settled-ink); }
.meter__fill[data-state="attention"] { background: var(--state-attention-ink); }
.meter__fill[data-state="act"] { background: var(--state-act-ink); }
.meter__fill[data-state="info"] { background: var(--state-info-ink); }
.meter__value { font-size: var(--text-xs); font-weight: var(--font-strong-weight); font-family: var(--font-mono);
                font-variant-numeric: tabular-nums; }

/* Heatmap cell: colour tints, the number carries the meaning. */
.heat { display: grid; place-items: center; min-height: var(--hit-min);
        font-size: var(--text-sm); font-weight: var(--font-strong-weight); font-variant-numeric: tabular-nums;
        font-family: var(--font-mono);
        border-right: var(--rule-row); border-bottom: var(--rule-row); }
.heat[data-state="act"] { background: var(--state-act-fill);       color: var(--state-act-ink); }
.heat[data-state="attention"] { background: var(--state-attention-fill); color: var(--state-attention-ink); }
.heat[data-state="settled"] { background: var(--state-settled-fill);   color: var(--state-settled-ink); }
.heat[data-state="info"] { background: var(--state-info-fill);      color: var(--state-info-ink); }

/* ── Laboratory results ───────────────────────────────────────────────────
   Flags must survive greyscale printing and a colour-blind reader. */

.flag { font-weight: var(--font-heading-weight); font-family: var(--font-mono); }
.flag[data-flag="H"] { color: var(--state-act-ink); }
.flag[data-flag="L"] { color: var(--state-info-ink); }
.flag[data-flag="HH"] { color: var(--state-act-ink); }
.flag[data-flag="LL"] { color: var(--state-info-ink); }
.flag[data-flag="HH"]::after, .flag[data-flag="LL"]::after { content: " ✱"; }

/* Radiograph and cytology placeholders, per §8. */
.image-placeholder {
  display: grid; place-items: center; min-height: 64px;
  font-family: var(--font-mono); font-size: var(--text-3xs);
  color: var(--color-muted);
  background: repeating-linear-gradient(45deg,
    color-mix(in srgb, var(--color-text) 10%, transparent) 0 4px,
    transparent 4px 8px);
}

/* ── Flashes ──────────────────────────────────────────────────────────────
   Inline, in the flow, never floating over content. One canvas — §9. */

.flashes { display: flex; flex-direction: column; }
.flash {
  display: flex; align-items: baseline; gap: var(--space-2-5); flex-wrap: wrap;
  padding: var(--space-2) var(--space-3-5); font-size: var(--text-md);
  border-bottom: var(--rule-row); border-left: 3px solid var(--color-neutral-600);
  background: var(--color-surface);
}
.flash[data-state="act"] { background: var(--state-act-fill);       color: var(--state-act-ink);       border-left-color: var(--state-act-ink); }
.flash[data-state="attention"] { background: var(--state-attention-fill); color: var(--state-attention-ink); border-left-color: var(--state-attention-ink); }
.flash[data-state="settled"] { background: var(--state-settled-fill);   color: var(--state-settled-ink);   border-left-color: var(--state-settled-ink); }
.flash[data-state="info"] { background: var(--state-info-fill);      color: var(--state-info-ink);      border-left-color: var(--state-info-ink); }
.flash__word { font-weight: var(--font-strong-weight); flex: none; }
.flash .btn { margin-left: auto; }

/* ── The patient band ─────────────────────────────────────────────────────
   Everything a clinician must know before touching the animal, on one line
   of the screen: identity, owner, the clinical alert, why they are here,
   what is outstanding. */
.band { display: flex; padding: 11px var(--space-3-5); gap: 0; border-bottom: var(--rule-region); }
.band__cell { padding: 0 var(--space-4-5); border-right: var(--rule-row); min-width: 0; }
.band__cell:first-child { padding-left: 0; }
.band__cell:last-child { border-right: 0; padding-right: 0; }
.band__cell--identity { flex: 1 1 auto; }
.band__cell--owner { width: 190px; flex: none; }
.band__cell--alerts { width: 230px; flex: none; }
.band__cell--presenting { width: 220px; flex: none; }
.band__cell--outstanding { width: 236px; flex: none; margin-left: auto; border-right: 0; padding-right: 0; }
.band__lead { font-size: var(--text-md); font-weight: var(--font-strong-weight); margin-top: var(--space-1); }
.band__lead a { color: inherit; }
.band__alert { font-size: var(--text-md); font-weight: var(--font-strong-weight); margin-top: var(--space-1); color: var(--state-act-ink); }
.band__chips { display: flex; gap: 5px; margin-top: 7px; flex-wrap: wrap; }
.band__list { font-size: var(--text-sm); margin-top: var(--space-1); line-height: 1.5; }
.band__list b[data-state="act"] { color: var(--state-act-ink); }

/* ── The ward ─────────────────────────────────────────────────────────────
   Two surfaces, and they are not the same job.

   The ward screens are worked on a phone in a corridor with one hand and a lead
   in the other, so the sheet collapses from a table into stacked rows below
   680px: a table with five columns on a 390px screen is either unreadable or a
   horizontal scroll, and a nurse will not scroll sideways to find the button
   that says a drug was given. The `data-label` attributes in the markup carry
   the column headings into that stacked form.

   The whiteboard is the opposite: read at three metres, never touched. It is
   the only place in Roan that sets a type size by hand. */

.ward-heading {
  display: flex; align-items: baseline; gap: var(--space-2-5); flex-wrap: wrap;
  padding: 9px var(--space-3-5); border-bottom: var(--rule-row);
}
.ward-strip {
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
  padding: var(--space-2) var(--space-3-5); border-bottom: var(--rule-row);
}
.ward-strip[data-state="blocked"] { background: var(--state-act-fill); }

.ward-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  border-bottom: var(--rule-region);
}
.ward-cell {
  display: flex; flex-direction: column; gap: var(--space-1); min-height: 96px;
  padding: var(--space-2-5) var(--space-3); border-right: var(--rule-row); border-bottom: var(--rule-row);
}
.ward-cell[data-state="blocked"] { background: var(--state-act-fill); }
.ward-cell[data-state="settled"] { background: var(--state-settled-fill); }
.ward-cell__head { display: flex; align-items: center; gap: var(--space-1-5); flex-wrap: wrap; }
.ward-cell__chips { display: flex; gap: var(--space-1); flex-wrap: wrap; margin-top: auto; }

.ward-actions { display: flex; gap: var(--space-1); flex-wrap: wrap; align-items: center; }
.ward-actions .btn { min-height: var(--hit-min); }
.ward-form select, .ward-form input, .ward-form textarea { min-height: var(--hit-min); width: 100%; }

.whiteboard { padding: var(--space-4-5) var(--space-5-5); }
.whiteboard__head {
  display: flex; align-items: baseline; gap: var(--space-3-5); flex-wrap: wrap;
  padding-bottom: var(--space-3); border-bottom: var(--rule-region);
}
/* The cards are ruled, not gapped over a painted ground: a last row with
   fewer cards than columns would otherwise show the ground as a grey block. */
.whiteboard__grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  margin-top: var(--space-3-5); border-left: var(--rule-row); border-top: var(--rule-row);
}
.whiteboard__card {
  display: flex; flex-direction: column; gap: var(--space-1-5); align-items: flex-start;
  padding: var(--space-3-5) var(--space-4); background: var(--color-bg); font-size: var(--text-lg);
  border-right: var(--rule-row); border-bottom: var(--rule-row);
}
.whiteboard__card[data-state="blocked"] { background: var(--state-act-fill); }
/* The card's fill follows its state, and the state's word is always in the
   chip on the card: overdue, due soon, expected. Settled cards stay on the
   ground so the ones that need somebody stand out. */
.whiteboard__card[data-state="act"] { background: var(--state-act-fill); }
.whiteboard__card[data-state="attention"] { background: var(--state-attention-fill); }
.whiteboard__card[data-state="info"] { background: var(--state-info-fill); }
.whiteboard__card-head { display: flex; align-items: baseline; gap: var(--space-2); flex-wrap: wrap; }
.whiteboard__facts { display: grid; grid-template-columns: auto 1fr; gap: var(--space-0-5) var(--space-2-5); margin: 0; }
.whiteboard__facts dt { font-size: var(--text-2xs); letter-spacing: .08em; text-transform: uppercase; }
.whiteboard__facts dd { margin: 0; }

/* Plans, as cards in a ruled grid. */
.plan-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); }
.plan-card { border-right: var(--rule-region); border-bottom: var(--rule-region); }
.plan-card__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); padding: var(--space-3-5); border-bottom: var(--rule-row); }
.plan-card__head h2 { margin: var(--space-0-5) 0 0; font-size: var(--text-2xl); }
.plan-card__summary { display: flex; flex-wrap: wrap; gap: var(--space-4); padding: 9px var(--space-3-5); border-bottom: var(--rule-row); font-size: var(--text-sm); }
.plan-card > p { padding: var(--space-2-5) var(--space-3-5); border-bottom: var(--rule-row); }

@media (max-width: 680px) {


  .ward-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .ward-table, .ward-table tbody, .ward-table tr, .ward-table td { display: block; width: auto; }
  .ward-table tr { padding: var(--space-1-5) 0; border-bottom: var(--rule-row); }
  .ward-table td { display: flex; gap: var(--space-2-5); border: 0; padding: var(--space-1) var(--space-3-5); }
  .ward-table td::before {
    content: attr(data-label); flex: 0 0 34%;
    font-size: var(--text-2xs); letter-spacing: .08em; text-transform: uppercase;
  }
  .ward-table td:empty { display: none; }
  .ward-actions .btn { flex: 1 1 auto; }
}

/* ── Tasks ────────────────────────────────────────────────────────────────
   A stack, not a table. This list is read on a phone at the kennel door as
   often as at a desk, and a six-column table at 390px is a horizontal
   scrollbar with a to-do list hidden inside it. Priority tints the left edge
   and the chip prints the word, so the list reads with colour removed — §2. */

.task-figures { display: grid; grid-template-columns: repeat(4, 1fr); }
.task-figures__cell { padding: var(--space-3-5); border-right: var(--rule-row); border-bottom: var(--rule-region); }

.task-filters { display: flex; align-items: center; gap: var(--space-1-5); flex-wrap: wrap;
                padding: var(--space-2) var(--space-2-5); border-bottom: var(--rule-region); }
.task-filters__spacer { margin-left: auto; }
.task-filters__form { display: flex; align-items: center; gap: var(--space-1-5); flex-wrap: wrap; min-width: 0; }
.task-filters__search { flex: 1 1 12rem; min-width: 0; width: 12rem; max-width: 100%; }
@media (max-width: 680px) {
  .task-filters__search { flex-basis: 100%; width: 100%; }
}

.task-list { margin: 0; padding: 0; list-style: none; }
.task-row {
  display: flex; align-items: flex-start; gap: var(--space-3); flex-wrap: wrap;
  padding: var(--space-2-5) var(--space-3-5); border-bottom: var(--rule-row);
  border-left: 3px solid var(--color-neutral-600);
}
.task-row[data-state="act"] { border-left-color: var(--state-act-ink); }
.task-row[data-state="attention"] { border-left-color: var(--state-attention-ink); }
.task-row[data-state="info"] { border-left-color: var(--state-info-ink); }
.task-row__main { flex: 1 1 260px; min-width: 0; }
.task-row__title { font-size: var(--text-base); font-weight: var(--font-strong-weight); overflow-wrap: anywhere; }
.task-row__meta { display: flex; align-items: center; gap: var(--space-2-5); flex-wrap: wrap; margin-top: 5px; }
.task-row__actions { display: flex; gap: var(--space-1-5); flex-wrap: wrap; margin-left: auto; }
/* The tick that puts a row into the bulk form. Native checkbox, thumb-sized target. */
.task-row__tick { display: flex; align-items: center; min-height: var(--hit-min); flex: none; }
.task-row__tick input { width: 18px; height: 18px; margin: 0; }
/* Reassign and cancel are folded under "More": the rare actions, kept off
   the row so Done stays the one obvious button. */
.task-row__more { flex: 1 1 100%; }
.task-row__more-body { display: flex; flex-direction: column; gap: var(--space-1-5); padding-top: var(--space-1); }
.task-row__inline { display: flex; align-items: center; gap: var(--space-1-5); flex-wrap: wrap; }
.task-row__inline .input { flex: 1 1 180px; min-width: 0; }

/* ── The shell on a handheld ──────────────────────────────────────────────
   The shared chrome only: the header, the navigation and the layout grids
   every screen sits in. Individual screens carry their own narrow rules in
   their own sections above.

   The rule the whole block serves: at 320px — the narrowest phone anyone
   still brings to work — the page reflows and nothing scrolls sideways. A
   fixed rail beside a fluid column does not reflow, it overhangs, so every
   grid that names a rail width collapses to a single column here and the
   rule that separated them turns from a left edge into a top one. */

@media (max-width: 680px) {
  /* The header is one band, about a thumb tall: the monogram, the site and
     the person's initials. The practice name and the "Working at" label are
     still in the markup and still read aloud, but not drawn — the monogram
     carries the identity, the site name carries the place, and the two were
     costing a row each on a screen five rows tall. The account corner and
     the section links fold behind the initials (`.nav-menu`); the site name
     stays in the band because a menu that has to be opened is a menu that
     hides where you are, and where you are is the one thing the coat must
     always say. The band still wraps if it must (the iOS install line takes
     a row of its own), and it never scrolls sideways. */
  .nav { flex-wrap: wrap; gap: var(--space-1-5) var(--space-3); padding: var(--space-1-5) var(--space-3); min-height: var(--hit-min); }
  .nav-brand { margin-right: 0; flex: none; }
  .nav-brand__name, .nav-context__label {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  }
  .nav-context { flex: 1 1 auto; min-width: 0; padding-inline: 0; border-left: 0; }
  /* The one place a label may wrap (§5 forbids it in chips and cells): the
     site name is what stops someone believing they are at another branch, so
     it wraps rather than being cut or pushing the row sideways. */
  .nav-context__value { white-space: normal; font-size: var(--text-base); }
  .nav-account { display: none; }
  .nav-menu { display: contents; }
  .nav-menu__toggle { order: 1; }
  .nav-menu__body { order: 2; }
  /* Newer engines box the details' content in a ::details-content pseudo-
     element, and that box is the flex item, not the body inside it. It takes
     the body's place in the row order and its full-width share. Its own rule,
     so an engine without the pseudo-element drops this line and nothing else:
     there the body itself is the flex item and the rules above hold. */
  .nav-menu::details-content { display: block; flex: 1 1 100%; order: 2; }
  /* Closed, that box would still claim a row of its own and the row gap
     with it; it has nothing to show, so it takes no row. */
  .nav-menu:not([open])::details-content { display: none; }





  /* Rails. Every one of them is a fixed pixel column beside a fluid one. */
  .workspace--with-rail, .workspace--wide-rail, .workspace--rail-left, .workspace--record, .workspace--consult, .diary-workspace { grid-template-columns: minmax(0, 1fr); }
  .workspace > * + * { border-left: 0; border-top: var(--rule-region); }
  .diary-side { border-left: 0; border-top: var(--rule-region); margin-top: var(--space-2); }
  /* Screens that still write their split inline — a conversion the area
     teams are making — get the same collapse, with the weight it takes to
     beat an inline declaration. */
  .workspace[style*="grid-template-columns"] { grid-template-columns: minmax(0, 1fr) !important; }
  /* Figure strips written inline as three or four equal columns. */
  [style*="grid-template-columns:repeat(4"],
  [style*="grid-template-columns:repeat(3"] { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }

  /* Grids whose minimum track is wider than the viewport. auto-fit does not
     save them: below the minimum the track keeps its width and overhangs. */
  .plan-grid { grid-template-columns: minmax(0, 1fr); }
  .whiteboard__grid { grid-template-columns: minmax(0, 1fr); }
  .check-grid { grid-template-columns: minmax(0, 1fr); }
  .whiteboard { padding: var(--space-3) var(--space-3-5); }
  .cells { flex-wrap: wrap; }
  .cell { flex: 1 1 100%; border-right: 0; border-bottom: var(--rule-row); }
  .band { flex-wrap: wrap; gap: var(--space-2-5) 0; }
  .band__cell { width: 100%; flex: 1 1 100%; padding-inline: 0; border-right: 0; }
  .band__cell--outstanding { margin-left: 0; }
  /* The spine's Clinical column is prose: it keeps a readable width and the
     listing scrolls inside its box, as every listing does. */
  .spine th:nth-child(2), .spine td:nth-child(2) { min-width: 18rem; }
  .hit { grid-template-columns: minmax(0, 1fr) auto; }
  .hit__pets, .hit__where, .hit__account { grid-column: 1 / -1; }
  .hit__match { grid-row: 1; grid-column: 2; }

  /* iOS Safari zooms the page whenever a focused field's type is under 16px,
     and does not zoom back out when the field is blurred — so one tap on a
     search box leaves every screen after it at about 114%. These three are
     every field in the product: .input is the class the templates use, and
     the command line and the SOAP note carry their own. Desktop keeps
     --text-md; this is a browser behaviour, not a change of type scale —
     --text-lg is a step the ramp already had, reached for a different reason. */
  .input, .cmd__input, .note-field__input { font-size: var(--text-lg); }

  /* Bars that assume there is room for a row. */
  .topbar, .action-bar { flex-wrap: wrap; }
  .action-bar__spacer { margin-left: 0; }
  /* A search field has a minimum width of its own, so the row it shares with
     the title and the primary action cannot shrink to a phone: it pushed the
     page wide and the browser zoomed everything out to fit. The field takes
     a row of its own, after the title and the action. */
  .topbar__search { flex: 1 1 100%; max-width: none; order: 1; }
  /* The primary action closes the bar: title, controls, search, then the
     site context and the action on one last row. */
  .topbar > .btn-primary { order: 2; margin-left: auto; }
  .topbar .nav-context { order: 2; flex: 1 1 auto; border-left: 0; padding-left: 0; }
  .topbar__actions { order: 2; flex: 1 1 100%; }
  /* The diary grid keeps most of the screen; the waiting room and capacity
     follow underneath rather than squeezing it to a strip. */
  .diary-screen { height: auto; }
  .diary-main { height: 70vh; }

  /* One hand, one thumb: the figures become two columns and the action drops
     under the task rather than squeezing the title into a column of letters. */
  .task-figures { grid-template-columns: repeat(2, 1fr); }
  .figures { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .figure:nth-child(2n) { border-right: 0; }
  .figure:nth-child(-n+2) { border-bottom: var(--rule-row); }
  .task-row__actions { margin-left: 0; width: 100%; }
  .task-row__actions form { flex: 1 1 100%; }
  .task-row__inline .btn { width: auto; }
  .task-row__actions .btn { width: 100%; }
  .page-narrow { margin-block: var(--space-4); }
  .empty-state { padding: var(--space-6) var(--space-3-5); }
  .record-sidebar:not([open]) > summary {
    writing-mode: horizontal-tb; height: auto; justify-content: space-between;
    padding: var(--space-2) var(--space-3);
  }
  .record-sidebar:not([open]) .record-sidebar__toggle { writing-mode: horizontal-tb; padding: 0 var(--space-2); }
  .record-cta > .btn, .record-cta > form, .record-cta > form .btn { width: 100%; }
}

/* A phone on its side has about 340px of height, and a sticky header with an
   offline bar above it can take a third of that. Below this the chrome scrolls
   away with the page: the header is navigation, and navigation is worth less
   than the field someone is trying to type into. */

@media (max-height: 480px) {
  .app-header { position: static; }
}

/* A finger, not a pointer. Neither breakpoint is a width: this is the input
   the device reports, and a touchscreen needs a target a finger can land on
   without hitting the one beside it. --hit-min is the one floor every
   control already carries, so lifting it lifts .btn, .input, .seg-opt,
   .check, .radio and the command line together; a listing row gets the
   same height through its cell padding, because a row is what a thumb taps
   on a phone. The desk keeps 36px: a mouse is precise, and density is the
   point of the desk. */
@media (pointer: coarse) {
  :root { --hit-min: 44px; }
  .table td { padding-block: var(--space-3); }
  .task-row { padding-block: var(--space-3); }
  .table td.actions .btn { margin-block: 0; }
}

/* ── Print ────────────────────────────────────────────────────────────────
   A label, a receipt, a register page. The chrome, the rail and every
   control are navigation and stay on the screen; what prints is the sheet.
   A screen that prints wraps the printable part in .print-sheet and marks
   its buttons .no-print. The label templates set their own stock size. */
@media print {
  .app-header, .app-footer, .offline-bar, .flashes, .cmd, .topbar__actions, .topbar__search, .presence-block { display: none !important; }

  .roan-main { padding: 0; }
  body { background: none; color: var(--color-text); }
  .print-sheet { max-width: 100%; }
  .table th, .table td { border-color: var(--color-text); }
  tr[data-state] > td, .chip { background: none !important; box-shadow: inset 0 0 0 1px currentColor; }
  a { color: inherit; text-decoration: none; }
  @page { margin: 12mm; }
}
/* A label: an address, a patient, a medicine, a specimen. What prints is the
   sheet; the lines come sized from the label service and the sizes are steps.
   The template's own <style> sets only the stock size and the page. */
.record-label {
  border: 1px solid var(--color-text); padding: var(--space-4) var(--space-3-5);
  background: var(--color-surface-editing);
}
.record-label__line { margin: 0 0 var(--space-1); }
.record-label__line:last-child { margin-bottom: 0; }
.record-label__line[data-size="headline"] { font-size: var(--text-lg); font-weight: var(--font-heading-weight); line-height: 1.25; }
.record-label__line[data-size="body"] { font-size: var(--text-clinical); line-height: 1.4; }
.record-label__line[data-size="footnote"] { font-size: var(--text-xs); line-height: 1.35; }
/* A particular the reader must not miss: a withdrawal period, a warning. */
.record-label__line[data-emphasis="rule"] { border-left: 3px solid var(--color-text); padding-left: var(--space-2-5); }
@media print {
  .record-label { border: 0; padding: 0; page-break-inside: avoid; }
}

/* ── Area: operations and reports ───────────────── */
/* The capacity heatmap: day headings sit over centred cells, and a heat cell
   fills its table cell so the tint reaches the rules. */
.ops-heatmap th.heat-head { text-align: center; }
.ops-heatmap td.heat-cell { padding: 0; }
/* The group operations rail: a footer line pushed to the bottom. */
.ops-rail__foot { margin-top: auto; }
.ops-band { flex: none; }
.ops-gap-actions { flex: 1 1 100%; }
/* People × days grows to its content inside its scroll box. */
.ops-grid { width: max-content; min-width: 100%; }
.ops-actions { justify-content: flex-end; flex-wrap: nowrap; }
/* ── end area: operations and reports ── */

/* ── Area: clinical ───────────────── */
/* A history entry the server marked relevant to this consult: the accent bar,
   not a state — relevance is where to look, not an emergency. */
.history-entry[data-relevant="true"] { box-shadow: inset 3px 0 0 var(--color-accent); }
/* A suggestion sits inside the field it proposes text for. */
.note-field .note-field { margin-top: var(--space-2); border-bottom: 0; }
.note-field[data-source="suggested"] .note-field__label { color: var(--state-attention-ink); }
/* The consult's action bar stays in view at the foot of the note column
   while the note scrolls: Finish consult is never below the fold. The
   note's body must not scroll on its own for that to work. */
.consult-note > .panel__body { overflow: visible; }
.consult-note .action-bar { position: sticky; bottom: var(--footer-offset); z-index: 3; padding-bottom: calc(var(--space-2-5) + var(--inset-bottom)); }
/* The version chain, collapsed but never hidden. */
.versions { border-top: var(--rule-region); }
.versions__summary { padding: var(--space-2) var(--space-3); font-size: var(--text-sm); }
.section[data-retracted="true"] .versions__body { text-decoration: line-through; }
@media (max-width: 680px) {
  /* On a phone the note comes first; history and capture follow it. */
  .consult-columns > .consult-history { order: 2; }
  .consult-columns > .consult-capture { order: 3; }
}
/* The dental chart: an HTML grid numbered by the modified Triadan system and
   laid out as the clinician faces the animal. Two arches, each two quadrants
   either side of a region rule that is the midline; one column on a phone.
   A tooth is a native details: closed, a cell with its number, name and AVDC
   codes; open, it takes its quadrant's width for its fields, so charting on a
   tablet needs no script and nothing opens over the grid. The fill is never
   the only signal: the codes are printed in the cell, and a tooth that is
   gone has its number struck through and a dashed edge. */
.dental__arch { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); border-bottom: var(--rule-region); }
.dental__quadrant { min-width: 0; margin: 0; padding: var(--space-2) var(--space-2-5); border: 0; }
.dental__quadrant + .dental__quadrant { border-left: var(--rule-region); }
.dental__quadrant > legend { padding: 0; }
.dental__teeth {
  display: grid; gap: var(--space-1);
  grid-template-columns: repeat(auto-fill, minmax(calc(var(--hit-min) + var(--space-3)), 1fr));
}
.dental__tooth { border: var(--rule-row); background: var(--color-bg); }
.dental__tooth[data-absent="true"] { border-style: dashed; }
.dental__tooth[data-absent="true"] .dental__num { text-decoration: line-through; }
.dental__tooth[data-state="act"] { background: var(--state-act-fill); }
.dental__tooth[data-state="attention"] { background: var(--state-attention-fill); }
.dental__tooth[data-state="info"] { background: var(--state-info-fill); }
.dental__tooth[data-state="act"]       .dental__flags { color: var(--state-act-ink); }
.dental__tooth[data-state="attention"] .dental__flags { color: var(--state-attention-ink); }
.dental__tooth[data-state="info"]      .dental__flags { color: var(--state-info-ink); }
.dental__tooth > summary {
  flex-direction: column; justify-content: center; gap: 0; text-align: center;
  padding: var(--space-1) var(--space-0-5); font-weight: var(--font-medium-weight);
}
.dental__tooth > summary::before { content: none; }
/* The tooth being charted is the white surface, as the field being typed into is. */
.dental__tooth[open] { grid-column: 1 / -1; background: var(--color-surface-editing); }
.dental__tooth[open] > summary { flex-direction: row; justify-content: flex-start; gap: var(--space-2); padding-inline: var(--space-2-5); }
.dental__num { font-size: var(--text-md); }
.dental__name, .dental__flags { font-size: var(--text-xs); }
.dental__flags { display: flex; flex-wrap: wrap; justify-content: center; column-gap: var(--space-1); }
.dental__fields {
  display: grid; gap: var(--space-2) var(--space-3); padding: var(--space-2) var(--space-2-5) var(--space-3);
  grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
}
.dental__note { grid-column: 1 / -1; }
.dental__read { margin: 0; padding: 0 var(--space-2-5) var(--space-2); }
@media (max-width: 680px) {
  .dental__arch { grid-template-columns: minmax(0, 1fr); }
  .dental__quadrant + .dental__quadrant { border-left: 0; border-top: var(--rule-row); }
}
/* ── end area: clinical ── */

/* ── Area: front of house ───────────────── */
/* The public booking sheet's step, at the end of the top bar. */
.fh-step { flex-direction: column; align-items: flex-end; gap: var(--space-0-5); }
/* A slot is a time and who with; the two sit on one line inside the button. */
.fh-slots .btn { gap: var(--space-1-5); }
/* ── end area: front of house ── */

/* ── Area: insight ───────────────── */
/* A chart is a picture of the table under it, drawn by static/js/chart.js. It
   is information, never a state, so it is drawn in the ink at its strengths:
   no state fill, no brand hue, and every figure it shows is printed in the
   table beside it (DESIGN_RULES §1–2). */
.chart { display: block; width: 100%; height: auto; margin-bottom: var(--space-2); }
.chart__grid { stroke: var(--color-divider); stroke-width: 1; }
.chart__axis { stroke: var(--color-divider-strong); stroke-width: 1; }
.chart__bar { fill: var(--color-muted-strong); }
.chart__line { fill: none; stroke: var(--color-text); stroke-width: 2; stroke-linejoin: round; }
.chart__dot { fill: var(--color-bg); stroke: var(--color-text); stroke-width: 2; }
.chart__tick { fill: var(--color-muted); font-family: var(--font-mono); font-size: var(--text-xs); }
/* A drawn signature. The pad is a field being written into, so it takes the
   editing surface and a field's border and radius; the stroke is the ink. It
   keeps its proportions rather than a fixed height, and takes every touch as
   a stroke rather than a scroll. The filed drawing sits on a rule, the way a
   signature sits on a line. */
.signature-pad { display: block; width: 100%; max-width: 30rem; aspect-ratio: 3 / 1; border: 1px solid var(--color-divider-strong); border-radius: var(--radius-md); background: var(--color-surface-editing); color: var(--color-text); touch-action: none; }
.signature-pad[data-signed="true"] { border-color: var(--color-text); }
.signature-image { display: block; width: 100%; max-width: 20rem; height: auto; border-bottom: 1px solid var(--color-text); }
/* ── end area: insight ── */

/* Global access remains in the document flow: search never covers a record. */
.skip-link {
  position: fixed; top: var(--space-2); left: var(--space-2); z-index: 100;
  padding: var(--space-2) var(--space-3); background: var(--color-bg);
  color: var(--color-accent); border: var(--rule-region); border-radius: var(--radius-md);
  transform: translateY(calc(-100% - var(--space-4)));
}
.skip-link:focus { transform: translateY(0); }
.nav:has(.nav-search) { flex-wrap: wrap; }
.nav-search { margin-left: auto; min-width: 0; }
.nav-search > summary { gap: var(--space-2); padding-inline: var(--space-3); font-size: var(--text-sm);
  border: 1px solid var(--color-coat-divider); border-radius: var(--radius-lg);
  background: var(--wash-coat); color: var(--color-coat-soft); }
.nav-search > summary::before { content: none; }
.nav-search > summary .kbd { margin-left: auto; }
.nav-search > summary:hover { color: var(--color-coat-text); }
.nav-search .kbd { color: var(--color-coat-soft); background: var(--wash-coat); border-color: var(--color-coat-divider); }
.nav-search[open] { flex-basis: 100%; }
.nav-search__body { display: grid; gap: var(--space-2); padding-block: var(--space-3); width: 100%; }
.nav-search__body .cmd { color: var(--color-text); background: var(--color-bg); }
.nav-search__body .btn-secondary { color: var(--color-text); background: var(--color-bg); border-color: var(--color-divider-strong); }
.nav-search__body p { color: var(--color-coat-soft); }
.dashboard-clear > summary, .search-summary { padding: var(--space-2) var(--space-3-5); border-bottom: var(--rule-row); }
.dashboard-clear > summary { color: var(--color-muted); font-size: var(--text-sm); }
.search-summary { background: var(--color-surface); }
.hit:focus-within { background: var(--wash-hover); }
.hit__name a { display: inline-flex; align-items: center; min-height: var(--hit-min); }
@media (max-width: 680px) {
  /* In the one-band header the search sits between the site and the
     initials, so the initials keep the far end of the band (the mirror of
     the monogram); open, it takes a row of its own under the band. */
  .nav-search { order: 0; }
  .nav-search[open] { order: 3; }
}
@media print {
  .skip-link { display: none; }
}

/* Keep location, search and account on one mobile row. Native disclosures
   expand below it; only the page content moves, never the account control. */
@media (max-width: 680px) {
  .nav:has(.nav-search) {
    display: grid;
    grid-template-columns: 32px minmax(0, 1fr) auto 36px;
    gap: var(--space-1) var(--space-2);
    padding: var(--space-1) var(--space-2);
  }
  .nav > .nav-brand { grid-column: 1; grid-row: 1; }
  .nav > .nav-context { grid-column: 2; grid-row: 1; }
  .nav > .nav-context .nav-context__value { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .nav > .nav-context .mono { display: none; }
  .nav-menu__toggle { grid-column: 4; grid-row: 1; width: 36px; min-height: 36px; padding: 0; }
  .nav-search, .nav-menu { display: contents; }
  .nav-search > summary { grid-column: 3; grid-row: 1; min-height: 36px; margin: 0; font-size: var(--text-sm); }
  .nav-search > summary .kbd { display: none; }
  .nav-menu__body, .nav-search__body, .nav-install { grid-column: 1 / -1; }
  .nav-menu::details-content, .nav-search::details-content { display: contents; }
  .nav-menu:not([open])::details-content, .nav-search:not([open])::details-content { display: none; }
  .today-topbar { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-1) var(--space-2); padding: var(--space-2) var(--space-3); }
  .today-topbar .topbar__search { display: none; }
  .today-topbar .topbar__title { grid-column: 1; grid-row: 1; }
  .today-topbar .topbar__meta { grid-column: 1 / -1; grid-row: 2; }
  .today-topbar > .btn-primary { grid-column: 2; grid-row: 1; margin: 0; }
  .figures .figure { padding: var(--space-2) var(--space-3); }
  .figures .figure__value { font-size: var(--text-xl); line-height: 1.2; }
}

/* Calendar keeps the time grid quiet and gives appointments a distinct shape. */
.calendar-help { padding: var(--space-1) var(--space-3); font-size: var(--text-2xs); color: var(--color-muted); border-bottom: var(--rule-row); }
.calendar-help [role="status"]:not(:empty) { display: block; font-size: var(--text-sm); color: var(--color-text); padding-block: var(--space-1); }
.diary-grid .calendar-event { border-radius: var(--radius-lg); padding-inline: var(--space-2); }
.diary-grid .calendar-event { background: var(--appointment-fill); color: var(--color-text); border-color: var(--color-neutral-500); border-left-color: var(--appointment-colour); border-left-width: 5px; }
.appointment-swatch { display: inline-block; width: 14px; height: 14px; flex: 0 0 14px; margin-inline-end: var(--space-2); vertical-align: middle; background: var(--appointment-colour); border: 1px solid var(--color-neutral-600); border-radius: var(--radius-sm); }
.calendar-colours__legend { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); list-style: none; padding: var(--space-2) 0; margin: 0; }
.calendar-colours__legend li { display: flex; align-items: center; font-size: var(--text-sm); }
.appointment-colour-settings { max-width: 900px; padding: var(--space-4); }
.appointment-colour-row { display: grid; grid-template-columns: minmax(0, 1fr) 48px auto auto; align-items: center; gap: var(--space-3); padding-block: var(--space-3); border-bottom: var(--rule-row); }
.appointment-colour-row label { overflow-wrap: anywhere; }
.appointment-colour-row input[type="color"] { width: 48px; height: 44px; padding: 3px; border: var(--rule-row); background: var(--color-surface); cursor: pointer; }
@media (max-width: 680px) {
  .appointment-colour-row { grid-template-columns: 48px 1fr 1fr; }
  .appointment-colour-row label { grid-column: 1 / -1; }
}
.calendar-event[data-editable="true"] { cursor: grab; touch-action: none; }
@media (pointer: coarse) {
  .calendar-event[data-editable="true"], .calendar-event[data-editable="true"] .calendar-event__edge { touch-action: pan-x pan-y; }
}
.calendar-event.is-dragging { z-index: 10; cursor: grabbing; box-shadow: 0 2px 8px var(--color-divider-strong); opacity: .85; pointer-events: none; }
.calendar-event__link { color: inherit; text-decoration: none; display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.calendar-event__link:focus-visible { outline: 2px solid var(--color-accent); outline-offset: -2px; }
.calendar-event[data-state] .calendar-event__link { padding-inline-end: var(--space-3); }
.calendar-event__status { position: absolute; right: 5px; top: 8px; width: 7px; height: 7px; background: var(--color-neutral-600); }
.calendar-event__status[data-state="act"] { background: var(--state-act-ink); }
.calendar-event__status[data-state="attention"] { background: var(--state-attention-ink); }
.calendar-event__status[data-state="settled"] { background: var(--state-settled-ink); }
.calendar-event__status[data-state="info"] { background: var(--state-info-ink); }
.calendar-event .calendar-event__edge { position: absolute; height: 8px; width: 100%; left: 0; margin: 0; cursor: ns-resize; touch-action: none; }
.calendar-event__edge--start { top: 0; }
.calendar-event__edge--end { bottom: 0; }
.calendar-event { cursor: pointer; }
.calendar-event:hover, .calendar-event:focus-visible { filter: brightness(.97); outline: 2px solid var(--color-accent); outline-offset: -2px; }
.appointment-preview, .appointment-dialog {
  color: var(--color-text); background: var(--color-bg); border: 1px solid var(--color-divider);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); padding: 0;
  overflow-wrap: anywhere; letter-spacing: 0;
}
.appointment-preview { position: fixed; z-index: 1000; width: min(380px, calc(100vw - 24px)); max-height: calc(100dvh - 24px); overflow: auto; }
.appointment-preview[hidden] { display: none; }
.appointment-dialog { width: min(540px, calc(100vw - 24px)); max-width: none; max-height: calc(100dvh - 32px); margin: auto; overflow: auto; }
.appointment-dialog::backdrop { background: color-mix(in srgb, var(--color-coat) 33%, transparent); }
body:has(.appointment-dialog[open]) { overflow: hidden; }
.appointment-dialog__toolbar { display: flex; align-items: center; justify-content: space-between; padding: var(--space-3) var(--space-4) 0 var(--space-6); }
.appointment-dialog__toolbar .btn-icon { width: 40px; height: 40px; font-size: var(--text-3xl); }
.appointment-summary { padding: var(--space-5) var(--space-6); }
.appointment-summary h2 { font-size: var(--text-3xl); line-height: 1.25; margin: var(--space-3) 0 var(--space-1-5); }
.appointment-summary__patient { font-size: var(--text-sm); margin: 0; }
.appointment-facts { display: grid; gap: var(--space-3-5); margin: var(--space-6) 0 0; font-size: var(--text-sm); }
.appointment-facts > div { display: grid; grid-template-columns: 100px minmax(0, 1fr); gap: var(--space-3); }
.appointment-facts dt { color: var(--color-muted); }
.appointment-facts dd { margin: 0; white-space: pre-wrap; }
.appointment-note { padding: var(--space-4) var(--space-6); border-top: var(--rule-row); }
.appointment-note h3 { font-size: var(--text-sm); margin: 0 0 var(--space-2); }
.appointment-note p { margin: 0; white-space: pre-wrap; font-size: var(--text-sm); }
.appointment-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: var(--space-4) var(--space-6) var(--space-6); border-top: var(--rule-row); }
.appointment-actions .btn { white-space: normal; text-align: center; }
@media (max-width: 480px) {
  .appointment-summary { padding: var(--space-4); }
  .appointment-facts > div { grid-template-columns: 80px minmax(0, 1fr); }
  .appointment-actions { padding: var(--space-4); }
}
.calendar-event__edge::after { content: ''; position: absolute; left: 40%; width: 20%; top: 3px; border-top: 2px solid var(--color-accent); opacity: 0; }
.calendar-event:hover .calendar-event__edge::after, .calendar-event:focus .calendar-event__edge::after { opacity: 1; }
.diary-gutter { position: sticky; left: 0; background: var(--color-bg); z-index: 3; }
.diary-resource-head { border-bottom: var(--rule-row); }
.diary-half-hour { background: none; }
.diary-week-grid { --diary-columns: 7; }
@media (max-width: 680px) {
  .diary-screen > .topbar { gap: var(--space-1); padding: var(--space-2); }
  .diary-screen > .topbar .nav-context, .diary-screen > .topbar .topbar__search { display: none; }
  .calendar-help > span:first-child { display: none; }
  .calendar-help { padding-block: 0; }
}
.calendar-picker[open] { flex-basis: 100%; }
.calendar-picker form { padding-block: var(--space-1); }
.calendar-picker select { min-width: 0; max-width: 24rem; flex: 1; }
.diary-week-grid .diary-resource-head__cell a { text-decoration: none; }
.diary-week-grid .diary-resource-head__cell { padding-block: var(--space-3); }

.diary-screen > .topbar, .calendar-help { flex-shrink: 0; }
.diary-screen > .diary-main { flex: 1; }

/* The managed provider carries the same Roan mark in every channel. */
.provider-brand { display: inline-flex; align-items: center; gap: var(--space-3); }
.provider-brand img { flex: 0 0 auto; }
.provider-roan { border-inline-start: 3px solid var(--color-accent); padding-inline-start: var(--space-4); }

.provider-service h2 { font-size: var(--text-xl); margin-bottom: var(--space-2); }
.provider-service p:last-child { margin-bottom: 0; }

/* Reception's next actions stay near the top on a handheld visit overview. */
@media (max-width: 680px) {
  .visit-workspace > .visit-handover { order: -1; }
}

/* Focused work surfaces: quieter hierarchy and explicit secondary actions.
   These shared rules apply to every module without another asset request. */
.mobile-sections { display: none; }
.action-disclosure { max-width: 100%; }
.action-disclosure > summary { padding-inline: var(--space-3); border: var(--rule-row); border-radius: var(--radius-lg); font-size: var(--text-md); }
.action-disclosure[open] { flex-basis: 100%; }
.action-disclosure__body { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); padding-block: var(--space-3); }
.action-disclosure__body form { margin: 0; }
.note-template-picker > summary { font-size: var(--text-sm); font-weight: var(--font-medium-weight); }
.note-template-picker[open] > summary { margin-bottom: var(--space-2); }
.settings-list { display: grid; }
.settings-list__item { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) auto; gap: var(--space-4); align-items: center; padding: var(--space-4); border-bottom: var(--rule-row); text-decoration: none; color: var(--color-text); }
.settings-list__item > span { color: var(--color-muted); }
.settings-list__item:hover { background: var(--wash-hover); color: var(--color-text); }
.settings-list__item:focus-visible { outline-offset: -2px; }
.settings-list__item > span:last-child { font-size: var(--text-xl); }
.topbar__heading { min-width: 0; }
.topbar__title { text-wrap: balance; }
.panel__head, .t-label, .note-field__label { text-transform: none; letter-spacing: normal; font-size: var(--text-xs); }
.panel__head { font-weight: var(--font-strong-weight); color: var(--color-text); }
.btn, .input { border-radius: var(--radius-lg); }
@media (max-width: 680px) {








  .mobile-sections { display: block; min-width: 0; background: var(--color-bg); border-bottom: var(--rule-row); }
  .mobile-sections > summary { padding: var(--space-1) var(--space-3); min-height: var(--hit-touch); font-size: var(--text-sm); }
  .mobile-sections__current { margin-left: auto; color: var(--color-muted); font-weight: var(--font-medium-weight); }






  .btn, .input, summary { min-height: var(--hit-touch); }
  .nav-menu__toggle, .nav-search > summary { min-height: var(--hit-touch); }
  .settings-list__item { grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-1) var(--space-3); }
  .settings-list__item > strong { grid-column: 1; }
  .settings-list__item > span:nth-child(2) { grid-column: 1; font-size: var(--text-sm); }
  .settings-list__item > span:last-child { grid-column: 2; grid-row: 1 / 3; }
  .action-disclosure__body { align-items: stretch; }
  .action-disclosure__body > * { flex: 1 1 auto; }
}
@media print {
  .mobile-sections, .action-disclosure { display: none; }
}


/* A quiet, labelled sidebar: the work stays on the main canvas. Native
   fonts paint immediately; the compact mobile section chooser is unchanged. */


/* Narrower than this the header takes two rows -- measured, not assumed: one
   row from 955px, two at 945 and below -- and --chrome-height then names less
   than the header really occupies. Anything positioned against it would sit
   under the header or hang past the foot of the window, so on a tablet held
   upright nothing pins itself: the bar and both columns take their place in
   the page and scroll with it. Nothing is clipped and nothing is hidden. */

.today-summary .figure, .task-summary .figure { padding: var(--space-2-5) var(--space-3-5); }
.today-attention .attention-row[data-state="attention"] { background: var(--color-bg); border-left: 3px solid var(--state-attention-ink); }
.today-attention .attention-row__main a { color: var(--color-text); text-decoration: none; }
.today-attention .attention-row__main a:hover { text-decoration: underline; }
.workflow-tools { display: flex; flex-wrap: wrap; gap: var(--space-1-5); align-items: center; padding: var(--space-2) var(--shell-gutter); border-bottom: var(--rule-row); }
.workflow-tools__label { color: var(--color-muted); font-size: var(--text-sm); margin-right: var(--space-2); }
.task-summary .figure__note { font-size: var(--text-xs); }
.task-row:not([data-state="act"]):not([data-state="attention"]) { border-left-color: transparent; }
.task-row__more > summary { min-height: var(--hit-min); display: flex; align-items: center; cursor: pointer; }
@media (max-width: 680px) {
  .today-summary .figure__note, .task-summary .figure__note { display: none; }
  .today-summary .figure, .task-summary .figure { display: flex; flex-wrap: wrap; gap: var(--space-1); align-items: baseline; }
  .today-summary .t-label, .task-summary .t-label { flex: 1 1 auto; }
  .today-summary .figure__value, .task-summary .figure__value { font-size: var(--text-figure); }
  .workflow-tools .btn { flex: 1 1 auto; }
}


.rx-editor { width: 100%; max-width: 880px; min-width: 0; margin-inline: auto; padding: var(--space-4); box-sizing: border-box; }
.rx-editor .field { margin-block: var(--space-3); }
.rx-editor .actionbar { margin-top: var(--space-5); }

.rx-editor .field__label { display: block; margin-bottom: var(--space-1); color: var(--color-muted-strong); font-size: var(--text-sm); font-weight: var(--font-medium-weight); }
.rx-editor .input { width: 100%; min-width: 0; }
.rx-editor .rx-confirm { display: flex; align-items: flex-start; gap: var(--space-2); margin-block: var(--space-3); }
.rx-editor textarea { resize: vertical; }
.medicine-sections__more { position: relative; }
.medicine-sections__more > summary { list-style: none; cursor: pointer; }
.medicine-sections__more > summary::-webkit-details-marker { display: none; }
.medicine-sections__menu { position: absolute; z-index: 20; right: 0; min-width: 180px; padding: var(--space-1); background: var(--color-bg); border: var(--rule-row); border-radius: var(--radius-lg); display: grid; }

.rx-editor > .t-name { font-size: var(--text-xl); margin-block: 0 var(--space-1); }
.rx-editor .rx-treatment { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.rx-treatment > .field:nth-child(-n+2), .rx-treatment > .field:last-child { grid-column: 1 / -1; }
.rx-treatment > .field { display: flex; flex-direction: column; }
.rx-treatment .input { margin-top: auto; }

/* Specialist workflows keep ordinary screens compact. */
.fi-form { max-width: 880px; padding: var(--space-4); box-sizing: border-box; }
.fi-form .form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.fi-form .input { min-width: 0; width: 100%; }
.fi-form .actionbar { flex-wrap: wrap; }
.fi-signature { margin-top: 3rem; border-top: var(--rule-row); padding-top: .5rem; }
@media (max-width: 680px) { .fi-form .form-grid { grid-template-columns: 1fr; } }
@media print { .fi-prescription .no-print, .app-header { display: none !important; } .fi-prescription { max-width: none; } }

.fi-tabs { display: flex; flex-wrap: nowrap; overflow-x: auto; max-width: 100%; scrollbar-width: thin; }
.fi-tabs .seg-opt { flex: 0 0 auto; white-space: nowrap; }
.fi-secondary-actions { flex-basis: 100%; }
.fi-secondary-actions > summary { display: flex; align-items: center; min-height: var(--hit-min); cursor: pointer; color: var(--color-muted-strong); }
.fi-secondary-actions .actionbar { margin-block: var(--space-2); }
.fi-particulars { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: var(--space-2) var(--space-3); }
.fi-particulars dt { color: var(--color-muted); }
.fi-particulars dd { margin: 0; overflow-wrap: anywhere; }
.fi-form .field { min-width: 0; margin: 0; }
.fi-form .field__label { display: block; margin-bottom: var(--space-1); }
@media (max-width: 680px) { .fi-form .actionbar > .btn { flex: 1 1 auto; } .fi-particulars { grid-template-columns: 1fr; } .fi-particulars dd { margin-bottom: var(--space-2); } }

@media (max-width: 680px) {
  .today-attention-heading { flex-wrap: nowrap; gap: var(--space-2); }
  .today-attention-heading .panel__count { display: none; }
  .today-attention-heading .btn { flex: 0 0 auto; margin-left: auto; }
}

.nav-brand__name { font-size: var(--text-lg); font-weight: var(--font-strong-weight); }
.nav-account { margin-left: var(--space-4); }
.nav-account__name { font-size: var(--text-sm); }
.nav-search__icon { display: inline-flex; flex: none; }
.nav-search__extended { display: inline; }
@media (min-width: 681px) {
  .nav-search > summary { min-width: 14rem; }
  .nav-search[open] { order: 4; }
  .shell--rail > .panel > .panel__body > .panel > .panel__head { padding-inline: var(--shell-gutter); }
  .today-summary .figure, .task-summary .figure { padding: var(--space-4) var(--shell-gutter); }
  .today-attention .attention-row { padding-inline: var(--shell-gutter); }
  .today-topbar .topbar__search { display: none; }
}
@media (min-width: 681px) and (max-width: 950px) {
  .nav-search > summary { min-width: 0; }
  .nav-search__extended { display: none; }
  .nav-brand__name { max-width: 12rem; }
  .nav-account { margin-left: auto; }
}
@media (max-width: 680px) {
  :root { --shell-gutter: var(--space-3); }
  .nav-search__extended, .nav-search__icon { display: none; }
  .nav-search > summary { padding-inline: var(--space-2); }
  .mobile-sections__current { min-width: 0; text-align: right; }


  .topbar { min-height: var(--hit-touch); }
}

/* With no room left below an expanded header, let navigation flow normally. */



/* Search has one home. Page-specific filters remain beside their own results. */
body:has([data-global-search]) .topbar__search:has([data-command-line]) { display: none; }
@media (min-width: 681px) and (max-width: 950px) {
  /* Three clinical lanes or a till beside a ledger cannot fit in a tablet's
     remaining canvas once navigation is present. Keep each region readable. */
  .workspace--consult, .workspace--wide-rail { grid-template-columns: minmax(0, 1fr); }
  .workspace--consult > * + *, .workspace--wide-rail > * + * { border-left: 0; border-top: var(--rule-region); }
  .consult-columns > .consult-history { order: 2; }
  .consult-columns > .consult-capture { order: 3; }
  .band { flex-wrap: wrap; gap: var(--space-3) 0; }
  .band__cell { flex: 1 1 50%; width: auto; }
  .band__cell--identity { flex-basis: 100%; }
}
.nav-search__body { min-width: 0; }
.nav-search__body .cmd { min-width: 0; width: 100%; }
@media (max-width: 680px) {
  .nav-search__body .cmd__hint { display: none; }
  .nav-search__body .cmd__input { width: 0; min-width: 0; }
}

@media (min-width: 681px) and (max-width: 950px) {
  /* The ledger keeps its columns inside its region when their minimum widths
     exceed the canvas left beside navigation. */
  .workspace--wide-rail .table { position: relative; display: block; max-width: 100%; overflow-x: auto; }
}

/* ── Unified workspace navigation ─────────────────────────────────────────
   One column for the product map and its on-demand page trees. Clinical
   side lanes remain part of their own screens. */
.shell--rail { grid-template-columns: var(--workspace-width) minmax(0, 1fr); }
body[data-nav-pages="collapsed"] .shell--rail { grid-template-columns: var(--workspace-compact) minmax(0, 1fr); }
.workspace-sidebar {
  display: flex; flex-direction: column; min-width: 0;
  background: var(--workspace-surface); border-right: var(--rule-row);
  position: sticky; top: var(--header-offset, var(--chrome-height));
  height: calc(100dvh - var(--header-offset, var(--chrome-height)) - var(--footer-offset));
  align-self: start; overflow: hidden;
}
.workspace-navigation { padding: var(--space-3) var(--space-2); min-width: 0; }
.workspace-sidebar > .workspace-navigation { flex: 1; min-height: 0; overflow-y: auto; scrollbar-width: thin; }
.workspace-group + .workspace-group { margin-top: var(--space-4); }
.workspace-group__title {
  display: flex; align-items: center; justify-content: space-between;
  margin: 0; padding: var(--space-1-5) var(--space-2-5);
  font-size: var(--text-2xs); font-weight: var(--font-medium-weight); color: var(--color-muted);
  line-height: 1.5; letter-spacing: .02em;
}
.workspace-group__title svg { width: var(--space-3); height: var(--space-3); }
.workspace-area { min-width: 0; margin-top: var(--space-0-5); }
.workspace-area__heading {
  display: flex; gap: 0; min-height: var(--hit-min); padding: 0;
  border-radius: var(--radius-lg); color: var(--color-muted-strong); position: relative;
}
.workspace-area__heading::before, .workspace-page__options > summary::before { content: none; }
.workspace-link {
  display: flex; flex: 1; min-width: 0; align-items: center; gap: var(--space-2-5);
  min-height: var(--hit-min); padding: var(--space-1) var(--space-2-5);
  color: var(--color-muted-strong); text-decoration: none; font-size: var(--text-sm);
  border-radius: var(--radius-lg); font-weight: var(--font-medium-weight); line-height: 1.35;
}
.workspace-link svg { width: var(--space-4); height: var(--space-4); flex: none; }
.workspace-link__label { min-width: 0; }
.workspace-link:hover { color: var(--color-text); text-decoration: none; }
.workspace-area__heading:hover, .workspace-link--pinned:hover { background: var(--wash-hover); color: var(--color-text); }
.workspace-area--active > .workspace-area__heading { background: var(--workspace-selected); }
.workspace-area--active > .workspace-area__heading .workspace-link { color: var(--color-text); font-weight: var(--font-strong-weight); }
.workspace-area__chevron { display: grid; place-items: center; width: var(--hit-min); align-self: stretch; font-size: var(--text-xl); color: var(--color-muted); }
.workspace-area[open] > .workspace-area__heading .workspace-area__chevron { transform: rotate(90deg); }
.workspace-pages { border-left: var(--rule-row); margin: var(--space-1) var(--space-2) var(--space-2) var(--space-4-5); padding-left: var(--space-2); }
.workspace-page { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; border-radius: var(--radius-md); }
.workspace-page--current { background: var(--color-bg); box-shadow: var(--shadow-sm); }
.workspace-page__link { display: flex; align-items: center; min-height: var(--hit-min); padding: var(--space-1) var(--space-2); color: var(--color-muted-strong); font-size: var(--text-sm); line-height: 1.35; text-decoration: none; }
.workspace-page__link:hover { color: var(--color-text); text-decoration: none; }
.workspace-page--current > .workspace-page__link { color: var(--color-text); font-weight: var(--font-strong-weight); }
.workspace-page:hover { background: var(--color-bg); }
.workspace-page__options { display: contents; }
.workspace-page__options > summary { display: grid; place-items: center; padding: 0; min-height: var(--hit-min); width: var(--space-7); color: var(--color-muted); font-size: var(--text-base); grid-column: 2; }
.workspace-page__options::details-content { display: contents; }
.workspace-page__options:not([open])::details-content { display: none; }
.workspace-page__menu { grid-column: 1 / -1; display: grid; padding: var(--space-1) var(--space-2); border-top: var(--rule-row); background: var(--color-bg); }
.workspace-page__menu form { margin: 0; }
.workspace-page__menu a, .workspace-page__menu button { display: flex; align-items: center; min-height: var(--hit-min); padding: 0; border: 0; background: none; color: var(--color-muted-strong); font: inherit; font-size: var(--text-2xs); text-align: left; cursor: pointer; text-decoration: none; }
.workspace-page__menu a:hover, .workspace-page__menu button:hover { color: var(--color-text); text-decoration: underline; }
.workspace-subgroup > summary { min-height: var(--hit-min); gap: var(--space-2); padding: var(--space-1) var(--space-2); font-size: var(--text-2xs); line-height: 1.4; color: var(--color-muted); }
.workspace-link--pinned[aria-current="page"] { background: var(--workspace-selected); color: var(--color-text); }
.workspace-sidebar__foot { display: flex; justify-content: space-between; align-items: center; gap: var(--space-2); padding: var(--space-3) var(--space-4); border-top: var(--rule-row); font-size: var(--text-2xs); color: var(--color-muted); }
.workspace-sidebar :focus-visible, .workspace-drawer :focus-visible { outline-color: var(--color-accent); outline-offset: -2px; }

/* The practice, working location, trail and account share one quiet band. */
.app-header:has(.nav--workspace) { background: var(--color-bg); border-bottom: var(--rule-row); }
.nav.nav--workspace { display: flex; flex-wrap: nowrap; gap: var(--space-3); background: var(--color-bg); color: var(--color-text); min-height: var(--chrome-height); padding: var(--space-2) var(--space-3); }
.workspace-toggle { flex: none; margin: 0; }
.workspace-toggle__button { display: grid; place-items: center; width: var(--hit-min); height: var(--hit-min); padding: 0; border: 0; border-radius: var(--radius-md); background: none; color: var(--color-muted); cursor: pointer; }
.workspace-toggle__button:hover { background: var(--wash-hover); color: var(--color-text); }
.nav--workspace .nav-brand { flex: none; min-width: 0; gap: var(--space-2); margin-right: 0; width: calc(var(--workspace-width) - var(--space-6) - var(--hit-min) - var(--space-3)); }
.nav--workspace .nav-brand__name { font-size: var(--text-sm); max-width: 11rem; line-height: 1.3; }
.nav--workspace .nav-monogram { width: var(--space-7); height: var(--space-7); font-size: var(--text-2xs); }
.nav--workspace .nav-context { min-width: 0; flex: none; padding: 0 var(--space-3); border-left: var(--rule-row); }
.nav--workspace .nav-context__label { font-size: var(--text-3xs); text-transform: none; letter-spacing: 0; color: var(--color-muted); }
.nav--workspace .nav-context__value { font-size: var(--text-sm); }
.nav--workspace .nav-context .text-muted { color: var(--color-muted); }
.workspace-trail { font-size: var(--text-sm); min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.workspace-trail a, .workspace-trail span { overflow: hidden; text-overflow: ellipsis; }
.nav--workspace .nav-account { margin-left: var(--space-1); flex: none; gap: var(--space-3); }
.nav--workspace .nav-account__who { flex-direction: row; align-items: center; gap: var(--space-2); text-align: left; }
.nav-account__avatar { display: grid; place-items: center; width: var(--space-8); height: var(--space-8); border: var(--rule-row); border-radius: var(--radius-lg); background: var(--workspace-surface); color: var(--color-muted-strong); font-size: var(--text-2xs); font-weight: var(--font-strong-weight); }
.nav--workspace .btn-secondary { color: var(--color-muted-strong); border-color: var(--color-divider); background: transparent; }
.nav--workspace .btn-secondary:hover { color: var(--color-text); background: var(--wash-hover); border-color: var(--color-divider-strong); }
.nav--workspace :focus-visible { outline-color: var(--color-accent); }
.nav--workspace .nav-search, .nav--workspace .nav-search[open] { margin-left: auto; flex: 0 1 17rem; order: 0; position: relative; }
.nav--workspace .nav-search > summary { min-width: 0; min-height: var(--hit-min); background: var(--workspace-surface); color: var(--color-muted); border: var(--rule-row); padding-inline: var(--space-2-5); }
.nav--workspace .nav-search > summary:hover { color: var(--color-text); border-color: var(--color-divider-strong); }
.nav--workspace .nav-search .kbd { background: var(--color-bg); border-color: var(--color-divider); color: var(--color-muted); }
.nav--workspace .nav-search__body { position: absolute; right: 0; top: calc(100% + var(--space-2)); width: min(var(--workspace-search-width), calc(100vw - var(--space-6))); padding: var(--space-3); background: var(--color-bg); border: var(--rule-row); border-radius: var(--radius-lg); box-shadow: var(--shadow-md); z-index: 80; }
.nav--workspace .nav-search__body p { color: var(--color-muted); }
.nav--workspace .nav-search__body .cmd { border: var(--rule-row); border-radius: var(--radius-md); }
.nav--workspace:has(.nav-install:not([hidden])) { flex-wrap: wrap; }
.nav--workspace .nav-install { color: var(--color-muted); border-color: var(--color-divider); }
body:not(:has(.workspace-sidebar)) .workspace-toggle { display: none; }

@media (min-width: 681px) {
  body[data-nav-pages="collapsed"] .workspace-sidebar .workspace-group__title,
  body[data-nav-pages="collapsed"] .workspace-sidebar .workspace-link__label,
  body[data-nav-pages="collapsed"] .workspace-sidebar .workspace-area__chevron,
  body[data-nav-pages="collapsed"] .workspace-sidebar .workspace-pages,
  body[data-nav-pages="collapsed"] .workspace-sidebar__foot { display: none; }
  body[data-nav-pages="collapsed"] .workspace-sidebar .workspace-link { justify-content: center; padding: var(--space-2) 0; }
  body[data-nav-pages="collapsed"] .workspace-sidebar .workspace-group + .workspace-group { border-top: var(--rule-row); padding-top: var(--space-2); margin-top: var(--space-2); }
}
@media (max-width: 1200px) {
  .nav--workspace .workspace-trail { display: none; }
  .nav--workspace .nav-brand__name { max-width: 9rem; }
}
@media (min-width: 681px) and (max-width: 950px) {
  .nav--workspace .nav-account__name { display: none; }
  .nav--workspace .nav-search__extended { display: none; }
  .nav--workspace .nav-search > summary .kbd { display: none; }
  .nav--workspace .nav-brand__name { max-width: 7rem; }
}
.workspace-drawer__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-3); border-bottom: var(--rule-row); font-size: var(--text-sm); }
.mobile-sections__icon { display: flex; }
.mobile-sections__icon svg { width: var(--space-4); height: var(--space-4); }
@media (max-width: 680px) {
  .shell--rail, body[data-nav-pages="collapsed"] .shell--rail { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); }
  .workspace-sidebar, .workspace-toggle { display: none; }
  .nav.nav--workspace { display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; gap: var(--space-2); padding: var(--space-1-5) var(--space-3); }
  .nav--workspace .nav-brand { grid-column: 1; grid-row: 1; width: auto; }
  .nav--workspace .nav-brand__name { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .nav--workspace .nav-context { grid-column: 2; grid-row: 1; padding: 0; border-left: 0; }
  .nav--workspace .nav-context__label { position: static; width: auto; height: auto; clip: auto; overflow: visible; }
  .nav--workspace .nav-context__value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .nav--workspace .nav-search, .nav--workspace .nav-search[open], .nav--workspace .nav-menu { display: contents; }
  .nav--workspace .nav-search > summary { grid-column: 3; grid-row: 1; min-height: var(--hit-touch); padding: 0 var(--space-2); background: transparent; border: 0; }
  .nav--workspace .nav-search__body { position: static; grid-column: 1 / -1; width: 100%; box-shadow: none; padding: var(--space-2); }
  .nav--workspace .nav-account { display: none; }
  .nav--workspace .nav-menu__toggle { grid-column: 4; grid-row: 1; min-height: var(--hit-touch); color: var(--color-text); border-color: var(--color-divider); }
  .nav--workspace .nav-menu__toggle:hover { background: var(--wash-hover); }
  .nav--workspace .nav-menu[open] > .nav-menu__toggle { color: var(--color-text); background: var(--workspace-selected); }
  .nav--workspace .nav-menu__body { grid-column: 1 / -1; color: var(--color-text); border-color: var(--color-divider); }
  .nav--workspace .nav-menu__practice { color: var(--color-muted); }
  .nav--workspace .nav-menu__link { color: var(--color-muted-strong); border-color: var(--color-divider); }
  .nav--workspace .nav-menu__link:hover { color: var(--color-text); }
  .nav--workspace .nav-menu__link[aria-current="page"] { color: var(--color-text); box-shadow: none; font-weight: var(--font-strong-weight); }
  .mobile-sections { background: var(--workspace-surface); }
  .mobile-sections > summary { gap: var(--space-2); }
  .mobile-sections > summary::before { content: none; }
  .mobile-sections .workspace-navigation { padding: var(--space-2); }
  .mobile-sections .workspace-group + .workspace-group { margin-top: var(--space-3); }
  .mobile-sections .workspace-link, .mobile-sections .workspace-page__link,
  .mobile-sections .workspace-page__options > summary,
  .mobile-sections .workspace-page__menu a, .mobile-sections .workspace-page__menu button,
  .mobile-sections .workspace-subgroup > summary { min-height: var(--hit-touch); }
  .mobile-sections .workspace-page__options > summary { width: var(--hit-touch); }
  .mobile-sections[data-drawer-ready][open] .workspace-drawer { position: fixed; inset: var(--header-offset, var(--chrome-height)) 0 0; background: var(--workspace-surface); z-index: 70; overflow-y: auto; padding-bottom: var(--inset-bottom); }
  body:has(.mobile-sections[data-drawer-ready][open]) { overflow: hidden; }
}
@media print {
  .workspace-sidebar, .mobile-sections, .workspace-toggle, .workspace-trail { display: none !important; }
  .shell--rail, body[data-nav-pages="collapsed"] .shell--rail { display: block; }
}


/* Direct calendar booking: appointments sit above the native slot links. */
.calendar-slot { display: block; position: relative; color: var(--color-muted); text-decoration: none; }
.calendar-slot__label { display: none; padding: var(--space-2); font-size: var(--text-xs); }
.calendar-slot:focus-visible { outline: 2px solid var(--color-accent); outline-offset: -2px; background: var(--wash-accent); }
.calendar-slot:focus-visible .calendar-slot__label { display: block; }
@media (hover: hover) {
  .calendar-slot:hover { background: var(--wash-accent); text-decoration: none; }
  .calendar-slot:hover .calendar-slot__label { display: block; }
}
.diary-column .calendar-event { z-index: 1; }
.appointment-summary > .appointment-actions { margin-block: var(--space-3); }
.diary-column .calendar-event.is-dragging { z-index: 10; }
