/* App surfaces (booking, manage, barber, admin) share the site's design system.
   Fonts load from the site being served at web root. */
@font-face { font-family: 'Anton'; src: url('/assets/fonts/anton-latin.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Archivo'; src: url('/assets/fonts/archivo-latin.woff2') format('woff2'); font-weight: 100 900; font-display: swap; }

:root {
  --bg: #0b0d11; --surface: #14171d; --surface-hi: #1a1e26;
  --line: #262b34; --line-hi: #39404c;
  --text: #f4f5f7; --muted: #98a0ad;
  --red: #e03a3d; --red-soft: rgba(224, 58, 61, 0.13);
  --green: #35c17b;
  --r: 16px; --r-sm: 10px;
  --ease: cubic-bezier(0.23, 1, 0.32, 1);
  --display: 'Anton', 'Arial Narrow', sans-serif;
  --sans: 'Archivo', system-ui, sans-serif;
}
* { box-sizing: border-box; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font-family: var(--sans); font-size: 16px; line-height: 1.6;
  -webkit-font-smoothing: antialiased; min-height: 100dvh;
}
h1, h2, h3, p, ul { margin: 0; }
ul { padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; padding: 0; }
input, select, textarea {
  font: inherit; color: var(--text); background: var(--surface);
  border: 1px solid var(--line-hi); border-radius: var(--r-sm);
  padding: 0.8rem 1rem; width: 100%;
}
input:focus-visible, select:focus-visible, textarea:focus-visible, button:focus-visible, a:focus-visible {
  outline: 2px solid var(--red); outline-offset: 2px;
}

.shell { max-width: 860px; margin-inline: auto; padding: 1.25rem; }
.wide { max-width: 1280px; }
/* The dashboard is the widest screen in the shop. Capping it wastes the half
   of the monitor the schedule most wants. */
.full { max-width: none; padding-inline: 1.5rem; }

.top {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1rem 1.25rem; border-bottom: 1px solid var(--line);
  padding-top: calc(1rem + env(safe-area-inset-top, 0px));
  position: sticky; top: 0; background: rgba(11,13,17,0.9);
  backdrop-filter: blur(12px); z-index: 20;
}
.brand { font-family: var(--display); letter-spacing: 0.05em; font-size: 1rem; }
.brand .the { font-size: 0.62em; color: var(--muted); }
.brand .shave { color: var(--red); }

.h-display {
  font-family: var(--display); font-weight: 400; text-transform: uppercase;
  letter-spacing: 0.01em; line-height: 0.95;
}

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  padding: 0.9rem 1.6rem; border-radius: var(--r-sm); font-weight: 600;
  border: 1px solid transparent; white-space: nowrap;
  transition: background-color 180ms var(--ease), border-color 180ms var(--ease), transform 140ms var(--ease);
}
.btn:active { transform: scale(0.97); }
.btn-primary { background: var(--red); color: #fff; }
.btn-primary:hover { background: #ee4649; }
.btn-ghost { border-color: var(--line-hi); }
.btn-ghost:hover { border-color: var(--text); }
.btn[disabled] { opacity: 0.45; pointer-events: none; }

.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); padding: 1.25rem;
}

