/* ── tab-bar ────────────────────────────────────────────────────────────────── */
/* Floating pill everywhere — bottom-centre on phones, moved inside the
   header on tablet/desktop (see the 900px block below). Stays
   position:fixed at every size (not nested in .app-header) so it never
   depends on the header's own stacking context. */
tab-bar {
  position: fixed;
  left: 50%;
  bottom: calc(var(--sp-4) + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 100;
  display: inline-flex;
  gap: var(--sp-1);
  padding: var(--sp-2);
  border: 1px solid var(--color-border);
  border-radius: var(--r-pill);
  background: var(--color-background);
  background: color-mix(in srgb, var(--color-background) 82%, transparent);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
}

.tab-bar-item {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: var(--sp-2) var(--sp-3);
  background: none;
  border: none;
  border-radius: var(--r-pill);
  font-family: var(--font);
  color: var(--color-text-secondary);
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.tab-bar-icon  { display: block; line-height: 1; }
.tab-bar-icon svg { width: 1.25rem; height: 1.25rem; display: block; }
.tab-bar-label { font-size: 0.6875rem; font-weight: var(--fw-semibold); }

.tab-bar-item:hover                 { background: var(--color-surface); }
.tab-bar-item[aria-selected="true"] { color: var(--color-primary); background: var(--color-accent); }
.tab-bar-item:focus-visible {
  outline: 2px solid var(--color-slope-blue);
  outline-offset: -2px;
}

/* On tablet/desktop the bottom edge is too easy to miss, so the pill leaves
   the bottom dock and moves inside the header instead, mirroring the
   live-temperature badge's placement on the opposite side. */
@media (min-width: 900px) {
  tab-bar {
    left: var(--sp-4);
    bottom: auto;
    top: var(--sp-4);
    transform: none;
    z-index: 160; /* above .app-header (150) */
    transition: top 0.25s ease, padding 0.25s ease;
  }

  /* Shrink and re-centre alongside the header's own compact state. */
  .app-header--compact ~ tab-bar {
    top: var(--sp-2);
    padding: var(--sp-1);
  }

  .tab-bar-item {
    flex-direction: row;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-4);
    transition: background-color 0.15s ease, color 0.15s ease, padding 0.25s ease;
  }

  .app-header--compact ~ tab-bar .tab-bar-item {
    padding: var(--sp-1) var(--sp-3);
  }

  .tab-bar-label { font-size: 0.8125rem; }
}

/* In a WCO desktop PWA window, keep the pill clear of native chrome drawn on
   the titlebar's left edge (e.g. macOS traffic-light buttons) — see the
   matching .app-header rule in layout.css for the right edge. */
@media (display-mode: window-controls-overlay) and (min-width: 900px) {
  tab-bar {
    left: max(var(--sp-4), env(titlebar-area-x, var(--sp-4)));
  }
}

/* ── location-gate ─────────────────────────────────────────────────────────── */
location-gate { display: block; }
location-gate[hidden] { display: none; }

.location-gate-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  padding: var(--sp-5) var(--sp-4);
  text-align: center;
}

.location-gate-text {
  font-size: 0.9375rem;
  color: var(--color-text);
  margin-bottom: var(--sp-4);
}

.location-gate-actions {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.location-gate-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  text-align: left;
}

.location-gate-option {
  width: 100%;
  padding: var(--sp-3) var(--sp-4);
  font-family: var(--font);
  font-size: 0.9375rem;
  font-weight: var(--fw-semibold);
  color: var(--color-text);
  background: var(--color-background);
  border: 1px solid var(--color-border);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: border-color 0.15s;
}
.location-gate-option:hover { border-color: var(--color-primary); }

/* ── weather-hero ──────────────────────────────────────────────────────────── */
weather-hero { display: block; }
weather-hero[hidden] { display: none; }

.hero-card {
  background: var(--color-hero-bg);
  color: var(--color-hero-text);
  border-radius: var(--r-lg);
  padding: var(--sp-5) var(--sp-5) var(--sp-4);
}

.hero-card--loading {
  height: 220px;
  animation: pulse 1.4s ease-in-out infinite;
}

.hero-card--empty {
  text-align: center;
  color: var(--color-hero-text);
  opacity: 0.85;
  padding: var(--sp-8) var(--sp-4);
}

.hero-top {
  display: flex;
  align-items: center;
  margin-bottom: var(--sp-4);
}

.hero-live {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-family: var(--font);
  font-size: 0.8125rem;
  font-weight: var(--fw-semibold);
  color: var(--color-hero-text);
  background: none;
  border: none;
  padding: 0;
  opacity: 0.9;
  cursor: pointer;
}
.hero-live:hover { opacity: 1; }
.hero-live:focus-visible {
  outline: 2px solid var(--color-hero-text);
  outline-offset: 2px;
}

