/* ==========================================================================
   Skylark — stylesheet

   Direction B, glass cockpit. An instrument, not a dashboard.

   The vocabulary is deliberately small. Every colour, size, radius and gap
   comes from the token table in DESIGN.md, which also records the measured
   problem this replaced: 8 border radii, 9 font sizes and 11 hues.

   Layers, in order:
     1. Tokens      2. Base        3. Access      4. Shell
     5. Primitives  6. Tail        7. Dublin      8. Overhead
     9. Pilot brief 10. 3D sky     11. Responsive
   ========================================================================== */

/* ==========================================================================
   1. Tokens
   ========================================================================== */

:root {
  /* Surfaces. Opaque, flat, no gradients anywhere. */
  --bg: #04060a;
  --bg-sunk: #070a0f;
  --bg-raise: #0b0f16;
  --line: #141821;
  --line-strong: #232936;

  /* Ink */
  --text: #eaf0f7;
  --text-dim: #b0b7c1;
  --muted: #767f8c;

  /* Signal. Amber, green and red, and nothing else. */
  --accent: #f5a524;
  --live: #35d07f;
  --alert: #ff5c5c;
  --neutral: #949ba6;

  /* State, derived from the signal set so a value is never invented inline. */
  --arriving: var(--accent);
  --departing: var(--live);
  --ground: var(--neutral);
  --overflight: var(--neutral);
  --selected: var(--text);
  --focus: #eaf0f7;

  /* Type. Five sizes, each a clear step from the next. */
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  --font-prose: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, "Segoe UI", Roboto, sans-serif;
  --fs-micro: 9.5px;
  --fs-sm: 11.5px;
  --fs-base: 13.5px;
  --fs-lg: 17px;
  --fs-num: 22px;
  --track: 0.2em;
  --lh-tight: 1.3;
  --lh-base: 1.5;

  /* Space */
  --sp-1: 4px;
  --sp-2: 6px;
  --sp-3: 8px;
  --sp-4: 10px;
  --sp-5: 12px;
  --sp-6: 16px;
  --sp-7: 20px;
  --sp-8: 28px;

  /* Radius. Two values. */
  --r: 4px;
  --r-sm: 2px;

  /* Motion */
  --t-fast: 120ms;
  --t-base: 180ms;
  --ease: cubic-bezier(0.2, 0.7, 0.3, 1);

  /* Shell geometry, measured from JavaScript so a wrapped top bar and the
     alert banner can never desynchronise the layout height. */
  --shell-h: 60px;

  color-scheme: dark;
}

/* ==========================================================================
   2. Base
   ========================================================================== */

* { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

body {
  background: var(--bg);
  color: var(--text);
  font: var(--fs-base)/var(--lh-base) var(--font-mono);
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  touch-action: manipulation;
}

/* The only places the product holds a real paragraph. Monospace prose is
   measurably harder to read and these are the exceptions to the mono rule. */
.brief-raw,
.notam-text,
#airframeCaveat,
#overheadHelp,
#schSource,
.overhead-profile > .muted,
.notice,
.taf-period,
.brief-note,
.wx-raw,
.fbwrap p,
.sky-fallback span {
  font-family: var(--font-prose);
}

a { color: var(--text-dim); text-decoration: underline; text-underline-offset: 2px; }
a:hover { color: var(--text); }

code {
  font-family: var(--font-mono);
  background: var(--bg-sunk);
  padding: 1px 5px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
}

h1, h2, h3, h4 { line-height: var(--lh-tight); }

.metric strong,
.dub-stat b,
.row b,
.board .row-flight,
.traffic,
.timeline,
.sch-list,
.live-strip,
.ticker,
.wx-grid b,
.brief-kv b,
table.dt td {
  font-variant-numeric: tabular-nums;
}

* { scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border: 3px solid transparent;
  background-clip: padding-box;
  border-radius: var(--r);
}
*::-webkit-scrollbar-thumb:hover { background: var(--muted); background-clip: padding-box; }

/* ==========================================================================
   3. Access
   ========================================================================== */

:where(a, button, input, select, textarea, summary, [tabindex]):focus { outline: none; }
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
.btn:focus-visible,
.seg button:focus-visible,
.viewtabs button:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: var(--sp-4);
  top: -60px;
  z-index: 1000;
  padding: 8px 14px;
  border-radius: var(--r);
  background: var(--bg-raise);
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: var(--fs-sm);
  font-weight: 700;
  transition: top var(--t-fast) var(--ease);
}
.skip-link:focus { top: var(--sp-4); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

@media (prefers-reduced-transparency: reduce) {
  .topbar, .card, .map-overlay, .legend, .sky-legend, .sky-tools, .toasts,
  .sky-label, .sky-hud__stat, .apt-label, .tfc-label, .dm-label, .ov-pin__label {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }
}

@media (prefers-contrast: more) {
  :root { --line: #2a3648; --muted: #93a2b5; --text-dim: #c3cede; }
}

/* ==========================================================================
   4. Shell
   ========================================================================== */

.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-6);
  flex-wrap: wrap;
  padding: var(--sp-4) var(--sp-7);
  background: var(--bg);
  /* The one inset hairline in the product, separating the bar from content
     that scrolls underneath it. */
  box-shadow: inset 0 -1px 0 var(--line);
}

.brand { display: flex; align-items: center; gap: var(--sp-5); min-width: 0; }
.logo { width: 22px; height: 22px; fill: var(--accent); flex: none; }
.brand h1 { margin: 0; font-size: var(--fs-lg); letter-spacing: 0.02em; font-weight: 700; }
.brand .sub {
  margin: 2px 0 0;
  font-size: var(--fs-sm);
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.topstatus { display: flex; align-items: center; gap: var(--sp-5); flex-wrap: wrap; }

.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 5px 10px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-strong);
  background: transparent;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
  white-space: nowrap;
}
.pill .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--muted); flex: none; }
.pill--starting { color: var(--muted); }
.pill--live { color: var(--live); border-color: rgba(53, 208, 127, 0.4); }
.pill--live .dot { background: var(--live); animation: blink 1.6s ease-in-out infinite; }
.pill--quiet { color: var(--accent); border-color: rgba(245, 165, 36, 0.4); }
.pill--quiet .dot { background: var(--accent); }
.pill--error { color: var(--alert); border-color: rgba(255, 92, 92, 0.45); }
.pill--error .dot { background: var(--alert); }
.pill--sim { color: var(--accent); border-color: rgba(245, 165, 36, 0.5); }
.pill--sim .dot { background: var(--accent); animation: blink 1s ease-in-out infinite; }

@keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

.ticker {
  font-size: var(--fs-sm);
  color: var(--muted);
  display: flex;
  gap: var(--sp-3);
  flex-wrap: wrap;
}
.ticker .sep { opacity: 0.5; }

