/* ============================================================
   Voyage components — soft organic eco-modern skin.
   Consumes tokens only. Class names match the design-off mockup
   (design/mockups/), which is the visual reference for this file.
   ============================================================ */

@layer components {

/* ============ layout primitives ============ */
.container {
  width: min(1120px, 100% - 2 * var(--sp-5));
  margin-inline: auto;
}

/* ============ header / nav ============ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 1100; /* above Leaflet panes/controls (which go up to ~1000) */
  background: var(--header-bg);
  border-bottom: 1px solid var(--border);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.site-header > .container {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  min-height: 68px;
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  text-decoration: none;
  margin-right: auto;
}
.brand-mark { height: 56px; width: auto; flex-shrink: 0; object-fit: contain; }
.brand-word {
  height: 56px;
  width: auto;
  color: var(--text);
  flex-shrink: 0;
  display: block;
}
@media (max-width: 768px) {
  .brand-word { height: 40px; }
}
@media (max-width: 480px) {
  .brand-word { height: 32px; }
}

.nav { display: flex; align-items: center; gap: var(--sp-1); }
.nav > li { list-style: none; position: relative; }
.nav a, .nav-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  text-decoration: none;
  color: var(--text-muted);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-full);
  font-size: var(--fs--1);
  font-weight: 600;
  background: none;
  border: none;
  transition: color var(--dur-1) var(--ease-out), background-color var(--dur-1) var(--ease-out);
}
.nav a:hover, .nav-link:hover, .nav a[aria-current="page"] {
  color: var(--text);
  background: var(--bg-inset);
}

/* dropdown menus (keyboard accessible: driven by aria-expanded) */
.nav-drop { position: relative; }
.nav-drop > .nav-link .caret { transition: transform var(--dur-1) var(--ease-out); }
.nav-drop[data-open] > .nav-link .caret { transform: rotate(180deg); }
.drop-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 220px;
  max-height: 70vh;
  overflow-y: auto;
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--r-2);
  box-shadow: var(--shadow-2);
  padding: var(--sp-2);
  list-style: none;
  margin: 0;
  display: none;
  z-index: 120;
}
.nav-drop[data-open] > .drop-menu { display: block; }
.drop-menu li { list-style: none; }
.drop-menu a, .drop-menu button {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  text-align: left;
  padding: 9px 14px;
  border-radius: var(--r-1);
  color: var(--text-muted);
  text-decoration: none;
  font-size: var(--fs--1);
  font-weight: 600;
  background: none;
  border: none;
}
.drop-menu a:hover, .drop-menu button:hover { background: var(--bg-inset); color: var(--text); }
.drop-menu img.flag { width: 20px; height: 14px; border-radius: 3px; object-fit: cover; }
.drop-menu-divider { height: 1px; background: var(--border); margin: var(--sp-1) 0; }

.header-tools { display: flex; align-items: center; gap: var(--sp-2); }

/* theme toggle */
.theme-toggle {
  position: relative;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border: 1.5px solid var(--border);
  border-radius: var(--r-full);
  background: var(--bg-inset);
  color: var(--text);
  transition: transform var(--dur-1) var(--ease-out), background-color var(--dur-2) var(--ease-out);
}
.theme-toggle:hover { transform: translateY(-1px); }
.theme-toggle svg { width: 18px; height: 18px; position: absolute; transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out); }
[data-theme="dark"]  .theme-toggle .icon-sun  { opacity: 0; transform: rotate(90deg) scale(.4); }
[data-theme="dark"]  .theme-toggle .icon-moon { opacity: 1; transform: none; }
[data-theme="light"] .theme-toggle .icon-sun  { opacity: 1; transform: none; }
[data-theme="light"] .theme-toggle .icon-moon { opacity: 0; transform: rotate(-90deg) scale(.4); }