.hero-live-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-status-open);
  flex-shrink: 0;
}

.hero-place {
  font-size: 1.5rem;
  font-weight: var(--fw-bold);
  margin-bottom: var(--sp-1);
}

.hero-sub {
  font-size: 0.875rem;
  opacity: 0.85;
  margin-bottom: var(--sp-5);
}

.hero-temp-row {
  display: flex;
  align-items: baseline;
  gap: var(--sp-4);
  margin-bottom: var(--sp-5);
}

.hero-temp {
  font-size: 3rem;
  font-weight: var(--fw-bold);
  line-height: 1;
}

.hero-feels {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 0.875rem;
}
.hero-feels strong { font-weight: var(--fw-semibold); }
.hero-feels span   { opacity: 0.85; }

.hero-avalanche-block {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  border-radius: var(--r-md);
  padding: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-4);
}

.hero-avalanche-icon {
  flex-shrink: 0;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: var(--r-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9375rem;
}

/* Avalanche danger level 1-5 — official EAWS colours, see --color-avalanche-* in base.css */
.hero-avalanche-block[data-level="1"] { background: color-mix(in srgb, var(--color-avalanche-1) 22%, transparent); }
.hero-avalanche-block[data-level="2"] { background: color-mix(in srgb, var(--color-avalanche-2) 22%, transparent); }
.hero-avalanche-block[data-level="3"] { background: color-mix(in srgb, var(--color-avalanche-3) 20%, transparent); }
.hero-avalanche-block[data-level="4"] { background: color-mix(in srgb, var(--color-avalanche-4) 26%, transparent); }
.hero-avalanche-block[data-level="5"] { background: color-mix(in srgb, var(--color-avalanche-5) 32%, transparent); }

.hero-avalanche-block[data-level="1"] .hero-avalanche-icon { background: var(--color-avalanche-1); color: var(--color-on-avalanche-1); }
.hero-avalanche-block[data-level="2"] .hero-avalanche-icon { background: var(--color-avalanche-2); color: var(--color-on-avalanche-2); }
.hero-avalanche-block[data-level="3"] .hero-avalanche-icon { background: var(--color-avalanche-3); color: var(--color-on-avalanche-3); }
.hero-avalanche-block[data-level="4"] .hero-avalanche-icon { background: var(--color-avalanche-4); color: var(--color-on-avalanche-4); }
.hero-avalanche-block[data-level="5"] .hero-avalanche-icon { background: var(--color-avalanche-5); color: var(--color-on-avalanche-5); }

.hero-avalanche-block strong {
  display: block;
  font-size: 0.875rem;
  font-weight: var(--fw-bold);
}
.hero-avalanche-block span {
  font-size: 0.75rem;
  opacity: 0.85;
}

.hero-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-2);
}

