/* Spa — time-first Today board + Calendar + booking drawer (tasks/070).
 *
 * Spa is appointment-based: the Today board is bookings in time order grouped by
 * a derived status (Needs you / On now / Next / Done); the Calendar tab is a
 * day/week rack of the same bookings positioned by time. The whole row / cell
 * opens a persistent #drawer turbo-frame (mirrors front_office + watersports).
 *
 * DS rule (064 §6): reuse the base os-ds / HotelOS / front-office components; do
 * NOT mint a parallel namespace for what already ships. This sheet holds ONLY
 * (a) small EXTENSIONS to existing families the base omits (shared with the
 * watersports board), and (b) the few components with genuinely no base
 * equivalent (the calendar rack + its lanes). Everything else is base:
 *   KPI line ....... os-ds  .kpi-strip / __stat / __value / __label
 *   status chips ... fo-board .hos-chip + .hos-tone--* triad
 *   board rows ..... fo-board .hos-fo-rows / .hos-fo-row / .hos-fo-row__time/__t/__d/__name/__n
 *   sections ....... reservation_drawer .hos-secblock / .hos-sectitle / .hos-seccard
 *   drawer ......... reservation_drawer .hos-drawer / .hos-dhead / .hos-foot
 *   icon tiles ..... reservation_drawer .hos-itile (+ .hos-tile-44 sizing helper)
 *
 * Token-only. Neutrals = slate, accent = teal. Sky (`--status-in-water-*`) is
 * reserved for the INFERRED on-now state and nothing else; amber = attention
 * (unassigned / allergy); green = done/assigned.
 */

/* ── (a) extensions (mirror watersports_board.css) ───────────────────────
   The base `.hos-tone--*` triad ships ok/warn/crit/accent only; the board needs
   sky (inferred on-now) and slate (done/terminal). Same mechanism, two keys. */
.hos-tone--water { --tone: var(--status-in-water-fg); --tone-bg: var(--status-in-water-bg); --tone-line: var(--status-in-water-border); }
.hos-tone--slate { --tone: var(--status-returning-fg); --tone-bg: var(--status-returning-bg); --tone-line: var(--status-returning-border); }
.kpi-strip__value--warn { color: var(--warning); }

/* ── DRAWER ────────────────────────────────────────────────────────────────
   The panel now carries the gem's `.os-side-panel`, so the chassis owns the
   anatomy: `__header` (flex none) · `__body` (flex:1, the only scroller) ·
   `__action-bar` (flex none, pinned at the floor). That deletes three local
   rules that existed only to compensate for the old `.hos-drawer`
   display:contents shape — the panel-level `overflow-y`, and the per-block
   `padding-inline` that hand-aligned head / card / money to one gutter. The
   gem's 24px body inset is that gutter now. ── */

/* The therapist / room / allergy rows now ride the transport drawer's spec-row
   chassis (`.os-desclist--inline.hos-td-rows`) so the two drawers read as one
   family. The gem's `__body` already supplies the 24px gutter, so zero the
   chassis' own inline padding here to avoid a double inset; the assign form
   wraps onto its own line inside the value cell. */
.os-side-panel__body .hos-td-rows { padding-inline: 0; }
.os-side-panel__body .hos-td-rows .sp-assign__form { flex: 1 0 100%; margin-top: var(--space-1); }

/* The New/Edit booking form wraps the whole panel in a <form>. Collapse that
   form out of the box tree (display:contents) so its children — `__header`,
   `__body`, `__action-bar` — become the direct flex items of the
   `.os-side-panel` frame, exactly as the detail drawer's `.hos-drawer` does.
   Without this the form is a single flex child and the footer scrolls away
   (clips) with the body instead of pinning to the panel floor. */
.sp-drawer-form { display: contents; }

/* Footer: money above, actions below, both full width — same shape as the
   watersports drawer's `.ws-drawer-foot`. */
.sp-drawer-foot { flex-direction: column; align-items: stretch; gap: var(--space-3); }
.sp-drawer-acts { display: flex; gap: var(--space-2); }
/* button_to emits a <form> per button; forms are block-level, so without this
   the three actions stack. The primary takes the free space, the two recovery
   actions size to their labels. */
.sp-drawer-acts form { margin: 0; display: contents; }
.sp-drawer-acts .os-btn { white-space: nowrap; }
.sp-drawer-acts form:first-child .os-btn { flex: 1 1 auto; justify-content: center; }

