/* Guest-portal components (.hos-gp-*) — the shared vocabulary the mockup rebuild composes
   from. Semantic tokens only (slate neutrals, teal-700 accent); dark surfaces (Stay Pass)
   are the sanctioned token-permission, expressed via --pass-bg, never a dark: variant.
   Scoped under .hos-gp (the portal shell) so nothing leaks into the staff app. */

.hos-gp {
  /* teal-900 dark-card surface + the mobile bottom-tab reserve height. */
  --pass-bg: var(--teal-900);
  --hos-gp-tabbar-h: 74px;
}

/* ── Page head: greeting + weather/locale chip ────────────────────────────── */
/* `.hos-gp-pagehead` (read pages) and `.hos-gp-formhead` (form pages) were two
   names for ONE block — same flex row, same 20px margin, same h1 declarations,
   drifting independently. They now share every rule below; only the two class
   names survive so existing callsites keep working. The single spec lives with
   `.hos-gp-formhead` further down this file. */
.hos-gp-locale { display: inline-flex; align-items: center; gap: 7px; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); white-space: nowrap; }
.hos-gp-locale b { color: var(--ink); }

/* ── 2-up hero grid (Stay Pass + Transfer hero); stacks on mobile ─────────── */
.hos-gp-hero2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: stretch; }

/* ── Stay Pass — the signature dark boarding-pass card (§1.1) ──────────────── */
.hos-gp-pass { background: var(--pass-bg); color: var(--on-accent); border-radius: var(--radius-xl); padding: 20px; position: relative; overflow: hidden; box-shadow: 0 20px 40px -20px rgba(4, 47, 46, 0.7); }
.hos-gp-pass__top { display: flex; align-items: center; justify-content: space-between; font-family: var(--font-mono); font-size: var(--text-2xs); font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: rgba(255, 255, 255, 0.72); }
.hos-gp-pass__top .l { display: inline-flex; align-items: center; gap: 6px; }
.hos-gp-pass__st { display: inline-flex; align-items: center; gap: 5px; color: var(--green-300); }
.hos-gp-pass__st::before { content: ""; width: 6px; height: 6px; border-radius: var(--radius-pill); background: var(--green-400); }
.hos-gp-pass__name { font-family: var(--font-display); font-size: var(--text-2xl); font-weight: 600; letter-spacing: -0.02em; margin: 14px 0 18px; }
.hos-gp-pass__name b { color: rgba(255, 255, 255, 0.55); font-weight: 600; }
/* flight-leg route */
.hos-gp-route { display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; }
.hos-gp-route__end .l { font-family: var(--font-mono); font-size: var(--text-2xs); font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: rgba(255, 255, 255, 0.55); }
.hos-gp-route__end .v { font-family: var(--font-mono); font-weight: 600; font-size: var(--text-lg); margin-top: 4px; white-space: nowrap; }
.hos-gp-route__end--r { text-align: right; }
.hos-gp-route__mid { flex: 1; display: flex; flex-direction: column; align-items: center; padding-bottom: 2px; }
.hos-gp-route__mid .n { font-family: var(--font-mono); font-size: var(--text-2xs); font-weight: 600; letter-spacing: 0.1em; color: rgba(255, 255, 255, 0.82); margin-bottom: 6px; }
.hos-gp-route__mid .ln { width: 100%; height: 1px; background: repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.4) 0 5px, transparent 5px 10px); position: relative; }
.hos-gp-route__mid .ln .hos-gp-glyph { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); background: var(--pass-bg); color: var(--on-accent); padding: 0 3px; display: inline-flex; }
/* room / board / villa foot cells, mono, hairline dividers */
.hos-gp-pass__foot { display: flex; margin-top: 18px; padding-top: 14px; border-top: 1px solid rgba(255, 255, 255, 0.14); }
.hos-gp-pcell { flex: 1; padding-left: 14px; position: relative; }
.hos-gp-pcell:first-child { padding-left: 0; }
.hos-gp-pcell + .hos-gp-pcell::before { content: ""; position: absolute; left: 0; top: 1px; bottom: 1px; width: 1px; background: rgba(255, 255, 255, 0.14); }
.hos-gp-pcell .l { font-family: var(--font-mono); font-size: var(--text-2xs); font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: rgba(255, 255, 255, 0.55); }
.hos-gp-pcell .v { font-family: var(--font-mono); font-weight: 600; font-size: var(--text-md); margin-top: 5px; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; }

/* ── Image placeholder (§ shared) — neutral "photo goes here" slot ─────────────
   The reusable no-photo-yet affordance: a muted slate surface + centered image
   glyph. Real transfer/experience photos are a later feature (Setting#hero_image +
   catalog photos); until then this reads as an intentional slot, not a broken img. */
.hos-gp-imgph { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: var(--surface-alt, var(--slate-100)); color: var(--slate-300); }
.hos-gp-imgph svg { width: 40%; height: 40%; max-width: 64px; max-height: 64px; }
/* real (demo) photo layer — covers the slot, sits above the .hos-gp-imgph fallback but
   below the overlaid scrims/panels/chips (those follow in DOM order). */
.hos-gp-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.hos-gp-expcard__img .hos-gp-photo { z-index: 0; }
/* scrim over the transfer-hero photo — keeps the top eyebrow + Confirmed chip and the
   bottom "Your transfer" panel legible over a bright resort photo. */
.hos-gp-rph__scrim { position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(15, 23, 42, 0.42) 0%, transparent 30%, transparent 48%, rgba(15, 23, 42, 0.5) 100%); }
/* on the transfer hero, a scrim keeps the overlaid dark panel + chips legible over the light slot */
.hos-gp-rph .hos-gp-imgph::after, .hos-gp-expcard__img .hos-gp-imgph::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(15, 23, 42, 0.28) 0%, transparent 34%, transparent 52%, rgba(15, 23, 42, 0.4) 100%); }