/* mobile nav */
.mobile-nav-toggle {
  display: none;
  width: 40px; height: 40px;
  place-items: center;
  border: 1.5px solid var(--border);
  border-radius: var(--r-full);
  background: var(--bg-inset);
  color: var(--text);
}
.mobile-nav-toggle svg { width: 18px; height: 18px; }
.mobile-nav {
  display: none;
  position: absolute;
  top: 100%; left: 0; right: 0;
  background: var(--surface);
  border-bottom: 1.5px solid var(--border);
  box-shadow: var(--shadow-2);
  padding: var(--sp-3) var(--sp-5) var(--sp-5);
  z-index: 110;
}
.mobile-nav.open { display: block; }
.mobile-nav ul { list-style: none; margin: 0; padding: 0; }
.mobile-nav a, .mobile-nav button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 12px var(--sp-2);
  color: var(--text-muted);
  text-decoration: none;
  font-weight: 600;
  border: none;
  background: none;
  border-radius: var(--r-1);
}
.mobile-nav a:hover, .mobile-nav button:hover { background: var(--bg-inset); color: var(--text); }
.mobile-nav .mobile-nav-sep { border-top: 1.5px solid var(--border); margin: var(--sp-2) 0; padding-top: var(--sp-2); }
.mobile-nav .lang-row { display: flex; gap: var(--sp-3); padding: var(--sp-2); }
.mobile-nav .lang-row a { display: inline-flex; align-items: center; gap: 6px; width: auto; }
.mobile-nav img.flag { width: 20px; height: 14px; border-radius: 3px; object-fit: cover; }

/* tablets keep the full nav; the hamburger only appears on phones */
@media (max-width: 767px) {
  .nav-desktop { display: none; }
  .mobile-nav-toggle { display: grid; }
}

/* ============ buttons ============ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  border: none;
  border-radius: var(--btn-radius);
  padding: 13px 26px;
  font-weight: 700;
  font-size: var(--fs-0);
  text-decoration: none;
  transition: transform var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out), background-color var(--dur-1) var(--ease-out);
}
.btn svg { width: 17px; height: 17px; }
.btn-primary { background: var(--accent); color: var(--on-accent); box-shadow: var(--shadow-1); }
.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-2);
  background: color-mix(in srgb, var(--accent) 86%, var(--accent-2));
  color: var(--on-accent);
}
.btn-secondary {
  background: var(--bg-inset);
  color: var(--text);
  border: 1.5px solid var(--border);
}
.btn-secondary:hover { border-color: var(--border-strong); transform: translateY(-2px); }
.btn-sm { padding: 8px 18px; font-size: var(--fs--1); }

/* ============ chips ============ */
.chip-group { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.chip {
  border: 1.5px solid var(--border);
  background: var(--bg-inset);
  color: var(--text-muted);
  border-radius: var(--chip-radius);
  padding: 8px 16px;
  font-size: var(--fs--1);
  font-weight: 600;
  transition: all var(--dur-1) var(--ease-out);
}
.chip:hover { border-color: var(--border-strong); color: var(--text); }
.chip[aria-pressed="true"], .chip.is-active {
  background: var(--accent);
  color: var(--on-accent);
  border-color: transparent;
  box-shadow: var(--shadow-1);
}

/* ============ fields / forms ============ */
.field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.field label {
  font-size: var(--fs--2);
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-subtle);
}
.field input, .field select, .field textarea {
  background: var(--bg-inset);
  border: 1.5px solid var(--border);
  border-radius: var(--input-radius);
  padding: 12px 14px;
  font-size: var(--fs-0);
  width: 100%;
  transition: border-color var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out);
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--focus-ring) 30%, transparent);
}
.field .errors { color: var(--danger); font-size: var(--fs--1); }
.field .help { color: var(--text-subtle); font-size: var(--fs--2); }
.field--error input, .field--error select, .field--error textarea { border-color: var(--danger); }
.field input[type="checkbox"], .field input[type="radio"],
.check-row input { accent-color: var(--accent); width: 16px; height: 16px; }
.check-row {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs--1);
  color: var(--text-muted);
}

/* ============ cards ============ */
.card {
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--card-radius);
  box-shadow: var(--shadow-1);
  padding: var(--sp-6);
}
.card--hover { transition: transform var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out); }
.card--hover:hover { transform: translateY(-4px); box-shadow: var(--shadow-2); border-color: var(--border-strong); }

/* ============ labels / badges ============ */
.label {
  display: inline-block;
  font-size: var(--fs--2);
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 12px;
  border-radius: var(--label-radius);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  color: var(--accent);
}
.label--night,
.label--overnight { background: color-mix(in srgb, var(--mode-sleeper) 18%, transparent); color: var(--mode-sleeper); }
.label--ferry  { background: color-mix(in srgb, var(--mode-ferry) 18%, transparent); color: var(--mode-ferry); }
.label--green  { background: color-mix(in srgb, var(--co2-good) 18%, transparent); color: var(--co2-good); }
.label--flight { background: var(--bg-inset); color: var(--text-subtle); }

