/* ── Reservation Details page (tasks/041) ─────────────────────────────────
   The drawer is triage; this page is the depth. Ported from the DiveOS Booking
   Details anatomy: a fixed-width rail beside a fluid main column, cards with
   generous padding, and tiny uppercase eyebrow heads instead of big titles —
   hierarchy comes from the content, not the chrome.
   Token-only (no naked hex, no inline token props). Light-only.
   ────────────────────────────────────────────────────────────────────────── */

/* Body: fluid main + fixed rail. The rail never competes with the main column,
   which is what stops the cards stretching end-to-end (the drawer's problem). */
/* Keep the tab band flush under the header band.
   The gem's body-gap rule is
     .os-page-head + :not(.os-page-tools):not(.os-page-head):not(:has(.os-page-tools))
   i.e. it excludes a wrapper holding a .os-page-tools, but NOT one holding a
   bare .os-page-band. Our tab-panel wrapper holds .os-page-band.os-tabnav, so it
   matches and picks up margin-top: 2rem — an empty grey strip between the header
   and the tabs. The gem INTENDS this wrapper to stay flush (header_band.css:
   "that wrapper must stay flush; its internal nav->panel spacing lives in
   bookings.css"), so its exclusion is simply incomplete.
   Fixed locally rather than upstream because DiveOS has the identical structure
   (account/bookings/show.html.erb: .os-page-band.page-header + an unclassed
   tab-panel wrapper holding a .os-page-band nav) and would also lose 32px — a
   cross-product visual change that needs eyes on DiveOS first.
   TODO upstream: add :not(:has(.os-page-band)) to the gem's body-gap selectors.
   The gap BELOW the band is owned by .hos-body's margin-top, not this. */
.hos-tabwrap { margin-top: 0 !important; }

.hos-body {
  display: grid;
  grid-template-columns: 1fr 336px;
  column-gap: var(--space-6);
  align-items: start;
  /* Body gap under the tab band. The DS auto-gaps content after .os-page-tools,
     but a tabs-only band uses bare .os-tabnav (no such rule), so own the 2rem
     rhythm here — matches every other archetype's header→body gap. */
  margin-top: 2rem;
}
@media (max-width: 1100px) {
  .hos-body { grid-template-columns: 1fr; row-gap: var(--space-5); }
}

.hos-main { display: flex; flex-direction: column; gap: var(--space-5); min-width: 0; }
.hos-rail { display: flex; flex-direction: column; gap: var(--space-4); position: sticky; top: var(--space-5); }
@media (max-width: 1100px) { .hos-rail { position: static; } }

/* Card shell — head is a 10px uppercase eyebrow + muted icon, not a heading. */
.hos-rd-card {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.hos-rd-card__head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-4) var(--space-5) 0;
}
.hos-card__head-left { display: inline-flex; align-items: center; gap: 7px; }
.hos-card__label {
  font-size: var(--text-2xs); font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted);
}
.hos-card__body { padding: var(--space-4) var(--space-5) var(--space-5); }

/* Tab band retired 2026-07-19 — the show tabs now render from the os-ds gem's
   .os-page-band.os-tabnav + .page-tabs directly (no .hos-tools wrapper). The gem
   band owns height (page-tab padding), the flush underline, and the narrow-width
   horizontal scroll (.page-tabs overflow-x). No local scaffolding needed. */

/* Header identity line — the personal "who + how to reach" subtitle: mono RES
   ref, then country/email/phone as icon-led items (icons inherit the muted
   sub colour). Booking facts (room/dates/source) live in the rail, not here. */
.hos-idline { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.hos-idline__ref { font-family: var(--font-mono); font-weight: 600; color: var(--text-secondary); }
.hos-idline__it { display: inline-flex; align-items: center; gap: 5px; min-width: 0; max-width: 100%; overflow-wrap: anywhere; }
.hos-idline__sep { color: var(--hairline-strong); }

/* Overview panel stack — the read cards (hero · journey · capture · remarks) are
   wrapped in the form-drawer controller div, so the panel's own gap can't reach
   them; own the vertical rhythm here. Hidden edit-drawer panels are display:none
   and don't add a phantom gap. */
.hos-stack { display: flex; flex-direction: column; gap: var(--space-5); }

/* Balance — one big mono figure, a progress bar, then the split. */
.hos-bal__amt {
  font-family: var(--font-mono); font-size: var(--text-3xl); font-weight: 600;
  color: var(--ink); letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}
.hos-bal__amt--settled { color: var(--status-confirmed-fg); }
.hos-bal__bar {
  height: 6px; border-radius: var(--radius-pill); background: var(--surface-alt);
  overflow: hidden; margin: var(--space-3) 0 var(--space-2);
}
.hos-bal__fill { display: block; height: 100%; background: var(--status-confirmed-fg); }
.hos-bal__split {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2);
  font-size: var(--text-xs);
}