/* The assign row's select + submit. NOTHING sizes them here on purpose: arena
   scopes `--control-h` to the 46px field rung on `form` (hotelos_ds/tokens.css),
   and since os-ds v1.6.0 `.os-input` / `.os-field-select` / `.os-btn` all read
   that same token — so an unmodified button and select in a form already share
   one height. The old defect was `.os-btn--sm` on the submit, which re-declares
   the trio at 32px and sat 14px short. Fixed by dropping the modifier, not by
   pinning heights here. */
.sp-assign__form { display: flex; align-items: center; gap: var(--space-2); margin: 0; }
.sp-assign__select { width: 140px; flex: none; }


/* ── status strip — the gem's `.kpi-strip` at board weight: hairline-separated
   figures rather than four 30px numerals, because this strip sits ABOVE the
   buckets and must not out-shout them. ── */
.sp-strip { margin: 0; padding: 0; border-top: 0; gap: var(--space-5) var(--space-8); align-items: stretch; }
.sp-strip .kpi-strip__stat { flex-direction: column; align-items: flex-start; gap: 2px; padding-right: var(--space-8); border-right: 1px solid var(--hairline); }
.sp-strip .kpi-strip__stat:last-child { border-right: 0; padding-right: 0; }
.sp-strip .kpi-strip__value { font-size: var(--text-lg); white-space: nowrap; }
.sp-strip .kpi-strip__label { font-size: var(--text-2xs); font-weight: var(--fw-semibold); text-transform: uppercase; letter-spacing: .14em; white-space: nowrap; }
.sp-sep { color: var(--hairline-strong); font-weight: var(--fw-regular); }

/* ── bucket scaffolding — spacing, not boxes (BRIEF pattern 7). ── */
.sp-listcard > .os-profile-row { padding-inline: var(--space-4); }
.sp-stack { display: flex; flex-direction: column; gap: var(--space-3); }
.sp-stack--tight { gap: var(--space-2); margin-bottom: var(--space-3); }
.sp-grow { flex: 1 1 auto; min-width: 0; }
.sp-mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.sp-meta { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-1); font-size: var(--text-sm); color: var(--muted); }
.sp-note { font-size: var(--text-sm); color: var(--muted); margin: calc(var(--space-1) * -1) 0 var(--space-3); }
/* The row time column — mono, fixed width so the bucket reads as a column of
   clock times rather than ragged text. */
.sp-time { flex: 0 0 52px; font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--text-md); font-weight: var(--fw-semibold); color: var(--ink); }

/* Assigned therapist on a board row: avatar + a visible name, so staff read who is
   on it at a glance rather than hovering the avatar's title. */
.sp-thera { display: inline-flex; align-items: center; gap: var(--space-2); min-width: 0; }
.sp-thera__name { font-size: var(--text-xs); font-weight: var(--fw-medium); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ── ON NOW — the accent-filled elapsed bar IS the signal; the card stays white. ── */
.sp-onnow-foot { display: flex; align-items: center; gap: var(--space-3); }
.sp-onnow-foot form { margin: 0; }
.sp-elapse { flex: 1 1 auto; min-width: 0; height: 8px; border-radius: var(--radius-pill); background: var(--surface-alt); box-shadow: inset 0 0 0 1px var(--hairline); overflow: hidden; }
.sp-elapse i { display: block; height: 100%; border-radius: var(--radius-pill); background: var(--accent); }

/* ── DONE TODAY / catalogue disclosures — a summary bar that reads as a lid. ── */
.sp-done__bar, .sp-catalogue__bar {
  display: flex; align-items: center; gap: var(--space-3); cursor: pointer; list-style: none;
  padding: var(--space-3) var(--space-4); color: var(--muted);
}
.sp-done__bar::-webkit-details-marker, .sp-catalogue__bar::-webkit-details-marker { display: none; }
.sp-done__t { font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--text-secondary); }
.sp-done__m { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--text-sm); color: var(--muted); }
.sp-done__w { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--warning); }
.sp-done__chev { margin-left: auto; display: inline-flex; }
.sp-done[open] .sp-done__chev, .sp-catalogue[open] .sp-catalogue__bar .sp-done__chev { transform: rotate(180deg); }
/* ── READY TO POST — same compact list-card as Done today, but the lid reads as
   a live money warning and each row carries its Post + Open-folio actions. ── */