/* ============ option card (journey result) ============ */
.option-card {
  position: relative;
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--card-radius);
  padding: var(--sp-5) var(--sp-6);
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--sp-3) var(--sp-6);
  box-shadow: var(--shadow-1);
  transition: transform var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out);
  cursor: pointer;
}
.option-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-2); border-color: var(--border-strong); }
.option-card.is-selected {
  border-color: var(--accent);
  box-shadow: 0 0 0 1.5px var(--accent), var(--shadow-2);
}
.option-main { min-width: 0; }
.option-labels { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-3); flex-wrap: wrap; }

.option-times { display: flex; align-items: center; gap: var(--sp-4); }
.option-times .t {
  font-size: var(--fs-3);
  font-weight: 700;
  font-family: var(--font-numeric);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.option-times .t small { display: block; font-size: var(--fs--2); font-weight: 600; color: var(--text-subtle); }
.plus-day { font-size: 0.55em; vertical-align: super; color: var(--accent); font-weight: 800; }

/* dep ──○──○──→ arr strip (pure CSS: cannot distort) */
.route-strip {
  position: relative;
  flex: 1;
  min-width: 90px;
  height: 14px;
  color: var(--text-subtle);
}
.route-strip::before {
  content: "";
  position: absolute;
  left: 0; right: 7px; top: 50%;
  height: 2px;
  transform: translateY(-50%);
  background: currentColor;
  border-radius: 1px;
}
.route-strip--dashed::before {
  background: repeating-linear-gradient(90deg, currentColor 0 6px, transparent 6px 12px);
}
.route-strip::after {
  content: "";
  position: absolute;
  right: 1px; top: 50%;
  width: 8px; height: 8px;
  border-top: 2px solid currentColor;
  border-right: 2px solid currentColor;
  transform: translateY(-50%) rotate(45deg);
}
.route-strip i {
  position: absolute;
  top: 50%;
  width: 10px; height: 10px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid currentColor;
}

.option-stats {
  display: flex;
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
  flex-wrap: wrap;
  margin-top: var(--sp-3);
  font-size: var(--fs--1);
  color: var(--text-muted);
}
.option-stats .stat { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.option-stats svg { width: 14px; height: 14px; color: var(--text-subtle); flex: none; }
.stat--good {
  color: var(--co2-good);
  font-weight: 700;
  background: color-mix(in srgb, var(--co2-good) 13%, transparent);
  border-radius: var(--r-full);
  padding: 3px 12px;
}
.stat--good svg { color: var(--co2-good); }
.stat--bad { color: var(--danger); font-weight: 700; }
.stat--bad svg { color: var(--danger); }

.option-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-3);
}
/* Price block — see priceBlockHtml in planner.js. Sits at the top of the card's side column so it
   reads as one of the headline facts about an option, not a footnote among the stats. */
.option-price {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
  text-align: right;
  line-height: 1.1;
  /* A floor width so amounts right-align into one column down the list. With tabular figures that
     makes prices directly comparable by eye, which is the whole reason someone scans this list. */
  min-width: 5.5rem;
}
.option-price .amount {
  font-size: var(--fs-3);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--text);          /* contrast, not colour: green would blend into the CO2 pill */
  letter-spacing: -0.02em;
}
.option-price .src {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.64rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-subtle);
  white-space: nowrap;
}
.option-price .src svg { width: 11px; height: 11px; }
/* Green earns its place here — on the confirmation, not on the number. */
.option-price--live .src { color: var(--co2-good); }
.option-price--live .src svg { color: var(--co2-good); }

/* An estimated figure is computed, not quoted. It keeps the precision of a number but wears the
   muted colour and lighter weight of an estimate, so only a fare someone can actually be charged
   gets the full-contrast treatment. */
.option-price--estimate .amount {
  color: var(--text-muted);
  font-weight: 700;
  font-size: var(--fs-2);
}

@media (max-width: 880px) {
  /* Side column goes horizontal on narrow screens, so the price sits beside the mode icons. */
  .option-price { align-items: flex-start; text-align: left; }
}

.mode-icons { display: flex; gap: var(--sp-2); }
.mode-icons span {
  width: 28px; height: 28px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--bg-inset);
}
.mode-icons svg { width: 15px; height: 15px; }
.mi-rail    svg { color: var(--mode-rail); }
.mi-hs      svg { color: var(--accent); }
.mi-sleeper svg { color: var(--mode-sleeper); }
.mi-ferry   svg { color: var(--mode-ferry); }
.mi-bus     svg { color: var(--mode-bus); }
.mi-walk    svg { color: var(--mode-walk); }

.confirmed { display: inline-flex; align-items: center; gap: 5px; font-size: var(--fs--2); color: var(--success); font-weight: 600; }
.confirmed svg { width: 13px; height: 13px; }

