/* Shared console rhythm; palette and operator marks remain owned by the themes. */
:root { --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-6: 24px; --radius: 12px; --press: 120ms; --fade: 180ms; --sheet: 240ms; --camera: 300ms; }
.product-nav { display: flex; flex: 0 0 auto; align-items: center; gap: 4px; padding: 3px; border: 1px solid var(--line); border-radius: 12px; background: var(--card); }
.product-nav a { display: inline-flex; align-items: center; justify-content: center; gap: 5px; min-width: 48px; min-height: 44px; padding: 0 8px; color: var(--navy); font: 700 13px Lato, sans-serif; text-decoration: none; border-radius: 8px; }
.product-nav a[aria-current] { background: var(--navy); color: var(--card); }
.product-nav .map-button { width: auto; height: auto; border: 0; box-shadow: none; background: transparent; }
.product-nav .map-icon { width: 18px; height: 18px; }
.landing-search { display: grid; gap: 8px; padding: 12px 16px; color: var(--muted); font-size: 13px; }
.landing-search input { width: 100%; min-height: 44px; padding: 10px; background: var(--card); color: var(--ink); border: 1px solid var(--line); border-radius: 8px; font: inherit; font-size: 16px; }
:root[data-surface="app"] .board-heading { flex-wrap: wrap; gap: 12px; }
:root[data-surface="app"] .board-heading h1 { flex: 1; font-size: clamp(22px, 4vw, 34px); line-height: 1.1; }
:root[data-surface="app"] .board-state { flex-basis: 100%; display: flex; align-items: center; justify-content: space-between; gap: 8px; }
:root[data-surface="app"] .board-footer { flex-wrap: wrap; gap: 8px; }
:root[data-surface="app"] .sort-toggle { margin: 0; padding: 0; gap: 4px; flex: 1 0 100%; }
:root[data-surface="app"] .sort-option { min-height: 44px; font-size: 14px; }
:root[data-surface="app"] .departures { gap: 12px; align-content: start; grid-auto-rows: max-content; scroll-padding: 12px; }
:root[data-surface="app"] .departure { height: auto; min-height: 0; border-radius: var(--radius); box-shadow: 0 2px 6px rgb(0 0 0 / .04); animation: none; }
:root[data-surface="app"] .timeline-row { display: flex; }
:root[data-surface="app"] .tl-head { gap: 12px; }
:root[data-surface="app"] .tl-head time { font-variant-numeric: tabular-nums; }
:root[data-surface="app"] .tl-relative { font-size: 14px; }
:root[data-surface="app"] .tl-dest { font-size: 22px; line-height: 1.2; flex-wrap: wrap; }
:root[data-surface="app"] :is(.tl-dest, .tl-dest-name, .departure-layover, .destination strong, .via, .route-name, .boat-name, .tl-boat, .tl-context) { white-space: normal; overflow: visible; overflow-wrap: anywhere; text-overflow: clip; }
:root[data-surface="app"] :is(.tl-meta, .tl-status, .departure-last-slot) { flex-wrap: wrap; overflow: visible; white-space: normal; line-height: 1.5; gap: 6px; }
:root[data-surface="app"] :is(.tl-context, .tl-boat, .boat-name) { font-size: 14px; }
:root[data-surface="app"] .departure-slot { min-height: 72px; padding: 12px 8px; }
:root[data-surface="app"] .departure-slot:nth-child(n) { display: flex; }
:root[data-surface="app"] .departure-slots { height: auto; grid-template-columns: repeat(auto-fit,minmax(150px,1fr)); }
:root[data-surface="app"] .slot-time-row { flex-wrap: wrap; overflow: visible; gap: 8px; }
:root[data-surface="app"] time { font-variant-numeric: tabular-nums; }
:root[data-surface="app"] :is(button, .landing-star), .map-body button { min-height: 44px; min-width: 44px; }
:root[data-surface="app"] :is(button, a), .map-body :is(button, a) { touch-action: manipulation; transition: background-color var(--press), opacity var(--press); }
:root[data-surface="app"] button:active, .map-body button:active { opacity: .72; }
:root[data-surface="app"] :focus-visible { outline: 3px solid var(--blue); outline-offset: 3px; }
.filter-menu-panel, .landing-menu-panel { animation: none; }
.map-body .map-heading { gap: 12px; }
.map-body .card-close { width: 44px; height: 44px; }
.map-body .search-input { min-height: 44px; }
/* One phone block. It was four, appended over four commits, and a rule's behaviour depended on
   which of them it had landed in. Everything here is ordered so the 820px block further down still
   wins where the two overlap. */
