/* person-travel.css — the trip colour presets, plus admin controls, the form
   modal, and the stop screen for the person page travel section. Loaded by
   about.html and trip.html. Self-contained dark styling so it reads consistently
   on the Pico about page and on the trip page. */

/* ── Trip colour presets ───────────────────────────────────────────────────
   A trip picks one of four palettes (person_trips.theme; the slugs are pinned
   by a CHECK constraint and by TripTheme in the backend's constants.py). This
   file is the ONE place the colours are written down, because it is the only
   stylesheet both about.html and trip.html load — trip.html's inline block and
   about.css both read these tokens rather than restating hex.

   Deliberately attribute selectors and not :root rules. The trip page puts the
   attribute on <html> (one theme per document); the about page puts it on each
   individual .travel-card (four themes in one document). Same block, both jobs.

   Only hue-bearing values are tokens. The white-alpha chrome elsewhere in this
   file (rgba(255,255,255,.05) and friends) is theme-neutral by construction —
   it reads correctly on any dark ground — and is left alone on purpose.

   --trip-accent-rgb is the accent again as a bare "r g b" triple, for the
   handful of places that need it at alpha: rgb(var(--trip-accent-rgb) / .14).
   var() can't be interpolated into a legacy rgba(…) call, hence the pair. */
:root {
  /* Constant across every preset. The cream postcard-on-paper stop card is the
     section's identity — only the ground, the accents and the numbered plate
     re-colour. */
  --paper: #E7E3D6;
  --ink: #1E2A33;
  --plaque: #FBFAF6;
  --stop-border: #B9B2A0;
}

/* Enamel is also the bare :root fallback, so an element with no
   data-trip-theme (or an unrecognised one) still paints the original look. */
:root,
[data-trip-theme="enamel"] {
  --trip-ground-top: #2E5C86;
  --trip-ground-mid: #16324B;
  --trip-ground-deep: #0E2032;
  --trip-accent: #F2D46B;
  --trip-accent-rgb: 242 212 107;
  --trip-plate: #123C6B;
  --trip-meta: #4E7FA6;
  --trip-go: #B0552E;
  --trip-card-border: rgba(120, 160, 200, 0.28);
  --trip-card-border-hover: rgba(160, 195, 230, 0.55);
  --trip-card-border-muted: rgba(120, 160, 200, 0.16);
}

[data-trip-theme="terracotta"] {
  --trip-ground-top: #8A4A2E;
  --trip-ground-mid: #4A2318;
  --trip-ground-deep: #241009;
  --trip-accent: #E8B77A;
  --trip-accent-rgb: 232 183 122;
  --trip-plate: #6B2E1E;
  --trip-meta: #B07A5C;
  /* Teal, not the usual terracotta: the ↗ is the one warm pop on the cream
     card, and a clay arrow on a clay theme stops being a pop. */
  --trip-go: #2E6B5A;
  --trip-card-border: rgba(200, 150, 120, 0.28);
  --trip-card-border-hover: rgba(230, 180, 145, 0.55);
  --trip-card-border-muted: rgba(200, 150, 120, 0.16);
}

[data-trip-theme="pine"] {
  --trip-ground-top: #2D6A4F;
  --trip-ground-mid: #1B4332;
  --trip-ground-deep: #0B1F16;
  --trip-accent: #D9C089;
  --trip-accent-rgb: 217 192 137;
  /* Lighter and more saturated than --trip-ground-mid, as in every preset:
     the plate is the card gradient's mid-tone as well as the stop number's
     block, and matching the two flattens the card. */
  --trip-plate: #22614A;
  --trip-meta: #6B9080;
  --trip-go: #B0552E;
  --trip-card-border: rgba(130, 190, 160, 0.26);
  --trip-card-border-hover: rgba(165, 220, 190, 0.5);
  --trip-card-border-muted: rgba(130, 190, 160, 0.15);
}

