/* ================================================================
   Flight Tracker — departure-board design system
   Airport-native: the dashboard reads like a status board, each route
   is a boarding pass with split-flap (mono) numerals.
   Dark "ink board" is the default palette; light is the "paper boarding
   pass", applied either by OS preference or by [data-theme] (the toggle).

   FONT TRIO (all self-hosted woff2, latin subset — no CDNs, CSP-clean):
     · Bricolage Grotesque  → --font-display  (headings, brand)
     · IBM Plex Sans        → --font          (body / UI; replaced Inter)
     · IBM Plex Mono        → --font-mono      (prices, times, IATA codes,
                                                deltas, stats — the split-flap)
   ================================================================ */

/* Body / UI — engineered, transit feel (variable weight axis). */
@font-face {
  font-family: "IBM Plex Sans";
  src: url("fonts/IBMPlexSans.woff2") format("woff2");
  font-weight: 100 700;
  font-style: normal;
  font-display: swap;
}

/* Mono — the split-flap board face. Two static weights (Plex Mono has no
   variable cut). Used for every numeral / flight code via --font-mono. */
@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/IBMPlexMono-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/IBMPlexMono-600.woff2") format("woff2");
  font-weight: 600 800;
  font-style: normal;
  font-display: swap;
}

/* Display face — headings, the brand, the big board labels. Vendored
   (latin subset, variable 300–800); self-hosted for CSP. */
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("fonts/BricolageGrotesque.woff2") format("woff2");
  font-weight: 300 800;
  font-style: normal;
  font-display: swap;
}

:root {
  /* spacing / radii / elevation */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px; --sp-6: 32px;
  --r-sm: 8px; --r-md: 12px; --r-lg: 16px; --r-pill: 999px;
  /* boarding-pass "ticket" radius — crisper than card radius */
  --r-ticket: 10px;
  --font: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  --font-display: "Bricolage Grotesque", "IBM Plex Sans", -apple-system, BlinkMacSystemFont, sans-serif;

  /* dark "ink board" palette (default) — deep terminal ink, split-flap amber.
     Amber is the brand/interactive accent; price moves use signal green (down)
     / red (up); a deal gets a green "great price" halo so it never collides
     with the amber accent. */
  --bg: #0a0c10;
  --bg-accent:
    radial-gradient(1100px 520px at 80% -14%, rgba(255, 176, 32, .12), transparent 60%),
    radial-gradient(900px 520px at 4% 6%, rgba(45, 212, 191, .07), transparent 55%);
  /* faint board dot-grid texture layered under content (atmosphere, low opacity) */
  --bg-grid:
    radial-gradient(circle at 1px 1px, rgba(255, 255, 255, .035) 1px, transparent 0);
  --bg-grid-size: 22px 22px;
  --panel: #12151c;
  --card: #161a23;
  --card-top: #1b212c;
  --line: #2a3140;
  --line-strong: #404a5e;
  --txt: #f1f4fa;
  --muted: #b7c0d2;
  --accent: #ffb000;          /* departure-board amber */
  --accent-strong: #ff9100;
  --accent-soft: rgba(255, 176, 32, .14);
  --on-accent: #1a1405;       /* text/icon sitting on a filled amber surface */
  --good: #34d399;            /* price down / good */
  --good-soft: rgba(52, 211, 153, .15);
  --bad: #fb7185;             /* price up / bad */
  --bad-soft: rgba(251, 113, 133, .14);
  --deal: #34d399;            /* great-price halo (green, not amber) */
  --deal-soft: rgba(52, 211, 153, .16);
  --shadow-1: 0 1px 2px rgba(0, 0, 0, .45);
  --shadow-2: 0 16px 44px rgba(0, 0, 0, .55);
  --topbar-bg: rgba(12, 14, 19, .82);
  color-scheme: dark;
}

/* light palette, twice: once for OS preference (when the toggle is on
   "system" there is no data-theme attribute), once for the explicit toggle. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    /* "paper boarding pass" — warm manila stock, ink text, amber + ink accents */
    --bg: #f4efe4;
    --bg-accent:
      radial-gradient(1100px 520px at 80% -14%, rgba(201, 122, 0, .10), transparent 60%),
      radial-gradient(900px 520px at 4% 6%, rgba(13, 148, 136, .06), transparent 55%);
    --bg-grid:
      radial-gradient(circle at 1px 1px, rgba(60, 45, 20, .05) 1px, transparent 0);
    --panel: #fffdf8;
    --card: #fffdf8;
    --card-top: #f7f1e6;
    --line: #e3dac6;
    --line-strong: #c8bb9e;
    --txt: #2a2418;
    --muted: #6b6450;
    --accent: #b86b00;          /* ink-on-paper amber (darkened for contrast) */
    --accent-strong: #99560a;
    --accent-soft: rgba(184, 107, 0, .12);
    --on-accent: #fff8ea;
    --good: #0f7a52;
    --good-soft: rgba(15, 122, 82, .12);
    --bad: #c0392b;
    --bad-soft: rgba(192, 57, 43, .09);
    --deal: #0f7a52;
    --deal-soft: rgba(15, 122, 82, .13);
    --shadow-1: 0 1px 2px rgba(60, 45, 20, .08);
    --shadow-2: 0 16px 44px rgba(60, 45, 20, .16);
    --topbar-bg: rgba(255, 253, 248, .85);
    color-scheme: light;
  }
}
:root[data-theme="light"] {
  /* "paper boarding pass" — keep in sync with the @media light block above */
  --bg: #f4efe4;
  --bg-accent:
    radial-gradient(1100px 520px at 80% -14%, rgba(201, 122, 0, .10), transparent 60%),
    radial-gradient(900px 520px at 4% 6%, rgba(13, 148, 136, .06), transparent 55%);
  --bg-grid:
    radial-gradient(circle at 1px 1px, rgba(60, 45, 20, .05) 1px, transparent 0);
  --panel: #fffdf8;
  --card: #fffdf8;
  --card-top: #f7f1e6;
  --line: #e3dac6;
  --line-strong: #c8bb9e;
  --txt: #2a2418;
  --muted: #6b6450;
  --accent: #b86b00;
  --accent-strong: #99560a;
  --accent-soft: rgba(184, 107, 0, .12);
  --on-accent: #fff8ea;
  --good: #0f7a52;
  --good-soft: rgba(15, 122, 82, .12);
  --bad: #c0392b;
  --bad-soft: rgba(192, 57, 43, .09);
  --deal: #0f7a52;
  --deal-soft: rgba(15, 122, 82, .13);
  --shadow-1: 0 1px 2px rgba(60, 45, 20, .08);
  --shadow-2: 0 12px 34px rgba(60, 45, 20, .14);
  --topbar-bg: rgba(255, 253, 248, .85);
  color-scheme: light;
}

