/* =========================================================================
   Aesthetica — design system
   A calm clinical surface: warm neutrals, one deep teal accent, generous
   spacing, and type that stays readable on a tablet at arm's length.
   ========================================================================= */

/* `hidden` means hidden.
 *
 * The browser's own `[hidden] { display: none }` lives in the user-agent
 * stylesheet, which every rule in this file outranks — so any class that sets
 * `display` (and most of the layout here does) quietly un-hides an element
 * that JavaScript has marked hidden. It has already been patched once, one
 * selector at a time, further down this file; a button that appeared before
 * there was anything behind it made the case for saying it once, here.
 */
[hidden] { display: none !important; }

:root {
  /* neutrals */
  --bg:           #f7f6f3;
  --surface:      #ffffff;
  --surface-2:    #fbfaf8;
  --surface-3:    #f2f0ec;
  --line:         #e4e1db;
  --line-strong:  #cfcbc2;
  --ink:          #1c1f1e;
  --ink-2:        #4a504e;
  --ink-3:        #7b827f;
  --ink-4:        #a8ada9;

  /* brand */
  --accent:       #0f766e;
  --accent-ink:   #ffffff;
  --accent-soft:  #e3f2ef;
  --accent-line:  #b7ddd6;
  --accent-deep:  #0d3b36;

  /* semantic */
  --ok:      #15803d;   --ok-soft:      #e6f4ea;
  --warn:    #b45309;   --warn-soft:    #fdf1e0;
  --danger:  #b42318;   --danger-soft:  #fdeceb;
  --info:    #1d4ed8;   --info-soft:    #e8eefc;
  --purple:  #6d28d9;   --purple-soft:  #f0e9fd;

  /* appointment types */
  --t-consultation: #0f766e;
  --t-follow_up:    #2563eb;
  --t-surgery:      #b42318;
  --t-injectable:   #7c3aed;
  --t-laser:        #c2410c;
  --t-skin:         #0d9488;
  --t-dressing:     #b45309;
  --t-photo:        #0891b2;
  --t-other:        #64748b;
  --t-blocked:      #94a3b8;

  /* Who wrote it. Orange is the assistant, green the secretary; the surgeon's
     own entries carry no colour, because most of the record is his. */
  --by-assistant:      #c2410c;
  --by-assistant-soft: #fdf0e7;
  --by-secretary:      #15803d;
  --by-secretary-soft: #e9f6ed;
  --by-admin:          #64748b;
  --by-admin-soft:     #f1f3f5;

  --radius:    12px;
  --radius-sm: 8px;
  --radius-lg: 18px;
  --shadow-1: 0 1px 2px rgba(20,25,24,.05), 0 1px 3px rgba(20,25,24,.04);
  --shadow-2: 0 2px 4px rgba(20,25,24,.05), 0 8px 24px rgba(20,25,24,.07);
  --shadow-3: 0 12px 48px rgba(20,25,24,.16);

  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --sidebar-w: 232px;
  --header-h: 60px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:          #121514;
    --surface:     #1a1e1d;
    --surface-2:   #1f2423;
    --surface-3:   #272d2b;
    --line:        #2e3533;
    --line-strong: #414a47;
    --ink:         #eef1f0;
    --ink-2:       #b9c0bd;
    --ink-3:       #8a918e;
    --ink-4:       #646b68;
    --accent:      #4db6a5;
    --accent-ink:  #06231f;
    --accent-soft: #13312c;
    --accent-line: #1e4a43;
    --accent-deep: #8ed6c6;
    --ok: #4ade80;      --ok-soft: #14301f;
    --warn: #fbbf24;    --warn-soft: #33260c;
    --danger: #f87171;  --danger-soft: #3a1a19;
    --info: #7ea6ff;    --info-soft: #16203a;
    --purple: #b18aff;  --purple-soft: #241a3d;
    --by-assistant: #fb923c;  --by-assistant-soft: #3a2213;
    --by-secretary: #4ade80;  --by-secretary-soft: #14301f;
    --by-admin: #94a3b8;      --by-admin-soft: #262b2f;
    --shadow-1: 0 1px 2px rgba(0,0,0,.4);
    --shadow-2: 0 2px 4px rgba(0,0,0,.35), 0 8px 24px rgba(0,0,0,.35);
    --shadow-3: 0 12px 48px rgba(0,0,0,.55);
  }
}

:root[data-theme="dark"] {
  --bg:          #121514;  --surface: #1a1e1d;  --surface-2: #1f2423;  --surface-3: #272d2b;
  --line:        #2e3533;  --line-strong: #414a47;
  --ink:         #eef1f0;  --ink-2: #b9c0bd;    --ink-3: #8a918e;      --ink-4: #646b68;
  --accent:      #4db6a5;  --accent-ink: #06231f; --accent-soft: #13312c; --accent-line: #1e4a43;
  --accent-deep: #8ed6c6;
  --ok: #4ade80;   --ok-soft: #14301f;
  --warn: #fbbf24; --warn-soft: #33260c;
  --by-assistant: #fb923c;  --by-assistant-soft: #3a2213;
  --by-secretary: #4ade80;  --by-secretary-soft: #14301f;
  --by-admin: #94a3b8;      --by-admin-soft: #262b2f;
  --danger: #f87171; --danger-soft: #3a1a19;
  --info: #7ea6ff; --info-soft: #16203a;
  --purple: #b18aff; --purple-soft: #241a3d;
  --shadow-1: 0 1px 2px rgba(0,0,0,.4);
  --shadow-2: 0 2px 4px rgba(0,0,0,.35), 0 8px 24px rgba(0,0,0,.35);
  --shadow-3: 0 12px 48px rgba(0,0,0,.55);
}