.sp-ready { margin-bottom: var(--space-4); }
.sp-ready__bar .sp-done__t { color: var(--warning); }
.sp-ready__bar > svg:first-child { color: var(--warning); }
.sp-ready__trail { display: inline-flex; align-items: center; gap: var(--space-2); }
.sp-ready__trail form { margin: 0; }

/* ── NEEDS YOU — the same compact list row as Ready-to-post / Next, but the
   card keeps a warning tint so the exceptions bucket still reads as the alert
   lane at a glance (colour only — the row structure matches the other lanes). ── */
.sp-needs { background: var(--warning-bg); box-shadow: inset 0 0 0 1px var(--warning-border); }

.sp-catalogue { margin-top: var(--space-6); background: var(--surface); border-radius: var(--radius-lg); box-shadow: 0 0 0 1px var(--hairline); }
.sp-catalogue[open] .sp-catalogue__bar { border-bottom: 1px solid var(--hairline); }
.sp-catalogue .sp-cat { padding: var(--space-5); }

/* ── RAIL: day-density strip. NOT a second rack — one axis, ticks where
   bookings sit, so the reader learns "how full am I" and clicks through to the
   Calendar tab for the real thing. left/width are GEOMETRY, computed in the
   view; every colour here is a token. ── */
.sp-spark { position: relative; height: 26px; }
.sp-spark__track { position: absolute; left: 0; right: 0; top: 10px; height: 6px; border-radius: var(--radius-pill); background: var(--surface-alt); box-shadow: inset 0 0 0 1px var(--hairline); }
.sp-spark__spent { position: absolute; left: 0; top: 10px; height: 6px; border-radius: var(--radius-pill) 0 0 var(--radius-pill); background: var(--hairline); }
.sp-dtick { position: absolute; top: 6px; width: 4px; height: 14px; border-radius: 2px; background: var(--accent); transform: translateX(-2px); }
.sp-dtick--warn { background: var(--status-briefing-fg); }
.sp-dtick--inert { background: var(--hairline-strong); }
.sp-now { position: absolute; top: 0; width: 1px; height: 26px; background: var(--accent); }
.sp-spark__ax { display: flex; justify-content: space-between; font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--text-2xs); color: var(--muted); margin-top: var(--space-1); }
.sp-spark__leg { display: flex; align-items: center; gap: var(--space-3); margin-top: var(--space-2); font-size: var(--text-xs); color: var(--muted); }
.sp-leg { display: inline-flex; align-items: center; gap: 6px; }
.sp-leg i { width: 3px; height: 10px; border-radius: 2px; background: var(--accent); }
.sp-leg i.sp-leg--warn { background: var(--status-briefing-fg); }
.sp-facts { font-size: var(--text-sm); color: var(--text-secondary); padding-top: var(--space-3); margin-top: var(--space-3); border-top: 1px solid var(--hairline); }
.sp-raillink { display: inline-flex; align-items: center; gap: 6px; margin-top: var(--space-2); font-size: var(--text-sm); font-weight: var(--fw-semibold); }

/* rail rows reuse `.os-profile-row`; only the utilisation gauge is local. */
.sp-trow { padding-left: 0; padding-right: 0; }
/* `.os-profile-row` ships `padding: space-3 0` — right inside a padded card
   body, but a bucket card holds the rows BARE, so it supplies the inline inset
   the body would otherwise have given them. */
.sp-gauge { height: 4px; border-radius: var(--radius-pill); background: var(--hairline); overflow: hidden; margin-top: var(--space-1); }
.sp-gauge i { display: block; height: 100%; border-radius: var(--radius-pill); background: var(--accent); }
.sp-free--best { color: var(--accent); font-weight: var(--fw-semibold); }
.sp-trow--warn .os-profile-row__name { color: var(--warning); }
.sp-lowdot { display: inline-block; width: 6px; height: 6px; border-radius: var(--radius-pill); background: var(--warning); margin-right: 6px; }
.sp-railfoot { border-top: 0; border-radius: var(--radius-lg); background: var(--surface); box-shadow: 0 0 0 1px var(--hairline); }

/* ── (b) drawer leaf rows — the editable therapist/room assignee rows have no
   base equivalent (front-office rows are read-only tap-rows). Mirror .ws-lead. ── */
