/* ─── HotelOS guest surfaces — the LOCAL ~10% (tasks/069) ────────────────────
   The guest arrival surfaces are built almost entirely from shared components
   (`.os-workpage`, `.os-page-hero`, `.os-status-card`, `.os-progress-spine`,
   `.os-section-head`, `.os-card`, `.os-desclist`, …). This sheet adds ONLY the
   two things those components cannot own:

     1. `.hos-page-hero--guest` — the AUDIENCE HUE. Guest surfaces wear a warm
        sand hero; staff operational tools stay cool teal. The hero component is
        deliberately neutral, so the tint (and the warm-on-warm header-local
        neutrals that stop cool slate sitting on a warm ground) is a product
        modifier. Tokens: `--sand-*` in hotelos_ds/tokens.css.

     2. `.hos-arrival-page` — PAGE-LEVEL GEOMETRY. The float of the first main
        card + the first rail card up onto the hero is an arrangement of two
        components relative to a third; no single component can express it.
        Same for pinning the workpage footer to the viewport bottom.

   No new component families. Every visual inside is a shared `.os-*` class.
   Token-only, light-only, no raw hex.
   ────────────────────────────────────────────────────────────────────────── */

/* ── 0 · Shared geometry constants ───────────────────────────────────────────
   The hero and the action bar are both full-bleed bands and MUST bleed the same
   distance, or the tinted block renders a different width from the bar beneath
   it. Declared once here rather than repeated per rule: they were briefly a
   scoped variable on the hero plus a hardcoded 68px on the footer, which is the
   shape of a bug — change one and the two silently drift apart.
   ────────────────────────────────────────────────────────────────────────── */
:root {
  --hos-gutter: 28px;      /* fallback — see the shell-token derivation below */
  --hos-page-inset: 40px;  /* the design's own inner inset (mockup floatwrap) */
  --hos-page-max: 1080px;  /* fallback — see the shell-token derivation below */
  --hos-body-pad-top: 26px; /* = .hos-gp-body padding-top (inline in guest_v2) */
  --hos-body-pad-bottom: 44px; /* = .hos-gp-body padding-bottom (inline in guest_v2) */
  /* Extra inset applied to the HERO's content only, so the kicker/title line up
     with the floating cards that ride up onto the band. The reg card's panels
     have no such inset, so it zeroes this — see `.hos-regcard`. */
  --hos-hero-inset: var(--hos-page-inset);
}

/* DERIVE the band geometry from the SHELL INSET CONTRACT (tasks/073 A3 /
   tasks/074 G1) instead of keeping a second copy of the numbers. Every shell
   publishes `--gutter` and `--page-max` on its content pane (`.hos-gp-body` in
   the guest shell, `.hos-shell-content` in the staff shell); inside the guest
   pane these bands now READ that token, so the 28px/16px inset has exactly one
   source of truth and the "change one and the two silently drift apart" failure
   this block was written to prevent can no longer happen at all.

   It stays SCOPED to `.hos-gp-body`. The staff shell keeps the `:root` 28px
   above on purpose: `.hos-regcard` runs in the 48px staff pane and reclaims the
   difference deliberately (see gr_card.css) — pointing it at 48px here would
   double that correction. Same pixels as before, one owner instead of two. */
.hos-gp-body {
  --hos-gutter: var(--gutter, 28px);
  --hos-page-max: var(--page-max, 1080px);
}

/* The page inset (the design's own inner inset) and the body pad still narrow at
   the shell's own breakpoint — mirror it. `--hos-gutter` no longer needs a
   mobile value here: it tracks `--gutter`, which the shell already narrows. */

/* ── 0b · THE ONE GUEST-PORTAL PAGE INSET (tasks/074 G1) ─────────────────────
   The portal grew two page archetypes with two different left edges:

     hero pages   (/flight, /transfers, /arrival)  .hos-*-page → +40px inset
     plain pages  (/g/, /folio, /requests, /book, /dining, /profile, …)  nothing

   So a guest walking the nav saw the content column jump 40px sideways between
   Dashboard and Transfers — the "padding-x is a site-wide issue, needs a sweep
   and enforcement" finding. It is not a per-page bug; it is a missing contract.

   `.hos-gp-page` IS that contract: the single wrapper every plain portal page
   puts its content in, carrying the SAME `--hos-page-inset` the hero pages
   already use. Content then starts on one edge portal-wide, and it is the edge
   the reference page (/transfers) established.

   Not merged into `.hos-gp-body`: that is the SHELL's column (layouts/guest_v2)
   and the shell's inset/max-width contract is owned elsewhere. This wrapper is
   page-level, which is what the pages themselves own.

   Hero pages keep their own `.hos-*-page` wrappers — they add a negative
   margin-top to float onto the band, which a plain page must not have. Both
   read the same token, so the two can no longer drift.
   ────────────────────────────────────────────────────────────────────────── */
.hos-gp-page {
  padding-inline: var(--hos-page-inset);
}

/* The shell narrows its own gutter at 860px (.hos-gp-body padding 26px 28px 44px
   -> 18px 16px 40px, declared INLINE in layouts/guest_v2, which is why it does
   not grep). The bands must bleed exactly that much or they overhang the
   viewport — at 28px on a 375px phone the hero ran -12 -> 387. Mirror the
   shell's breakpoint and value, and shrink the page inset to the mockup's
   mobile figure while we're here. */
@media (max-width: 860px) {
  :root {
    --hos-gutter: 16px;
    --hos-page-inset: 14px;
    --hos-body-pad-top: 18px;
    --hos-body-pad-bottom: 40px;
  }
}

/* ── 1 · Sand hue (guest audience cue) ───────────────────────────────────── */

.os-page-hero.hos-page-hero--guest {
  background: var(--sand);
}

.hos-page-hero--guest .os-page-hero__kicker {
  color: var(--accent-strong);
}

/* Colour only. The font-weight restatement that used to live here is GONE
   (2026-07-26): it existed because hotelos_ds/base's `.hos-ds h1,…h6` was
   (0,1,1) and beat the gem's `.os-page-hero__title` (0,1,0), silently forcing
   every hero title to 600. The systemic fix has landed — base.css now reads
   `:where(.hos-ds) h1,…` (0,0,1), so the element layer can no longer outrank
   a component class. Re-measured after removal: the title still computes 700. */
.hos-page-hero--guest .os-page-hero__title {
  color: var(--sand-ink);
}

.hos-page-hero--guest .os-page-hero__sub {
  color: var(--sand-muted);
}