/* ── Transfer / photo-glass hero (§1.2) — image placeholder (no real photo yet) ─ */
.hos-gp-rph { position: relative; display: block; border-radius: var(--radius-xl); overflow: hidden; min-height: 210px; text-decoration: none;
  background: var(--surface-alt, var(--slate-100)); box-shadow: var(--shadow-card); }
.hos-gp-rph__top { position: absolute; top: 14px; left: 14px; right: 14px; display: flex; align-items: center; justify-content: space-between; color: var(--on-accent); }
.hos-gp-rph__ey { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-mono); font-size: var(--text-2xs); font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; }
.hos-gp-rph__glass { display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; border-radius: var(--radius-pill); background: rgba(255, 255, 255, 0.92); color: var(--green-700); font-size: var(--text-2xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em; }
.hos-gp-rph__panel { position: absolute; left: 12px; right: 12px; bottom: 12px; background: linear-gradient(180deg, rgba(6, 42, 40, 0.82), rgba(6, 42, 40, 0.94)); border: 1px solid rgba(255, 255, 255, 0.12); border-radius: var(--radius-md); padding: 12px 14px; color: var(--on-accent); }
.hos-gp-rph__row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.hos-gp-rph__name { font-family: var(--font-display); font-size: var(--text-lg); font-weight: 600; letter-spacing: -0.01em; }
.hos-gp-rph__time { font-family: var(--font-mono); font-weight: 600; font-size: var(--text-md); }
.hos-gp-rph__meta { font-size: var(--text-xs); color: rgba(255, 255, 255, 0.82); margin-top: 3px; }
/* empty-state CTA variant: no glass chip, centered prompt */
.hos-gp-rph__cta { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: flex-start; justify-content: flex-end; gap: 4px; padding: 20px; color: var(--on-accent); }
.hos-gp-rph__cta .t { font-family: var(--font-display); font-size: var(--text-lg); font-weight: 600; }
.hos-gp-rph__cta .d { font-size: var(--text-sm); color: rgba(255, 255, 255, 0.85); }

/* ── Progress / arrival-readiness ring (§1.3) ─────────────────────────────── */
.hos-gp-ring { position: relative; flex: none; display: inline-flex; }
.hos-gp-ring svg { transform: rotate(-90deg); }
.hos-gp-ring__track { stroke: var(--hairline); }
.hos-gp-ring__ind { stroke: var(--accent); stroke-linecap: round; }
.hos-gp-ring__t { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-family: var(--font-mono); font-weight: 600; color: var(--accent); font-size: var(--text-xs); }

/* ── Section head (§ shared) ──────────────────────────────────────────────── */
.hos-gp-sechead { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin: 28px 0 14px; }
.hos-gp-sechead__t { font-family: var(--font-display); font-size: var(--text-lg); font-weight: 600; letter-spacing: -0.02em; color: var(--ink); }
/* the "See all" / "Manage" affordance is the gem's `.os-link` — no local rule. */
.hos-gp-sechead > .os-link { flex: none; }

/* ── Experience card (§1.5) — gradient fallback ───────────────────────────── */
.hos-gp-exprow { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.hos-gp-exprow > * { min-width: 0; }
.hos-gp-expcard { display: block; text-decoration: none; }
/* real catalog photos are a later feature — image placeholder for now. */
.hos-gp-expcard__img { position: relative; height: 184px; border-radius: var(--radius-md); overflow: hidden; background: var(--surface-alt, var(--slate-100)); box-shadow: var(--shadow-card); }
.hos-gp-expcard__price { position: absolute; top: 9px; right: 9px; background: rgba(255, 255, 255, 0.94); border-radius: var(--radius-pill); padding: 3px 9px; font-family: var(--font-mono); font-weight: 600; font-size: var(--text-xs); color: var(--ink); }
.hos-gp-expcard__cap { position: absolute; left: 0; right: 0; bottom: 0; padding: 12px 11px 10px; color: var(--on-accent); background: linear-gradient(180deg, transparent, rgba(6, 42, 40, 0.82)); }
.hos-gp-expcard__k { font-family: var(--font-mono); font-size: var(--text-2xs); font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.85; }
.hos-gp-expcard__t { font-size: var(--text-sm); font-weight: 600; letter-spacing: -0.01em; margin-top: 2px; }
.hos-gp-expcard__meta { font-size: var(--text-xs); color: var(--muted); margin-top: 8px; display: flex; align-items: center; gap: 6px; }
.hos-gp-expcard__meta svg { color: var(--muted-2); }

/* Filter pill row: `.os-filter-bar` + `.os-filter-pill` / `--active` (rule 6).
   The local `.hos-gp-filterbar` / `.hos-gp-fpill` duplicated them — deleted (tasks/071). */

/* Status pills are `.os-status-pill` + the gem's status modifiers (rule 5). The
   local `.gpc-pill--muted` / `.gpc-spill--*` set re-declared tones the gem already
   ships (`--muted` / `--returning` / `--in_water` / `--completed` / `--cancelled`)
   and was deleted in the tasks/071 sweep; `.gpc-emptyline` went with the empty
   states that became `.os-empty-state`. */

/* ── Catalog grid (Book/Explore) — full grid, 2-up on mobile (not the dashboard
   "See all" carousel that .hos-gp-exprow becomes below 860px). ────────────────── */
.hos-gp-catgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(216px, 1fr)); gap: 16px; }
.hos-gp-catgrid > * { min-width: 0; }
@media (max-width: 620px) {
  .hos-gp-catgrid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
  .hos-gp-catgrid .hos-gp-expcard__img { height: 148px; }
}

