/* ══════════════════════════════════════════════════════════════════════════
   Grand Tour — Routesmith design system.
   Warm off-whites and racing green, set in Bricolage Grotesque: soft cards on
   a quiet ground, pill chips, 10px controls, 14px cards, 1px hairline rules.
   Ships light and dark themes off one set of role/ramp tokens; the app
   resolves light / dark / system and stamps `data-theme` on <html>, so every
   component below is theme-agnostic and reads from the tokens.
   Tokens + component classes follow the "Grand Tour system" sheet in the
   design-system rebrand project (pre-dating the Routesmith rename);
   app-specific chrome (tab bar, chat, route cards, admin console) is
   layered underneath.
   ════════════════════════════════════════════════════════════════════════ */

:root {
  color-scheme: light;

  --color-bg: #faf8f5;
  --color-surface: #f1ede7;
  --color-card: #ffffff;
  --color-text: #191c1a;
  --color-accent: #1e6b4e;
  --color-accent-hover: #164f3a;
  --color-accent-active: #0f3527;
  /* Accent-tinted panel + the ink that sits on it (wind notes, user bubbles). */
  --color-tint: #e3efe8;
  --color-on-tint: #124534;
  --color-divider: color-mix(in srgb, #191c1a 25%, transparent);
  --color-hairline: color-mix(in srgb, #191c1a 12%, transparent);

  /* Tonal ramps — generated in OKLCH on one shared lightness scale, so the
     same step of any role matches the others in visual value. */
  --color-neutral-100: #f3f1ec;
  --color-neutral-200: #e8e5de;
  --color-neutral-300: #d8d4cd;
  --color-neutral-400: #b9b5af;
  --color-neutral-500: #9c9f96;
  --color-neutral-600: #84887e;
  --color-neutral-700: #54584f;
  --color-neutral-800: #3f443e;
  --color-neutral-900: #262a26;

  /* Racing-green accent ramp (OKLCH, hue 162) — 100 = lightest tint,
     900 = deepest. The accent role pins step 700 (6.2:1 on bg). */
  --color-accent-100: #eef6f1;
  --color-accent-200: #dcece3;
  --color-accent-300: #b9d9c9;
  --color-accent-400: #8abfa5;
  --color-accent-500: #57a181;
  --color-accent-600: #2e8262;
  --color-accent-700: #1e6b4e;
  --color-accent-800: #164f3a;
  --color-accent-900: #0f3527;

  --font-heading: "Bricolage Grotesque", system-ui, -apple-system, sans-serif;
  --font-heading-weight: 800;
  --font-body: "Bricolage Grotesque", system-ui, -apple-system, sans-serif;
  /* UI weight — buttons, chips, controls sit at 600, between body and display. */
  --font-ui-weight: 600;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;

  /* Radius scale: 999 pills (chips, tags) · 10px controls · 14px cards. */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-pill: 999px;

  --shadow-sm: 0 1px 3px color-mix(in srgb, #191c1a 8%, transparent);
  --shadow-md: 0 3px 10px color-mix(in srgb, #191c1a 12%, transparent);
  --shadow-lg: 0 12px 32px color-mix(in srgb, #191c1a 18%, transparent);
}

/* ── Dark theme ────────────────────────────────────────────────────────────
   Same token contract, dark values. The app stamps `data-theme="dark"` (or
   "light") on <html> from the resolved preference, so `[data-theme="dark"]`
   is the primary source of truth. The `prefers-color-scheme` block is a
   no-JS / pre-hydration fallback that themes the same tokens — it never wins
   over an explicit `data-theme="light"`.

   The neutral ramp is inverted for dark (100 = darkest surface → 900 =
   lightest text) so components that read "100 = subtle raised surface" and
   "600–700 = muted text" keep working. The accent role picks a brighter green
   (#3ba57c) so small text passes on #151816, and the ramp flips its tint steps
   (100 = deep green wash → 700–900 = light green) so tinted panels and links
   stay legible on dark. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --color-bg: #151816;
  --color-surface: #1e2320;
  --color-card: #242a26;
  --color-text: #e9ece8;
  --color-accent: #3ba57c;
  --color-accent-hover: #57bb92;
  --color-accent-active: #2f8a66;
  --color-tint: #1c3529;
  --color-on-tint: #8fd4b6;
  --color-divider: color-mix(in srgb, #e9ece8 18%, transparent);
  --color-hairline: color-mix(in srgb, #e9ece8 12%, transparent);

  --color-neutral-100: #1e2320;
  --color-neutral-200: #262c28;
  --color-neutral-300: #333833;
  --color-neutral-400: #454b45;
  --color-neutral-500: #626861;
  --color-neutral-600: #9aa39b;
  --color-neutral-700: #b9bfb8;
  --color-neutral-800: #ced3cd;
  --color-neutral-900: #e9ece8;

  --color-accent-100: #12241b;
  --color-accent-200: #1c3529;
  --color-accent-300: #234d39;
  --color-accent-400: #2c6b4d;
  --color-accent-500: #2f8a66;
  --color-accent-600: #3ba57c;
  --color-accent-700: #57bb92;
  --color-accent-800: #8fd4b6;
  --color-accent-900: #c6ead9;

  --shadow-sm: 0 1px 2px color-mix(in srgb, #000 40%, transparent);
  --shadow-md: 0 3px 12px color-mix(in srgb, #000 48%, transparent);
  --shadow-lg: 0 14px 36px color-mix(in srgb, #000 58%, transparent);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --color-bg: #151816;
    --color-surface: #1e2320;
    --color-card: #242a26;
    --color-text: #e9ece8;
    --color-accent: #3ba57c;
    --color-accent-hover: #57bb92;
    --color-accent-active: #2f8a66;
    --color-tint: #1c3529;
    --color-on-tint: #8fd4b6;
    --color-divider: color-mix(in srgb, #e9ece8 18%, transparent);
    --color-hairline: color-mix(in srgb, #e9ece8 12%, transparent);

    --color-neutral-100: #1e2320;
    --color-neutral-200: #262c28;
    --color-neutral-300: #333833;
    --color-neutral-400: #454b45;
    --color-neutral-500: #626861;
    --color-neutral-600: #9aa39b;
    --color-neutral-700: #b9bfb8;
    --color-neutral-800: #ced3cd;
    --color-neutral-900: #e9ece8;

    --color-accent-100: #12241b;
    --color-accent-200: #1c3529;
    --color-accent-300: #234d39;
    --color-accent-400: #2c6b4d;
    --color-accent-500: #2f8a66;
    --color-accent-600: #3ba57c;
    --color-accent-700: #57bb92;
    --color-accent-800: #8fd4b6;
    --color-accent-900: #c6ead9;

    --shadow-sm: 0 1px 2px color-mix(in srgb, #000 40%, transparent);
    --shadow-md: 0 3px 12px color-mix(in srgb, #000 48%, transparent);
    --shadow-lg: 0 14px 36px color-mix(in srgb, #000 58%, transparent);
  }
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

body {
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.55;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  line-height: 1.12; letter-spacing: -0.015em;
}
h6 { letter-spacing: 0.08em; text-transform: uppercase; }
a { color: var(--color-accent); text-decoration: none; text-underline-offset: 3px; }
img { display: block; max-width: 100%; }

.text-muted { color: var(--color-neutral-600); }
.grayscale { filter: grayscale(1) contrast(1.08); }

:focus { outline: none; }
:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }

/* — rules — */
.hr { height: 1px; border: 0; margin: var(--space-4) 0; background: var(--color-divider); }

/* — buttons — */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  cursor: pointer; text-decoration: none;
  font-family: var(--font-heading); font-weight: var(--font-ui-weight);
  font-size: 14px; line-height: 1.2; color: var(--color-text);
  background: transparent; border: 1px solid transparent;
  padding: var(--space-2) calc(var(--space-3) * 1.2);
  border-radius: var(--radius-md);
}
/* Icon glyphs never capture the pointer themselves: a tap anywhere in the
   button box lands on the button, not on an SVG <path>. Without this, taps on
   the fill:none interior of a stroked icon are hit-tested against the path
   geometry, which iOS Safari intermittently misses — the button then reads as
   "sometimes doesn't respond". */
.btn svg, .btn-icon span { pointer-events: none; }
.btn svg { display: block; }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn-primary { background: var(--color-accent); color: var(--color-bg); }
.btn-primary:hover:not(:disabled) { background: var(--color-accent-hover); }
.btn-primary:active:not(:disabled) { background: var(--color-accent-active); }
.btn-secondary { border-color: var(--color-divider); }
.btn-secondary:hover:not(:disabled) { background: color-mix(in srgb, var(--color-text) 7%, transparent); }
.btn-secondary:active:not(:disabled) { background: color-mix(in srgb, var(--color-text) 14%, transparent); }
.btn-ghost { color: var(--color-accent); padding-inline: var(--space-1); }
.btn-ghost:hover:not(:disabled) { background: color-mix(in srgb, var(--color-accent) 10%, transparent); }
/* Danger keeps a genuine brick red — the green accent can't read destructive. */
.btn-danger { background: #a63d2a; color: #faf8f5; }
.btn-danger:hover:not(:disabled) { background: #8c3323; }
.btn-icon { width: 36px; height: 36px; padding: 0; flex: none; }
.btn-block { width: 100%; justify-content: flex-start; text-align: left; }

/* — forms — */
.input {
  width: 100%; min-height: 36px; padding: 8px 12px; font: inherit;
  font-size: 14px; color: var(--color-text); caret-color: var(--color-accent);
  background: var(--color-card);
  border: 1px solid var(--color-divider); border-radius: var(--radius-md);
}
.input::placeholder { color: var(--color-neutral-600); }
.input:hover { border-color: color-mix(in srgb, var(--color-text) 45%, transparent); }
.input:focus-visible { border-color: var(--color-accent); outline: none; }
textarea.input { resize: none; }
/* iOS Safari auto-zooms when focusing a control whose font-size is <16px and
   never zooms back out on blur. Bump form controls to 16px on touch devices so
   focus doesn't trigger the zoom; desktop keeps the 14px design. */
@media (pointer: coarse) {
  .input { font-size: 16px; }
}

.seg {
  display: inline-flex; overflow: hidden;
  border: 1px solid var(--color-divider); border-radius: var(--radius-md);
}
.seg-opt {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 12px; font-size: 13px; cursor: pointer;
  font-family: var(--font-heading); font-weight: var(--font-ui-weight);
  color: var(--color-text); background: transparent; user-select: none;
}
.seg-opt + .seg-opt { border-left: 1px solid var(--color-divider); }
.seg-opt.active { background: var(--color-accent); color: var(--color-bg); }
.seg-opt:not(.active):hover { background: color-mix(in srgb, var(--color-text) 7%, transparent); }

.admin-select {
  width: 100%; min-height: 40px; padding: 8px 12px; font: inherit; font-size: 14px;
  color: var(--color-text); background: var(--color-card);
  border: 1px solid var(--color-divider); border-radius: var(--radius-md); cursor: pointer;
}
.admin-select:disabled { opacity: 0.5; cursor: default; }

/* — cards — */
.card {
  display: flex; flex-direction: column; gap: var(--space-2);
  padding: var(--space-3); border-radius: var(--radius-lg); background: var(--color-card);
  box-shadow: var(--shadow-sm);
}
.card-title { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 17px; line-height: 1.2; }
.elev-sm { box-shadow: var(--shadow-sm); }
.elev-md { box-shadow: var(--shadow-md); }
.elev-lg { box-shadow: var(--shadow-lg); }

/* — tags — */
.tag {
  display: inline-flex; align-items: center; font-size: 11px; font-weight: var(--font-ui-weight);
  letter-spacing: 0.02em; padding: 3px 10px; border-radius: var(--radius-pill); white-space: nowrap;
}
.tag-accent { background: var(--color-tint); color: var(--color-on-tint); }
.tag-neutral { background: var(--color-neutral-100); color: var(--color-neutral-800); }
.tag-solid { background: var(--color-accent); color: var(--color-bg); }
.tag-outline { border: 1px solid var(--color-accent); color: var(--color-accent); }

/* — navigation header — */
.nav {
  display: flex; align-items: center; gap: var(--space-3);
  padding: 12px 18px; border-bottom: 1px solid var(--color-divider);
}
.nav-brand { display: flex; align-items: center; gap: 10px; margin-right: auto; }
.brand-mark { flex: none; display: block; }
.brand-mark svg { display: block; width: 100%; height: 100%; }
.nav-brand .brand-text { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 18px; line-height: 1; }
.nav-brand .tagline {
  display: block; font-family: var(--font-body); font-weight: 400; font-size: 10px;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-accent); margin-top: 3px;
}

/* — tables — */
.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th {
  text-align: left; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--color-neutral-600); padding: var(--space-2); border-bottom: 1px solid var(--color-divider);
}
.table td { padding: var(--space-2); border-bottom: 1px solid var(--color-hairline); }

/* ══════════════════════════════════════════════════════════════════════════
   App chrome
   ════════════════════════════════════════════════════════════════════════ */

html, body { height: 100%; }
body { overscroll-behavior-y: none; }

/* Full-viewport app shell — header, swappable panels, bottom tab bar. */
#app {
  height: 100dvh; display: flex; flex-direction: column; overflow: hidden;
  background: var(--color-bg);
}

.app-header {
  padding-top: calc(12px + env(safe-area-inset-top));
  padding-right: calc(18px + env(safe-area-inset-right));
  padding-left: calc(18px + env(safe-area-inset-left));
  flex-shrink: 0;
}
.app-header .btn-icon { color: var(--color-text); }

.header-user { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--color-neutral-600); }
.header-user img { width: 26px; height: 26px; border-radius: 50%; object-fit: cover; }

/* Header overflow menu — theme + sign-out, so they stop being top-level icons. */
.header-menu-wrap { position: relative; display: flex; }
.header-menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 45;
  min-width: 180px; background: var(--color-card); border: 1px solid var(--color-divider);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg); display: flex; flex-direction: column; padding: 4px;
}
.header-menu[hidden] { display: none; }
.hm-item {
  display: flex; align-items: center; gap: 10px; width: 100%; box-sizing: border-box;
  padding: 10px 12px; background: none; border: none; cursor: pointer;
  font: inherit; font-size: 13px; color: var(--color-text); text-align: left; text-decoration: none;
}
.hm-item { border-radius: var(--radius-sm); }
.hm-item:hover { background: var(--color-surface); }
.hm-item svg, .hm-item #theme-icon { flex: none; color: var(--color-text); }