/* Booking summary — 2-col instrument grid. Each cell is a MUTED glyph (no filled
   accent tile) + an uppercase eyebrow + a value. Long values (Booked, the
   full-year dates, Source) take a full-width row; the short instruments pair
   2-across. Hairlines: a top border on every cell (the first sits flush under the
   card head) gives horizontal rules; .hos-cell--divide draws the single vertical
   rule between a 2-col pair (set in the ERB, so a full-width row never straddles
   it — no double borders). */
.hos-sum { display: grid; grid-template-columns: 1fr 1fr; }
.hos-cell {
  /* left padding = --space-5 to align the cell labels with the card head
     (.hos-rd-card__head is padded --space-5); --space-4 sat them 4px too far left. */
  padding: 13px var(--space-5);
  border-top: 1px solid var(--hairline-2);
  min-width: 0; /* let the value ellipsis instead of overflowing the grid cell */
}
.hos-sum > .hos-cell:first-child { border-top: none; }
.hos-cell--full { grid-column: 1 / -1; }
.hos-cell--divide { border-right: 1px solid var(--hairline-2); }
.hos-cell__k {
  display: block; font-size: var(--text-2xs); font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 3px;
}
.hos-cell__v {
  display: block; font-size: var(--text-sm); font-weight: 640; color: var(--ink);
  line-height: 1.15; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hos-cell__v--mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* Small named text roles — these exist so callsites don't set token-governed
   props inline (hallmark [InlineStyle]); layout-only inline styles are fine. */
.hos-body-text { font-size: var(--text-sm); color: var(--ink); }
.hos-paid { color: var(--status-confirmed-fg); font-weight: 600; }

/* ── Folio, ported from the DiveOS Invoices anatomy (account/bookings.css) ──
   Arena has ONE folio per stay rather than N invoices, so the accordion header
   becomes the folio header — same shape: mono ref · status · total on the right.
   ────────────────────────────────────────────────────────────────────────── */
.hos-inv { background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius-lg); overflow: hidden; }
.hos-inv__head { display: flex; align-items: center; gap: 10px; padding: 14px 18px; }
.hos-inv__id { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 600; color: var(--ink); letter-spacing: -0.01em; }
.hos-inv__sep { color: var(--muted-2); font-size: var(--text-xs); }
.hos-inv__date { font-size: var(--text-xs); color: var(--muted); }
.hos-inv__spacer { flex: 1; }
.hos-inv__total { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.hos-inv__body { border-top: 1px solid var(--hairline); }

/* line-items table */
.hos-invtable { overflow-x: auto; }
.hos-invtable table { width: 100%; border-collapse: collapse; }
.hos-invtable thead tr { background: var(--canvas); border-bottom: 1px solid var(--hairline); }
.hos-invtable thead th {
  font-size: var(--text-2xs); font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--slate-600); padding: 10px 0; text-align: left;
}
.hos-invtable thead th:first-child { padding-left: 18px; }
.hos-invtable thead th:last-child { padding-right: 18px; text-align: right; }
.hos-invtable tbody tr { border-bottom: 1px solid var(--hairline-2); }
.hos-invtable tbody tr:last-child { border-bottom: none; }
.hos-invtable tbody td { padding: 13px 0; font-size: var(--text-sm); color: var(--ink); vertical-align: middle; }
.hos-invtable tbody td:first-child { padding-left: 18px; }
.hos-invtable tbody td:last-child { padding-right: 18px; text-align: right; }
.hos-invtable .hos-li-day { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); }
.hos-invtable .hos-li-desc { font-weight: 500; }
.hos-invtable .hos-li-sub { font-size: var(--text-2xs); color: var(--muted-2); }
.hos-invtable .hos-li-amount { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 500; text-align: right; font-variant-numeric: tabular-nums; }
.hos-invtable .hos-li-empty { color: var(--muted); font-weight: 400; text-align: center; padding: 22px 18px; }

/* shared money row */
.hos-fin { display: flex; flex-direction: column; }
.hos-fin__row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 7px 0; }
.hos-lbl { font-size: var(--text-2xs); font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted-2); }
.hos-val { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--muted); font-variant-numeric: tabular-nums; }
.hos-fin__row--secondary .hos-lbl { color: var(--muted-2); }
.hos-fin__row--semantic .hos-lbl { color: var(--muted); }
.hos-fin__row--semantic .hos-val { font-size: var(--text-md); font-weight: 500; }
.hos-val--paid { color: var(--status-confirmed-fg); }
.hos-val--outstanding { color: var(--status-briefing-fg); font-weight: 600; }
.hos-fin__row--total .hos-lbl { color: var(--ink); }
.hos-fin__row--total .hos-val { color: var(--ink); font-size: var(--text-md); font-weight: 600; }