/* ── Flagship "Complete your arrival" tile + readiness ring/steps (§1.3) ───── */
.hos-gp-flagship { display: block; overflow: hidden; border-radius: var(--radius-lg); box-shadow: var(--shadow-card); text-decoration: none; background: var(--surface); }
.hos-gp-flagship__band { padding: 18px 20px; display: flex; align-items: center; gap: 16px; color: var(--on-accent); position: relative;
  background: linear-gradient(120deg, var(--teal-700), var(--teal-900)); }
.hos-gp-flagship__ring { flex: none; }
.hos-gp-flagship__band h3 { font-family: var(--font-display); font-weight: 600; font-size: var(--text-lg); margin: 0; color: var(--on-accent); }
.hos-gp-flagship__band .d { font-size: var(--text-sm); margin-top: 2px; color: rgba(255, 255, 255, 0.85); }
.hos-gp-flagship__mand { position: absolute; top: 14px; right: 16px; background: rgba(255, 255, 255, 0.2); border: 1px solid rgba(255, 255, 255, 0.35); padding: 2px 9px; border-radius: var(--radius-pill); font-size: var(--text-2xs); font-weight: 600; color: var(--on-accent); }
.hos-gp-flagship__foot { padding: 14px 20px; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.hos-gp-flagship__foot p { margin: 0; color: var(--muted); font-size: var(--text-sm); }
.hos-gp-flagship__cta { display: inline-flex; align-items: center; gap: 6px; color: var(--accent); font-weight: 600; font-size: var(--text-sm); flex: none; }
/* ring inside the flagship band uses white ink on a translucent track */
.hos-gp-flagship .hos-gp-ring__track { stroke: rgba(255, 255, 255, 0.28); }
.hos-gp-flagship .hos-gp-ring__ind { stroke: var(--on-accent); }
.hos-gp-flagship .hos-gp-ring__t { color: var(--on-accent); }

/* readiness step list (§1.4, compact)

   The card sits directly under the flagship band and was BUTTED to it (measured
   gap 0) while every other pair on this page breathes at 14–28px — so the two
   read as one card that had broken in half. It takes the same 14px the page
   gives its other blocks.

   The rows had `padding: 13px 0` — no horizontal inset at all, so the icon tile
   and the "Added" pill sat ON the card's border. `--space-5` matches the inset
   every other card on the portal uses, and the row dividers now stop at that
   inset too (a hairline that runs edge-to-edge under an inset row is the other
   half of the same mistake). */
.hos-gp-steps { display: flex; flex-direction: column; margin-top: 14px; }
.hos-gp-step { display: flex; align-items: center; gap: 12px;
  padding: 13px var(--space-5); border-top: 1px solid var(--hairline); }
.hos-gp-step:first-child { border-top: 0; }
.hos-gp-step__b { width: 34px; height: 34px; border-radius: var(--radius-md); display: inline-flex; align-items: center; justify-content: center; flex: none; background: var(--surface-alt, var(--slate-50)); color: var(--muted); }
.hos-gp-step.is-done .hos-gp-step__b { background: var(--status-confirmed-bg); color: var(--status-confirmed-fg); }
/* the actionable (incomplete) step out-weighs the completed ones: accent tile + Add link */
.hos-gp-step.is-now .hos-gp-step__b { background: var(--accent-soft); color: var(--accent); }
.hos-gp-step__x { flex: 1; min-width: 0; }
.hos-gp-step__t { font-size: var(--text-sm); font-weight: 600; color: var(--ink); }
.hos-gp-step__d { font-size: var(--text-xs); color: var(--muted); }
/* composes the gem's `.os-link`; adds only the padded hit area + hover tint. */
.hos-gp-step__add { flex: none; padding: 4px 8px; border-radius: var(--radius-sm); }
.hos-gp-step__add:hover { background: var(--state-hover); }

/* ── Nudge banner (severity-tinted) ───────────────────────────────────────── */
.hos-gp-nudge { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 13px 16px; margin-bottom: 16px; border-radius: var(--radius-md); text-decoration: none; background: var(--accent-soft); }
.hos-gp-nudge__t { font-size: var(--text-sm); font-weight: 600; color: var(--accent-strong, var(--accent)); }
.hos-gp-nudge__cta { flex: none; display: inline-flex; align-items: center; gap: 5px; font-size: var(--text-xs); font-weight: 600; color: var(--accent-strong, var(--accent)); }
.hos-gp-nudge.is-warning { background: var(--status-briefing-bg); }
.hos-gp-nudge.is-warning .hos-gp-nudge__t, .hos-gp-nudge.is-warning .hos-gp-nudge__cta { color: var(--status-briefing-fg); }
.hos-gp-nudge.is-critical { background: var(--status-cancelled-bg); }
.hos-gp-nudge.is-critical .hos-gp-nudge__t, .hos-gp-nudge.is-critical .hos-gp-nudge__cta { color: var(--status-cancelled-fg); }

/* ── Stage to-do rows (in-house / departing) ──────────────────────────────── */
.hos-gp-todos { display: grid; gap: 8px; }
.hos-gp-todo { display: flex; align-items: center; gap: 13px; padding: 15px 16px; text-decoration: none; }
.hos-gp-todo__x { flex: 1; min-width: 0; }
.hos-gp-todo__t { font-size: var(--text-sm); font-weight: 600; color: var(--ink); }
.hos-gp-todo__d { font-size: var(--text-xs); color: var(--muted); }
.hos-gp-todo__chev { flex: none; color: var(--muted-2); display: inline-flex; }

/* ── "Manage your stay" quick-links grid (phase-1 bridge until d-stay/d-profile) ─ */
.hos-gp-managegrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 10px; }
/* §1.6 detail-row: tinted icon tile + title/sub + trailing chevron on a surface card */
.hos-gp-navcard { display: flex; align-items: center; gap: 13px; padding: 14px 15px; text-decoration: none; background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius-md); }
.hos-gp-navcard:hover { background: var(--state-hover); }
.hos-gp-navcard__ic { width: 38px; height: 38px; border-radius: var(--radius-md); flex: none; display: inline-flex; align-items: center; justify-content: center; background: var(--accent-soft); color: var(--accent); }
.hos-gp-navcard__x { flex: 1; min-width: 0; }
.hos-gp-navcard__t { font-size: var(--text-sm); font-weight: 600; color: var(--ink); }
.hos-gp-navcard__d { font-size: var(--text-xs); color: var(--muted); margin-top: 1px; }
.hos-gp-navcard__chev { flex: none; color: var(--muted-2); display: inline-flex; }

