/* ==========================================================================
   Style

   Component styles for the page shell: header, totals, nav, footer, and the
   six generated pages (overview, checklist, itinerary, Brussels, notes, and
   the selections chrome). Group rows inside #selections-root belong to the
   selections module, not this file.

   Density varies on purpose: flights and ticket are tight and tabular,
   checklist reads as running prose under a bold instruction, itinerary is
   airy and led by time. Nothing here uses a side-stripe accent border, a
   card grid, or a modal.
   ========================================================================== */

/* -------------------------------------------------------------- skip link */

.skip-link {
  position: absolute;
  top: -3rem;
  left: var(--sp-4);
  z-index: 100;
  padding: var(--sp-2) var(--sp-4);
  background: var(--accent);
  color: var(--accent-ink);
  transition: top var(--dur-fast) var(--ease-quart);
}

.skip-link:focus {
  top: var(--sp-4);
}

.skip-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ------------------------------------------------------------- site header */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--bg);
  border-bottom: 1px solid var(--rule);
}

.site-header-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3) var(--sp-5);
  padding-block: var(--sp-3);
}

.brand {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  text-decoration: none;
  color: var(--fg);
}

.brand:hover {
  color: var(--fg);
}

.brand:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.brand-trip {
  font-family: var(--font-display);
  font-size: var(--step-0);
  font-weight: 600;
}

.brand-dates {
  font-size: var(--step--2);
  color: var(--fg-subtle);
}

/* --- Totals: committed reads larger and darker, projected sits smaller and
   muted beside it, and the gap gets its own labelled figure rather than
   being left for the reader to subtract by eye. ------------------------- */

.totals {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-6);
}

.totals-figure {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.totals-label {
  font-size: var(--step--2);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fg-subtle);
}

.totals-value {
  font-weight: 600;
}

.totals-committed .totals-value {
  font-size: var(--step-2);
  color: var(--fg);
}

.totals-projected .totals-value {
  font-size: var(--step-1);
  color: var(--fg-muted);
  font-weight: 500;
}

.totals-gap {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding-left: var(--sp-5);
  border-left: 1px solid var(--rule);
}

.totals-gap .totals-value {
  font-size: var(--step-1);
  color: var(--accent-strong);
}

.totals-unpriced {
  font-size: var(--step--1);
  color: var(--fg-subtle);
}

.site-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-4);
}

.site-nav a {
  color: var(--fg-muted);
  text-decoration: none;
  font-size: var(--step--1);
  padding-block: var(--sp-1);
  border-bottom: 2px solid transparent;
}

.site-nav a:hover {
  color: var(--fg);
}

.site-nav a[aria-current="page"] {
  color: var(--fg);
  font-weight: 600;
  border-bottom-color: var(--accent);
}

.site-nav a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.shell-controls {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.theme-toggle,
.sign-out {
  font: inherit;
  font-size: var(--step--1);
  background: var(--bg-raised);
  color: var(--fg-muted);
  border: 1px solid var(--rule-strong);
  padding: var(--sp-1) var(--sp-3);
  cursor: pointer;
}

.theme-toggle:hover,
.sign-out:hover {
  color: var(--fg);
}

.theme-toggle:focus-visible,
.sign-out:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.sign-out {
  background: transparent;
  border-color: transparent;
}

/* --- Phone width. Four totals figures, the brand, six nav links and two
   controls compete for 375px. Committed must never drop, so the header
   stacks into predictable full-width rows instead of packing items
   left-to-right: brand first, totals second (still its own two-line wrap,
   committed and projected first), controls third, nav last, since nav is
   the one element that can afford to collapse to the bottom. Tap targets
   on the controls and nav links reach the 44px minimum here only, so the
   desktop header, which already carries a lot, is untouched. ------------ */
@media (max-width: 29.99rem) {
  /* Not sticky on a phone. Stacked, this header measures 371px, which is 56
     per cent of a 375x667 viewport, pinned on every scroll. The city masthead
     now carries that city's own committed and projected figures, so a pinned
     header repeating them costs more than half the screen to say the same
     thing twice. It scrolls away here and the content gets the viewport. */
  .site-header {
    position: static;
  }

  .site-header-inner {
    flex-direction: column;
    align-items: stretch;
    gap: var(--sp-4);
  }

  .totals {
    order: 2;
  }

  .shell-controls {
    order: 3;
    align-self: flex-end;
  }

  .site-nav {
    order: 4;
    width: 100%;
  }

  .site-nav a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding-block: var(--sp-2);
  }

  .theme-toggle,
  .sign-out {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    padding: var(--sp-2) var(--sp-3);
  }
}