/* ------------------------------------------------------------------ reset */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html, body { height: 100%; }
body {
  font-family: var(--sans);
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img, svg, video, canvas { display: block; max-width: 100%; }
/* Icons default to a sensible inline size; component rules below override. */
svg { width: 17px; height: 17px; flex: none; }
h1 > svg, h2 > svg, h3 > svg, h4 > svg, p > svg, span > svg, b > svg, a > svg, label > svg,
.list-item > svg, .day-item > svg, .alert-banner > svg, .hx-flag > svg {
  display: inline-block; vertical-align: -3px; color: var(--ink-3);
}
.alert-banner > svg, .hx-flag > svg, h1 > svg, h2 > svg, h3 > svg { color: currentColor; }
.chip svg { display: inline-block; width: 14px; height: 14px; vertical-align: -2px; margin-right: 4px; }
button, input, select, textarea { font: inherit; color: inherit; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3, h4 { font-weight: 600; line-height: 1.25; letter-spacing: -0.011em; }
h1 { font-size: 1.5rem; } h2 { font-size: 1.15rem; } h3 { font-size: 1rem; } h4 { font-size: .875rem; }
::selection { background: var(--accent-soft); color: var(--ink); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

/* --------------------------------------------------------------- booting */
.app-loading { display: grid; place-items: center; min-height: 100dvh; }
.boot { text-align: center; color: var(--ink-3); animation: fade .5s ease; }
.boot-mark { width: 44px; height: 44px; margin: 0 auto 12px; color: var(--accent); }
.boot p { font-size: .8rem; letter-spacing: .16em; text-transform: uppercase; }
@keyframes fade { from { opacity: 0 } to { opacity: 1 } }

/* =================================================================== login */
.login-wrap {
  min-height: 100dvh; display: grid; place-items: center; padding: 24px;
  background:
    radial-gradient(1200px 600px at 15% -10%, var(--accent-soft), transparent 60%),
    radial-gradient(900px 500px at 110% 110%, var(--surface-3), transparent 55%),
    var(--bg);
}
.login-card {
  width: 100%; max-width: 400px; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 34px 30px; box-shadow: var(--shadow-2);
}
.login-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 26px; }
.login-brand svg { width: 30px; height: 30px; color: var(--accent); }
.login-brand b { font-size: 1.06rem; letter-spacing: -.02em; }
.login-brand span { color: var(--ink-3); font-size: .74rem; letter-spacing: .13em; text-transform: uppercase; display: block; }

/* ================================================================= layout */
.shell { display: grid; grid-template-columns: var(--sidebar-w) 1fr; min-height: 100dvh; }

.sidebar {
  background: var(--accent-deep);
  color: #cfe6e0;
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100dvh; overflow-y: auto;
}
:root[data-theme="dark"] .sidebar,
:root:not([data-theme="light"]) .sidebar { background: #0c100f; border-right: 1px solid var(--line); }

.sidebar-brand { display: flex; align-items: center; gap: 10px; padding: 18px 18px 14px; }
.sidebar-brand svg { width: 26px; height: 26px; color: #8ed6c6; flex: none; }
.sidebar-brand b { color: #fff; font-size: .98rem; letter-spacing: -.015em; }
.sidebar-brand small { display: block; color: #7fa9a0; font-size: .66rem; letter-spacing: .14em; text-transform: uppercase; }

.nav { padding: 6px 10px; display: flex; flex-direction: column; gap: 1px; flex: 1; }
.nav-section { padding: 14px 8px 5px; font-size: .65rem; letter-spacing: .13em; text-transform: uppercase; color: #6e948c; }
.nav a {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: var(--radius-sm);
  color: #cfe6e0; font-size: .875rem; font-weight: 500; text-decoration: none; transition: background .12s, color .12s;
}
.nav a svg { width: 17px; height: 17px; flex: none; opacity: .8; }
.nav a:hover { background: rgba(255,255,255,.07); color: #fff; text-decoration: none; }
.nav a.active { background: rgba(255,255,255,.13); color: #fff; }
.nav a.active svg { opacity: 1; color: #8ed6c6; }
.nav .badge { margin-left: auto; background: rgba(255,255,255,.16); color: #fff; font-size: .68rem;
  padding: 1px 6px; border-radius: 20px; font-weight: 600; }

.sidebar-foot { padding: 12px 14px 16px; border-top: 1px solid rgba(255,255,255,.08); }
.sidebar-user { display: flex; align-items: center; gap: 9px; }
.sidebar-user .avatar { width: 30px; height: 30px; border-radius: 50%; background: #8ed6c6; color: #0d3b36;
  display: grid; place-items: center; font-weight: 700; font-size: .76rem; flex: none; }
.sidebar-user b { color: #fff; font-size: .8rem; display: block; line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar-user span { color: #7fa9a0; font-size: .7rem; text-transform: capitalize; }

.main { display: flex; flex-direction: column; min-width: 0; }

.topbar {
  height: var(--header-h); display: flex; align-items: center; gap: 14px; padding: 0 22px;
  background: color-mix(in srgb, var(--surface) 85%, transparent);
  backdrop-filter: saturate(1.6) blur(10px);
  border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 30;
}
/* A long page title truncates rather than shoving the search box off the
   right-hand edge, which is what it used to do on a narrow screen. */
.topbar h1 {
  font-size: 1.06rem; font-weight: 600; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
.topbar .spacer { flex: 1; }

.search-box { position: relative; flex: 1; max-width: 340px; }
.search-box input {
  width: 100%; padding: 7px 12px 7px 32px; border: 1px solid var(--line); border-radius: 20px;
  background: var(--surface-3); font-size: .84rem;
}
.search-box input:focus { outline: none; border-color: var(--accent); background: var(--surface); }
.search-box svg { position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  width: 15px; height: 15px; color: var(--ink-4); pointer-events: none; }
.search-results {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-3);
  max-height: 380px; overflow-y: auto; z-index: 50;
}
.search-results a { display: block; padding: 9px 12px; border-bottom: 1px solid var(--line); color: var(--ink); }
.search-results a:last-child { border-bottom: 0; }
.search-results a:hover { background: var(--surface-3); text-decoration: none; }
.search-results small { color: var(--ink-3); }

.content { padding: 22px; flex: 1; min-width: 0; }
.content.flush { padding: 0; }

/* mobile */
.mobile-nav { display: none; }
@media (max-width: 900px) {
  .shell { grid-template-columns: 1fr; }
  .sidebar { display: none; }
  .content { padding: 14px 14px 84px; }
  .topbar { padding: 0 14px; }
  .topbar h1 { font-size: .98rem; }
  .mobile-nav {
    display: flex; position: fixed; bottom: 0; left: 0; right: 0; z-index: 40;
    background: color-mix(in srgb, var(--surface) 94%, transparent); backdrop-filter: blur(12px);
    border-top: 1px solid var(--line); padding: 6px 4px calc(6px + env(safe-area-inset-bottom));
  }
  .mobile-nav a { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px;
    padding: 5px 2px; color: var(--ink-3); font-size: .63rem; text-decoration: none; }
  .mobile-nav a svg { width: 19px; height: 19px; }
  .mobile-nav a.active { color: var(--accent); }
  /* On the bar the count rides the icon rather than taking a line of its own. */
  .mobile-nav a { position: relative; }
  .mobile-nav .nav-badge {
    position: absolute; top: 0; left: 50%; margin: 0; transform: translateX(4px);
    min-width: 15px; padding: 0 4px; line-height: 15px; font-size: .6rem;
    background: var(--accent); color: #fff;
  }
  .mobile-nav .nav-badge.urgent { background: var(--danger); }
}

/* ================================================================== cards */
.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-1);
}
.card-head {
  display: flex; align-items: center; gap: 10px; padding: 13px 16px; border-bottom: 1px solid var(--line);
}
.card-head h2, .card-head h3 { font-size: .93rem; font-weight: 600; }
.card-head .spacer { flex: 1; }
.card-body { padding: 16px; }
.card-body.tight { padding: 10px 12px; }
.card + .card { margin-top: 16px; }

/* Grid items default to `min-width: auto`, which means they refuse to shrink
   below their content — so one wide table inside a card pushes the whole
   column, and the page, sideways. This is the standard fix and it belongs
   here rather than being rediscovered per screen. */
.grid { display: grid; gap: 16px; }
.grid > * { min-width: 0; }
.grid.c2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid.c3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid.c4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid.sidebar-right { grid-template-columns: minmax(0,1fr) 330px; align-items: start; }
@media (max-width: 1100px) { .grid.c4 { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .grid.sidebar-right { grid-template-columns: 1fr; } }
@media (max-width: 760px) { .grid.c2, .grid.c3, .grid.c4 { grid-template-columns: 1fr; } }

/* stat tiles */
.stat { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 15px 16px; }
.stat .label { font-size: .72rem; color: var(--ink-3); text-transform: uppercase; letter-spacing: .07em; font-weight: 600; }
.stat .value { font-size: 1.6rem; font-weight: 600; letter-spacing: -.025em; margin-top: 4px; font-variant-numeric: tabular-nums; }
.stat .sub { font-size: .78rem; color: var(--ink-3); margin-top: 2px; }
.stat.accent { background: var(--accent-soft); border-color: var(--accent-line); }
.stat.warn { background: var(--warn-soft); border-color: color-mix(in srgb, var(--warn) 30%, transparent); }

/* ================================================================ buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 7px 13px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); font-size: .84rem; font-weight: 550;
  cursor: pointer; transition: background .12s, border-color .12s, transform .06s; white-space: nowrap;
}
.btn:hover { background: var(--surface-3); }
.btn:active { transform: translateY(.5px); }
.btn svg { width: 15px; height: 15px; }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn.primary:hover { background: color-mix(in srgb, var(--accent) 88%, black); }
.btn.danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn.danger:hover { filter: brightness(.93); }
.btn.ghost { background: transparent; border-color: transparent; color: var(--ink-2); }
.btn.ghost:hover { background: var(--surface-3); color: var(--ink); }
.btn.sm { padding: 4px 9px; font-size: .78rem; }
.btn.sm svg { width: 13px; height: 13px; }
.btn.lg { padding: 10px 18px; font-size: .92rem; }
.btn.block { width: 100%; }
.btn[disabled] { opacity: .5; cursor: not-allowed; }
.btn-row { display: flex; gap: 8px; flex-wrap: wrap; }

.icon-btn {
  display: grid; place-items: center; width: 30px; height: 30px; border-radius: var(--radius-sm);
  border: 1px solid transparent; background: transparent; color: var(--ink-3); cursor: pointer;
}
.icon-btn:hover { background: var(--surface-3); color: var(--ink); }
.icon-btn svg { width: 16px; height: 16px; }

/* ================================================================== forms */
.field { margin-bottom: 14px; }
.field > label, .label {
  display: block; font-size: .76rem; font-weight: 600; color: var(--ink-2); margin-bottom: 5px;
  letter-spacing: .01em;
}
/* Explanatory small print. It was only ever styled inside a field, so the
   seventy-odd hints written outside one — under cards, beside buttons — were
   rendering at full body weight and reading as instructions rather than as the
   quiet aside they are. */
.hint { font-size: .74rem; color: var(--ink-3); margin-top: 4px; line-height: 1.5; }
.field .hint { font-size: .74rem; color: var(--ink-3); margin-top: 4px; }
/* `input:not([type])` matters more than it looks. A plain `<input>` is a text
   input, but it does not match `input[type=text]` — that selector needs the
   attribute to be *written*. Every typeless input in the app was therefore
   falling back to the browser's default size (about 180px, ignoring the column
   it sits in), which is why the document title and the prescription directions
   were the same width as a field a quarter their length. `:not([type])` cannot
   catch a checkbox or a radio, because those always declare their type. */
input:not([type]),
input[type=text], input[type=email], input[type=password], input[type=number], input[type=date],
input[type=time], input[type=tel], input[type=datetime-local], input[type=search], select, textarea {
  width: 100%; padding: 8px 11px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); font-size: .875rem; transition: border-color .12s, box-shadow .12s;
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent);
}
input[disabled], textarea[disabled], select[disabled] { background: var(--surface-3); color: var(--ink-3); }
textarea { resize: vertical; min-height: 78px; line-height: 1.55; }
select { appearance: none; background-image:
  linear-gradient(45deg, transparent 50%, var(--ink-3) 50%), linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
  background-position: right 13px center, right 8px center; background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat; padding-right: 28px; }
.row { display: grid; gap: 12px; grid-template-columns: repeat(2, minmax(0,1fr)); }
.row.c3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
.row.c4 { grid-template-columns: repeat(4, minmax(0,1fr)); }
@media (max-width: 700px) { .row, .row.c3, .row.c4 { grid-template-columns: 1fr; } }

.check { display: flex; align-items: flex-start; gap: 9px; padding: 7px 0; cursor: pointer; }
.check input { width: 16px; height: 16px; margin-top: 2px; accent-color: var(--accent); flex: none; }
.check span { font-size: .85rem; }
.check small { display: block; color: var(--ink-3); font-size: .76rem; }

.switch-row { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 0; border-bottom: 1px solid var(--line); }
.switch-row:last-child { border-bottom: 0; }

.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  padding: 4px 10px; border-radius: 20px; border: 1px solid var(--line-strong); background: var(--surface);
  font-size: .78rem; cursor: pointer; user-select: none; transition: all .12s;
}
.chip:hover { border-color: var(--accent); }
.chip.on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }

.seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); overflow: hidden; }
.seg button { padding: 5px 12px; background: var(--surface); border: 0; border-right: 1px solid var(--line);
  font-size: .8rem; cursor: pointer; color: var(--ink-2); }
.seg button:last-child { border-right: 0; }
.seg button.on { background: var(--accent); color: var(--accent-ink); font-weight: 600; }

/* ================================================================= tables */
.table-wrap { overflow-x: auto; }
table.data { width: 100%; border-collapse: collapse; font-size: .85rem; }
table.data th {
  text-align: left; font-size: .7rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-3); font-weight: 650; padding: 9px 12px; border-bottom: 1px solid var(--line);
  white-space: nowrap; background: var(--surface-2);
}
table.data td { padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: middle; }
table.data tbody tr:last-child td { border-bottom: 0; }
table.data tbody tr.clickable { cursor: pointer; }
table.data tbody tr.clickable:hover { background: var(--surface-2); }
table.data .num { text-align: right; font-variant-numeric: tabular-nums; }
table.data .muted { color: var(--ink-3); }

/* ================================================================= pills */
.pill {
  display: inline-flex; align-items: center; gap: 5px; padding: 2px 9px; border-radius: 20px;
  font-size: .73rem; font-weight: 600; background: var(--surface-3); color: var(--ink-2); white-space: nowrap;
}
.pill.ok { background: var(--ok-soft); color: var(--ok); }
.pill.warn { background: var(--warn-soft); color: var(--warn); }
.pill.danger { background: var(--danger-soft); color: var(--danger); }
.pill.info { background: var(--info-soft); color: var(--info); }
.pill.accent { background: var(--accent-soft); color: var(--accent); }
.pill.purple { background: var(--purple-soft); color: var(--purple); }
.pill .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

.avatar-sm { width: 28px; height: 28px; border-radius: 50%; background: var(--accent-soft); color: var(--accent);
  display: grid; place-items: center; font-weight: 700; font-size: .72rem; flex: none; }

/* ================================================================ agenda */
.agenda-toolbar { display: flex; align-items: center; gap: 10px; padding: 12px 16px;
  border-bottom: 1px solid var(--line); flex-wrap: wrap; background: var(--surface); }
.agenda-grid { display: grid; grid-template-columns: 56px repeat(var(--days, 5), minmax(0,1fr));
  overflow-x: auto; background: var(--surface); }
.agenda-col { border-left: 1px solid var(--line); position: relative; min-width: 120px; }
.agenda-col.today { background: color-mix(in srgb, var(--accent-soft) 45%, transparent); }
.agenda-head { position: relative; background: var(--surface); z-index: 12;
  border-bottom: 1px solid var(--line); padding: 8px 6px; text-align: center;
  height: 56px; box-sizing: border-box; }
.agenda-head .dow { font-size: .68rem; text-transform: uppercase; letter-spacing: .09em; color: var(--ink-3); }
.agenda-head .dom { font-size: 1.05rem; font-weight: 600; }
.agenda-head.today .dom { color: var(--accent); }
.agenda-times { position: sticky; left: 0; background: var(--surface); z-index: 11; }
.agenda-time { height: 52px; font-size: .68rem; color: var(--ink-4); text-align: right;
  padding: 3px 7px 0 0; }
.agenda-slot { height: 52px; border-bottom: 1px solid var(--line); cursor: pointer; }
.agenda-slot:hover { background: color-mix(in srgb, var(--accent) 6%, transparent); }
.appt {
  position: absolute; left: 3px; right: 3px; border-radius: 6px; padding: 4px 6px; overflow: hidden;
  font-size: .74rem; line-height: 1.25; cursor: pointer; border-left: 3px solid currentColor;
  background: var(--surface); box-shadow: var(--shadow-1); transition: transform .08s, box-shadow .12s;
}
.appt:hover { box-shadow: var(--shadow-2); transform: translateY(-1px); z-index: 5; }
.appt b { display: block; font-weight: 650; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.appt span { color: var(--ink-3); font-size: .7rem; }
.appt.cancelled { opacity: .45; text-decoration: line-through; }

.day-list { display: flex; flex-direction: column; }
.day-item { display: flex; gap: 12px; padding: 11px 16px; border-bottom: 1px solid var(--line);
  cursor: pointer; align-items: flex-start; }
.day-item:hover { background: var(--surface-2); }
.day-item:last-child { border-bottom: 0; }
.day-time { font-variant-numeric: tabular-nums; font-weight: 650; font-size: .85rem; width: 46px; flex: none; }
.day-bar { width: 3px; align-self: stretch; border-radius: 3px; background: currentColor; flex: none; }
.day-main { flex: 1; min-width: 0; }
.day-main b { display: block; font-size: .875rem; font-weight: 600; }
.day-main span { font-size: .78rem; color: var(--ink-3); }

/* =============================================================== patient */
.patient-header {
  background: var(--surface); border-bottom: 1px solid var(--line); padding: 16px 22px 0;
  position: sticky; top: var(--header-h); z-index: 20;
}
.patient-top { display: flex; align-items: flex-start; gap: 14px; flex-wrap: wrap; }
.patient-avatar { width: 48px; height: 48px; border-radius: 50%; background: var(--accent-soft);
  color: var(--accent); display: grid; place-items: center; font-weight: 700; font-size: 1.05rem; flex: none; }
.patient-name h1 { font-size: 1.3rem; }
.patient-meta { display: flex; gap: 12px; flex-wrap: wrap; color: var(--ink-3); font-size: .8rem; margin-top: 3px; }
/* Wrapped, not scrolled.
 *
 * These used to scroll sideways with the scrollbar hidden, which is fine for
 * six tabs and a trap for sixteen: Settings grew past the width of the screen
 * and the last few tabs became unreachable — there was nothing on the page to
 * suggest they existed. A row of tabs is a menu, not a carousel, so it wraps
 * and all of it is visible. */
.tabs { display: flex; flex-wrap: wrap; gap: 2px 0; margin-top: 14px; }
.tabs button {
  padding: 9px 13px; background: none; border: 0; border-bottom: 2px solid transparent; cursor: pointer;
  font-size: .84rem; font-weight: 550; color: var(--ink-3); white-space: nowrap;
}
.tabs button:hover { color: var(--ink); }
.tabs button.on { color: var(--accent); border-bottom-color: var(--accent); }

.alert-banner { background: var(--danger-soft); color: var(--danger); border: 1px solid color-mix(in srgb, var(--danger) 25%, transparent);
  border-radius: var(--radius-sm); padding: 8px 12px; font-size: .82rem; font-weight: 550; margin: 12px 0; }

/* ============================================================== photos */
.photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
.photo-tile { position: relative; aspect-ratio: 3/4; border-radius: var(--radius-sm); overflow: hidden;
  background: var(--surface-3); border: 1px solid var(--line); cursor: pointer; }
.photo-tile img { width: 100%; height: 100%; object-fit: cover; }
.photo-tile .cap { position: absolute; inset: auto 0 0 0; padding: 14px 8px 5px;
  background: linear-gradient(transparent, rgba(0,0,0,.72)); color: #fff; font-size: .7rem; font-weight: 600; }
.photo-tile .badge-sim { position: absolute; top: 6px; right: 6px; background: var(--purple); color: #fff;
  font-size: .62rem; padding: 2px 6px; border-radius: 4px; font-weight: 700; letter-spacing: .04em; }
.photo-empty { aspect-ratio: 3/4; border: 1.5px dashed var(--line-strong); border-radius: var(--radius-sm);
  display: grid; place-items: center; color: var(--ink-4); font-size: .74rem; text-align: center; cursor: pointer; gap: 4px; }
.photo-empty:hover { border-color: var(--accent); color: var(--accent); }

.compare { position: relative; overflow: hidden; border-radius: var(--radius); background: #000;
  user-select: none; touch-action: none; }
.compare img { width: 100%; display: block; }
.compare .after { position: absolute; inset: 0; overflow: hidden; }
.compare .after img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.compare .handle { position: absolute; top: 0; bottom: 0; width: 2px; background: #fff; cursor: ew-resize;
  box-shadow: 0 0 8px rgba(0,0,0,.5); }
.compare .handle::after { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%);
  width: 30px; height: 30px; border-radius: 50%; background: #fff; box-shadow: 0 2px 8px rgba(0,0,0,.4); }
.compare .tag { position: absolute; top: 8px; padding: 3px 9px; border-radius: 20px; background: rgba(0,0,0,.62);
  color: #fff; font-size: .7rem; font-weight: 600; }

.sim-stage { position: relative; background: #14100f; border-radius: var(--radius); overflow: hidden;
  display: grid; place-items: center; min-height: 320px; }
.sim-stage canvas { max-width: 100%; max-height: 70dvh; touch-action: none; cursor: crosshair; }
.sim-tools { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }

/* ============================================================= documents */
.doc-page {
  background: #fff; color: #16181a; border-radius: var(--radius); box-shadow: var(--shadow-2);
  padding: 44px 48px; max-width: 800px; margin: 0 auto; font-size: 14px; line-height: 1.65;
}
.doc-page h1 { font-size: 1.35rem; margin-bottom: 14px; }
.doc-page h2 { font-size: 1.02rem; margin: 20px 0 7px; }
.doc-page p { margin-bottom: 10px; }
.doc-page ul, .doc-page ol { margin: 0 0 12px 20px; }
.doc-page li { margin-bottom: 4px; }
.doc-page table { width: 100%; border-collapse: collapse; margin: 12px 0; }
.doc-page th, .doc-page td { border: 1px solid #ddd; padding: 7px 10px; text-align: left; font-size: 13px; }
.doc-page hr { border: 0; border-top: 1px solid #e3e3e3; margin: 20px 0; }
.doc-page code { background: #f3f3f3; padding: 1px 4px; border-radius: 3px; font-family: var(--mono); font-size: 12.5px; }
/* Documents rendered by the server (receipts, and the preview of anything a
   patient is sent) use the same fragments as the patient-facing page. */
.doc-page .clinic b { font-size: 1.05rem; display: block; margin-bottom: 2px; }
.doc-page .clinic span,
.doc-page .party span { display: block; font-size: .85rem; color: var(--ink-3); }
.doc-page .party h4 { margin: 0 0 3px; font-size: .7rem; text-transform: uppercase;
  letter-spacing: .08em; color: var(--ink-3); }
.doc-page .party b { display: block; }
.doc-page .doc-parties { display: flex; gap: 28px; flex-wrap: wrap; margin-bottom: 20px; }
.doc-page .right { text-align: right; }
.doc-page .lead { font-size: 1.02rem; margin: 16px 0; }
.doc-page .doc-totals { margin-left: auto; width: min(300px, 100%); }
.doc-page .doc-totals div { display: flex; justify-content: space-between; padding: 5px 0; }
.doc-page .doc-totals .grand { border-top: 2px solid var(--ink); margin-top: 4px;
  padding-top: 8px; font-size: 1.05rem; font-weight: 700; }
.doc-page .doc-foot { margin-top: 24px; padding-top: 13px; border-top: 1px solid var(--line);
  font-size: .76rem; color: var(--ink-3); }

/* invoice / quote layout inside .doc-page */
.doc-head { display: flex; justify-content: space-between; gap: 24px; align-items: flex-start;
  border-bottom: 2px solid #16181a; padding-bottom: 16px; margin-bottom: 22px; }
.doc-head .clinic b { font-size: 1.1rem; display: block; }
.doc-head .clinic span { font-size: 12.5px; color: #555; display: block; line-height: 1.5; }
.doc-head .meta { text-align: right; font-size: 12.5px; }
.doc-head .meta b { font-size: 1.25rem; display: block; letter-spacing: -.02em; }
.doc-parties { display: flex; justify-content: space-between; gap: 24px; margin-bottom: 22px; font-size: 13px; }
.doc-parties h4 { font-size: 10.5px; text-transform: uppercase; letter-spacing: .1em; color: #777; margin-bottom: 5px; }
.doc-totals { margin-left: auto; width: 290px; font-size: 13.5px; }
.doc-totals div { display: flex; justify-content: space-between; padding: 5px 0; }
.doc-totals .grand { border-top: 2px solid #16181a; margin-top: 5px; padding-top: 9px;
  font-size: 1.06rem; font-weight: 700; }
.doc-foot { margin-top: 30px; padding-top: 16px; border-top: 1px solid #e3e3e3; font-size: 11.5px; color: #666; }

/* =================================================================== misc */
.empty { text-align: center; padding: 44px 20px; color: var(--ink-3); }
.empty svg { width: 34px; height: 34px; margin: 0 auto 10px; color: var(--ink-4); }
.empty p { font-size: .88rem; }
.empty .btn { margin-top: 14px; }

.muted { color: var(--ink-3); }
.small { font-size: .8rem; }
.tiny { font-size: .72rem; }
.bold { font-weight: 650; }
.nowrap { white-space: nowrap; }
.right { text-align: right; }
.tnum { font-variant-numeric: tabular-nums; }
.mt { margin-top: 14px; } .mt-sm { margin-top: 8px; } .mt-lg { margin-top: 24px; }
.mb { margin-bottom: 14px; }
.flex { display: flex; gap: 10px; align-items: center; }
.flex.wrap { flex-wrap: wrap; }
.flex.between { justify-content: space-between; }
.spacer { flex: 1; }
.divider { height: 1px; background: var(--line); margin: 14px 0; }

.list-item { display: flex; gap: 12px; align-items: center; padding: 11px 14px; border-bottom: 1px solid var(--line); }
.list-item:last-child { border-bottom: 0; }
.list-item.clickable { cursor: pointer; }
.list-item.clickable:hover { background: var(--surface-2); }
.list-item .body { flex: 1; min-width: 0; }
.list-item .body b { display: block; font-size: .86rem; font-weight: 600; }
.list-item .body span { font-size: .78rem; color: var(--ink-3); }

/* ---- folders: the shelf of things written once and used many times ---- */

.sec-head {
  font-size: .74rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-3); margin: 22px 0 8px;
}
.sec-head:first-child { margin-top: 0; }

/* ---- the cupboard ------------------------------------------------------
 *
 * Six buttons above the size box, because a garment comes in six sizes and
 * typing "M" is a keystroke and a chance to type "m ". The box underneath
 * stays: it is the field being saved, and a supplier who sizes 1 to 5 is not
 * going to change for us.
 */
/* All six on one line inside a third of the dialogue, which is the only width
   they ever get. Equal-width buttons read as one scale rather than six words,
   so they are padded to a common size — but only just, because 44px each was
   enough to push XXL onto a second row. */
.size-chips { margin-bottom: 7px; gap: 5px; }
.size-chips .chip { min-width: 36px; padding: 4px 7px; text-align: center; }
.size-chips .chip.other { min-width: 0; font-size: .74rem; color: var(--ink-3); }
.size-chips .chip.other.on { color: var(--accent-ink); }

/* A drawer within the cupboard. It is a row of the table rather than a heading
   above one, so every kind of garment keeps the same columns in the same
   places — six little tables side by side would be six things to read. */
tr.shelf-kind td {
  background: var(--surface-2); border-bottom: 1px solid var(--line);
  font-size: .7rem; font-weight: 650; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-3); padding: 7px 12px;
}
tr.shelf-kind td span { font-weight: 500; letter-spacing: 0; text-transform: none; }

.folder-row { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 4px; }
.folder {
  display: flex; gap: 11px; align-items: center; text-align: left; cursor: pointer;
  min-width: 220px; padding: 13px 16px; border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); color: inherit; font: inherit;
  transition: border-color .12s, background .12s;
}
.folder:hover { border-color: var(--accent); background: var(--surface-2); }
.folder > svg { width: 20px; height: 20px; color: var(--accent); flex: none; }
.folder .body { display: flex; flex-direction: column; min-width: 0; }
.folder .body b { font-size: .86rem; font-weight: 600; }
.folder .body span { font-size: .76rem; color: var(--ink-3); }

/* ---- ink: a signature and a stamp on a document -----------------------
 *
 * Blue, on purpose. A printed document in blue pen is visibly an original
 * rather than a photocopy of one, which is the whole reason a practice signs
 * in blue and stamps in blue.
 *
 * The stamp sits opposite the signature on the same line, the way a rubber
 * stamp lands beside a pen rather than under it, and the block is kept
 * together when the page breaks — a signature alone at the top of page three
 * is a mark on a page, not a signed document.
 */
.doc-sign { margin-top: 26px; break-inside: avoid; page-break-inside: avoid; }
.doc-sign-marks {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 24px; min-height: 46px;
}
.doc-sign .ink-sig { width: 132px; height: auto; }
.doc-sign .ink-stamp { width: 178px; height: auto; }
.doc-sign .ink-rule { flex: 0 0 220px; border-bottom: 1px solid var(--ink-3, #7b827f); height: 34px; }
.doc-sign-who { font-size: .76rem; color: var(--ink-3, #7b827f); margin-top: 4px; line-height: 1.45; }
@media (max-width: 560px) {
  .doc-sign-marks { flex-direction: column; align-items: flex-start; gap: 10px; }
}

/* ---- the fields that fill themselves in -------------------------------
 *
 * A merge field you have to remember the exact spelling of is a merge field
 * nobody uses, so each one is a button and they are grouped by what they are
 * about. It sits directly above the box it types into and folds away, because
 * somebody working from a supplied template never touches it and somebody
 * writing his own letters wants all of it.
 *
 * The marks are dashed, not solid: `{{signature}}` is not a fact that gets
 * frozen into the document like a name — it is a picture drawn afresh every
 * time the document is rendered — and looking slightly different is a cheap
 * way to say so.
 */
.mergebar {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface-2); margin-bottom: 6px;
}
.mergebar .mb-toggle {
  display: flex; align-items: center; gap: 6px; width: 100%;
  background: none; border: 0; padding: 6px 10px; cursor: pointer; text-align: left;
  font-size: .68rem; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-3);
}
.mergebar .mb-toggle svg { width: 14px; height: 14px; transition: transform .15s ease; }
.mergebar.folded .mb-toggle svg { transform: rotate(-90deg); }
.mergebar.folded .mb-groups { display: none; }
.mergebar .mb-groups { padding: 0 10px 9px; display: grid; gap: 5px; }
.mergebar .mb-group { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.mergebar .mb-label {
  font-size: .64rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-3); flex: 0 0 92px;
}
.mergebar .mb-chip {
  border: 1px solid var(--line); background: var(--surface); color: var(--ink-2);
  border-radius: 999px; padding: 2px 9px; font-size: .74rem; cursor: pointer;
}
.mergebar .mb-chip:hover { border-color: var(--accent); color: var(--accent); }
.mergebar .mb-group.ink .mb-chip { border-style: dashed; }
@media (pointer: coarse) {
  .mergebar .mb-chip { padding: 7px 12px; font-size: .8rem; }
  .mergebar .mb-label { flex-basis: 100%; }
}

/* ---- replacing the signature and the stamp ----------------------------
 *
 * The two drop targets are shown on white, not on the app's grey, because the
 * one thing being judged here is how the mark looks on paper. A signature
 * previewed on a tinted panel looks fine and then prints wrong.
 */
.ink-editor { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 18px; }
@media (max-width: 720px) { .ink-editor { grid-template-columns: 1fr; } }

.ink-slot-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 6px; }
.ink-drop {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; min-height: 150px; padding: 16px;
  background: #fff; border: 1px dashed var(--line-strong); border-radius: var(--radius);
  text-align: center; transition: border-color .15s, background .15s;
}
.ink-drop.over { border-color: var(--accent); background: var(--accent-soft, #eef3ff); }
.ink-drop.busy { opacity: .5; pointer-events: none; }
.ink-drop img { max-width: 100%; max-height: 96px; object-fit: contain; }
/* Its own file input is inside the label, so the whole control is the button. */
.ink-drop label.btn { cursor: pointer; }

.ink-proof {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  padding: 20px 22px 24px; color: #1c1f1d;
}
.ink-proof > p { margin: 0 0 6px; font-size: .88rem; color: #6b716e; }

/* ---- writing to a patient ---------------------------------------------
 *
 * Letter on the left, what travels with it on the right, because the two are
 * separate decisions and putting the attachments underneath the message makes
 * them look like an afterthought — which is exactly how a leaflet gets
 * forgotten and a prescription gets attached.
 */
.em-grid { display: grid; grid-template-columns: 1.35fr 1fr; gap: 22px; }
@media (max-width: 900px) { .em-grid { grid-template-columns: 1fr; } }

/* Two panes, each scrolling inside itself.
 *
 * One scrolling column put "Sent as a link" below the fold, which defeats the
 * entire arrangement: somebody looking for their patient's prescription found
 * a list of leaflets and no reason to think there was anything else. Both
 * headings are now always on screen, and each list scrolls under its own. */
.em-side {
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 16px 18px;
  /* The library is thirty rows and a patient's own documents are usually one
     or two, so the split is not even. */
  display: grid; grid-template-rows: minmax(0, 1.5fr) minmax(0, 1fr); gap: 14px;
  max-height: 62dvh; min-height: 0;
}
.em-pane { display: flex; flex-direction: column; min-height: 0; }
.em-pane + .em-pane { border-top: 1px solid var(--line); padding-top: 12px; }
.em-side h4 { margin: 0 0 4px; font-size: .78rem; text-transform: uppercase;
  letter-spacing: .07em; color: var(--ink-3); flex: none;
  display: flex; align-items: center; gap: 6px; }
.em-side h4 svg { width: 13px; height: 13px; }
.em-side .hint { margin: 0 0 8px; flex: none; }
/* `align-content: start` matters: a grid told to fill its parent stretches its
   rows, so two prescriptions in a tall pane sat a hundred pixels apart. */
.em-picks { display: grid; gap: 2px; align-content: start; overflow-y: auto; min-height: 0; flex: 1; }
@media (max-width: 900px) {
  /* Stacked, the panel is no longer competing for height with anything, so
     each list is given its head rather than squeezed into half a short box. */
  .em-side { grid-template-rows: none; max-height: none; }
  .em-picks { max-height: 40dvh; }
}
.em-folder { margin-bottom: 12px; }
.em-folder > b { display: block; font-size: .8rem; color: var(--ink-2); margin: 6px 0 3px; }
.em-picks .check { padding: 3px 0; align-items: flex-start; }
.em-letter textarea { min-height: 220px; resize: vertical; }

/* ---- information leaflets: picking them, and handing the iPad over ---- */

.lf-list { display: grid; gap: 2px; max-height: 46dvh; overflow-y: auto; }
.lf-row { align-items: flex-start; padding: 9px 4px; border-bottom: 1px solid var(--line); }
.lf-row:last-child { border-bottom: 0; }
.lf-row span b { display: block; font-size: .86rem; font-weight: 600; }
.lf-row span small { display: block; font-size: .76rem; color: var(--ink-3); margin-top: 2px; }
.lf-given { color: var(--ok); font-weight: 600; }

/* The kiosk. While the patient is reading, nothing on screen belongs to the
   surgeon — no navigation, no other patient's name, nothing to wander into by
   pressing the wrong thing. It covers everything, deliberately. */
/* 80 puts it over every part of the app — the top bar is 30, the mobile tab
   bar 40, the search results 50, the waiting-room dock 60 — and *under* the
   modal layer at 100. That ordering is deliberate: a dialog is the app asking
   a question, and a question that opens behind a full-screen panel is a
   freeze. "Hand the device back" asks before it closes, and the asking has to
   be visible. */
.lf-kiosk {
  position: fixed; inset: 0; z-index: 80; background: var(--bg);
  display: flex; flex-direction: column;
}
body.kiosk-open { overflow: hidden; }
.lf-kiosk-bar {
  display: flex; align-items: center; gap: 12px; flex: none;
  padding: 10px 16px calc(10px + env(safe-area-inset-top, 0px));
  border-bottom: 1px solid var(--line); background: var(--surface);
}
.lf-kiosk-bar b { font-size: .9rem; }
.lf-kiosk-frame { flex: 1; width: 100%; border: 0; min-height: 0; overflow-y: auto; }

/* A leaflet page previewed inside the app. Same reservation as the signing
   page for the same reason — see sign.css. */
.leaflet-pages { display: grid; gap: 12px; margin: 0 0 18px; }
.leaflet-page {
  display: block; width: 100%; aspect-ratio: 1 / 1.414; object-fit: contain;
  background: var(--surface-3); border: 1px solid var(--line); border-radius: 6px;
}

/* ---- a prescription line: the medicine, and what he wrote after it ---- */

/* Written directions get twice the width of the drug name, because that is
   the ratio the text actually has. Declared as `.row.rx-line` so it beats the
   plain `.row` rule above, and undone below 700px so a phone still stacks. */
.row.rx-line { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
@media (max-width: 700px) { .row.rx-line { grid-template-columns: 1fr; } }
.rx-more > summary {
  cursor: pointer; padding: 4px 0; list-style: none; user-select: none;
}
.rx-more > summary::-webkit-details-marker { display: none; }
.rx-more > summary::before { content: '▸ '; }
.rx-more[open] > summary::before { content: '▾ '; }

.timeline { position: relative; }
.timeline::before {
  content: ''; position: absolute; left: 15px; top: 10px; bottom: 10px; width: 2px; background: var(--line);
}
.timeline-item {
  position: relative; display: flex; gap: 12px; align-items: flex-start;
  padding: 10px 10px 10px 0; border-radius: var(--radius-sm);
}
.timeline-item.clickable { cursor: pointer; }
.timeline-item.clickable:hover { background: var(--surface-2); }
.timeline-item > svg:last-child { width: 15px; height: 15px; color: var(--ink-4); align-self: center; flex: none; }
.timeline-item .tl-body { flex: 1; min-width: 0; }
.timeline-item .when { font-size: .72rem; color: var(--ink-3); }
.timeline-item b { display: block; font-size: .87rem; }

.tl-dot {
  position: relative; z-index: 1; flex: none;
  display: grid; place-items: center; width: 32px; height: 32px; border-radius: 50%;
  background: var(--surface); border: 2px solid var(--line-strong); color: var(--ink-3);
}
.tl-dot svg { width: 14px; height: 14px; }

/* An entry someone else wrote is marked down its left edge, not shouted. */
.timeline-item.by-assistant { border-left: 3px solid var(--by-assistant); padding-left: 9px; margin-left: -12px; }
.timeline-item.by-secretary { border-left: 3px solid var(--by-secretary); padding-left: 9px; margin-left: -12px; }
.timeline-item.by-admin { border-left: 3px solid var(--by-admin); padding-left: 9px; margin-left: -12px; }
.timeline-item.by-assistant .tl-dot { border-color: var(--by-assistant); color: var(--by-assistant); }
.timeline-item.by-secretary .tl-dot { border-color: var(--by-secretary); color: var(--by-secretary); }

.byline { display: block; font-size: .72rem; margin-top: 3px; color: var(--ink-3); }
.byline.by-assistant { color: var(--by-assistant); font-weight: 600; }
.byline.by-secretary { color: var(--by-secretary); font-weight: 600; }
.byline.by-admin { color: var(--by-admin); font-weight: 600; }

.by-tag {
  display: inline-block; padding: 1px 7px; border-radius: 20px;
  font-size: .68rem; font-weight: 650; white-space: nowrap;
}
.by-tag.by-assistant { background: var(--by-assistant-soft); color: var(--by-assistant); }
.by-tag.by-secretary { background: var(--by-secretary-soft); color: var(--by-secretary); }
.by-tag.by-admin { background: var(--by-admin-soft); color: var(--by-admin); }

/* ------------------------------------------- contact details in the header */

.contact-chip { display: inline-flex; align-items: center; gap: 2px; }
.contact-chip a {
  display: inline-flex; align-items: center; gap: 4px; color: inherit; text-decoration: none;
  border-radius: 4px; padding: 1px 3px;
}
.contact-chip a:hover { color: var(--accent); text-decoration: underline; }
.contact-chip a svg { width: 13px; height: 13px; }
.copy-btn {
  display: grid; place-items: center; width: 22px; height: 22px; border-radius: 4px;
  border: 0; background: transparent; color: var(--ink-4); cursor: pointer;
  opacity: 0; transition: opacity .12s, background .12s;
}
.copy-btn svg { width: 12px; height: 12px; }
.contact-chip:hover .copy-btn, .copy-btn:focus-visible { opacity: 1; }
.copy-btn:hover { background: var(--surface-3); color: var(--ink); }
@media (hover: none) { .copy-btn { opacity: 1; } }

/* --------------------------------- the medical history, under the name */

.hx-strip {
  display: flex; gap: 7px; flex-wrap: wrap; align-items: center;
  padding: 10px 0 2px; border-top: 1px solid var(--line); margin-top: 12px;
}
.hx-chip {
  display: inline-flex; align-items: baseline; gap: 6px; max-width: 100%;
  padding: 4px 11px; border-radius: 20px; font-size: .76rem;
  background: var(--surface-3); color: var(--ink-2);
}
.hx-chip > svg { width: 12px; height: 12px; align-self: center; flex: none; }
.hx-chip b { font-weight: 650; flex: none; }
.hx-chip > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hx-chip.danger { background: var(--danger-soft); color: var(--danger); }
.hx-chip.warn { background: var(--warn-soft); color: var(--warn); }
.hx-more {
  border: 0; background: transparent; color: var(--ink-3); font: inherit; font-size: .74rem;
  cursor: pointer; display: inline-flex; align-items: center; gap: 2px; padding: 4px 6px;
}
.hx-more:hover { color: var(--accent); }
.hx-more svg { width: 12px; height: 12px; }

/* modal */
#modal-root:empty { display: none; }
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(15,20,19,.45); backdrop-filter: blur(3px);
  display: grid; place-items: center; padding: 20px; z-index: 100; animation: fade .14s ease;
}
.modal {
  background: var(--surface); border-radius: var(--radius-lg); box-shadow: var(--shadow-3);
  width: 100%; max-width: 560px; max-height: 90dvh; display: flex; flex-direction: column;
  border: 1px solid var(--line); animation: pop .16s cubic-bezier(.2,.9,.3,1.2);
}
.modal.wide { max-width: 900px; }
.modal.xwide { max-width: 1200px; }
@keyframes pop { from { opacity: 0; transform: translateY(8px) scale(.985) } to { opacity: 1; transform: none } }
.modal-head { display: flex; align-items: center; gap: 10px; padding: 15px 18px; border-bottom: 1px solid var(--line); }
.modal-head h2 { font-size: 1rem; flex: 1; }
.modal-body { padding: 18px; overflow-y: auto; flex: 1; }
.modal-foot { display: flex; gap: 8px; justify-content: flex-end; padding: 13px 18px;
  border-top: 1px solid var(--line); background: var(--surface-2); border-radius: 0 0 var(--radius-lg) var(--radius-lg); }
@media (max-width: 640px) {
  .modal-backdrop { padding: 0; align-items: flex-end; }
  .modal { max-width: 100%; max-height: 94dvh; border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
}

/* toast */
#toast-root { position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%); z-index: 200;
  display: flex; flex-direction: column; gap: 8px; align-items: center; pointer-events: none; }
.toast { background: var(--ink); color: var(--bg); padding: 9px 15px; border-radius: 20px;
  font-size: .84rem; box-shadow: var(--shadow-3); animation: pop .16s ease; max-width: 90vw;
  display: inline-flex; align-items: center; gap: 12px; }
.toast.err { background: var(--danger); color: #fff; }
.toast.ok { background: var(--ok); color: #fff; }
/* The one interactive thing on a layer that is otherwise click-through — it
   turns pointer events back on for itself in `toast()`. */
.toast-do {
  border: 0; background: transparent; color: inherit; font: inherit;
  font-weight: 700; text-decoration: underline; text-underline-offset: 3px;
  cursor: pointer; padding: 2px; margin: -2px -2px -2px 0; opacity: .92;
}
.toast-do:hover { opacity: 1; }
@media (max-width: 900px) { #toast-root { bottom: 78px; } }

/* spinner */
.spinner { width: 17px; height: 17px; border: 2px solid var(--line-strong); border-top-color: var(--accent);
  border-radius: 50%; animation: spin .6s linear infinite; }
@keyframes spin { to { transform: rotate(360deg) } }
.loading-block { display: grid; place-items: center; padding: 44px; }

/* consultation editor */
.note-editor { display: grid; grid-template-columns: minmax(0,1fr) 300px; gap: 16px; align-items: start; }
@media (max-width: 1050px) { .note-editor { grid-template-columns: 1fr; } }

/* -------------------------------------------------- the record editors
   A long note is scrolled while it is written, and Save must not be at the
   top of a page you have left behind. The header docks under the top bar and
   the side column — allergies, shortcuts — comes with you. */

.record-head { margin: 0 0 16px; }

/* The record's own buttons, in the patient's header. The row is the one the
   patient page already used for its own actions, so a note, a treatment and an
   operation all put their buttons in the same place — which is the place that
   does not move. */
.patient-top .btn-row { align-items: center; row-gap: 8px; }
.record-chip {
  display: inline-flex; align-items: center; gap: 8px; margin-right: 4px;
  font-size: .78rem; color: var(--ink-3); white-space: nowrap;
}
/* What the old band said that was worth keeping, said once, in the note. */
.record-line { margin: 0 0 14px; font-size: .84rem; color: var(--ink-2); }
.record-line b { color: var(--ink); }
@media (max-width: 700px) {
  .record-chip { width: 100%; margin: 0 0 4px; }
}
/* Nothing sticks any more. A record's buttons live in the patient header — see
 * `patientchrome.js` — which was already pinned and already had a row for them,
 * so there is no second header to stick, nothing to slide over the patient's
 * name, and no title repeated from the bar above. */

.note-editor > #side {
  position: sticky; top: calc(var(--header-h) + 74px);
  max-height: calc(100vh - var(--header-h) - 96px); overflow-y: auto;
}
@media (max-width: 1050px) {
  .note-editor > #side { position: static; max-height: none; overflow: visible; }
}
.note-section { border-bottom: 1px solid var(--line); padding: 14px 0; }
.note-section:last-child { border-bottom: 0; }
.note-section > label { display: flex; align-items: center; gap: 8px; font-size: .78rem; font-weight: 650;
  text-transform: uppercase; letter-spacing: .06em; color: var(--ink-3); margin-bottom: 7px; }
/* A one-line section: heading on the left, the line itself on the right.
   Measurements read down a column instead of pushing the examination two
   screens away. Below the tablet breakpoint it stacks like every other. */
.note-section.one-line { display: grid; grid-template-columns: minmax(140px, 30%) 1fr;
  align-items: center; gap: 0 16px; padding: 7px 0; }
.note-section.one-line > label { margin-bottom: 0; }
.note-section.one-line textarea { min-height: 0; height: 38px; padding-top: 8px; resize: none;
  white-space: pre; overflow-x: auto; }
@media (max-width: 720px) {
  .note-section.one-line { display: block; padding: 12px 0; }
  .note-section.one-line > label { margin-bottom: 7px; }
}
/* A divider inside a note — "First surgical time". It is not a field, so it
   does not look like one. */
.ns-heading { font-size: .8rem; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-2); margin: 22px 0 2px; padding-top: 14px; border-top: 2px solid var(--line); }
.note-section:first-child + .ns-heading, .ns-heading:first-child { margin-top: 4px; border-top: 0; padding-top: 0; }

/* One option out of several reads as a row of chips, like several out of
   several — the difference is what happens when you tap, not what it looks
   like, and two visual languages for "choose" is one too many. */
.chips.single .chip.on { box-shadow: inset 0 0 0 1px var(--accent); }

/* Turn what is in this box into a phrase you can tap next time. */
.ns-save { margin-left: auto; background: none; border: 0; cursor: pointer; color: var(--ink-3);
  padding: 0 2px; line-height: 1; opacity: 0; transition: opacity .12s; }
.ns-save svg { width: 14px; height: 14px; }
.note-section:hover .ns-save, .ns-save:focus-visible { opacity: 1; }
.ns-save:hover { color: var(--accent); }
.ns-drop:hover { color: var(--danger); }
/* Rename this heading, or stop asking for it, on this note. It appears on
   hover beside every heading; the "save this phrase" button takes the margin,
   so this one follows it rather than fighting for the same corner. */
.ns-edit { margin-left: 0; }
.ns-save + .ns-edit { margin-left: 0; }
.ns-heading .ns-edit { margin-left: 10px; vertical-align: middle; opacity: 0; }
.ns-heading:hover .ns-edit, .ns-heading .ns-edit:focus-visible { opacity: 1; }

/* Add a heading the form did not think of, without leaving the note. */
.ns-add { margin-top: 14px; padding-top: 14px; border-top: 1px dashed var(--line); }
.ns-add button { font-size: .78rem; }

/* ---- a list inside a note ----------------------------------------------
 *
 * Numbered, because the order is usually part of what is being recorded, and
 * every item stays editable — a typo in the third of five is not a reason to
 * delete it and type it again. The empty box at the foot is always ready, so
 * a list is built by typing and pressing Enter.
 */
.ns-list-rows { display: grid; gap: 4px; margin-bottom: 6px; }
.ns-list-row { display: flex; align-items: center; gap: 8px; }
.ns-list-n { font-size: .72rem; color: var(--ink-4); font-variant-numeric: tabular-nums;
  min-width: 16px; text-align: right; flex: none; }
.ns-list-row input { flex: 1; min-width: 0; }
.ns-list-add { display: flex; align-items: center; gap: 8px; }
.ns-list-add input { flex: 1; min-width: 0; }
.ns-list-add .btn { flex: none; }
.ns-list-none { margin: 0 0 6px; font-size: .76rem; color: var(--ink-3); }

/* The photograph of an implant's own label, in the row it belongs to. */
.imp-shot-cell { width: 44px; text-align: center; }
.imp-shot { width: 34px; height: 34px; object-fit: cover; border-radius: var(--radius-sm);
  border: 1px solid var(--line); cursor: zoom-in; display: block; }

.quickphrases { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.quickphrases button { font-size: .72rem; padding: 2px 8px; border-radius: 20px; border: 1px solid var(--line);
  background: var(--surface-2); cursor: pointer; color: var(--ink-2); }
.quickphrases button:hover { border-color: var(--accent); color: var(--accent); }

/* ---- a quick phrase, and the cross that stops it being offered ---------
 *
 * The cross appears on hover and on keyboard focus. Permanently visible, a row
 * of eight phrases reads as a list of mistakes rather than a row of shortcuts;
 * absent entirely, the only way to remove one is to remember which of nine
 * forms it came from and go to Settings.
 */
.quickphrases .qp { display: inline-flex; align-items: stretch; position: relative; }
.quickphrases .qp-x {
  display: grid; place-items: center; width: 0; padding: 0; overflow: hidden;
  /* Collapsed means *no* border as well as no width: a zero-width box with a
     1px border still paints a hairline, which read as a stray rule at the end
     of every phrase row. */
  border: 0 solid var(--line-strong); border-radius: 0 20px 20px 0;
  background: var(--surface); color: var(--ink-3); cursor: pointer;
  transition: width .1s, padding .1s, color .12s, background .12s;
}
.quickphrases .qp-x svg { width: 11px; height: 11px; }
.quickphrases .qp:hover .qp-x,
.quickphrases .qp:focus-within .qp-x {
  width: 22px; padding: 0 2px; border-width: 1px; border-left-width: 0;
}
.quickphrases .qp-x:hover { background: var(--danger-soft); color: var(--danger); border-color: var(--danger); }
/* There is no hover on an iPad, and this is an iPad app as much as a desktop
   one — so on a touch screen the cross is simply always there. The same rule
   the copy buttons in the patient header already follow. */
@media (hover: none) {
  .quickphrases .qp-x { width: 22px; padding: 0 2px; border-width: 1px; border-left-width: 0; }
  .quickphrases .qp > [data-phrase] { border-radius: 20px 0 0 20px; border-right-color: transparent; }
}
/* With a cross beside it the phrase gives up its own right-hand rounding, so
   the two read as one control rather than two buttons that happen to touch. */
.quickphrases .qp:hover > [data-phrase],
.quickphrases .qp:focus-within > [data-phrase] { border-radius: 20px 0 0 20px; border-right-color: transparent; }

.hx-flag { display: flex; align-items: center; gap: 7px; padding: 6px 10px; border-radius: var(--radius-sm);
  font-size: .8rem; margin-bottom: 6px; }
.hx-flag.danger { background: var(--danger-soft); color: var(--danger); }
.hx-flag.warn { background: var(--warn-soft); color: var(--warn); }
.hx-flag.ok { background: var(--ok-soft); color: var(--ok); }
/* A fact rather than a warning: stated plainly, in the ordinary ink. A BMI
   inside the normal range is worth showing and is not worth colouring. */
.hx-flag.plain { background: var(--surface-3); color: var(--ink-2); }

/* ------------------------------------------------------------- treatments */
.plan-band {
  border: 1px solid var(--accent-line); background: var(--accent-soft);
  border-radius: var(--radius); padding: 14px 16px; margin-bottom: 16px;
}
.plan-band h4 { font-size: .8rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--accent); margin-bottom: 7px; }
.plan-band .envelope { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: .82rem; }
.plan-band .envelope b { font-variant-numeric: tabular-nums; }
.plan-band .escalation { margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--accent-line);
  font-size: .82rem; }

.blocker {
  border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent);
  background: var(--danger-soft); color: var(--danger);
  border-radius: var(--radius); padding: 14px 16px; margin-bottom: 16px; font-size: .87rem;
}
.blocker b { display: block; margin-bottom: 4px; }

.checkgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); gap: 2px 14px; }
.checkgrid .check { padding: 4px 0; }
.checkgrid .check span { font-size: .82rem; }

.params { width: 100%; border-collapse: collapse; font-size: .82rem; min-width: 820px; }
.params th { font-size: .64rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-3);
  text-align: left; padding: 5px 6px; border-bottom: 1px solid var(--line); white-space: nowrap; }
.params td { padding: 4px 3px; border-bottom: 1px solid var(--line); }
.params input, .params select { padding: 5px 7px; font-size: .81rem; }
.params .out-of-range { border-color: var(--warn); background: var(--warn-soft); }

.session-dots { display: flex; gap: 4px; align-items: center; }
.session-dots i { width: 15px; height: 15px; border-radius: 4px; background: var(--surface-3);
  border: 1px solid var(--line-strong); display: block; }
.session-dots i.used { background: var(--accent); border-color: var(--accent); }
.session-dots i.now { background: var(--warn); border-color: var(--warn); }

.course-card { border: 1px solid var(--line); border-radius: var(--radius); padding: 13px 15px;
  background: var(--surface); }
.course-card + .course-card { margin-top: 10px; }
.course-card .flex { align-items: flex-start; }

/* line item editor */
.items-table { width: 100%; border-collapse: collapse; font-size: .85rem; }
.items-table th { font-size: .68rem; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3);
  text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--line); }
.items-table td { padding: 5px 4px; border-bottom: 1px solid var(--line); vertical-align: top; }
.items-table input { padding: 6px 8px; font-size: .84rem; }
.items-table .num input { text-align: right; }


/* =========================================================================
   Questionnaires — the inbox, the review screen, the form library
   ========================================================================= */

.page-head { display: flex; gap: 16px; align-items: flex-start; flex-wrap: wrap; margin-bottom: 16px; }
.page-head > div:first-child { min-width: 0; }
.page-head h1 { font-size: 1.45rem; margin: 0; }
.page-head h1 > svg { width: 20px; height: 20px; vertical-align: -3px; margin-right: 5px; color: var(--ink-3); }
.page-head p { margin: 3px 0 0; }
.page-head .btn-row { flex: none; }
.page-head .btn.sm.ghost { margin-bottom: 6px; }

.tabs .count {
  display: inline-block; min-width: 18px; padding: 0 5px; margin-left: 5px;
  border-radius: 9px; background: var(--accent); color: var(--accent-ink);
  font-size: .68rem; font-weight: 700; line-height: 18px; text-align: center;
}

.avatar-sm.public { background: var(--info-soft); color: var(--info); }
.avatar-sm > svg { width: 15px; height: 15px; }

.list-item .right { display: flex; align-items: center; gap: 6px; flex: none; }
.sub-summary {
  display: block; font-size: .78rem; color: var(--ink-2); margin-top: 3px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.chip.ok   { background: var(--ok-soft);   border-color: transparent; color: var(--ok); }
.chip.warn { background: var(--warn-soft); border-color: transparent; color: var(--warn); }
.chip.info { background: var(--info-soft); border-color: transparent; color: var(--info); }
.chip.muted { background: var(--surface-3); border-color: transparent; color: var(--ink-3); }
.chip.ok:hover, .chip.warn:hover, .chip.info:hover, .chip.muted:hover { border-color: transparent; }

.callout {
  display: flex; gap: 9px; align-items: flex-start;
  padding: 11px 13px; border-radius: var(--radius-sm);
  font-size: .82rem; line-height: 1.5;
  background: var(--surface-3); color: var(--ink-2);
}
.callout > svg { flex: none; margin-top: 1px; }
.callout.info { background: var(--info-soft); color: var(--info); }
.callout.ok   { background: var(--ok-soft);   color: var(--ok); }
.callout.warn { background: var(--warn-soft); color: var(--warn); }
.callout.err  { background: var(--danger-soft); color: var(--danger); }

/* the form library --------------------------------------------------- */

.form-card { display: flex; flex-direction: column; }
.form-card.off { opacity: .58; }
.form-card .card-body { flex: 1; }
.card-foot {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  padding: 11px 14px; border-top: 1px solid var(--line); background: var(--surface-2);
}
.stat-row { display: flex; gap: 20px; margin-top: 12px; }
.stat-row > div { display: flex; flex-direction: column; }
.stat-row b { font-size: 1.15rem; line-height: 1.2; }
.stat-row span { font-size: .72rem; color: var(--ink-3); text-transform: uppercase; letter-spacing: .04em; }

/* reviewing a submission ---------------------------------------------- */

.contact-row { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: .85rem; }
.contact-row span { color: var(--ink-2); }

.prose { font-size: .87rem; line-height: 1.6; color: var(--ink-2); }
.prose h2 {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-3); font-weight: 700;
  margin: 22px 0 10px; padding-bottom: 6px; border-bottom: 1px solid var(--line);
}
.prose h2:first-child { margin-top: 0; }
.prose p { margin: 0 0 12px; }
.prose strong { color: var(--ink); font-weight: 600; }

.sub-photos { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 10px; }
.sub-photos figure { margin: 0; position: relative; border-radius: var(--radius-sm); overflow: hidden;
  border: 1px solid var(--line); background: var(--surface-3); aspect-ratio: 3/4; }
.sub-photos img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sub-photos figure:not(.filed) img { filter: saturate(.75); }
.sub-photos figcaption {
  position: absolute; inset: auto 0 0 0; padding: 3px 6px;
  background: rgba(21,128,61,.9); color: #fff; font-size: .66rem; text-align: center;
}

.match-list { display: flex; flex-direction: column; gap: 7px; margin: 10px 0 4px; }
.match {
  display: flex; gap: 10px; align-items: flex-start; cursor: pointer;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm); padding: 10px 12px;
}
.match:hover { border-color: var(--accent-line); }
.match:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
.match.strong { border-left-width: 3px; border-left-color: var(--ok); }
.match input { margin-top: 3px; accent-color: var(--accent); flex: none; }
.match > div { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.match b { font-size: .86rem; }
.match .tiny svg { width: 12px; height: 12px; vertical-align: -2px; color: var(--ok); }

.merge-group { margin-top: 16px; }
.merge-group h4 {
  font-size: .7rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-3); margin: 0 0 8px;
}
.merge-group.conflict h4 { color: var(--warn); }
.merge-row {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 8px 10px; border-radius: var(--radius-sm); background: var(--surface-2);
  margin-bottom: 6px;
}
.merge-row > span > svg, .merge-row > span svg { width: 14px; height: 14px; color: var(--ok); margin-top: 3px; }
.merge-row > div { min-width: 0; flex: 1; }
.merge-row b { font-size: .8rem; display: block; }
.merge-val { font-size: .84rem; color: var(--ink); word-break: break-word; }
.merge-old { font-size: .74rem; color: var(--ink-3); text-decoration: line-through; }
.merge-group.conflict .merge-row { background: var(--warn-soft); }
.merge-row.standalone { display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
  background: var(--warn-soft); padding: 11px 12px; }
.merge-row.standalone .btn-row { margin-left: auto; }

.w-full { width: 100%; justify-content: center; }
.inline-select { width: auto; padding: 4px 8px; font-size: .78rem; }

/* the form itself, previewed ------------------------------------------ */

.preview-title { font-size: 1.15rem; margin: 0 0 6px; }
.preview-intro { margin-bottom: 18px; }
.preview-section { margin-bottom: 20px; }
.preview-section h4 {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-3); margin: 0 0 8px; padding-bottom: 5px; border-bottom: 1px solid var(--line);
}
.preview-section ol { margin: 0; padding-left: 20px; }
.preview-section li { font-size: .84rem; margin-bottom: 7px; color: var(--ink-2); }
.preview-section li.note-q { list-style: none; margin-left: -20px; color: var(--ink-3); font-style: italic; }
.q-type {
  display: inline-block; font-size: .64rem; text-transform: uppercase; letter-spacing: .05em;
  background: var(--surface-3); color: var(--ink-3); border-radius: 4px;
  padding: 1px 5px; margin-right: 6px; vertical-align: 1px;
}
.q-meta { font-size: .7rem; color: var(--ink-4); margin-left: 6px; }

/* ============================================================ accounting */

:root { --bar-inv: #4f46e5; --bar-col: #15803d; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --bar-inv: #818cf8; --bar-col: #4ade80; } }
:root[data-theme="dark"] { --bar-inv: #818cf8; --bar-col: #4ade80; }

.acc-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; }
.acc-dates { display: flex; align-items: center; gap: 8px; }
.acc-dates input { max-width: 160px; }
.acc-period {
  font-size: .78rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--ink-3); margin-bottom: 10px;
}

.inline-field { display: inline-flex; align-items: center; gap: 8px; font-size: .82rem; color: var(--ink-2); }
.inline-field select { max-width: 170px; }
.check.tight { padding: 0; }

.stat.ok { background: var(--ok-soft); border-color: color-mix(in srgb, var(--ok) 30%, transparent); }
.stat.muted .value { color: var(--ink-3); }

.mb-row { padding: 4px 0; }
.mb-row + .mb-row { border-top: 1px solid var(--line); }

/* the month-by-month pair of bars */
.legend { display: inline-flex; align-items: center; gap: 5px; font-size: .72rem; color: var(--ink-3); }
.legend i { width: 9px; height: 9px; border-radius: 2px; display: inline-block; }
.legend i.inv { background: var(--bar-inv); }
.legend i.col { background: var(--bar-col); }

.mbar { display: grid; grid-template-columns: 62px minmax(0, 1fr) 128px; align-items: center; gap: 12px; padding: 5px 0; }
.mbar-label { font-size: .76rem; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.mbar-track { display: flex; flex-direction: column; gap: 3px; }
.mbar-fill { height: 9px; border-radius: 3px; min-width: 2px; transition: width .25s ease; }
.mbar-fill.inv { background: var(--bar-inv); }
.mbar-fill.col { background: var(--bar-col); }
.mbar-val { text-align: right; line-height: 1.3; }
.mbar-val b { display: block; font-size: .8rem; }
.mbar-val span { display: block; font-size: .72rem; color: var(--ink-3); }

table.mini { width: 100%; border-collapse: collapse; font-size: .8rem; }
table.mini th {
  text-align: left; font-size: .68rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-3); font-weight: 650; padding: 4px 6px; border-bottom: 1px solid var(--line);
}
table.mini td { padding: 5px 6px; border-bottom: 1px solid var(--line); font-variant-numeric: tabular-nums; }
table.mini tr:last-child td { border-bottom: 0; }
table.mini .right { text-align: right; }
table.mini.bridge td { border-bottom: 0; padding: 4px 0; }
table.mini.bridge tr.total td { border-top: 1px solid var(--line-strong); padding-top: 8px; }

table.data tfoot td {
  padding: 10px 12px; border-top: 2px solid var(--line-strong);
  background: var(--surface-2); font-weight: 650;
}
table.data tbody tr.struck td { color: var(--ink-4); text-decoration: line-through; }
table.data tbody tr.struck td:last-child { text-decoration: none; }
.overdue { color: var(--danger); font-weight: 600; }

@media (max-width: 700px) {
  .mbar { grid-template-columns: 52px minmax(0, 1fr) 96px; gap: 8px; }
  .acc-filters .seg { width: 100%; overflow-x: auto; }
}

/* ========================================================= payments desk */

.pay-head {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px 16px; background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius);
}
.pay-head b { display: block; }
.pay-head span { display: block; }

.seg.wide { display: flex; width: 100%; }
.seg.wide button { flex: 1; padding: 10px 8px; }
.seg.wrap { flex-wrap: wrap; border: 0; gap: 6px; }
.seg.wrap button {
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  padding: 6px 12px; display: inline-flex; align-items: center; gap: 6px;
}
.seg button .count {
  font-size: .7rem; font-variant-numeric: tabular-nums; opacity: .7;
  background: color-mix(in srgb, currentColor 12%, transparent);
  border-radius: 20px; padding: 0 6px; min-width: 18px; text-align: center;
}

/* the receipt-or-invoice question */
.choice-grid { display: grid; gap: 10px; }
button.choice {
  display: grid; grid-template-columns: 22px 1fr; gap: 4px 12px; align-items: start;
  width: 100%; text-align: left; padding: 14px 16px; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--radius);
  font: inherit; color: var(--ink); transition: border-color .12s, background .12s;
}
button.choice:hover:not(:disabled) { border-color: var(--accent); background: var(--accent-soft); }
button.choice:disabled { opacity: .5; cursor: default; }
button.choice svg { grid-row: span 2; width: 20px; height: 20px; color: var(--accent); margin-top: 2px; }
button.choice b { font-size: .95rem; }
button.choice span { font-size: .82rem; color: var(--ink-3); line-height: 1.5; }

.menu-list { display: flex; flex-direction: column; gap: 2px; }
.menu-list button {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 11px 12px; border: 0; border-radius: var(--radius-sm); background: none;
  font: inherit; font-size: .88rem; color: var(--ink); cursor: pointer;
}
.menu-list button:hover { background: var(--surface-2); }
.menu-list button.danger { color: var(--danger); }
.menu-list button svg { color: var(--ink-3); }
.menu-list button.danger svg { color: var(--danger); }

td.link { cursor: pointer; }
td.link:hover { color: var(--accent); text-decoration: underline; }
td.link span { display: block; }

/* ================================================= sending and signatures */

.link-row { display: flex; gap: 8px; align-items: center; }
.link-row input {
  flex: 1; min-width: 0; font-family: var(--mono); font-size: .78rem;
}

.sig-row {
  display: flex; align-items: center; gap: 11px; padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.sig-row:last-child { border-bottom: 0; }
.sig-row > svg { color: var(--ink-3); flex: none; }
.sig-row > div { flex: 1; min-width: 0; }
.sig-row b { display: block; font-size: .88rem; }
.sig-row span { display: block; }

.evidence { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line);
  border-radius: var(--radius-sm); overflow: hidden; }
.evidence > div {
  display: flex; justify-content: space-between; gap: 16px; align-items: baseline;
  background: var(--surface); padding: 9px 12px;
}
.evidence span { font-size: .78rem; color: var(--ink-3); }
.evidence b { font-size: .85rem; text-align: right; word-break: break-all; }

.sig-image {
  max-width: 320px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: #fff; margin-top: 6px; padding: 6px;
}

/* =========================================================================
   The diary window that opens when you go to choose a time
   ========================================================================= */

.with-button { display: flex; gap: 6px; align-items: stretch; }
.with-button input { flex: 1; min-width: 0; }
.with-button .btn { flex: none; }

.picker { display: flex; flex-direction: column; min-height: 46vh; }
.picker-bar {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  padding-bottom: 12px; border-bottom: 1px solid var(--line); margin-bottom: 14px;
}
.picker-bar input[type=date] { width: auto; }
.check.inline { padding: 0; }
.check.inline span { font-size: .8rem; white-space: nowrap; }

.picker-body { flex: 1; max-height: 52vh; overflow-y: auto; }
.picker-block { margin-bottom: 20px; }
.picker-block h4 {
  margin: 0 0 9px; font-size: .76rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-3); font-weight: 650;
}
.picker-block h4 span { text-transform: none; letter-spacing: 0; font-weight: 400; }

.picker-slots { display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: 7px; }
.pk-slot {
  display: flex; flex-direction: column; gap: 1px; text-align: left;
  padding: 8px 10px; border-radius: var(--radius-sm); cursor: pointer; font: inherit;
  border: 1px solid var(--line-strong); border-left: 3px solid var(--t);
  background: var(--surface); color: var(--ink); transition: border-color .12s, background .12s;
}
.pk-slot b { font-size: .85rem; font-variant-numeric: tabular-nums; }
.pk-slot span {
  font-size: .72rem; color: var(--ink-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pk-slot.free { background: color-mix(in srgb, var(--ok) 7%, var(--surface)); }
.pk-slot.taken span { color: var(--t); font-weight: 600; }
.pk-slot:hover:not(:disabled) { border-color: var(--accent); }
.pk-slot.on {
  border-color: var(--accent); background: var(--accent-soft);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent);
}
.pk-slot:disabled, .pk-slot.past { opacity: .4; cursor: default; }

.picker-list { display: flex; flex-direction: column; gap: 5px; }
.pk-row {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); font: inherit; cursor: pointer;
}
.pk-row:hover { border-color: var(--accent); }
.pk-row.on { border-color: var(--accent); background: var(--accent-soft); }
.pk-row b { font-size: .84rem; font-variant-numeric: tabular-nums; min-width: 48px; }
.pk-row > span:last-child { font-size: .82rem; color: var(--ink-2); }
.pk-bar { width: 3px; align-self: stretch; border-radius: 2px; flex: none; }

.picker-foot { padding-top: 12px; border-top: 1px solid var(--line); margin-top: 12px; }

/* =========================================================================
   Bookable time — the availability blocks behind online booking
   ========================================================================= */

.form-grid { display: grid; gap: 0 14px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.form-grid .span2 { grid-column: 1 / -1; }
@media (max-width: 620px) { .form-grid { grid-template-columns: 1fr; } }

.av-rows { display: flex; flex-direction: column; }
.av-row {
  display: grid; grid-template-columns: 110px minmax(0, 1fr) auto auto;
  gap: 14px; align-items: center; padding: 14px 16px; border-bottom: 1px solid var(--line);
}
.av-row:last-child { border-bottom: 0; }
.av-row.off { opacity: .55; }

.av-when { line-height: 1.3; }
.av-when b { display: block; font-size: .9rem; }
.av-when span { font-size: .78rem; color: var(--ink-3); font-variant-numeric: tabular-nums; }

.av-what { min-width: 0; }
.av-what b { display: block; font-size: .9rem; }
.av-what > span { display: block; font-size: .76rem; color: var(--ink-3); }
.av-types { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 6px; }

.av-flags { display: flex; flex-direction: column; gap: 4px; align-items: flex-end; }
.av-actions { display: flex; gap: 5px; align-items: center; }

@media (max-width: 760px) {
  .av-row { grid-template-columns: minmax(0, 1fr) auto; }
  .av-what { grid-column: 1 / -1; }
  .av-flags { flex-direction: row; align-items: center; }
  .av-actions { grid-column: 1 / -1; }
}

.type-chip {
  display: inline-block; padding: 2px 8px; border-radius: 20px; font-size: .7rem; font-weight: 600;
  background: color-mix(in srgb, var(--t) 14%, transparent); color: var(--t);
}
.type-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.type-chips button {
  padding: 6px 12px; border-radius: 20px; font: inherit; font-size: .78rem; cursor: pointer;
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink-2);
}
.type-chips button.on {
  background: color-mix(in srgb, var(--t) 16%, transparent);
  border-color: var(--t); color: var(--t); font-weight: 650;
}

.day-picker { display: flex; gap: 5px; flex-wrap: wrap; }
.day-picker button {
  min-width: 46px; padding: 7px 10px; border-radius: var(--radius-sm); font: inherit; font-size: .8rem;
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink-2); cursor: pointer;
}
.day-picker button.on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); font-weight: 650; }