/* ---- base ---- */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg);
  /* board atmosphere: warm glow + faint dot-grid, fixed so it reads as a backdrop */
  background-image: var(--bg-accent), var(--bg-grid);
  background-size: auto, var(--bg-grid-size, 22px 22px);
  background-repeat: no-repeat, repeat;
  background-attachment: fixed, fixed;
  color: var(--txt);
  font: 16.5px/1.6 var(--font);
  -webkit-font-smoothing: antialiased;
  transition: background-color .25s ease, color .25s ease;
}
/* every numeral / flight code / code-like datum reads as split-flap board type */
.mono, .price, .delta, .chip, .fare-price, .fare-times, .stat-v,
.summary-stat strong, .datecell-p, .pricepos-now, .pricepos-ends,
table.snaps td, .iata {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
main { max-width: 1200px; margin: 0 auto; padding: var(--sp-6) 24px 80px; }
h1 { font-family: var(--font-display); font-size: 36px; font-weight: 750; letter-spacing: -.03em; margin: 6px 0 20px; }
h2 { font-family: var(--font-display); font-size: 22px; font-weight: 650; letter-spacing: -.02em; margin: 0 0 12px; }
code { background: var(--accent-soft); border-radius: 5px; padding: 1px 5px; font-size: .9em; }

/* ---- topbar ---- */
.topbar {
  display: flex; align-items: center; gap: 16px;
  padding: 10px 18px;
  padding-top: calc(10px + env(safe-area-inset-top));
  padding-left: calc(18px + env(safe-area-inset-left));
  padding-right: calc(18px + env(safe-area-inset-right));
  background: var(--topbar-bg);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  backdrop-filter: saturate(160%) blur(14px);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 40;
}
.brand {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--font-display);
  font-weight: 750; font-size: 18.5px; letter-spacing: -.02em; color: var(--txt);
}
.brand:hover { text-decoration: none; }
.brand svg { width: 28px; height: 28px; border-radius: 8px; box-shadow: var(--shadow-1); }
.folder-chip {
  font-size: 12px; color: var(--muted); background: var(--card);
  border: 1px solid var(--line); border-radius: var(--r-pill);
  padding: 3px 11px; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; max-width: 180px;
}
.topbar nav { margin-left: auto; display: flex; align-items: center; gap: 16px; }
.topbar nav a { color: var(--muted); font-weight: 550; font-size: 15px; }
.topbar nav a:hover, .topbar nav a[aria-current="page"] { color: var(--txt); text-decoration: none; }
/* nav icons are a mobile-only affordance (bottom tab bar); hidden on desktop */
.topbar nav .nav-ic { display: none; }
.inline { display: inline; margin: 0; }

.icon-btn {
  background: var(--card); border: 1px solid var(--line); color: var(--muted);
  width: 32px; height: 32px; border-radius: var(--r-pill); cursor: pointer;
  font-size: 15px; line-height: 1; display: inline-flex;
  align-items: center; justify-content: center;
  transition: border-color .15s, color .15s, transform .15s;
  flex: none;
}
.icon-btn:hover { border-color: var(--accent); color: var(--txt); transform: rotate(20deg); }

/* ---- buttons ---- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 9px 15px; border: 1px solid var(--line);
  border-radius: var(--r-sm); background: var(--card); color: var(--txt);
  cursor: pointer; font: 600 14px/1.4 var(--font);
  transition: border-color .15s, background .15s, transform .1s, box-shadow .15s;
}
.btn:hover { border-color: var(--line-strong); text-decoration: none; box-shadow: var(--shadow-1); }
.btn:active { transform: translateY(1px); }
.btn-primary {
  background: linear-gradient(135deg, var(--accent), var(--accent-strong));
  border-color: var(--accent-strong); color: var(--on-accent);
  box-shadow: 0 4px 14px -4px var(--accent-soft);
}
.btn-primary:hover { border-color: var(--accent-strong); filter: brightness(1.08); }
.btn-danger { background: transparent; border-color: var(--bad); color: var(--bad); }
.btn-danger:hover { background: var(--bad-soft); border-color: var(--bad); }
.btn-on { background: var(--good-soft); border-color: var(--good); color: var(--good); }
.btn[disabled] { opacity: .55; cursor: default; }

/* ---- toasts (flashes) ---- */
.flashes {
  position: fixed; z-index: 60;
  top: calc(64px + env(safe-area-inset-top)); right: 16px;
  display: flex; flex-direction: column; gap: 8px;
  width: min(380px, calc(100vw - 32px));
  pointer-events: none;
}
.flash {
  pointer-events: auto; cursor: pointer;
  padding: 11px 14px; border-radius: var(--r-md);
  background: var(--panel); border: 1px solid var(--line);
  box-shadow: var(--shadow-2); font-size: 13.5px;
  border-left: 3px solid var(--accent);
  animation: toast-in .3s cubic-bezier(.2, .9, .3, 1.2) both;
  transition: opacity .3s, transform .3s;
}
.flash-ok { border-left-color: var(--good); }
.flash-err { border-left-color: var(--bad); }
.flash-out { opacity: 0; transform: translateX(24px); }
@keyframes toast-in {
  from { opacity: 0; transform: translateX(36px); }
  to   { opacity: 1; transform: none; }
}

/* ---- check-all progress bar ---- */
.progress-wrap {
  max-width: 1200px; margin: 14px auto -6px; padding: 0 24px;
}
.progress-card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 10px 14px; box-shadow: var(--shadow-1);
}
.progress-label { font-size: 13px; color: var(--muted); margin-bottom: 7px; }
.progress-track {
  height: 6px; border-radius: var(--r-pill); background: var(--line); overflow: hidden;
}
.progress-fill {
  height: 100%; width: 0; border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--accent), var(--accent-strong));
  transition: width .5s ease;
}