.sp-assign { display: flex; align-items: center; gap: var(--space-3); }
.sp-assign__body { flex: 1 1 auto; min-width: 0; }
.sp-assign__name { font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--ink); }
.sp-assign__role { font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: .04em; color: var(--muted-2); }
.sp-assign__empty { font-size: var(--text-sm); color: var(--muted); }

/* Allergy callout inside a base `.hos-seccard` — amber attention leaf. */
.sp-allergy { display: flex; align-items: flex-start; gap: var(--space-2); }
.sp-allergy__ico { color: var(--warning); flex: 0 0 auto; margin-top: 1px; }
.sp-allergy__body { min-width: 0; }
.sp-allergy__list { font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--warning); }
.sp-allergy__diet { font-size: var(--text-xs); color: var(--muted); margin-top: 2px; }

/* money footer line inside the base `.hos-foot` (mirror .ws-calc). */
.sp-calc { font-size: var(--text-sm); color: var(--muted); display: flex; align-items: center; gap: var(--space-2); }
.sp-calc .amt { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-weight: var(--fw-semibold); color: var(--ink); }

.sp-empty { padding: 28px; text-align: center; color: var(--muted-2); font-size: var(--text-sm); }

/* ── (b) WEEK summary — the lighter view: per-day ordered appointment cards.
   (The Day view is the proportional time-grid below.) No base equivalent. */
.sp-cal { display: flex; flex-direction: column; gap: var(--space-6); }
.sp-cal-day__head { display: flex; align-items: baseline; gap: var(--space-2); padding: 0 var(--space-1) var(--space-3); }
.sp-cal-day__name { font-size: var(--text-md); font-weight: var(--fw-semibold); color: var(--ink); }
.sp-cal-day__count { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--text-xs); color: var(--muted); }
.sp-weekrows { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: var(--space-2); }
.sp-cal-appt {
  display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: var(--space-3);
  align-items: center; text-decoration: none; padding: 10px var(--space-3);
  border-radius: var(--radius-md); background: var(--surface);
  box-shadow: 0 0 0 1px var(--hairline); margin-bottom: var(--space-2);
}
.sp-cal-appt:hover { box-shadow: 0 0 0 1px var(--hairline-strong); }
.sp-cal-appt--now { box-shadow: 0 0 0 1px var(--status-in-water-border); background: var(--status-in-water-bg); }
.sp-cal-appt--done { opacity: .7; }
.sp-cal-appt__time { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--ink); }
.sp-cal-appt__t2 { font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--muted-2); }
.sp-cal-appt__name { font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--ink); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sp-cal-appt__meta { font-size: var(--text-xs); color: var(--muted); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sp-cal-appt__meta .warn { color: var(--warning); }

/* ── (b) DAY time-grid — proportional rack. No base equivalent. A time axis
   (hour gutter + rules) with therapist lanes; each appointment is a block
   positioned by scheduled_at and sized by duration. Inline top/height/left are
   GEOMETRY (computed in the view), not token-governed style. Colour/type below. */
.sp-rack { padding: 0; overflow: hidden; }
.sp-rackscroll { overflow: auto; max-height: calc(100vh - 220px); }

/* column heads — sticky, share the grid's column template (set inline). */
.sp-colheads { display: grid; position: sticky; top: 0; z-index: 9; background: var(--surface); border-bottom: 1px solid var(--hairline); min-width: max-content; }
.sp-colheads__gutter { width: 52px; border-right: 1px solid var(--hairline-2); }
.sp-colhead { padding: var(--space-3); border-right: 1px solid var(--hairline-2); min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.sp-colhead:last-child { border-right: 0; }
.sp-colhead--warn { background: var(--warning-bg); }
.sp-colhead__who { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.sp-colhead__ava { width: 24px; height: 24px; flex: 0 0 24px; border-radius: var(--radius-pill); background: var(--slate-200); color: var(--slate-700); font-size: var(--text-2xs); font-weight: var(--fw-bold); letter-spacing: .02em; display: inline-flex; align-items: center; justify-content: center; }
.sp-colhead__ava--warn { background: var(--surface); color: var(--warning); box-shadow: 0 0 0 1px var(--status-briefing-border); }
.sp-colhead__name { font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--ink); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sp-colhead--warn .sp-colhead__name { color: var(--warning); }
.sp-colhead__count { margin-left: auto; font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--text-2xs); font-weight: var(--fw-semibold); color: var(--muted); }
.sp-colhead__free { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--text-xs); color: var(--text-secondary); }
.sp-colhead--warn .sp-colhead__free { color: var(--warning); }

/* grid body — same column template (inline); rules/now-line overlay via absolute. */
.sp-grid { display: grid; position: relative; min-width: max-content; }
.sp-rules { position: absolute; left: 52px; right: 0; top: 0; bottom: 0; pointer-events: none; z-index: 0; }
.sp-rule { position: absolute; left: 0; right: 0; height: 0; border-top: 1px solid var(--hairline-2); }
.sp-rule--hour { border-top-color: var(--hairline); }
.sp-nowline { position: absolute; left: 52px; right: 0; height: 0; border-top: 1px solid var(--accent); z-index: 6; pointer-events: none; }
.sp-nowline__tag { position: absolute; left: 4px; transform: translateY(-50%); font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--text-2xs); font-weight: var(--fw-semibold); color: var(--surface); background: var(--accent); border-radius: var(--radius-sm); padding: 0 var(--space-1); }
.sp-gutter { position: relative; border-right: 1px solid var(--hairline-2); }
.sp-tick { position: absolute; right: 8px; transform: translateY(-7px); font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--text-xs); color: var(--muted); }
.sp-col { position: relative; border-right: 1px solid var(--hairline-2); min-width: 0; }
.sp-col:last-child { border-right: 0; }
.sp-col--warn { background: var(--warning-bg); }