/* Booked-item tile (My bookings). Domain: a read-only confirmed booking, icon +
   category eyebrow + status, over an .os-card. Replaced the page's inline
   <style> `.bkg-*` family (tasks/071). */
.hos-gp-bookcard { padding: 16px 17px; }
.hos-gp-bookcard__head { display: flex; align-items: center; gap: 9px; }
.hos-gp-bookcard__ic { width: 26px; height: 26px; border-radius: var(--radius-sm); flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent-soft); color: var(--accent); }
.hos-gp-bookcard__st { flex: none; margin-left: auto; }
.hos-gp-bookcard__t { font-size: var(--text-sm); font-weight: 600; color: var(--ink); margin: 10px 0 2px; }
.hos-gp-bookcard__d { font-size: var(--text-xs); color: var(--muted); }

/* ── §3.5 Profile (d-profile) — head actions, hero, detail rows, prefs, party ──
   READ view only: every row/card is a link or non-interactive; no write surface. */
.hos-gp-pagehead__actions { display: flex; align-items: center; gap: 8px; flex: none; }

/* Initials disc: `.os-avatar` (+ `--sm` / `--lg` / `--muted`). The local
   `.hos-gp-avatar*` family duplicated it and was deleted in the tasks/071 sweep. */

/* Hero band: avatar + name + stay line, accent-soft gradient. */
.hos-gp-phero { display: flex; align-items: center; gap: 16px; padding: 20px 22px; border-radius: var(--radius-lg);
  background: linear-gradient(135deg, var(--accent-soft), var(--surface-alt)); border: 1px solid var(--hairline); margin-bottom: 22px; }
.hos-gp-phero__b { flex: 1; min-width: 0; }
.hos-gp-phero__t { font-family: var(--font-display); font-size: var(--display-xs); font-weight: 600; letter-spacing: -0.02em; color: var(--ink); }
.hos-gp-phero__t span { color: var(--muted-2); font-weight: 600; }
.hos-gp-phero__d { font-size: var(--text-sm); color: var(--muted); margin-top: 3px; }

/* Two-column grid (details+prefs | party) → single column on mobile. */
.hos-gp-p2 { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; align-items: start; }
.hos-gp-p2 > * { min-width: 0; }

/* §1.6 detail row — tinted icon tile + title/sub + trailing badge/link. As a link
   the whole row is clickable (hover tint); a done row is a plain, static div. */
.hos-gp-row { display: flex; align-items: center; gap: 13px; width: 100%; text-align: left; padding: 14px 16px; border-top: 1px solid var(--hairline-2);
  text-decoration: none; background: transparent; color: inherit; }
.hos-gp-row:first-child { border-top: 0; }
a.hos-gp-row:hover { background: var(--state-hover); }
.hos-gp-row__ic { width: 38px; height: 38px; border-radius: var(--radius-md); flex: none; display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent-soft); color: var(--accent); }
.hos-gp-row__ic.n { background: var(--surface-alt); color: var(--muted); }
.hos-gp-row__ic.ok { background: var(--status-confirmed-bg); color: var(--status-confirmed-fg); }
.hos-gp-row__b { flex: 1; min-width: 0; }
.hos-gp-row__t { font-size: var(--text-sm); font-weight: 600; color: var(--ink); }
.hos-gp-row__d { font-size: var(--text-xs); color: var(--muted); margin-top: 2px; }
.hos-gp-row__d .mono { font-family: var(--font-mono); }
.hos-gp-row__add { flex: none; display: inline-flex; align-items: center; gap: 4px; font-size: var(--text-sm); font-weight: 600; color: var(--accent); }

/* Preferences tag card — label + tag row; add-tag is a dashed accent chip link. */
.hos-gp-prefcard { padding: 18px; }
.hos-gp-prefcard .hos-gp-tagrow + .hos-gp-taglabel { margin-top: 16px; }
.hos-gp-count { display: inline-flex; align-items: center; padding: 1px 8px; border-radius: var(--radius-pill); background: var(--surface-alt); color: var(--muted); font-size: var(--text-2xs); font-weight: 600; }
.hos-gp-taglabel { font-family: var(--font-mono); font-size: var(--text-2xs); font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted-2); margin-bottom: 8px; }
.hos-gp-tagrow { display: flex; flex-wrap: wrap; gap: 7px; }
.hos-gp-tag { display: inline-flex; align-items: center; gap: 5px; padding: 5px 12px; border-radius: var(--radius-pill);
  background: var(--surface-alt); border: 1px solid var(--hairline); font-size: var(--text-xs); font-weight: 600; color: var(--ink); }
.hos-gp-tag--add { background: transparent; border-style: dashed; border-color: var(--accent); color: var(--accent); text-decoration: none; }
.hos-gp-tag--add:hover { background: var(--accent-soft); }