/* ---- page / cards ---- */
.page-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.cards { display: flex; flex-direction: column; gap: 14px; }
.card {
  background: linear-gradient(180deg, var(--card-top), var(--card));
  border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 18px 20px; box-shadow: var(--shadow-1);
  transition: border-color .2s, box-shadow .2s, transform .2s, opacity .3s;
}
.card:hover { border-color: var(--line-strong); box-shadow: var(--shadow-2); transform: translateY(-2px); }
.card.deal {
  border-color: var(--deal);
  box-shadow: 0 0 0 1px var(--deal) inset, 0 0 24px -6px var(--deal-soft), var(--shadow-1);
}
.card.inactive { opacity: .55; }
.card.checking { opacity: .65; }
.card.checking .card-head h2::after {
  content: ""; display: inline-block; width: 10px; height: 10px; margin-left: 8px;
  border: 2px solid var(--accent); border-top-color: transparent; border-radius: 50%;
  animation: spin .8s linear infinite; vertical-align: middle;
}
@keyframes spin { to { transform: rotate(360deg); } }
.card-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.card-head h2 { margin: 0; }
.card-head h2 a { color: var(--txt); }
.card-head h2 a:hover { color: var(--accent); text-decoration: none; }
.route-sub { color: var(--muted); font-size: 15px; margin: 5px 0 10px; }
.badge {
  font-size: 11.5px; font-weight: 750; letter-spacing: .04em;
  padding: 4px 10px; border-radius: var(--r-pill);
}
.badge-deal { background: var(--deal); color: var(--on-accent); box-shadow: 0 0 12px var(--deal-soft); }
.badge-off { background: var(--line); color: var(--muted); }
/* fare-outlook verdict badges (predict.forecast.recommendation) */
.badge-buy { background: var(--good-soft); color: var(--good); border: 1px solid var(--good); }
.badge-consider { background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent); }
.badge-wait { background: var(--bad-soft); color: var(--bad); border: 1px solid var(--bad); }
.badge-watch { background: var(--card-top); color: var(--muted); border: 1px solid var(--line); }

.price-row { display: flex; align-items: baseline; gap: 10px; }
.price { font-family: var(--font-display); font-size: 34px; font-weight: 800; letter-spacing: -.035em; font-variant-numeric: tabular-nums; }
.delta {
  font-size: 13px; font-weight: 650; padding: 2px 9px; border-radius: var(--r-pill);
  font-variant-numeric: tabular-nums;
}
.delta.up { color: var(--bad); background: var(--bad-soft); }
.delta.down { color: var(--good); background: var(--good-soft); }
.meta { color: var(--muted); font-size: 14px; margin-top: 4px; }
.meta.muted, .muted { color: var(--muted); }
.spark { font-size: 18px; letter-spacing: 1px; margin: 8px 0 2px; color: var(--accent); opacity: .9; }
.warn {
  color: var(--bad); font-size: 13px; line-height: 1.45; margin-top: 10px;
  background: var(--bad-soft); border: 1px solid var(--bad);
  border-radius: var(--r-sm); padding: 8px 10px;
}
.warn .muted { color: var(--muted); }
.card-actions { display: flex; gap: 8px; margin-top: 14px; flex-wrap: wrap; }
.empty { color: var(--muted); }
.empty-state {
  text-align: center; padding: 48px 20px; color: var(--muted);
  border: 1px dashed var(--line-strong); border-radius: var(--r-lg);
}
.empty-state .empty-icon { font-size: 34px; margin-bottom: 10px; }

/* ---- panels / forms ---- */
.panel {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 22px 24px; margin-bottom: 18px;
  box-shadow: var(--shadow-1);
}
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 14px; align-items: end; }
label { display: flex; flex-direction: column; gap: 5px; font-size: 14px; font-weight: 550; }
label small { color: var(--muted); font-weight: 450; }
input, select {
  background: var(--bg); border: 1px solid var(--line); color: var(--txt);
  border-radius: var(--r-sm); padding: 9px 10px;
  font-size: 16px; /* 16px stops iOS zoom-on-focus */
  font-family: var(--font); max-width: 100%;
  transition: border-color .15s, box-shadow .15s;
}
input:focus, select:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.inline-num { width: 80px; display: inline-block; }
.inline-sel { width: auto; display: inline-block; padding: 7px 8px; }
.rules .check { flex-wrap: wrap; }

fieldset { border: 1px solid var(--line); border-radius: var(--r-md); margin: 14px 0; padding: 12px 14px; }
legend { padding: 0 6px; color: var(--muted); font-size: 12px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase; }
.radio, .check { flex-direction: row; align-items: center; gap: 7px; margin: 6px 0; font-weight: 450; }
.checkgrid { display: flex; flex-wrap: wrap; gap: 2px 16px; margin: 4px 0; }
.checkgrid .check { margin: 3px 0; }
.toggles { display: flex; gap: 20px; margin: 12px 0; flex-wrap: wrap; }
.route-form { margin-top: 6px; }
.route-form > label, .route-form .seg-field, .route-form .field-wide { margin: 12px 0; }

/* grouped month / day / year dropdowns → one bordered date control */
.dsel { display: flex; gap: 0; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--bg); overflow: hidden; transition: border-color .15s, box-shadow .15s; }
.dsel:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.dsel select { flex: 1; min-width: 0; border: none; border-radius: 0; background: transparent; padding: 9px 8px; }
.dsel select + select { border-left: 1px solid var(--line); }
.dsel select:focus { box-shadow: none; }

/* segmented pill control — radios styled as a tab strip (trip type, stops, dates) */
.seg-field { display: flex; flex-direction: column; gap: 5px; }
.seg-label { font-size: 13px; font-weight: 550; }
.seg-label small { color: var(--muted); font-weight: 450; }
.segmented { display: flex; gap: 4px; padding: 4px; background: var(--bg);
  border: 1px solid var(--line); border-radius: var(--r-md); }
.segmented label { flex: 1; margin: 0; display: block; cursor: pointer; }
.segmented input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.segmented span { display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 9px 8px; border-radius: var(--r-sm); font-size: 13px; font-weight: 600;
  color: var(--muted); white-space: nowrap;
  transition: background .15s, color .15s, box-shadow .15s; }
.segmented label:hover span { color: var(--txt); }
.segmented input:checked + span { background: var(--card); color: var(--txt); box-shadow: var(--shadow-1); }
.segmented input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- alert-rules selector bar (multi-select toggle pills + revealed inputs) ---- */
.rulefield { display: flex; flex-direction: column; gap: 10px; margin: 14px 0; }
.rulebar { display: flex; gap: 8px; flex-wrap: wrap; }
.rule-pill { flex: 1 1 150px; margin: 0; cursor: pointer; position: relative; }
.rule-pill input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.rule-pill > span {
  display: flex; flex-direction: column; gap: 2px;
  padding: 12px 14px 12px 38px; border-radius: var(--r-md);
  border: 1px solid var(--line); background: var(--bg);
  transition: border-color .15s, background .15s, box-shadow .15s, color .15s;
}
.rule-pill > span b { font-size: 14.5px; font-weight: 650; }
.rule-pill > span small { font-size: 12px; color: var(--muted); font-weight: 450; }
/* the on/off dot */
.rule-pill > span::before {
  content: ""; position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; border-radius: 50%; border: 2px solid var(--line-strong);
  transition: border-color .15s, background .15s, box-shadow .15s;
}
.rule-pill:hover > span { border-color: var(--line-strong); }
.rule-pill input:checked + span {
  border-color: var(--accent); background: var(--accent-soft);
  box-shadow: 0 0 0 1px var(--accent) inset;
}
.rule-pill input:checked + span b { color: var(--accent); }
.rule-pill input:checked + span::before {
  border-color: var(--accent); background: var(--accent);
  box-shadow: inset 0 0 0 3px var(--card);
}
.rule-pill input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }

.rule-details { display: flex; flex-direction: column; gap: 8px; }
.rule-detail {
  display: none; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 14px; color: var(--txt);
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: 10px 13px;
}
.rule-detail .rd-key {
  font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--accent); margin-right: 2px;
}
.rulefield:has(#rule-threshold:checked) .rd-threshold,
.rulefield:has(#rule-pct:checked) .rd-pct { display: flex; }
/* progressive fallback: if :has() is unsupported, JS adds .show */
.rule-detail.show { display: flex; }

/* ---- settings: CSS-only segmented tabs ---- */
.tabs > input { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.tabstrip {
  display: flex; gap: 4px; padding: 5px; margin-bottom: 20px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md);
  box-shadow: var(--shadow-1);
}
.tab {
  flex: 1; text-align: center; padding: 10px 16px; border-radius: var(--r-sm);
  font-size: 14.5px; font-weight: 600; color: var(--muted); cursor: pointer;
  white-space: nowrap; user-select: none;
  transition: background .15s, color .15s, box-shadow .15s;
}
.tab:hover { color: var(--txt); }
.tab-panel { display: none; }
#tab-routes:checked ~ .tabstrip label[for="tab-routes"],
#tab-add:checked    ~ .tabstrip label[for="tab-add"],
#tab-folder:checked ~ .tabstrip label[for="tab-folder"] {
  background: var(--card); color: var(--txt); box-shadow: var(--shadow-1);
}
#tab-routes:checked ~ .panel-routes,
#tab-add:checked    ~ .panel-add,
#tab-folder:checked ~ .panel-folder { display: block; }

/* full-width field that lives outside the auto-fit grid */
.field-wide { display: flex; flex-direction: column; gap: 4px; }
.iata { text-transform: uppercase; letter-spacing: .08em; }
.iata::placeholder { letter-spacing: normal; }

/* collapsible section (preferred airlines) — reads like a fieldset, hides its bulk */
.accordion { border: 1px solid var(--line); border-radius: var(--r-md); margin: 14px 0; }
.accordion > summary { list-style: none; cursor: pointer; user-select: none;
  padding: 13px 14px; color: var(--txt); font-size: 14px; font-weight: 650;
  letter-spacing: .01em; display: flex; align-items: center; gap: 8px; }
.accordion > summary::-webkit-details-marker { display: none; }
.accordion > summary::after { content: "▾"; margin-left: auto; font-size: 13px;
  transition: transform .2s; }
.accordion[open] > summary::after { transform: rotate(180deg); }
.accordion > summary:hover { color: var(--txt); }
.accordion-body { padding: 2px 14px 14px; }

/* larger, easier checkbox / radio tap targets */
.check input[type=checkbox], .check input[type=radio], .radio input[type=radio] {
  width: 18px; height: 18px; margin: 0; padding: 0; border: none;
  accent-color: var(--accent); flex: none; }
.checkgrid .check { padding: 6px 0; font-size: 14.5px; color: var(--txt); }

/* preferred-airline selectable pills (multi-select; SAME checkbox names as before,
   so _route_form parsing is unchanged — just a nicer control than the checkbox grid) */
.airline-pills { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 4px; }
.airline-pills + .airline-pills { margin-top: 4px; }
.airline-pill { margin: 0; cursor: pointer; }
.airline-pill input { position: absolute; opacity: 0; width: 0; height: 0; }
.airline-pill > span {
  display: inline-block; padding: 8px 14px; border-radius: var(--r-pill);
  border: 1px solid var(--line); background: var(--bg); color: var(--txt);
  font-size: 14px; font-weight: 500; white-space: nowrap;
  transition: border-color .15s, background .15s, color .15s, box-shadow .15s;
}
.airline-pill.alliance > span { font-weight: 650; }
.airline-pill:hover > span { border-color: var(--line-strong); }
.airline-pill input:checked + span {
  border-color: var(--accent); background: var(--accent-soft); color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent) inset; font-weight: 650;
}
.airline-pill input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }

.form-actions { margin-top: 16px; }
.datefields { display: flex; gap: 16px; flex-wrap: wrap; margin: 8px 0; }
.datefields > label { flex: 1; min-width: 220px; }
.leg-row { display: flex; gap: 10px; align-items: flex-end; margin: 8px 0; flex-wrap: wrap; }
.leg-row .legno {
  width: 22px; height: 22px; flex: none; border-radius: 50%; background: var(--card);
  border: 1px solid var(--line); color: var(--muted); font-size: 12px;
  display: flex; align-items: center; justify-content: center; margin-bottom: 8px;
}
.leg-row > label:nth-child(2), .leg-row > label:nth-child(3) { width: 90px; flex: none; }
.leg-row > label:last-child { flex: 1; min-width: 220px; }

.route-row {
  border: 1px solid var(--line); border-radius: var(--r-md); padding: 11px 14px;
  margin-bottom: 10px; background: var(--card);
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  transition: border-color .15s;
}
.route-row:hover { border-color: var(--line-strong); }
.route-row-main { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; min-width: 0; }
.route-row-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* ---- route detail page ---- */
.detail-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 6px; }
.detail-hero { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; }
.detail-hero .price { font-size: 52px; }
.stat-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 10px; margin-top: 6px;
}
.stat {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 10px 12px;
}
.stat .stat-k { font-size: 11.5px; font-weight: 650; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }
.stat .stat-v { font-family: var(--font-display); font-size: 21px; font-weight: 750; margin-top: 3px; font-variant-numeric: tabular-nums; }

.chart { position: relative; width: 100%; height: 280px; }
.chart svg { display: block; width: 100%; height: 100%; }
.chart-grid { stroke: var(--line); stroke-width: 1; }
.chart-line { stroke: var(--accent); stroke-width: 2.25; fill: none; stroke-linejoin: round; stroke-linecap: round; }
.chart-area-from { stop-color: var(--accent); stop-opacity: .28; }
.chart-area-to { stop-color: var(--accent); stop-opacity: 0; }
.chart-dot { fill: var(--accent); stroke: var(--panel); stroke-width: 2; }
.chart-pt { fill: var(--accent); stroke: var(--panel); stroke-width: 1.5; }
.chart-guide { stroke: var(--line-strong); stroke-width: 1; stroke-dasharray: 3 3; }
.chart-label { fill: var(--muted); font: 11px var(--font); }
.chart-empty { color: var(--muted); padding: 40px 0; text-align: center; }
.chart-tip {
  position: absolute; pointer-events: none; z-index: 5; display: none;
  background: var(--panel); border: 1px solid var(--line-strong);
  border-radius: var(--r-sm); box-shadow: var(--shadow-2);
  padding: 6px 10px; font-size: 12.5px; white-space: nowrap;
  transform: translate(-50%, calc(-100% - 12px));
}
.chart-tip .tip-price { font-weight: 700; font-size: 14px; }