/* Panels: only the active one is shown. */
.panel { flex: 1; min-height: 0; display: none; flex-direction: column; overflow: hidden; }
.panel.active { display: flex; }

/* — bottom tab bar — */
.tabbar {
  display: flex; flex-shrink: 0;
  border-top: 1px solid var(--color-divider); background: var(--color-bg);
  padding-bottom: env(safe-area-inset-bottom);
}
.tab {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 11px 0 12px; color: var(--color-neutral-600);
  background: none; border: none; cursor: pointer; font: inherit;
}
.tab svg { display: block; }
.tab span { font-size: 9px; letter-spacing: 0.06em; text-transform: uppercase; font-weight: 600; }
.tab.active { color: var(--color-accent); }

/* ── Chat panel ─────────────────────────────────────────────────────────── */

/* Welcome wind line — the day's wind, surfaced in the first assistant message. */
.welcome-wind {
  display: inline-flex; align-items: center; margin-top: 8px; padding: 4px 12px;
  background: var(--color-tint); color: var(--color-on-tint);
  font-size: 13px; font-weight: 600; border-radius: var(--radius-pill);
}
.welcome-wind[hidden] { display: none; }   /* inline-flex would beat the hidden attribute */

.chat-mode { flex: 1; min-height: 0; display: none; flex-direction: column; overflow: hidden; position: relative; }
.chat-mode.active { display: flex; }