/* STATIC CONTENT MUST NOT LOOK INTERACTIVE (tasks/074 G4).
   The gem draws `.os-page-hero__fact` as a filled, hairlined, rounded chip.
   On a guest hero that is a lie: these facts are a read-only summary — "45 min
   crossing", "Flight — not added" — and every OTHER rounded-and-filled thing on
   these pages (`.os-option-card`, `.os-btn`, the entity tabs) IS tappable. The
   owner read them as controls and tried to press them.

   So on the guest hero a fact is a READOUT, not a chip: no fill, no border, no
   pill radius. Label in the warm muted, value in the warm ink, and a thin warm
   rule between facts to keep them legible as separate items. Nothing here is
   round, filled or raised, so nothing here invites a tap.

   Scoped to `.hos-page-hero--guest` on purpose — a staff hero's facts are
   untouched. */
.hos-page-hero--guest .os-page-hero__facts {
  gap: 0;
  row-gap: var(--space-2);
}

.hos-page-hero--guest .os-page-hero__fact {
  padding: 0 var(--space-4);
  border: 0;
  border-left: 1px solid var(--sand-hairline);
  border-radius: 0;
  background: none;
  color: var(--sand-label);
  font-weight: 500;
}

.hos-page-hero--guest .os-page-hero__fact:first-child {
  padding-left: 0;
  border-left: 0;
}

.hos-page-hero--guest .os-page-hero__fact-value {
  color: var(--sand-ink);
  font-weight: 600;
}

/* Phone: the rules read as clutter once the row wraps — stack to a plain list. */
@media (max-width: 640px) {
  .hos-page-hero--guest .os-page-hero__facts {
    flex-direction: column;
    align-items: flex-start;
  }

  .hos-page-hero--guest .os-page-hero__fact {
    padding-left: 0;
    border-left: 0;
  }
}

.hos-page-hero--guest .hos-entity-tabs {
  margin-top: var(--space-5);
}

.hos-page-hero--guest .hos-entity-tabs__group-label {
  color: var(--sand-label);
}

.hos-page-hero--guest .hos-entity-tabs__tab {
  border-color: var(--sand-hairline);
  color: var(--sand-muted);
}

.hos-page-hero--guest .hos-entity-tabs__tab.is-active {
  border-color: var(--accent);
  color: var(--accent-strong);
}

/* Phone: ONE scrolling row, not a wrapped block. `.hos-entity-tabs` and its
   `__tabs` both `flex-wrap: wrap`, so a four-guest party stacked into two rows
   and pushed the whole card down. A switcher is a single axis of choice and
   should read as one — overflow horizontally instead.

   INSET SCROLLER. The scroll BOX bleeds to both screen edges (negative margin)
   while its CONTENT starts at the gutter (matching padding) — so at rest the
   room label and first tab align with the title, and once you scroll, tabs run
   right off the edge instead of stopping short at an invisible wall.
   `scroll-padding-inline` keeps that inset for programmatic scrolls too (focus,
   scrollIntoView), so tabbing to a control never parks it under the edge.
   NO scroll-snap: `scroll-snap-align` makes the browser scroll the active tab
   into view on load, which consumes exactly the left padding (scrollLeft lands
   at the gutter width) and drops the label and first tab flush against the
   screen. The snap cue is not worth a broken starting edge. */
/* Breakpoint is the SHELL's own (860px), not 720: that is where the sidebar
   hides and the pane becomes the viewport, and a five/six-guest party overflows
   well before 720. Below it the switcher is always a scroller, so it can never
   be the thing that wraps into a second row again. */
@media (max-width: 860px) {
  .hos-page-hero--guest .hos-entity-tabs,
  .hos-page-hero--guest .hos-entity-tabs__tabs {
    flex-wrap: nowrap;
  }

  .hos-page-hero--guest .hos-entity-tabs {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* BLEED TO THE PANE, NOT TO THE GUTTER (tasks/075 F5).
       The scroll BOX must reach both pane edges or the last pill is cut in half
       against an invisible wall: measured at 390px the box ran 14 -> 376 inside
       a 0 -> 390 pane, so the 4th pill was clipped at 376 with 14px of empty
       hero either side of it. It reclaimed only `--hos-gutter` (16px) while the
       hero's content inset is `--hos-bleed-edge + --hos-hero-inset` (16 + 14),
       i.e. the same "two parallel bleed implementations" trap this file already
       warns about two blocks down. It now reads the HERO's own pair, so the box
       spans the pane exactly and its CONTENT re-insets to the title's edge —
       first and last pill land on the reading column, everything between it
       scrolls off the real edge. `scroll-padding-inline` keeps that inset for
       programmatic scrolls (focus / scrollIntoView) too.
       Fallbacks cover `.hos-regcard`, which sets `--hos-rc-*` and zeroes the
       hero inset. NO scroll-snap — see the note above. */
    --hos-tabs-inset: calc(
      var(--hos-bleed-edge, var(--hos-rc-gutter, var(--hos-gutter))) +
      var(--hos-hero-inset, 0px)
    );

    margin-inline: calc(-1 * var(--hos-tabs-inset));
    padding-inline: var(--hos-tabs-inset);
    scroll-padding-inline: var(--hos-tabs-inset);
  }

  .hos-page-hero--guest .hos-entity-tabs::-webkit-scrollbar {
    display: none;
  }

  /* Tabs must keep their intrinsic width — in a nowrap flex row they would
     otherwise be squeezed to fit and the labels would clip. */
  .hos-page-hero--guest .hos-entity-tabs__tab {
    flex: none;
  }

  /* The room group is a column (label over tabs); it must not be compressed
     either, or a multi-room party collapses its groups into each other. */
  .hos-page-hero--guest .hos-entity-tabs__group {
    flex: none;
  }
}

/* ── 2 · Arrival page geometry ───────────────────────────────────────────── */

/* FULL-BLEED SAND — ONE contract, both shells.
   The sand is a BAND: it runs the full width of its pane and the content column
   floats on top of it. Reclaiming only the shell's gutter (the previous
   `margin-inline: -28px`) stopped the band at the reading column's edge, so it
   read as an inset floating panel that began from nowhere instead of a band.

   Bleeds off the pane's container query and re-insets content to the same
   centred column the rest of the page uses, so hero text stays aligned with the
   form below. `max()` collapses the re-inset to a single gutter once the
   viewport is narrower than the column.

   Both shells declare `container-type: inline-size` on their pane —
   `.hos-shell-main` (staff) and `.hos-gp-main` (guest, in layouts/guest_v2) — so
   `cqw` resolves to the pane width, EXCLUDING the sidebar. Viewport units would
   be wrong here: they'd include the sidebar and overhang by its width.

   Per-shell numbers arrive as variables rather than a second copy of this rule.
   The reg card sets the `--hos-rc-*` pair; everything else falls back to the
   guest-shell `:root` values. Two parallel bleed implementations is exactly how
   the action bar drifted 20px narrower than the hero. */