/* grand-total card — confirmed-green wash + 3px top rule (DiveOS .fin-card--c2r) */
.hos-fincard {
  --fin-border: color-mix(in srgb, var(--status-confirmed-fg) 18%, transparent);
  background: color-mix(in srgb, var(--status-confirmed-fg) 6%, transparent);
  border: 1px solid var(--fin-border);
  border-top: 3px solid var(--status-confirmed-fg);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  padding: 18px 20px 16px; display: flex; flex-direction: column;
}
.hos-fincard .hos-fin__row + .hos-fin__row { border-top: 1px solid var(--fin-border); }
.hos-fincard .hos-fin__row { padding: 10px 0; }
.hos-fincard .hos-fin__row--total .hos-val { font-size: var(--text-2xl); font-weight: 700; color: var(--status-confirmed-fg); letter-spacing: -0.02em; }

.hos-inv__actions {
  display: flex; flex-wrap: wrap; gap: var(--space-2);
  padding: 14px 18px; border-top: 1px solid var(--hairline);
}

/* the folio card and its totals read as ONE object — square the seam */
.hos-inv--attached { border-radius: var(--radius-lg) var(--radius-lg) 0 0; border-bottom: none; }

.hos-fin__fig { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ── Form drawer (Details page) — reuses .hos-odrawer chrome from arena_ds.css.
   The Details page is a full page, so a drawer here is a first layer, not a
   modal-on-a-modal (which is why the drawer's OWN departure form stays inline). */
/* outstanding callout inside the payment drawer */
.hos-fd__due { background: var(--surface-alt); border-radius: var(--radius-md); padding: var(--space-3) var(--space-4); margin-bottom: var(--space-4); }
.hos-fd__due-amt {
  font-family: var(--font-mono); font-size: var(--text-xl); font-weight: 600;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
/* ── Occupant roster (Details > Guest) ────────────────────────────────────
   Ported from the DiveOS booking-details diver roster (`_waiver_roster` +
   `.waiver-diver-row`, dive-os account/bookings.css): hairline-separated rows
   inside ONE card — not a bordered box per person — a gradient initials avatar,
   and a GRID badge column so every row's pills and actions snap to the same
   right edge regardless of text length. Read-only rows; every form is a drawer.
   ────────────────────────────────────────────────────────────────────────── */
.hos-occhead {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3); font-size: var(--text-xs); color: var(--muted);
}
.hos-occhead__pct { font-weight: 600; color: var(--ink); }
.hos-occ__bar {
  height: 4px; border-radius: var(--radius-pill); background: var(--surface-alt);
  overflow: hidden; margin: 10px 0 14px;
}
.hos-occ__fill { display: block; height: 100%; background: var(--status-confirmed-fg); }

/* Grid, not flex: pills and actions line up across rows whatever the label says. */
/* flex, not a fixed 84px trail column: the trail holds Edit AND (when a C Form
   exists) a second button, which overflowed the fixed column and overlapped the
   role pill. Let each group size to its content. */
.hos-profile-row__role { color: var(--text-muted); background: var(--slate-100); }
.hos-profile-row__role--lead { color: var(--accent); background: var(--accent-soft); }
.hos-profile-row__id { color: var(--status-confirmed-fg); background: var(--status-confirmed-bg); }
/* Whole-row link variant (Overview "Guest capture" → Details·Guest). */
/* Muted avatar for an as-yet-uncaptured placeholder guest. */

.hos-occempty {
  display: flex; align-items: flex-start; gap: var(--space-3); padding: 18px;
  border: 1px dashed var(--border-strong); border-radius: var(--radius-md);
  background: var(--surface-alt);
}
.hos-occempty__title { font-size: var(--text-sm); font-weight: 600; color: var(--ink); margin-bottom: 2px; }
.hos-occdrawer__scans { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: var(--space-3); }

/* Folio ledger day grouping (tasks/052 row 7, #26): subdued full-width day header
   carrying the day's billable subtotal. */
.hos-invtable .hos-li-dayrow td {
  background: var(--surface-alt);
  color: var(--muted);
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding-top: 8px;
  padding-bottom: 8px;
}

/* ── New-reservation wizard body (tasks/073 B5) ───────────────────────────
   Reference: the DiveOS POS booking wizard (`~/Repos/dive-os`,
   app/views/account/bookings/pos/*). Its shape per step is
   STAGE HEAD (display H2 + one muted context line) → content panel →
   action bar — NOT a tiny uppercase accordion label on a collapsed <details>,
   which is what this page had. The `.hos-section` <details> family that used to
   live here is gone: inside a wizard only one step is ever on screen, so a
   per-step collapse was chrome with no job.
   Built from gem primitives (`.os-workpage`, `.os-form-section`,
   `.os-field-grid`, `.os-ds-sum`, `.os-desclist`) — the DiveOS `wz-*` names are
   a DiveOS-local family and are deliberately NOT imported.
   ────────────────────────────────────────────────────────────────────────── */

/* Stage head — same geometry as the reference's `.wz-stage-head`
   (text-xl display face · 22px to the panel · 7px to the sub-line). */
.hos-stagehead { margin-bottom: 22px; }
.hos-stagehead h2 {
  margin: 0; font-family: var(--font-display); font-weight: 600;
  font-size: var(--text-xl); letter-spacing: -0.015em; color: var(--ink);
}
/* The sub-line is the step's LIVE summary (written by refreshSummaries) — what
   this step currently holds — standing in for the reference's static prose.
   min-height reserves its line so the panel doesn't jump as it fills in. */
.hos-stagesum {
  margin: 7px 0 0; font-size: var(--text-sm); color: var(--muted);
  line-height: 1.5; max-width: 64ch; min-height: 1.5em;
}

/* Page column. The work/summary grid itself is the gem's `.os-workpage --a1`
   (its documented "create / edit / checkout / multi-step" archetype); this only
   sets the measure, centres it (tasks/073 A3) and spaces it off the stepper. */
.hos-newres {
  display: flex; flex-direction: column; gap: var(--space-5);
  max-width: 1080px; margin-inline: auto;
}
/* A wizard step's panel carries no section header — the stage head above the
   card is the title — so the gem's header→body gap has nothing to clear.
   Scoped to the wizard step: elsewhere a headerless form-section should keep the
   gem's default rather than inherit this page's decision. */
.hos-wzstep .os-form-section > .os-form-section__body:first-child { margin-top: 0; }

/* Vertical rhythm inside a step's mode block. The gem gives
   `.os-form-section__body > * + *` its 22px rhythm, but the individual/group
   blocks are ONE child each, so their own contents need it. flex rather than the
   margin rule because setResMode toggles these two by `style.display` —
   `display=""` must fall back to a layout mode that still stacks. */
.hos-modeblock { display: flex; flex-direction: column; gap: var(--space-5); }
.hos-roomrows { display: flex; flex-direction: column; gap: 10px; }
.hos-btnrow { display: flex; flex-wrap: wrap; gap: 8px; }
.hos-field--block { display: block; }
/* Note type is a short enum beside a long free-text note — a 50/50 split would
   waste the note's measure. */
.hos-notegrid { grid-template-columns: 160px minmax(0, 1fr); }

/* Guest search — the gem's `.os-search-wrap` is a 32px TOOLBAR search; as the
   primary field of a form step it takes the form control's 40px height and the
   full column. An extension of a gem component, not a second search component. */
.hos-searchfield { display: flex; width: 100%; height: 40px; }
.hos-searchfield input { height: 40px; font-size: var(--text-sm); border-radius: var(--radius-md); }

/* Group room row: compact grid + horizontal scroll rather than crush (row 3). */
.hos-room-row {
  min-width:0; padding:10px; align-items:end; gap:8px;
  display:grid; grid-template-columns:1.6fr 1.6fr 72px 72px 72px 32px;
}
.hos-room-row .os-input, .hos-room-row .os-field-select { min-width:0; }
.hos-room-row__drop { margin-bottom:2px; }
@media (max-width: 720px) {
  .hos-room-row { grid-template-columns:1fr 1fr; }
}

/* Rail summary sections — the gem's `.os-ds-sum` ships a header band, icon-tile
   rows and a tinted total footer, but no plain "labelled ledger block"; this is
   that block, using the card's own divider rhythm. */
.hos-sumsec { padding: 12px 20px; border-top: 1px solid var(--hairline); }
.hos-sumsec__lbl { margin-bottom: 6px; }
.hos-sumrow--on { font-weight: 600; }
/* Room-type names are long and the rail is 320px. The gem's inline desclist
   pins the term at its natural width (`flex: 0 0 auto`), which pushed the value
   past the card's right edge; let the term shrink and wrap, and keep the figure
   hard against the right. */
.hos-sumsec .os-desclist__term { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.hos-sumsec .os-desclist__desc { flex: 0 0 auto; white-space: nowrap; }

/* ── Overview redesign (variant-E) ────────────────────────────────────────
   Horizontal arrival-readiness stepper (hero) + rich boarding-pass / boat
   route cards + icon-led capture/remarks rows. Token-only; layout-only inline
   styles (segment left/width %) are the sole inline styles, and carry no colour
   or type tokens (hallmark flags those, not geometry).
   ────────────────────────────────────────────────────────────────────────── */

/* Hero — readiness header + horizontal stepper */
.hos-rd-hero { padding: 0; }
.hos-hero__head {
  display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  background: var(--accent-softer); border-bottom: 1px solid var(--accent-border);
}
.hos-hero__ico {
  width: 40px; height: 40px; flex: none; border-radius: var(--radius-md);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent-soft); color: var(--accent);
}
.hos-hero__h { font-size: var(--text-md); font-weight: 680; color: var(--ink); line-height: 1.2; }
.hos-hero__s { font-size: var(--text-xs); color: var(--muted); margin-top: 2px; }
.hos-hero__eta { margin-left: auto; text-align: right; flex: none; }
.hos-hero__eta-t {
  display: block; font-family: var(--font-mono); font-size: var(--text-xl);
  font-weight: 680; letter-spacing: -0.02em; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.hos-hero__eta-l {
  display: block; font-size: var(--text-2xs); color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.08em; margin-top: 2px;
}

/* Terminal (cancelled / no-show) — flat inert status card, muted (no accent,
   no readiness tracker, no ETA). Mirrors the hero head layout, calm palette. */
.hos-dead__head {
  display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
}
.hos-dead__ico {
  width: 40px; height: 40px; flex: none; border-radius: var(--radius-md);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface-alt); color: var(--muted);
}
.hos-dead__h { font-size: var(--text-md); font-weight: 680; color: var(--muted); line-height: 1.2; }
.hos-dead__s { font-size: var(--text-xs); color: var(--muted-2); margin-top: 2px; }

/* Stepper track */
.hos-stepper { display: flex; position: relative; padding: 26px var(--space-5) 22px; }
.hos-stepper__seg { position: absolute; top: 47px; height: 2px; background: var(--hairline); z-index: 0; }
.hos-stepper__seg--fill { background: var(--status-confirmed-fg); }
.hos-rd-step {
  flex: 1; min-width: 0; position: relative; z-index: 1;
  display: flex; flex-direction: column; align-items: center; text-align: center;
}
.hos-rd-step__node {
  width: 44px; height: 44px; border-radius: var(--radius-pill);
  display: grid; place-items: center; position: relative; z-index: 2;
  background: var(--surface); border: 2px solid var(--border-strong); color: var(--muted-2);
}
.hos-rd-step__lbl { font-size: var(--text-sm); font-weight: 640; color: var(--ink); margin-top: 10px; }
.hos-rd-step__sub {
  font-size: var(--text-2xs); color: var(--muted); margin-top: 2px;
  font-family: var(--font-mono); letter-spacing: 0.02em;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hos-rd-step--done .hos-rd-step__node { background: var(--status-confirmed-fg); border-color: var(--status-confirmed-fg); color: var(--surface); }
.hos-rd-step--now .hos-rd-step__node { background: var(--accent-light); border-color: var(--accent); color: var(--accent); box-shadow: 0 0 0 5px var(--accent-soft); }
.hos-rd-step--todo .hos-rd-step__lbl { color: var(--muted); font-weight: 560; }
.hos-rd-step__badge {
  position: absolute; top: -3px; right: calc(50% - 30px); z-index: 3;
  width: 16px; height: 16px; border-radius: var(--radius-pill);
  display: grid; place-items: center;
  background: var(--warning); color: var(--surface); border: 2px solid var(--surface);
}

/* Section title on the canvas (eyebrow + right meta) */
.hos-rd-sectitle { display: flex; align-items: center; gap: 8px; padding: 2px 2px 10px; }
.hos-rd-sectitle__ico { color: var(--accent); display: inline-flex; }
.hos-rd-sectitle__eye {
  font-size: var(--text-xs); font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--slate-700);
}
.hos-sectitle__meta { margin-left: auto; font-size: var(--text-xs); color: var(--muted); font-family: var(--font-mono); }

/* Rich journey — boarding-pass + boat route */
.hos-jgrid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
@media (max-width: 720px) { .hos-jgrid { grid-template-columns: 1fr; } }
.hos-jcard {
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: var(--radius-lg); padding: 18px 20px;
  display: flex; flex-direction: column;
}
.hos-jc-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 16px; }

.hos-rd-route { display: flex; align-items: center; gap: 10px; }
.hos-rd-route__end { flex: 1; min-width: 0; }
.hos-rd-route__end--to { text-align: right; }
.hos-route__cap { font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); }
.hos-rd-route__code {
  font-family: var(--font-mono); font-weight: 680; font-size: var(--text-2xl);
  letter-spacing: -0.02em; line-height: 1.1; color: var(--ink);
}
.hos-route__code--sm { font-size: var(--text-lg); }
.hos-rd-route__city { font-size: var(--text-xs); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hos-rd-route__line { flex: none; width: 74px; display: flex; flex-direction: column; align-items: center; color: var(--accent); }
/* On a narrow (stacked) journey card, give the From/To ends more room so the
   longer boat codes ("MLE Airport", resort name) don't crush the connector. */
@media (max-width: 420px) { .hos-rd-route__line { width: 44px; } }
.hos-route__dots {
  width: 100%; height: 2px; margin: 6px 0;
  background: repeating-linear-gradient(90deg, var(--accent-border) 0 5px, transparent 5px 10px);
}
.hos-rd-route__foot {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--hairline-2);
}
.hos-route__meta { font-size: var(--text-xs); color: var(--muted); }
.hos-rd-route__time { text-align: right; }
.hos-route__time-l { display: block; font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
.hos-route__time-v { font-family: var(--font-mono); font-weight: 680; font-size: var(--text-md); color: var(--ink); }
/* Card footer action slot — the journey card's action lives here, never dangling
   after the body (rubric rule 10). The button itself is a plain `.os-btn`.
   Gem gap: os-ds has `.os-card__head`/`__body`/`__actions` but no `__foot`. */
/* The journey cards adopt the gem's .os-card__foot (os-ds v1.5.0). .hos-jcard
   carries its own padding, so the foot re-zeroes the gem's card-level inset —
   geometry stays identical to the .hos-jcard__foot this replaced. */
/* `margin-top: auto` pins the foot to the card's inner bottom edge. The two
   journey cards sit in a `.hos-jgrid` that stretches them to a common height,
   but their BODIES differ (the boat card's "MLE Airport" code wraps where the
   flight card's "COL" does not), so without this each foot floats directly
   under its own body and the two buttons land 13.2px apart — the misalignment
   the owner flagged. Pinning both to the bottom makes them share a baseline
   whatever the bodies do. */
.hos-jcard > .os-card__foot { padding: 12px 0 0; margin-top: auto; }

/* Icon-led rows (capture / remarks) */
.hos-rowhead {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--hairline-2);
}
.hos-rowhead__pct { font-size: var(--text-xs); font-weight: 600; color: var(--muted); }