/* Who's-travelling party cards + readiness pips (§1.8). */
.hos-gp-party { display: grid; gap: 10px; }
.hos-gp-pcard { display: flex; align-items: flex-start; gap: 12px; padding: 14px; border: 1px solid var(--hairline); border-radius: var(--radius-md); background: var(--surface); }
.hos-gp-pcard__b { flex: 1; min-width: 0; }
.hos-gp-pcard__t { font-size: var(--text-sm); font-weight: 600; color: var(--ink); }
.hos-gp-pcard__t span { color: var(--muted-2); font-weight: 600; }
.hos-gp-pcard__d { font-size: var(--text-xs); color: var(--muted); margin-top: 1px; }
.hos-gp-pips { display: flex; flex-wrap: wrap; gap: 6px 12px; margin-top: 9px; }
.hos-gp-pip { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-2xs); font-weight: 600; color: var(--muted-2); }
.hos-gp-pip .d { width: 7px; height: 7px; border-radius: var(--radius-pill); background: var(--hairline-2); border: 1px solid var(--muted-2); flex: none; }
.hos-gp-pip.ok { color: var(--status-confirmed-fg); }
.hos-gp-pip.ok .d { background: var(--status-confirmed-fg); border-color: var(--status-confirmed-fg); }

/* The `.gpc-guestlist` / `.gpc-guestrow*` travel-party list had no callsite left
   (the party list retired with the tasks/069 arrival redesign, which uses
   `.hos-entity-tabs`). Deleted in the tasks/071 sweep — the gem's
   `.os-profile-row` is the component to reach for if it is ever needed again. */

@media (max-width: 860px) {
  .hos-gp-p2 { grid-template-columns: 1fr; gap: 16px; }
}

/* ── §1.13 Statement — balance header + Charges/Payments ledgers ──────────────
   Balance is READ-ONLY: no guest payment surface exists. The rose figure is the
   ONE sanctioned balance-red on a guest page; charges/payments are §1.6 rows. */
.hos-gp-balance { background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius-lg); padding: 22px 24px; box-shadow: var(--shadow-card); }
.hos-gp-balance__l { font-family: var(--font-mono); font-size: var(--text-2xs); font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--muted-2); }
.hos-gp-balance__row { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-top: 8px; }
.hos-gp-balance__amt { font-family: var(--font-mono); font-size: var(--display-sm); font-weight: 700; letter-spacing: -.02em; color: var(--rose-700); line-height: 1; }
.hos-gp-balance__amt.is-credit { color: var(--success); }
.hos-gp-balance__amt small { display: block; font-family: var(--font-sans); font-size: var(--text-sm); font-weight: 500; color: var(--muted); margin-top: 8px; letter-spacing: 0; }
/* Non-interactive "settled at checkout" label — deliberately NOT a button/link. */
/* A READOUT, not a settle button (GitLab #138 / tasks/074 G4). It sits in the
   balance card's action zone, so a filled + bordered + pill-radius chip read as a
   tappable "Pay" button though no guest payment exists. Plain muted text + icon
   reads as the status note it is. */
.hos-gp-balance__note { display: inline-flex; align-items: center; gap: 7px; flex: none; color: var(--muted); font-size: var(--text-xs); font-weight: 600; white-space: nowrap; }
.hos-gp-balance__bar { height: 6px; border-radius: var(--radius-pill); background: var(--surface-alt); margin-top: 18px; overflow: hidden; }
.hos-gp-balance__bar i { display: block; height: 100%; border-radius: inherit; background: var(--accent); }

.hos-gp-ledger { padding: 4px 0; }
.hos-gp-lrow { display: flex; align-items: center; gap: 14px; padding: 14px 18px; border-top: 1px solid var(--hairline-2); }
.hos-gp-lrow:first-child { border-top: 0; }
.hos-gp-lrow__ic { width: 36px; height: 36px; border-radius: var(--radius-md); background: var(--surface-alt); color: var(--muted); display: flex; align-items: center; justify-content: center; flex: none; }
.hos-gp-lrow__ic.is-credit { background: var(--success-bg); color: var(--success); }
.hos-gp-lrow__b { flex: 1; min-width: 0; }
.hos-gp-lrow__t { font-size: var(--text-sm); font-weight: 600; color: var(--ink); letter-spacing: -.01em; }
.hos-gp-lrow__d { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); margin-top: 2px; }
.hos-gp-lrow__amt { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 600; color: var(--ink); text-align: right; white-space: nowrap; }
.hos-gp-lrow__amt.is-credit { color: var(--success); }
.hos-gp-lrow__amt--muted { color: var(--muted-2); font-weight: 500; }

/* Empty states use the gem `.os-empty-state` (+ `__icon` / `__message` /
   `__description` / `__actions`); the local `.hos-gp-empty*` trio duplicated it and
   was deleted (tasks/071). Trailing fine print stays domain copy. */
.hos-gp-fineprint { font-size: var(--text-xs); color: var(--muted); margin: 18px 0 0; }

/* Flash notices are the gem's `.os-callout` verbatim (tasks/074 G2 — see
   guest_portal/_flash). The ONLY thing local to the portal is the gap to the
   page below it, which is page rhythm, not the component's business. */
.hos-gp-flash { margin-bottom: var(--space-4); }

/* Tax + totals summary (real Maldives split) — label-left / mono-right.
   tasks/074: "the text looks off — check the styling from front_office/g/10 >
   Folio." It was: the block wore `.os-card` but supplied NO padding of its own,
   so the rows sat flush against the card's border and every hairline ran the
   full card width — the totals read as a bare table dumped on the page rather
   than a panel, which is exactly what the staff folio does NOT do. And at
   `--text-xs` the money on a GUEST's own statement was the smallest type on the
   screen.

   Brought in line with the front-office Folio tab: real panel padding, labels at
   `--text-sm`, amounts mono + tabular so the decimal points stack, and the
   closing balance stepped up so the number the guest actually came for is the
   largest thing in the block. Hairlines now inset with the content. */