.outlook { display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap; }
.rec-pill {
  font-size: 14px; font-weight: 750; padding: 7px 16px; border-radius: var(--r-pill);
  border: 1px solid var(--line); white-space: nowrap;
}
/* buy = green, consider = amber, wait = red (prices likely to fall → hold off),
   watch = neutral. Distinct hues under the ink+amber palette. */
.rec-buy-now { background: var(--good-soft); border-color: var(--good); color: var(--good); }
.rec-consider-buying { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.rec-wait { background: var(--bad-soft); border-color: var(--bad); color: var(--bad); }
.rec-watch { background: var(--card); color: var(--muted); }
.conf-track { height: 5px; border-radius: var(--r-pill); background: var(--line); overflow: hidden; width: 140px; margin-top: 6px; }
.conf-fill { height: 100%; background: linear-gradient(90deg, var(--accent), var(--good)); border-radius: var(--r-pill); }
.disclaimer { font-size: 11.5px; color: var(--muted); font-style: italic; margin-top: 10px; }

table.snaps { width: 100%; border-collapse: collapse; font-size: 13.5px; }
table.snaps th {
  text-align: left; color: var(--muted); font-size: 11.5px; font-weight: 650;
  letter-spacing: .05em; text-transform: uppercase;
  padding: 6px 10px; border-bottom: 1px solid var(--line);
}
table.snaps td { padding: 8px 10px; border-bottom: 1px solid var(--line); font-variant-numeric: tabular-nums; }
table.snaps tr:last-child td { border-bottom: none; }

/* ---- footer ---- */
.foot { text-align: center; color: var(--muted); font-size: 12px; padding: 20px; }
.foot form, .foot .btn { display: inline; }
.linklike { background: none; border: none; color: var(--muted); cursor: pointer; text-decoration: underline; font: inherit; padding: 0; }

/* ---- login (boarding-pass card) ---- */
.login-wrap { display: flex; min-height: 70vh; align-items: center; justify-content: center; padding: 20px; }
.login-card {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-ticket);
  border-top: 3px solid var(--accent);
  padding: 30px 28px; width: 100%; max-width: 340px; text-align: center;
  box-shadow: var(--shadow-2); position: relative;
}
/* tear line under the title, with two side punch-notches → reads as a ticket */
.login-card h1 { font-size: 20px; margin: 10px 0 0; padding-bottom: 20px; position: relative; }
.login-card h1::after {
  content: ""; position: absolute; left: -28px; right: -28px; bottom: 0;
  border-bottom: 2px dashed var(--line-strong);
}
.login-card::before, .login-card::after {
  content: ""; position: absolute; width: 18px; height: 18px; border-radius: 50%;
  background: var(--bg); border: 1px solid var(--line); bottom: 92px;
}
.login-card::before { left: -10px; }
.login-card::after { right: -10px; }
.login-card form { margin-top: 18px; }
.login-card .login-logo svg { width: 52px; height: 52px; border-radius: 14px; }
.login-card label { text-align: left; }
.login-card .flash { position: static; animation: none; margin-bottom: 12px; }

/* ---- skeleton (loading) ---- */
.skeleton {
  background: linear-gradient(90deg, var(--line) 25%, var(--card) 50%, var(--line) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.4s infinite; border-radius: var(--r-sm);
}
@keyframes shimmer { to { background-position: -200% 0; } }

/* ================================================================
   Dashboard v2 — summary bar, controls, richer card, sparkline,
   price-target bar, cheaper-alternative, overflow menu.
   ================================================================ */

/* summary bar — a departure-board status strip: ink bar, mono, amber pulse */
.summary {
  display: flex; flex-wrap: wrap; gap: 6px 22px; align-items: center;
  padding: 12px 18px 12px 40px; margin-bottom: 16px; position: relative;
  font-family: var(--font-mono); font-size: 12.5px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted);
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-ticket);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .02);
}
/* a live "board active" amber dot, top-left */
.summary::before {
  content: ""; position: absolute; left: 18px; top: 50%;
  width: 9px; height: 9px; margin-top: -4px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 10px var(--accent);
  animation: board-pulse 2.4s ease-in-out infinite;
}
@keyframes board-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
.summary-stat strong { color: var(--txt); font-weight: 600; letter-spacing: .04em; }
.summary-stat.has-deals strong { color: var(--accent); }

/* sort / filter / search controls */
.controls { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-bottom: 16px; }
.control-input {
  background: var(--card); border: 1px solid var(--line); color: var(--txt);
  border-radius: var(--r-sm); padding: 9px 12px; font: inherit; font-size: 14px;
}
.control-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
#card-search { flex: 1 1 220px; max-width: 320px; }
/* dashboard filter toggles — same dot-pill look as the settings "Alert me when"
   rules (.rule-pill), just sized to sit inline in the controls bar */
.toggle-pill { flex: 0 0 auto; }
.toggle-pill > span { padding: 10px 16px 10px 38px; }
.toggle-pill > span b { font-size: 15px; }
.no-match { text-align: center; color: var(--muted); padding: 30px; }

/* ================================================================
   Triage dashboard — hero (best deal) + Deals / Watching / Paused
   sections. Surfaces what to act on instead of a flat card list.
   ================================================================ */
.dash-section { margin-top: 24px; }
.section-head {
  display: flex; align-items: center; gap: 10px; margin: 0 0 12px;
  font-family: var(--font-mono); font-size: 12px; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--muted);
}
.section-head::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.section-count {
  font-family: var(--font-mono); font-size: 11px; color: var(--txt);
  background: var(--card-top); border: 1px solid var(--line);
  border-radius: var(--r-pill); padding: 1px 9px;
}
/* paused = a collapsed <details> */
.section-paused { margin-top: 24px; }
.section-paused > summary { cursor: pointer; list-style: none; }
.section-paused > summary::-webkit-details-marker { display: none; }
.section-paused > summary::before { content: "▸"; color: var(--muted); transition: transform .15s; }
.section-paused[open] > summary::before { transform: rotate(90deg); }
.section-paused .cards { margin-top: 12px; }

.no-deals {
  margin: 16px 0 4px; padding: 14px 18px;
  font-family: var(--font-mono); font-size: 13px; color: var(--muted);
  background: var(--panel); border: 1px dashed var(--line-strong);
  border-radius: var(--r-ticket);
}
.no-deals strong { color: var(--accent); }