/* The gem's `.os-profile-row` is `padding: var(--space-3) 0` on purpose — it is
   a full-bleed list row and expects its CONTAINER to own the horizontal inset
   (in os-ds it sits inside an `.os-card__body`). `.hos-rd-card` has no padding
   of its own — its head and `.hos-rowline` each carry `--space-5` — so occupant
   rows dropped straight into the card ran flush to the border while the head
   sat 20px in. Give them the same inset the card's other rows use, so the list
   still spans the card (hover/hairline stay full-bleed) but its CONTENT aligns
   with the head. */
.hos-rd-card > .os-profile-row { padding-left: var(--space-5); padding-right: var(--space-5); }
.hos-rowline {
  display: flex; align-items: center; gap: 14px; padding: 14px var(--space-5);
  text-decoration: none; color: inherit;
}
.hos-rowline + .hos-rowline { border-top: 1px solid var(--hairline-2); }
a.hos-rowline:hover { background: var(--accent-softer); }
.hos-rd-itile {
  width: 36px; height: 36px; flex: none; border-radius: var(--radius-md);
  display: grid; place-items: center;
  background: var(--surface-alt); color: var(--text-secondary);
}
.hos-rd-itile--accent { background: var(--accent-soft); color: var(--accent); }
.hos-rd-itile--warn { background: var(--warning-bg); color: var(--warning); }
.hos-rl__body { min-width: 0; }
.hos-rl-t { font-size: var(--text-sm); font-weight: 600; color: var(--ink); }
.hos-rl-s { font-size: var(--text-xs); color: var(--muted); margin-top: 1px; }
.hos-rl-v {
  margin-left: auto; flex: none;
  display: inline-flex; align-items: center; gap: 2px; white-space: nowrap;
  color: var(--accent); font-weight: 600; font-size: var(--text-xs);
}
/* Row rendered as a <button> (opens a drawer) — reset native chrome to match <a>. */
.hos-rowline--btn { width: 100%; text-align: left; background: none; border: 0; cursor: pointer; font-family: var(--font-sans); }
.hos-rd-card--warn { border-color: var(--amber-300); }
.hos-rd-card--warn .hos-rowhead { background: var(--warning-bg); border-bottom-color: var(--amber-300); }
.hos-rd-card--warn .hos-card__label { color: var(--warning); }