/* buttons ---------------------------------------------------------------- */

.btn {
  appearance: none;
  border: 1px solid var(--line-strong);
  background: transparent;
  color: var(--text-dim);
  padding: 6px 12px;
  border-radius: var(--r);
  font: inherit;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.btn:hover { color: var(--text); border-color: var(--muted); background: var(--bg-raise); }
.btn:active { background: var(--bg-sunk); }
.btn[disabled], .btn[aria-disabled='true'] { opacity: 0.4; cursor: not-allowed; }
.btn--ghost { border-color: var(--line); color: var(--muted); }
.btn--ghost:hover { color: var(--text-dim); border-color: var(--line-strong); }
.btn--small { padding: 5px 9px; font-size: var(--fs-micro); letter-spacing: 0.08em; text-transform: uppercase; }
.btn--on { border-color: var(--accent); color: var(--accent); }
.btn--icon { padding: 5px 8px; line-height: 1; }

.btn.is-busy { position: relative; color: transparent; }
.btn.is-busy::after {
  content: '';
  position: absolute;
  inset: 50% auto auto 50%;
  width: 11px;
  height: 11px;
  margin: -5.5px 0 0 -5.5px;
  border-radius: 50%;
  border: 2px solid var(--text-dim);
  border-top-color: transparent;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* alert banner ----------------------------------------------------------- */

.alert-banner {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: 9px var(--sp-7);
  background: var(--bg-sunk);
  border-bottom: 1px solid rgba(255, 92, 92, 0.45);
  border-left: 3px solid var(--alert);
  color: #ffc9c9;
  font-weight: 700;
  font-size: var(--fs-sm);
  letter-spacing: 0.02em;
}
.alert-banner[hidden] { display: none; }
.alert-banner::before {
  content: '';
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--alert);
}

/* toasts, the one feedback surface present on every view ----------------- */

.toasts {
  position: fixed;
  z-index: 950;
  right: var(--sp-6);
  bottom: var(--sp-6);
  width: min(380px, calc(100vw - 28px));
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  pointer-events: none;
}
.toasts:empty { display: none; }

.toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: var(--sp-4);
  padding: 10px 12px;
  border-radius: var(--r);
  border: 1px solid var(--line-strong);
  border-left-width: 3px;
  background: var(--bg-raise);
  font-size: var(--fs-sm);
  color: var(--text-dim);
  animation: toast-in var(--t-base) var(--ease);
}
.toast::before { content: none; }
.toast--warn { border-left-color: var(--accent); }
.toast--error { border-left-color: var(--alert); color: #ffc9c9; }
.toast--good { border-left-color: var(--live); }
.toast__text { flex: 1; min-width: 0; }
.toast__close {
  appearance: none;
  border: 0;
  background: none;
  color: var(--muted);
  cursor: pointer;
  font: inherit;
  font-size: var(--fs-sm);
  line-height: 1;
  min-width: 26px;
  min-height: 26px;
  display: grid;
  place-items: center;
  margin: -4px -4px -4px 0;
  border-radius: var(--r-sm);
}
.toast__close:hover { color: var(--text); }
@keyframes toast-in { from { opacity: 0; transform: translateY(6px); } }

/* ==========================================================================
   5. Primitives
   ========================================================================== */

.layout {
  display: grid;
  grid-template-columns: minmax(340px, 410px) minmax(0, 1fr);
  gap: var(--sp-5);
  padding: var(--sp-5);
  height: calc(100dvh - var(--shell-h));
}
.layout[hidden] { display: none; }

.panel {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  overflow: auto;
  padding-right: var(--sp-1);
}

.card {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: var(--sp-5) var(--sp-6);
}

.card h2 {
  margin: 0 0 var(--sp-4);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: var(--track);
  color: var(--muted);
  font-weight: 700;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-4);
}
.card h2 small {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: none;
  color: var(--muted);
  font-family: var(--font-mono);
}

.muted { color: var(--muted); }
.small { font-size: var(--fs-sm); line-height: 1.5; }