.hos-page-hero--guest {
  --hos-bleed-gutter: var(--hos-rc-gutter, var(--hos-gutter));
  --hos-bleed-max: var(--hos-rc-page-max, var(--hos-page-max));
  --hos-bleed-edge: max(
    var(--hos-bleed-gutter),
    calc(50cqw - var(--hos-bleed-max) / 2 + var(--hos-bleed-gutter))
  );

  width: 100cqw;
  margin-inline: calc(50% - 50cqw);
  padding-inline: calc(var(--hos-bleed-edge) + var(--hos-hero-inset, 0px));
  /* a band that spans the pane has no corners to round */
  border-radius: 0;
}

/* …and it must butt the shell's top bar, not float below a strip of canvas.
   `.hos-gp-body` pads 26px on top (18px ≤860px, declared inline in guest_v2); left
   alone, the band starts from nowhere — the same defect the reg card had under
   the staff header. Scoped to `:first-child` on purpose: when a flash notice
   renders above the hero it SHOULD push the band down rather than slide under
   the bar. The staff shell needs no equivalent — `.os-page-head` already
   cancels its own top padding there. */
.hos-gp-body > .hos-page-hero--guest:first-child {
  margin-top: calc(-1 * var(--hos-body-pad-top));
}

/* The whole work page rides UP onto the hero's generous bottom padding, and is
   inset from the hero's edge so the sand shows around the floating cards (the
   signature). Mockup: floatwrap padding 0 40px, margin-top -56px. */
.hos-arrival-page {
  position: relative;
  z-index: 2;
  margin-top: -56px;
  padding-inline: var(--hos-page-inset);
}

/* Rail matches the front-office rail width the archetype was ported from.
   MUST stay inside the min-width query. The gem collapses the grid to `1fr` at
   max-width:1100px with `.os-workpage` (0,1,0); an unscoped override here is
   (0,2,0) and so wins at EVERY width — which pinned the grid two-column on a
   phone, collapsed the work column to 0px and pushed the 336px rail off-screen
   (scrollWidth 416 on a 375 viewport). Media queries add no specificity, so the
   only safe way to widen a gem grid is to scope the override to the breakpoint
   where it applies. */
@media (min-width: 1101px) {
  .hos-arrival-page > .os-workpage,
  .hos-transfers-page > .os-workpage {
    grid-template-columns: 1fr 336px;
  }
}

/* READ-ONLY RAIL SURFACE — shared by every guest work page, not just arrival.
   The CARD carries the tint and the desclist sits flush and transparent inside
   it. Shipping it the other way round — a white card PADDING a tinted --panel —
   makes every row read as a chip floating in a card instead of one calm passive
   surface. os-ds v1.4.2 documents the same rule on --panel ("--panel IS the
   surface, do not nest it inside .os-card__body").
   Scoped to both pages deliberately: transfers was built using arrival as its
   reference and inherited the inverted markup, so an arrival-only selector left
   it broken. Zeroing __body padding fixes it whether or not the callsite wraps
   the list, so neither markup shape can reintroduce the inset. */
.hos-arrival-page .os-workpage__rail > .os-card,
.hos-transfers-page .os-workpage__rail > .os-card {
  background: var(--surface-alt);
}

.hos-arrival-page .os-workpage__rail > .os-card > .os-card__body,
.hos-transfers-page .os-workpage__rail > .os-card > .os-card__body {
  padding: 0;
}

.hos-arrival-page .os-workpage__rail .os-desclist--panel,
.hos-transfers-page .os-workpage__rail .os-desclist--panel {
  background: transparent;
  border-radius: 0;
}

/* Two elevation levels, no more: the cards that OVERLAP the hero lift, and the
   sticky footer lifts off the page beneath it. Everything else is flat + a
   hairline. Scoped by position, so no card needs an elevation class. */
.hos-arrival-page > .os-workpage > .os-workpage__main > .os-status-card,
.hos-arrival-page > .os-workpage > .os-workpage__rail > .os-card:first-child {
  box-shadow: var(--elevation-overlay);
}

/* ── THE STEP-BODY FRAME (tasks/075 F6) ──────────────────────────────────────
   The step content used to sit loose on the canvas as a stack of separate white
   section cards. The reference the owner named is `/book/speedboat`: the tinted
   band runs full width and the WORK sits in one white panel floating on it. So
   the body gets one container — and the hero, the party switcher and the
   readiness card stay outside it, because they are chrome above the body, not
   the body.

   Not a new component family: it is a page-level ARRANGEMENT, the same kind of
   thing `.hos-arrival-page` already owns (the float onto the hero, the sticky
   bar). The gem has no "frame the whole step body" component to reuse — `.os-card`
   is a content card with its own head/body slots and a --radius-lg, `.os-sheet`
   is a mobile bottom sheet, `.os-workpage__main` is a bare flex column. Logged as
   a gem gap rather than dressed up as one of those.

   --shadow-sm, deliberately: --shadow-card adds a second hairline ring on top of
   the border, and --elevation-overlay is reserved on these pages for the two
   things that OVERLAP the hero. */
.hos-arrival-frame {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-sm);
}

/* EXACTLY ONE FILLED BOX (DESIGN.md G5). The frame is now the surface, so every
   section inside it drops its own fill, border, radius and shadow and becomes a
   hairline-divided block. Written as "unset the card, keep the padding" rather
   than as a new flat variant, so the section markup is untouched and a section
   moved off this page still draws its own card. */
.hos-arrival-frame :is(.os-form-section, .os-card) {
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  margin-bottom: 0;
}

.hos-arrival-frame .os-form-section {
  padding: 22px 24px 24px;
}

.hos-arrival-frame .os-card > .os-card__body {
  padding: 22px 24px 24px;
}

/* The blocks butt each other, so the gap that separated the free-standing cards
   has to go or the hairline floats in dead space. The step partials nest their
   own `.os-workpage__main` (a flex column with a --space-8 gap) inside the frame. */
.hos-arrival-frame .os-workpage__main {
  gap: 0;
}

.hos-arrival-frame :is(.os-form-section, .os-card) + :is(.os-form-section, .os-card),
.hos-arrival-frame .os-workpage__main + :is(.os-form-section, .os-card),
.hos-arrival-frame form + section {
  border-top: 1px solid var(--hairline);
}

/* Anything that is NOT a section (the passport-scan callouts, which sit outside
   the profile form) still needs the frame's inset — the frame itself has none so
   the sections can run edge to edge and their dividers span the full width. */
.hos-arrival-frame > .os-callout,
.hos-arrival-frame > div[hidden] + .os-callout {
  margin: 22px 24px;
}

@media (max-width: 640px) {
  .hos-arrival-frame .os-form-section {
    padding: 18px 16px 20px;
  }

  .hos-arrival-frame .os-card > .os-card__body {
    padding: 18px 16px 20px;
  }

  .hos-arrival-frame > .os-callout {
    margin: 18px 16px;
  }
}

/* Spine steps are links; strip the anchor chrome the component assumes away. */
.hos-arrival-page .os-progress-spine__step {
  text-decoration: none;
  color: inherit;
}