.hero-stat {
  background: rgba(255, 255, 255, 0.12);
  border-radius: var(--r-md);
  padding: var(--sp-2) var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.hero-stat-label {
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: 0.6875rem;
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  opacity: 0.8;
}

.hero-icon { display: inline-flex; }
.hero-icon svg { width: 1em; height: 1em; display: block; }

.hero-stat-value {
  font-size: 0.9375rem;
  font-weight: var(--fw-bold);
}

.hero-updated {
  font-size: 0.75rem;
  opacity: 0.7;
  margin-top: var(--sp-3);
}

.hero-toggle {
  display: block;
  width: 100%;
  font-family: var(--font);
  color: inherit;
  background: none;
  border: none;
  padding: 0;
  text-align: left;
  cursor: pointer;
}
.hero-toggle:focus-visible {
  outline: 2px solid var(--color-hero-text);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* ── Shared chevron ────────────────────────────────────────────────────────
   Every expand/collapse/dropdown chevron in the app uses ICONS.chevronDown
   at this size and opacity (the weather card's chevron is the reference).
   Native <select> arrows are replaced with the same glyph via
   --select-chevron in base.css. Layout (position, margins) stays with each
   component's own class. */
.chevron {
  display: inline-flex;
  flex-shrink: 0;
  font-size: 1.375rem;
  opacity: 0.6;
  transition: transform 0.2s ease;
}
.chevron svg { width: 1em; height: 1em; display: block; }
.chevron--up { transform: rotate(180deg); }

.hero-chevron {
  display: flex;
  width: 100%;
  justify-content: center;
  margin-top: var(--sp-3);
}

/* ── Collapsed hero card ───────────────────────────────────────────────────
   A slim single-row strip — the real use case is route search below it, so
   this should read at a glance and get out of the way, not compete for
   attention with a full card. */
.hero-card--collapsed {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
}

.hero-dot-btn {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}
.hero-dot-btn:focus-visible {
  outline: 2px solid var(--color-hero-text);
  outline-offset: 2px;
  border-radius: 50%;
}

.hero-toggle--collapsed {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0; /* allow child truncation inside a flex row */
}

.hero-compact-place {
  flex-shrink: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.8125rem;
  font-weight: var(--fw-semibold);
  opacity: 0.9;
}

.hero-compact-temp {
  flex-shrink: 0;
  font-size: 1.0625rem;
  font-weight: var(--fw-bold);
}

.hero-compact-snow {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  flex-shrink: 0;
  font-size: 0.8125rem;
  opacity: 0.85;
  white-space: nowrap;
}

.hero-toggle--collapsed .hero-chevron {
  width: auto;
  margin-top: 0;
  margin-left: auto;
  flex-shrink: 0;
}

.hero-avalanche-line {
  flex-shrink: 0;
  white-space: nowrap;
  font-weight: var(--fw-semibold);
  font-size: 0.8125rem;
}

.hero-vicinity-note {
  flex-shrink: 0;
  white-space: nowrap;
  opacity: 0.7;
  font-size: 0.8125rem;
}

.hero-vicinity-message {
  font-size: 0.8125rem;
  opacity: 0.85;
  margin-bottom: var(--sp-5);
}

/* Avalanche danger level 1-5 — colours the triangle glyph only; label text
   stays the hero card's default light colour for legibility on the navy card. */
.hero-avalanche-line[data-level="1"] span:first-child { color: var(--color-avalanche-1); }
.hero-avalanche-line[data-level="2"] span:first-child { color: var(--color-avalanche-2); }
.hero-avalanche-line[data-level="3"] span:first-child { color: var(--color-avalanche-3); }
.hero-avalanche-line[data-level="4"] span:first-child { color: var(--color-avalanche-4); }
.hero-avalanche-line[data-level="5"] span:first-child { color: var(--color-avalanche-5); }

/* ── avalanche-banner ──────────────────────────────────────────────────────── */
avalanche-banner {
  display: block;
  border-radius: var(--r-lg);
  opacity: 1;
  transition: opacity 0.4s ease;
}
avalanche-banner[hidden] { display: none; }
avalanche-banner.avalanche-banner--fading { opacity: 0; }

.alert-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  list-style: none;
  margin: 0;
  padding: 0;
}

.warning-banner {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  background: var(--color-warning-bg);
  border-radius: var(--r-lg);
  padding: var(--sp-3) var(--sp-4);
}

.warning-banner--loading {
  height: 72px;
  animation: pulse 1.4s ease-in-out infinite;
}

.warning-icon-badge {
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  border-radius: var(--r-md);
  background: var(--color-warning-icon);
  color: var(--color-warning-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
}

/* Avalanche danger level 1-5 — official EAWS colours, see --color-avalanche-* in base.css */
.warning-banner[data-level="1"] { background: color-mix(in srgb, var(--color-avalanche-1) 24%, var(--color-surface)); }
.warning-banner[data-level="2"] { background: color-mix(in srgb, var(--color-avalanche-2) 24%, var(--color-surface)); }
.warning-banner[data-level="3"] { background: color-mix(in srgb, var(--color-avalanche-3) 20%, var(--color-surface)); }
.warning-banner[data-level="4"] { background: color-mix(in srgb, var(--color-avalanche-4) 18%, var(--color-surface)); }
.warning-banner[data-level="5"] { background: color-mix(in srgb, var(--color-avalanche-5) 26%, var(--color-surface)); }

.warning-banner[data-level="1"] .warning-icon-badge { background: var(--color-avalanche-1); color: var(--color-on-avalanche-1); }
.warning-banner[data-level="2"] .warning-icon-badge { background: var(--color-avalanche-2); color: var(--color-on-avalanche-2); }
.warning-banner[data-level="3"] .warning-icon-badge { background: var(--color-avalanche-3); color: var(--color-on-avalanche-3); }
.warning-banner[data-level="4"] .warning-icon-badge { background: var(--color-avalanche-4); color: var(--color-on-avalanche-4); }
.warning-banner[data-level="5"] .warning-icon-badge { background: var(--color-avalanche-5); color: var(--color-on-avalanche-5); }

.warning-body { flex: 1; min-width: 0; }
.warning-body strong {
  display: block;
  font-weight: var(--fw-bold);
  font-size: 0.9375rem;
  color: var(--color-text);
}
.warning-body p {
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
  margin-top: 2px;
}

.warning-provenance {
  font-size: 0.75rem;
  font-style: italic;
  color: var(--color-text-secondary);
}

/* ── weather-caution-list ──────────────────────────────────────────────────── */
weather-caution-list { display: block; }

.caution-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin: 0;
  padding: 0;
}

@media (min-width: 640px) {
  .alert-list,
  .caution-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-4);
  }
  /* Caution cards hold a varying number of notes; let each keep its own
     height rather than stretching to its row's tallest sibling. */
  .caution-list { align-items: start; }
}