.notice {
  padding: 9px 11px;
  border-radius: var(--r-sm);
  border-left: 2px solid var(--muted);
  background: var(--bg-sunk);
  color: var(--text-dim);
  font-size: var(--fs-sm);
}
.notice b { color: var(--text); font-weight: 700; }
.notice--warn { border-left-color: var(--accent); color: #f0cf90; }
.notice--warn b { color: var(--accent); }
.notice--error { border-left-color: var(--alert); color: #ffc9c9; }
.notice--error b { color: var(--alert); }
.notice--good { border-left-color: var(--live); color: #a7e8c6; }

.is-stale { opacity: 0.6; }
.stale-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--accent);
}

.skeleton {
  position: relative;
  overflow: hidden;
  background: var(--bg-sunk);
  border-radius: var(--r-sm);
  animation: pulseSkeleton 1.4s ease-in-out infinite;
}
@keyframes pulseSkeleton { 0%, 100% { opacity: 0.5; } 50% { opacity: 0.9; } }
.sk-row { height: 40px; border-radius: var(--r-sm); margin-bottom: var(--sp-2); }
.sk-line { height: 10px; margin: var(--sp-3) 0; }
.sk-line--short { width: 45%; }

/* status card ------------------------------------------------------------ */

.status-head { display: flex; align-items: center; gap: var(--sp-4); margin-bottom: var(--sp-4); flex-wrap: wrap; }
.status-head .muted { font-size: var(--fs-sm); }

.chip {
  display: inline-flex;
  align-items: center;
  padding: 4px 8px;
  border-radius: var(--r-sm);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  border: 1px solid transparent;
  white-space: nowrap;
}
.chip--air { color: var(--live); border-color: rgba(53, 208, 127, 0.4); }
.chip--ground { color: var(--accent); border-color: rgba(245, 165, 36, 0.35); }
.chip--landed { color: var(--live); border-color: rgba(53, 208, 127, 0.35); }
.chip--none { color: var(--neutral); border-color: var(--line-strong); }
.chip--error { color: var(--alert); border-color: rgba(255, 92, 92, 0.4); }
.chip--sim { color: var(--accent); border-color: rgba(245, 165, 36, 0.45); }

.route-line { display: flex; align-items: baseline; gap: var(--sp-4); margin-bottom: var(--sp-4); }
.route-line .apt { font-size: var(--fs-num); font-weight: 700; letter-spacing: 0.02em; }
.route-line .arrow { color: var(--muted); font-size: var(--fs-lg); }
.route-line .tail { margin-left: auto; font-size: var(--fs-sm); color: var(--muted); }

.live-strip {
  font-size: var(--fs-sm);
  color: var(--live);
  background: var(--bg-sunk);
  border-left: 2px solid var(--live);
  border-radius: var(--r-sm);
  padding: 7px 10px;
  margin-bottom: var(--sp-4);
  min-height: 30px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.live-strip.tick { animation: strip 0.7s ease-out; }
@keyframes strip { from { background: rgba(53, 208, 127, 0.14); } to { background: var(--bg-sunk); } }
.live-strip.is-stale { color: var(--accent); border-left-color: var(--accent); }

.progress .bar {
  position: relative;
  height: 4px;
  background: var(--line);
  border-radius: var(--r-sm);
  margin: var(--sp-2) 3px var(--sp-3);
}
.progress .fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0%;
  background: var(--live);
  transition: width 0.8s var(--ease);
}
/* No position, so no progress to draw. The track empties rather than showing a
   filled 0 per cent, which would read as "still at Dublin". */
.progress .bar.is-unknown .fill { background: var(--line-strong); }
.progress .bar.is-unknown .plane { display: none; }
.progress .plane {
  position: absolute;
  top: 50%;
  left: 0%;
  transform: translate(-50%, -52%);
  font-size: var(--fs-sm);
  color: var(--live);
  transition: left 0.8s var(--ease);
}
.progress-meta { display: flex; justify-content: space-between; font-size: var(--fs-sm); color: var(--muted); }
.route-hint { margin-top: var(--sp-3); font-size: var(--fs-sm); color: var(--muted); }

/* telemetry -------------------------------------------------------------- */

.tele { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 var(--sp-6); margin-bottom: var(--sp-5); }
.metric { padding: var(--sp-4) 0; border-top: 1px solid var(--line); min-width: 0; }
.metric label { display: block; font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: var(--track); color: var(--muted); }
.metric strong {
  display: block;
  /* Three of these sit across a 410px panel. Monospace numerals are about 20
     percent wider than the sans they replaced, and 22px overflowed the cell
     on "37,000 ft". 17px keeps a 1.5x step over the label and fits. */
  font-size: var(--fs-lg);
  font-weight: 700;
  margin-top: var(--sp-2);
  color: var(--text);
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.metric small { display: block; font-size: var(--fs-sm); color: var(--muted); min-height: 15px; }
.metric strong.pulse { animation: valuePulse 0.7s ease-out; }
@keyframes valuePulse { 0% { color: var(--live); } 100% { color: var(--text); } }

.rows { display: flex; flex-direction: column; }
.rows.tight { gap: 0; }
.row {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-5);
  font-size: var(--fs-sm);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--line);
}
.row:last-child { border-bottom: 0; padding-bottom: 0; }
.row span { color: var(--muted); flex: none; }
.row b { color: var(--text); font-weight: 700; text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#rLeg, #rRoute { white-space: normal; line-height: 1.35; overflow: visible; }

#spark { display: block; width: 100%; height: 120px; }
.k-alt { background: var(--live); }
.k-gs { background: var(--accent); margin-left: var(--sp-2); }
.k-vs { background: var(--neutral); margin-left: var(--sp-2); }

/* schedule --------------------------------------------------------------- */

.sch-next { font-size: var(--fs-sm); color: var(--live); margin-bottom: var(--sp-4); }
.sch-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.sch-list .leg {
  display: grid;
  grid-template-columns: 56px 68px 1fr auto;
  gap: var(--sp-4);
  align-items: center;
  font-size: var(--fs-sm);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--line);
}
.sch-list .leg:last-child { border-bottom: 0; }
.sch-list .leg .fl { font-weight: 700; color: var(--text); }
.sch-list .leg .rt { color: var(--muted); }
.sch-list .leg .tm { color: var(--muted); text-align: right; }
.sch-list .leg .tag { font-size: var(--fs-micro); letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent); }
.sch-list .leg.active .fl { color: var(--accent); }
.sch-list .leg.done { opacity: 0.45; }

/* event feed ------------------------------------------------------------- */

.feed { list-style: none; margin: 0; padding: 0; max-height: 240px; overflow: auto; display: flex; flex-direction: column-reverse; }
.feed li { display: flex; gap: var(--sp-4); font-size: var(--fs-sm); padding: 5px 0; border-bottom: 1px solid var(--line); }
.feed li time { color: var(--muted); flex: none; }
.feed li.f-air span { color: var(--live); }
.feed li.f-ground span { color: var(--accent); }
.feed li.f-good span { color: var(--live); }
.feed li.f-warn span { color: var(--alert); }
.feed li.f-sim span { color: var(--accent); }
.feed li.f-info span { color: var(--text-dim); }

/* inputs ----------------------------------------------------------------- */

.reg-form { display: flex; gap: var(--sp-3); }
.reg-form input,
.field {
  flex: 1;
  min-width: 0;
  background: var(--bg-sunk);
  border: 1px solid var(--line-strong);
  color: var(--text);
  border-radius: var(--r);
  padding: 7px 10px;
  font: inherit;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
}
.reg-form input { text-transform: uppercase; letter-spacing: 0.06em; }
.reg-form input:focus,
.field:focus { border-color: var(--muted); }

/* maps ------------------------------------------------------------------- */

.mapwrap {
  position: relative;
  min-height: 340px;
  border-radius: var(--r);
  border: 1px solid var(--line);
  overflow: hidden;
  background: var(--bg-sunk);
}
#map, #dubMap { position: absolute; inset: 0; }

.map-overlay {
  position: absolute;
  z-index: 500;
  left: var(--sp-4);
  bottom: var(--sp-4);
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: 6px 9px;
  border-radius: var(--r);
  background: var(--bg);
  border: 1px solid var(--line-strong);
}
.map-overlay .muted { font-size: var(--fs-sm); }