/* "Jump to latest" pill — shown while the reader has scrolled away from the
   live reply, so following it again is one tap. Sits just above the composer. */
.jump-latest {
  position: absolute; left: 50%; bottom: 78px; transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 5px; z-index: 5;
  padding: 6px 12px; font-size: 12px; font-weight: 600;
  color: var(--color-bg); background: var(--color-text);
  border: none; border-radius: 999px; cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.22);
}
.jump-latest[hidden] { display: none; }
.jump-latest svg { display: block; }

#messages {
  flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior-y: contain;
  padding: 18px; display: flex; flex-direction: column; gap: 14px;
}

.msg { font-size: 14px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
.msg.user {
  max-width: 82%; align-self: flex-end;
  background: var(--color-tint); color: var(--color-on-tint); padding: 11px 14px;
  border-radius: var(--radius-lg);
}
.msg.assistant {
  max-width: 90%; align-self: flex-start;
  background: var(--color-card); padding: 13px 15px;
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
}
.msg.tool {
  align-self: flex-start; max-width: 90%;
  background: var(--color-neutral-100); color: var(--color-neutral-700);
  border: 1px solid var(--color-hairline); border-radius: var(--radius-md);
  font-size: 12px; padding: 6px 10px;
  font-family: ui-monospace, "SF Mono", "Fira Code", monospace;
}
.msg.thinking { align-self: flex-start; color: var(--color-neutral-600); font-size: 13px; padding: 2px 0; }
.msg.thinking::after { content: ""; }
.msg strong { font-weight: 700; }
.msg code { background: var(--color-neutral-200); padding: 1px 5px; font-family: ui-monospace, "SF Mono", monospace; font-size: 0.9em; }
.msg a { color: var(--color-accent); text-decoration: underline; }

/* — route card (rendered under an assistant reply, or in Browse) — */
.route-card { align-self: flex-start; width: 100%; max-width: 100%; padding: 0; gap: 0; overflow: hidden; background: var(--color-card); }
.route-card .rc-map { height: 120px; position: relative; background: var(--color-surface); border-bottom: 1px solid var(--color-hairline); }
.route-card .rc-map svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.route-card .rc-map .tag { position: absolute; top: 10px; right: 10px; }
.route-card .rc-body { padding: 13px; display: flex; flex-direction: column; gap: 12px; }
.route-card .rc-title { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 17px; line-height: 1.2; }
.route-card .rc-sub { font-size: 12px; color: var(--color-neutral-600); margin-top: 2px; }

.rc-stats { display: flex; border-top: 1px solid var(--color-hairline); border-bottom: 1px solid var(--color-hairline); }
.rc-stat { flex: 1; padding: 9px 0; }
.rc-stat + .rc-stat { border-left: 1px solid var(--color-hairline); padding-left: 12px; }
.rc-stat .v { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 18px; }
.rc-stat .v small { font-size: 11px; font-weight: 800; }
.rc-stat .k { font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-neutral-600); margin-top: 1px; }