.option-card--flight { opacity: 0.85; cursor: default; }
.option-card--flight:hover { transform: none; box-shadow: var(--shadow-1); border-color: var(--border); }
.option-card--flight .option-times .t { color: var(--text-muted); }

@media (max-width: 880px) {
  .option-card { grid-template-columns: 1fr; }
  .option-side { flex-direction: row; align-items: center; }
}

/* ============ journey timeline ============ */
.timeline {
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--card-radius);
  padding: var(--sp-6);
  box-shadow: var(--shadow-1);
}
.leg {
  display: grid;
  grid-template-columns: 74px 26px 1fr;
  gap: 0 var(--sp-4);
}
.leg-times {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  text-align: right;
  padding-block: 2px;
  color: var(--text);
}
.leg-times .num { display: block; font-weight: 700; font-size: var(--fs-0); }
.leg-times .num.dim { color: var(--text-subtle); }

.leg-rail { position: relative; display: flex; flex-direction: column; align-items: center; }
.leg-rail::before {
  content: "";
  position: absolute;
  top: 9px; bottom: -9px;
  width: 4px;
  border-radius: 4px;
  background: var(--leg-color, var(--mode-rail));
}
.leg--dashed .leg-rail::before {
  background: repeating-linear-gradient(to bottom, var(--leg-color, var(--mode-walk)) 0 5px, transparent 5px 10px);
}
.leg-rail .dot {
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--surface);
  border: 3px solid var(--leg-color, var(--mode-rail));
  z-index: 1;
  margin-top: 3px;
}
.leg:last-child .leg-rail::before { bottom: 9px; }
.leg:last-child .leg-rail::after {
  content: "";
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--leg-color, var(--mode-rail));
  border: 3px solid var(--leg-color, var(--mode-rail));
  position: absolute; bottom: 3px; z-index: 1;
}

.leg--rail    { --leg-color: var(--mode-rail); }
.leg--hs      { --leg-color: var(--accent); }
.leg--sleeper { --leg-color: var(--mode-sleeper); }
.leg--ferry   { --leg-color: var(--mode-ferry); }
.leg--walk    { --leg-color: var(--mode-walk); }
.leg--metro   { --leg-color: var(--mode-rail); }
.leg--transfer{ --leg-color: var(--mode-bus); }
.leg--bus     { --leg-color: var(--mode-bus); }

.leg-body { padding-bottom: var(--sp-6); min-width: 0; }
.leg:last-child .leg-body { padding-bottom: 0; }
.leg-station { font-weight: 700; font-size: var(--fs-0); }
.leg-service {
  display: flex; align-items: center; gap: var(--sp-2);
  margin: var(--sp-2) 0;
  font-size: var(--fs--1);
  color: var(--text-muted);
  flex-wrap: wrap;
}
.leg-service svg { width: 14px; height: 14px; color: var(--leg-color, var(--mode-rail)); }
.leg-service .svc { font-weight: 700; color: var(--text); }
.leg-meta { font-size: var(--fs--2); color: var(--text-subtle); }
.leg--metro .leg-meta { color: var(--text-muted); margin-top: 2px; }
.leg-note {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: var(--sp-2);
  font-size: var(--fs--2);
  color: var(--text-muted);
  background: var(--bg-inset);
  border-radius: var(--r-full);
  padding: 4px 12px;
}
.leg-note svg { width: 12px; height: 12px; color: var(--text-subtle); }
.leg-arrive .leg-station { font-size: var(--fs-1); }

/* Real All Aboard price for one leg, reused from a different option's fetch — see
   requestSegmentPrice/segmentPriceHtml in planner.js. Same pill shape as .leg-note but in the
   "real price" green, so it reads as a confirmed fact rather than routine trip detail. */
.leg-segment-price {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: var(--sp-2);
  font-size: var(--fs--2);
  font-weight: 700;
  color: var(--co2-good);
  background: var(--bg-inset);
  border-radius: var(--r-full);
  padding: 4px 12px;
}
.leg-segment-price svg { width: 12px; height: 12px; color: var(--co2-good); }

/* Same pill, but while the fare is still being fetched: neutral rather than green, because
   nothing is confirmed yet. */
.leg-segment-price--loading { color: var(--text-subtle); font-weight: 600; }

/* And the same pill for the engine's own per-section estimate, which is what most legs show most
   of the time. Muted and tilde-prefixed: the green pill above means "this is what it costs", this
   one means "this is roughly what it costs", and the two must never be confused at a glance. */