.copy-row { display: flex; gap: 6px; align-items: center; }
.copy-row code {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 7px 10px; font-size: .78rem;
}

.icon-btn.danger { color: var(--danger); }
.icon-btn.danger:hover { background: var(--danger-soft, color-mix(in srgb, var(--danger) 12%, transparent)); }

/* =========================================================================
   The live day board

   A clock you can read from across the room, and one row per patient. The
   colours carry meaning: amber means someone is sitting in your waiting room
   and the number beside it is how long they have been there.
   ========================================================================= */

.board-head {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 12px;
}
.board-head h2 { margin: 0; font-size: 1.05rem; }
.board-head .spacer { flex: 1; }
.board-head #board-sub { flex: 1 1 100%; order: 3; }
@media (min-width: 720px) { .board-head #board-sub { flex: none; order: 0; } }

.warn-text { color: var(--warn); }

/* ---------------------------------------------------------- the time bar */

.board-timeline { padding: 14px 16px 12px; overflow: hidden; }

.board-scale { position: relative; height: 16px; margin-bottom: 4px; }
.board-tick { position: absolute; top: 0; transform: translateX(-50%); }
.board-tick span {
  font-size: .68rem; color: var(--ink-3); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.board-tick:first-child { transform: none; }

.board-track {
  position: relative; height: 46px; background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden;
}
.board-grid-line {
  position: absolute; top: 0; bottom: 0; width: 1px; background: var(--line);
}

.board-block {
  position: absolute; top: 6px; bottom: 6px; min-width: 6px;
  background: color-mix(in srgb, var(--t) 16%, var(--surface));
  border: 1px solid var(--t); border-left: 3px solid var(--t);
  border-radius: 5px; padding: 0 6px; cursor: pointer; overflow: hidden;
  display: flex; align-items: center; transition: filter .12s;
}
.board-block:hover { filter: brightness(.96); }
.board-block span {
  font-size: .72rem; font-weight: 600; color: var(--t);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.board-block.completed { opacity: .5; }
.board-block.cancelled, .board-block.no_show {
  opacity: .45; background: repeating-linear-gradient(45deg,
    var(--surface-2), var(--surface-2) 4px, var(--surface-3) 4px, var(--surface-3) 8px);
}
.board-block.in_progress { box-shadow: 0 0 0 2px color-mix(in srgb, var(--t) 45%, transparent); }

/* The marker. It moves; everything else stands still. */
.board-now {
  position: absolute; top: 0; bottom: 0; width: 2px; background: var(--danger);
  z-index: 3; pointer-events: none; transition: left .6s linear;
}
.board-now::before {
  content: ''; position: absolute; top: -3px; left: -3px;
  width: 8px; height: 8px; border-radius: 50%; background: var(--danger);
}
/* The clock reading rides above the bar, where it cannot sit on a name. */
.board-now-label {
  position: absolute; top: -1px; transform: translateX(-50%);
  padding: 1px 5px; border-radius: 4px; background: var(--danger); color: #fff;
  font-size: .64rem; font-weight: 700; font-variant-numeric: tabular-nums;
  white-space: nowrap; transition: left .6s linear; z-index: 4;
}

/* ------------------------------------------------------------- the rows */

.board-rows { display: flex; flex-direction: column; }
.board-row {
  display: grid; grid-template-columns: auto 3px minmax(0, 1fr) auto auto;
  gap: 12px; align-items: center; padding: 11px 16px;
  border-bottom: 1px solid var(--line); cursor: pointer; transition: background .12s;
}
.board-row:last-child { border-bottom: 0; }
.board-row:hover { background: var(--surface-2); }

.board-time {
  text-align: right; font-variant-numeric: tabular-nums; line-height: 1.25;
  min-width: 52px; white-space: nowrap;
}
.board-time b { display: block; font-size: .88rem; }
.board-time span { font-size: .7rem; color: var(--ink-3); }

.board-bar { align-self: stretch; border-radius: 2px; min-height: 30px; }

.board-who { display: flex; align-items: center; gap: 10px; min-width: 0; }
.board-name { min-width: 0; }
.board-name b {
  display: block; font-size: .92rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.board-name span { display: block; font-size: .74rem; color: var(--ink-3); }

.board-state { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; text-align: right; }
.board-actions { display: flex; align-items: center; gap: 4px; flex: none; }

/* Faded once the visit is over, so the eye lands on what is still live. */
.board-row.completed .board-who,
.board-row.completed .board-time,
.board-row.cancelled, .board-row.no_show { opacity: .62; }
.board-row.in_progress { background: color-mix(in srgb, var(--accent) 7%, transparent); }
.board-row.arrived { background: color-mix(in srgb, var(--warn) 7%, transparent); }
.board-row.long-wait { background: color-mix(in srgb, var(--warn) 15%, transparent); }
.board-row.bd-overdue .board-time b { color: var(--warn); }

/* ------------------------------------------------------------ the chips */

.chip-state {
  display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
  border-radius: 20px; padding: 4px 10px; font-size: .76rem; font-weight: 600;
  background: var(--surface-3); color: var(--ink-2);
}
.chip-state > svg { width: 12px; height: 12px; }
.chip-state b { font-variant-numeric: tabular-nums; }
.chip-state.ok { background: var(--ok-soft); color: var(--ok); }
.chip-state.warn { background: var(--warn-soft); color: var(--warn); }
.chip-state.accent { background: var(--accent-soft); color: var(--accent); }
.chip-state.done { background: var(--surface-3); color: var(--ink-3); }
.chip-state.muted { background: transparent; color: var(--ink-3); border: 1px solid var(--line); }
.chip-state.danger { background: var(--danger-soft); color: var(--danger); }

/* The waiting list: the note somebody made on the telephone belongs under the
   row it is about, not in a column of its own — it is a sentence, and a
   sentence in a table cell is a sentence nobody reads. */
tr.wl-note td { padding-top: 0; border-top: 0; }
tr.wl-urgent + tr.wl-note td { padding-bottom: 10px; }
table.data td.wl-actions { white-space: nowrap; }

.pulse {
  width: 7px; height: 7px; border-radius: 50%; background: currentColor;
  animation: pulse 1.8s ease-in-out infinite;
}
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) {
  .pulse { animation: none; }
  .board-now { transition: none; }
}

/* Narrow screens: the state moves under the name, actions stay reachable. */
@media (max-width: 720px) {
  .board-row { grid-template-columns: auto 3px minmax(0, 1fr) auto; row-gap: 8px; }
  .board-who { grid-column: 3 / -1; }
  .board-state {
    grid-column: 3; grid-row: 2; flex-direction: row; align-items: center;
    justify-content: flex-start; flex-wrap: wrap; text-align: left;
  }
  .board-actions { grid-column: 4; grid-row: 2; justify-self: end; }
  .board-timeline { display: none; }
}


/* =========================================================================
   The operation — quote, plan, note, side by side
   ========================================================================= */

.triptych { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; align-items: start; }
@media (max-width: 1100px) { .triptych { grid-template-columns: 1fr; } }

.panel-agreed { border-top: 3px solid var(--t-consultation); }
.panel-plan   { border-top: 3px solid var(--warn); }
.panel-note   { border-top: 3px solid var(--t-surgery); }

.op-procs { list-style: none; margin: 0 0 14px; padding: 0; display: grid; gap: 8px; }
.op-procs li {
  padding: 9px 12px; border-radius: var(--radius-sm); background: var(--surface-2);
  border-left: 3px solid var(--t-surgery);
}
.op-procs li b { display: block; font-size: .9rem; }
.op-procs li span { display: block; margin-top: 2px; }

.op-lines { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line);
  border-radius: var(--radius-sm); overflow: hidden; }
.op-line { display: flex; justify-content: space-between; gap: 14px; align-items: baseline;
  background: var(--surface); padding: 8px 11px; }
.op-line span { font-size: .76rem; color: var(--ink-3); flex: none; }
.op-line b { font-size: .84rem; text-align: right; }

.op-inout { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 14px; }
@media (max-width: 620px) { .op-inout { grid-template-columns: 1fr; } }
.op-inout h4 { margin: 0 0 6px; font-size: .74rem; text-transform: uppercase;
  letter-spacing: .07em; color: var(--ink-3); }
.op-inout ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.op-inout li { display: flex; gap: 6px; align-items: flex-start; font-size: .82rem; }
.op-inout li svg { width: 12px; height: 12px; margin-top: 3px; flex: none; }
.op-inout div:first-child li svg { color: var(--ok); }
.op-inout div:last-child li svg { color: var(--ink-4); }

.op-total { display: flex; justify-content: space-between; align-items: baseline;
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.op-total span { font-size: .8rem; color: var(--ink-3); }
.op-total b { font-size: 1.15rem; font-variant-numeric: tabular-nums; }

.op-when { text-align: center; padding: 14px 0 16px; border-bottom: 1px solid var(--line); margin-bottom: 14px; }
.op-when b { display: block; font-family: var(--serif); font-size: 1.2rem; }
.op-when span { font-size: .95rem; color: var(--ink-2); font-variant-numeric: tabular-nums; }

.op-money { display: grid; gap: 8px; }
.op-charge { display: flex; align-items: center; gap: 10px; padding: 9px 11px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); }
.op-charge b { font-size: .85rem; font-variant-numeric: tabular-nums; }
.op-charge span.muted { display: block; }
.op-charge.paid { background: var(--ok-soft); border-color: transparent; }

.op-due { margin-top: 14px; padding: 9px 12px; border-radius: var(--radius-sm);
  font-size: .82rem; background: var(--surface-3); display: flex; gap: 7px; align-items: center; }
.op-due svg { width: 14px; height: 14px; flex: none; }
.op-due.ok { background: var(--ok-soft); color: var(--ok); }
.op-due.warn { background: var(--warn-soft); color: var(--warn); }
.op-due.err { background: var(--danger-soft); color: var(--danger); }

.op-terms { margin-top: 14px; font-size: .8rem; }
.op-terms summary { cursor: pointer; font-weight: 600; color: var(--ink-2); }
.op-terms p { margin: 8px 0 0; line-height: 1.6; }

.op-note-card { text-align: center; padding: 10px 0; }
.op-note-card b { display: block; font-size: .95rem; }
.op-note-card span { display: block; margin-top: 3px; }

.op-rows { display: flex; flex-direction: column; }
.op-row { display: grid; grid-template-columns: 92px minmax(0, 1fr) auto auto; gap: 12px;
  align-items: center; padding: 12px 16px; border-bottom: 1px solid var(--line); }
.op-row:last-child { border-bottom: 0; }
.op-row.clickable { cursor: pointer; }
.op-row.clickable:hover { background: var(--surface-2); }
.op-row > svg:last-child { width: 15px; height: 15px; color: var(--ink-4); }
.op-row-when { line-height: 1.25; font-variant-numeric: tabular-nums; }
.op-row-when b { display: block; font-size: .86rem; }
.op-row-when span { font-size: .72rem; color: var(--ink-3); }
.op-row-what b { display: block; font-size: .9rem; }
.op-row-what span { font-size: .75rem; color: var(--ink-3); }
@media (max-width: 700px) {
  .op-row { grid-template-columns: minmax(0, 1fr) auto; }
  .op-row-what { grid-column: 1 / -1; }
}

/* the surgical half of a quote */
.surgical-panel { border-top: 3px solid var(--t-surgery); }
.proc-row { display: grid; grid-template-columns: minmax(0, 2.2fr) 130px minmax(0, 1.5fr) auto;
  gap: 8px; align-items: start; margin-bottom: 10px; }
@media (max-width: 820px) { .proc-row { grid-template-columns: 1fr; } }
.terms-block { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line);
  font-size: .78rem; line-height: 1.6; }
.terms-block p { margin: 0 0 8px; }

/* =========================================================================
   Composed blocks
   ========================================================================= */

.plan-rows { display: grid; gap: 8px; }
.plan-row { display: grid; grid-template-columns: minmax(0, 1fr) 150px 78px 68px auto;
  gap: 7px; align-items: center; }
@media (max-width: 760px) { .plan-row { grid-template-columns: 1fr 1fr; } }
.plan-row input, .plan-row select { font-size: .82rem; }
/* Subject, then its variant if it has one, then free text if it has neither.
   Stacked rather than side by side: three controls across a 1fr column would
   leave nothing readable in any of them. */
.plan-what { display: grid; gap: 5px; min-width: 0; }
.hint.over { color: var(--danger); font-weight: 600; }

/* What a consultation is about, in the appointment modal. */
.subj-pick { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: 8px; }
.subj-pick:has(> :only-child) { grid-template-columns: 1fr; }
@media (max-width: 560px) { .subj-pick { grid-template-columns: 1fr; } }
tr.dim > td { opacity: .55; }
/* A batch where most of what was opened did not reach a patient. Tinted rather
   than shouted at: it wants explaining, and quite often the explanation is
   perfectly good — one patient, one vial, and the rest expired with it. */
tr.warn-row > td { background: var(--warn-soft); }

/* The pencil that edits the booking itself.
   Clicking an appointment now opens what it produced — the consultation, the
   operation — because that is what you were after. Moving or cancelling the
   slot is a different intention and gets its own small target, out of the way
   until you look for it. Always visible where there is no hover to rely on. */
.appt-edit {
  position: absolute; top: 2px; right: 2px; z-index: 2;
  opacity: 0; padding: 2px; background: color-mix(in srgb, var(--surface) 80%, transparent);
  border-radius: 5px;
}
.appt-edit svg { width: 13px; height: 13px; }
.appt:hover .appt-edit, .day-item:hover .appt-edit { opacity: .85; }
.day-item .appt-edit { position: static; opacity: 0; flex: none; }
@media (hover: none) { .appt-edit, .day-item .appt-edit { opacity: .7; } }
.type-chip em { font-style: normal; opacity: .7; margin-left: 3px; }

/* =========================================================================
   The waiting room, from inside a consultation
   ========================================================================= */

.wr-card .pill.warn { background: var(--warn-soft); color: var(--warn); }
.wr-list { display: grid; gap: 5px; }
.wr-row {
  display: flex; align-items: center; gap: 9px; width: 100%; text-align: left;
  padding: 7px 9px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); font: inherit; cursor: pointer;
}
.wr-row:hover { border-color: var(--accent); }
.wr-row.long { background: var(--warn-soft); border-color: transparent; }
.wr-row.long .wr-mins { color: var(--warn); }
.wr-row.is-you { border-color: var(--accent); background: var(--accent-soft); cursor: default; }
.wr-who { flex: 1; min-width: 0; }
.wr-who b { display: block; font-size: .82rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wr-mins { font-size: .82rem; font-variant-numeric: tabular-nums; flex: none; }
.wr-foot { display: grid; gap: 3px; margin-top: 10px; padding-top: 9px;
  border-top: 1px solid var(--line); font-size: .74rem; color: var(--ink-3); }

/* Choosing which photographs go to the patient. */
.sp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: 8px; margin: 12px 0; max-height: 46vh; overflow-y: auto; }
.sp-tile { position: relative; padding: 0; border: 2px solid var(--line); border-radius: var(--radius-sm);
  overflow: hidden; background: var(--surface-2); cursor: pointer; aspect-ratio: 3/4; }