.rc-note { display: flex; align-items: flex-start; gap: 8px; background: var(--color-tint); padding: 9px 11px; border-radius: var(--radius-md); }
.rc-note svg { flex: none; margin-top: 1px; color: var(--color-accent); }
.rc-note div { font-size: 12px; line-height: 1.45; color: var(--color-on-tint); }
.rc-actions { display: flex; gap: 8px; }

/* — chips — */
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  font-family: var(--font-heading); font-weight: var(--font-ui-weight); font-size: 13px;
  padding: 7px 13px; cursor: pointer; user-select: none;
  background: var(--color-surface); color: var(--color-neutral-800);
  border: 1px solid transparent; border-radius: var(--radius-pill);
}
.chip:hover { background: var(--color-neutral-200); }
.chip.selected { background: var(--color-accent); color: var(--color-bg); }
.chip.ghost { background: transparent; border-color: var(--color-divider); color: var(--color-text); font-size: 13px; }
.chip.ghost:hover { background: color-mix(in srgb, var(--color-text) 7%, transparent); }

/* — composer — */
.composer {
  display: flex; align-items: flex-end; gap: 10px; flex-shrink: 0;
  padding: 12px 16px; border-top: 1px solid var(--color-divider); background: var(--color-bg);
  padding-bottom: calc(12px + env(safe-area-inset-bottom));
}
.composer textarea { flex: 1; max-height: 120px; min-height: 42px; }

/* ── Browse panel ───────────────────────────────────────────────────────── */
.wind-banner { display: flex; align-items: center; gap: 9px 14px; flex-wrap: wrap; padding: 10px 18px; background: var(--color-tint); border-bottom: 1px solid var(--color-divider); flex-shrink: 0; }
.wind-banner b { font-weight: var(--font-heading-weight); }
#wind-banner-text { display: flex; align-items: center; gap: 8px 14px; flex-wrap: wrap; }

/* — wind day/time scrubber — reuses the shared .seg / .sort-select kit so it
   reads as the same modernist control language as the sort cluster below. */
.wb-scrub { display: flex; align-items: center; gap: 8px; }
/* Day + arrow cells take the banner's tint ink, not .seg-opt's default text. */
.wb-seg .seg-opt { padding: 5px 10px; font-size: 13px; line-height: 1; color: var(--color-on-tint); }
.wb-nav { min-width: 26px; }                       /* ‹ › stepper cells */
.wb-day { cursor: default; min-width: 96px; }      /* the date label cell */
.wb-day:hover { background: transparent; }
.wb-seg .seg-opt.is-off { opacity: 0.32; pointer-events: none; }
.wb-from { font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-on-tint); }
/* Sits in the accent banner like the .seg beside it: transparent fill + accent
   text, not the sort-select's opaque surface grey. The descendant selector
   outranks .sort-select (equal specificity, but it's later in the file, so a
   bare .wb-time would lose the background). Height matched to .wb-seg. */