@media (max-width: 700px) {
  :root[data-surface="app"] .product-nav { order: 2; }
  :root[data-surface="app"] .nearest-button { order: 1; }
  :root[data-surface="app"] .board-state { order: 3; }
  :root[data-surface="app"] .product-nav .map-icon { display: none; }
  :root[data-surface="app"] .departure:not(.timeline-row) { display: grid; grid-template-columns: 1fr; gap: 12px; }
  :root[data-surface="app"] .departure-slots { border-left: 0; }
  /* Inert while the 820px block below lays the heading out as a grid, and kept because it is what
     the heading falls back to if that block ever stops applying. */
  :root[data-surface="app"] .board-heading:not(.map-heading) h1 { flex: 1 1 calc(100% - 120px); white-space: normal; overflow: visible; overflow-wrap: anywhere; text-overflow: clip; }
  :root[data-surface="app"] .board-heading:not(.map-heading) .board-state { flex: 1 1 calc(100% - 130px); flex-wrap: wrap; }
  .map-heading { flex-wrap: wrap; }
  .map-heading-copy { flex: 1; }
  .map-heading .product-nav { order: 2; }
  .map-heading .board-state { margin-left: auto; }
  /* visibility rides the transition at 0s so the collapsed sheet leaves the tab order the moment it
     starts closing, and rejoins it the moment it starts opening. */
  .map-body .fleet-content { display: flex; height: min(29dvh,250px); overflow: hidden; opacity: 1; visibility: visible; transition: height var(--sheet), opacity var(--fade), transform var(--sheet), visibility 0s; }
  .map-body .bottom-sheet[data-state="peek"] .fleet-content { display: flex; height: 0; opacity: 0; transform: translateY(12px); visibility: hidden; transition: height var(--sheet), opacity var(--fade), transform var(--sheet), visibility 0s var(--sheet); }
  .map-body .bottom-sheet { padding-bottom: var(--app-safe-bottom); }
  .map-tools button { width: 44px; height: 44px; }
  /* Keep the selected vessel and map controls visible above the detail card. */
  .map-body .vessel-card { max-height: 40%; width: calc(100% - 76px); }
}
@media (max-height: 520px) and (max-width: 700px) { .map-body .fleet-content { height: 22dvh; } }
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; } }
/* Kiosk keeps its fixed layout and original map affordance. */
:root[data-surface="kiosk"] .product-nav { padding: 0; border: 0; background: none; }
:root[data-surface="kiosk"] .product-nav > a:first-child, :root[data-surface="kiosk"] .product-nav .map-button span { display: none; }
:root[data-surface="kiosk"] .board-footer .sort-toggle { display: none; }
/* The map remains an app surface even when opened from the root-mounted kiosk. */
:root[data-surface="kiosk"] .map-body .product-nav { display: flex; padding: 3px; border: 1px solid var(--line); background: var(--card); }
:root[data-surface="kiosk"] .map-body .product-nav > a:first-child { display: inline-flex; }

/* Use the browser's text preference; iOS exposes Dynamic Type through this font. */
:root[data-surface="app"] { font-size: 100%; }
@supports (font: -apple-system-body) {
  :root[data-surface="app"] { font: -apple-system-body; font-family: Lato, Arial, sans-serif; }
}
:root { --app-safe-bottom: env(safe-area-inset-bottom, 0px); }
:root[data-keyboard="open"] { --app-safe-bottom: 0px; }
/* The shell is the visible viewport, measured, never a viewport unit. A unit describes the window
   the page was given; on an installed iOS board that window is taller than the web view drawn in
   it, and a shell in vh hangs its last bar over the edge where the screen stops painting. 100dvh is
   only the value that holds until the runtime's first measurement. */