/* CHIP-INPUT PARITY. `list_field` renders an `.os-input` textarea inside
   [data-chip-input]; shared/_chip_input_js enhances it into a `.hos-chipbox`
   (the textarea survives as the no-JS fallback + source of truth, but computes
   height:0). The enhanced widget must therefore be INDISTINGUISHABLE from a
   plain `.os-input` at rest, or the Preferences fields read as a different kind
   of control from every other field on the page. Same bg/border/radius/padding
   and the same control height an `.os-input` resolves to on this theme (44px —
   the gem's 2.25rem base plus the HotelOS step). Scoped to the guest work pages
   so no other surface's chipbox shifts under a parallel edit. */
.hos-arrival-page .hos-chipbox,
.hos-transfers-page .hos-chipbox {
  box-sizing: border-box;
  min-height: 2.75rem;
  padding: 6px 8px;
  background: var(--input-bg);
  border: 1px solid var(--input-border);
  border-radius: var(--radius-sm);
}

.hos-arrival-page .hos-chipbox:hover,
.hos-transfers-page .hos-chipbox:hover {
  border-color: var(--input-border-hover);
}

/* PHONE FIELD. Two controls (dial-code select + national number) on one row.
   `phone_field` used to hardcode an inline `minmax(130px,42%) 1fr` grid, which
   on a 375px phone (single-column field grid, ~230px of usable width) could not
   fit 130px + a number field and overflowed. Flex with real bases lets the pair
   reflow onto two lines instead. NEW class (HotelOS-local); its long-term home
   is hotelos_ds/components.css — parked here because that file is being edited
   concurrently. Deliberately UNSCOPED: the helper is shared with Front Office. */