@media (min-width: 900px) {
  .alert-list,
  .caution-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.caution-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  padding: var(--sp-4);
}
.caution-card-skeleton {
  height: 72px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  animation: pulse 1.4s ease-in-out infinite;
}

.caution-card-top {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
}
.caution-flag { font-size: 1.125rem; }
.caution-name {
  font-weight: var(--fw-bold);
  font-size: 0.9375rem;
  color: var(--color-text);
}

.caution-notes {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
}

.caution-note {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
}
.caution-icon {
  flex-shrink: 0;
  color: var(--color-warning-icon);
}
.caution-icon svg { width: 1.125rem; height: 1.125rem; display: block; }

/* ── resort-conditions-list ────────────────────────────────────────────────── */
resort-conditions-list { display: block; }

.resort-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.resort-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  padding: var(--sp-4);
}

.resort-card-top {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
}

.resort-flag { font-size: 1.125rem; }
.resort-name {
  flex: 1;
  font-weight: var(--fw-bold);
  font-size: 0.9375rem;
  color: var(--color-text);
}
.resort-elevation {
  font-size: 0.75rem;
  color: var(--color-text-secondary);
}

.resort-weather {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
  margin-bottom: var(--sp-2);
}
.resort-weather-icon { display: inline-flex; flex-shrink: 0; }
.resort-weather-icon svg { width: 1.25rem; height: 1.25rem; display: block; }

.resort-temp {
  font-size: 1.25rem;
  font-weight: var(--fw-bold);
  color: var(--color-text);
}
.resort-weather--empty { font-style: italic; }

.resort-avalanche {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
}
.resort-avalanche--empty { font-style: italic; }

.resort-ava-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--color-text-secondary);
}
.resort-avalanche[data-level="1"] .resort-ava-dot { background: var(--color-avalanche-1); }
.resort-avalanche[data-level="2"] .resort-ava-dot { background: var(--color-avalanche-2); }
.resort-avalanche[data-level="3"] .resort-ava-dot { background: var(--color-avalanche-3); }
.resort-avalanche[data-level="4"] .resort-ava-dot { background: var(--color-avalanche-4); }
.resort-avalanche[data-level="5"] .resort-ava-dot { background: var(--color-avalanche-5); }

.resort-card-skeleton {
  height: 92px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  animation: pulse 1.4s ease-in-out infinite;
}

.resort-list-empty {
  text-align: center;
  color: var(--color-text-secondary);
  font-size: 0.875rem;
  padding: var(--sp-4);
}

@media (min-width: 900px) {
  .resort-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: var(--sp-4);
  }
}

/* ── station-input ─────────────────────────────────────────────────────────── */
station-input {
  display: block;
  position: relative;
}

station-input .si-input {
  width: 100%;
  padding: var(--sp-3) var(--sp-4);
  font-family: var(--font);
  font-size: 1rem;
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-md);
  outline: none;
  transition: border-color 0.15s;
}
station-input .si-input:focus { border-color: var(--color-primary); }

station-input .si-listbox {
  position: absolute;
  inset-inline: 0;
  top: calc(100% + 4px);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-md);
  max-height: 220px;
  overflow-y: auto;
  z-index: 200;
  list-style: none;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
  overscroll-behavior: contain;
}

station-input .si-option {
  padding: var(--sp-3) var(--sp-4);
  cursor: pointer;
  font-size: 0.9375rem;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}
station-input .si-option:hover,
station-input .si-option[aria-selected="true"] {
  background: var(--color-accent);
  color: var(--color-text);
}

/* ── difficulty-selector / preference-selector / settings-panel ────────────── */
difficulty-selector,
preference-selector,
settings-panel {
  display: block;
}

difficulty-selector select,
preference-selector select,
settings-panel select {
  width: 100%;
  /* Right padding clears the 1.375rem chevron plus breathing room. */
  padding: var(--sp-3) calc(var(--sp-4) + 1.375rem + var(--sp-3)) var(--sp-3) var(--sp-4);
  font-family: var(--font);
  font-size: 1rem;
  color: var(--color-text);
  background: var(--color-surface) var(--select-chevron) no-repeat right var(--sp-4) center / 1.375rem;
  border: 1px solid var(--color-border);
  border-radius: var(--r-md);
  outline: none;
  cursor: pointer;
  appearance: none;
  transition: border-color 0.15s;
}
difficulty-selector select:focus,
preference-selector select:focus,
settings-panel select:focus { border-color: var(--color-primary); }