.sp-tile img { width: 100%; height: 100%; object-fit: cover; display: block; opacity: .5; }
.sp-tile.on { border-color: var(--accent); }
.sp-tile.on img { opacity: 1; }
.sp-tick { position: absolute; top: 5px; right: 5px; width: 20px; height: 20px; border-radius: 50%;
  background: var(--surface); border: 1px solid var(--line); display: grid; place-items: center; color: transparent; }
.sp-tile.on .sp-tick { background: var(--accent); border-color: var(--accent); color: #fff; }
.sp-tick svg { width: 12px; height: 12px; }
.sp-tile .badge-sim { position: absolute; left: 5px; bottom: 5px; }

/* The simulation studio: one pane, or the original beside it. */
.sim-stage.dual { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: start; }
.sim-pane { margin: 0; }
.sim-pane canvas { width: 100%; height: auto; display: block; border-radius: var(--radius-sm); }
.sim-pane figcaption { margin-top: 5px; text-align: center; font-size: .72rem;
  text-transform: uppercase; letter-spacing: .08em; color: var(--ink-3); }
/* The brush, drawn where it will land and at the size it will be. A slider
   saying "110 px" means nothing on a photograph scaled to fit a screen; a
   circle over the nose means exactly one thing. */
.sim-pane { position: relative; }
.sim-ring {
  position: absolute; pointer-events: none; transform: translate(-50%, -50%);
  border-radius: 50%;
  /* A hairline. It is there to say where the brush is and how big, not to be
     looked at — a thick ring hides the edge it is being lined up against,
     which is the one thing it must not do. */
  border: 1px solid rgba(255,255,255,.9);
  box-shadow: 0 0 0 .5px rgba(0,0,0,.55);
  /* The growing and shrinking is eased a frame at a time in the view, which a
     transition here would only fight — it restarts on every write, so the
     circle would arrive late at a size it had already left. */
}
.sim-hud {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  pointer-events: none; background: rgba(0,0,0,.62); color: #fff;
  padding: 6px 12px; border-radius: 999px; font-size: .8rem; font-weight: 700;
  letter-spacing: .01em; font-variant-numeric: tabular-nums;
}
.sim-bar { justify-content: center; gap: 8px; flex-wrap: wrap; }

/* ---- the versions saved in this sitting ---------------------------------
 *
 * A consultation does not end at one simulation: the patient says "a little
 * less than that", and the second attempt has to sit beside the first rather
 * than replace it. Each one that has been filed appears here, and each keeps
 * the warp that made it, so "the first one, but less" is a click away.
 */
.sim-versions {
  display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap;
  margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--line);
}
.sim-versions-label { font-size: .72rem; text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-3); align-self: center; margin-right: 2px; }
.sim-version { margin: 0; width: 96px; text-align: center; }
.sim-version img { width: 96px; height: 96px; object-fit: cover; display: block;
  border-radius: var(--radius-sm); border: 2px solid var(--line); background: var(--surface-3); }