.chip {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0.55rem 0.9rem; border: 1px solid var(--line-hi);
  border-radius: var(--r-sm); font-weight: 600; font-size: 0.95rem;
  transition: border-color 140ms var(--ease), background-color 140ms var(--ease), transform 140ms var(--ease);
}
.chip:hover { border-color: var(--text); }
.chip:active { transform: scale(0.96); }
.chip.on { background: var(--red); border-color: var(--red); color: #fff; }
.chip.off { opacity: 0.35; pointer-events: none; }

[hidden] { display: none !important; }

/* The walk-in queue — someone standing at the kiosk waiting for a chair. Amber
   so it reads as "act now", and the claim button is the whole point. */
.queue { border: 1px solid rgba(229,161,58,0.4); background: rgba(229,161,58,0.07);
         border-radius: var(--r); padding: 0.85rem 1rem; margin-bottom: 1rem; }
.queue h3 { margin: 0 0 0.6rem; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.08em;
            color: #e5a13a; }
.qrow { display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem 0; }
.qrow + .qrow { border-top: 1px solid var(--line); }
.qrow .qn { font-weight: 650; }
.qrow .qs { color: var(--muted); font-size: 0.85rem; }
.qrow .qw { color: #e5a13a; font-size: 0.8rem; margin-left: auto; white-space: nowrap; }
.qrow .qclaim { flex: 0 0 auto; }
/* The take-next panel: who is next, how long they have waited, one button. No
   list to skim — so nobody races for the phone and nobody cherry-picks the
   expensive cut off the top of the line. */
.qnext { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem; margin-bottom: 0.6rem; }
.qnext .qn { font-weight: 700; font-size: 1.15rem; }
.qnext .qw { color: #e5a13a; font-size: 0.8rem; margin-left: auto; }
.qtake { width: 100%; padding: 0.85rem !important; font-size: 1rem !important; }
.qrest { color: var(--muted); font-size: 0.78rem; margin: 0.5rem 0 0; }
.qpick { display: flex; gap: 0.4rem; flex-wrap: wrap; margin-top: 0.4rem; }

/* A sheet is open: freeze the page behind it WITHOUT moving it. overflow
   stops programmatic/wheel scrolling; touch-action:none stops iOS touch
   scrolling (the part overflow alone never could); the dialog sits in the
   top layer and restores its own touch handling. Nothing is repositioned,
   so closing a sheet cannot jump or flash. */
html.sheet-open, html.sheet-open body { overflow: hidden !important; }
html.sheet-open body { touch-action: none; }
dialog[open] { touch-action: auto; }

.muted { color: var(--muted); }
.small { font-size: 0.875rem; }
.error { color: #ff7b7d; font-weight: 600; }
.grid { display: grid; gap: 0.75rem; min-width: 0; }
.row { display: flex; gap: 0.75rem; flex-wrap: wrap; align-items: center; min-width: 0; }
.spread { justify-content: space-between; }
.stack { display: grid; gap: 1.25rem; min-width: 0; }

/* Grid and flex children default to min-width:auto, so they refuse to shrink
   below their content. A horizontally scrollable child (the day strip) then
   stretches the whole page instead of scrolling inside itself, which pushed
   the Next button off screen on phones. Letting these shrink to zero is what
   makes the inner overflow actually work. */
.stack > *, .grid > *, .row > * { min-width: 0; }

.toast {
  position: fixed; left: 50%; bottom: 1.5rem; transform: translateX(-50%);
  background: var(--surface-hi); border: 1px solid var(--line-hi);
  border-radius: var(--r-sm); padding: 0.8rem 1.2rem; z-index: 50;
  box-shadow: 0 20px 50px rgba(0,0,0,0.5); max-width: min(92vw, 480px);
}

@media (prefers-reduced-motion: reduce) {
  .btn, .chip { transition: none; }
}

/* The returning-customer line in the walk-in dialog: quiet, but it is the
   difference between retyping someone's details and greeting them by name. */
.known { margin: -0.25rem 0 0; padding: 0.5rem 0.7rem; border-radius: var(--r-sm);
         background: rgba(62,203,134,0.09); border: 1px solid rgba(62,203,134,0.28);
         color: #9fe3c1; font-size: 0.82rem; }
.known[hidden] { display: none; }

/* ── the lane: one chair's day, proportional. Shared by /me and the owner's
   phone via lane.js. ── */
.lane { position: relative; margin-left: 50px; border-left: 1px solid var(--line);
        background: rgba(255,255,255,0.018); border-radius: 0 10px 10px 0; }
.lhr { position: absolute; left: 0; right: 0; border-top: 1px solid rgba(255,255,255,0.05);
       pointer-events: none; }
.lhr.half { border-top-color: rgba(255,255,255,0.024); }
/* The tap ghost: shows exactly which slot a tap snapped to, on the grid
   itself, and stays put while the booking sheet is open so there is never a
   doubt about where the appointment is about to land. */
/* The change history. Quiet by design: it is a reference, not a headline. */
.hist { margin: 0 0 1rem; padding: 0.6rem 0 0; border-top: 1px solid var(--line); }
.hist p { display: flex; gap: 0.4rem; margin: 0.28rem 0; font-size: 0.82rem; color: var(--muted); }
.hist p span:first-child { color: var(--text); }
.hist .hw { margin-left: auto; white-space: nowrap; opacity: 0.75; }

/* Walked in / called in. Two buttons rather than a checkbox: the counter is
   answering a question about the person in front of them, not ticking a box. */
.wvia { display: flex; gap: 0.4rem; margin-top: 0.85rem; }
.wvia button { flex: 1; padding: 0.55rem 0.5rem; font: inherit; font-size: 0.92rem;
               color: var(--muted); background: transparent; cursor: pointer;
               border: 1px solid var(--line); border-radius: 10px; }
.wvia button.on { color: var(--text); border-color: var(--green); background: rgba(62,203,134,0.10); }

/* "Blocking this time instead?" -- the other thing an empty slot means. */
.swap { display: inline-block; margin-top: 0.4rem; background: none; border: 0; padding: 0;
        color: var(--green); font: inherit; font-size: 0.86rem; text-decoration: underline;
        text-underline-offset: 3px; cursor: pointer; }
.swap:hover { opacity: 0.8; }

/* Changing what is being cut, from the appointment itself. */
.svcedit { display: flex; align-items: center; gap: 0.6rem; margin: 0 0 1rem; }
.svcedit span { font-size: 0.78rem; letter-spacing: 0.05em; text-transform: uppercase; color: var(--dim); }
.svcedit select { flex: 1; }

/* A guest whose barber has not been chosen yet. */
.needpick { border-color: var(--red) !important; }

/* A second corner button, sitting beside the walk-in one. */
.fab2 { right: auto !important; left: 1.25rem; background: var(--surface) !important;
        color: var(--ink) !important; border: 1px solid var(--line) !important; }
.fab2:hover { border-color: var(--ink) !important; }

/* The counter's date picker: the heading is the button. */
.dpick { background: none; border: 0; padding: 0; font: inherit; color: inherit; cursor: pointer;
         display: inline-flex; align-items: baseline; gap: 0.4rem; }
.dpick:hover { opacity: 0.85; }
.dcar { font-size: 0.55em; color: var(--dim); }

.confirm-sheet.cal { min-width: min(21rem, 92vw); }
.calhead { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; margin-bottom: 0.75rem; }
.calhead strong { font-size: 1.02rem; }
.caldow { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; margin-bottom: 0.3rem; }
.caldow span { text-align: center; font-size: 0.7rem; letter-spacing: 0.06em; color: var(--dim); text-transform: uppercase; }
.calgrid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cd { aspect-ratio: 1; border: 0; background: none; color: var(--ink); border-radius: 7px;
      font: inherit; font-variant-numeric: tabular-nums; cursor: pointer; min-height: 2.4rem; }
.cd:hover { background: rgba(255,255,255,0.07); }
.cd.empty { pointer-events: none; }
.cd.past { color: var(--dim); }
.cd.today { box-shadow: inset 0 0 0 1.5px var(--red); }
.cd.on { background: var(--green); color: #06210f; font-weight: 700; }
.cd.on:hover { background: var(--green); }

/* Who is actually coming, when a booking is more than one person. */
.party { border: 1px solid var(--line); border-radius: 8px; padding: 0.6rem 0.75rem; margin-bottom: 1rem; }
.party h4 { margin: 0 0 0.45rem; font-size: 0.82rem; letter-spacing: 0.03em; text-transform: uppercase;
            color: var(--green); font-weight: 700; }
.prow { display: grid; grid-template-columns: 4.6rem 1fr auto; gap: 0.6rem; align-items: baseline;
        padding: 0.22rem 0; font-size: 0.94rem; }
.prow + .prow { border-top: 1px solid var(--line); }
.prow .pt { color: var(--dim); font-variant-numeric: tabular-nums; }
.prow .ps { color: var(--dim); font-size: 0.86rem; }

/* The counter board's day bar: arrows either side of the day it is showing. */
.dbar { display: flex; align-items: center; gap: 0.6rem; }
.daynav { background: none; border: 1px solid var(--line); color: var(--ink);
          width: 2rem; height: 2rem; border-radius: 6px; font-size: 1.15rem; line-height: 1;
          cursor: pointer; flex: none; }
.daynav:hover { border-color: var(--ink); }
.dbar .today { margin-left: 0.35rem; }

/* The counter board's tap ghost, same idea as the barber lane's. */
.appt.ghost { border: 1.5px dashed var(--green) !important; background: rgba(62,203,134,0.10) !important;
              pointer-events: none; }
.appt.ghost .tm { color: var(--green); font-weight: 700; }

.lghost { position: absolute; left: 10px; right: 6px; z-index: 2; pointer-events: none;
          border: 1.5px dashed var(--green); border-radius: 10px;
          background: rgba(62,203,134,0.10); display: flex; align-items: center;
          padding-left: 12px; color: var(--green); font-weight: 700; font-size: 0.82rem; }
.lmark { position: absolute; left: -50px; width: 42px; text-align: right;
         font-size: 0.7rem; color: var(--muted); transform: translateY(-7px); }
.ltick { position: absolute; left: -4px; width: 8px; border-top: 1px solid var(--line); }
.lap { position: absolute; left: 10px; right: 0; border-radius: 10px;
       padding: 6px 10px 6px 12px; overflow: hidden; line-height: 1.3;
       background: var(--c-bg); cursor: pointer;
       transition: opacity 180ms var(--ease), transform 120ms var(--ease); }
.lap:active { transform: scale(0.985); }
.lap::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
               background: var(--c); border-radius: 10px 0 0 10px; }
/* Both rows are laid out across the block's full width instead of stacking at
   its left edge: what the cut is on the left, what is unusual about it on the
   right. The block was always this wide; only a third of it was being used. */
.lap .t, .lap .n { display: flex; align-items: baseline; gap: 8px; }
.lap .t { font-size: 0.72rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.lap .t .tl, .lap .n .who { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lap .n { font-weight: 650; font-size: 0.95rem; }
.lap .src { margin-left: auto; flex: 0 0 auto; font-size: 0.66rem; font-weight: 700;
            text-transform: uppercase; letter-spacing: 0.04em; color: #8b93a1; }
.lap .g { font-weight: 500; font-size: 0.78rem; color: var(--muted); }
/* Paid extras are work the barber must remember to do, so they read as a tag
   rather than fading into the service line — the shop charged for this. */
/* Paid extras are work the barber must remember to do, so they sit at the end
   of the name row as a tag rather than dissolving into the meta line. */
/* The extras keep their words as long as there is room; when the block is
   narrow (two bookings sharing a slot) the name gives way first, because a
   half-read name is still recognisable and a half-read service is not. */
.lap .ex, .appt .ex { margin-left: auto; flex: 0 1 auto; min-width: 0; padding: 1px 8px;
                      border-radius: 999px; background: rgba(255,255,255,0.12); color: #eef1f5;
                      font-size: 0.7rem; font-weight: 700; white-space: nowrap;
                      overflow: hidden; text-overflow: ellipsis; }
.lap .n .who { flex: 1 1 auto; }

/* Pull-to-refresh pill, and the type-ahead suggestion list in staff dialogs. */
.ptr { position: fixed; top: calc(env(safe-area-inset-top, 0px) + 10px); left: 50%;
       transform: translateX(-50%); z-index: 60; padding: 0.45rem 1rem; border-radius: 999px;
       background: var(--surface-hi); border: 1px solid var(--line-hi); color: var(--muted);
       font-size: 0.8rem; font-weight: 650; opacity: 0; pointer-events: none;
       transition: opacity 120ms linear; }
.ptr.armed { color: var(--text); border-color: var(--red); }
/* Type-ahead results must NOT look like more form fields — that is exactly how
   they got mistaken for one. They render as one attached panel: green accent,
   a spoken label, compact tappable rows with an arrow saying "pick me". */
.sugg { display: grid; gap: 0; margin-top: -0.35rem; border-radius: var(--r-sm);
        border: 1px solid rgba(62,203,134,0.45); background: rgba(62,203,134,0.06);
        overflow: hidden; }
.sugg::before { content: 'In the book — tap to fill'; display: block;
        padding: 0.4rem 0.8rem 0.3rem; font-size: 0.66rem; font-weight: 700;
        text-transform: uppercase; letter-spacing: 0.09em; color: var(--green); }
.sugg button { display: flex; align-items: baseline; gap: 0.55rem; width: 100%; text-align: left;
        padding: 0.6rem 0.8rem; background: transparent; border: 0;
        border-top: 1px solid rgba(62,203,134,0.18); color: var(--text); font-weight: 650; }
.sugg button:active { background: rgba(62,203,134,0.15); }
.sugg button::after { content: '\2192'; margin-left: 0.35rem; color: var(--green); font-weight: 400; }
.sugg .sp { margin-left: auto; color: var(--muted); font-size: 0.8rem; font-weight: 400;
        font-variant-numeric: tabular-nums; }
.sugg .sv2 { color: var(--muted); font-size: 0.76rem; font-weight: 400; }

/* Extras in the walk-in dialog: tap to add, green when on — the same language
   the customer sees on the kiosk and the booking site. */
.wex { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.wexb { font-size: 0.85rem; padding: 0.45rem 0.7rem; }
.wexb.on { border-color: var(--green); background: rgba(62,203,134,0.12); }
.wexb.on .muted { color: var(--green); }
.lap .exfull, .appt .exfull { margin-top: 3px; padding: 1px 8px; border-radius: 999px;
                      display: inline-block; background: rgba(255,255,255,0.12); color: #eef1f5;
                      font-size: 0.72rem; font-weight: 650; white-space: nowrap;
                      max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
/* A first-available booking is visibly its own thing: the accent edge goes
   amber on every board, so the owner reads "may trade chairs" at a glance. */
.lap.float::before, .appt.float::before { background: #e5a13a; }
.appt.float { border-color: rgba(229, 161, 58, 0.4); }
/* Two people in one chair: the block is half as wide, so it keeps the name and
   drops the decoration rather than truncating everything equally. */
.lap.shared { padding-left: 8px; }
.lap.shared .t { font-size: 0.66rem; }
.lap.shared .n { font-size: 0.85rem; }
.lap.shared .g { display: none; }
.lap.done { opacity: 0.42; }
.lap.noshow { opacity: 0.5; }
.lap.noshow::before { background: #ff7b7d; }
.lap.live .t { color: var(--green); font-weight: 700; }
.lap.blocked { background: transparent; border: 1px dashed var(--line-hi); }
.lap.blocked::before { display: none; }
.lap.blocked .n { font-weight: 500; font-size: 0.8rem; color: var(--muted); font-style: italic; }
.lgap { position: absolute; left: 10px; right: 0; display: flex; align-items: center; gap: 8px;
        color: #454d5a; font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.06em;
        transform: translateY(-50%); pointer-events: none; }
.lgap::before, .lgap::after { content: ''; height: 1px; background: var(--line); flex: 1; }
.lnow { position: absolute; left: -50px; right: 0; border-top: 2px solid var(--red); z-index: 3;
        pointer-events: none; }
.lnow span { position: absolute; right: 0; top: -16px; font-size: 0.68rem; font-weight: 700;
             color: var(--red); }

/* ── dialogs feel like phone sheets, not desktop alerts. On small screens they
   slide from the bottom; everywhere they fade in rather than appear. ── */
dialog { opacity: 1; transition: opacity 180ms var(--ease), transform 220ms var(--ease),
                     overlay 220ms allow-discrete, display 220ms allow-discrete; }
dialog::backdrop { background: rgba(0,0,0,0.65);
                   transition: background-color 220ms var(--ease); }
@starting-style {
  dialog[open] { opacity: 0; transform: translateY(14px); }
  dialog[open]::backdrop { background: rgba(0,0,0,0); }
}
@media (max-width: 620px) {
  dialog { position: fixed !important; left: 0 !important; right: 0 !important;
           top: auto !important; bottom: var(--kb, 0px) !important;
           margin: 0 !important; width: 100vw !important;
           max-width: 100vw !important; border-radius: 18px 18px 0 0 !important;
           border-left: 0 !important; border-right: 0 !important; border-bottom: 0 !important;
           padding: 1.1rem 1.1rem max(1.5rem, env(safe-area-inset-bottom)) !important;
           /* Pinned above the keyboard (--kb, from walkin.js), capped to the
              visual viewport's own height so the top cannot reach the island,
              scrolling inside itself. */
           max-height: calc(var(--vvh, 100dvh) - env(safe-area-inset-top, 0px) - 2.5rem) !important;
           /* Reaching the end of a sheet used to hand the scroll to the page
              underneath — you would be reading times and the schedule behind
              would slide instead. The sheet keeps its own scrolling. */
           overscroll-behavior: contain;
           overflow-y: auto; }
  /* Anything under 16px inside a form invites iOS to zoom the page on focus —
     which reads as the app randomly zooming. */
  input, select, textarea { font-size: 16px; }
  @starting-style { dialog[open] { transform: translateY(100%); opacity: 1; } }
}

/* ── installed to the home screen ── */
/* contain, on body: kills pull-to-refresh without touching scrolling itself.
   `none` on html stops iOS standalone from scrolling the page at all. */
/* On html, not body: iOS applies the intersection down the tree, and anchoring
   at the root is the form that reliably sticks in standalone mode. */
html { touch-action: manipulation; }
body { overscroll-behavior-y: contain;
  /* Tapping the day arrows twice is paging, not a request to zoom. manipulation
     keeps scrolling and pinch-zoom and removes only the double-tap gesture —
     the accessibility-safe way, unlike user-scalable=no which iOS ignores
     anyway. touch-action intersects down the tree, so body covers everything. */
  touch-action: manipulation; }
.fab { bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px)); }

/* In-app confirm: same sheet language as every other dialog. */
.confirm-sheet { background: var(--surface-hi); color: var(--text);
                 border: 1px solid var(--line-hi); border-radius: var(--r);
                 padding: 1.5rem; max-width: min(420px, 92vw); width: 100%; }
.cs-title { font-family: var(--display); font-weight: 400; text-transform: uppercase;
            font-size: 1.3rem; line-height: 1; }
.cs-body { color: var(--muted); font-size: 0.9rem; margin-top: 0.5rem; }
.cs-danger { background: var(--red); color: #fff; }

/* Move: open times grouped under each chair, not a wall of mixed chips. */
/* The move sheet is three parts: a header that stays put, the times that
   scroll, and the buttons pinned at the bottom. Before this the whole sheet
   scrolled as one, so the last row of times was sliced in half by the footer. */
.mvwrap { display: flex; flex-direction: column; min-height: 0;
          max-height: calc(var(--vvh, 82vh) - env(safe-area-inset-top, 0px) - 6rem); }
.mvtop { flex: 0 0 auto; }
.mvbody { flex: 1 1 auto; overflow-y: auto; overscroll-behavior: contain;
          min-height: 0; padding-right: 2px;
          -webkit-mask-image: linear-gradient(180deg, #000 0, #000 calc(100% - 18px), transparent 100%);
          mask-image: linear-gradient(180deg, #000 0, #000 calc(100% - 18px), transparent 100%); }
.mvfoot { flex: 0 0 auto; display: flex; gap: 0.6rem; align-items: center;
          padding-top: 0.8rem; margin-top: 0.2rem; border-top: 1px solid var(--line); }
.mvfoot .btn-ghost { margin-left: auto; }
.mvsec { margin-bottom: 0.9rem; }
.mvhead { display: flex; align-items: center; gap: 6px; font-weight: 650;
          font-size: 0.9rem; margin-bottom: 0.45rem; }
.mvchips { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 0.45rem;
           max-height: 7.6rem; overflow-y: auto; }


.mvdays { display: flex; gap: 0.4rem; overflow-x: auto; padding-bottom: 0.6rem;
          scrollbar-width: none; }
.mvdays::-webkit-scrollbar { display: none; }
.mvchips .chip { white-space: nowrap; justify-content: center; padding: 0.65rem 0.3rem;
                 font-size: 0.9rem; font-variant-numeric: tabular-nums; }
/* Group headings, so a day reads as morning / afternoon / evening instead of a
   run-on sentence of every free window. */
.mvgroup { font-size: 0.68rem; color: var(--muted); text-transform: uppercase;
           letter-spacing: 0.09em; margin: 0 0 0.45rem; }
.mvsec + .mvsec .mvgroup { margin-top: 0.2rem; }
.mvnone { color: var(--muted); padding: 1rem 0; }

/* The verbal consent script, wherever staff take a number. */
.script { background: var(--surface); border-left: 3px solid var(--red);
          border-radius: var(--r-sm); padding: 0.7rem 0.85rem;
          font-size: 0.85rem; line-height: 1.55; color: #cdd2da; }
.script strong { display: block; color: var(--muted); font-size: 0.7rem;
                 text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 0.35rem; }

/* A squeezed-in booking shares its chair's column, so the block is half width
   and keeps the name over the decoration. */
.appt.shared { padding-left: 0.5rem; padding-right: 0.35rem; }
.appt.shared .tm { font-size: 0.68rem; }
.appt.shared .nm { font-size: 0.85rem; }
.appt.shared .sv, .appt.shared .quick { display: none; }