/* hero — the single best deal, a prominent amber-edged boarding pass */
.hero {
  position: relative; margin: 18px 0 4px; padding: 20px 22px;
  background: linear-gradient(180deg, var(--card-top), var(--card));
  border: 1px solid var(--accent); border-radius: var(--r-lg);
  box-shadow: 0 0 0 1px var(--accent) inset, 0 0 34px -10px var(--accent-soft), var(--shadow-1);
  animation: rise-in .42s ease both;
}
.hero-tag {
  font-family: var(--font-mono); font-size: 11.5px; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: var(--accent); margin-bottom: 10px;
}
.hero-main { display: flex; align-items: flex-start; justify-content: space-between;
  gap: 18px 28px; flex-wrap: wrap; }
.hero-id { flex: 1 1 320px; min-width: 0; }
.hero-route { font-family: var(--font-mono); font-weight: 600;
  font-size: clamp(26px, 5.5vw, 42px); letter-spacing: .04em; color: var(--txt);
  display: inline-flex; align-items: center; gap: 14px; }
.hero-route:hover { text-decoration: none; }
.hero-route:hover .bp-code { color: var(--accent); }
.hero-route .bp-code { color: inherit; transition: color .15s; }
.hero-route .bp-plane { color: var(--accent); font-size: .8em; transform: translateY(-1px); }
.hero-label { font-family: var(--font-display); font-size: 18px; font-weight: 650; margin-top: 4px; }
.hero .route-sub { margin: 4px 0 0; }
.hero-why { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; align-items: center; }
.hero-price { text-align: right; flex: 0 0 auto; }
.hero .price { font-size: clamp(40px, 8vw, 60px); line-height: 1; }
.hero-low { font-family: var(--font-mono); font-size: 12px; color: var(--good); margin-top: 5px; }
.hero-actions { display: flex; gap: 10px; margin-top: 16px; flex-wrap: wrap; }
/* the hero now carries the same fare table + gauge + sparkline as the cards */
.hero .pricepos, .hero .fares { margin-top: 16px; }
.hero-trend { margin-top: 14px; max-width: 360px; }
.hero-trend .spark { margin: 0; width: 100%; }
/* checking spinner on the hero (mirrors .card.checking) */
.hero.checking { opacity: .7; }
.hero.checking .hero-tag::after {
  content: ""; display: inline-block; width: 10px; height: 10px; margin-left: 8px;
  border: 2px solid var(--accent); border-top-color: transparent; border-radius: 50%;
  animation: spin .8s linear infinite; vertical-align: middle;
}