.hos-gp-sum { display: flex; flex-direction: column; gap: 10px; padding: 18px 20px; }
.hos-gp-sumrow { display: flex; justify-content: space-between; gap: 16px; font-size: var(--text-sm); color: var(--muted); }
.hos-gp-sumrow span:last-child { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--ink); white-space: nowrap; }
.hos-gp-sumrow.is-total { font-size: var(--text-sm); font-weight: 600; color: var(--ink); border-top: 1px solid var(--hairline-2); padding-top: 10px; margin-top: 2px; }
.hos-gp-sumrow.is-total span:last-child { font-weight: 700; }
.hos-gp-sumrow.is-total.is-due { font-size: var(--text-base); }
.hos-gp-sumrow.is-total.is-due span:last-child { color: var(--rose-700); }

@media (max-width: 620px) {
  .hos-gp-balance__row { flex-wrap: wrap; }
  .hos-gp-balance__amt { font-size: var(--display-xs); }
}

/* ── Mobile bottom tab bar (§2) — shown ≤860px, sidebar hidden ─────────────── */
.hos-gp-tabbar { display: none; }
.hos-gp-tab { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; min-height: 44px;
  color: var(--muted-2); text-decoration: none; font-size: var(--text-2xs); font-weight: 600; }
.hos-gp-tab[aria-current="page"] { color: var(--accent); }

@media (max-width: 860px) {
  .hos-gp-hero2 { grid-template-columns: 1fr; }
  .hos-gp-rph { min-height: 230px; }
  /* experiences: horizontal snap-scroll rail, edge-to-edge */
  .hos-gp-exprow { display: flex; gap: 12px; overflow-x: auto; scrollbar-width: none; margin: 0 -16px; padding: 0 16px 4px; }
  .hos-gp-exprow::-webkit-scrollbar { display: none; }
  .hos-gp-exprow > .hos-gp-expcard { flex: none; width: 168px; }
  .hos-gp-expcard__img { height: 150px; }
  .hos-gp-sechead { margin: 22px 0 12px; }
  /* dock the fixed bottom tab bar; reserve its height on the content column */
  .hos-gp-tabbar { display: flex; position: fixed; left: 0; right: 0; bottom: 0; height: var(--hos-gp-tabbar-h);
    background: rgba(255, 255, 255, 0.94); backdrop-filter: blur(10px); border-top: 1px solid var(--hairline);
    z-index: 40; padding: 8px 10px calc(8px + env(safe-area-inset-bottom, 0px)); }
  .hos-gp .hos-gp-body { padding-bottom: calc(var(--hos-gp-tabbar-h) + 24px); }
}

/* ── Entry / PIN-unlock gate (§1.14) — two-pane art treatment ──────────────────
   The pre-PIN access screen. Desktop: a full-bleed resort photo (left, ~52%) with
   a pull-quote scrim + a centered form panel (right, 380px) carrying the brand
   lockup, heading and the REAL check-in-PIN field. ≤860px the art panel drops and
   the panel becomes a single centered column. Art copy is static; mechanics (the
   PIN field + unlock POST) are unchanged — this is styling only. */
.hos-gp-entry { min-height: 100vh; display: grid; grid-template-columns: 1fr; background: var(--canvas); }
.hos-gp-entry__art { position: relative; display: none; overflow: hidden; }
.hos-gp-entry__artscrim { position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(15, 23, 42, 0.30) 0%, rgba(15, 23, 42, 0.36) 45%, rgba(15, 23, 42, 0.80) 100%); }
.hos-gp-entry__artcap { position: absolute; left: 44px; right: 44px; bottom: 44px; color: var(--on-accent); }
.hos-gp-entry__artcap .q { font-family: var(--font-display); font-size: var(--text-2xl, 28px); font-weight: 700;
  letter-spacing: -0.02em; line-height: 1.28; max-width: 460px; text-wrap: pretty; }
.hos-gp-entry__artcap .by { font-family: var(--font-mono); font-size: var(--text-xs); opacity: 0.85;
  margin-top: 14px; letter-spacing: 0.04em; }
.hos-gp-entry__panel { display: flex; flex-direction: column; justify-content: center; padding: 40px 24px; overflow-y: auto; }
.hos-gp-entry__inner { width: 100%; max-width: 380px; margin: 0 auto; }
.hos-gp-entry__brand { display: flex; align-items: center; gap: 11px; font-family: var(--font-display);
  font-weight: 700; font-size: var(--text-lg); color: var(--ink); margin-bottom: 34px; }
.hos-gp-entry__brand .m { width: 36px; height: 36px; border-radius: var(--radius-md); background: var(--accent);
  color: var(--on-accent); display: inline-flex; align-items: center; justify-content: center; flex: none; }
.hos-gp-entry__brand small { display: block; font-family: var(--font-mono); font-size: var(--text-2xs);
  font-weight: 500; color: var(--muted); text-transform: uppercase; letter-spacing: 0.12em; margin-top: 2px; }
.hos-gp-entry__ey { font-family: var(--font-mono); font-size: var(--text-2xs); font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); }
.hos-gp-entry__h { font-family: var(--font-display); font-size: var(--text-3xl); font-weight: 800;
  letter-spacing: -0.03em; color: var(--ink); margin: 8px 0; }
.hos-gp-entry__sub { font-size: var(--text-sm); color: var(--text-muted); line-height: 1.55; margin-bottom: 24px; }
.hos-gp-entry__foot { font-size: var(--text-xs); color: var(--muted-2); text-align: center; margin-top: 22px; }

@media (min-width: 861px) {
  .hos-gp-entry { grid-template-columns: 1.05fr 0.95fr; }
  .hos-gp-entry__art { display: block; }
  .hos-gp-entry__panel { padding: 56px 60px; }
}