/* Forced-colours mode drops background images, which would leave no
   dropdown affordance: fall back to the native arrow there. */
@media (forced-colors: active) {
  difficulty-selector select,
  preference-selector select,
  settings-panel select {
    appearance: auto;
    background-image: none;
    padding-right: var(--sp-4);
  }
}

settings-panel .settings-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
}
settings-panel .settings-hint {
  font-size: 0.875rem;
  color: var(--color-text-secondary);
}
settings-panel .btn-find:disabled {
  opacity: 0.6;
  cursor: progress;
}
settings-panel .settings-status {
  font-size: 0.875rem;
  color: var(--color-text-secondary);
  min-height: 1.25em;
}
settings-panel .settings-status:empty { min-height: 0; }

/* ── swipe-panel (Route / Meet up switcher on the search form) ───────────────── */
swipe-panel {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

/* Segmented control — same pill language as the tab bar's selected item. */
.swipe-tabs {
  display: flex;
  gap: var(--sp-1);
  padding: var(--sp-1);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-pill);
}
.swipe-tab {
  flex: 1;
  min-height: 44px; /* glove-friendly touch target */
  padding: var(--sp-2) var(--sp-3);
  background: none;
  border: none;
  border-radius: var(--r-pill);
  font-family: var(--font);
  font-size: 0.875rem;
  font-weight: var(--fw-semibold);
  color: var(--color-text-secondary);
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.swipe-tab[aria-selected="true"] {
  background: var(--color-background);
  color: var(--color-primary);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
}
.swipe-tab:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* overflow-x: clip (not hidden) keeps overflow-y visible, so a
   station-input dropdown can still drop out below the panel — see
   swipe-panel.js. The clip margin keeps focus rings at the edges visible. */
.swipe-viewport {
  overflow-x: clip;
  overflow-clip-margin: var(--sp-1);
}
/* The track's transform makes it a stacking context, which would trap the
   dropdown's own z-index under the floating tab bar — lift the whole
   viewport above it, but only while a dropdown is actually open. */
.swipe-viewport:has(.si-listbox:not([hidden])) {
  position: relative;
  z-index: 200;
}

.swipe-track {
  --swipe-gap: var(--sp-6);
  display: flex;
  align-items: flex-start;
  gap: var(--swipe-gap);
  touch-action: pan-y;
  transform: translateX(calc(var(--swipe-index, 0) * -1 * (100% + var(--swipe-gap)) + var(--swipe-drag, 0px)));
  transition: transform 0.32s cubic-bezier(0.4, 0, 0.2, 1);
}
.swipe-track--dragging { transition: none; }

.swipe-page {
  flex: 0 0 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
.swipe-page[data-swipe-hidden],
.swipe-tabs[hidden] { display: none; }
/* Off-screen pages take no height, so the panel is only as tall as the page showing. */
.swipe-page--away {
  visibility: hidden;
  max-height: 0;
  overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .swipe-track { transition: none; }
}

/* Route options (difficulty, Find route) only apply to the meet page once
   someone's shared location has been received. */
.search-form[data-mode="meet"]:not([data-has-incoming]) .route-option { display: none; }

/* ── Meet up page ──────────────────────────────────────────────────────────── */
.meet-share {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
.meet-share[hidden] { display: none; }

.meet-explanation {
  font-size: 0.9375rem;
  line-height: 1.5;
}

.meet-icon { display: inline-flex; }
.meet-icon svg { width: 1.25rem; height: 1.25rem; display: block; }

.meet-share-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  width: 100%;
  min-height: 48px;
  padding: var(--sp-3) var(--sp-6);
  background: var(--color-accent);
  color: var(--color-primary);
  font-family: var(--font);
  font-size: 1rem;
  font-weight: var(--fw-semibold);
  border: 1px solid var(--color-primary);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: opacity 0.15s ease;
}
.meet-share-btn:hover  { opacity: 0.85; }
.meet-share-btn:active { opacity: 0.70; }
.meet-share-btn:disabled { opacity: 0.6; cursor: progress; }
.meet-share-btn:focus-visible {
  outline: 2px solid var(--color-slope-blue);
  outline-offset: 3px;
}

.meet-share-status {
  font-size: 0.875rem;
  color: var(--color-text-secondary);
}
.meet-share-status:empty { display: none; }

.meet-privacy {
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
}

.meet-incoming {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--color-accent);
  border: 1px solid var(--color-primary);
  border-radius: var(--r-md);
}
.meet-incoming[hidden] { display: none; }
.meet-incoming > .meet-icon { color: var(--color-primary); padding-top: 2px; }
.meet-incoming--invalid { border-color: var(--color-slope-red); }
.meet-incoming--invalid > .meet-icon { color: var(--color-slope-red); }
.meet-incoming-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.meet-incoming-title { font-weight: var(--fw-semibold); font-size: 0.9375rem; }
.meet-incoming-meta,
.meet-incoming-hint { font-size: 0.8125rem; color: var(--color-text-secondary); }
.meet-incoming-meta:empty { display: none; }
.meet-dismiss {
  flex: 0 0 auto;
  min-height: 44px;
  padding: 0 var(--sp-2);
  margin: calc(-1 * var(--sp-2)) calc(-1 * var(--sp-2)) 0 0;
  background: none;
  border: none;
  border-radius: var(--r-sm);
  font-family: var(--font);
  font-size: 0.8125rem;
  font-weight: var(--fw-semibold);
  color: var(--color-primary);
  cursor: pointer;
}
.meet-dismiss:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }

/* ── search-summary (collapsed find-route bar) ───────────────────────────────── */
.search-summary {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  margin-bottom: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-md);
  font-family: var(--font);
  color: var(--color-text);
  cursor: pointer;
  text-align: left;
  transition: border-color 0.15s;
}
.search-summary:hover,
.search-summary:focus-visible { border-color: var(--color-primary); }

.search-summary-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.search-summary-route {
  font-weight: var(--fw-semibold);
  font-size: 0.9375rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.search-summary-pref {
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
}

.search-summary[hidden] { display: none; }

/* ── route-result ──────────────────────────────────────────────────────────── */
route-result { display: block; }

.result-cards {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  list-style: none;
}

.route-card {
  border-radius: var(--r-lg);
  overflow: hidden;
}

.route-card-btn {
  display: block;
  width: 100%;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  overflow: hidden;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.route-card-btn:hover { background: var(--color-background); }
.route-card-btn:focus-visible {
  outline: 2px solid var(--color-slope-blue);
  outline-offset: -2px;
}

.route-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--color-border);
}

/* Detail page reuses .route-card as a plain (non-button) container. */
.detail-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
}

/* ── Live GPS progress rail (route-detail) ───────────────────────────────────
   A vertical track beside the step list — filled/dotted to show how far
   along the route the device's live position projects to. Hidden (no fill,
   no dot) whenever there's no confident GPS fix on this route. */
.route-progress {
  display: flex;
  align-items: stretch;
  gap: var(--sp-3);
  padding-left: var(--sp-4);
}

.route-progress-track {
  position: relative;
  width: 4px;
  flex-shrink: 0;
  margin: var(--sp-3) 0;
  background: var(--color-border);
  border-radius: var(--r-pill);
}

.route-progress-fill {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 0%;
  background: var(--color-primary);
  border-radius: var(--r-pill);
  transition: height 0.4s ease;
}

.route-progress-dot {
  position: absolute;
  top: 0%;
  left: 50%;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--color-primary);
  border: 2px solid var(--color-surface);
  box-shadow: 0 0 0 3px var(--color-accent);
  transform: translate(-50%, -50%);
  transition: top 0.4s ease;
}

.route-progress .route-steps { flex: 1; min-width: 0; }

.route-progress-status {
  margin: 0;
  padding: 0 var(--sp-4) var(--sp-4);
  text-align: center;
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
  min-height: 1.5em;
}

.route-label {
  font-weight: var(--fw-bold);
  font-size: 0.875rem;
}

.route-stops {
  font-size: 0.75rem;
  font-weight: var(--fw-semibold);
  color: var(--color-text-secondary);
  background: var(--color-background);
  border: 1px solid var(--color-border);
  border-radius: var(--r-pill);
  padding: 2px var(--sp-3);
}

.route-steps {
  list-style: none;
  padding: var(--sp-2) 0;
}

.route-step {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4);
  font-size: 0.9375rem;
}

/* Slope steps only — tinted with their piste-difficulty colour */
.route-step[data-d="green"] { background: var(--color-slope-green-bg); }
.route-step[data-d="blue"]  { background: var(--color-slope-blue-bg); }
.route-step[data-d="red"]   { background: var(--color-slope-red-bg); }
.route-step[data-d="black"] { background: var(--color-slope-black-bg); }

.step-icon  { width: 1.5rem; flex-shrink: 0; }
.step-icon svg { width: 1.25rem; height: 1.25rem; display: block; margin: 0 auto; }
.step-name  { flex: 1; font-weight: var(--fw-semibold); }
.step-flag  { flex-shrink: 0; }

