/* ===== Display view ===== */
#app {
  position: relative;
  height: 100vh; height: 100dvh;
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--bg); color: var(--text);
}

/* ---- Themes ---- */
#app[data-theme='departure'] {
  --bg: #0a0a0b; --panel: #141414; --card: #131313;
  --text: #ffb000; --muted: #b07e2e; --dim: #6d5320;
  --accent: #ffb000; --accent2: #ff7a00;
  --line: rgba(255, 176, 0, 0.16); --radar-line: rgba(255, 176, 0, 0.22);
  --num-font: var(--mono);
}
#app[data-theme='radar'] {
  --bg: #001103; --panel: #04220a; --card: #05230b;
  --text: #34ff6a; --muted: #1f9e46; --dim: #147a34;
  --accent: #34ff6a; --accent2: #6dffa0;
  --line: rgba(52, 255, 106, 0.18); --radar-line: rgba(52, 255, 106, 0.28);
  --num-font: var(--mono);
}
#app[data-theme='minimal'] {
  --bg: #0e1116; --panel: #161b22; --card: #161b22;
  --text: #e6edf3; --muted: #8b949e; --dim: #545d68;
  --accent: #4ea1ff; --accent2: #7cc3ff;
  --line: rgba(255, 255, 255, 0.09); --radar-line: rgba(255, 255, 255, 0.16);
  --num-font: var(--mono);
}
/* Yunex Traffic — light theme, matching the yunextraffic.com site.
   Brand palette sourced from their own CSS: petrol #226d7a (the workhorse on
   light backgrounds), cyan #22b8d1, light cyan #b0e0e9, tint #e4f5fa, plus the
   signature green #00e38c.
   Note: #00e38c measures only ~1.6:1 on white, so it cannot carry text or thin
   lines here. It is used as a solid bar on the petrol header (3.5:1) where it
   reads strongly; petrol does the accent work on light surfaces (5.4:1). */
#app[data-theme='yunex'] {
  --bg: #eef4f6; --panel: #ffffff; --card: #ffffff;
  --text: #0e2c34; --muted: #45707b; --dim: #557f89;
  --accent: #226d7a; --accent2: #00915c;
  --line: rgba(34, 109, 122, 0.22); --radar-line: rgba(34, 109, 122, 0.32);
  --private-color: #5c6b7a;
  --num-font: var(--brand-mono);
  font-family: var(--brand-font);
}
/* Echoes the dot-grid motif Yunex uses in its own illustrations. */
#app[data-theme='yunex']::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 5;
  background-image: radial-gradient(rgba(34, 109, 122, 0.13) 1px, transparent 1px);
  background-size: 26px 26px;
  opacity: 0.6;
}
/* Petrol header band with the signature green rule beneath it. */
#app[data-theme='yunex'] #hdr {
  background: #226d7a; border-bottom: none;
  box-shadow: inset 0 -4px 0 0 #00e38c;
}
#app[data-theme='yunex'] #hdr .brand,
#app[data-theme='yunex'] #hdr .clock { color: #ffffff; }
#app[data-theme='yunex'] #hdr .ctx,
#app[data-theme='yunex'] #hdr .ctx .home,
#app[data-theme='yunex'] #hdr .pill,
#app[data-theme='yunex'] #hdr .fs { color: #e4f5fa; }
#app[data-theme='yunex'] #hdr .pill,
#app[data-theme='yunex'] #hdr .fs { border-color: rgba(255, 255, 255, 0.45); }
#app[data-theme='yunex'] #hdr .fs:hover { color: #ffffff; border-color: #00e38c; }
#app[data-theme='yunex'] .brand { letter-spacing: 0.14em; font-weight: 700; }
#app[data-theme='yunex'] .brand .logo { color: #00e38c; }
/* Lift the white cards off the light background. */
#app[data-theme='yunex'] .flight,
#app[data-theme='yunex'] .side {
  box-shadow: 0 1px 3px rgba(14, 44, 52, 0.09);
}
#app[data-theme='yunex'] .pill { border-radius: 3px; }