/* airline badge + chips */
.airline-badge {
  display: inline-flex; align-items: center; justify-content: center; align-self: center;
  width: 30px; height: 30px; border-radius: 50%; flex: none; overflow: hidden;
  background: var(--brand-soft, var(--accent-soft)); color: var(--brand, var(--accent));
  font-size: 11px; font-weight: 750; letter-spacing: .02em;
}
/* vendored SVG logos sit on a white chip so full-color marks read in both themes */
.airline-badge.has-logo { background: #fff; border: 1px solid var(--line); padding: 3px; }
.airline-logo { width: 100%; height: 100%; object-fit: contain; display: block; }
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.chip {
  font-size: 14px; padding: 5px 11px; border-radius: var(--r-pill);
  background: var(--card-top); border: 1px solid var(--line); color: var(--txt);
  font-variant-numeric: tabular-nums;
}
.chip.muted { color: var(--muted); }
.chip-low { color: var(--good); border-color: var(--good); background: var(--good-soft); }

/* top-3 cheapest itineraries — a clean full-width table on the card.
   A hidden checkbox (.fare-cb) per row drives a CSS-only collapse so the flight
   times show inline on desktop but tap-to-expand on mobile (keeps the row short
   so it never runs off-screen). No JS → CSP-safe. */
.fares { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column;
  border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; }
.fare + .fare { border-top: 1px solid var(--line); }
.fare-cb { position: absolute; opacity: 0; width: 0; height: 0; }
.fare-row { display: flex; flex-direction: row; align-items: center; gap: 12px;
  flex-wrap: wrap; padding: 11px 14px; margin: 0; font-weight: 500; background: var(--card); }
.fare:first-child .fare-row { background: var(--card-top); box-shadow: inset 3px 0 0 var(--accent); }
.fare:first-child .fare-price { color: var(--accent); }
.fare .airline-badge { width: 30px; height: 30px; font-size: 11px; }
.airline-badge-generic { background: var(--line); color: var(--muted); font-size: 14px; }
.airline-name { font-size: 15.5px; font-weight: 650; color: var(--txt); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; flex: 0 1 auto; }
/* always-visible trip line: "Nov 26 → Dec 3 · 1 stop" (mono, both directions' dates) */
.fare-when { color: var(--muted); font-size: 13.5px; font-family: var(--font-mono);
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.fare-price { font-size: 17px; font-weight: 750; font-variant-numeric: tabular-nums;
  margin-left: auto; white-space: nowrap; }
.fare-chevron { color: var(--muted); font-size: 12px; flex: none; transition: transform .15s; }
.fare-plus { color: var(--accent); font-weight: 700; font-size: 11px; margin-left: 1px; }

/* Expandable per-leg detail dropdown — collapsed by default at EVERY width, opened by
   the hidden .fare-cb checkbox (CSP-safe, no JS). Tap/click the row to toggle. */
.fare-row { cursor: pointer; }
.fare-detail { display: none; flex-basis: 100%; order: 1; padding-left: 42px;
  flex-direction: column; gap: 3px; }
.fare-cb:checked + .fare-row .fare-detail { display: flex; }
.fare-cb:checked + .fare-row .fare-chevron { transform: rotate(180deg); }
.fare-leg { color: var(--muted); font-size: 13.5px; font-family: var(--font-mono);
  font-variant-numeric: tabular-nums; }
.fare-leg-dir { display: inline-block; min-width: 52px; color: var(--muted);
  text-transform: uppercase; font-size: 11px; letter-spacing: .04em; }

/* cheapest-depart-date mini calendar (route detail, flexible routes) */
.datecal { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.datecell {
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--card-top); padding: 8px 12px; text-align: center; min-width: 92px;
}
.datecell-d { font-size: 12.5px; color: var(--muted); }
.datecell-p { font-size: 16px; font-weight: 750; font-variant-numeric: tabular-nums; margin-top: 2px; }
.datecell.is-low { border-color: var(--good); background: var(--good-soft); }
.datecell.is-low .datecell-p { color: var(--good); }

/* price-position gauge: a marker for TODAY on a low->max scale (low = cheap,
   left/green; max = right/red). Replaces the old fill bar, whose fill grew
   toward the 'max' label and read backwards. Lives in its own card row. */
.pricepos { margin: 0; }
.pricepos-track {
  position: relative; height: 8px; border-radius: var(--r-pill);
  margin-top: 17px;   /* clearance for the price label floating above the pin */
  background: linear-gradient(90deg, var(--good), var(--deal) 52%, var(--bad));
}
.pricepos-pin {
  position: absolute; top: 50%; transform: translate(-50%, -50%);
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--txt); border: 3px solid var(--panel); box-shadow: var(--shadow-1);
}
.pricepos-now {
  position: absolute; left: 50%; bottom: calc(100% + 5px); transform: translateX(-50%);
  font-size: 11px; font-weight: 750; white-space: nowrap;
  color: var(--txt); font-variant-numeric: tabular-nums;
}
.pricepos-ends {
  display: flex; justify-content: space-between; margin-top: 7px;
  font-size: 10.5px; color: var(--muted); font-variant-numeric: tabular-nums;
}

/* Date endpoints under the sparkline (oldest … newest check date). */
.spark-dates {
  display: flex; justify-content: space-between; margin-top: 1px;
  font-size: 10.5px; color: var(--muted); font-variant-numeric: tabular-nums;
}

/* SVG sparkline (replaces the text one when JS runs) */
.spark { height: 36px; margin: 10px 0 2px; overflow: hidden;
  color: var(--accent); opacity: .95; font-size: 16px; line-height: 36px; letter-spacing: 1px; }
.spark .spark-svg { display: block; width: 100%; height: 36px; }
.spark-line { fill: none; stroke: var(--accent); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.spark-low { fill: var(--good); }
.spark-down .spark-line { stroke: var(--good); }
.spark-up .spark-line { stroke: var(--bad); }
.spark-area-from { stop-color: var(--accent); stop-opacity: .22; }
.spark-area-to { stop-color: var(--accent); stop-opacity: 0; }
.spark-down .spark-area-from { stop-color: var(--good); stop-opacity: .20; }
.spark-up .spark-area-from { stop-color: var(--bad); stop-opacity: .18; }

/* cheaper-alternative call-to-action */
.alt-fare {
  display: flex; align-items: center; gap: 8px; margin-top: 10px;
  padding: 8px 10px; border-radius: var(--r-sm); font-size: 13px; color: var(--txt);
  background: var(--accent-soft); border: 1px solid transparent;
}
.alt-fare:hover { border-color: var(--accent); text-decoration: none; }
.alt-fare .alt-icon { flex: none; }
.alt-fare strong { color: var(--accent); }
.alt-fare .alt-go { margin-left: auto; color: var(--muted); }

/* "⋯" overflow menu (native <details>) */
.menu { position: relative; display: inline-block; }
.menu > summary { list-style: none; cursor: pointer; user-select: none; }
.menu > summary::-webkit-details-marker { display: none; }
.menu-pop {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 30; min-width: 184px;
  background: var(--panel); border: 1px solid var(--line-strong);
  border-radius: var(--r-md); box-shadow: var(--shadow-2); padding: 6px;
}
.menu-pop form { display: block; margin: 0; }
.menu-item {
  display: block; width: 100%; text-align: left; background: none; border: none;
  color: var(--txt); font: inherit; font-size: 13.5px; padding: 8px 10px;
  border-radius: var(--r-sm); cursor: pointer;
}
.menu-item:hover { background: var(--card-top); text-decoration: none; }
.menu-item.danger { color: var(--bad); }
.menu-item.danger:hover { background: var(--bad-soft); }

/* Sectioned one-per-row card (dashboard grid; detail page uses .panel):
   a header row (identity + price), a full-width fares table, then a foot
   (trend + actions). Reads top-to-bottom instead of cramming into columns. */
.cards .card { display: flex; flex-direction: column; gap: 14px; }

.card-top { display: flex; align-items: flex-start; justify-content: space-between;
  gap: 14px 28px; flex-wrap: wrap; }
.card-id { flex: 1 1 300px; min-width: 0; }
.card-id .card-head { margin: 0; }
.card-id .route-sub { margin: 4px 0 0; }
.card-id .meta { margin-top: 3px; }
.card-id .warn { margin-top: 8px; }

/* the price block is the boarding-pass STUB: a perforated tear-off panel. */
.card-head-price { display: flex; flex-direction: column; align-items: flex-end;
  text-align: right; gap: 7px; flex: 0 0 auto; position: relative;
  padding-left: 26px; }
.card-head-price .price-row { align-items: baseline; }
.card-head-price .chips { margin: 0; justify-content: flex-end; }
.cards .price { font-size: 40px; line-height: 1; }
.cards .card.deal .price { color: var(--deal); }
/* perforation: a dashed tear line down the stub's left edge with two punch
   notches that "cut" into the ticket (filled with the page bg so they read
   as holes). On mobile the card stacks → the line/notches go horizontal. */
.card-head-price::before {
  content: ""; position: absolute; left: 0; top: -6px; bottom: -6px;
  border-left: 2px dashed var(--line-strong);
}
/* a punch notch straddling the top of the tear line (reads as a ticket hole) */
.card-head-price::after {
  content: ""; position: absolute; left: -9px; top: -18px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--bg); border: 1px solid var(--line);
}
.board-route {
  display: flex; align-items: center; gap: 12px; margin: 8px 0 2px;
  font-family: var(--font-mono); font-weight: 600;
  font-size: clamp(20px, 4.5vw, 30px); letter-spacing: .04em; color: var(--txt);
}
.board-route .bp-link { display: inline-flex; align-items: center; gap: 12px;
  color: var(--txt); }
.board-route .bp-link:hover { text-decoration: none; }
.board-route .bp-link:hover .bp-code { color: var(--accent); }
.board-route .bp-code { color: inherit; transition: color .15s; }
.board-route .bp-plane { color: var(--accent); font-size: .8em;
  transform: translateY(-1px); }

.card-foot { display: flex; align-items: center; justify-content: space-between;
  gap: 14px 28px; flex-wrap: wrap; border-top: 1px solid var(--line); padding-top: 13px; }
/* shorter sparkline on desktop so the action buttons get real estate (#4) */
.card-trend { flex: 0 1 340px; min-width: 0; max-width: 360px;
  display: flex; flex-direction: column; gap: 7px; }
.card-trend .spark { margin: 0; width: 100%; height: 40px; }
.card-trend .spark .spark-svg { height: 40px; }
.card-trend .alt-fare { margin: 0; }
.cards .card-actions { margin: 0; justify-content: flex-end; flex: 0 0 auto; }
/* desktop: chunkier Check / Edit buttons (paired with the shorter sparkline) */
@media (min-width: 641px) {
  .cards .card-actions .btn { padding: 11px 22px; font-size: 14.5px; }
  .cards .card-actions > form[data-route-check] .btn,
  .cards .card-actions > a.btn { min-width: 96px; }
}

/* gentle entrance on load. The .cards CONTAINER animates once (not each card),
   so live card swaps never replay an entrance — they get cardflash + the
   split-flap price reveal below instead. */
@keyframes rise-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
main > h1, .summary, .controls, .panel, .empty-state, .tabstrip, #cards { animation: rise-in .42s ease both; }

/* brief highlight when a card refreshes live (also overrides the hero's rise-in
   so a live hero swap flashes in place instead of replaying the entrance) */
.card.just-updated,
.hero.just-updated { animation: cardflash 1.2s ease; }
@keyframes cardflash {
  0% { box-shadow: 0 0 0 2px var(--accent) inset, var(--shadow-2); }
  100% { box-shadow: var(--shadow-1); }
}
/* split-flap reveal: the price flips down when a card refreshes live. Triggered
   by .just-updated, which checks.js adds synchronously on swap (CSS-only, no JS).
   Suppressed under prefers-reduced-motion by the global block below. */
.card-head-price, .hero-price { perspective: 480px; }
.card.just-updated .price,
.hero.just-updated .price {
  display: inline-block; transform-origin: 50% 0;
  animation: split-flap .55s cubic-bezier(.2, .75, .25, 1) both;
}
@keyframes split-flap {
  0%   { transform: rotateX(-88deg); opacity: 0; }
  55%  { transform: rotateX(12deg);  opacity: 1; }
  100% { transform: rotateX(0);      opacity: 1; }
}

/* ---- reduced motion ---- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ---- mobile / iPhone ---- */
@media (max-width: 640px) {
  main { padding: 16px 14px calc(96px + env(safe-area-inset-bottom)); }
  h1 { font-size: 24px; }

  /* hero stacks: route/why over price, full-width CTAs */
  .hero { padding: 16px; }
  .hero-main { flex-direction: column; gap: 12px; }
  .hero-price { text-align: left; }
  .hero-actions .btn { flex: 1 1 auto; }

  /* settings tabs: full-width 3-up segmented bar, tighter so labels fit */
  .tabstrip { gap: 3px; padding: 4px; }
  .tab { padding: 9px 6px; font-size: 13px; }
  /* alert-rules pills stack 1-up for comfortable tap targets */
  .rule-pill { flex: 1 1 100%; }

  .topbar { gap: 10px;
    /* Drop the blur on mobile: a backdrop-filter ancestor becomes the containing
       block for its position:fixed children, which traps the bottom tab bar up
       under the topbar instead of pinning it to the viewport bottom. With no blur,
       use a SOLID background so scrolled content can't ghost through the bar. */
    background: var(--bg);
    -webkit-backdrop-filter: none; backdrop-filter: none; }
  .brand span { white-space: nowrap; }   /* never wrap "Flight Tracker" onto two lines */
  #theme-toggle { margin-left: auto; }    /* nav is at the bottom now → push toggle right */
  .folder-chip { max-width: 110px; }

  /* nav becomes a fixed bottom tab bar: equal-width icon-over-label tabs */
  .topbar nav {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
    margin: 0; padding: 6px 10px calc(6px + env(safe-area-inset-bottom));
    background: var(--topbar-bg);
    -webkit-backdrop-filter: saturate(160%) blur(14px);
    backdrop-filter: saturate(160%) blur(14px);
    border-top: 1px solid var(--line);
    justify-content: space-around; gap: 4px;
  }
  .topbar nav a, .topbar nav .btn, .topbar nav form {
    flex: 1; min-width: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px; padding: 6px 4px; white-space: nowrap;
  }
  .topbar nav form { padding: 0; }
  .topbar nav form .btn { width: 100%; padding: 6px 4px; }
  .topbar nav .nav-ic { display: block; font-size: 20px; line-height: 1; }
  .topbar nav .nav-tx { font-size: 10.5px; font-weight: 600; letter-spacing: .01em; }
  .topbar nav a[aria-current="page"] { color: var(--accent); }
  /* the primary "Check all" reads as an accent tab, not a filled gradient block */
  .topbar nav .btn-primary {
    background: none; border: none; color: var(--accent); box-shadow: none;
  }
  .topbar nav .btn-primary:hover { filter: none; box-shadow: none; }

  .flashes { top: calc(58px + env(safe-area-inset-top)); }

  /* sectioned card stacks fully: price block drops under the identity, the foot
     stacks trend over the action buttons */
  .cards .card { gap: 12px; }
  .card-top { flex-direction: column; gap: 10px; }
  /* the desktop flex-basis (300/320px) is a WIDTH; in these stacked columns it
     becomes a HEIGHT and leaves a big void — reset to content height */
  .card-id, .card-trend { flex: 0 1 auto; }
  /* stub sits BELOW the identity now → the perforation goes horizontal */
  .card-head-price { align-items: flex-start; text-align: left;
    width: 100%; padding-left: 0; padding-top: 16px; }
  .card-head-price .chips { justify-content: flex-start; }
  .card-head-price::before { left: -6px; right: -6px; top: 0; bottom: auto;
    border-left: none; border-top: 2px dashed var(--line-strong); }
  .card-head-price::after { left: -19px; top: -9px; }
  .card-foot { flex-direction: column; align-items: stretch; gap: 12px; }
  .cards .card-actions { justify-content: flex-start; }
  .grid { grid-template-columns: 1fr; }
  /* route form: keep short fields 2-up instead of 1-per-row → far less scrolling */
  .route-form .grid { grid-template-columns: repeat(2, 1fr); gap: 10px 12px; }
  .route-form .grid > * { min-width: 0; }   /* let tracks shrink; labels wrap, no clip */
  .route-form .grid .field-wide,
  .route-form .grid > label.wide { grid-column: 1 / -1; }
  .route-form .form-actions .btn { width: 100%; padding: 13px; font-size: 16px; }
  .segmented span { padding: 10px 6px; font-size: 12.5px; }
  .checkgrid { gap: 2px 12px; }
  .checkgrid .check { padding: 7px 0; }
  .btn { padding: 11px 14px; font-size: 15px; }
  /* detail page action row: buttons fill available width and wrap */
  .card-actions .btn, .card-actions form { flex: 1 1 auto; }
  .card-actions form .btn { width: 100%; }
  /* dashboard card: Check + Edit are equal halves; ⋯ is a compact trailer (#3) */
  .cards .card-actions > form[data-route-check],
  .cards .card-actions > a.btn { flex: 1 1 0; min-width: 0; }
  .cards .card-actions > .menu { flex: 0 0 auto; }

  .toggles { flex-direction: column; gap: 10px; }
  .price { font-size: 32px; }
  .detail-hero .price { font-size: 36px; }
  .chart { height: 220px; }
  .route-row summary { flex-wrap: wrap; }
  table.snaps th:nth-child(n+5), table.snaps td:nth-child(n+5) { display: none; }

  /* inline numeric inputs (max price, % drop) shouldn't span full width */
  .inline-num { width: 90px; }
}

/* respect users who add the app to the home screen (standalone) */
@media all and (display-mode: standalone) {
  body { min-height: 100vh; }
}