/* Slope difficulty dot — semantic colours only */
.diff-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
  border: 1px solid transparent;
}
.diff-dot[data-d="green"] { background: var(--color-slope-green); }
.diff-dot[data-d="blue"]  { background: var(--color-slope-blue); }
.diff-dot[data-d="red"]   { background: var(--color-slope-red); }
.diff-dot[data-d="black"] { background: var(--color-slope-black); border-color: var(--color-border); }
/* Lift steps carry no piste colour — render as invisible placeholder to preserve alignment */
.diff-dot--lift { background: transparent; border-color: transparent; }

/* ── Preference badge in route card header ──────────────────────────────────── */
.route-pref-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  font-size: 0.75rem;
  font-weight: var(--fw-semibold);
  color: var(--color-text-secondary);
  background: var(--color-background);
  border: 1px solid var(--color-border);
  border-radius: var(--r-pill);
  padding: 2px var(--sp-3);
  margin-inline: auto var(--sp-2);
}

/* ── No-route empty state ──────────────────────────────────────────────────── */
.no-route {
  text-align: center;
  padding: var(--sp-8) var(--sp-4);
  color: var(--color-text-secondary);
}
.no-route-icon  { display: block; margin-bottom: var(--sp-3); }
.no-route-icon svg { width: 2.5rem; height: 2.5rem; margin: 0 auto; }
.no-route-title {
  font-weight: var(--fw-bold);
  color: var(--color-text);
  margin-bottom: var(--sp-2);
}

/* ── Loading skeleton ──────────────────────────────────────────────────────── */
.loading-cards {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
.skeleton-card {
  height: 140px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  animation: pulse 1.4s ease-in-out infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.45; }
}

/* ── route-detail ─────────────────────────────────────────────────────────── */
route-detail { display: block; }

.detail-back {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-4);
  color: var(--color-text-secondary);
  font-weight: var(--fw-semibold);
  font-size: 0.9375rem;
  text-decoration: none;
}
.detail-back:hover { color: var(--color-text); }
.detail-back:focus-visible {
  outline: 2px solid var(--color-slope-blue);
  outline-offset: 3px;
}
.detail-back svg { width: 1.1rem; height: 1.1rem; display: block; }

.detail-skeleton { height: 320px; }

.detail-map-offline {
  padding: var(--sp-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-md);
  color: var(--color-text-secondary);
  font-size: 0.875rem;
  text-align: center;
}

/* Map section: a bordered card (matching .detail-card) plus the size-toggle
   button beneath it. Stacks above .detail-body on mobile; sits side by side
   with it on wide screens (see the :has(.detail-map-card) flex-row rule in
   layout.css). */
.detail-map-section {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-bottom: var(--sp-6);
}
@media (min-width: 900px) {
  .detail-map-section { flex: 1 1 45%; min-width: 0; margin-bottom: 0; }
  .detail-body { flex: 1 1 55%; min-width: 0; margin-top: 0; }
}

.detail-map-card {
  position: relative;
  /* Establishes a stacking context so Leaflet's own internal z-indices
     (its controls alone go up to ~1000 — see .detail-back-floating below)
     are contained here rather than leaking out to compete with the sticky
     header/tab-bar when this card scrolls past it. overflow:hidden only
     clips geometry, it does nothing to contain z-index on its own. */
  z-index: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--color-background);
  transition: height 0.2s ease;
}
.detail-map-card--large { height: 440px; }
.detail-map-card--small { height: 220px; }

/* Leaflet needs an explicit height on its container; the "Loading map…" /
   error text (set as plain textContent, see route-detail.js) uses the same
   flex centering before Leaflet replaces the container's contents.
   position:relative gives .detail-map-rotor (below) its positioning context. */
.detail-map {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-secondary);
  font-size: 0.875rem;
}

/* The oversized, rotatable div Leaflet actually mounts into — see the
   comment in route-detail.js's #initMap for why. Width/height are set
   inline (computed from the visible box's diagonal); only the centring/
   rotation behaviour lives here. The transition smooths out raw sensor
   jitter into a steadier-looking needle when compass mode is active. */
.detail-map-rotor {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotate(0deg);
  transition: transform 0.2s linear;
}

.detail-back-floating {
  position: absolute;
  top: var(--sp-4);
  left: var(--sp-4);
  /* Leaflet's own controls (in .detail-map, a sibling) go up to z-index
     ~1000 and — since neither element establishes an isolated stacking
     context — compete directly with this one, so this must clear that. */
  z-index: 1010;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
  transition: background 0.15s ease;
}
.detail-back-floating svg { width: 1.25rem; height: 1.25rem; display: block; }
.detail-back-floating:hover { background: var(--color-background); }
.detail-back-floating:focus-visible {
  outline: 2px solid var(--color-slope-blue);
  outline-offset: 2px;
}