#app[data-theme='radar']::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 5;
  background: repeating-linear-gradient(0deg, rgba(0,0,0,0.22) 0 1px, transparent 1px 3px);
  opacity: 0.5;
}

/* ---- Header ---- */
#hdr {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: clamp(0.5rem, 1.6vh, 1.1rem) clamp(0.8rem, 2vw, 1.6rem);
  border-bottom: 1px solid var(--line);
}
.brand { font-weight: 800; letter-spacing: 0.18em; font-size: clamp(0.9rem, 1.8vw, 1.4rem); }
.brand .logo { color: var(--accent2); margin-right: 0.35em; }
.ctx { display: flex; align-items: center; gap: 0.8rem; color: var(--muted); min-width: 0; }
.ctx .home { font-size: clamp(0.8rem, 1.5vw, 1.15rem); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.right { display: flex; align-items: center; gap: 0.7rem; }
.clock { font-family: var(--num-font); font-size: clamp(1rem, 2.4vw, 1.8rem); font-weight: 700; letter-spacing: 0.06em; }
.fs { background: transparent; border: 1px solid var(--line); color: var(--muted); border-radius: 8px; width: 2rem; height: 2rem; line-height: 1; font-size: 1rem; }
.fs:hover { color: var(--text); border-color: var(--accent); }

/* ---- Main layout ---- */
#main {
  flex: 1; min-height: 0; display: grid; gap: clamp(0.5rem, 1.4vw, 1.2rem);
  /* Two equal halves: flight board left, map/radar right. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  padding: clamp(0.5rem, 1.4vh, 1.1rem) clamp(0.8rem, 2vw, 1.6rem);
}
#app.no-side #main { grid-template-columns: minmax(0, 1fr); }

/* ---- Board + cards ---- */
/* Cards are a FIXED height: sized so the maximum row count still fits the
   board, and identical no matter how many flights are showing. Previously they
   were flex: 1 1 0 and stretched to fill, so with few flights they grew very
   tall, the cqh-based font scaling grew with them, and the text outran the
   card width. Fixing the height pins every cqh unit, so text size is constant
   and predictable at any flight count. */
.board {
  --rows: 8;
  --row-gap: clamp(0.4rem, 1vh, 0.8rem);
  min-height: 0; display: flex; flex-direction: column; justify-content: flex-start;
  gap: var(--row-gap); overflow: hidden;
}
.flight {
  flex: 0 0 auto;
  height: calc((100% - (var(--rows) - 1) * var(--row-gap)) / var(--rows));
  min-height: 0; overflow: hidden; container-type: size;
  display: flex; align-items: center; gap: clamp(0.4rem, 1.1vw, 1.1rem);
  padding: clamp(0.4rem, 1.1vh, 1rem) clamp(0.7rem, 1.6vw, 1.3rem);
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  border-left: 4px solid var(--fc, var(--accent));
}
/* Card contents scale to each card's own height (cqh) so any row count fits. */
.ac-col { flex: 0 0 auto; width: clamp(48px, 6vw, 92px); display: flex; flex-direction: column; align-items: center; gap: 0.25em; min-width: 0; }
.ac-icon { width: clamp(24px, 44cqh, 56px); height: clamp(24px, 44cqh, 56px); opacity: 0.95; }
.ac-icon svg { width: 100%; height: 100%; display: block; }
.ac-model { font-family: var(--num-font); font-size: clamp(0.5rem, min(12cqh, 1.6cqw), 1.05rem); line-height: 1.05; color: var(--muted); text-align: center; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; word-break: break-word; }

/* Floor the identity column: the metrics grow with the card's font size, and
   without this they squeeze .ident until the route's airport codes clip. */
.ident { flex: 1 1 auto; min-width: min(36%, 22em); }
.flightno {
  font-family: var(--num-font); font-weight: 800; letter-spacing: 0.04em;
  font-size: clamp(0.95rem, min(26cqh, 4.2cqw), 3.4rem); line-height: 1.05;
  display: flex; align-items: baseline; gap: 0.5em; overflow: hidden;
}
.flightno .cs { flex: 0 0 auto; } /* callsign never truncates */
.flightno .cs.cs-name { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; font-family: system-ui, sans-serif; } /* airline-name title can shrink */
.flightno .airline { flex: 0 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-family: system-ui, sans-serif; font-weight: 600; font-size: 0.46em; color: var(--muted); letter-spacing: 0; }
.flightno .emerg { flex: 0 0 auto; font-size: 0.42em; color: #ff4d4d; border: 1px solid #ff4d4d; border-radius: 4px; padding: 0 0.3em; text-transform: uppercase; }
.seen-badge { flex: 0 0 auto; font-family: system-ui, sans-serif; font-weight: 700; font-size: 0.4em; letter-spacing: 0.02em; color: var(--accent2); border: 1px solid var(--accent2); border-radius: 999px; padding: 0.05em 0.55em; white-space: nowrap; }
.route { margin-top: 0.2em; font-size: clamp(0.72rem, min(20cqh, 2.6cqw), 2.6rem); color: var(--text); display: flex; align-items: baseline; gap: 0.4em; white-space: nowrap; overflow: hidden; }
/* Airport codes and the arrow are the essential payload — never shrink them,
   so "LGW → FAO" always survives. The city names absorb the pressure and
   ellipsise instead (min-width: 0 is required, otherwise a flex item refuses
   to shrink below its min-content width and gets hard-clipped). */
.route .ap { font-family: var(--num-font); font-weight: 700; letter-spacing: 0.05em; flex: 0 0 auto; }
.route .arrow { color: var(--accent2); flex: 0 0 auto; }
.route .cities { color: var(--muted); font-size: 0.72em; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.route.muted { color: var(--muted); }
.route.owner { color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.subline { display: flex; align-items: center; gap: 0.5em; min-width: 0; margin-top: 0.22em; }
.subline .route { margin-top: 0; min-width: 0; flex: 1 1 auto; }
.airline-pill {
  flex: 0 0 auto; min-width: 0; max-width: 58%;
  padding: 0.12em 0.7em; border-radius: 999px;
  font-family: system-ui, sans-serif; font-weight: 700;
  font-size: clamp(0.6rem, min(13cqh, 1.15vw), 1rem); line-height: 1.45;
  color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.airline-pill.private { background: transparent; border: 1px solid var(--fc); color: var(--fc); font-weight: 600; }

/* Single row by default so short cards never overflow vertically. */
.metrics { flex: 0 1 auto; min-width: 0; flex-wrap: nowrap; justify-content: flex-end; row-gap: 0.3em; display: flex; gap: clamp(0.3rem, 0.85vw, 0.95rem); align-items: center; }
/* Only wrap to a second row when the card is tall enough to hold one, so a
   metric moving down never pushes content outside the fixed-height card.
   .flight is the size container this queries. */
@container (min-height: 132px) {
  .metrics { flex-wrap: wrap; }
}
.metric { display: flex; flex-direction: column; align-items: flex-start; }
.metric label { font-size: clamp(0.5rem, min(10cqh, 1.1cqw), 1.1rem); letter-spacing: 0.1em; color: var(--dim); text-transform: uppercase; }
.metric span { font-family: var(--num-font); font-weight: 700; font-size: clamp(0.75rem, min(20cqh, 2.15cqw), 2.2rem); white-space: nowrap; }

.tail { flex: 0 0 auto; display: flex; align-items: center; justify-content: center; width: clamp(50px, 6.3vw, 116px); }
.logo-box { width: 100%; height: clamp(30px, 60cqh, 104px); display: flex; align-items: center; justify-content: center; }
.logo-img { max-width: 100%; max-height: 100%; object-fit: contain; background: #fff; border-radius: 6px; padding: 4px; }
.logo-box svg { max-width: 100%; max-height: 100%; border-radius: 8px; }

/* not-found tracked flight */
.flight.not-found { opacity: 0.72; justify-content: space-between; border-left-color: var(--dim); }
.flight .await { font-family: var(--num-font); color: var(--muted); letter-spacing: 0.14em; font-size: clamp(0.8rem, 16cqh, 1.2rem); }

/* ---- Empty states ---- */
.empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 0.6rem; color: var(--muted); }
.empty .big { font-size: clamp(1.4rem, 4vw, 3rem); font-weight: 800; letter-spacing: 0.08em; color: var(--text); }
.empty .sub { font-size: clamp(0.9rem, 1.8vw, 1.3rem); }
.empty .url { font-family: var(--mono); color: var(--accent); margin-top: 0.4rem; }

/* ---- Cycle mode (single flight, auto-cycling) ---- */
#app[data-layout='cycle'] #main { grid-template-columns: minmax(0, 1fr); }
.cycle {
  height: 100%; display: flex; flex-direction: column; justify-content: center;
  gap: clamp(1rem, 4vh, 3rem); padding: clamp(0.5rem, 3vw, 3rem);
  animation: cyc-in 0.45s ease;
}
@keyframes cyc-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
.cyc-head { display: flex; align-items: center; gap: clamp(1rem, 3vw, 2.5rem); min-width: 0; }
.cyc-icon { flex: 0 0 auto; width: clamp(48px, min(15vh, 13vw), 170px); height: clamp(48px, min(15vh, 13vw), 170px); }
.cyc-icon svg { width: 100%; height: 100%; display: block; }
.cyc-title { flex: 1 1 auto; min-width: 0; }
.cyc-name { font-family: var(--num-font); font-weight: 800; font-size: clamp(1.8rem, min(9vh, 7vw), 6rem); line-height: 1; letter-spacing: 0.02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: flex; align-items: baseline; gap: 0.35em; }
.cyc-sub { display: flex; align-items: center; gap: 0.6em; margin-top: 0.4em; font-size: clamp(0.9rem, min(3.6vh, 2.6vw), 2.4rem); min-width: 0; }
.cyc-sub .route { font-size: 1em; min-width: 0; }
.cyc-sub .airline-pill { font-size: 0.62em; }
.cyc-model { margin-top: 0.35em; color: var(--muted); font-family: var(--num-font); font-size: clamp(0.8rem, 2.2vh, 1.5rem); }
.cyc-logo { flex: 0 0 auto; display: flex; align-items: center; }
.cyc-logo .logo-box { height: clamp(48px, 13vh, 140px); }
.cyc-logo .logo-img { background: #fff; border-radius: 10px; padding: 6px; max-height: 100%; max-width: clamp(90px, 18vw, 240px); object-fit: contain; }
.cyc-logo svg { max-height: clamp(48px, 13vh, 140px); border-radius: 12px; }
.cyc-metrics { display: flex; justify-content: space-between; gap: clamp(0.5rem, 2vw, 2rem); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: clamp(0.8rem, 3vh, 2rem) 0; }
.cyc-metric { display: flex; flex-direction: column; gap: 0.3em; min-width: 0; }
.cyc-metric label { font-size: clamp(0.55rem, 1.6vh, 1rem); letter-spacing: 0.14em; color: var(--dim); text-transform: uppercase; }
.cyc-metric span { font-family: var(--num-font); font-weight: 700; font-size: clamp(1rem, min(5vh, 3.4vw), 3.2rem); white-space: nowrap; }
.cyc-progress { display: flex; justify-content: center; gap: 0.5rem; flex-wrap: wrap; }
.cyc-dot { width: 0.7rem; height: 0.7rem; border-radius: 50%; background: var(--line); }
.cyc-dot.on { background: var(--fc, var(--accent)); }

/* ---- Side panel: map / radar ---- */
.side { position: relative; background: var(--panel); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; min-height: 0; }
/* Map ink adapts to the basemap polarity (set from CARTO_TILE_STYLE). */
#app[data-map='dark'] {
  --map-bg: #0b1020;
  --map-ink: #ffffff;                  /* home marker */
  --map-ring: rgba(255, 255, 255, 0.3); /* range circles */
  --map-label: #ffffff;
  --map-halo: #000000;                 /* text halo */
  --map-icon-halo: rgba(0, 0, 0, 0.85);
}
#app[data-map='light'] {
  --map-bg: #eaeaea;
  --map-ink: #11333c;
  --map-ring: rgba(17, 51, 60, 0.45);
  --map-label: #0b2a32;
  --map-halo: #ffffff;
  /* Aircraft icons are airline-coloured and often bright, which has almost no
     contrast on near-white tiles — outline them darkly, not with white. */
  --map-icon-halo: rgba(0, 0, 0, 0.6);
}
.map { position: absolute; inset: 0; background: var(--map-bg, #0b1020); }
.leaflet-container { background: var(--map-bg, #0b1020); font: inherit; }
.leaflet-control-attribution { font-size: 9px; background: rgba(0,0,0,0.5); color: #888; }
.leaflet-control-attribution a { color: #aaa; }
.radar-canvas { position: absolute; inset: 0; margin: auto; aspect-ratio: 1 / 1; max-width: 100%; max-height: 100%; }
.range { position: absolute; bottom: 0.5rem; right: 0.7rem; font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.1em; color: var(--muted); z-index: 400; }

/* ---- Map plane markers ---- */
.plane-div { background: none !important; border: none !important; }
.pm { position: relative; width: 42px; height: 42px; }
.pm-ico { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; filter: drop-shadow(0 0 2px var(--map-icon-halo, rgba(0,0,0,0.85))) drop-shadow(0 0 1px var(--map-icon-halo, rgba(0,0,0,0.85))); }
.pm-ico svg { width: 26px; height: 26px; }
.pm-lbl { position: absolute; top: 100%; left: 50%; transform: translateX(-50%); margin-top: 1px; font: 700 9px/1 var(--mono); color: var(--map-label, #fff); text-shadow: 0 0 3px var(--map-halo, #000), 0 0 3px var(--map-halo, #000), 0 0 2px var(--map-halo, #000); white-space: nowrap; }

/* ---- Appearance alert ---- */
.alert {
  position: absolute; left: 50%; bottom: 9%; transform: translate(-50%, 24px);
  display: flex; align-items: center; gap: 0.5em; z-index: 30;
  background: var(--accent); color: #06121f;
  padding: 0.7em 1.4em; border-radius: 999px; font-weight: 800;
  font-size: clamp(0.9rem, 2vw, 1.4rem); letter-spacing: 0.01em;
  box-shadow: 0 10px 34px rgba(0,0,0,0.55); opacity: 0;
  transition: opacity 0.4s ease, transform 0.4s ease;
}
.alert.show { opacity: 1; transform: translate(-50%, 0); }
.alert-ico { font-size: 1.1em; }

/* ---- Footer ---- */
#foot {
  display: flex; align-items: center; gap: 1.2rem;
  padding: clamp(0.3rem, 1vh, 0.7rem) clamp(0.8rem, 2vw, 1.6rem);
  border-top: 1px solid var(--line); color: var(--muted);
  font-family: var(--mono); font-size: clamp(0.65rem, 1.3vw, 0.9rem); letter-spacing: 0.06em;
}
#foot .count { margin-left: auto; }
.status .dot { margin-right: 0.4em; }

/* ---- ATC audio ---- */
.audio-bar { display: flex; align-items: center; gap: 0.9rem; min-width: 0; overflow: hidden; }
.ach { display: inline-flex; align-items: center; gap: 0.35em; white-space: nowrap; }
.audio-gate {
  position: absolute; left: 50%; bottom: 9%; transform: translateX(-50%); z-index: 25;
  background: var(--accent); color: #06121f; border: none; cursor: pointer;
  padding: 0.7em 1.4em; border-radius: 999px; font-weight: 800;
  font-size: clamp(0.9rem, 2vw, 1.3rem); box-shadow: 0 10px 34px rgba(0,0,0,0.55);
}
.audio-gate:hover { filter: brightness(1.06); }

/* ---- Kiosk ---- */
body.idle #app { cursor: none; }
body.idle .fs { opacity: 0; }

/* ---- Narrow (portrait / small screens) ---- */
@media (max-width: 820px) {
  #main, #app.no-side #main { grid-template-columns: minmax(0, 1fr); }
  .side { display: none; }
  .flight { flex-wrap: wrap; gap: 0.3rem 0.8rem; }
  .metrics { flex-wrap: wrap; }
  .tail { flex-direction: row; gap: 0.5em; }
}