.legend {
  position: absolute;
  z-index: 500;
  right: var(--sp-4);
  bottom: var(--sp-4);
  font-size: var(--fs-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 5px 8px;
}

.plane-marker { background: none; border: 0; }
.plane-inner {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  transition: transform 1.4s linear;
}
.plane-inner svg { fill: var(--live); }
.apt-label {
  background: var(--bg) !important;
  border: 1px solid var(--line-strong) !important;
  color: var(--text-dim) !important;
  font-family: var(--font-mono);
  font-size: var(--fs-micro) !important;
  letter-spacing: 0.08em;
  padding: 1px 6px !important;
  border-radius: var(--r-sm) !important;
  box-shadow: none !important;
}
.apt-label::before { display: none !important; }
  /* The Esri dark-grey base is mid grey with white place names — the brightest
     surface in the product, and it disagrees with the #121822 the 3D scope paints
     land. Pull the tile pane (base and reference both live in it) down to the
     product's own values. Markers, trails and the pin are in other panes and are
     untouched. */
  .leaflet-tile-pane { filter: brightness(0.42) saturate(0.6) contrast(1.05); }
  .leaflet-container { background: var(--bg-sunk); font: inherit; }
.leaflet-control-attribution { background: var(--bg) !important; color: var(--muted) !important; font-size: var(--fs-micro) !important; }
.leaflet-control-attribution a { color: var(--text-dim) !important; display: inline-block; padding: 2px 3px; }
.leaflet-bar a { background: var(--bg) !important; color: var(--text-dim) !important; border-color: var(--line-strong) !important; }
.leaflet-bar a:hover { background: var(--bg-raise) !important; }
.leaflet-marker-icon[tabindex='-1'] { cursor: default; }

/* fallback map when Leaflet cannot load */
.fbwrap { position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: center; gap: var(--sp-4); padding: var(--sp-7); }
.fbline { position: relative; height: 4px; background: var(--line); }
.fbfill { position: absolute; inset: 0 auto 0 0; width: 0; background: var(--live); transition: width 1s var(--ease); }
.fbplane { position: absolute; top: -12px; left: 0; font-size: var(--fs-sm); color: var(--live); transition: left 1s var(--ease); }
.fblabels { display: flex; justify-content: space-between; font-size: var(--fs-sm); color: var(--muted); }

/* schedule deltas -------------------------------------------------------- */

.delay-strip { margin-top: var(--sp-4); display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.delay-strip:empty { display: none; }
.delta {
  font-size: var(--fs-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 7px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-strong);
  color: var(--muted);
}
.delta--late { color: var(--alert); border-color: rgba(255, 92, 92, 0.4); }
.delta--early { color: var(--live); border-color: rgba(53, 208, 127, 0.35); }
.delta--on { color: var(--accent); border-color: rgba(245, 165, 36, 0.35); }

/* timeline --------------------------------------------------------------- */

.timeline { list-style: none; margin: 0; padding: 0 0 0 var(--sp-3); display: flex; flex-direction: column; }
.timeline li {
  position: relative;
  padding: var(--sp-3) 0 7px var(--sp-6);
  border-left: 1px solid var(--line);
  font-size: var(--fs-sm);
  display: flex;
  gap: var(--sp-4);
  align-items: baseline;
}
.timeline li:last-child { border-left-color: transparent; }
.timeline li::before {
  content: '';
  position: absolute;
  left: -3px;
  top: 12px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--line-strong);
  border: 1px solid var(--bg);
}
.timeline li.done::before { background: var(--live); }
.timeline li.current::before { background: var(--accent); }
.timeline li .tl-time { color: var(--muted); flex: none; width: 52px; }
.timeline li .tl-label { color: var(--text); }
.timeline li .tl-sub { color: var(--muted); font-size: var(--fs-micro); margin-left: auto; text-align: right; }
.timeline li.est .tl-time { font-style: italic; }
.timeline li.pending { opacity: 0.55; }

/* avionics chips --------------------------------------------------------- */

.chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: 1px 0 var(--sp-5); }
.chips:empty { display: none; }
.chip-sm {
  font-size: var(--fs-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 7px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-strong);
  color: var(--muted);
}
.chip-sm b { color: var(--text-dim); font-weight: 700; }
.chip-sm.warn { border-color: rgba(245, 165, 36, 0.45); color: var(--accent); }

/* weather ---------------------------------------------------------------- */

.weather { display: flex; flex-direction: column; gap: 0; }
.wx { padding: var(--sp-4) 0; border-top: 1px solid var(--line); }
.wx:first-child { border-top: 0; padding-top: 0; }
.wx-head { display: flex; align-items: center; gap: var(--sp-4); margin-bottom: var(--sp-3); }
.wx-head .icao { font-weight: 700; font-size: var(--fs-base); color: var(--text); }
.wx-head .cat { font-size: var(--fs-micro); padding: 2px 6px; border-radius: var(--r-sm); font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; border: 1px solid; }
.cat--VFR { color: var(--live); border-color: rgba(53, 208, 127, 0.4); }
.cat--MVFR { color: var(--accent); border-color: rgba(245, 165, 36, 0.4); }
.cat--IFR { color: var(--alert); border-color: rgba(255, 92, 92, 0.4); }
.cat--LIFR { color: var(--alert); border-color: rgba(255, 92, 92, 0.6); }
.wx-head .age { margin-left: auto; font-size: var(--fs-micro); color: var(--muted); letter-spacing: 0.06em; }
.wx-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2) var(--sp-5); font-size: var(--fs-sm); }
.wx-grid span { color: var(--muted); }
.wx-grid b { color: var(--text); font-weight: 700; }
.wx-raw { margin: var(--sp-3) 0 0; font-size: var(--fs-sm); color: var(--muted); word-break: break-word; }
.wx-rwy { margin-top: var(--sp-3); font-size: var(--fs-sm); color: var(--accent); }

/* traffic list ----------------------------------------------------------- */

.traffic { list-style: none; margin: 0 0 var(--sp-2); padding: 0; display: flex; flex-direction: column; max-height: 240px; overflow: auto; }
.traffic li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-4);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-sm);
  cursor: pointer;
}
.traffic li:last-child { border-bottom: 0; }
.traffic li:hover { background: var(--bg-sunk); }
.traffic li.selected { background: var(--bg-raise); }
.traffic li.is-active { outline: 2px solid var(--focus); outline-offset: -2px; }
.traffic .t-name { display: flex; gap: var(--sp-4); align-items: baseline; min-width: 0; }
.traffic .t-cs { font-weight: 700; color: var(--text); }
.traffic .t-type { color: var(--muted); font-size: var(--fs-micro); }
.traffic .t-meta { color: var(--muted); font-size: var(--fs-micro); margin-top: 2px; }
.traffic .t-dist { text-align: right; font-size: var(--fs-micro); color: var(--muted); }
.traffic .t-dist b { display: block; color: var(--text); font-size: var(--fs-sm); }

.tfc-marker { background: none; border: 0; }
.tfc-marker .tfc-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--neutral);
  border: 1px solid var(--bg);
}
.tfc-label {
  background: var(--bg) !important;
  border: 1px solid var(--line-strong) !important;
  color: var(--text-dim) !important;
  font-family: var(--font-mono);
  font-size: var(--fs-micro) !important;
  padding: 1px 5px !important;
  border-radius: var(--r-sm) !important;
  box-shadow: none !important;
}
.tfc-label::before { display: none !important; }

/* photo and card actions ------------------------------------------------- */

.photo { margin: 0 0 var(--sp-4); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; background: var(--bg-sunk); }
.photo[hidden] { display: none; }
.photo img { display: block; width: 100%; height: auto; aspect-ratio: 3 / 2; object-fit: cover; background: var(--bg); }
.photo figcaption { padding: var(--sp-3) 0 0; }
.card-actions { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-top: var(--sp-4); }

/* chart ------------------------------------------------------------------ */