.wb-scrub .wb-time { max-width: 96px; min-height: 0; padding: 5px 10px; font-size: 13px;
                     background: transparent; color: var(--color-on-tint); }
/* The region picker (only rendered when the library spans >1 region) shares
   the .wb-time treatment but needs room for a settlement name + count. */
.wb-scrub .wb-region { max-width: 180px; }
/* The wind glyph sits with the direction here (right of the date/time controls),
   not adrift at the banner's top-left. */
.wb-sum { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; line-height: 1.35; color: var(--color-on-tint); }
.wb-sum > svg { flex: none; color: var(--color-accent); }
.wb-low { font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-neutral-700); }

/* — wind reason (the "why" behind a route's dated wind score) — a pill in
   the shared .tag language: accent when the wind works for you, neutral when
   it doesn't. Green + neutrals only; the phrase itself carries head vs tail. */
.wind-tag { gap: 5px; font-weight: 600; }
.wind-tag svg { flex: none; }

.browse-controls { padding: 12px 18px; display: flex; flex-direction: column; gap: 11px; border-bottom: 1px solid var(--color-divider); flex-shrink: 0; }
.filter-scroll { display: flex; align-items: stretch; gap: 8px; overflow-x: auto; padding-bottom: 1px; }
.filter-scroll .chip { flex: none; font-size: 12px; padding: 6px 12px; }
/* Thin rule marking the boundary between filter groups (distance | terrain | …). */
.filter-div { flex: none; align-self: stretch; width: 1px; margin: 3px 2px; background: var(--color-divider); }
.browse-meta { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.browse-count { font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-neutral-600); }

/* — sort cluster: Data toggle + view switch + sort key + direction —
   Reuses the shared .chip / .seg / .input language so it reads as part of the
   same modernist kit; wraps to a second line rather than overflowing on a
   narrow phone. */
.sort-cluster { display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-end; gap: 8px; min-width: 0; }
.sort-cluster .chip { flex: none; font-size: 12px; padding: 6px 12px; }
.sort-cluster .chip.selected { background: var(--color-accent); color: var(--color-bg); }
.view-seg .seg-opt { padding: 6px 9px; }
.view-seg .seg-opt svg { display: block; }
.sort-select {
  min-width: 0; max-width: 130px; min-height: 32px; padding: 4px 8px;
  font-family: var(--font-heading); font-weight: var(--font-ui-weight); font-size: 12px;
  color: var(--color-text); background: var(--color-surface);
  border: 1px solid var(--color-divider); border-radius: var(--radius-md); cursor: pointer;
}
.sort-dir {
  flex: none; width: 32px; height: 32px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-heading); font-weight: var(--font-ui-weight); font-size: 15px;
  color: var(--color-text); background: transparent;
  border: 1px solid var(--color-divider); border-radius: var(--radius-md);
}
.sort-dir:hover { background: color-mix(in srgb, var(--color-text) 7%, transparent); }

/* — data panel: show/hide, sort & filter the computed score columns — */
.data-panel { border-top: 1px solid var(--color-divider); margin-top: 4px; padding-top: 12px; }
.data-panel[hidden] { display: none; }
.dp-hint { font-size: 11px; line-height: 1.4; color: var(--color-neutral-600); margin-bottom: 11px; }
#data-rows { display: flex; flex-direction: column; gap: 7px; }
.dp-row { display: grid; grid-template-columns: 1fr 62px 62px 44px; gap: 8px; align-items: center; }
.dp-row .chip { font-size: 12px; padding: 6px 10px; text-align: left; }
.input.dp-bound { min-height: 30px; padding: 4px 8px; font-size: 13px; }
.dp-unit { font-size: 10px; letter-spacing: 0.04em; color: var(--color-neutral-600); white-space: nowrap; }
/* Number spinners eat most of the tiny inputs — hide them. */
.input.dp-bound::-webkit-inner-spin-button, .input.dp-bound::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.input.dp-bound { -moz-appearance: textfield; appearance: textfield; }

#browse-list[hidden], #browse-table[hidden] { display: none; }
#browse-list { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; }

/* — data table view: a genuine sortable column per metric —
   Follows the shared .table conventions (uppercase small-caps headings, 2px
   header rule, 1px row dividers, Archivo tabular numerals). The Route column
   is sticky so it holds while the numeric columns scroll horizontally. */