.leg-segment-price--estimate { color: var(--text-muted); font-weight: 600; }

/* "Retrieving price from X" — shown in the detail panel and in a leg pill while an All Aboard
   offer call is in flight. Those calls are documented at up to 30s, so an unexplained pause is
   the norm rather than the exception; naming the operator says who we're waiting on. */
.price-loading {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--text-subtle);
  font-weight: 600;
}
/* .spinner--inline lives in pages/planner.css, immediately after the .spinner base it modifies —
   planner.css loads after this file, so defining it here would let .spinner's own 48px size win. */

/* ---- later-connection explorer (rendered under a transfer leg) ---- */
.leg-alt {
  margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-left: 3px solid var(--leg-color, var(--mode-rail));
  border-radius: var(--r-2);
  background: var(--bg-inset);
  font-size: var(--fs--2);
}
.leg-alt--pending,
.leg-alt--none {
  border-left-color: var(--border);
  color: var(--text-subtle);
  display: flex; align-items: center; gap: 6px;
}
.leg-alt--guaranteed {
  border-left-color: var(--success);
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 500;
}
.leg-alt--guaranteed svg {
  width: 14px;
  height: 14px;
  color: var(--success);
  flex-shrink: 0;
}
.leg-alt--none svg { width: 12px; height: 12px; }
.leg-alt-line {
  display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap;
  color: var(--text-muted);
}
.leg-alt-label { font-weight: 700; color: var(--text); }
.leg-alt-line .num { font-weight: 700; color: var(--text); }
.leg-alt-line .svc { font-weight: 700; color: var(--text); }
.leg-alt-delay { color: var(--text-subtle); }
.leg-alt-ticket { margin-top: 4px; font-weight: 600; }
.leg-alt-ticket--valid   { color: var(--success); }
.leg-alt-ticket--invalid { color: var(--danger); }
.leg-alt-ticket--unknown { color: var(--warn); }
/* The block's primary action. Follows the .btn idiom (pill, weight 700, lift on
   hover) at the smaller scale the timeline needs, and borrows the leg's mode
   colour so the button reads as belonging to that connection. */
.leg-alt-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: var(--sp-3);
  padding: 7px 15px 7px 13px;
  font: inherit;
  font-size: var(--fs--2);
  font-weight: 700;
  line-height: 1.1;
  color: var(--leg-color, var(--mode-rail));
  background: var(--surface);
  border: 1.5px solid color-mix(in srgb, var(--leg-color, var(--mode-rail)) 40%, transparent);
  border-radius: var(--r-full);
  cursor: pointer;
  transition: transform var(--dur-1) var(--ease-out),
              box-shadow var(--dur-1) var(--ease-out),
              background-color var(--dur-1) var(--ease-out),
              border-color var(--dur-1) var(--ease-out),
              color var(--dur-1) var(--ease-out);
}
.leg-alt-btn svg {
  width: 14px; height: 14px;
  flex-shrink: 0;
  transition: transform var(--dur-2) var(--ease-spring);
}
.leg-alt-btn:hover {
  color: var(--on-accent);
  background: var(--leg-color, var(--mode-rail));
  border-color: transparent;
  transform: translateY(-2px);
  box-shadow: var(--shadow-1);
}
/* The swap arrows trade places — a small nod to what the button does. */
.leg-alt-btn:hover svg { transform: rotate(180deg); }
.leg-alt-btn:active { transform: translateY(0); box-shadow: none; }
.leg-alt-btn:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

/* The revert action is deliberately quieter than the one that got you here:
   an outline that only fills on hover, and no mode colour to compete with. */
.leg-alt-btn--ghost {
  margin-top: 0;
  color: var(--text-muted);
  background: transparent;
  border-color: var(--border-strong);
}
.leg-alt-btn--ghost:hover {
  color: var(--text);
  background: var(--surface);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-1);
}
.leg-alt-btn--ghost:hover svg { transform: rotate(-30deg); }

.detail-variant {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
  margin: var(--sp-3) 0;
  padding: var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-4);
  border-radius: var(--r-full);
  background: var(--bg-inset);
  border: 1.5px solid var(--border);
  font-size: var(--fs--1);
  color: var(--text-muted);
}
.detail-variant-label {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-weight: 600;
}
.detail-variant-label svg {
  width: 14px; height: 14px;
  flex-shrink: 0;
  color: var(--accent);
}

@media (prefers-reduced-motion: reduce) {
  .leg-alt-btn, .leg-alt-btn svg { transition: none; }
  .leg-alt-btn:hover { transform: none; }
  .leg-alt-btn:hover svg { transform: none; }
}