/* ------------------------------------------------------------------ main */

.page-head {
  padding-block: var(--sp-7) var(--sp-5);
}

/* The workhorse label of the whole system: above every masthead title,
   every section title, and (unstyled here, PanePolish's file) every priced
   option. Carries structure that a container would otherwise carry, so it
   gets its own margin rather than relying on a parent to space it. */
.eyebrow {
  font-size: var(--step--2);
  font-weight: 650;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-subtle);
  margin-bottom: var(--sp-2);
}

.page-head h1 {
  font-family: var(--font-display);
  font-size: var(--step-5);
  line-height: 1.05;
  margin-bottom: var(--sp-3);
}

.page-standfirst {
  font-size: var(--step-1);
  color: var(--fg-muted);
  line-height: 1.5;
}

.measure {
  max-width: var(--measure);
}

.section {
  padding-block: var(--sp-6);
  border-top: 1px solid var(--rule);
}

.section-head {
  margin-bottom: var(--sp-4);
}

.section-head h2 {
  font-family: var(--font-display);
  font-size: var(--step-2);
}

.section-note {
  color: var(--fg-muted);
  margin-top: var(--sp-2);
}

/* ============================================================== masthead
   The signature component. A drenched slab in the active city's brand
   colour (or the stone-grey fallback, on a page with no data-city), full
   bleed, carrying an eyebrow, the page or city name at display scale, and
   a standfirst. Interior pages get a shorter variant: half the padding,
   the title capped at --step-4, no photography. ========================== */

.masthead {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  min-height: 100svh;
  background: var(--brand-900);
  color: var(--brand-050);
  padding-block: clamp(3.5rem, 9vw, 8rem) 5.5rem;
}

/* Photography at near full strength: the scrim carries the contrast, not
   a dimmed image, so what shows is a photograph rather than a texture. */
.masthead-photo {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  opacity: 0.92;
}

.masthead-scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, var(--brand-900) 0%,
      color-mix(in oklch, var(--brand-900) 92%, transparent) 26%,
      color-mix(in oklch, var(--brand-900) 46%, transparent) 58%,
      color-mix(in oklch, var(--brand-900) 12%, transparent) 100%),
    linear-gradient(to right, color-mix(in oklch, var(--brand-900) 62%, transparent),
      transparent 70%);
}

.masthead-inner {
  position: relative;
}

.masthead .eyebrow {
  color: color-mix(in oklch, var(--brand-050) 88%, transparent);
  letter-spacing: 0.22em;
  margin-bottom: 0;
}

/* Beyond step-6 on purpose: a city arrival is the one place on the site
   permitted to break the type scale, because it is the only thing on its
   screen. City masthead titles only, never twice on a page. */
.masthead-title {
  font-family: var(--font-display);
  font-size: var(--step-masthead);
  font-weight: 800;
  font-variation-settings: 'SOFT' 0, 'WONK' 1, 'opsz' 144;
  line-height: 0.78;
  letter-spacing: -0.045em;
  max-width: 12ch;
  text-wrap: balance;
  margin: var(--sp-4) 0 var(--sp-5);
}

.masthead-standfirst {
  font-size: var(--step-2);
  line-height: 1.3;
  max-width: 32ch;
  font-weight: 400;
  color: color-mix(in oklch, var(--brand-050) 94%, transparent);
  margin: 0 0 var(--sp-7);
}