#browse-table { flex: 1; overflow: auto; -webkit-overflow-scrolling: touch; }
.data-table { border-collapse: collapse; font-size: 14px; width: 100%; }
.data-table th {
  position: sticky; top: 0; z-index: 2; background: var(--color-bg);
  padding: 10px 14px; text-align: right; white-space: nowrap; vertical-align: bottom;
  font-family: var(--font-body); font-weight: 400;
  font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-neutral-600);
  border-bottom: 1px solid var(--color-divider);
}
.data-table th.col-name { text-align: left; }
.data-table th.col-sortable { cursor: pointer; user-select: none; }
.data-table th.col-sortable:hover { color: var(--color-text); }
.data-table th.col-active { color: var(--color-accent); border-bottom-color: var(--color-accent); }
.data-table .th-unit { margin-left: 5px; font-size: 9px; letter-spacing: 0.02em; color: var(--color-neutral-500); text-transform: none; }
.data-table th.col-active .th-unit { color: color-mix(in srgb, var(--color-accent) 65%, var(--color-neutral-500)); }
.data-table .sort-caret { margin-left: 5px; color: var(--color-accent); }
.data-table td { padding: 11px 14px; border-bottom: 1px solid var(--color-hairline); white-space: nowrap; }
.data-table td.col-num {
  text-align: right; font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-variant-numeric: tabular-nums;
}
.data-table td.col-num.col-active { color: var(--color-accent); }
.data-table .col-name { position: sticky; left: 0; background: var(--color-bg); min-width: 148px; max-width: 210px; }
.data-table th.col-name { z-index: 3; }
.data-table td.col-name a {
  display: block; overflow: hidden; text-overflow: ellipsis;
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 15px; line-height: 1.2; color: var(--color-text);
}
.data-table td.col-name a:hover { color: var(--color-accent); }
.data-table .cell-sub { display: block; overflow: hidden; text-overflow: ellipsis; font-size: 11px; color: var(--color-neutral-600); margin-top: 2px; }
.data-table tbody tr:hover td { background: color-mix(in srgb, var(--color-text) 4%, transparent); }
.data-table tbody tr:hover td.col-name { background: color-mix(in srgb, var(--color-text) 4%, var(--color-bg)); }
.browse-row { display: flex; border-bottom: 1px solid var(--color-hairline); color: var(--color-text); }
.browse-row:hover { background: color-mix(in srgb, var(--color-text) 4%, transparent); }
.browse-row .br-body { flex: 1; min-width: 0; padding: 13px 16px; display: flex; flex-direction: column; gap: 7px; }
.browse-row .br-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.browse-row .br-name { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 16px; line-height: 1.2; }
.browse-row .br-stats { display: flex; gap: 16px; }
.browse-row .br-stats span { font-size: 13px; white-space: nowrap; }
.browse-row .br-stats b { font-family: var(--font-heading); font-weight: var(--font-heading-weight); }
.browse-row .br-stats .u { font-size: 11px; color: var(--color-neutral-600); }
.browse-row .br-tags { font-size: 12px; color: var(--color-neutral-600); }

/* ── Help panel ─────────────────────────────────────────────────────────── */
.help-scroll { flex: 1; overflow-y: auto; padding: 20px 18px; display: flex; flex-direction: column; gap: 22px; }
.section-label { font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-neutral-600); margin-bottom: 12px; }
.accordion { border-top: 1px solid var(--color-divider); }
.acc-item { border-bottom: 1px solid var(--color-hairline); }
.acc-q { all: unset; cursor: pointer; display: flex; align-items: center; gap: 12px; width: 100%; padding: 14px 2px; box-sizing: border-box; }
.acc-q .q { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 14px; line-height: 1.3; flex: 1; }
.acc-q .sign { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 18px; color: var(--color-accent); flex: none; width: 16px; text-align: center; }
.acc-a { font-size: 13px; line-height: 1.55; color: var(--color-neutral-700); padding: 0 2px 15px; }
.acc-a .scale-table { border-collapse: collapse; margin: 10px 0; width: 100%; max-width: 320px; }
.acc-a .scale-table th { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 12px; text-align: left; padding: 4px 12px 4px 0; border-bottom: 1px solid var(--color-divider); }
.acc-a .scale-table td { padding: 4px 12px 4px 0; border-bottom: 1px solid var(--color-hairline); }
.acc-a .scale-table .scale-note { color: var(--color-neutral-600); font-size: 12px; }
.try-item { display: flex; align-items: center; gap: 11px; background: var(--color-card); border: none; border-radius: var(--radius-md); box-shadow: var(--shadow-sm); padding: 11px 13px; cursor: pointer; width: 100%; text-align: left; font: inherit; }
.try-item:hover { background: var(--color-surface); }
.try-item svg { flex: none; color: var(--color-accent); }
.try-item span { font-size: 13px; }
.help-contact { margin-top: auto; background: var(--color-card); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); padding: 15px 16px; display: flex; align-items: center; gap: 13px; }

/* ── Help (overlay) ─────────────────────────────────────────────────────── */
#help-overlay {
  position: fixed; inset: 0; z-index: 40; background: var(--color-bg);
  display: none; flex-direction: column;
}
#help-overlay.open { display: flex; }

/* ── Library tab (sources · maintenance · advanced) ─────────────────────────
   Was two full-screen overlays (Libraries + Admin); now one panel that reuses
   the admin shell (head / tool-card / stats) so it reads as the same system. */
.lib-head { padding-top: 16px; }
.lib-scroll { flex: 1; min-height: 0; overflow-y: auto; }
.lib-col { max-width: 720px; width: 100%; margin: 0 auto; padding: 20px; display: flex; flex-direction: column; gap: 14px; }
/* Section headers set the tiers apart; the accent one flags Maintenance as a
   first-class core section rather than an admin footnote. */