/* Rail — Balance: big mono figure + cents + CTA */
.hos-bal__cents { color: var(--muted-2); font-size: var(--text-xl); }
.hos-bal__due { font-family: var(--font-sans); font-size: var(--text-sm); font-weight: 400; color: var(--muted); margin-left: 8px; }
.hos-bal__cta { margin-top: var(--space-4); }
.hos-bal__cta .os-btn { width: 100%; justify-content: center; }

/* Rail — Guest portal & access: PIN digit squares */
.hos-portal__eye {
  font-size: var(--text-2xs); font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 6px;
}
.hos-pin { display: flex; gap: 6px; margin: 2px 0 14px; }
.hos-pin__d {
  width: 30px; height: 36px; border-radius: var(--radius-sm);
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent-strong);
  font-family: var(--font-mono); font-weight: 600; font-size: var(--text-lg);
}
.hos-portalrow {
  display: flex; align-items: center; gap: 12px; padding: 12px 0;
  border-top: 1px solid var(--hairline-2);
}
.hos-portalrow:first-of-type { border-top: none; }
.hos-portalrow__body { flex: 1; min-width: 0; }
.hos-portalrow__t { font-size: var(--text-sm); font-weight: 600; color: var(--ink); }
.hos-portalrow__s { font-size: var(--text-xs); color: var(--muted); }
.hos-pinactions { display: flex; gap: 6px; margin-bottom: var(--space-3); }