/* ── Choice-card GRID (§1.10) ──────────────────────────────────────────────────
   The CARD is the gem's `.os-option-card` (+ `__icon` / `__body` / `__title` /
   `__desc` / `__price` / `--selected`) — the local `.hos-gp-choice*` family was a
   straight duplicate of it and was deleted in the tasks/071 sweep. What survives
   here is only the portal's own LAYOUT (a 2-up grid on the request/guest-type
   forms) plus the no-JS self-selecting radio variant, neither of which the gem
   ships. The stacking margin the gem gives consecutive cards is neutralised
   inside the grid, which owns the gap.
   GEM GAP (raised for upstream): `.os-option-card` has no `:has(:checked)`
   self-selecting form, so a <label>-wrapped native radio cannot show selection
   without JS or a server round-trip. Until it lands, the rule below is local. */
.hos-gp-choicegrid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
.hos-gp-choicegrid--1 { grid-template-columns: 1fr; }
@media (max-width: 560px) { .hos-gp-choicegrid { grid-template-columns: 1fr; } }
.hos-gp-choicegrid .os-option-card + .os-option-card { margin-top: 0; }

/* Visually-hidden native radio + the selection it drives (no JS). */
.hos-gp-choice__radio { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; pointer-events: none; }
.os-option-card:has(.hos-gp-choice__radio:checked) { border-color: var(--accent); background: var(--accent-soft); }
.os-option-card:has(.hos-gp-choice__radio:checked) .os-option-card__icon { background: var(--surface); color: var(--accent); }
.os-option-card:has(.hos-gp-choice__radio:focus-visible) { outline: none; box-shadow: var(--shadow-focus); }

/* Reassurance line in a form-actions leading slot ("No charge now …"). */
.hos-gp-nocharge { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-xs);
  color: var(--muted); line-height: 1.4; }
.hos-gp-nocharge svg { color: var(--accent); flex: none; }

/* Full-screen form chrome shared by the portal forms (§1.9): back link, head,
   lead sentence, optional-field hint. .os-form-page (640 centered) owns width. */
/* Slim header ROW (Trip>Run .hos-run__focus pattern): eyebrow+title on the left,
   a `‹ Parent` secondary-sm back button on the right of the SAME row. */
/* ONE heading block for every portal form page — rendered through
   `guest_portal/_page_head`, never hand-copied. The rhythm and the type are the
   gem's `.os-page-hero` spec, so the portal's two heading archetypes (this one,
   and the sand hero on /flight + the arrival wizard) measure identically:

     eyebrow --text-xs  ·  eyebrow -> title 12px (--space-3)
     title -> subtitle 4px (--space-1)  ·  subtitle --text-md / --leading-md
     subtitle -> first card 32px (DESIGN.md rule 3: the gem's page-head gap)

   Before this pass they did not: the eyebrow rendered at the 10px card-micro
   size, the subtitle at --text-sm (14px) with a 20px gap to the title, and it
   sat INSIDE the <form> as a stray paragraph so the gap to the first card was
   0px on every form page. */
:is(.hos-gp-formhead, .hos-gp-pagehead) { display: flex; align-items: flex-start;
  justify-content: space-between; gap: 16px; margin-bottom: 32px; }
.hos-gp-formhead__ttl { min-width: 0; }
/* PAGE eyebrow size. `.os-eyebrow` on its own is the 10px micro-label used
   INSIDE a card ("STATUS", "ROOM"); at the top of a page it takes --text-xs,
   the same step the gem's `.os-page-hero__kicker` uses, so the portal's two
   heading archetypes measure identically. */
:is(.hos-gp-formhead, .hos-gp-pagehead) .os-eyebrow { font-size: var(--text-xs); color: var(--accent-strong); }
:is(.hos-gp-formhead, .hos-gp-pagehead) h1 { font-family: var(--font-display);
  font-size: var(--display-md); letter-spacing: -0.02em; font-weight: 600; color: var(--ink);
  margin: 0; }
:is(.hos-gp-formhead, .hos-gp-pagehead) .os-eyebrow + h1 { margin-top: var(--space-3); }
:is(.hos-gp-formhead, .hos-gp-pagehead) .hos-gp-formlead { font-size: var(--text-md);
  line-height: var(--leading-md); color: var(--muted); max-width: var(--measure);
  margin: var(--space-1) 0 0; }
.hos-gp-optional { font-weight: 400; color: var(--muted-2); }

/* Group sub-heading inside a form page (e.g. "Who's travelling"). */
.hos-gp-formgrouphead { display: flex; align-items: baseline; gap: 8px; margin: 26px 0 12px; }
.hos-gp-formgrouphead__t { font-size: var(--text-sm); font-weight: 600; color: var(--ink); }
.hos-gp-formgrouphead__n { font-size: var(--text-xs); color: var(--muted-2); }
.hos-gp-formgrouphead__d { font-size: var(--text-xs); color: var(--muted); margin: -6px 0 12px; }

/* Removable party row (§1.10): avatar + name/role + round ✕ remove. Heads an
   occupant edit card; the ✕ is a real delete button_to (round, danger on hover). */
.hos-gp-mrow { display: flex; align-items: center; gap: 12px; }
.hos-gp-mrow__b { flex: 1; min-width: 0; }
.hos-gp-mrow__t { font-size: var(--text-sm); font-weight: 600; color: var(--ink); }
.hos-gp-mrow__t span { color: var(--muted-2); font-weight: 600; }
.hos-gp-mrow__d { font-size: var(--text-xs); color: var(--muted); margin-top: 2px; }
/* composes `.os-btn os-btn--secondary os-btn--icon os-btn--sm` (32px square,
   hairline, muted glyph, focus ring); adds only the round shape + danger hover. */