:root[data-surface="app"] :is(.screen, .landing-menu, .filter-menu), .map-body {
  position: fixed; top: var(--app-viewport-top, 0px); right: 0; bottom: auto; left: 0;
  height: var(--app-viewport-height, 100dvh);
}
:root[data-surface="app"] .screen, .map-body { width: auto; }
:root[data-surface="app"] .filter-menu-panel { padding-bottom: calc(14px + var(--app-safe-bottom)); }
.map-body .fleet-footer { padding-bottom: calc(12px + var(--app-safe-bottom)); }
:root[data-surface="app"] .departure { padding: 12px; }
:root[data-surface="app"] .timeline-row { gap: 8px; }
:root[data-surface="app"] .tl-head time { font-size: 1.5rem; }
:root[data-surface="app"] :is(.tl-dest, .destination strong) { font-size: 1.125rem; line-height: 1.3; }
:root[data-surface="app"] :is(.tl-relative, .tl-context, .tl-boat, .boat-name, .slot-relative, .departure-layover) { font-size: .75rem; }
:root[data-surface="app"] .slot-time-row time { font-size: 1.375rem; }
:root[data-surface="app"] :is(.departure-last-badge, .vessel-delay-badge, .on-time-badge, .scheduled-badge, .boat-assignment, .no-pickup-badge, .arrival-badge, .drop-off-badge, .drop-off-only-badge, .via-terminal-badge) { font-size: .6875rem; }
:root[data-surface="app"] :is(.sort-option, .date-current, .clock-toggle, .product-nav a) { font-size: .8125rem; }
:root[data-surface="app"] :is(.landing-option-name, .filter-option, .theme-option) { font-size: .875rem; }
:root[data-surface="app"] :is(.landing-search input, .search-input) { font-size: 1rem; }
:root[data-surface="app"] .service-alert-bar { padding-bottom: max(8px, var(--app-safe-bottom)); }
:root[data-surface="app"] :is(.service-alert-copy strong, .service-alert-summary) { font-size: .75rem; line-height: 1.25; }
:root[data-surface="app"] .service-alert-copy small { font-size: .625rem; }
@media (max-width: 820px) {
  :root[data-surface="app"] .board-heading:not(.map-heading) {
    display: grid; grid-template-columns: 44px minmax(0,1fr) minmax(0,1fr) 44px;
    gap: 8px 10px; padding: calc(8px + env(safe-area-inset-top)) 12px 10px;
  }
  :root[data-surface="app"] .board-heading:not(.map-heading) .menu-button { grid-column: 1; grid-row: 1; }
  :root[data-surface="app"] .board-heading:not(.map-heading) h1 {
    grid-column: 2 / 4; grid-row: 1; margin: 0; font-family: inherit; font-size: 1.125rem;
    font-weight: 800; line-height: 1.25; text-transform: none; white-space: normal;
  }
  :root[data-surface="app"] .board-heading:not(.map-heading) .nearest-button { grid-column: 4; grid-row: 1; }
  :root[data-surface="app"] .board-heading:not(.map-heading) .product-nav { grid-column: 1 / 3; grid-row: 2; justify-self: start; padding: 2px; border-radius: 10px; }
  :root[data-surface="app"] .board-heading:not(.map-heading) .board-state {
    grid-column: 3 / 5; grid-row: 2; display: flex; flex-wrap: wrap; justify-content: flex-end;
    gap: 4px 8px; min-width: 0; align-content: center;
  }
  :root[data-surface="app"] :is(.route-count, .status) { padding: 0; border: 0; background: transparent; font-size: .625rem; font-weight: 700; }
  :root[data-surface="app"] .clock { flex-basis: 100%; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 3px 6px; }
  :root[data-surface="app"] .clock time { font-family: inherit; font-size: .8125rem; }
  :root[data-surface="app"] .clock span { font-size: .625rem; white-space: normal; text-align: right; }
}

/* A scrolling flex column must never shrink route cards to fit the viewport. */
:root[data-surface="app"] .departures[data-view="routes"] > .departure { flex: 0 0 auto; }
.landing-menu-panel { height: 100%; }
:root[data-surface="app"] .landing-menu-panel .sort-toggle,
.landing-menu-panel .sort-toggle {
  flex: 0 0 auto; margin-top: auto; padding: 12px 14px max(12px, var(--app-safe-bottom));
  border-top: 1px solid var(--line); border-bottom: 0;
}
.landing-menu-panel .landing-list { padding-bottom: 8px; }
.landing-menu-panel > .landing-menu-head, .landing-menu-panel > .landing-search { flex-shrink: 0; }