.sim-version.on img { border-color: var(--accent); }
.sim-version figcaption { font-size: .7rem; color: var(--ink-2); margin: 4px 0 3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sim-version .btn.sm { font-size: .66rem; padding: 2px 7px; width: 100%; }

/* Side by side, with the original — because the question is not "is this
   good" but "which of these", and that cannot be answered one at a time.
   One row, always: a grid that wraps puts the fourth option under the first
   and turns the comparison back into looking at them one after another. The
   pictures are fitted to a height rather than a width so a whole row of
   portraits is on screen at once. */
.modal.compare { max-width: min(1500px, 96vw); }
.sim-compare { display: flex; gap: 14px; overflow-x: auto; padding-bottom: 4px; }
.sim-compare-card { margin: 0; text-align: center; flex: 1 1 0; min-width: 190px; }
.sim-compare-card img {
  width: 100%; height: min(54vh, 460px); object-fit: contain; display: block;
  border-radius: var(--radius-sm); border: 1px solid var(--line); background: var(--surface-3);
}
.sim-compare-card figcaption { font-size: .76rem; font-weight: 600; margin: 6px 0 5px; }
@media (max-width: 700px) { .sim-compare-card img { height: 44vh; } }
.sim-bar .btn.on { border-color: var(--accent); color: var(--accent); }
@media (max-width: 700px) { .sim-stage.dual { grid-template-columns: 1fr; } }

/* Dragging a booking to another hour. The block itself is the handle; a
   deliberate five pixels of travel separates a drag from a click. */
.appt.draggable { cursor: grab; touch-action: none; }
.appt.dragging { cursor: grabbing; opacity: .9; z-index: 30;
  box-shadow: 0 10px 24px rgba(0,0,0,.22); transform: scale(1.02); }
.agenda-col.drop-target { background: var(--accent-soft); }

/* The move dialogue: what it was, what it becomes. */
.mv-when { display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 12px 14px; margin: 12px 0; border-radius: var(--radius-sm);
  background: var(--surface-2); font-size: .84rem; }
.mv-when b { display: block; }
.mv-arrow { color: var(--ink-3); font-size: 1.1rem; }
.check.off { opacity: .62; }

/* ---- the dock -----------------------------------------------------------
 *
 * The waiting room while somebody is in the room: a small panel in the corner
 * with its own scroll. Its header is the control — click it and the list
 * folds away, leaving one line that is still on screen and still says how
 * many are waiting and how long the longest has been. There is no close
 * button, because a panel you can close and cannot find again is worse than
 * one you never had.
 *
 * It sits at the **top right, under the buttons**. The record header is
 * sticky, so Print, Save and Sign stay where they are as a long note is
 * scrolled — and the panel tucks under them and stays there too, which is the
 * one place on the page where nothing is being written and nothing has to be
 * read. `top` is set from the real bottom of whatever chrome is pinned above
 * it (see `waitingroom.js`), because that is a different height on a patient
 * record, on a plain list, and on a note whose header has shrunk after
 * sticking.
 *
 * It floats. It does not take width off the note: an editor that shrinks
 * because a corner panel appeared is a worse trade than a panel that overlaps
 * the margin, and the note is the thing being written.
 */
.wr-dock {
  position: fixed; right: 14px; left: auto; top: 96px; bottom: auto; z-index: 60;
  width: 244px; max-height: min(38vh, 300px);
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 12px 34px rgba(0,0,0,.14); overflow: hidden;
}
.wr-dock-head {
  display: flex; align-items: center; gap: 7px; width: 100%;
  padding: 9px 10px; font-size: .78rem; cursor: pointer; text-align: left;
  background: var(--surface-2); border: 0; border-bottom: 1px solid var(--line); color: inherit;
}
.wr-dock-head:hover { background: var(--surface-3, var(--surface-2)); }
.wr-dock-head svg { width: 15px; height: 15px; flex: none; }
.wr-dock-head .spacer { flex: 1; }
/* Ducked: the panel is open, but the field being typed into is underneath it,
   so it folds to its one line until focus leaves. The surgeon's own choice of
   open or minimised is untouched — this is a courtesy, not a setting. */
.wr-dock.ducked { max-height: none; }
.wr-dock.ducked .wr-dock-head { border-bottom: 0; }
.wr-dock.ducked .wr-dock-list { display: none; }
.wr-dock.ducked .wr-dock-chev { transform: none; }

/* Open, the arrow points up: click to fold it away. Minimised it points down,
   because that is the direction the list will come back from. */
.wr-dock-chev { display: flex; color: var(--ink-3); transition: transform .15s; transform: rotate(180deg); }
.wr-dock.min { max-height: none; }
.wr-dock.min .wr-dock-head { border-bottom: 0; }
.wr-dock.min .wr-dock-chev { transform: none; }
.wr-dock.min .wr-dock-list { display: none; }
.wr-dock-count { font-size: .72rem; font-weight: 600; min-width: 18px; text-align: center;
  padding: 1px 6px; border-radius: 10px; background: var(--surface); color: var(--ink-3); }
.wr-dock-count.warn { background: var(--warn-soft); color: var(--warn); }
.wr-dock-peak { font-size: .72rem; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.wr-dock-peak.warn { color: var(--warn); font-weight: 700; }
.wr-dock-list { overflow-y: auto; padding: 6px; display: grid; gap: 4px; }
.wr-dock-row { display: flex; align-items: center; gap: 7px; width: 100%; text-align: left;
  padding: 5px 7px; border: 1px solid transparent; border-radius: var(--radius-sm);
  background: none; cursor: pointer; color: inherit; }
.wr-dock-row:hover { border-color: var(--line); }
.wr-dock-row.long { background: var(--warn-soft); }
.wr-dock-row.long .wr-mins { color: var(--warn); font-weight: 700; }
.wr-dock-row.is-you { background: var(--accent-soft); cursor: default; }
.wr-dock-who { flex: 1; min-width: 0; }
.wr-dock-who b { display: block; font-size: .78rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wr-dock-none { padding: 10px; margin: 0; font-size: .74rem; color: var(--ink-3); }

/* Nothing is reserved for it. At the top right it overlaps the head of the
   right-hand column rather than the field somebody is writing in, and folding
   it to one line clears even that. */

/* On a phone there is no top right corner to speak of — the title and the
   search box are already in it — and the whole screen is the note. So the
   panel stays at the foot, above the tab bar, where it starts as its one line.
   The breakpoint matches the rail's own, so there is never a width at which
   the panel sits on top of the navigation. */
@media (max-width: 700px) {
  .wr-dock { right: 10px; left: 10px; width: auto; top: auto !important;
    bottom: 74px; max-height: 40vh; }
  body.has-dock .content { padding-bottom: 96px; }
  body.has-dock.dock-open .content { padding-bottom: calc(40vh + 90px); }
}

/* =========================================================================
   The ledger and the accountant's pack
   ========================================================================= */

.ledger-bar { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap; }
.ledger-bar .field { margin-bottom: 0; }
.ledger-bar input[type=date], .ledger-bar select { width: auto; min-width: 130px; }

.linklike {
  border: 0; background: none; padding: 0; font: inherit; color: var(--accent);
  cursor: pointer; text-align: left; text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--accent) 40%, transparent);
}
.linklike:hover { text-decoration-color: var(--accent); }
.linklike .muted { display: block; text-decoration: none; }
a.plain { color: inherit; text-decoration: none; }
a.plain:hover { color: var(--accent); text-decoration: underline; }
td.right, th.right { text-align: right; }

/* =========================================================================
   Places
   ========================================================================= */

.place-rows { display: flex; flex-direction: column; }
.place-row { display: flex; gap: 14px; align-items: flex-start; padding: 14px 16px;
  border-bottom: 1px solid var(--line); }
.place-row:last-child { border-bottom: 0; }
.place-row.off { opacity: .5; }
.place-what { flex: 1; min-width: 0; }
.place-what b { display: block; font-size: .92rem; }
.place-what > span { display: block; font-size: .8rem; color: var(--ink-2); }
.place-dir { margin: 7px 0 0; font-size: .78rem; color: var(--ink-3); line-height: 1.55;
  padding-left: 10px; border-left: 2px solid var(--line); }
.place-note { margin: 7px 0 0; font-size: .76rem; color: var(--warn);
  display: flex; gap: 5px; align-items: flex-start; }
.place-note svg { width: 12px; height: 12px; margin-top: 2px; flex: none; }

/* =========================================================================
   Timeline as a roadmap
   ========================================================================= */

.tl-band {
  font-size: .7rem; text-transform: uppercase; letter-spacing: .09em; font-weight: 700;
  color: var(--ink-3); margin: 4px 0 8px; padding-left: 44px;
}
.tl-band.past { margin-top: 20px; padding-top: 14px; border-top: 1px dashed var(--line); }
.timeline-item.ahead { opacity: .95; }
.timeline-item.ahead .tl-dot { border-style: dashed; }
.ahead-tag { color: var(--accent); font-weight: 700; }
.tl-dot.tl-operation { border-color: var(--t-surgery); color: var(--t-surgery); }
.tl-dot.tl-consultation { border-color: var(--t-consultation); color: var(--t-consultation); }
.tl-dot.tl-treatment { border-color: var(--t-laser); color: var(--t-laser); }

/* What the visit cost, on the row for the visit. */
.tl-money {
  display: inline-flex; align-items: baseline; gap: 5px; margin-top: 5px;
  padding: 2px 8px; border-radius: 999px; font-weight: 700; font-size: .78rem;
  font-variant-numeric: tabular-nums;
}
.tl-money .tiny { font-weight: 600; text-transform: uppercase; letter-spacing: .05em; opacity: .8; }
.tl-money.paid { background: var(--ok-soft); color: var(--ok); }
.tl-money.due { background: var(--warn-soft); color: var(--warn); }

/* =========================================================================
   The money for one record, in its side column
   ========================================================================= */

.money-card .money-total { font-variant-numeric: tabular-nums; }
.money-lines { display: flex; flex-direction: column; gap: 8px; }
.money-line {
  display: grid; grid-template-columns: 1fr auto; gap: 4px 10px;
  padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.money-line.paid { border-color: color-mix(in srgb, var(--ok) 35%, var(--line)); }
.money-line .ml-what { min-width: 0; }
.money-line .ml-what b { display: block; font-size: .84rem; word-break: break-word; }
.money-line .ml-right {
  display: flex; flex-direction: column; align-items: flex-end; gap: 3px;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.money-line .ml-take { grid-column: 1 / -1; justify-self: stretch; }
.money-sum {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-top: 10px; padding-top: 8px; border-top: 1px dashed var(--line);
  font-size: .85rem; font-variant-numeric: tabular-nums;
}
.ok-text { color: var(--ok); }

.hx-chip.clickable { cursor: pointer; }
.hx-chip.clickable:hover { filter: brightness(.96); }
.hx-trend { font-style: normal; font-size: .7rem; font-weight: 700; margin-left: 4px; }
.hx-trend.down { color: var(--ok); }
.hx-trend.up { color: var(--warn); }

@media print {
  /* The patient's header belongs on the screen, not on the paper: a printed
     quotation carrying the allergy strip and a row of tabs is a screenshot of
     an application, not a document. Pressing Print uses a clean frame anyway
     (see printHtml), but the browser's own Ctrl+P has to produce something
     sensible too. */
  .sidebar, .topbar, .mobile-nav, .btn, .tabs, .no-print,
  .patient-header, .mergebar { display: none !important; }
  body, .content { background: #fff; padding: 0; }
  .doc-page { box-shadow: none; padding: 0; max-width: 100%; }
  .shell { grid-template-columns: 1fr; }
}

/* A table row someone else wrote carries a coloured edge, not a coloured row. */
table.data tr.by-assistant td:first-child { box-shadow: inset 3px 0 0 var(--by-assistant); }
table.data tr.by-secretary td:first-child { box-shadow: inset 3px 0 0 var(--by-secretary); }
table.data tr.by-admin td:first-child { box-shadow: inset 3px 0 0 var(--by-admin); }

/* =========================================================================
   The shared list
   ========================================================================= */

.nav a { position: relative; }
.nav-badge {
  margin-left: auto; min-width: 20px; padding: 1px 7px; border-radius: 999px;
  background: rgba(255,255,255,.16); color: #fff;
  font-size: .68rem; font-weight: 700; text-align: center; font-variant-numeric: tabular-nums;
  white-space: nowrap; flex: none;
}

/* ---- the chevron that drops the list down instead of opening the screen --
 *
 * Quiet until the row is hovered, because it is the second thing you might
 * want from that row and the first is still the row itself. It carries a
 * 28-pixel target inside a 44-pixel row, which is enough on a mouse; where
 * there is no hover it is simply always visible, since a control nobody can
 * reveal is a control that is not there.
 */
.nav-more {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  display: grid; place-items: center;
  width: 24px; height: 24px; border-radius: var(--radius-sm);
  color: #cfe6e0; opacity: 0; pointer-events: none;
  transition: opacity .12s, background .12s;
}
.nav-more svg { width: 15px; height: 15px; opacity: 1; }
/* It takes the badge's place rather than sitting beside it. There is no room
   for both on a 232-pixel rail without the label wrapping, and anybody
   reaching for the chevron is asking for more than the badge can say. */
.nav a:hover .nav-more, .nav a:focus-within .nav-more {
  opacity: .8; pointer-events: auto;
}
.nav a:hover .nav-badge, .nav a:focus-within .nav-badge { opacity: 0; }
.nav-badge { transition: opacity .12s; }
.nav-more:hover { background: rgba(255,255,255,.18); opacity: 1; }
.nav-more:focus-visible { opacity: 1; outline: 2px solid #8ed6c6; outline-offset: 1px; }
/* No hover to reveal it with: it is simply there, tucked into the corner. */
@media (hover: none) {
  .nav-more { opacity: .75; pointer-events: auto; }
  .nav a .nav-badge { opacity: 1; }
  .nav-badge { margin-right: 26px; }
}

/* ---- who is waiting, in a corner rather than a screen ------------------ */
.wr-menu {
  position: fixed; z-index: 90; width: 268px; max-width: calc(100vw - 16px);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-3, 0 12px 32px rgba(0,0,0,.18));
  overflow: hidden;
}
.wr-menu-head {
  display: flex; align-items: center; gap: 8px; padding: 9px 12px;
  border-bottom: 1px solid var(--line-soft); font-size: .8rem;
}
.wr-menu-head svg { width: 15px; height: 15px; color: var(--ink-3); }
.wr-menu-head .spacer { flex: 1; }
.wr-menu-body { max-height: 46dvh; overflow-y: auto; padding: 6px; }
.wr-menu-body .wr-list { display: grid; gap: 2px; }
.wr-menu-body > p { margin: 8px 10px; }
.wr-menu-next { border-top: 1px dashed var(--line); padding-top: 7px; margin-top: 7px !important; }
.wr-menu-foot {
  display: block; width: 100%; text-align: left; padding: 9px 12px; border: 0;
  border-top: 1px solid var(--line-soft); background: var(--surface-2);
  color: var(--accent); font-size: .78rem; font-weight: 600; cursor: pointer;
}
.wr-menu-foot:hover { background: var(--surface-3, var(--surface-2)); }
.nav-badge.urgent { background: var(--danger); color: #fff; }

.list-toolbar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 16px; border-bottom: 1px solid var(--line); background: var(--surface-2);
}

.task-row {
  display: grid; grid-template-columns: auto 1fr auto; align-items: start; gap: 12px;
  padding: 12px 16px; border-bottom: 1px solid var(--line);
}
.task-row:last-child { border-bottom: 0; }
.task-row:hover { background: var(--surface-2); }
.task-row.urgent { box-shadow: inset 3px 0 0 var(--warn); }
.task-row.is-overdue { box-shadow: inset 3px 0 0 var(--danger); }
.task-row.done { opacity: .55; }
.task-row.done .task-body > b { text-decoration: line-through; }

.task-tick {
  width: 22px; height: 22px; margin-top: 1px; flex: none; padding: 0;
  display: grid; place-items: center; cursor: pointer;
  border: 2px solid var(--line-strong); border-radius: 6px; background: var(--surface);
  color: transparent; transition: background .12s, border-color .12s;
}
.task-tick:hover { border-color: var(--accent); }
.task-tick.on { background: var(--ok); border-color: var(--ok); color: #fff; }
.task-tick svg { width: 14px; height: 14px; }

.task-body { min-width: 0; cursor: pointer; }
.task-body > b { display: block; font-size: .9rem; }
.task-body > span { display: block; }
.task-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 3px 8px;
  margin-top: 5px; font-size: .72rem; color: var(--ink-3);
}
/* A dot between the facts, so the line reads as a sentence rather than a run. */
.task-meta > span + span::before { content: '·'; margin-right: 7px; opacity: .5; }
.task-meta svg { width: 12px; height: 12px; vertical-align: -2px; margin-right: 2px; }
.task-meta .tm-patient { color: var(--ink-2); font-weight: 600; }
.task-meta .tm-who { font-weight: 700; color: var(--accent); }
.task-meta .tm-who.unclaimed { color: var(--ink-3); font-weight: 500; font-style: italic; }
.task-meta .td-late { color: var(--danger); font-weight: 700; }

.task-thread { display: flex; flex-direction: column; gap: 8px; max-height: 260px; overflow-y: auto; }
.task-comment {
  padding: 8px 10px; border-radius: var(--radius-sm); background: var(--surface-2);
  border-left: 3px solid var(--line-strong);
}
.task-comment.by-assistant { border-left-color: var(--by-assistant); }
.task-comment.by-secretary { border-left-color: var(--by-secretary); }
.task-comment b { font-size: .8rem; margin-right: 6px; }
.task-comment p { margin: 3px 0 0; font-size: .85rem; white-space: pre-wrap; }

/* What the patient did about their own appointment, wherever it is shown. */
.reply-tag { color: var(--ok); font-weight: 600; }
.reply-tag svg { width: 11px; height: 11px; vertical-align: -1px; }
.tl-reply {
  margin-top: 4px; font-size: .74rem; color: var(--ok); font-weight: 600;
  display: flex; align-items: center; gap: 5px;
}
.tl-reply svg { width: 12px; height: 12px; }
.appt-reply {
  position: absolute; top: 4px; right: 4px; width: 7px; height: 7px; border-radius: 50%;
  background: var(--ok);
}
.appt-reply.cancelled { background: var(--danger); }
.appt-reply.rescheduled { background: var(--warn); }

/* A table cell that leads somewhere. */
button.linkish {
  display: inline-flex; align-items: center; gap: 5px; padding: 0; border: 0; background: none;
  color: var(--accent); font: inherit; font-weight: 600; cursor: pointer; text-align: left;
}
button.linkish:hover { text-decoration: underline; }
button.linkish svg { width: 13px; height: 13px; opacity: .7; }

/* =========================================================================
   Choosing rows, and doing one thing to all of them
   ========================================================================= */

.sel-bar {
  position: sticky; top: calc(var(--header-h) + 8px); z-index: 20;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-bottom: 14px; padding: 9px 14px;
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  border-radius: var(--radius); box-shadow: var(--shadow-1);
}
.sel-bar b { color: var(--accent-deep); font-size: .85rem; }

table.data th.pick, table.data td.pick { width: 34px; padding-right: 0; }
table.data td.pick input { width: 15px; height: 15px; cursor: pointer; margin: 0; }
table.data tr.picked > td { background: var(--accent-soft); }

/* =========================================================================
   The surgery, whole
   ========================================================================= */

.filed-list { display: flex; flex-direction: column; gap: 6px; }
.filed-row {
  display: flex; align-items: center; gap: 9px; padding: 7px 9px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface-2); text-decoration: none; color: inherit;
}
.filed-row:hover { border-color: var(--accent-line); background: var(--accent-soft); }
.filed-row svg { width: 15px; height: 15px; flex: none; color: var(--ink-3); }
.filed-row b { display: block; font-size: .8rem; }

.callout.accent {
  background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-deep);
}
.chip-state.accent { background: var(--accent-soft); color: var(--accent); }

/* A record shown inside its patient keeps its own head, one step smaller. */
.patient-header + .content .record-head h1 { font-size: 1.35rem; }

/* =========================================================================
   Payments: a question and its answer
   ========================================================================= */

.search-bar {
  display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap;
}
.search-bar .field { margin: 0; min-width: 150px; }
.search-bar .btn { margin-bottom: 1px; }

/* The amount is the way into the record the money was taken in. */
button.amount-link {
  border: 0; background: none; padding: 0; font: inherit; font-weight: 700;
  color: var(--accent); cursor: pointer; font-variant-numeric: tabular-nums;
}
button.amount-link:hover { text-decoration: underline; }

/* A payment inside its record: state on one line, what you can do on the next. */
.money-line { grid-template-columns: 1fr auto; }
.money-line .ml-actions {
  grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  margin-top: 6px; padding-top: 6px; border-top: 1px dashed var(--line);
}
.money-line .ml-actions .btn { flex: 0 0 auto; }
.money-line .ml-actions .icon-btn { margin-left: auto; }

/* =========================================================================
   Drawing bookable time on a week
   ========================================================================= */

.avg-wrap { padding: 12px 14px 18px; }
.avg-hint {
  display: flex; align-items: center; gap: 7px; margin-bottom: 10px;
  font-size: .78rem; color: var(--ink-3);
}
.avg-hint svg { width: 14px; height: 14px; flex: none; }

.avg-grid {
  display: grid; grid-template-columns: 52px repeat(7, minmax(0, 1fr));
  border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden;
  background: var(--surface);
}
.avg-head {
  height: 30px; display: flex; align-items: center; justify-content: center;
  font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-3); background: var(--surface-2); border-bottom: 1px solid var(--line);
}
.avg-times .avg-hour {
  height: calc(var(--row-px) * 4); font-size: .68rem; color: var(--ink-4);
  padding: 1px 6px 0 0; text-align: right; font-variant-numeric: tabular-nums;
}
.avg-col { border-left: 1px solid var(--line); min-width: 0; }
.avg-track {
  position: relative; height: calc(var(--rows) * var(--row-px));
  cursor: crosshair; touch-action: none;
}
.avg-line { position: absolute; left: 0; right: 0; height: 1px; background: var(--line); }

.avg-block {
  position: absolute; left: 2px; right: 2px; overflow: hidden; cursor: pointer;
  padding: 3px 5px; border-radius: 5px; font-size: .7rem; line-height: 1.25;
  background: var(--accent-soft); border-left: 3px solid var(--accent);
  color: var(--accent-deep);
}
.avg-block:hover { filter: brightness(.97); }

/* A composed block is a list of appointments, so it is drawn as one: the block
   is a container, and each slot inside says its hour and what it is for. */
.avg-block.composed { padding: 0; overflow: hidden; }
.avg-cap {
  padding: 2px 5px; font-size: .62rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em;
  color: var(--accent-deep); opacity: .72;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.avg-slots { position: relative; }
.avg-slot {
  position: absolute; left: 3px; right: 3px;
  border-radius: 3px; padding: 1px 4px; overflow: hidden;
  background: var(--surface); border-left: 2px solid var(--accent);
  font-size: .63rem; line-height: 1.22; color: var(--ink-2);
}
.avg-slot em { font-style: normal; font-weight: 700; color: var(--accent-deep);
  font-variant-numeric: tabular-nums; }
.avg-block.off .avg-slot { background: var(--surface-3); }
.avg-over {
  position: absolute; left: 3px; right: 3px; bottom: 1px;
  font-size: .6rem; color: var(--danger); font-weight: 600;
}
.avg-block b { display: block; font-size: .72rem; }
.avg-block span { display: block; opacity: .8; font-variant-numeric: tabular-nums; }
.avg-block .avg-plan { font-style: italic; }
.avg-block.public { border-left-style: double; border-left-width: 5px; }
.avg-block.off { opacity: .45; background: var(--surface-3); border-left-color: var(--ink-4); color: var(--ink-3); }

/* `display: flex` below would otherwise beat [hidden] on source order, and the
   draft rectangle would sit at the top of every column as a dashed stripe. */
.avg-draft[hidden] { display: none; }
.avg-draft {
  position: absolute; left: 2px; right: 2px; z-index: 3; pointer-events: none;
  border: 2px dashed var(--accent); border-radius: 5px;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  display: flex; align-items: center; justify-content: center;
  font-size: .7rem; font-weight: 700; color: var(--accent-deep);
  font-variant-numeric: tabular-nums;
}


/* ---------------------------------------------- ringed from the timeline */

/* The appointment you came here to look at, ringed rather than opened: you
   asked where it sits, and the answer is a place on the grid with the rest of
   the week around it. Clicking it opens it, like any other. */
.appt.ringed, .day-item.ringed {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 20%, transparent);
  z-index: 4;
}
@keyframes ring-pulse {
  0%   { box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 34%, transparent); }
  100% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 14%, transparent); }
}
.appt.ringed, .day-item.ringed { animation: ring-pulse 1.1s ease-in-out 3 alternate; }
@media (prefers-reduced-motion: reduce) {
  .appt.ringed, .day-item.ringed { animation: none; }
}