.masthead-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-7);
  padding-top: var(--sp-4);
  border-top: 1px solid color-mix(in oklch, var(--brand-050) 30%, transparent);
}

.masthead-meta div {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.masthead-meta .num {
  font-family: var(--font-mono);
  font-size: var(--step-2);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.masthead-meta .sub {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: color-mix(in oklch, var(--brand-050) 64%, transparent);
}

/* Interior variant: any page that is not a city arrival. Still a drenched
   slab (stone grey on a page with no data-city), just shorter and quieter. */
.masthead--interior {
  min-height: auto;
  align-items: flex-start;
  padding-block: var(--sp-7) var(--sp-6);
}

.masthead--interior .masthead-title {
  font-size: var(--step-4);
  font-weight: 640;
  font-variation-settings: 'SOFT' 0, 'WONK' 1, 'opsz' 96;
  line-height: 1.0;
  letter-spacing: -0.024em;
  max-width: 20ch;
  margin: var(--sp-3) 0 var(--sp-4);
}

.masthead--interior .masthead-standfirst {
  max-width: 46ch;
  font-size: var(--step-1);
  margin-bottom: 0;
}

@media (max-width: 29.99rem) {
  .masthead-meta {
    gap: var(--sp-5);
  }
}

/* ================================================================ subhead
   An eyebrow with a rule under it. Marks a division inside a page where a
   heading would be too loud. */
.subhead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--rule-strong);
  margin-bottom: var(--sp-4);
}

.subhead .eyebrow {
  margin-bottom: 0;
}

.subhead a {
  font-size: var(--step--1);
  text-decoration: none;
}

/* ============================================================ section-title
   Headline weight (640, step-4, opsz 96): section titles on any page this
   file owns, and the interior masthead title above. Not used for Selections
   group headings, which are Title weight and belong to PanePolish. */
.section-title {
  font-family: var(--font-display);
  font-size: var(--step-4);
  font-weight: 640;
  font-variation-settings: 'SOFT' 0, 'WONK' 1, 'opsz' 96;
  line-height: 1.0;
  letter-spacing: -0.024em;
  max-width: 22ch;
  text-wrap: balance;
  margin: var(--sp-2) 0 var(--sp-3);
}

.section-standfirst {
  max-width: 60ch;
  color: var(--fg-muted);
  margin: 0;
}

/* =================================================================== callout
   Recommendation and pending-state prose. A rule and a tonal ground, never
   a shadow or a radius. */
.callout {
  border: 1px solid var(--rule-strong);
  background: var(--bg-raised);
  padding: var(--sp-5);
  margin-block: var(--sp-5);
  max-width: 68ch;
}

.callout .eyebrow {
  margin-bottom: var(--sp-2);
}

.callout p {
  margin: var(--sp-2) 0 0;
  color: var(--fg-muted);
}

/* ------------------------------------------------------------------ links */

.link-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}

/* 44px minimum: the most-tapped elements on the page, one-handed, several
   in a row, so the gap above matters as much as the height here. Negative
   margin cancels the extra hit-area padding so the link text stays where
   it was visually. */
.link-list a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--sp-2);
  margin-inline: calc(var(--sp-2) * -1);
  font-size: var(--step--1);
}

/* ----------------------------------------------------------------- badges */

.badge {
  display: inline-block;
  font-size: var(--step--2);
  font-weight: 650;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

/* -------------------------------------------------------------- flights */

.flights-table,
.ticket-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
}

/* Scrolls inside its own box rather than pushing the page sideways. Setting
   the table itself to block lets it establish an overflow container without
   a wrapper element; the row-group children keep their table display values
   so the internal grid layout is unaffected. */