.chart { position: relative; width: 100%; }
.chart-svg { display: block; width: 100%; height: auto; touch-action: pan-y; }
.chart-empty { margin: var(--sp-7) 0; text-align: center; }
.cx-label { font-family: var(--font-mono); font-size: var(--fs-sm); fill: var(--muted); font-variant-numeric: tabular-nums; }
.cx-title { font-family: var(--font-mono); font-size: var(--fs-micro); fill: var(--text-dim); letter-spacing: var(--track); }

.cx-legend { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-5); margin: 0 0 var(--sp-4); }
.cx-chip { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-micro); color: var(--muted); letter-spacing: 0.06em; }
.cx-chip i { width: 7px; height: 7px; display: inline-block; }
.cx-chip em { font-style: normal; }
.cx-chip b { color: var(--text-dim); font-weight: 700; }

.chart-tip {
  position: absolute;
  z-index: 6;
  pointer-events: none;
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  padding: 7px 9px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 150px;
}
.chart-tip[hidden] { display: none; }
.chart-tip span { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-micro); }
.chart-tip i { width: 7px; height: 7px; flex: none; }
.chart-tip b { color: var(--text); font-weight: 700; }

/* segmented control ------------------------------------------------------ */

.seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: var(--r); overflow: hidden; }
.seg button {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 6px 10px;
  min-height: 28px;
  cursor: pointer;
  border-right: 1px solid var(--line);
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.seg button:last-child { border-right: 0; }
.seg button.on { background: var(--bg-raise); color: var(--accent); }
.seg button:hover { color: var(--text-dim); }
.seg--wrap { flex-wrap: wrap; }

/* ==========================================================================
   6. Tail view
   ========================================================================== */

/* ==========================================================================
   7. Dublin view
   ========================================================================== */

.viewtabs { display: inline-flex; border: 1px solid var(--line-strong); border-radius: var(--r); overflow: hidden; }
.viewtabs button {
  appearance: none;
  border: 0;
  border-right: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 7px 12px;
  min-height: 30px;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.viewtabs button:last-child { border-right: 0; }
.viewtabs button.on { background: var(--bg-raise); color: var(--accent); }
.viewtabs button:hover { color: var(--text-dim); }

.layout--airport {
  display: grid;
  grid-template-columns: minmax(340px, 430px) minmax(0, 1fr);
  gap: var(--sp-5);
  padding: var(--sp-5);
  height: calc(100dvh - var(--shell-h));
}
.layout--airport .panel { overflow-y: auto; overflow-x: hidden; }
.layout--airport .board { flex: 1 1 auto; min-height: 0; }

.dubmain { display: grid; grid-template-rows: minmax(220px, 1.2fr) minmax(280px, 1fr); gap: var(--sp-5); min-height: 0; }
.dubmain .mapwrap { min-height: 0; }

.card--grow { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
/* The live board is the reason the Dublin view exists, so it keeps a floor even
   when the cards above and below it want the space. Without this it collapsed to
   a single clipped row as the overhead card grew. */
.layout--airport .card--grow { min-height: 340px; }

.board { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; overflow: auto; min-height: 60px; }
.board:focus-visible { outline: 1px solid var(--line-strong); outline-offset: 2px; }

.dub-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0 var(--sp-5); margin-top: var(--sp-4); }
.dub-stat { padding: var(--sp-3) 0; border-top: 1px solid var(--line); }
.dub-stat b { display: block; font-size: var(--fs-lg); font-weight: 700; }
.dub-stat span { font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: var(--track); color: var(--muted); }
.dub-stat.s-arr b { color: var(--arriving); }
.dub-stat.s-dep b { color: var(--departing); }
.dub-stat.s-ground b { color: var(--ground); }
.dub-stat.s-over b { color: var(--overflight); }
.dub-stat.is-on { border-top-color: var(--accent); }

.wx-mini { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-5); margin-top: var(--sp-4); font-size: var(--fs-micro); color: var(--muted); letter-spacing: 0.06em; }
.wx-mini b { color: var(--text-dim); }
.wx-mini .rwy { color: var(--accent); }

.board-controls { display: flex; flex-direction: column; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.board-controls input {
  background: var(--bg-sunk);
  border: 1px solid var(--line-strong);
  color: var(--text);
  border-radius: var(--r);
  padding: 6px 9px;
  font: inherit;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
}

/* Board rows. Phase is the left rule, selection is the background. Two
   signals, one variable each, so they never contradict. */
.board .row-flight {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr) auto;
  gap: var(--sp-4);
  align-items: center;
  padding: var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line);
  border-left: 2px solid transparent;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.board .row-flight:hover { background: var(--bg-sunk); }
.board .row-flight.selected { background: var(--bg-raise); border-left-color: var(--text); }
.board .row-flight[data-state='arr'] { border-left-color: var(--arriving); }
.board .row-flight[data-state='dep'] { border-left-color: var(--departing); }
.board .row-flight[data-state='ground'] { border-left-color: var(--ground); }
.board .row-flight[data-state='over'] { border-left-color: var(--overflight); }
.board .row-flight.is-active { outline: 2px solid var(--focus); outline-offset: -2px; }

.board .f-call { font-weight: 700; font-size: var(--fs-base); color: var(--text); }
.board .f-sub { font-size: var(--fs-micro); color: var(--muted); }
.board .f-mid { font-size: var(--fs-micro); color: var(--muted); }
.board .f-right { text-align: right; font-size: var(--fs-micro); color: var(--muted); }
.board .f-right b { display: block; color: var(--text); font-size: var(--fs-sm); }

.state-pill { display: inline-block; padding: 1px 5px; font-size: var(--fs-micro); font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; border: 1px solid; }
.state-arr { color: var(--arriving); border-color: rgba(245, 165, 36, 0.4); }
.state-dep { color: var(--departing); border-color: rgba(53, 208, 127, 0.4); }
.state-ground { color: var(--ground); border-color: var(--line-strong); }
.state-over { color: var(--overflight); border-color: var(--line-strong); }

.selected-card { display: flex; flex-direction: column; min-height: 0; }
/* With nothing selected the card is just the quick-pick empty state. It takes
   its content height and the map row takes the rest, instead of reserving a
   full 1fr row of dead space next to a board that is scrolling. app.js adds
   and removes `is-empty` as the selection changes. */
.selected-card.is-empty { min-height: 0; }
/* Nothing is selected, so the chart, its legend and the chart-range control
   are an empty region, not content. Collapse them; the quick picks stay. */
.selected-card.is-empty .chart,
.selected-card.is-empty .cx-legend,
.selected-card.is-empty .card-actions { display: none; }
@media (min-width: 1101px) {
  .dubmain:has(.selected-card.is-empty) { grid-template-rows: minmax(220px, 1fr) auto; }
}
.sel-head { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-5); align-items: baseline; margin-bottom: var(--sp-3); }
.sel-head .sel-call { font-weight: 700; font-size: var(--fs-lg); color: var(--text); }
.sel-head .sel-meta { font-size: var(--fs-sm); color: var(--muted); }
.sel-empty { color: var(--muted); font-size: var(--fs-sm); padding: var(--sp-3) 0; width: 100%; }
.micro-label {
  margin: var(--sp-2) 0 var(--sp-3);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--muted);
}
.sel-picks { width: 100%; display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--sp-3); }
.sel-pick {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  align-items: flex-start;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  padding: var(--sp-4) var(--sp-4);
  background: var(--bg-sunk);
  border: 1px solid var(--line);
  border-radius: var(--r);
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.sel-pick:hover { border-color: var(--line-strong); background: var(--bg-raise); }
.sel-pick:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
.sel-pick .f-call { font-size: var(--fs-base); font-weight: 700; color: var(--text); }
.sel-pick .f-sub { font-size: var(--fs-micro); color: var(--muted); }

.dub-marker { background: none; border: 0; }
.dub-marker .dm-inner { width: 30px; height: 30px; display: grid; place-items: center; transition: transform 1.6s linear; }
.dub-marker svg { width: 17px; height: 17px; }
.dub-marker.arr svg { fill: var(--arriving); }
.dub-marker.dep svg { fill: var(--departing); }
.dub-marker.ground svg { fill: var(--ground); }
.dub-marker.over svg { fill: var(--overflight); opacity: 0.7; }
.dub-marker.sel svg { fill: var(--selected); }
.dm-label {
  background: var(--bg) !important;
  border: 1px solid var(--line-strong) !important;
  color: var(--text-dim) !important;
  font-family: var(--font-mono);
  font-size: var(--fs-micro) !important;
  padding: 1px 5px !important;
  border-radius: var(--r-sm) !important;
  box-shadow: none !important;
}
.dm-label::before { display: none !important; }
.apt-runway { stroke: var(--line-strong); stroke-width: 2; }
.apt-runway.active { stroke: var(--accent); stroke-width: 3; }
.rwy-label {
  background: var(--bg) !important;
  border: 1px solid var(--line) !important;
  color: var(--muted) !important;
  font-family: var(--font-mono);
  font-size: var(--fs-micro) !important;
  padding: 0 4px !important;
  border-radius: var(--r-sm) !important;
  box-shadow: none !important;
}
.rwy-label::before { display: none !important; }

/* ==========================================================================
   8. Overhead announcements
   ========================================================================== */

.overhead-card { padding: 0; }
.overhead-body { padding: var(--sp-5) var(--sp-6) var(--sp-6); display: flex; flex-direction: column; gap: var(--sp-4); }

.overhead-summary {
  position: relative;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-5) var(--sp-7) var(--sp-5) var(--sp-6);
  cursor: pointer;
  list-style: none;
  transition: background var(--t-fast) var(--ease);
}
.overhead-summary::-webkit-details-marker { display: none; }
.overhead-summary:hover { background: var(--bg-sunk); }
.overhead-summary:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.overhead-summary__title {
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: var(--track);
  font-weight: 700;
  color: var(--muted);
}
.overhead-summary::after {
  content: '+';
  position: absolute;
  right: var(--sp-6);
  top: 50%;
  transform: translateY(-50%);
  color: var(--muted);
  font-size: var(--fs-base);
}
.overhead-card[open] .overhead-summary { border-bottom: 1px solid var(--line); }
.overhead-card[open] .overhead-summary::after { content: '\2212'; }
.overhead-summary #overheadState { text-align: right; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--accent); }