/* free-gap label on canvas — quiet, no box. */
.sp-gap { position: absolute; left: 4px; right: 4px; display: flex; align-items: center; justify-content: center; z-index: 1; pointer-events: none; }
.sp-gap span { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--text-xs); color: var(--muted-2); }

/* appointment block — absolute, positioned/sized in the view. */
.sp-blk { position: absolute; z-index: 3; display: flex; flex-direction: column; gap: 1px; overflow: hidden; padding: var(--space-1) var(--space-2); border-radius: var(--radius-md); text-decoration: none; }
.sp-blk__t { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--text-2xs); line-height: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sp-blk__n { font-size: var(--text-sm); font-weight: var(--fw-semibold); line-height: 18px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sp-blk__g { font-size: var(--text-xs); line-height: 16px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* A split block (concurrent bookings sharing the column) has ~half the width,
   so the meta line stops fitting; drop to the essentials and let the guest name
   own the space. The block is still fully clickable and fully readable, which
   is the whole point of splitting. */
.sp-blk--split { padding-inline: var(--space-1); }
.sp-blk--split .sp-blk__g { display: none; }
.sp-blk__st { font-size: var(--text-2xs); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .07em; line-height: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sp-blk__flag { display: inline-flex; align-items: center; gap: 3px; font-size: var(--text-2xs); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .06em; color: var(--danger); margin-top: 1px; }
/* booked = white fill + confirmed ring */
.sp-blk--booked { background: var(--surface); box-shadow: inset 0 0 0 1.5px var(--status-confirmed-border); color: var(--ink); }
.sp-blk--booked .sp-blk__t { color: var(--slate-600); }
/* on-now = accent ring (sky/teal live emphasis) */
.sp-blk--live { background: var(--surface); box-shadow: inset 0 0 0 2px var(--accent), var(--shadow-md); color: var(--ink); z-index: 5; }
.sp-blk--live .sp-blk__t { color: var(--accent); }
/* completed = slate tint */
.sp-blk--done { background: var(--status-returning-bg); box-shadow: inset 0 0 0 1px var(--status-returning-border); color: var(--slate-700); }
.sp-blk--done .sp-blk__n { font-weight: var(--fw-regular); }
.sp-blk--done .sp-blk__t, .sp-blk--done .sp-blk__g { color: var(--muted); }
/* no-show = amber tint */
.sp-blk--noshow { background: var(--status-briefing-bg); box-shadow: inset 0 0 0 1px var(--status-briefing-border); color: var(--warning); }
.sp-blk--noshow .sp-blk__t, .sp-blk--noshow .sp-blk__g { color: var(--warning); }
.sp-blk--noshow .sp-blk__flag { color: var(--warning); }
/* cancelled = rose tint + strike */
.sp-blk--cancel { background: var(--status-cancelled-bg); box-shadow: inset 0 0 0 1px var(--status-cancelled-border); color: var(--danger); }
.sp-blk--cancel .sp-blk__n { text-decoration: line-through; font-weight: var(--fw-regular); }
/* clash = danger ring overrides the status ring */
.sp-blk--clash { box-shadow: inset 0 0 0 2px var(--danger); z-index: 4; }
/* the status WORD takes the block's status colour — colour is the second
   encoding, never the only one. */
.sp-blk--booked .sp-blk__st { color: var(--status-confirmed-fg); }
.sp-blk--live   .sp-blk__st { color: var(--accent); }
.sp-blk--done   .sp-blk__st { color: var(--muted); }

/* ── New-booking disclosure in the page-head actions — a popover panel so the
   day's live state leads the body (no always-open form). ── */
.sp-book { position: relative; display: inline-block; }
.sp-book > summary { list-style: none; cursor: pointer; }
.sp-book > summary::-webkit-details-marker { display: none; }
.sp-book__pop {
  position: absolute; right: 0; top: calc(100% + var(--space-2)); z-index: 60;
  width: 300px; display: flex; flex-direction: column; gap: var(--space-3);
  padding: var(--space-4); background: var(--surface); border-radius: var(--radius-lg);
  box-shadow: 0 0 0 1px var(--hairline), var(--shadow-md); text-align: left;
}
.sp-book__pop .os-input, .sp-book__pop .os-field-select { width: 100%; }
.sp-book__check { display: flex; align-items: center; gap: 6px; }
/* ANSWERED BY THE SLOT — the facts the system already holds, stated so nobody
   types them. End time is derived from the treatment's duration and is never an
   input field; the DERIVED tag says so rather than leaving a reader to wonder
   why there is no end picker. */
.sp-slotfacts { gap: var(--space-2); padding: var(--space-3) 0 0; border-top: 1px solid var(--hairline); }
.sp-derived { display: inline-block; margin-left: var(--space-2); font-family: var(--font-sans); font-size: var(--text-2xs); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .08em; color: var(--accent); background: var(--accent-soft); border-radius: var(--radius-sm); padding: 0 var(--space-1); }
.sp-book__submit { width: 100%; justify-content: center; }

/* ── New/Edit booking drawer form (tasks/090) ──────────────────────────────
   Lives inside the canonical .os-side-panel chassis; these style the DB-backed
   guest/room autocomplete, the resolved-stay card, and the occupant chips. ── */

/* Autocomplete */
.sp-ac { position: relative; }
.sp-ac__input { width: 100%; }
.sp-ac__menu {
  position: absolute; left: 0; right: 0; top: calc(100% + var(--space-1)); z-index: 20;
  background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius-md);
  box-shadow: var(--shadow-md); overflow: hidden; max-height: 264px; overflow-y: auto;
}
.sp-ac__opt {
  display: flex; align-items: center; gap: var(--space-3); width: 100%; text-align: left;
  padding: var(--space-2) var(--space-3); background: none; border: 0; cursor: pointer;
  border-bottom: 1px solid var(--surface-alt);
}
.sp-ac__opt:last-child { border-bottom: 0; }
.sp-ac__opt:hover, .sp-ac__opt.is-hi { background: var(--surface-alt); }
.sp-ac__av {
  width: 28px; height: 28px; flex: none; border-radius: 50%; display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent); font-size: var(--text-2xs); font-weight: var(--fw-bold);
}
.sp-ac__txt { display: flex; flex-direction: column; min-width: 0; }
.sp-ac__name { font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--ink); }
.sp-ac__sub { font-size: var(--text-2xs); color: var(--muted); }