/* ------------------------------------------- choosing a day for a surgery */

.pick-bar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 9px 16px; background: var(--accent-soft);
  border-bottom: 1px solid var(--accent-line); color: var(--accent-deep);
  font-size: .84rem;
}
.pick-bar .pick-what { display: inline-flex; align-items: center; gap: 7px; font-weight: 600; }
.pick-bar svg { width: 15px; height: 15px; }
.pick-bar .pick-hint { color: var(--accent-deep); opacity: .8; }
.pickable { position: relative; }
.pickable:hover { box-shadow: inset 0 0 0 2px var(--accent); }

.plan-day {
  display: flex; align-items: center; gap: 9px;
  padding: 10px 12px; border-radius: var(--radius-sm);
  background: var(--accent-soft); color: var(--accent-deep); margin-bottom: 12px;
}
.plan-day svg { width: 16px; height: 16px; flex: none; }
.plan-day .btn { margin-left: auto; }

.plan-list { border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; }
.plan-list-head {
  padding: 6px 11px; background: var(--surface-2); border-bottom: 1px solid var(--line);
  font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-3);
}
.plan-list-row {
  display: flex; align-items: center; gap: 9px; padding: 7px 11px;
  border-bottom: 1px solid var(--line-soft); font-size: .84rem;
}
.plan-list-row:last-child { border-bottom: 0; }
.plan-list-row .pos {
  flex: none; width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center; font-size: .72rem; font-weight: 700;
  background: var(--surface-3); color: var(--ink-2);
}