.overhead-profile { display: flex; flex-direction: column; gap: var(--sp-2); }
.overhead-profile > .muted { line-height: 1.45; }

.overhead-log { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; max-height: 190px; overflow: auto; }
.overhead-log:empty { display: none; }
.overhead-log li {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: var(--sp-4);
  align-items: baseline;
  font-size: var(--fs-micro);
  padding: 6px 0 6px var(--sp-3);
  border-bottom: 1px solid var(--line);
  border-left: 2px solid transparent;
}
.overhead-log li time { color: var(--muted); }
.overhead-log li b { font-weight: 700; color: var(--text); }
.overhead-log li .ov-why { display: block; color: var(--muted); font-size: var(--fs-micro); margin-top: 2px; }
.overhead-log li.is-spoken { border-left-color: var(--live); }
.overhead-log li.is-dropped { opacity: 0.65; }

.ov-pin { background: none; border: 0; }
.ov-pin__dot {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--text);
  border: 3px solid var(--bg);
  box-shadow: 0 0 0 2px var(--text);
}
.ov-pin--pin .ov-pin__dot { background: var(--accent); box-shadow: 0 0 0 2px var(--accent); }
.ov-pin__label {
  background: var(--bg) !important;
  border: 1px solid var(--line-strong) !important;
  color: var(--text) !important;
  font-family: var(--font-mono);
  font-size: var(--fs-micro) !important;
  padding: 1px 6px !important;
  border-radius: var(--r-sm) !important;
  box-shadow: none !important;
}
.ov-pin__label::before { display: none !important; }
.ov-reach { stroke: var(--line-strong); fill: rgba(148, 155, 166, 0.05); }

/* ==========================================================================
   9. Pilot brief
   ========================================================================== */

.drawer {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: flex;
  justify-content: flex-end;
  background: rgba(2, 4, 7, 0.72);
  animation: fade-in var(--t-base) var(--ease);
}
.drawer[hidden] { display: none; }
@keyframes fade-in { from { opacity: 0; } }
.drawer-panel {
  width: min(780px, 96vw);
  height: 100%;
  background: var(--bg);
  border-left: 1px solid var(--line-strong);
  display: flex;
  flex-direction: column;
  animation: slide-in var(--t-base) var(--ease);
}
@keyframes slide-in { from { transform: translateX(16px); opacity: 0.4; } }
.drawer-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-4);
  justify-content: space-between;
  padding: var(--sp-5) var(--sp-6);
  border-bottom: 1px solid var(--line);
}
.drawer-head h2 { margin: 0; font-size: var(--fs-lg); letter-spacing: 0.02em; }
.drawer-head p { margin: 3px 0 0; }
.drawer-body { padding: var(--sp-6); overflow: auto; display: flex; flex-direction: column; gap: var(--sp-6); }

.brief-note { font-size: var(--fs-sm); color: var(--muted); }
.brief-group h3 {
  margin: 0 0 var(--sp-3);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-micro);
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--muted);
}
.chart-list { display: flex; flex-direction: column; }
.chart-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-sm);
}
.chart-item:last-child { border-bottom: 0; }
.chart-item a { font-size: var(--fs-micro); letter-spacing: 0.06em; white-space: nowrap; }