.flights-table {
  display: block;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  /* Right-edge scroll hint: a shadow fixed to the viewport (background-
     attachment: scroll) sits under a same-width cover that scrolls with the
     content (background-attachment: local). The cover only lines up over
     the shadow once scrolled all the way to the end, so the hint is there
     exactly when there is more to see and gone once there is not, no JS,
     no wrapper element. */
  background-image:
    linear-gradient(to left, var(--bg) 40%, transparent),
    linear-gradient(to left, var(--rule-strong), transparent);
  background-repeat: no-repeat;
  background-position: 100% 0, 100% 0;
  background-size: 28px 100%, 10px 100%;
  background-attachment: local, scroll;
}

.flights-table th,
.flights-table td,
.ticket-table th,
.ticket-table td {
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--rule);
  text-align: left;
  vertical-align: top;
}

/* Tight and tabular: an instrument panel, not running prose. */
.flights-table th,
.flights-table td {
  padding-block: var(--sp-1);
  line-height: 1.3;
}

.flights-table th {
  font-size: var(--step--2);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--fg-subtle);
  font-weight: 600;
}

.flights-table td:first-child,
.flights-table td:nth-child(3) {
  white-space: nowrap;
}

.flight-row-gap {
  background: var(--bg-sunken);
}

.ticket-table th {
  width: 12rem;
  font-weight: 600;
  color: var(--fg-muted);
}

/* ---------------------------------------------------------------- checklist */

.checklist-group {
  padding-block: var(--sp-6);
  border-top: 1px solid var(--rule);
}

.checklist-group-head h2 {
  font-family: var(--font-display);
  font-size: var(--step-2);
}

.checklist-group-note {
  color: var(--fg-muted);
  margin-top: var(--sp-2);
  max-width: var(--measure);
}

.task-list {
  margin-top: var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}

.task {
  padding-top: var(--sp-5);
  border-top: 1px solid var(--rule);
}

.task:first-child {
  padding-top: 0;
  border-top: none;
}

/* Restated label, not the instruction: PRODUCT.md puts the imperative
   first, so this stays in the DOM as the accessible heading (screen reader
   heading navigation still announces it) but carries no visual weight. */
.task-title {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.task-lead {
  font-size: var(--step-0);
  font-weight: 600;
  color: var(--fg);
  max-width: var(--measure);
}

.task-reasoning {
  margin-top: var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  max-width: var(--measure);
}

.task-reasoning p {
  color: var(--fg-muted);
  font-size: var(--step--1);
}

/* ---------------------------------------------------------------- itinerary */

.day {
  padding-block: var(--sp-9);
  border-top: 1px solid var(--rule);
}

.day-head {
  margin-bottom: var(--sp-6);
}

.day-date {
  font-family: var(--font-display);
  font-size: var(--step-3);
}

.day-city {
  color: var(--fg-muted);
  font-size: var(--step-0);
  margin-top: var(--sp-1);
}

.day-note {
  color: var(--fg-subtle);
  margin-top: var(--sp-2);
  max-width: var(--measure);
}

.day-items {
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}

.day-item {
  display: grid;
  grid-template-columns: 6rem 1fr;
  gap: var(--sp-4);
}

.day-item-time {
  font-weight: 600;
  font-size: var(--step-2);
  color: var(--accent-strong);
}

.day-item-title {
  font-size: var(--step-0);
  font-weight: 600;
  margin-bottom: var(--sp-1);
}

.day-item-detail {
  color: var(--fg-muted);
  max-width: var(--measure);
}

@media (max-width: 29.99rem) {
  .day-item {
    grid-template-columns: 4.5rem 1fr;
  }

  .day-item-time {
    font-size: var(--step-1);
  }
}

/* ------------------------------------------------------------------- notes */

.note-card {
  padding-block: var(--sp-6);
  border-top: 1px solid var(--rule);
}

.note-card:first-child {
  border-top: none;
  padding-top: 0;
}

.note-card h2 {
  font-family: var(--font-display);
  font-size: var(--step-1);
  margin-bottom: var(--sp-2);
}

.note-card p {
  color: var(--fg-muted);
}

/* ---------------------------------------------------------------- brussels */

.venue-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

.venue-photo {
  width: 100%;
  border-radius: var(--radius-s);
}

.venue-details {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-2) var(--sp-4);
  font-size: var(--step-0);
}