@media (max-width: 880px) {
  .leg { grid-template-columns: 56px 22px 1fr; }
}

/* ============ hero ============ */
.hero { position: relative; overflow: hidden; background: var(--hero-bg); }
.hero::before, .hero::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  filter: blur(70px);
  pointer-events: none;
}
.hero::before {
  width: 480px; height: 480px;
  right: -120px; top: -140px;
  background: color-mix(in srgb, var(--accent-2) 34%, transparent);
}
.hero::after {
  width: 380px; height: 380px;
  left: -140px; bottom: -180px;
  background: color-mix(in srgb, var(--accent) 22%, transparent);
}
@media (prefers-reduced-motion: no-preference) {
  .hero::before { animation: blob-drift 14s ease-in-out infinite alternate; }
  .hero::after { animation: blob-drift 18s ease-in-out infinite alternate-reverse; }
  @keyframes blob-drift { to { transform: translate(30px, 24px) scale(1.08); } }
}

.hero-inner {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 4fr);
  gap: var(--sp-7);
  align-items: center;
  padding-block: var(--sp-9) var(--sp-8);
  position: relative;
  z-index: 1;
}
.hero-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs--2);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--sp-4);
}
.hero-eyebrow::before { content: ""; width: 28px; height: 2px; border-radius: 2px; background: currentColor; }
.hero h1 { font-size: clamp(2.5rem, 5.2vw, 3.8rem); max-width: 16ch; }
.hero h1 em { font-style: normal; color: var(--accent); }
.hero-sub {
  margin: var(--sp-5) 0 var(--sp-6);
  max-width: 44ch;
  font-size: var(--fs-1);
  color: var(--text-muted);
}

/* animated rail-map art */
.hero-art { position: relative; }
.hero-art svg { width: 100%; height: auto; color: var(--text-subtle); }

/* ---- live network animation ---- */
/* The stage carries the aspect ratio so the canvases have a height to size
   against; the readout sits below it in normal flow rather than floating over
   the map, where it collided with the dots it describes. */
/* Always laid out, never display:none — the canvases size themselves against
   it, so hiding it until the animation starts would leave them 0x0 and the
   animation could never start. */
.hero-art__stage {
  position: relative;
  aspect-ratio: 520 / 420;
}

.hero-art__layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 1;
  pointer-events: none;
}

/* readout clock & info */
.hero-art__readout {
  position: relative;          /* anchor for the info panel */
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-top: var(--sp-2);
  visibility: visible;
  opacity: 1;
}

.hero-art__clock {
  font-size: var(--fs-3);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  color: var(--text);
}

.hero-art__info {
  display: inline-grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 0;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--text-subtle);
  cursor: pointer;
  pointer-events: auto;
  transition: color var(--dur-1, 150ms) var(--ease-out, ease),
              background var(--dur-1, 150ms) var(--ease-out, ease);
}
.hero-art__info svg { width: 1.05rem; height: 1.05rem; }
.hero-art__info:hover,
.hero-art__info[aria-expanded="true"] {
  color: var(--text);
  background: color-mix(in srgb, var(--text) 8%, transparent);
}
.hero-art__info:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.hero-art__panel {
  position: absolute;
  left: 0;
  bottom: calc(100% + var(--sp-2));
  z-index: 3;
  width: min(20rem, 100%);
  padding: var(--sp-4);
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--r-2);
  box-shadow: var(--shadow-2);
  pointer-events: auto;
  text-align: left;
}
.hero-art__panel[hidden] { display: none; }
.hero-art__panel-text {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs--1);
  line-height: 1.5;
  color: var(--text-muted);
}
.hero-art__legend {
  display: grid;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs--1);
  color: var(--text);
}
.hero-art__legend li { display: flex; align-items: center; gap: var(--sp-2); }
.hero-art__legend i {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: var(--r-full);
  flex: none;
}

/* Map palette. The coastline is deliberately faint — it is a ground for the
   dots to move over, not a thing to read. */
.hero-art {
  --live-coast: color-mix(in srgb, var(--text) 22%, transparent);
  --live-rail: var(--accent);
  --live-night: #8b6bb1;
  --live-ferry: var(--mode-ferry);
}
[data-theme="dark"] .hero-art {
  --live-coast: color-mix(in srgb, var(--text) 16%, transparent);
  --live-night: #b9a0e0;
}

@media (max-width: 880px) {
  .hero-inner { grid-template-columns: 1fr; padding-block: var(--sp-7) var(--sp-6); }
  .hero-art { max-width: 480px; }
}