.lib-section { margin: 10px 0 0; }
.lib-section:first-child { margin-top: 0; }
.lib-section-accent { color: var(--color-accent); }
.lib-col .admin-stats { border-top: 0; }
/* legacy libraries overlay body (no longer rendered, retained for safety) */
.lib-body { grid-template-columns: 1fr !important; max-width: 720px; width: 100%; margin: 0 auto; }
.lib-row { display: flex; align-items: center; gap: 10px; padding: 11px 0; border-top: 1px solid var(--color-hairline); }
.lib-row:first-child { border-top: 0; padding-top: 2px; }
.lib-name { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 14px; line-height: 1.25; }
.lib-meta { font-size: 12px; color: var(--color-neutral-600); margin-top: 2px; overflow-wrap: anywhere; }
.lib-meta.err { color: #a63d2a; }
:root[data-theme="dark"] .lib-meta.err { color: #e08a72; }
.lib-row .chip { flex: none; font-size: 12px; padding: 6px 14px; min-width: 52px; text-align: center; }
.src-badge {
  display: inline-block; font-size: 9px; letter-spacing: 0.09em; text-transform: uppercase;
  border: 1px solid var(--color-divider); color: var(--color-neutral-600);
  border-radius: var(--radius-pill);
  padding: 1px 7px; margin-left: 8px; vertical-align: middle; white-space: nowrap;
}
/* Provider source marks in Browse — official vendor logos (never recoloured,
   kept visually separate from our own branding per the providers' guidelines).
   They lead the route title, wrapped in .src-lead. */
.src-badge-logo {
  display: inline-block; vertical-align: middle;
  width: auto; flex: none;
}
/* The leading provider mark, sitting to the left of the route title. Zeroes
   the badge chip's trailing-position margin when GPX's text chip stands in
   for a logo. vertical-align:middle centres on the x-height, which leaves
   the mark hanging below the title's baseline; the nudge re-centres it on
   the cap band without disturbing the line box. */
.src-lead { display: inline-block; margin-right: 7px; vertical-align: middle;
  transform: translateY(-1.5px); }
.src-lead .src-badge { margin-left: 0; }
/* Sized as small source markers, not competing with the route title —
   kept compact so they don't dominate the narrow PWA/mobile card. */
.src-badge-logo.is-rwgps { height: 13px; }
/* Strava's official square brandmark — a compact source glyph on its own
   orange field, legible on both themes (no recolour, per Strava's rules).
   Set a touch taller than the RWGPS mark: a solid square reads optically
   smaller than the wide cyclist line-icon at equal height, so 15px balances. */
.src-badge-logo.is-strava { height: 15px; }

/* Ownership descriptor (Personal / club name) — leads the tags row in the
   same plain style as the type/terrain descriptor text (it inherits the
   row's font and colour; the class exists as a styling hook and so the
   multi-source summary text matches too). */
.src-own { white-space: nowrap; }

/* Multi-source badge — a route folded from more than one library. The
   representative shows once in Browse; the badge names every library it
   lives in and expands to list each copy. */
.src-multi { display: inline-flex; flex-direction: column; align-items: flex-start;
  vertical-align: top; }
.src-summary { display: inline-flex; align-items: center; cursor: pointer;
  border-radius: 3px; }
.src-summary:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
/* First label chip already carries margin-left:8px; the count sits snug after it. */
.src-count {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 9px; letter-spacing: 0.06em; margin-left: 6px;
  color: var(--color-neutral-600); white-space: nowrap;
}
.src-caret { display: inline-block; transition: transform 0.12s ease; font-size: 8px; }
.src-summary.is-open .src-caret { transform: rotate(90deg); }
.src-list {
  display: flex; flex-direction: column; gap: 2px;
  margin: 4px 0 2px 8px; padding-left: 8px;
  border-left: 1px solid var(--color-divider);
}
/* display:flex above would otherwise override the hidden attribute the
   collapsed state relies on. */
.src-list[hidden] { display: none; }
.src-row {
  display: flex; align-items: baseline; gap: 8px;
  font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--color-neutral-600);
}
.src-when { font-size: 9px; letter-spacing: 0; text-transform: none;
  color: var(--color-neutral-500); }

/* Official "Connect with Strava" button — an image asset, so preserve its
   aspect ratio (Strava prohibits distorting or recolouring the mark). */
.strava-connect-btn { display: inline-flex; line-height: 0; }
.strava-connect-btn img { display: block; height: 40px; width: auto; }
/* A branded tool-card glyph carries a real provider mark rather than a
   line-icon: drop the outline box and let the logo fill the slot. */
.tool-card .tc-glyph.tc-glyph-brand { border: none; }
.tool-card .tc-glyph.tc-glyph-brand img { display: block; width: 30px; height: auto; }
.admin-head {
  display: flex; align-items: center; gap: var(--space-3);
  padding: calc(16px + env(safe-area-inset-top)) 20px 16px;
  border-bottom: 1px solid var(--color-divider); flex-shrink: 0;
}
.admin-head h1 { font-size: 22px; }
.admin-head .sub { font-size: 11px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--color-accent); margin-top: 3px; }
.admin-stats { display: flex; background: var(--color-card); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); overflow: hidden; flex-shrink: 0; }
.admin-stat { flex: 1; padding: 14px 18px; }
.admin-stat + .admin-stat { border-left: 1px solid var(--color-hairline); }
.admin-stat .v { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 24px; }
.admin-stat .k { font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-neutral-600); margin-top: 2px; }
.admin-body { flex: 1; overflow-y: auto; padding: 20px; display: grid; grid-template-columns: 1fr; gap: 20px; }
@media (min-width: 780px) { .admin-body { grid-template-columns: 1.3fr 1fr; } }
.admin-tools { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.tool-card { background: var(--color-card); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); padding: 15px 16px; display: flex; flex-direction: column; gap: 12px; }
.tool-card .tc-head { display: flex; align-items: flex-start; gap: 11px; }
.tool-card .tc-glyph { width: 34px; height: 34px; flex: none; border: 2px solid var(--color-accent); border-radius: var(--radius-md); display: flex; align-items: center; justify-content: center; }
.tool-card .tc-glyph svg { color: var(--color-accent); }
.tool-card .tc-name { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 15px; line-height: 1.2; }
.tool-card .tc-desc { font-size: 12px; color: var(--color-neutral-600); line-height: 1.4; margin-top: 3px; }
.tool-card .tc-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.admin-console-wrap { display: flex; flex-direction: column; min-height: 0; }
#admin-console {
  flex: 1; min-height: 200px; background: var(--color-neutral-900); color: var(--color-neutral-200);
  border-radius: var(--radius-md);
  font-family: ui-monospace, "SF Mono", "Fira Code", monospace; font-size: 12px; line-height: 1.55;
  padding: 12px 14px; overflow-y: auto; white-space: pre-wrap; word-break: break-word;
}
#admin-console .add { color: #7fd77f; }
#admin-console .remove { color: #f0938a; }
#admin-console .info { color: var(--color-neutral-500); }
#admin-console .head { color: var(--color-accent-400); font-weight: 700; }