/* Form-drawer head/form structure. Replaces the inline flex/display styles the
   money + occupant drawers each repeated (`flex:1;min-width:0`, `flex:none`,
   `display:contents`) — same three declarations at every callsite, which is the
   signature of a missing class rather than a one-off. */
.hos-fd__ident { flex: 1; min-width: 0; }
.hos-fd__close { flex: none; }
/* display:contents so the form's children join the panel's flex column — the
   body scrolls and the footer pins, exactly as if the form element weren't there. */
.hos-fd__form { display: contents; }

/* ── Front-office write surfaces: form page + constrained chooser ──────────
   Archetype 3. Replaces the inline styles these pages each repeated (a shared
   `row` string of CSS in a Ruby local, in the case of exchange.html.erb). */
/* THE form measure for the staff app (tasks/073 A3). A form page is NOT a view
   page: it carries a single column of fields, so it takes the design system's
   FORM measure — the gem's `.os-form-page` (640px, margin-inline:auto) — while
   a view/list/detail page takes the VIEW measure, which is the shell column
   (`.hos-shell-content`, --page-wide 1280px). This class is only the gem
   measure plus the section rhythm; it must not drift off 640. */
.hos-formpage {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  max-width: 640px;
  margin-inline: auto;
}
.hos-formpage__actions { display: flex; gap: var(--space-2); margin-top: 6px; }
.hos-formpage__submit { flex: 1; justify-content: center; }