/* ============ auth card (login/register/reset) ============ */
.auth-section { display: grid; place-items: center; padding: var(--sp-8) 0; position: relative; }
.auth-card {
  width: min(440px, 100%);
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--card-radius);
  box-shadow: var(--shadow-2);
  padding: var(--sp-7) var(--sp-6);
}
.auth-card h1 { font-size: var(--fs-3); margin-bottom: var(--sp-5); }

/* ============ photo attribution pill ============ */
.hero-attribution {
  position: absolute;
  right: var(--sp-4); bottom: var(--sp-4);
  z-index: 2;
  font-size: var(--fs--2);
  color: #fff;
  background: rgba(0, 0, 0, 0.45);
  border-radius: var(--r-full);
  padding: 4px 12px;
  backdrop-filter: blur(4px);
}
.hero-attribution a { color: #fff; }

/* ============ Leaflet skin ============ */
.leaflet-container { font-family: var(--font-body); border-radius: var(--card-radius); }
.leaflet-popup-content-wrapper {
  background: var(--surface);
  color: var(--text);
  border-radius: var(--r-2);
  box-shadow: var(--shadow-2);
  border: 1.5px solid var(--border);
}
.leaflet-popup-tip { background: var(--surface); }
.voyage-tooltip {
  background: var(--surface);
  color: var(--text);
  border: 1.5px solid var(--border);
  border-radius: var(--r-full);
  box-shadow: var(--shadow-1);
  font-family: var(--font-body);
  font-weight: 600;
  padding: 2px 10px;
}
.voyage-tooltip::before { display: none; }

.marker-cluster div {
  background: color-mix(in srgb, var(--accent) 80%, var(--surface));
  color: var(--on-accent);
  font-weight: 700;
  font-family: var(--font-body);
  border-radius: 50%;
}
.marker-cluster {
  background: color-mix(in srgb, var(--accent) 30%, transparent);
  border-radius: 50%;
}

/* ============ reveal motion states ============ */
[data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--dur-3) var(--ease-out), transform var(--dur-3) var(--ease-out);
  transition-delay: calc(var(--i, 0) * 60ms);
}
[data-reveal].is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; }
}
/* no-JS safety: motion.js adds .js to <html>; without it nothing hides */
html:not(.js) [data-reveal] { opacity: 1; transform: none; }

/* ============ footer ============ */
.site-footer {
  border-top: 1.5px solid var(--border);
  background: var(--footer-bg);
  padding-block: var(--sp-6);
  font-size: var(--fs--1);
  color: var(--text-subtle);
  margin-top: auto;
}
.site-footer .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
}
.footer-brand-wrap {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  flex-wrap: wrap;
}
.footer-contact {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs--2);
}
.footer-contact-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--text-muted);
  text-decoration: none;
  transition: color var(--transition);
}
.footer-contact-link:hover {
  color: var(--accent);
}
.footer-contact-link svg {
  width: 13px;
  height: 13px;
  opacity: 0.8;
}
.footer-sep {
  opacity: 0.4;
}
.footer-links { display: flex; gap: var(--sp-4); list-style: none; margin: 0; padding: 0; flex-wrap: wrap; }
.footer-links a { color: var(--text-subtle); text-decoration: none; }
.footer-links a:hover { color: var(--text); }
.footer-brand { display: flex; align-items: center; gap: var(--sp-2); font-weight: 700; color: var(--text-muted); }
.footer-brand svg, .footer-brand img { width: 20px; height: 20px; flex-shrink: 0; object-fit: contain; }

/* ============ cookie consent banner ============ */
.cookie-banner {
  position: fixed;
  bottom: var(--sp-4);
  left: 50%;
  transform: translateX(-50%);
  width: min(1080px, calc(100% - 2 * var(--sp-4)));
  z-index: 1200;
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--card-radius);
  box-shadow: var(--shadow-3);
  padding: var(--sp-4) var(--sp-5);
  animation: cookieSlideUp var(--dur-2) var(--ease-out);
}
.cookie-banner[hidden] {
  display: none !important;
}

@keyframes cookieSlideUp {
  from {
    opacity: 0;
    transform: translate(-50%, 20px);
  }
  to {
    opacity: 1;
    transform: translate(-50%, 0);
  }
}

.cookie-banner-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  flex-wrap: wrap;
  width: 100%;
}

.cookie-banner-content {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  flex: 1 1 500px;
}