table.dt { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
table.dt th {
  text-align: left;
  font-size: var(--fs-micro);
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 700;
  padding: var(--sp-2);
  border-bottom: 1px solid var(--line-strong);
}
table.dt td { padding: var(--sp-2); border-bottom: 1px solid var(--line); }
table.dt td:first-child { color: var(--text); }
table.dt tr:last-child td { border-bottom: 0; }

.brief-kv { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3) var(--sp-6); font-size: var(--fs-sm); }
.brief-kv span { color: var(--muted); }
.brief-kv b { color: var(--text); font-weight: 700; }
.brief-raw {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  background: var(--bg-sunk);
  border-left: 2px solid var(--line-strong);
  border-radius: var(--r-sm);
  padding: var(--sp-3) var(--sp-4);
  word-break: break-word;
  white-space: pre-wrap;
}
.brief-links a { display: block; padding: 5px 0; font-size: var(--fs-sm); }
.taf-period {
  display: grid;
  grid-template-columns: 112px 1fr;
  gap: var(--sp-4);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-sm);
}
.taf-period.now { border-left: 2px solid var(--accent); padding-left: var(--sp-3); }
.taf-period .taf-time { color: var(--muted); }

.notam { border-bottom: 1px solid var(--line); padding: var(--sp-3) 0; }
.notam-head { display: flex; flex-wrap: wrap; gap: var(--sp-4); align-items: center; font-size: var(--fs-micro); }
.notam-num { font-weight: 700; color: var(--text); }
.notam-when { color: var(--muted); margin-left: auto; }
.notam-text { margin: var(--sp-2) 0 0; font-size: var(--fs-sm); color: var(--text-dim); line-height: 1.5; }
.brief-steps { margin: var(--sp-3) 0 0; padding-left: var(--sp-6); font-size: var(--fs-sm); color: var(--muted); }
.brief-steps li { margin-bottom: var(--sp-2); }

/* ==========================================================================
   10. 3D sky view
   ========================================================================== */

.layout--sky { grid-template-columns: minmax(0, 1fr); }

.skywrap {
  position: relative;
  min-height: 340px;
  border-radius: var(--r);
  border: 1px solid var(--line);
  overflow: hidden;
  background: var(--bg);
}

.sky3d { position: absolute; inset: 0; }
.sky3d canvas { position: absolute; inset: 0; width: 100% !important; height: 100% !important; display: block; z-index: 0; cursor: grab; }
.sky3d canvas:focus-visible { outline: 2px solid var(--focus); outline-offset: -4px; }

.sky-labels { position: absolute; inset: 0; z-index: 3; pointer-events: none; overflow: hidden; }

.sky-label {
  position: absolute;
  top: 0;
  left: 0;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 2px 6px;
  border-radius: var(--r-sm);
  color: var(--text-dim);
  background: var(--bg);
  border: 1px solid var(--line-strong);
  /* No pointer-events: a label sits above the canvas, and a pill that accepted
     pointer events swallowed any drag that started on it. view3d.js hit-tests
     labelRects instead, so the drag reaches OrbitControls. */
}
.sky-label.is-hover { color: var(--text); border-color: var(--muted); }
.sky-label--arr { color: var(--arriving); border-color: rgba(245, 165, 36, 0.5); }
.sky-label--dep { color: var(--departing); border-color: rgba(53, 208, 127, 0.5); }
.sky-label--ground { color: var(--ground); }
.sky-label--over { color: var(--overflight); }
.sky-label.is-tracked { border-color: var(--accent); }
.sky-label.is-sel { color: var(--text); border-color: var(--text); font-size: var(--fs-sm); }
.sky-label.is-alert { color: var(--alert); border-color: var(--alert); }

.sky-hud {
  position: absolute;
  z-index: 5;
  left: var(--sp-5);
  top: var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  pointer-events: none;
  max-width: min(52ch, 60%);
}
.sky-hud__title {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--text-dim);
}
.sky-live-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--live); animation: blink 1.6s ease-in-out infinite; }
.sky-hud__stat {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  padding: 4px 8px;
  align-self: flex-start;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sky-legend {
  position: absolute;
  z-index: 5;
  right: var(--sp-5);
  top: var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  font-size: var(--fs-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  padding: 8px 10px;
}
.sky-legend span { display: flex; align-items: center; gap: var(--sp-3); }
.sky-legend__hint { margin-top: var(--sp-1); padding-top: var(--sp-2); border-top: 1px solid var(--line); text-transform: none; letter-spacing: 0; }
.sw { width: 8px; height: 8px; display: inline-block; flex: none; }
.sw-arr { background: var(--arriving); }
.sw-dep { background: var(--departing); }
.sw-ground { background: var(--ground); }
.sw-over { background: var(--overflight); }
.sw-sel { background: var(--selected); }

.sky-tools {
  position: absolute;
  z-index: 5;
  left: var(--sp-5);
  right: var(--sp-5);
  bottom: var(--sp-5);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  padding: 8px 10px;
  border-radius: var(--r);
  background: var(--bg);
  border: 1px solid var(--line-strong);
}

.sky-range { display: flex; align-items: center; gap: var(--sp-3); font-size: var(--fs-micro); letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); margin-left: auto; }

/* Selected-aircraft dossier, shown in the 3D view as well as the Dublin card. */
.dossier { display: flex; flex-direction: column; gap: var(--sp-3); }
.dossier[hidden] { display: none; }
.dossier .photo { margin: 0; }

.sky-dossier {
  position: absolute;
  z-index: 6;
  right: var(--sp-5);
  top: var(--sp-5);
  width: min(360px, 40%);
  max-height: calc(100% - 2 * var(--sp-5) - 72px);
  overflow: auto;
  padding: var(--sp-4);
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
}
.sky-dossier[hidden] { display: none; }

@media (max-width: 980px) {
  .sky-dossier {
    left: var(--sp-5);
    right: var(--sp-5);
    top: auto;
    bottom: calc(var(--sp-5) + 64px);
    width: auto;
    max-height: 42%;
  }
}
.sky-range input { width: 118px; accent-color: var(--accent); }
.sky-range output { color: var(--accent); min-width: 62px; text-align: right; }

.sky-fallback[hidden] { display: none; }

.sky-fallback {
  position: absolute;
  z-index: 6;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-4);
  text-align: center;
  padding: var(--sp-7);
  background: var(--bg);
  color: var(--muted);
}
.sky-fallback strong { color: var(--alert); font-size: var(--fs-lg); }
.sky-fallback span { font-size: var(--fs-sm); max-width: 46ch; }

/* ==========================================================================
   11. Responsive
   ========================================================================== */