.venue-details dt {
  color: var(--fg-subtle);
  font-size: var(--step--1);
}

.venue-details dd {
  color: var(--fg);
}

.map-embed {
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--rule);
  margin-top: var(--sp-4);
}

.map-fallback {
  margin-top: var(--sp-3);
  color: var(--fg-muted);
  font-size: var(--step--1);
}

.hotel-pending-fields {
  margin-top: var(--sp-5);
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: var(--sp-3) var(--sp-5);
}

.hotel-pending-fields dt {
  font-size: var(--step--2);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--fg-subtle);
}

.hotel-pending-fields dd {
  color: var(--fg-subtle);
  font-style: italic;
}

/* -------------------------------------------------------------- selections */

#selections-root {
  display: block;
  min-height: 12rem;
  padding-block: var(--sp-6);
}

/* ---------------------------------------------------------------- ledger
   Summary page only. A ledger, not a dashboard: everything below is a
   ruled block or a ruled row, never a tile or a widget. Committed is
   static zero and Projected is a floor-price sum computed at build time
   from the open decisions in data/selections.js, since nothing is booked
   yet. Once bookings exist in Supabase, these figures need the same live
   hydration pass the header totals already get from
   window.TRIP_SHELL.setTotals, this file only lays out the shape. */

.ledger-totals {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-7) var(--sp-8);
  padding-block: var(--sp-7) var(--sp-6);
}

.ledger-total .eyebrow {
  margin-bottom: var(--sp-2);
}

.ledger-total-figure {
  font-family: var(--font-mono);
  font-size: var(--step-4);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: var(--fg);
}

.ledger-total--gap .ledger-total-figure {
  color: var(--accent-strong);
}

.ledger-total-sub {
  margin-top: var(--sp-2);
  font-size: var(--step--1);
  color: var(--fg-subtle);
}

.ledger-cities {
  display: flex;
  flex-direction: column;
}

.ledger-city {
  padding-block: var(--sp-5);
  border-top: 1px solid var(--rule);
}

.ledger-city:first-child {
  border-top: none;
  padding-top: 0;
}

.ledger-city-figures {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-6);
}

/* The eyebrow, the figure and its subtext are three inline spans in the
   markup, so without this they run together and read as "COMMITTEDAUD 0".
   Same stacking the masthead meta rail uses. */
.ledger-city-figures > div {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.ledger-city-figures .num {
  font-family: var(--font-mono);
  font-size: var(--step-1);
  font-weight: 600;
}

.ledger-city-figures .sub {
  display: block;
  margin-top: 2px;
  font-size: var(--step--1);
  color: var(--fg-subtle);
}

.ledger-list {
  margin-top: var(--sp-3);
  display: flex;
  flex-direction: column;
}

.ledger-row {
  display: grid;
  grid-template-columns: 6rem 1fr auto;
  align-items: baseline;
  gap: var(--sp-3);
  padding-block: var(--sp-3);
  border-top: 1px solid var(--rule);
}

.ledger-row:first-child {
  border-top: none;
}

.ledger-row-name {
  font-size: var(--step-0);
  font-weight: 600;
}

.ledger-row-state {
  font-size: var(--step--2);
  font-weight: 650;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-subtle);
}

.ledger-empty {
  margin-top: var(--sp-3);
  color: var(--fg-muted);
  max-width: var(--measure);
}

@media (max-width: 29.99rem) {
  .ledger-row {
    grid-template-columns: 1fr;
    gap: var(--sp-1);
  }

  .ledger-row-state {
    justify-self: start;
  }
}

/* -------------------------------------------------------------------- footer */

.site-footer {
  padding-block: var(--sp-6);
  border-top: 1px solid var(--rule);
  color: var(--fg-subtle);
  font-size: var(--step--1);
}

.site-footer a {
  color: inherit;
}