/* --------------------------------------- invoicing several payments at once */

/* The bar appears only when something is ticked. An action bar with nothing to
   act on is furniture. */
.sel-bar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 9px 14px; background: var(--accent-soft);
  border-bottom: 1px solid var(--accent-line); color: var(--accent-deep);
  font-size: .84rem;
}
.sel-bar .btn { flex: none; }
table.data th.tick, table.data td.tick { width: 34px; padding-left: 12px; padding-right: 0; }
table.data td.tick input, table.data th.tick input { cursor: pointer; margin: 0; }


/* ------------------------------------------- documents the patient brought */

.upload-preview { margin-top: 10px; }
.upload-preview img {
  max-height: 190px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); display: block;
}
.upload-preview .pdf-chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 12px; border-radius: var(--radius-sm);
  background: var(--surface-2); border: 1px solid var(--line);
  font-size: .84rem;
}
.upload-preview .pdf-chip svg { width: 16px; height: 16px; }
.center { text-align: center; }


/* --------------------------------------------------- the questionnaire editor */

/* Three languages side by side rather than behind a switch: a question written
   in English and never translated is not a bug you notice — it is a question a
   Greek patient silently cannot answer. The empty box is the warning. */
.fe { display: flex; flex-direction: column; gap: 14px; }
.fe-langs { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.fe-langs.grow { flex: 1; }
.fe-langs input, .fe-langs textarea { font-size: .84rem; }
.fe-top { display: flex; flex-direction: column; gap: 10px; }

.fe-section {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 11px; background: var(--surface-2);
}
.fe-sec-head { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 10px; }
.fe-sec-actions { display: flex; gap: 2px; flex: none; }

.fe-fields { display: flex; flex-direction: column; gap: 9px; }
.fe-q {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 9px; background: var(--surface);
}
.fe-q-head { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; flex-wrap: wrap; }
.fe-q-head .check.tiny { padding: 0; font-size: .74rem; }
.fe-opts, .fe-map { margin-top: 7px; }
.fe-opts textarea { font-family: var(--mono, ui-monospace, monospace); font-size: .76rem; }
.fe-map { display: flex; align-items: center; gap: 8px; }
.fe-map select { flex: 1; }

@media (max-width: 760px) {
  .fe-langs { grid-template-columns: 1fr; }
}


/* ------------------------------------------- picking a procedure from a list */

.proc-combo { min-width: 0; }
.pc-row { display: flex; gap: 6px; align-items: center; }
.pc-row .pc-select, .pc-row .pc-text { flex: 1; min-width: 0; }
.pc-row .btn, .pc-row .icon-btn { flex: none; }



/* A card that runs the full width of a two-column settings grid. */
.grid.c2 > .card.span2 { grid-column: 1 / -1; }


/* -------------------------------- a composed block, written out in the list */

.av-slots {
  list-style: none; margin: 8px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 4px 14px;
}
.av-slots li {
  display: flex; align-items: baseline; gap: 8px;
  font-size: .8rem; padding-left: 9px; position: relative;
}
.av-slots li::before {
  content: ''; position: absolute; left: 0; top: 5px;
  width: 3px; height: calc(100% - 8px); min-height: 10px;
  border-radius: 2px; background: var(--t, var(--ink-4));
}
.av-slots li b { font-variant-numeric: tabular-nums; color: var(--ink-2); flex: none; }
.av-slots li span { color: var(--ink); min-width: 0; }
.av-slots li.over { color: var(--danger); font-weight: 600; grid-column: 1 / -1; }
.av-slots li.over svg { width: 14px; height: 14px; vertical-align: -2px; }


/* =========================================================================
   The injection map
   -------------------------------------------------------------------------
   Three columns on a desk, two on an iPad in landscape, and one stacked
   column on a phone — but the diagram is never the thing that shrinks. It is
   what the screen is for; the panels move around it.
   ========================================================================= */

.inj-wrap { display: flex; flex-direction: column; gap: 12px; min-height: 0; }

.inj-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding-bottom: 10px; border-bottom: 1px solid var(--line);
}
.inj-head .spacer { flex: 1; }
.inj-who { display: flex; flex-direction: column; line-height: 1.25; }