/* Resolved room card (mirrors .sp-assign look) */
.sp-filled {
  display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3);
  border: 1px solid var(--hairline); border-radius: var(--radius-md); background: var(--surface-alt);
}
.sp-filled__av {
  width: 34px; height: 34px; flex: none; border-radius: var(--radius-sm); display: grid; place-items: center;
  background: var(--surface); border: 1px solid var(--hairline); color: var(--accent);
}
.sp-filled__body { flex: 1 1 auto; min-width: 0; }
.sp-filled__name { font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--ink); }
.sp-filled__sub { font-size: var(--text-2xs); color: var(--muted); }
.sp-filled__clear { border: 0; background: none; color: var(--muted); cursor: pointer; padding: var(--space-1); display: grid; place-items: center; }

/* Occupant chips (multi-guest) */
.sp-occ { display: flex; flex-direction: column; gap: var(--space-2); }
.sp-occ--stack { margin-top: var(--space-3); }
.sp-occ__row {
  display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3);
  border: 1px solid var(--hairline); border-radius: var(--radius-md); background: var(--surface); cursor: pointer;
}
.sp-occ__row.is-sel { border-color: var(--accent); background: var(--accent-soft); }
.sp-occ__cb { position: absolute; opacity: 0; width: 0; height: 0; }
.sp-occ__box {
  width: 18px; height: 18px; flex: none; border: 1.5px solid var(--muted-2); border-radius: var(--radius-sm);
  display: grid; place-items: center; color: var(--surface);
}
.sp-occ__box svg { opacity: 0; }
.sp-occ__row.is-sel .sp-occ__box { background: var(--accent); border-color: var(--accent); }
.sp-occ__row.is-sel .sp-occ__box svg { opacity: 1; }
.sp-occ__body { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.sp-occ__name { font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--ink); }
.sp-occ__sub { font-size: var(--text-2xs); color: var(--muted); }
.sp-occ__lead {
  font-size: var(--text-2xs); font-weight: var(--fw-bold); color: var(--muted); background: var(--surface-alt);
  padding: 0 var(--space-2); border-radius: var(--radius-pill); white-space: nowrap;
}
.sp-occ__row { align-items: flex-start; }
.sp-occ__cb + .sp-occ__box { margin-top: 2px; }
/* per-guest treatment picker — appears under a selected guest when 2+ are booked */
.sp-occ__tr { width: 100%; margin-top: var(--space-2); }
.sp-occnote { font-size: var(--text-2xs); color: var(--muted); margin: var(--space-2) 0 0; }