.hos-choicelist { display: flex; flex-direction: column; gap: var(--space-2); }
.hos-choicelist__lead {
  display: flex; align-items: center; justify-content: center;
  gap: var(--space-2); margin-bottom: 6px;
}
.hos-choicelist__empty { padding: 18px; text-align: center; }

/* One candidate. The whole card is the target (pattern 6: single-action card →
   whole-card hover), with the radio kept visible as the real control. */
.hos-choice {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  text-align: left;
  padding: 12px;
  cursor: pointer;
}
.hos-choice__body { flex: 1; min-width: 0; }
.hos-choice__name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Selected state driven by the radio itself, so the ring can never disagree
   with what will actually be submitted (the `.os-card--selected` idea). */
.hos-choice:has(.hos-choice__radio:checked) {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent-border);
}
.hos-choice:has(.hos-choice__radio:focus-visible) { box-shadow: var(--shadow-focus); }

/* ── Drawer interiors on the gem's `.os-side-panel*` chassis ─────────────────
   The gem's header assumes a block with a float:right close; the front-office
   drawer header is a row of [icon tile][identity][close]. Scoped to .hos-odrawer
   so only the drawer context differs, and the gem component is untouched.
   UPSTREAM CANDIDATES: a title-row header variant and a `--compact` title
   would remove all three of these. */
.hos-odrawer .os-side-panel__header { display: flex; align-items: flex-start; gap: 12px; }
.hos-drawer__title { font-size: var(--text-lg); margin-bottom: 0; }
.hos-fd__ident { flex: 1; min-width: 0; }
.hos-fd__close { flex: none; }
/* display:contents so the form's children join the panel's flex column — the
   body scrolls and the action bar pins, as if the form element weren't there. */
.hos-fd__form { display: contents; }
/* Folio-domain: the outstanding-balance callout inside the payment drawer.
   Resort domain (a folio balance), so it stays local by the rule. */

/* ── Inclusion list (archetype 3a · value picker) ─────────────────────────
   Checkbox state comes from the real `.os-field-check`; the card only carries
   the selected ring, driven by :has(:checked) so it cannot disagree with the
   control. Locked rate-plan items are a sentence, not a card — they are not
   choices, and card-shaping them made the operator scan twice as many tiles. */
.hos-incl__title { margin-bottom: var(--space-2); }
.hos-incl__locked {
  display: flex; align-items: flex-start; gap: var(--space-2);
  margin: 0; color: var(--muted); font-size: var(--text-sm);
}
.hos-incl__locked svg { flex: none; margin-top: 2px; color: var(--muted-2); }
.hos-incl__grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
@media (max-width: 560px) { .hos-incl__grid { grid-template-columns: 1fr; } }
.hos-incl__opt {
  padding: 10px 12px;
  border: 1px solid var(--hairline-2);
  border-radius: var(--radius-md);
  background: var(--surface);
  transition: border-color 120ms ease, background-color 120ms ease;
}
.hos-incl__opt:hover { border-color: var(--accent-border); }
.hos-incl__opt:has(.os-field-check__input:checked) {
  border-color: var(--accent);
  background: var(--accent-soft);
}