.inj-body {
  display: grid; grid-template-columns: 236px minmax(0, 1fr) 260px;
  gap: 14px; align-items: start;
}
.inj-side { display: grid; gap: 12px; align-content: start; }

.inj-panel {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 11px 12px;
}
.inj-panel-head {
  font-size: .72rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--ink-3); margin-bottom: 8px;
}
.inj-panel textarea { width: 100%; }

/* ---- the loaded syringe ---- */

.inj-vial {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 7px 8px; border: 1px solid var(--line); border-radius: 9px;
  background: var(--surface-2); cursor: pointer; text-align: left;
}
.inj-vial + .inj-vial { margin-top: 6px; }
.inj-vial.on { border-color: var(--accent); background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent-line); }
.inj-vial-body { display: flex; flex-direction: column; min-width: 0; flex: 1; line-height: 1.3; }
.inj-vial-body b { font-size: .82rem; }
.inj-vial-body span { font-size: .72rem; }
.inj-swatch { width: 12px; height: 12px; border-radius: 50%; flex: none; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15); }
.inj-swatch.sm { width: 9px; height: 9px; }

.inj-patterns { display: grid; gap: 5px; }
.inj-patterns .btn { justify-content: flex-start; font-size: .78rem; }

/* ---- the drawing ---- */

.inj-stage { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.inj-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.inj-tools .spacer { flex: 1; }
.check.inline { display: inline-flex; align-items: center; gap: 5px; font-size: .76rem; margin: 0; }

.inj-canvas {
  position: relative; overflow: hidden;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  display: flex; align-items: center; justify-content: center;
  min-height: 380px; padding: 10px;
  /* Safari will otherwise take the pan and pinch for itself, and the pen with
     it. Every gesture on this surface is handled in JavaScript. */
  touch-action: none;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
}
.inj-svg {
  width: auto; height: min(64vh, 620px); max-width: 100%;
  transform-origin: center center; will-change: transform;
  cursor: crosshair;
}

.inj-diagram .fm-skin path { fill: var(--surface-3); stroke: var(--line-strong); stroke-width: 1.2; }
.inj-diagram .fm-line path { fill: none; stroke: var(--ink-4); stroke-width: 1.1; stroke-linecap: round; }
.inj-diagram .fm-iris circle { fill: var(--ink-4); opacity: .5; }

/* Outlines rather than washes: the sites genuinely do overlap on a face, and
   twenty translucent filled discs stacked up is a purple bruise rather than a
   diagram. The one under the pen fills in. */
.inj-zone { fill: none; stroke: var(--accent); stroke-width: 1; stroke-dasharray: 3 3; opacity: .5; }
.inj-zone.toxin { stroke: var(--info); }
.inj-zone.filler { stroke: var(--purple); }
.inj-zones circle.hot { fill: currentColor; opacity: .28; stroke-dasharray: none; stroke-width: 1.6; }
.inj-zone.toxin.hot { color: var(--info); }
.inj-zone.filler.hot { color: var(--purple); }
.inj-zones circle { pointer-events: none; }
/* One label, following the pointer. Fifty-seven of them at once is a diagram
   nobody can read, and the only one anybody wants is the one under the pen. */
.inj-zone-label {
  font-size: 9px; font-weight: 600; fill: var(--ink); text-anchor: middle;
  paint-order: stroke; stroke: var(--surface); stroke-width: 3.4; pointer-events: none;
}

.inj-mark { stroke: var(--surface); stroke-width: 1.2; }
.inj-thread { stroke-width: 2.6; stroke-linecap: round; opacity: .85; }
/* Drawn small, hit big: a four-unit dot is six pixels and answers to forty. */
.inj-hit { fill: transparent; cursor: grab; }
.inj-pt.sel .inj-hit { cursor: grabbing; }
.inj-ring { fill: none; stroke: var(--accent); stroke-width: 1.8; opacity: .9; }
.inj-prev .inj-mark { fill: none !important; stroke: var(--ink-4); stroke-width: 1.4; opacity: .65; }
.inj-prev .inj-thread { stroke: var(--ink-4); opacity: .4; }

.inj-loaded { display: inline-flex; align-items: center; gap: 6px; }
.inj-loaded .linkish {
  border: 1px solid var(--line-strong); background: var(--surface); border-radius: 6px;
  width: 26px; height: 26px; font-size: 1rem; line-height: 1; cursor: pointer; color: var(--ink);
}
.inj-loaded .linkish:hover { background: var(--surface-3); }

/* The three sizes. Red four clicks, blue two, black one — the button carries
   the same dot it will draw, at the same relative size, so what you are about
   to place is visible before you place it. */
.inj-tiers { display: inline-flex; gap: 6px; align-items: stretch; }
.inj-tier {
  display: flex; align-items: center; gap: 7px; cursor: pointer;
  border: 1px solid var(--line-strong); background: var(--surface);
  border-radius: var(--radius-sm); padding: 5px 10px; color: var(--ink);
  font-size: .78rem; line-height: 1.15; min-height: 38px;
}
.inj-tier:hover { background: var(--surface-3); }
.inj-tier.on { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.inj-tier-dot { border-radius: 50%; flex: none; display: inline-block; }
.inj-tier-n { font-weight: 600; white-space: nowrap; }
.inj-tier small { color: var(--ink-3); white-space: nowrap; }
@media (max-width: 700px) {
  .inj-tier { padding: 6px 8px; }
  .inj-tier small { display: none; }
}

/* Editing what a consultation note asks you: the kinds down the side, the
   sections of the selected one beside them. Collapses to one column on a
   tablet, where the list becomes a row of chips above the panel. */
.cf-wrap { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: 16px; align-items: start; }
.cf-list { display: flex; flex-direction: column; gap: 4px; }
.cf-item {
  display: flex; flex-direction: column; gap: 2px; text-align: left; cursor: pointer;
  border: 1px solid var(--line); background: var(--surface); color: var(--ink);
  border-radius: var(--radius-sm); padding: 8px 10px; font-size: .82rem;
}
.cf-item:hover { background: var(--surface-3); }
.cf-item.on { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.cf-item.off { opacity: .55; }
@media (max-width: 900px) {
  .cf-wrap { grid-template-columns: 1fr; }
  .cf-list { flex-direction: row; flex-wrap: wrap; }
  .cf-item { flex: 1 1 160px; }
}

/* Photographing the pack. */
.scan-wrap { position: relative; border-radius: var(--radius); overflow: hidden; background: #000; }
.scan-wrap video { width: 100%; max-height: 52vh; display: block; object-fit: cover; }
.scan-frame {
  position: absolute; inset: 22% 30%; border: 2px solid rgba(255, 255, 255, .85);
  border-radius: 8px; box-shadow: 0 0 0 100vmax rgba(0, 0, 0, .35);
  pointer-events: none;
}
.scan-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 8px 0; }
.scan-row .hint.ok { color: var(--ok); }
.scan-shot { max-height: 140px; border-radius: var(--radius-sm); border: 1px solid var(--line); }

/* A label and its value on one line, the value hard right. Used by the
   injection totals and by the calendar panel in Settings — which has been
   asking for it since it was written and quietly running without it. */
.kv { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 3px 0; }
.kv > span { color: var(--ink-3); min-width: 0; }
.kv > b { flex: none; font-variant-numeric: tabular-nums; }
.kv.small { font-size: .78rem; }

/* ---- what was given ---- */

.inj-rows { display: grid; gap: 2px; max-height: 320px; overflow-y: auto; }
.inj-row {
  display: flex; align-items: center; gap: 7px; padding: 4px 6px;
  border-radius: 7px; font-size: .78rem; cursor: pointer;
}
.inj-row:hover { background: var(--surface-3); }
.inj-row.on { background: var(--accent-soft); }
.inj-num {
  flex: none; width: 19px; height: 19px; border-radius: 50%; background: var(--surface-3);
  color: var(--ink-3); font-size: .66rem; display: grid; place-items: center;
  font-variant-numeric: tabular-nums;
}
.inj-row-zone { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inj-row-dose { font-variant-numeric: tabular-nums; font-weight: 600; flex: none; }
.inj-row-del { opacity: 0; flex: none; }
.inj-row:hover .inj-row-del, .inj-row.on .inj-row-del { opacity: .7; }
@media (hover: none) { .inj-row-del { opacity: .7; } }

.inj-zonetotals { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line); }

.inj-event {
  border-left: 3px solid var(--line-strong); padding: 4px 0 4px 8px; margin-bottom: 6px;
  display: flex; flex-direction: column; font-size: .78rem;
}
.inj-event.urgent { border-left-color: var(--danger); }
.inj-event.urgent b { color: var(--danger); }

/* ---- iPad: two columns, the second folded underneath ---- */
@media (max-width: 1180px) {
  .inj-body { grid-template-columns: 220px minmax(0, 1fr); }
  .inj-side:last-child { grid-column: 1 / -1; grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 820px) {
  .inj-body { grid-template-columns: 1fr; }
  .inj-side, .inj-side:last-child { grid-template-columns: 1fr; grid-column: auto; }
  .inj-stage { order: -1; }
  .inj-svg { height: min(52vh, 460px); }
  .inj-canvas { min-height: 300px; }
}


/* =========================================================================
   Phone and iPad
   -------------------------------------------------------------------------
   Three real shapes, not a desktop that shrinks:

   · **Phone** (≤ 700px) — one column, tabs along the bottom, tables become
     cards because a five-column table on a 390-pixel screen is unreadable at
     any font size, and modals arrive as sheets from the bottom edge.
   · **iPad portrait** (700–1100px) — an icon rail rather than the phone's
     bottom bar. An iPad is not a big phone: it has room for navigation down
     the side and a hand is already at the edge of the screen.
   · **iPad landscape and desk** (> 1100px) — the full sidebar, unchanged.

   Everything below the first block is about touch rather than width, and is
   asked for with `pointer: coarse` — which is the honest question. A laptop
   with a small window is still a mouse, and shoving 44-pixel targets at it
   wastes the screen.
   ========================================================================= */

/* ---- the rail: an iPad in portrait, and a narrow desktop window ---- */
@media (min-width: 701px) and (max-width: 1100px) {
  :root { --sidebar-w: 62px; }
  .sidebar-brand { padding: 16px 0 12px; justify-content: center; }
  .sidebar-brand div { display: none; }
  .nav { padding: 6px 7px; }
  .nav a {
    flex-direction: column; gap: 3px; padding: 9px 2px; font-size: .58rem;
    text-align: center; line-height: 1.15; letter-spacing: .01em;
  }
  .nav a svg { width: 20px; height: 20px; opacity: .9; }
  .nav-section { display: none; }
  .nav .badge {
    margin: 0; position: absolute; top: 4px; right: 8px;
    font-size: .58rem; padding: 0 4px; line-height: 14px; min-width: 14px;
  }
  .nav a { position: relative; }
  /* On the rail there is no hover to reveal anything with, and the tile is
     the target for the screen — so the chevron takes the bottom corner and
     stays there. Small, but a secondary control beside a whole-tile primary. */
  .nav-more {
    top: 2px; right: 2px; bottom: auto; transform: none;
    width: 18px; height: 18px; opacity: .6; pointer-events: auto;
  }
  .nav-more svg { width: 12px; height: 12px; }
  .nav a:hover .nav-badge, .nav a:focus-within .nav-badge { opacity: 1; }
  .sidebar-user span, .sidebar-user b { display: none; }
  .sidebar-foot { padding: 10px 0 calc(12px + env(safe-area-inset-bottom)); }
  .sidebar-user { justify-content: center; }
  /* The bottom bar is the phone's answer; the rail is the iPad's. Never both. */
  .mobile-nav { display: none !important; }
  .content { padding: 16px; }
}

/* The bottom bar stops at 700 rather than 900, so an iPad portrait gets the
   rail above instead of a phone's tab bar. */
@media (min-width: 701px) and (max-width: 900px) {
  .shell { grid-template-columns: var(--sidebar-w) 1fr; }
  .sidebar { display: flex; }
  .content { padding-bottom: 16px; }
}

/* ---- phone ---- */
@media (max-width: 700px) {
  /* An appointment chip must never spill out of its column: at fifty pixels a
     name that overflows lands on top of the next day's. */
  .appt { overflow: hidden; }
  .appt b, .appt span { display: block; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; }
  /* Seven columns do not fit; the day view is the default here, and the week
     grid scrolls sideways for anyone who asks for it anyway. */
  /* The week and the bookable-time grids keep their real column widths and
     scroll sideways inside their own card. Squeezing seven columns into three
     hundred and ninety pixels makes both unreadable. */
  .agenda-grid { min-width: 720px; }
  .avg-grid { min-width: 720px; }
  #view > .card:has(> .agenda-grid), .agenda-scroll, .avg-wrap {
    overflow-x: auto; -webkit-overflow-scrolling: touch;
  }
  .content { padding: 12px 12px calc(84px + env(safe-area-inset-bottom)); }
  h1 { font-size: 1.12rem; }
  .card-body { padding: 13px; }
  .btn-row { flex-wrap: wrap; }

  /* A wide table becomes a stack of labelled cards. The header cells are
     carried down as ::before labels, so one markup serves both shapes and no
     view has to know which screen it is on. */
  .table-wrap.cards table.data,
  .table-wrap.cards table.data tbody,
  .table-wrap.cards table.data tr { display: block; width: 100%; }
  .table-wrap.cards table.data thead { display: none; }
  .table-wrap.cards table.data tr {
    border: 1px solid var(--line); border-radius: var(--radius-sm);
    padding: 9px 11px; margin-bottom: 8px; background: var(--surface);
  }
  .table-wrap.cards table.data td {
    display: flex; justify-content: space-between; gap: 12px;
    border: 0; padding: 3px 0; text-align: right;
  }
  .table-wrap.cards table.data td::before {
    content: attr(data-label); color: var(--ink-3); font-size: .74rem;
    text-align: left; flex: none; font-weight: 500;
  }
  .table-wrap.cards table.data td:empty { display: none; }
  /* A column with no heading is a chevron or an edit pencil. On a card the
     whole row is the target, so the arrow is a line of nothing. */
  .table-wrap.cards table.data td:not([data-label]) { display: none; }

  /* Everything else scrolls sideways rather than being crushed. */
  .table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  table.data { min-width: 520px; }
  .table-wrap.cards table.data { min-width: 0; }

  .tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  .tabs button { flex: none; }
}

/* ---- touch, at any width ---- */
@media (pointer: coarse) {
  /* Forty-four points is Apple's number and it is the right one. Inputs get
     16px because anything smaller makes iOS zoom the page on focus, which
     then leaves the field half off the screen. */
  .btn, .icon-btn, .tabs button, .chip, .nav a, .mobile-nav a { min-height: 44px; }
  .btn.sm, .icon-btn.sm { min-height: 38px; }
  input, select, textarea { font-size: 16px; min-height: 42px; }
  input[type="checkbox"], input[type="radio"] { min-height: 0; width: 20px; height: 20px; }
  .check { padding: 4px 0; }
  /* A row you can tap is a row that must not also select its own text. */
  tr.clickable, .list-item.clickable, .chip { -webkit-tap-highlight-color: transparent; }
  .inj-row-del, .copy-btn { opacity: .7; }
}

/* An iPad in landscape is a desk with a pen: keep the density, keep the
   targets. This is the one place the two rules above would disagree. */
@media (pointer: coarse) and (min-width: 1024px) {
  .content { padding: 18px; }
}

/* ---- installed as an app ---- */
@media (display-mode: standalone) {
  /* No browser chrome above the bar any more, so the app owns the notch. */
  .topbar { padding-top: env(safe-area-inset-top); height: calc(var(--header-h) + env(safe-area-inset-top)); }
  .sidebar { padding-top: env(safe-area-inset-top); }
  .mobile-nav { padding-bottom: calc(6px + env(safe-area-inset-bottom)); }
}

/* Stop iOS enlarging text in landscape, which silently breaks every layout
   that was measured in portrait. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

/* ---- the note under an email box ----------------------------------------
 * Amber for "is that right?", red for "that cannot receive mail". The button
 * is the whole point: the suggestion is one tap away while the patient is
 * still at the desk. */
.addr-note {
  display: flex; align-items: flex-start; gap: 6px; flex-wrap: wrap;
  margin: 6px 0 0; font-size: .76rem; line-height: 1.45;
}
.addr-note > svg { width: 14px; height: 14px; flex: none; margin-top: 2px; }
.addr-note.warn { color: var(--warn); }
.addr-note.bad { color: var(--danger); }
.addr-note .addr-use {
  border: 1px solid currentColor; background: transparent; color: inherit;
  border-radius: 999px; padding: 1px 9px; font: inherit; font-size: .74rem; cursor: pointer;
}
.addr-note .addr-use b { font-weight: 700; }
.addr-note .addr-use:hover { background: color-mix(in srgb, currentColor 10%, transparent); }

/* A button that reads as a link, for the small "forget it" kind of action
   that does not deserve a box. */
.link-btn {
  border: 0; background: none; padding: 0; font: inherit; color: var(--accent);
  text-decoration: underline; cursor: pointer;
}