@media (max-width: 980px) {
  .layout { display: flex; flex-direction: column; height: auto; padding-bottom: var(--sp-7); }
  .panel { display: contents; }
  .panel > .card, .mapwrap { width: 100%; }

  /* Tail: map directly after the status card, then the rest in reading order.
     Scoped to the tail layout so these ten-card rules cannot reorder Dublin. */
  #layoutTail .status-card { order: 1; }
  #layoutTail .mapwrap { order: 2; height: 56vh; min-height: 320px; }
  #layoutTail .panel > .card:nth-child(3) { order: 3; }
  #layoutTail .panel > .card:nth-child(2) { order: 4; }
  #layoutTail .panel > .card:nth-child(5) { order: 5; }
  #layoutTail .panel > .card:nth-child(4) { order: 6; }
  #layoutTail .panel > .card:nth-child(6) { order: 7; }
  #layoutTail .panel > .card:nth-child(7) { order: 8; }
  #layoutTail .panel > .card:nth-child(8) { order: 9; }
  #layoutTail .panel > .card:nth-child(9) { order: 10; }
  #layoutTail .panel > .card:nth-child(10) { order: 11; }

  /* Dublin: the live board is the reason this view exists, so it comes before
     the map it feeds, and the selected-flight card sits under that map. Scoped
     to the airport layout class, not its id, so [hidden] still wins. */
  .layout--airport .panel > .card:first-child { order: 1; }
  .layout--airport .card--grow { order: 2; }
  .layout--airport .dubmain { order: 3; grid-template-rows: auto auto; }
  .layout--airport .overhead-card { order: 4; }
  .layout--airport .mapwrap { order: 1; height: 56vh; min-height: 320px; }
  .layout--airport .selected-card { order: 2; }

  .topbar { padding: var(--sp-4) var(--sp-5); }
  .tele { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .toasts { left: var(--sp-5); right: var(--sp-5); bottom: var(--sp-5); width: auto; }
}

@media (max-width: 1100px) {
  .layout--airport { display: flex; flex-direction: column; height: auto; }
  .dubmain { grid-template-rows: 52vh auto; }
  .board { max-height: 46vh; }
}

/* 1101 to 1280: the common laptop widths. The board's 340px floor plus the
   search and both segmented rows left #dubBoard at 165px, so the panel, the
   board and the page all scrolled. Fold search and sort onto one row, let the
   grow card take the panel's remainder instead of a fixed floor, and the board
   keeps more than its floor with the panel carrying no scrollbar. */
@media (min-width: 1101px) and (max-width: 1280px) {
  .layout--airport .card--grow { min-height: 0; }
  .layout--airport .panel { gap: var(--sp-3); }
  .layout--airport .card--grow h2 { margin-bottom: var(--sp-2); padding-bottom: var(--sp-2); }
  .layout--airport .card--grow > .board-controls {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--sp-2);
    margin-bottom: var(--sp-2);
  }
  .layout--airport .card--grow > .board-controls > #dubSearch { grid-area: 1 / 1; }
  .layout--airport .card--grow > .board-controls > #dubSort { grid-area: 1 / 2; justify-self: end; }
  .layout--airport .card--grow > .board-controls > #dubFilter { grid-area: 2 / 1 / 3 / 3; }
}

@media (max-width: 720px) {
  .brand h1 { font-size: var(--fs-base); }
  .topstatus { gap: var(--sp-3); row-gap: var(--sp-2); }
  .ticker { order: 3; width: 100%; }
  .dub-stat b { font-size: var(--fs-base); }
  .drawer-panel { width: 100vw; }
  .sch-list .leg { grid-template-columns: 52px 1fr auto; }
  .sch-list .leg .tag { display: none; }
}

@media (max-width: 980px) {
  .layout--sky .skywrap { height: 66vh; min-height: 420px; }
  .sky-hud { max-width: calc(100% - 20px); }
  /* The legend and the toolbar become one bottom dock in normal flow, legend
     above toolbar. Two in-flow boxes in a column cannot overlap at any height,
     unlike the two absolutely-positioned boxes they replace. */
  .sky3d { display: flex; flex-direction: column; justify-content: flex-end; }
  .sky-legend {
    position: static;
    order: 1;
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--sp-2) var(--sp-3);
    margin: 0 var(--sp-3);
    padding: 6px 8px;
    border-radius: var(--r) var(--r) 0 0;
    border-bottom: 0;
  }
  .sky-tools {
    position: static;
    order: 2;
    margin: 0 var(--sp-3) var(--sp-3);
    padding: 6px 8px;
    border-radius: 0 0 var(--r) var(--r);
    border-top: 1px solid var(--line);
  }
  /* `.sky-legend span` is (0,1,1); this is (0,2,0), so the hint is really
     hidden instead of laid out under the toolbar. */
  .sky-legend .sky-legend__hint { display: none; }
  .sky-tools { gap: var(--sp-2); }
  .sky-range { margin-left: 0; width: 100%; justify-content: flex-end; }
  .sky-range input { width: 108px; }
  /* Every control in the toolbar is a 44px touch target on a phone. */
  .sky-tools .btn, .sky-tools .seg button, .sky-tools .seg, .sky-tools input[type='range'] { min-height: 44px; }
}

@media (pointer: coarse) {
  .btn, .btn--small { min-height: 34px; }
  .seg button, .viewtabs button { min-height: 34px; }
  .sky-tools .btn, .sky-tools .seg button, .sky-tools .seg, .sky-tools input[type='range'] { min-height: 44px; }
  /* A search field is the one control a thumb aims at blind, so it gets the same
     floor as a button rather than the 31px its padding happens to produce. */
  input[type='search'], input[type='text'], input[type='url'], input[type='email'] { min-height: 34px; }
  .board .row-flight { padding-top: var(--sp-4); padding-bottom: var(--sp-4); }
  .traffic li { padding-top: var(--sp-4); padding-bottom: var(--sp-4); }
  /* A link is inline, so vertical padding grows the hit box without moving the
     line box. 10px plus the 14px line reaches the 34px floor on the source
     attribution row, which is six small targets in a row. */
  .card .small a { padding: 10px 4px; }
  .leaflet-control-attribution a { padding: 5px 3px; }
}

.guided-spotting-link { display: inline-flex; align-items: center; min-height: 44px; padding: 8px 12px; border: 1px solid var(--line); border-radius: 4px; font-weight: 600; }

/* consent banner (Mixpanel EU) ------------------------------------------ */

.consent-banner {
  position: fixed;
  z-index: 80;
  left: var(--sp-5);
  right: var(--sp-5);
  bottom: var(--sp-5);
  max-width: 520px;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--sp-4);
  padding: var(--sp-5) var(--sp-6);
  background: var(--bg-raise);
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  color: var(--text-dim);
  font-size: var(--fs-sm);
  line-height: 1.45;
}
.consent-banner[hidden] { display: none; }
.consent-banner__body { flex: 1 1 240px; min-width: 0; }
.consent-banner__label {
  margin: 0 0 4px;
  font-size: var(--fs-micro);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
}
.consent-banner__copy { margin: 0; color: var(--text-dim); }
.consent-banner__actions {
  display: flex;
  gap: var(--sp-3);
  flex: none;
}