/* "Pay in full" sits with the balance it fills from, not with the field. */
.hos-fd__due { position: relative; }
.hos-fill { position: absolute; top: var(--space-3); right: var(--space-4); }

/* Field label above an input. The same three declarations were repeated inline
   at 37 callsites across the new-reservation page and the overview drawers —
   the signature of a missing class, not a per-field decision. */
.hos-fieldlabel { display: block; margin-bottom: var(--space-1); }

/* ── Wizard chrome (archetype 2) ──────────────────────────────────────────
   The horizontal stepper is 1:1 with DiveOS `shared/patterns/_stepper_horizontal`
   — same geometry, translated from its Tailwind utilities because arena has no
   Tailwind: py-2=8px · gap-1.5=6px · w-8 h-8=32px · border-2=2px · text-xs=12px
   · top-4=16px · h-0.5=2px · left calc(50%+20px) / right calc(-50%+20px).
   Colours come from OUR tokens: DiveOS resolves --accent-light to sky-100,
   arena to teal-100, which is what the token indirection is for.
   PROMOTION CANDIDATE: once both apps have a horizontal stepper, neither
   should own it. */
.hos-wizard { display: flex; align-items: flex-start; gap: 0; padding: var(--space-2) 0; }
.hos-wizard__step {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  flex: 1; min-width: 0; position: relative;
  background: none; border: none; padding: 0; font: inherit;
}
.hos-wizard__dot {
  width: 32px; height: 32px; border-radius: var(--radius-pill);
  display: flex; align-items: center; justify-content: center;
  border: 2px solid; font-size: var(--text-xs); font-weight: 600;
  position: relative; z-index: 10;
}
.hos-wizard__step--done .hos-wizard__dot { background: var(--accent); border-color: var(--accent); color: #fff; }
.hos-wizard__step--now  .hos-wizard__dot { background: var(--accent-light); border-color: var(--accent); color: var(--accent); }
.hos-wizard__step--todo .hos-wizard__dot { background: var(--surface); border-color: var(--hairline); color: var(--muted); }
.hos-wizard__label { line-height: 1.4; }
.hos-wizard__step--done .hos-wizard__label { color: var(--accent); }
.hos-wizard__step--now  .hos-wizard__label { color: var(--accent); font-weight: 700; }
.hos-wizard__step--todo .hos-wizard__label { color: var(--muted); }
.hos-wizard__step:not(:last-child)::after {
  content: ""; position: absolute; top: 16px;
  left: calc(50% + 20px); right: calc(-50% + 20px);
  height: 2px; background: var(--hairline);
}
.hos-wizard__step--done:not(:last-child)::after { background: var(--accent); }

/* The band is FULL BLEED — background and separator span the viewport while the
   content re-insets to the centred column. Sits on --canvas, not --surface: it
   is chrome around the step, not a surface you read. Sticky, so a long form
   never loses its progress indicator. */
.hos-wizard-band {
  /* position/top/z-index/ground/hairline + the 40-20 -> 16-16 condense all come
     from `.os-stickybar` (gem). This adds only the full-bleed geometry. */
  /* Bleed via the SHELL's --bleed-* contract, exactly like the gem's page
     bands. Fallbacks are auto/0/0, NOT 100vw: the content column is not the
     viewport (there is a sidebar), so a 100vw fallback bleeds the band out over
     the nav. Degrade to a plain non-bleeding band instead. */
  width: var(--bleed-w, auto);
  margin-inline: var(--bleed-mx, 0);
  padding-inline: var(--bleed-pad, 0);
}
/* Padding now comes from the gem's `.os-stickybar` (os-ds v1.14.0): 40/20 in
   flow, 16/16 once stuck, driven by the `stuck` controller. The band keeps only
   its own full-bleed geometry. */
.hos-wizard-band .hos-wizard { padding-inline: 0; }

/* One step's fields. Hidden steps stay in the DOM so the single form still
   posts every field on the final submit — create_reservation is unchanged. */
.hos-wzstep[hidden] { display: none; }
/* Step action bar — mirrors the DiveOS wizard footer (`.wz-foot` there): a
   STICKY bar pinned to the bottom of the work column, on surface, hairline top,
   Back at the start and the forward/commit action at the end. One bar per step,
   INSIDE the panel, so it appears and disappears with the step it belongs to —
   the reference renders per-step footers for the same reason.
   No drop shadow: the reference's is a raw rgba, and the hairline alone reads
   correctly here without minting an off-token colour. */
.hos-wzstep__foot {
  position: sticky; bottom: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3); padding: 14px 0;
  background: var(--surface);
  border-top: 1px solid var(--hairline);
}
/* Cancel + Create ride the LAST step's bar. Kept as its own element because the
   wizard controller shows/hides exactly this row (`submitTarget.closest("div")`)
   — the commit action exists only on the final step. */
.hos-wzstep__submit { display: flex; align-items: center; gap: var(--space-2); }