.hos-phone-field {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* True 1:2 split. The grow factors are 1:2, but unequal flex-bases (130 vs 150)
   skewed the rendered widths to ~1:1.48 (dial code too wide, GitLab #138). Equal
   bases of 0 let the grow factors set the ratio exactly; the select keeps a small
   min so the "+960" dial code stays legible when the row is narrow. */
.hos-phone-field > .os-field-select { flex: 1 1 0; min-width: 88px; }
.hos-phone-field > .os-input { flex: 2 1 0; min-width: 0; }

/* Contact is a ONE-per-row block, not a 2-up grid (tasks/074). Mobile is two
   controls; in a half-width grid cell they had ~250px between them and wrapped
   onto a second line inside their own cell, stranding Email beside a hole. Given
   a full row the pair fits side by side and splits it 1:2 via the flex bases
   above — the "email on one row, code + number on the next at relative widths"
   the review asked for. */
.hos-contact-grid {
  grid-template-columns: 1fr;
}

/* …and the grid AROUND it collapses on a phone. `.os-field-grid` holds two
   columns at every width; at 375px that is 124.5px per column, which wraps
   "Country of residence" onto two lines and puts the two-control Mobile field
   beside a single-line Email — the reported "Contact fields collapse". One
   column per field below 560px; above that two columns still fit comfortably
   (≈220px each). Guest work pages only — no other surface's grid moves. */
@media (max-width: 560px) {
  .hos-arrival-page .os-field-grid,
  .hos-transfers-page .os-field-grid {
    grid-template-columns: 1fr;
  }
}

/* Trailing footnote under the rail — it explains the rail, so it needs to sit
   AWAY from the card above it rather than butting against it. `.os-meta` ships
   with no margin (it is used inline inside rows), so the spacing belongs here. */
.hos-arrival-page .os-workpage__rail > .os-meta,
.hos-transfers-page .os-workpage__rail > .os-meta {
  display: block;
  margin-top: var(--space-3);
}

/* The leg sub-switch sits above the step's copy, not against it. */
.hos-arrival-page .os-segmented {
  margin-bottom: var(--space-4);
}

/* ── FULL-BLEED STICKY ACTION BAR (tasks/074) ────────────────────────────────
   Two defects, one root cause each.

   1. NOT FULL BLEED. The bar bled `--hos-gutter + --hos-page-inset` off the
      1080px reading column — 1136px of bar in a 1200px pane, so canvas showed
      down BOTH sides and it read as a wide card, not a bar. The hero on the same
      page spans the whole pane. This file already warned that "two parallel
      bleed implementations is exactly how the action bar drifted 20px narrower
      than the hero" — so the bar now uses the HERO'S recipe verbatim
      (`--hos-bleed-edge`, `100cqw`, `50% - 50cqw`) instead of a second one.
      Content re-insets to the same edge, so the status line and the buttons land
      on the hero's text column: full-bleed band, max-width-constrained content.

   2. NOT ACTUALLY AT THE BOTTOM. `position: sticky` bottoms out against its
      containing block, and the shell's `.hos-gp-body` pads 44px underneath it —
      so at the end of the scroll the bar lifted 44px off the viewport floor
      ("it comes up a bit from the bottom"). The page reclaims that padding with
      a matching negative bottom margin; the bar then sticks to the real bottom.
      `--hos-body-pad-bottom` mirrors the shell's value the same way
      `--hos-body-pad-top` already does.
   ────────────────────────────────────────────────────────────────────────── */
.hos-arrival-page,
.hos-flightpage {
  margin-bottom: calc(-1 * var(--hos-body-pad-bottom));
}

/* 3. NOT AT THE BOTTOM ON A SHORT PAGE — the defect `position: sticky` cannot
      fix on its own. Sticky only ever pulls an element UP into view; it never
      pushes one DOWN past its static position. So on a page whose content is
      shorter than the pane (`/flight/edit` ended 225px above the floor,
      `/departure/edit` 133px, `/flight` 8px) the bar simply sat at the end of
      the content column with canvas below it — floating in the middle of the
      viewport. It looked correct on the arrival steps only because their
      content happens to overflow.

      The fix is a HEIGHT chain, not another sticky trick: the shell body
      becomes a flex column, the page wrapper takes the leftover height, and
      the work-page grid gets an explicit `1fr auto` — work row grows, footer
      row stays its own height and lands on the floor. Long pages are untouched
      (the grid is already taller than the pane, `1fr` resolves to content) and
      the sticky rule above keeps the bar in view while they scroll.

      Applied to the SHELL, not to one page class, on purpose: every guest work
      page carrying an action bar inherits it, so the next one cannot ship with
      the bar floating again. */
.hos-gp-body {
  display: flex;
  flex-direction: column;
}

.hos-gp-body > .hos-arrival-page,
.hos-gp-body > .hos-flightpage,
.hos-gp-body > .hos-transfers-page {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

.hos-gp-body > .hos-arrival-page > .os-workpage,
.hos-gp-body > .hos-flightpage > .os-workpage,
.hos-gp-body > .hos-transfers-page > .os-workpage {
  flex: 1 1 auto;
  /* Row 1 = work column + rail, row 2 = the footer. `align-items: start` (gem)
     keeps the cards from stretching into the extra space. */
  grid-template-rows: 1fr auto;
}

/* ── The SAME bar on the `.os-form-page` archetype ────────────────────────────
   `/requests/new`, `/dining/new`, `/bookings/new`, `/transfers/new` carry a
   page-level `.os-form-actions` row that was plain in-flow: it landed 139px
   above the floor on a short page, i.e. the identical defect the work pages
   had, wearing a different class. They get the same height chain and the same
   full-bleed sticky recipe, so ONE bar behaviour exists across the portal.

   Marked with `.hos-gp-formbar` at the callsite rather than selected
   structurally: `/profile/edit` renders FOUR `.os-form-actions` rows (one per
   occupant form) and has no single page-level bar, so it is deliberately left
   in flow — see the note at the end of this block. */
.hos-gp-body > .os-form-page:has(> .os-form > .hos-gp-formbar) {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  margin-bottom: calc(-1 * var(--hos-body-pad-bottom));
}

.hos-gp-body > .os-form-page > .os-form:has(> .hos-gp-formbar) {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

.hos-gp-formbar {
  --hos-bleed-edge: max(
    var(--hos-gutter),
    calc(50cqw - var(--hos-page-max) / 2 + var(--hos-gutter))
  );

  /* pushed to the floor of the form column when the content is short */
  margin-top: auto;
  position: sticky;
  bottom: 0;
  z-index: 20;
  flex-wrap: wrap;
  gap: var(--space-3);
  width: 100cqw;
  margin-inline: calc(50% - 50cqw);
  margin-bottom: 0;
  padding: var(--space-3) calc(var(--hos-bleed-edge) + var(--hos-page-inset));
  background: var(--surface);
  border-top: 1px solid var(--hairline);
  box-shadow: var(--elevation-overlay);
}

/* The bar sits OUTSIDE the field column even though it is inside the <form>,
   so it needs the form's control density declared on itself — same reason and
   same trio as the work-page footer above. */
.hos-gp-formbar {
  --control-h: var(--control-h-field);
  --control-pad-x: var(--control-pad-x-field);
  --control-fs: var(--control-fs-field);
}

.hos-gp-formbar .os-btn {
  min-height: var(--control-h);
}

/* Its content re-insets to the reading column, and the leading note claims the
   left so the CTA pair stays bottom-right (the work-page footer's rhythm). */
.hos-gp-formbar > .os-form-actions__leading {
  flex: 1 1 auto;
  min-width: 0;
}

@media (max-width: 720px) {
  .hos-gp-formbar {
    /* clear the fixed bottom tab bar, exactly as the work-page footer does */
    bottom: var(--hos-gp-tabbar-h, 74px);
  }

  .hos-gp-formbar > .os-form-actions__leading {
    flex: 1 0 100%;
  }

  .hos-gp-formbar .os-btn {
    flex: 1 1 0;
    min-width: 0;
    width: 100%;
    min-height: 44px;
  }
}

.hos-arrival-page .os-workpage__footer,
.hos-flightpage .os-workpage__footer {
  --hos-bleed-edge: max(
    var(--hos-gutter),
    calc(50cqw - var(--hos-page-max) / 2 + var(--hos-gutter))
  );

  position: sticky;
  bottom: 0;
  z-index: 20;
  flex-wrap: wrap;
  gap: var(--space-3);
  width: 100cqw;
  margin: var(--space-5) calc(50% - 50cqw) 0;
  padding: var(--space-3) calc(var(--hos-bleed-edge) + var(--hos-page-inset));
  background: var(--surface);
  border-top: 1px solid var(--hairline);
  box-shadow: var(--elevation-overlay);
}

/* THE BAR BELONGS TO THE FORM EVEN THOUGH IT CANNOT BE INSIDE IT (tasks/075 F1).
   Same defect, same fix as `.hos-wz-foot` (components/new_reservation.css): the
   footer is pinned to the pane, so it sits OUTSIDE the <form> and the
   form-scoped field density in hotelos_ds/tokens.css never reaches it. Its
   buttons therefore fell back to the button rung while the fields above them
   sat on the field rung. Declaring the trio ON THE BAR puts every control in it
   on the form's rung — the whole point of the rung being a token and not a
   literal. The explicit min-height is needed because the guest shell publishes
   a 44px touch floor at `.hos-gp .os-btn` (0,2,0), which outranks the gem's own
   `min-height: var(--control-h)` (0,1,0); this selector is (0,3,0) so the field
   rung wins back. */
.hos-arrival-page .os-workpage__footer,
.hos-flightpage .os-workpage__footer {
  --control-h: var(--control-h-field);
  --control-pad-x: var(--control-pad-x-field);
  --control-fs: var(--control-fs-field);
}

.hos-arrival-page .os-workpage__footer .os-btn,
.hos-flightpage .os-workpage__footer .os-btn {
  min-height: var(--control-h);
}

/* The CTA group: bottom-right, primary rightmost. */
.hos-arrival-page .os-workpage__footer > form,
.hos-arrival-page .os-workpage__footer > .os-btn {
  flex: none;
}

.hos-arrival-page .os-workpage__footer > :nth-last-child(2) {
  margin-left: auto;
}

@media (max-width: 720px) {
  .hos-arrival-page {
    margin-top: -40px;
  }

  /* Footer wraps into TWO bands: the status line claims its own full-width row,
     then the CTAs stay SIDE BY SIDE beneath it. Stacking them vertically (the
     previous column-reverse) cost ~44px of an already short phone viewport for
     no benefit — a sticky bar should be as short as it can be. DOM order is
     preserved, so the single primary remains rightmost and the secondaries sit
     left of it, exactly as on desktop.
     Inline margin/padding are deliberately NOT restated here — they are already
     derived from --hos-gutter/--hos-page-inset, which are responsive. Pinning
     them to --space-4 landed the bar at 14->361 while the hero ran 0->375, i.e.
     the exact mismatched-bands defect this pass exists to remove. */
  .hos-arrival-page .os-workpage__footer {
    align-items: center;
    padding-block: var(--space-3);
    /* Sit ABOVE the shell's fixed bottom tab bar. At bottom:0 the action bar
       docks under it (tab bar is position:fixed, z-index 40; this bar is 20),
       occluding 61px — enough to swallow the secondary action and clip the
       primary. The shell already reserves this height on .hos-gp-body, so only the
       sticky offset was missing. Fallback matches --hos-gp-tabbar-h, which is
       scoped to .hos-gp and therefore not inherited here. */
    bottom: var(--hos-gp-tabbar-h, 74px);
  }

  /* The status line takes the whole first row… */
  .hos-arrival-page .os-workpage__footer > .os-meta {
    flex: 1 0 100%;
  }

  /* …and the controls share the second one evenly. `min-width: 0` lets a long
     label shrink rather than push the bar past the viewport. */
  .hos-arrival-page .os-workpage__footer > form,
  .hos-arrival-page .os-workpage__footer > .os-btn {
    flex: 1 1 0;
    min-width: 0;
  }

  .hos-arrival-page .os-workpage__footer > :nth-last-child(2) {
    margin-left: 0;
  }

  /* Comfortable phone tap target (the desktop control height is 36px). */
  .hos-arrival-page .os-workpage__footer .os-btn {
    width: 100%;
    min-height: 44px;
  }
}

/* ─── 3 · Transfers page geometry (tasks/069) ─────────────────────────────────
   APPENDED BLOCK — self-contained, does not touch anything above.

   "Your transfers" is the same A1 work-page archetype as the arrival wizard, so
   it needs the same three page-level arrangements, and nothing else:

     1. the work page rides UP onto the sand hero's bottom padding;
     2. exactly ONE elevation — the first main card (which overlaps the hero) and
        the rail's first card carry `--elevation-overlay`; everything else is flat
        + hairline;
     3. a right-aligned action row inside a leg card body.

   `.os-card--float` does NOT exist in os-ds v1.3.0 (only --raised/--divided/
   --interactive/--selected/--overflow-visible), so the overlap shadow is applied
   the same way the already-shipped arrival page applies it: by position, from the
   page-geometry class. `.os-card--overflow-visible` (which DOES exist) is on the
   markup so the lifted card's shadow isn't clipped.

   Token-only, light-only, no raw hex.
   ────────────────────────────────────────────────────────────────────────── */

.hos-transfers-page {
  position: relative;
  z-index: 2;
  margin-top: -54px;
  /* Same inset as `.hos-arrival-page`, and for the same reason: the floating
     cards sit inside the hero's content edge so the sand shows around them (the
     signature). Without it the cards ran 40px wider than the hero's own title —
     the two surfaces are the same archetype and must inset identically. */
  padding-inline: var(--hos-page-inset);
}

.hos-transfers-page .os-workpage__main > .hos-transfers-page__float,
.hos-transfers-page > .os-workpage > .os-workpage__rail > .os-card:first-child {
  box-shadow: var(--elevation-overlay);
}

/* Cards are the page's only rhythm here — no sticky footer on this surface, so
   the leg's own action row closes the card. */
.hos-transfers-page__legfoot {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

/* Spacing between the pieces stacked inside a leg card body. */
.hos-transfers-page .os-card__body > * + .os-option-card,
.hos-transfers-page .os-card__body > * + .os-section-head,
.hos-transfers-page .os-card__body > * + .os-route,
.hos-transfers-page .os-card__body > * + .os-locked,
.hos-transfers-page .os-card__body > form + form {
  margin-top: var(--space-4);
}

.hos-transfers-page .os-card__body > .os-section-head + .os-option-card,
.hos-transfers-page .os-card__body > form > .os-option-card {
  margin-top: 0;
}

/* Option cards rendered as links / form buttons: strip the anchor + button chrome
   the component assumes away, and let a wrapping button_to form fill the width. */
.hos-transfers-page .os-option-card {
  text-decoration: none;
  color: inherit;
}

.hos-transfers-page .os-card__body > form {
  margin: var(--space-2) 0 0;
}

/* The rail's summary note sits under the definition rows, not against them. */
.hos-transfers-page .os-workpage__rail .os-meta {
  display: block;
  margin: var(--space-3) 0 0;
}

@media (max-width: 720px) {
  .hos-transfers-page {
    margin-top: -40px;
  }

  .hos-transfers-page__legfoot .os-btn {
    width: 100%;
  }

  /* Phone: the leg head stops being one row — icon + status pill sit together,
     the route gets the full width beneath them instead of wrapping mid-airport. */
  .hos-transfers-page .os-leg__head {
    flex-wrap: wrap;
  }

  .hos-transfers-page .os-leg__head > div {
    order: 2;
    flex: 1 1 100%;
    min-width: 0;
  }

  .hos-transfers-page .os-leg__status {
    order: 1;
    margin-left: auto;
  }
}

/* ── 3 · Registration-card page geometry (tasks/069) ──────────────────────── */
/* Same job as `.hos-arrival-page` above, for the A2 (summary-as-banner) case:
   arrangement of shared components relative to one another. No component
   families are minted here — every visual inside is a shared `.os-*` class. */

.hos-regcard {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* FULL-BLEED SAND, STAFF SHELL. The reg card is the one guest-hued page that
   lives in the STAFF shell, so the §2 bleed above is wrong for it: that one
   reclaims `--hos-gutter` (28px, the GUEST shell's `.hos-gp-body` padding), while
   `.hos-shell-content` pads 48px. Reclaiming 28 of 48 left a ~20px canvas
   margin down both sides, and with the hero's top radius the sand read as an
   inset floating panel rather than a band — the "starts from nowhere" look.
   Bleed to the pane edges instead, off the shell's own container query
   (`.hos-shell-main` is `container-type: inline-size`), and re-inset content to
   the same centred 1280px column the rest of the page uses. `max()` keeps the
   inset at one gutter once the viewport is narrower than the column. */
.hos-regcard {
  /* 2026-07-28 — these were the LITERALS 48px / 1280px: a private second copy
     of the shell's inset contract. The moment the page took a narrower width
     tier (--page-reading, 960px) the body and the shell head band followed it
     and these did not, so the hero title and the footer bar stayed on the 1280
     column while everything between them moved in — three left edges on one
     page. That is the four-places drift `page_inset_contract_test` exists to
     catch, wearing a `--hos-rc-` prefix so the test could not see it.
     They now READ the shell's published pair, so the hero, the body, the head
     band and the footer re-inset together at whatever tier the page picks. */
  --hos-rc-gutter: var(--gutter, 48px);
  --hos-rc-page-max: var(--page-max, 1280px);
  /* The card's panels carry no extra inset (unlike the arrival page's floating
     cards), so the hero's content sits flush with the column edge. */
  --hos-hero-inset: 0px;
}

/* The gem gives any element following `.os-page-head` a 2rem top margin. A
   full-bleed tinted band must butt the header rule instead — the canvas gap
   above it is what made the sand read as a detached floating panel.
   The gem rule is `.os-page-head + :not(a):not(b):not(c)` — each `:not()`
   contributes a class, so it lands at (0,4,0) and a plain `.hos-regcard`
   (0,1,0) loses. Hence the doubled class: (0,4,0) tying, won on load order
   (components.css loads after the gem — see CLAUDE.md load chain).
   UPSTREAM GAP: the gem's `.os-page-header` branch already exempts
   `.os-page-band` for exactly this case; the `.os-page-head` branch does not.
   Once it does, this override should be replaced by that class. */
.hos-shell-content .os-page-head + .hos-regcard.hos-regcard {
  margin-top: 0;
}

/* The narrow-viewport inset used to be restated here as 16px. It is the SHELL's
   to decide and the shell now narrows `--gutter` itself, which this reads — so
   restating it could only ever disagree with it (and did, between 860px and the
   shell's own 1100px breakpoint). */

/* Breadcrumb spacing inside the shell head band. The gem ships `.os-breadcrumb`
   margin-free on purpose — "the host owns vertical spacing" — so the host says
   so here. Scoped to `.os-page-head` (not the reg card) because the slot is
   shell-wide: the next page to set :breadcrumb inherits the same rhythm. */
.os-page-head .os-breadcrumb {
  margin-bottom: var(--space-2);
}

/* The parent crumb carries a leading back-arrow (`page_breadcrumb`), so the
   crumb itself has to be a flex line — the gem only lays out the crumb ROW.
   Scoped to the shell band for the same reason as the rule above, and to the
   PARENT crumb only: a blanket `.os-breadcrumb__crumb` rule here outranks the
   gem's <=640px collapse (`:not(--parent)` is also 0,2,0, and we lose on source
   order), which silently kept the whole trail expanded on phones with only the
   separators hidden. Every crumb trail must therefore tag its immediate parent
   `--parent`, or nothing shows below 640px. */
.os-page-head .os-breadcrumb__crumb--parent {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* The gem draws its own CSS-corner chevron on the collapsed parent crumb. Where
   the crumb already renders a real back-arrow icon (`page_breadcrumb`) that is a
   duplicate, so drop it there only — hand-rolled text crumbs keep the chevron. */
@media (max-width: 640px) {
  .os-page-head .os-breadcrumb__crumb--parent:has(svg)::before { content: none; }
}

/* Hero top line: property kicker left, the mono GR reference right. */
.hos-regcard .os-page-hero__kicker {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}

.hos-regcard .os-page-hero__kicker .os-meta--mono {
  color: var(--sand-label);
}

/* Tracker sits on the sand hero: warm track + warm label. */
.hos-page-hero--guest .os-tracker {
  margin-top: var(--space-5);
}
.hos-page-hero--guest .os-tracker__count {
  color: var(--sand-muted);
}
.hos-page-hero--guest .os-tracker__bar {
  background: var(--sand-track);
}
.hos-page-hero--guest .os-tracker__jump {
  border-color: var(--sand-hairline);
}

/* The panels ride UP onto the hero's generous bottom padding. */
.hos-regcard-page {
  position: relative;
  z-index: 2;
  margin-top: -54px;
}

/* Elevation level 2 (the only one): the folio banner overlaps the hero. */
.hos-regcard-page .os-workpage__banner > .os-card {
  background: var(--surface-alt);
  box-shadow: var(--elevation-overlay);
}

/* Folio head: avatar · name/role · status pill. */
.hos-regcard-page .os-workpage__banner .os-card__head {
  gap: var(--space-3);
  padding-bottom: var(--space-4);
}
.hos-regcard-folio__id {
  flex: 1 1 auto;
  min-width: 0;
}
.hos-regcard-folio__provenance {
  display: block;
  margin-bottom: var(--space-2);
}

/* Read-only identity ledger: a 2x2 tinted panel with hairline rules both ways. */
.hos-regcard-page .os-desclist--panel {
  grid-template-columns: 1fr 1fr;
  border: 1px solid var(--hairline);
}
.hos-regcard-page .os-desclist--panel .os-desclist__row:nth-child(2n) {
  border-left: 1px solid var(--hairline);
}
.hos-regcard-page .os-desclist--panel .os-desclist__row:nth-child(2) {
  border-top: none;
}

/* 32px between the read-only folio and the interactive sections. */
.hos-regcard-page .os-workpage--a2 {
  row-gap: var(--space-8);
}

/* Two columns of sections: travel (flight + transfer) · signature. */
.hos-regcard-page .os-workpage__main {
  display: grid;
  grid-template-columns: 1.25fr 1fr;
  gap: var(--space-6);
  align-items: start;
}

.hos-regcard-sechead--gap {
  margin-top: var(--space-6);
}

.hos-regcard-formfoot {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--space-4);
}

.hos-regcard-locked__action {
  margin-left: auto;
  flex: none;
}

/* The gate bar IS the footer's content — it spans it. */
/* The sticky action bar's geometry (full bleed, grid-column span, sticky
   chrome) is owned by gr_card.css — it loads after this file and so wins.
   Keep it in ONE place; two competing bleed definitions is how the bar ended up
   20px narrower than the hero in the first place. */
.hos-regcard-page .os-workpage__footer {
  padding-top: 0;
}

.hos-regcard-page .os-gate-bar {
  flex: 1;
  min-width: 0;
}

@media (max-width: 720px) {
  /* CTAs stay SIDE BY SIDE on a phone. The gem stacks `.os-gate-bar__actions`
     `column-reverse` under 720px, which costs ~44px of an already short
     viewport for no benefit — a sticky bar should be as short as it can be.
     Same call already made for `.hos-arrival-page` above; the reg card never
     inherited it because it renders its own footer. DOM order is preserved, so
     the primary stays rightmost exactly as on desktop. */
  .hos-regcard-page .os-gate-bar {
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
  }

  .hos-regcard-page .os-gate-bar__body {
    flex: 1 0 100%;
  }

  .hos-regcard-page .os-gate-bar__actions {
    flex-direction: row;
    align-items: center;
    width: 100%;
    gap: var(--space-2);
  }

  /* `min-width: 0` lets a long label shrink rather than push the bar past the
     viewport — "Complete check-in" is wide enough to do exactly that. */
  .hos-regcard-page .os-gate-bar__actions > * {
    flex: 1 1 0;
    min-width: 0;
  }
}

/* Signed signature: the image sits behind a "View signature" disclosure. */
.hos-regcard-sigview {
  margin-left: auto;
}
.hos-regcard-sigview > summary {
  list-style: none;
  cursor: pointer;
}
.hos-regcard-sigview > summary::-webkit-details-marker {
  display: none;
}
.hos-regcard-sigview .os-signpad__pad {
  margin-top: var(--space-2);
}
.hos-regcard-page .os-signpad--signed .os-signpad__pad img {
  max-height: 110px;
  max-width: 100%;
}

/* The shared draw/type pad fills the signature card. */
.hos-regcard-page .hos-grc-signpad .hos-grc-pad {
  width: 100%;
}

@media (max-width: 960px) {
  .hos-regcard-page .os-workpage__main {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 720px) {
  .hos-regcard-page {
    margin-top: -40px;
  }
  .hos-regcard-page .os-workpage__main {
    gap: var(--space-5);
  }
  /* Flight number + datetime stack rather than squeezing to unreadable. */
  .hos-regcard-page .os-field-grid {
    grid-template-columns: 1fr;
  }
  /* Folio head: name/role block gets its own line under the avatar row. */
  .hos-regcard-page .os-workpage__banner .os-card__head {
    flex-wrap: wrap;
  }
}

/* ─── 4 · Flight-funnel page geometry (tasks/069) ─────────────────────────────
   APPENDED BLOCK — self-contained, touches nothing above.

   `/g/:token/flight`, `/flight/edit` and `/departure/edit` are the same A1
   work-page archetype as the arrival wizard, so they need the same page-level
   arrangements and nothing else: the work page rides UP onto the sand hero, the
   rail is one flush read-only tinted surface, exactly ONE elevation (the first
   main card + the first rail card, which overlap the hero), and a sticky action
   bar carrying one primary.

   DUPLICATION, DELIBERATE: the shared rail/footer rules above list their page
   scopes explicitly (`.hos-arrival-page, .hos-transfers-page`). Adding
   `.hos-flightpage` to those selector lists is the tidier edit, but that region
   of this file is being edited concurrently by two other agents, so it is
   restated here instead. FOLLOW-UP: fold these three selectors into the shared
   lists (sections 2) once those edits land — no markup change needed.

   Token-only, light-only, no raw hex.
   ────────────────────────────────────────────────────────────────────────── */

.hos-flightpage {
  position: relative;
  z-index: 2;
  margin-top: -54px;
  padding-inline: var(--hos-page-inset);
}

/* Rail width parity with the other guest work pages. MUST stay inside the
   min-width query — an unscoped 2-class override beats the gem's own
   max-width:1100px collapse at EVERY width and pins a phone two-column. */
@media (min-width: 1101px) {
  .hos-flightpage > .os-workpage {
    grid-template-columns: 1fr 336px;
  }
}

/* READ-ONLY RAIL SURFACE — the CARD carries the tint, the desclist sits flush
   and transparent inside it (never inset by an .os-card__body). */
.hos-flightpage .os-workpage__rail > .os-card {
  background: var(--surface-alt);
}
.hos-flightpage .os-workpage__rail > .os-card > .os-card__body {
  padding: 0;
}
.hos-flightpage .os-workpage__rail .os-desclist--panel {
  background: transparent;
  border-radius: 0;
}
.hos-flightpage .os-workpage__rail > .os-meta {
  display: block;
  margin-top: var(--space-3);
}

/* NO CARD WITHIN A CARD (tasks/074 G5).
   The read panels were a tinted `.os-desclist--panel` floating inside a white
   `.os-card__body` — a grey rounded block inset inside a white rounded block,
   which reads as a second card nested in the first. The owner: "it should just
   be full that color, or just white."

   In the MAIN column the answer is JUST WHITE: the card already is the surface,
   so the desclist drops its tint, its radius and its own inset and becomes rows
   ruled by hairlines — the same read-first treatment the front-office detail
   surfaces use. (The RAIL takes the other half of the same rule, above: there
   the CARD carries the tint and the desclist goes transparent. Either way there
   is exactly one filled box, never two.)

   The rows keep the panel's vertical rhythm; only the horizontal inset is
   dropped, because the card body already supplies it. */
.hos-flightpage .os-workpage__main .os-desclist--panel {
  background: none;
  border-radius: 0;
}

.hos-flightpage .os-workpage__main .os-desclist--panel .os-desclist__row {
  padding-inline: 0;
}

/* Same defect, same fix, on the OTHER surface that nests a tinted read panel
   inside a white card: the transfers rail's sibling in the main column. */
.hos-transfers-page .os-workpage__main .os-desclist--panel {
  background: none;
  border-radius: 0;
}

.hos-transfers-page .os-workpage__main .os-desclist--panel .os-desclist__row {
  padding-inline: 0;
}

/* Two elevation levels only: the cards overlapping the hero lift, plus the
   sticky footer. Everything else is flat + hairline. */
.hos-flightpage > .os-workpage > .os-workpage__main .hos-flightpage__float,
.hos-flightpage > .os-workpage > .os-workpage__rail > .os-card:first-child {
  box-shadow: var(--elevation-overlay);
}

/* Sections after the first inside one form/column keep the main column's rhythm
   (the gem's __main gap only applies to its DIRECT children, and here the first
   section is wrapped in the <form>). */
.hos-flightpage__section {
  display: block;
  margin-top: var(--space-8);
}

/* A quiet secondary action closing a card body. */
.hos-flightpage__cardfoot {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--space-4);
}

/* The persistent action bar's geometry is the SHARED full-bleed sticky rule in
   section 2 (`.hos-arrival-page, .hos-flightpage`) — this page's private copy
   was deleted in tasks/074 rather than fixed twice. Only the CTA-grouping rules,
   which genuinely differ from arrival's, stay here. */

/* CTA group: bottom-right, primary rightmost. Driven off the LEAD status line
   rather than `:nth-last-child(2)` (which the arrival bar uses) — these footers
   render a variable number of buttons, and the positional rule hands the auto
   margin to the status text itself whenever only one button is present. */
.hos-flightpage .os-workpage__footer > form,
.hos-flightpage .os-workpage__footer > .os-btn {
  flex: none;
}
.hos-flightpage .os-workpage__footer > .os-meta {
  margin-right: auto;
}

@media (max-width: 720px) {
  .hos-flightpage {
    margin-top: -40px;
  }

  /* Stack full-width with the primary on top; sit ABOVE the shell's fixed tab
     bar (position:fixed, z-index 40 — at bottom:0 this bar docks under it). */
  .hos-flightpage .os-workpage__footer {
    flex-direction: column-reverse;
    align-items: stretch;
    padding-block: var(--space-3);
    bottom: var(--hos-gp-tabbar-h, 74px);
  }
  .hos-flightpage .os-workpage__footer > .os-meta {
    margin-right: 0;
  }
  .hos-flightpage .os-workpage__footer .os-btn {
    width: 100%;
  }
  .hos-flightpage .os-workpage__footer form {
    width: 100%;
  }
  /* Flight number + datetime stack rather than squeezing to unreadable. */
  .hos-flightpage .os-field-grid {
    grid-template-columns: 1fr;
  }
}

/* The FIRST section head rides on the sand hero (the page floats up onto it), so
   it takes the warm-on-warm neutrals — a cool slate label on a warm ground reads
   as a mistake. Rule 4 of tasks/069.
   `:first-of-type`, not `:first-child`: `form_with` emits a hidden div of Rails
   internals as the form's first element, so `:first-child` never matches. */
.hos-flightpage .os-workpage__main > section:first-of-type > .os-section-head .os-section-head__label,
.hos-flightpage .os-workpage__main > form:first-of-type > section:first-of-type > .os-section-head .os-section-head__label {
  color: var(--sand-label);
}
.hos-flightpage .os-workpage__main > section:first-of-type > .os-section-head .os-section-head__meta,
.hos-flightpage .os-workpage__main > form:first-of-type > section:first-of-type > .os-section-head .os-section-head__meta {
  color: var(--sand-muted);
}