/* Custom zoom control — replaces Leaflet's built-in one, which anchors to
   .detail-map-rotor's own (oversized, off-screen) corners rather than the
   visible viewport; see the comment in route-detail.js's #initMap. */
.detail-zoom-controls {
  position: absolute;
  top: var(--sp-4);
  right: var(--sp-4);
  z-index: 1010;
  display: flex;
  flex-direction: column;
  border-radius: var(--r-md);
  overflow: hidden;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
}
.detail-zoom-controls button {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: var(--color-surface);
  color: var(--color-text);
  font-size: 1.25rem;
  font-weight: var(--fw-bold);
  cursor: pointer;
}
.detail-zoom-controls button:first-child { border-bottom: 1px solid var(--color-border); }
.detail-zoom-controls button:hover { background: var(--color-background); }
.detail-zoom-controls button:focus-visible {
  outline: 2px solid var(--color-slope-blue);
  outline-offset: -2px;
}

/* Compass toggle — requests device-orientation permission on tap; see
   specs/mapping.md and src/compass.js. Highlighted (primary colour) while
   heading-up rotation is active. */
.detail-compass-toggle {
  position: absolute;
  bottom: var(--sp-4);
  left: var(--sp-4);
  z-index: 1010;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: none;
  border-radius: 50%;
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.detail-compass-toggle svg { width: 1.25rem; height: 1.25rem; display: block; }
.detail-compass-toggle:hover { background: var(--color-background); }
.detail-compass-toggle:focus-visible {
  outline: 2px solid var(--color-slope-blue);
  outline-offset: 2px;
}
.detail-compass-toggle[aria-pressed="true"] {
  background: var(--color-primary);
  color: var(--color-on-primary);
}

/* Static attribution — required reading regardless of map rotation state
   (Leaflet's own attribution control has the same off-screen-corner problem
   as its zoom control once mounted inside the rotor, see above). */
.detail-map-attribution {
  position: absolute;
  bottom: var(--sp-2);
  right: var(--sp-2);
  z-index: 5;
  margin: 0;
  padding: 1px 6px;
  font-size: 0.6875rem;
  background: var(--color-surface);
  background: color-mix(in srgb, var(--color-surface) 80%, transparent);
  color: var(--color-text-secondary);
  border-radius: var(--r-sm);
}
.detail-map-attribution a { color: var(--color-primary); }

.detail-compass-status {
  text-align: center;
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
}
.detail-compass-status:empty { display: none; }

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

/* Live "you are here" marker — same visual language as .route-progress-dot
   (filled circle, surface-colour ring, accent halo) so the two live-position
   indicators on this page read as the same thing. */
.route-map-you-are-here {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--color-primary);
  border: 2px solid var(--color-surface);
  box-shadow: 0 0 0 3px var(--color-accent);
}

/* "Meet up" shared position — the pin icon, outlined in the surface colour
   so it reads on any tile. */
.detail-meet-marker {
  color: var(--color-primary);
  filter: drop-shadow(0 0 1px var(--color-surface)) drop-shadow(0 0 1px var(--color-surface));
}
.detail-meet-marker svg { width: 100%; height: 100%; display: block; }

/* Leaflet's own tooltips (Start/Finish/You are here) ship hard-coded light
   colours — patched here so they don't look broken in dark mode. Zoom and
   attribution are our own controls now (styled above) rather than Leaflet's. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .detail-map .leaflet-tooltip {
    background: var(--color-surface);
    color: var(--color-text);
  }
  :root:not([data-theme="light"]) .detail-map .leaflet-tooltip.leaflet-tooltip-top::before { border-top-color: var(--color-surface); }
}
:root[data-theme="dark"] .detail-map .leaflet-tooltip {
  background: var(--color-surface);
  color: var(--color-text);
}
:root[data-theme="dark"] .detail-map .leaflet-tooltip.leaflet-tooltip-top::before { border-top-color: var(--color-surface); }

.detail-share-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
}
.detail-share-icon svg { width: 1.25rem; height: 1.25rem; display: block; }

.detail-share-status {
  text-align: center;
  font-size: 0.875rem;
  color: var(--color-text-secondary);
  min-height: 1.25em;
}

@media (min-width: 900px) {
  /* Cards vary in height (different step counts), so let each size to its
     own content instead of stretching to match its row's tallest sibling. */
  .result-cards,
  .loading-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    align-items: start;
  }
}