.hos-gp-mrow__x { flex: none; border-radius: var(--radius-pill); }
.hos-gp-mrow__x:hover { border-color: var(--danger-border); background: var(--danger-bg); color: var(--danger); }

/* Booking form item recap (§1.11 b-detail): a compact chosen-item row at the top
   of the request form — photo + name/meta + price. Mirrors the mockup f-checkout
   thumb row. */
.hos-gp-recap { display: flex; align-items: center; gap: 14px; }
.hos-gp-recap__img { width: 60px; height: 60px; border-radius: var(--radius-md); flex: none;
  object-fit: cover; background: var(--surface-alt); }
.hos-gp-recap__ph { display: inline-flex; align-items: center; justify-content: center;
  color: var(--on-accent); background: linear-gradient(135deg, var(--accent), var(--accent-strong)); }
.hos-gp-recap__b { flex: 1; min-width: 0; }
.hos-gp-recap__t { font-size: var(--text-sm); font-weight: 600; color: var(--ink); }
.hos-gp-recap__d { font-size: var(--text-xs); color: var(--muted); margin-top: 2px; }
.hos-gp-recap__price { font-family: var(--font-mono); font-size: var(--text-sm);
  font-weight: 600; color: var(--ink); flex: none; white-space: nowrap; }

/* Party stepper (§1.10 p-step-ct): round − / mono count / + writing a real
   number input. No-JS fallback = the input stays a usable number field. */
.hos-gp-stepper { display: inline-flex; align-items: center; gap: 10px; }
.hos-gp-stepper__btn { width: 36px; height: 36px; border-radius: var(--radius-pill); flex: none;
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  border: 1px solid var(--hairline); background: var(--surface); color: var(--ink); }
.hos-gp-stepper__btn:hover { border-color: var(--accent); color: var(--accent); }
.hos-gp-stepper__btn:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
.hos-gp-stepper__n { width: 56px; text-align: center; font-family: var(--font-mono);
  font-size: var(--text-base); font-weight: 600; color: var(--ink);
  border: 1px solid var(--hairline); border-radius: var(--radius-md); height: 36px;
  background: var(--surface); -moz-appearance: textfield; appearance: textfield; }
.hos-gp-stepper__n::-webkit-outer-spin-button, .hos-gp-stepper__n::-webkit-inner-spin-button {
  -webkit-appearance: none; margin: 0; }
.hos-gp-stepper__n:focus-visible { outline: none; box-shadow: var(--shadow-focus); }

/* The `.gpw-*` arrival-wizard family was retired by tasks/069: the wizard now
   renders in `.os-workpage` / `.os-status-card` / `.os-progress-spine` /
   `.os-option-card` / `.os-callout`. Its 64 selectors had zero callsites and were
   deleted in the tasks/071 conformance sweep — do not reintroduce them. */

/* ── Unpriced transfer fare (tasks/144) ──────────────────────────────────────
   A fare the operator has not set in Settings → Transport renders as words
   ("Fare confirmed by the resort"), not "$0.00" — which reads as free. Words in
   the accent-coloured 600 weight the gem gives a real figure would shout; this
   is the gem's own de-emphasis concept for a notional figure (`.os-figure--muted`,
   `.os-avatar--muted`) applied to the price slot. Right-alignment and the slot
   itself are inherited, so a mixed list still lines up. */
.os-option-card__price--muted,
.hos-gp-recap__price--muted {
  font-family: var(--font-sans);
  font-weight: 400;
  color: var(--muted);
  white-space: normal;
  max-width: 11ch;      /* wraps to two short lines rather than crowding the title */
  line-height: var(--leading-sm);
}

/* ── Speedboat slot cards (tasks/144) ────────────────────────────────────────
   Two tiers live in `guest_portal/transfers/_slot_list`: a materialised boat
   (named, real seat count) and a timetable crossing (no boat yet). The card is
   the gem's `.os-option-card`; these add only the data treatment and the narrow
   reflow. */
.hos-gp-slot__time,
.hos-gp-slot__seats {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;   /* times + counts must align down the list */
}
.hos-gp-slot__time { font-weight: 600; }

/* DESIGN.md "responsive icon-led rows": placement is WIDTH-driven. On a narrow
   viewport the fare drops to its own line under the title instead of crushing it
   — never a chevron-only collapse, the fare has to stay readable. */
@media (max-width: 860px) {
  .hos-gp-slot { flex-wrap: wrap; }
  /* The icon tile stays on the title's line; only the fare wraps. Basis must be
     0, not auto: with flex-wrap the browser wraps an item BEFORE it shrinks it,
     so a content-sized basis pushes the body under the icon. */
  .hos-gp-slot .os-option-card__body { flex: 1 1 0; min-width: 0; }
  .hos-gp-slot .os-option-card__price {
    margin-left: calc(38px + var(--space-3));   /* aligns under the title, past the icon tile */
    text-align: left;
    flex-basis: 100%;
    padding-top: 2px;
  }
  .hos-gp-slot .os-option-card__price--muted { max-width: none; }
}

/* No crossings at all for their day. An empty state is a feature: say which day,
   say what happens next, and leave the boat-TBD request reachable above. */
.hos-gp-slots-empty {
  border: 1px dashed var(--hairline-strong);
  border-radius: var(--radius);
  background: var(--surface);
  padding: var(--space-5) var(--space-4);
  text-align: center;
}
.hos-gp-slots-empty__t { font-weight: 600; color: var(--ink); }
.hos-gp-slots-empty__d {
  margin-top: 4px;
  color: var(--muted);
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
  max-width: 44ch;
  margin-inline: auto;
}

/* Onward connection date + time (tasks/144 Slice E). Two fields that are one
   answer, so they sit side by side and stack only when there isn't room. */
.hos-gp-onward-when { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.hos-gp-onward-when > * { flex: 1 1 10rem; min-width: 0; }