.cookie-banner-icon {
  width: 36px;
  height: 36px;
  border-radius: var(--r-full);
  background: var(--bg-inset);
  color: var(--accent);
  display: grid;
  place-items: center;
  flex-shrink: 0;
  margin-top: 2px;
}

.cookie-banner-text h4 {
  margin: 0 0 2px;
  font-size: var(--fs-0);
  font-weight: 700;
  color: var(--text);
}

.cookie-banner-text p {
  margin: 0;
  font-size: var(--fs--1);
  color: var(--text-muted);
  line-height: 1.45;
}

.cookie-banner-text a {
  color: var(--accent);
  text-decoration: underline;
  font-weight: 600;
}

.cookie-banner-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-shrink: 0;
}

@media (max-width: 640px) {
  .cookie-banner {
    bottom: var(--sp-2);
    padding: var(--sp-3) var(--sp-4);
  }
  .cookie-banner-container {
    flex-direction: column;
    align-items: stretch;
    gap: var(--sp-3);
  }
  .cookie-banner-actions {
    justify-content: flex-end;
    width: 100%;
  }
  .cookie-banner-actions button {
    flex: 1;
  }
}

/* ============ Beta announcement banner ============ */
.beta-banner {
  background: var(--bg-inset);
  border-bottom: 1px solid var(--border);
  color: var(--text);
  font-size: var(--fs--1);
  line-height: 1.4;
  position: relative;
  z-index: 1101; /* above site-header */
}

.beta-banner-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding-top: var(--sp-2);
  padding-bottom: var(--sp-2);
}

.beta-banner-content {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
}

.beta-pill {
  display: inline-flex;
  align-items: center;
  font-size: var(--fs--2);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--accent);
  color: var(--on-accent);
  padding: 2px 8px;
  border-radius: var(--chip-radius);
  flex-shrink: 0;
}

.beta-banner-text {
  margin: 0;
  color: var(--text-muted);
}

.beta-banner-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text-subtle);
  border-radius: var(--r-full);
  cursor: pointer;
  flex-shrink: 0;
  transition: color var(--dur-1) var(--ease-out), background-color var(--dur-1) var(--ease-out);
}

.beta-banner-close:hover {
  color: var(--text);
  background: var(--surface);
}

.beta-banner-close:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 1px;
}

@media (max-width: 640px) {
  .beta-banner-container {
    align-items: flex-start;
  }
  .beta-banner-content {
    flex: 1;
    gap: var(--sp-2);
  }
  .beta-banner-text {
    font-size: var(--fs--2);
  }
}

/* ============================================================
   Toast notifications — non-blocking feedback messages
   ============================================================ */
.voyage-toast-container {
  position: fixed;
  bottom: var(--sp-6);
  left: 50%;
  transform: translateX(-50%);
  z-index: 9999;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
  pointer-events: none;
  max-width: min(90vw, 460px);
  width: 100%;
  padding-inline: var(--sp-3);
}

.voyage-toast {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-2);
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-2);
  font-size: var(--fs--1);
  line-height: 1.4;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  animation: voyageToastIn var(--dur-2) var(--ease-spring);
  transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out);
}

.voyage-toast.is-hiding {
  opacity: 0;
  transform: translateY(12px) scale(0.95);
  pointer-events: none;
}

.voyage-toast-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.voyage-toast--error .voyage-toast-icon {
  color: var(--danger);
}
.voyage-toast--error {
  border-color: color-mix(in srgb, var(--danger) 35%, var(--border));
}

.voyage-toast--warn .voyage-toast-icon {
  color: var(--warn);
}
.voyage-toast--warn {
  border-color: color-mix(in srgb, var(--warn) 35%, var(--border));
}

.voyage-toast--success .voyage-toast-icon {
  color: var(--success);
}
.voyage-toast--success {
  border-color: color-mix(in srgb, var(--success) 35%, var(--border));
}

.voyage-toast--info .voyage-toast-icon {
  color: var(--accent);
}
.voyage-toast--info {
  border-color: color-mix(in srgb, var(--accent) 35%, var(--border));
}

.voyage-toast-message {
  flex: 1;
  min-width: 0;
  word-break: break-word;
}

.voyage-toast-close {
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-subtle);
  border-radius: var(--r-full);
  padding: 4px;
  flex-shrink: 0;
  transition: color var(--dur-1) var(--ease-out), background-color var(--dur-1) var(--ease-out);
}

.voyage-toast-close:hover {
  color: var(--text);
  background: var(--bg-inset);
}

.voyage-toast-close:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 1px;
}

@keyframes voyageToastIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.96);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

} /* @layer components */