/* Field rhythm inside the drawer form */
.sp-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
.sp-field { display: flex; flex-direction: column; gap: var(--space-1); }
.sp-field .os-input { width: 100%; }
.sp-fieldhint { display: flex; align-items: center; gap: var(--space-1); font-size: var(--text-2xs); color: var(--muted); margin: var(--space-2) 0 0; }
.sp-fieldhint svg { color: var(--accent); flex: none; }
.sp-presold { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--ink); }

/* Drawer money footer — divider + one-line caption under the amount. */
.sp-money { width: 100%; }
.sp-money__cap { font-size: var(--text-xs); color: var(--muted); margin-top: var(--space-2); padding-top: var(--space-2); border-top: 1px solid var(--hairline); line-height: 18px; }

/* ── Catalogue pair (treatment menu + inventory) ───────────────────────────
   Two independent admin surfaces below the day board. Side by side when there
   is room; stacked below the hos-fo-row breakpoint so neither table has to
   horizontally scroll on a laptop half-window. ── */
.sp-cat { display: grid; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); gap: var(--space-5); align-items: start; }

/* Low stock reads as an alert in the figure column, matching the "Low" pill. */
.sp-stock--low { color: var(--status-briefing-fg); font-weight: var(--fw-bold); }

/* ── Inline record forms (add treatment / add item) ────────────────────────
   Shares the .sp-book field rhythm so the three forms on this page agree. ── */
/* Height is NOT set here — see the note on `.sp-assign__form`: one
   `--control-h` governs input, select and button, scoped to the 46px field rung
   inside a form. The old per-row height pinning (and the `.os-select` shell
   sizing beside it) predates os-ds v1.6.0. */
.sp-form-row { display: flex; gap: var(--space-3); flex-wrap: wrap; align-items: flex-end; }
.sp-form-row label { display: inline-flex; flex-direction: column; gap: var(--space-1); }
.sp-form-row__wide  .os-input { width: 170px; }
.sp-form-row__short .os-input { width: 104px; }
.sp-form-row__num   .os-input { width: 80px; }

/* Section eyebrow above a card needs its own air; .os-eyebrow ships no margin. */
.sp-seclabel { display: block; margin-bottom: var(--space-3); }

/* button_to emits a <form> per button, and forms are block-level — so the two
   stock-adjust buttons stacked and doubled the row height. Lay the forms out
   inline inside the actions cell. */
.sp-cat .os-table__actions { display: inline-flex; gap: var(--space-2); justify-content: flex-end; }
.sp-cat .os-table__actions form { display: inline-flex; margin: 0; }

/* The promoted-unposted group takes the attention tone of what it carries — it
   is money at risk, not a neutral heading. */
.sp-sec--warn .os-section-head__icon,
.sp-sec--warn .os-section-head__label,
.sp-sec--warn .os-section-head__meta { color: var(--warning); }