/* ══════════════════════════════════════════════════════════════════════════
   Dark-theme component overrides — a couple of components deliberately pin a
   ramp step assuming a light base (the console wants a dark terminal, danger
   wants a deep fill). Both are re-anchored here for dark so they don't invert.
   ════════════════════════════════════════════════════════════════════════ */
:root[data-theme="dark"] #admin-console { background: #0e110f; color: #cacfc9; }
:root[data-theme="dark"] #admin-console .info { color: #848a83; }
:root[data-theme="dark"] #admin-console .head { color: var(--color-accent-700); }

:root[data-theme="dark"] .btn-danger { background: #b8482f; color: #fdeee9; }
:root[data-theme="dark"] .btn-danger:hover:not(:disabled) { background: #9c3c26; }

/* ══════════════════════════════════════════════════════════════════════════
   PWA install affordances — a quiet header button + Help-panel card that fire
   the native install sheet where the browser supports it, and a coached
   overlay for iOS Safari (which has no install API). Hidden until JS decides
   they're relevant, and gone once the app is installed.
   ════════════════════════════════════════════════════════════════════════ */
.install-btn { position: relative; }
/* One-time "new" dot until the button is first used. */
.install-btn.has-dot::after {
  content: ""; position: absolute; top: -2px; right: -2px; width: 9px; height: 9px;
  background: var(--color-accent); border: 2px solid var(--color-bg); border-radius: 50%;
}

/* Help-panel card — mirrors the admin tool-card, but Help-panel scoped. */
.install-card {
  background: var(--color-card); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  padding: 15px 16px;
  display: flex; flex-direction: column; gap: 12px;
}
.install-card .ic-head { display: flex; align-items: flex-start; gap: 11px; }
.install-card .ic-glyph {
  width: 34px; height: 34px; flex: none; border: 2px solid var(--color-accent); border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center; color: var(--color-accent);
}
.install-card .ic-name {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 15px; line-height: 1.2;
}
.install-card .ic-desc { font-size: 12px; color: var(--color-neutral-600); line-height: 1.4; margin-top: 3px; }

/* iOS coach overlay — bottom sheet pointing at Safari's Share button. */
.ios-install {
  position: fixed; inset: 0; z-index: 50; display: none;
  flex-direction: column; justify-content: flex-end;
}
.ios-install.open { display: flex; }
.ios-install-scrim { position: absolute; inset: 0; background: color-mix(in srgb, #000 34%, transparent); }
.ios-install-sheet {
  position: relative;
  margin: 0 calc(12px + env(safe-area-inset-right)) calc(16px + env(safe-area-inset-bottom)) calc(12px + env(safe-area-inset-left));
  background: var(--color-card); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); padding: 16px 16px 17px;
}
/* Arrow toward the Share button in Safari's bottom toolbar. */
.ios-install-sheet::after {
  content: ""; position: absolute; left: 50%; bottom: -11px; transform: translateX(-50%);
  border-left: 9px solid transparent; border-right: 9px solid transparent;
  border-top: 11px solid var(--color-card);
}
.ios-install-x {
  position: absolute; top: 11px; right: 11px; padding: 2px;
  background: none; border: none; cursor: pointer; color: var(--color-neutral-600); display: flex;
}
.ios-install-title {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 15px; line-height: 1.25; padding-right: 24px;
}
.ios-install-note {
  font-size: 12px; line-height: 1.4; margin-top: 10px; padding: 8px 10px;
  background: var(--color-tint); color: var(--color-on-tint); border-radius: var(--radius-md);
}
.ios-install-steps {
  list-style: none; margin: 12px 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 10px;
}
.ios-install-steps li { display: flex; align-items: center; gap: 10px; font-size: 13px; line-height: 1.35; }
.ios-install-steps .num {
  width: 20px; height: 20px; flex: none; background: var(--color-accent); color: var(--color-bg);
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-heading); font-weight: var(--font-ui-weight); font-size: 12px;
}
.ios-install-steps svg { flex: none; vertical-align: -3px; color: var(--color-accent); }