[data-trip-theme="plum"] {
  --trip-ground-top: #6A3D74;
  --trip-ground-mid: #3E2148;
  --trip-ground-deep: #1B0F21;
  --trip-accent: #E0A9C4;
  --trip-accent-rgb: 224 169 196;
  --trip-plate: #562E64;
  --trip-meta: #9B7BA6;
  --trip-go: #C9A227;
  --trip-card-border: rgba(180, 140, 200, 0.28);
  --trip-card-border-hover: rgba(210, 175, 230, 0.55);
  --trip-card-border-muted: rgba(180, 140, 200, 0.16);
}

/* ── Edit-icon admin login button ──────────────────────────────────────────
   The pencil icon is the entry point for admin editing — it prompts for the
   key when there isn't one, and turns gold (--active) while editing. On the
   trip page it sits inline in the "Stops along the way" row. */
.pa-admin-login {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.05);
  color: #eaf1f7;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.pa-admin-login:hover { background: rgba(255, 255, 255, 0.12); border-color: rgba(255, 255, 255, 0.4); }
.pa-admin-login:active { transform: translateY(1px); }
.pa-admin-login svg { display: block; }
.pa-admin-login--active { border-color: rgba(242, 212, 107, 0.5); color: #f2d46b; background: rgba(242, 212, 107, 0.12); }

/* ── Slider switch ─────────────────────────────────────────────────────────
   A labelled on/off slider. The <input> does the work — it stays a real
   checkbox so the control is keyboard-operable and announced correctly — and is
   clipped rather than display:none'd, because a display:none input is not
   focusable. The whole <label> is the hit target. Used by the trip page's
   "Save offline" switch; the pill around it lives with that page's chrome. */
.pa-switch {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  cursor: pointer;
  user-select: none;
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: rgba(214, 223, 231, 0.85);
  white-space: nowrap;
}
.pa-switch input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.pa-switch__track {
  position: relative;
  flex: none;
  width: 40px;
  height: 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.16);
  transition: background 0.2s;
}
.pa-switch__track::before {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #eaf1f7;
  transition: transform 0.2s;
}
/* Gold when on — the same "this is active" accent as .pa-admin-login--active. */
.pa-switch input:checked + .pa-switch__track { background: rgba(242, 212, 107, 0.85); }
.pa-switch input:checked + .pa-switch__track::before { transform: translateX(18px); background: #1e2a33; }
.pa-switch input:checked ~ .pa-switch__label { color: #f2d46b; }
/* The input is clipped, so the focus ring has to be drawn on the track. */
.pa-switch input:focus-visible + .pa-switch__track {
  outline: 2px solid #f2d46b;
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .pa-switch__track,
  .pa-switch__track::before { transition: none; }
}

/* The header's right-hand action group (trip page: album + download pills). */
.header-actions { display: inline-flex; align-items: center; gap: 0.6rem; }

/* About page: pin the actions to the top-right of the centered header,
   at every width (including mobile). */
.header-inner .header-actions {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
}

/* ── Admin bar ─────────────────────────────────────────────────────────── */
.travel-admin-bar {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin: 0 0 1rem;
  padding: 0.6rem 0.85rem;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.14);
}
/* `display:flex` above would otherwise defeat the [hidden] attribute's
   display:none, leaking an empty bar into the public (non-admin) view. */
.travel-admin-bar[hidden] { display: none; }
.pa-tag {
  font-size: 0.68rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  font-weight: 700;
  color: #f2d46b;
  margin-right: auto;
}

/* ── Buttons ───────────────────────────────────────────────────────────── */
.pa-btn {
  font: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  line-height: 1;
  min-height: 40px;
  padding: 0.5rem 0.9rem;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  background: rgba(255, 255, 255, 0.08);
  color: #eaf1f7;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, transform 0.1s;
}
.pa-btn:hover { background: rgba(255, 255, 255, 0.16); border-color: rgba(255, 255, 255, 0.4); }
.pa-btn:active { transform: translateY(1px); }
.pa-btn:disabled { opacity: 0.5; cursor: default; }
.pa-btn--primary { background: #2b6cb0; border-color: #3f86d1; color: #fff; }
.pa-btn--primary:hover { background: #3f86d1; }
.pa-btn--danger { background: rgba(176, 85, 46, 0.22); border-color: rgba(176, 85, 46, 0.6); color: #f3c9b6; }
.pa-btn--danger:hover { background: rgba(176, 85, 46, 0.4); }
.pa-btn--ghost { background: transparent; }
.pa-btn--sm { min-height: 34px; padding: 0.35rem 0.6rem; font-size: 0.76rem; }

/* ── Trip card admin controls (about page) ─────────────────────────────── */
.travel-card-wrap { display: flex; flex-direction: column; gap: 0.5rem; }
.pa-card-controls { display: flex; gap: 0.5rem; }
.pa-card-controls .pa-btn { flex: 1; }
.pa-badge {
  display: inline-block;
  margin-left: 0.5rem;
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 700;
  vertical-align: middle;
  padding: 0.15rem 0.4rem;
  border-radius: 6px;
  background: rgba(242, 212, 107, 0.18);
  color: #f2d46b;
}
.travel-empty {
  color: rgba(214, 223, 231, 0.7);
  font-size: 0.95rem;
  padding: 1rem 0;
}
.travel-empty--error { color: #f3c9b6; }

/* ── Form modal ────────────────────────────────────────────────────────── */
/* Sized to the *visible* viewport, like .stop-screen below. `dvh` drops
   the retracted-URL-bar strip; `--pa-vv-h` (set by formModal from
   window.visualViewport) goes further and drops the software keyboard too —
   iOS overlays the keyboard without shrinking the layout viewport, so `dvh`
   alone still leaves the pinned actions row underneath it. The `vh` line is the
   no-dvh fallback. */
.pa-modal__backdrop {
  position: fixed;
  inset: 0;
  box-sizing: border-box;
  height: 100vh;
  height: 100dvh;
  height: var(--pa-vv-h, 100dvh);
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  padding-top: calc(1.5rem + env(safe-area-inset-top));
  padding-bottom: calc(1.5rem + env(safe-area-inset-bottom));
  background: rgba(8, 16, 26, 0.72);
  backdrop-filter: blur(3px);
}
/* Flex column: head and actions are flex:none, only the fields scroll — so the
   Save/Cancel row can never scroll (or be typed) off the bottom. */
.pa-modal {
  width: 100%;
  max-width: 640px;
  max-height: 100%;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: 16px;
  background: #16232f;
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 30px 70px -30px rgba(0, 0, 0, 0.85);
  color: #eaf1f7;
}
.pa-modal__head {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.pa-modal__title { font-size: 1.1rem; font-weight: 700; }
.pa-modal__x {
  font-size: 1.6rem;
  line-height: 1;
  width: 40px;
  height: 40px;
  border: none;
  background: none;
  color: rgba(234, 241, 247, 0.7);
  cursor: pointer;
  border-radius: 8px;
}
.pa-modal__x:hover { color: #fff; background: rgba(255, 255, 255, 0.08); }
.pa-modal__x:disabled { opacity: 0.4; cursor: default; background: none; }
.pa-modal__form { flex: 1; min-height: 0; display: flex; flex-direction: column; }
/* The one scroller in the modal — min-height:0 so it actually shrinks instead of
   pushing the actions row out of the shell. */
.pa-modal__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}
.pa-field { display: flex; flex-direction: column; gap: 0.35rem; }
.pa-field__label { font-size: 0.8rem; font-weight: 600; color: rgba(234, 241, 247, 0.85); }
.pa-req { color: #f2d46b; }
.pa-field input[type="text"],
.pa-field input[type="url"],
.pa-field input[type="number"],
.pa-field select,
.pa-field textarea {
  font: inherit;
  width: 100%;
  box-sizing: border-box;
  padding: 0.6rem 0.7rem;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
}
.pa-field textarea { resize: vertical; min-height: 3rem; }
/* The dropdown list itself is drawn by the OS and won't inherit the dark shell,
   so the options are given their own colours or they render white-on-white. */
.pa-field select option { background: #16324b; color: #fff; }
.pa-field input:focus, .pa-field select:focus, .pa-field textarea:focus {
  outline: none;
  border-color: #3f86d1;
  background: rgba(255, 255, 255, 0.09);
}
/* ── Colour preset picker ──────────────────────────────────────────────────
   One chip per preset. Each label carries its own data-trip-theme, so the chip
   is painted by the very tokens the card and the trip page will use — there is
   no second copy of the palette here to drift out of step.

   The radios stay real radios (clipped, not display:none, which would make them
   unfocusable), so arrow keys move between presets and the group is announced
   correctly. The visible selected state is on the label. */
.pa-swatches { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.pa-swatch {
  flex: 1 1 6rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.4rem;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.04);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.pa-swatch:hover { border-color: rgba(255, 255, 255, 0.32); }
.pa-swatch input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
/* The chip is the preset in miniature: the page ground, the numbered plate, and
   the accent — the three things that actually change between presets. */
.pa-swatch__chip {
  width: 100%;
  height: 30px;
  border-radius: 7px;
  border: 1px solid var(--trip-card-border);
  background: linear-gradient(135deg,
    var(--trip-ground-top) 0%, var(--trip-ground-mid) 45%, var(--trip-ground-deep) 100%);
  box-shadow: inset 0 -7px 0 -3px var(--trip-accent);
}
.pa-swatch__name {
  font-size: 0.72rem;
  font-weight: 600;
  color: rgba(234, 241, 247, 0.75);
}
.pa-swatch:has(input:checked) {
  border-color: rgba(255, 255, 255, 0.55);
  background: rgba(255, 255, 255, 0.1);
}
.pa-swatch:has(input:checked) .pa-swatch__name { color: #fff; }
.pa-swatch:has(input:focus-visible) { outline: 2px solid #f2d46b; outline-offset: 2px; }

.pa-field--check .pa-field__label {
  flex-direction: row;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
}
.pa-modal__err {
  flex: none;
  margin: 0 1.25rem;
  color: #f3b0b0;
  font-size: 0.85rem;
  padding: 0.4rem 0.6rem;
  border-radius: 8px;
  background: rgba(176, 46, 46, 0.15);
}

/* ── Saving state (formModal with an onSubmit handler) ─────────────────── */
/* The modal stays up while the save is in flight; dim and freeze the fields so
   it reads as "in progress" rather than "still editable". The buttons are
   disabled in JS, so .pa-btn:disabled already handles the actions row. */
.pa-modal--busy .pa-modal__body {
  opacity: 0.55;
  pointer-events: none;
}
.pa-spin {
  display: inline-block;
  width: 13px;
  height: 13px;
  margin-right: 0.45rem;
  vertical-align: -2px;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: pa-spin 0.6s linear infinite;
}
@keyframes pa-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .pa-spin { animation: none; }
}

/* Opaque + bordered: the fields scroll underneath this row, so it can't be
   translucent. */
.pa-modal__actions {
  flex: none;
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  padding: 0.75rem 1.25rem;
  padding-bottom: calc(0.75rem + env(safe-area-inset-bottom));
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  background: #16232f;
}

/* ── HTML editor textarea (stop content) gets a monospace, taller box ───── */
.pa-field textarea[data-name="html_content"] {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.8rem;
  min-height: 14rem;
  line-height: 1.45;
  tab-size: 2;
}

/* ── File import control (load an .html file into the editor) ───────────── */
.pa-import {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.5rem;
}
.pa-import__btn { display: inline-flex; align-items: center; cursor: pointer; }
.pa-import__name {
  font-size: 0.78rem;
  color: rgba(234, 241, 247, 0.6);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── HTML span editor (per-paragraph inline WYSIWYG) ────────────────────── */
.hse { display: flex; flex-direction: column; gap: 0.6rem; }
/* .hse already gaps its children — drop .pa-import's own trailing margin. */
.hse > .pa-import { margin-bottom: 0; }
.hse-tabs { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.hse-tab {
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  padding: 0.4rem 0.75rem;
  border-radius: 8px 8px 0 0;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-bottom: none;
  background: rgba(255, 255, 255, 0.04);
  color: rgba(234, 241, 247, 0.7);
  cursor: pointer;
}
.hse-tab--on { background: rgba(255, 255, 255, 0.1); color: #fff; }

.hse-toolbar { display: flex; gap: 0.35rem; margin-bottom: 0.5rem; }
.hse-tb {
  font: inherit;
  font-size: 0.85rem;
  min-width: 34px;
  min-height: 32px;
  padding: 0.25rem 0.55rem;
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.06);
  color: #eaf1f7;
  cursor: pointer;
}
.hse-tb:hover { background: rgba(255, 255, 255, 0.16); }

/* No max-height/overflow here: .pa-modal__body is the modal's one scroller, and
   a nested `vh`-capped scroller would fight it once the keyboard shrinks the
   shell. The cap only existed to keep Save reachable past a long block list,
   which the pinned actions row now handles. */
.hse-blocks {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding-right: 0.25rem;
}
/* Tag above the box, not beside it, so the box gets the full modal width — the
   old 2.6rem/7rem gutter ate a third of a phone-width row. */
.hse-block {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.hse-block__tag {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: rgba(234, 241, 247, 0.45);
  text-align: left;
  overflow-wrap: anywhere;
}
.hse-block__field {
  width: 100%;
  box-sizing: border-box;
  min-width: 0;
  padding: 0.5rem 0.7rem;
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  line-height: 1.5;
}
.hse-block__field:focus { outline: none; border-color: #3f86d1; background: rgba(255, 255, 255, 0.09); }
.hse-empty { color: rgba(234, 241, 247, 0.6); font-size: 0.9rem; margin: 0.5rem 0; }

.hse-source {
  font: inherit;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.8rem;
  line-height: 1.45;
  tab-size: 2;
  width: 100%;
  box-sizing: border-box;
  min-height: 14rem;
  resize: vertical;
  padding: 0.6rem 0.7rem;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
}
.hse-source:focus { outline: none; border-color: #3f86d1; }

/* ── Stop screen (sandboxed iframe) ────────────────────────────────────── */
/* The postcard reader at /travel/:slug/:stop. Deliberately a screen and not an
   overlay: it was a centred, bordered, rounded shell floating on a blurred
   backdrop, which framed every postcard in a box it wasn't designed for and
   nested three scrollable layers (page → shell → the postcard's own document)
   so touch scrolling fought itself at the edges. Now there is no backdrop, no
   inset, no border and no radius — just pinned chrome with the postcard filling
   everything between, and its own document as the only scroller on screen.

   Sized to the *visible* viewport: on mobile `vh` (and the fixed-position
   containing block) resolve against the viewport with the URL bar retracted, so
   a `vh`-sized screen pushes its nav row off the bottom while the URL bar is
   showing. `dvh` tracks the height actually on screen; the `vh` line above stays
   as the fallback. Same pattern as body in trip.html. */
.stop-screen {
  position: fixed;
  inset: 0;
  box-sizing: border-box;
  height: 100vh;
  height: 100dvh;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  /* Follows the trip's preset — the reader is the trip's reading surface, and
     a blue shell around a plum trip would read as a different site. The token
     resolves off <html>, which trip.js stamps with the theme. */
  background: var(--trip-ground-deep);
}
/* display:flex outranks the [hidden] UA rule, so it has to be restated. */
.stop-screen[hidden] { display: none; }

/* Chrome reads as chrome through a lifted background rather than a hairline
   rule — one less line drawn across the postcard. The safe-area padding lives
   here, not on a wrapper, so the bars clear the notch and the home indicator
   while the postcard keeps every pixel in between. */
.stop-screen__bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.7rem 0.85rem 0.7rem 1.1rem;
  padding-top: calc(0.7rem + env(safe-area-inset-top));
  background: rgba(255, 255, 255, 0.05);
  color: #eaf1f7;
}
.stop-screen__title {
  font-size: 0.95rem;
  font-weight: 700;
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Downloads the stop's stored HTML. Sits left of the close button and mirrors
   its box so the pair reads as one control group. */
.stop-screen__dl,
.stop-screen__close {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.06);
  color: #eaf1f7;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.stop-screen__dl svg,
.stop-screen__close svg { display: block; }
.stop-screen__dl:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.16);
  color: var(--trip-accent);
}
.stop-screen__dl:disabled { opacity: 0.4; cursor: default; }
.stop-screen__close:hover { background: rgba(255, 255, 255, 0.16); }

/* The only flexible row, and the slide's viewport. min-height:0 — an iframe is a
   replaced element, so its automatic minimum size would otherwise pin the row at
   its intrinsic 150px and push the nav off a short viewport. overflow:hidden
   clips the outgoing and incoming postcards to this box while they cross; it
   also means the frame inside can never be the page's scroller, which is exactly
   the arrangement the header of stop-view.js depends on. */
.stop-screen__stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

/* display:block kills the inline baseline gap that otherwise shows as a seam
   under the frame. The background matches the page (it used to be #fff, which
   flashed as a white band while a postcard loaded and edged the card wherever
   its own body didn't reach). Capped and centred so a postcard laid out for a
   phone isn't stretched across a desktop; phones fall under the cap and go edge
   to edge. */
.stop-screen__frame {
  display: block;
  width: 100%;
  height: 100%;
  max-width: 960px;
  margin: 0 auto;
  border: 0;
  background: var(--trip-ground-deep);
}

/* ── Previous / Next slide ────────────────────────────────────────────────
   While a slide runs, both postcards are absolutely positioned in the stage:
   the outgoing one leaves toward the direction of travel, the incoming one
   arrives from the opposite edge. Once it settles, stop-view.js strips these
   classes and the surviving frame is the plain static child again — so the
   steady state is exactly what it was before the animation existed.

   left:0;right:0 rather than width:100% so `margin:0 auto` still centres the
   capped frame inside the stage on a wide screen.

   height MUST stay explicit. An iframe is a *replaced* element, and an
   absolutely positioned replaced element with `height:auto` takes its intrinsic
   height — 150px — and drops `bottom` as over-constrained. It does not stretch
   between top and bottom the way a normal box does. `height:auto` here collapsed
   the outgoing postcard to a 150px strip the moment this class landed, leaving
   the stage's own navy filling the rest of the screen until the slide settled
   and the class came off again. 100% resolves against the stage, so the frame's
   box is identical sliding and settled. */
.stop-screen__frame--sliding {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  height: 100%;
  transition: transform 0.28s ease, opacity 0.28s ease;
}
.stop-screen__frame--from-right { transform: translateX(100%); opacity: 0.4; }
.stop-screen__frame--from-left { transform: translateX(-100%); opacity: 0.4; }
.stop-screen__frame--in { transform: translateX(0); opacity: 1; }
.stop-screen__frame--out-left { transform: translateX(-100%); opacity: 0.4; }
.stop-screen__frame--out-right { transform: translateX(100%); opacity: 0.4; }

/* stop-view.js also checks this query and takes the plain swap path, so this is
   belt and braces for a preference that changes mid-slide. */
@media (prefers-reduced-motion: reduce) {
  .stop-screen__frame--sliding { transition: none; }
}

/* Bottom nav: page Previous/Next through the trip's stops in place. Hidden by
   stop-view.js on a one-stop trip. */
.stop-screen__nav {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.6rem 0.85rem;
  padding-bottom: calc(0.6rem + env(safe-area-inset-bottom));
  background: rgba(255, 255, 255, 0.05);
}
.stop-screen__nav[hidden] { display: none; }
/* inline-flex, not a plain text button: the arrow and the word are separate
   spans so the landscape rails can drop the word (see trip.html). */
.stop-screen__nav-btn {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  min-height: 44px;
  padding: 0.5rem 0.9rem;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.06);
  color: #eaf1f7;
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.stop-screen__nav-btn:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.16);
  border-color: rgba(255, 255, 255, 0.4);
}
.stop-screen__nav-btn:disabled { opacity: 0.4; cursor: default; }
.stop-screen__counter {
  flex: 1;
  text-align: center;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: rgba(214, 223, 231, 0.7);
}

@media (max-width: 620px) {
  /* Tighter chrome so the postcard gets the room back. The 44px touch targets
     are untouched — only the padding around them shrinks, and the safe-area
     insets are re-added on top so the bars still clear the notch and the home
     indicator. */
  .stop-screen__bar {
    padding: 0.45rem 0.5rem 0.45rem 0.75rem;
    padding-top: calc(0.45rem + env(safe-area-inset-top));
  }
  .stop-screen__nav {
    padding: 0.45rem 0.5rem;
    padding-bottom: calc(0.45rem + env(safe-area-inset-bottom));
  }
  .pa-card-controls { flex-wrap: wrap; }
  .pa-modal__backdrop {
    padding: 0.5rem;
    padding-top: calc(0.5rem + env(safe-area-inset-top));
    padding-bottom: calc(0.5rem + env(safe-area-inset-bottom));
  }
  /* No forced height — max-height:100% already lets a long form (the stop
     editor) fill the padded backdrop, while a two-field form still shrink-wraps
     instead of stranding its actions row at the bottom of the screen. */
  .pa-modal__body { padding: 0.9rem; }
  .pa-modal__err { margin: 0 0.9rem; }
  .pa-modal__actions { padding-left: 0.9rem; padding-right: 0.9rem; }
}

/* ── Landscape phone: rails instead of bars ───────────────────────────────
   Held sideways, height is the scarce dimension and width is the plentiful one,
   which makes the two chrome bars exactly the wrong shape — they eat the
   postcard's height while the gutters either side of it sit empty. So the whole
   screen becomes a grid, and the bar and the nav become `display:contents` so
   their buttons promote to grid items and land in rails left and right of the
   card: close over Previous, download over Next. The markup's nesting doesn't
   change at all.

   Neither [hidden] rule needs restating here. `.stop-screen[hidden]` and
   `.stop-screen__nav[hidden]` are class + attribute, so they outrank the plain
   class selectors below whatever the source order — the opposite of the
   display:flex case above, which had to be restated because it came from an
   equally specific rule.

   The breakpoint is shared: stop-pair.js reads this same query to decide when
   to lay a postcard's two faces side by side, and the rails and the pairing
   only make sense together. Keep the two in step. */
@media (orientation: landscape) and (max-height: 620px) {
  .stop-screen {
    display: grid;
    grid-template-columns: auto 1fr auto;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
      "close stage   dl"
      "prev  stage   next"
      "prev  counter next";
    align-items: center;
    gap: 0.35rem;
    /* The bars carried the safe-area insets; with them gone the screen does.
       Landscape also puts the notch on the left or the right, which portrait
       never had to think about. */
    padding: calc(0.35rem + env(safe-area-inset-top))
             calc(0.35rem + env(safe-area-inset-right))
             calc(0.35rem + env(safe-area-inset-bottom))
             calc(0.35rem + env(safe-area-inset-left));
  }
  .stop-screen__bar,
  .stop-screen__nav { display: contents; }
  /* No room for it, and the stop's name is one tap away on the list. */
  .stop-screen__title { display: none; }
  .stop-screen__close { grid-area: close; }
  .stop-screen__dl { grid-area: dl; }
  /* Spans the two upper rows, so the card gets everything above the counter. */
  .stop-screen__stage { grid-area: stage; align-self: stretch; }
  .stop-screen__nav-btn[data-dir="-1"] { grid-area: prev; }
  .stop-screen__nav-btn[data-dir="1"] { grid-area: next; }
  .stop-screen__counter { grid-area: counter; }
  /* Arrow only, still a 44px target. The word would double each rail's width,
     and the width is the whole point of turning the phone. */
  .stop-screen__nav-btn {
    width: 44px;
    padding: 0;
    font-size: 1.15rem;
    line-height: 1;
  }
  .stop-screen__nav-label { display: none; }
}
