/* Vigiflamme — "Bulletin".
   The panel is a printed dispatch on paper; the map is a dark instrument it
   sits beside. Two colour namespaces on purpose: the paper tokens (-p suffix
   or explicit names) style the panel, and the original dark tokens style
   everything that floats on the map (timebar, popups, chips, zoom). The
   fire-data colours are validated on the dark basemap and never move; on
   paper they may appear only as swatches with an inset ink edge, never as
   text — their textual translations are --braise and --compute.
   Contrast floor on paper: --ink-pmuted, 5.06:1. Nothing lighter carries text. */
:root {
  color-scheme: dark;

  /* map-side (dark) — unchanged, consumed by map furniture only */
  --page: #0d0d0d;
  --surface: #1a1a19;
  --surface-2: #232322;
  --ink: #ffffff;
  --ink-2: #c3c2b7;
  --muted: #9d9b93;
  --grid: #2c2c2a;
  --hairline: rgba(255, 255, 255, 0.10);
  --hotspot: #d95926;      /* FIRMS theme colour */
  --age-0: #ffa570;        /* < 6 h  */
  --age-1: #e06c2e;        /* 6–24 h */
  --age-2: #93857a;        /* 1–3 j — n'est plus détecté */
  --age-3: #6f675f;        /* > 3 j — n'est plus détecté */
  --burnt: #9085e9;        /* EFFIS burnt area */
  --note: #199e70;         /* manual annotations */

  /* paper-side (panel) */
  --paper: #f4f1ea;
  --paper-2: #eae6dc;      /* hover / recessed fills */
  --field: #fbfaf6;        /* form control fill */
  --ink-p: #1c1a17;        /* 15.39:1 on paper */
  --ink-p2: #4a463f;       /*  8.31:1 */
  --ink-pmuted: #6b665c;   /*  5.06:1 — the floor */
  --hairline-p: #d8d2c4;   /* separators, never text */
  --officiel: #9e1b1b;     /* the ONLY red: 112 band, official credits,
                              reported rules, divergence, échec */
  --compute: #1f4e79;      /* computed figures, wind credit  (7.68:1) */
  --braise: #8a3d12;       /* text-safe translation of map orange (6.75:1) */
  --ok: #2e6b46;           /* pipeline ok (5.63:1) */
  --stale: #8a5900;        /* staleness (5.30:1) */
  --lab: #8d2f5f;          /* speculative model (6.88:1) */

  --font-body: system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-doc: ui-serif, Georgia, "Times New Roman", serif;

  /* How much of the bottom sheet shows before the visitor opens it:
     60px (just the handle) so the map is fully visible on mobile. */
  --sheet-peek: 60px;
}

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
  background: var(--page);
  color: var(--ink);
  font: 14px/1.45 var(--font-body);
}

#app {
  display: flex;
  height: 100vh;   /* fallback */
  height: 100dvh;  /* mobile: excludes the browser chrome */
}

/* ---------- the panel: a paper document ---------- */
#panel {
  width: 320px;
  flex: 0 0 320px;
  overflow-y: auto;
  background: var(--paper);
  color: var(--ink-p);
  color-scheme: light;           /* native controls render for a light surface */
  border-right: 1px solid #0d0d0d;
  padding: 18px 18px 28px;
  scrollbar-width: thin;
  scrollbar-color: #c9c2b2 transparent;
  counter-reset: section;
}
#app.panel-hidden #panel { display: none; }

/* Masthead under an Oxford rule (3px + a 1px echo), like a printed head. */
.panel-head {
  position: relative;
  padding-bottom: 10px;
  border-bottom: 3px solid var(--ink-p);
}
.panel-head::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -6px;
  border-top: 1px solid var(--ink-p);
}
.panel-head h1 {
  margin: 0;
  font: 600 21px/1.15 var(--font-doc);
  letter-spacing: 0;
  color: var(--ink-p);
  text-wrap: balance;
}
.subtitle { margin: 4px 0 0; color: var(--ink-p2); font-size: 12px; }

/* The closing rule: the document has a printed bottom edge too. */
#panel > .panel-section:last-of-type {
  position: relative;
  border-bottom: 1px solid var(--ink-p);
  padding-bottom: 12px;
}
#panel > .panel-section:last-of-type::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -5px;
  border-top: 3px solid var(--ink-p);
}

/* ---------- the 112 band ----------
   The one solid-red object in the panel (its only sibling is the red strip on
   the mobile sheet handle: both mean "emergency channel"). Full bleed, white
   on red at 8.0:1. Nothing else on the page may be filled red. */
.alert-box {
  margin: 14px -18px 0;
  background: var(--officiel);
  border: none;
  border-radius: 0;
  padding: 12px 18px;
  font-size: 13px;
  color: #fff;
}
.alert-box strong { color: #fff; }
/* 112 is the one thing on this page someone might need to act on in a hurry,
   so it is a real phone link with a real ≥44px tap target, not bold text. */
.tel-112 {
  color: #fff; font-weight: 700; font-size: 16px;
  text-decoration: underline; text-underline-offset: 3px;
  padding: 12px 8px; margin: -12px -8px;
  -webkit-tap-highlight-color: rgba(255, 255, 255, 0.3);
}
.tel-112:hover, .tel-112:focus-visible { background: rgba(255, 255, 255, 0.14); }

/* ---------- sections: numbered like a communiqué ---------- */
.panel-section { margin-top: 22px; }
.panel-section h2 {
  margin: 0 0 8px;
  border-top: 2px solid var(--ink-p);
  padding-top: 8px;
  font: 700 13px/1.3 var(--font-body);
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-p);
}
/* Only visible sections are counted — a dispatch numbered 1, 4, 5 reads broken. */
.panel-section:not([hidden]) h2::before {
  counter-increment: section;
  content: counter(section) ".\2002";
  font-family: var(--font-doc);
  font-weight: 600;
}
/* The situation head shares its row with the refresh button, so the rule
   belongs to the row, not the h2. */
.situation-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  border-top: 2px solid var(--ink-p);
  padding-top: 8px;
  margin-bottom: 8px;
}
#situation-section h2 { border-top: 0; padding-top: 0; margin: 0; }

.field-label {
  display: block;
  font-size: 12px; font-weight: 600;
  letter-spacing: 0; text-transform: none;
  color: var(--ink-p2);
  margin-bottom: 6px;
}

/* ---------- controls ----------
   Base styles are the dark ones (timebar, panel toggle live on the map);
   the panel overrides them for paper. */
select, .btn {
  background: var(--surface-2);
  color: var(--ink);
  border: 1px solid var(--hairline);
  border-radius: 4px;
  padding: 6px 10px;
  font: inherit;
  font-size: 13px;
}
select:focus-visible, .btn:focus-visible, input:focus-visible { outline: 2px solid var(--age-0); outline-offset: 1px; }
.btn { cursor: pointer; }
.btn:hover { background: #2b2b29; }

#panel select, #panel .btn {
  background: var(--field);
  color: var(--ink-p);
  border: 1px solid var(--ink-pmuted);
  border-radius: 0;
  padding: 7px 10px;
}
#panel .btn:hover { background: var(--paper-2); }
#panel .btn:active { translate: 0 1px; }
#panel select:focus-visible, #panel .btn:focus-visible, #panel input:focus-visible {
  outline: 2px solid var(--ink-p); outline-offset: 1px;
}
#dataset-select { width: 100%; }
.btn-row { display: flex; gap: 8px; }
.btn-wide { width: 100%; margin-top: 2px; }

/* The #panel control override above outspecifies bare classes, so the refresh
   button's tweaks are #panel-scoped too or they are silently dead. */
.btn-refresh, #panel .btn-refresh {
  width: 30px; height: 26px; flex: none; padding: 0; font-size: 14px; line-height: 1;
  color: var(--ink-p2);
}
.btn-refresh[data-busy="1"], #panel .btn-refresh[data-busy="1"] {
  color: var(--braise); animation: spin 1.1s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Fine print: 12px is the daylight floor — outdoors, on a phone, nothing
   under it earns its place. Dark-surface contexts recolour it below. */
.fine { font-size: 12px; line-height: 1.45; color: var(--ink-pmuted); margin: 6px 0 0; text-wrap: pretty; }
.fine a { color: var(--ink-p2); }
#timebar .fine, .leaflet-popup-content .fine { color: var(--muted); }

/* ---------- situation: a ledger, not a card grid ----------
   Reported and computed figures hang from coloured provenance rules (red =
   préfecture, blue = computed here) — they are not equally trustworthy, and
   the printed key under the grid says which is which in words. */
.sit-duration {
  font-size: 12px; color: var(--braise); font-variant-numeric: tabular-nums;
  margin: 2px 0 10px;
}
.sit-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.sit-cell {
  background: none;
  border-radius: 0;
  border-left: 3px solid transparent;
  border-bottom: 1px solid var(--hairline-p);
  padding: 6px 0 8px 10px;
}
.sit-cell.wide { grid-column: 1 / -1; }
.sit-cell.reported { border-left-color: var(--officiel); }
.sit-cell.computed { border-left-color: var(--compute); }
.sit-value {
  font: 650 22px/1.1 var(--font-body);
  letter-spacing: -0.01em;
  font-variant-numeric: lining-nums tabular-nums;
  color: var(--ink-p);
}
.sit-value .unit { font: 500 11px/1 var(--font-body); color: var(--ink-pmuted); margin-left: 2px; }
.sit-label { font-size: 11px; color: var(--ink-pmuted); margin-top: 2px; line-height: 1.25; }
.sit-sub { font-size: 11px; color: var(--ink-p2); margin-top: 3px; }
.sit-key { margin: 8px 0 0; font-size: 12px; color: var(--ink-pmuted); }
.sit-key .key-red, .sit-key .key-blue {
  display: inline-block; width: 10px; height: 10px;
  vertical-align: -1px; margin-right: 3px;
}
.sit-key .key-red { background: var(--officiel); }
.sit-key .key-blue { background: var(--compute); }
.sit-status { margin-top: 8px; font-size: 11px; color: var(--ink-pmuted); }
.sit-status .step { display: flex; justify-content: space-between; gap: 8px; padding: 1px 0; }
.sit-status .ok { color: var(--ok); }
.sit-status .ko { color: var(--officiel); }

/* ---------- layer toggles: rows, not cards ---------- */
.layer-item {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 0; margin: 0;
  background: none;
  border-radius: 0;
  border-bottom: 1px solid var(--hairline-p);
}
.layer-item input[type="checkbox"] {
  margin-top: 2px;
  width: 18px; height: 18px;
  accent-color: var(--ink-p);
}
.layer-item .layer-label { flex: 1; cursor: pointer; }
.layer-item .layer-title { font-weight: 600; font-size: 13px; color: var(--ink-p); }
.layer-item .layer-sub { font-size: 11px; color: var(--ink-pmuted); margin-top: 1px; }

/* ---------- source credits: [BRACKETED], like a wire agency ----------
   Pills are gone. Agency identity lives in the adjacent swatch; the credit
   carries provenance only, so most are neutral. Red stays official. */
.badge {
  display: inline-block;
  background: none; border-radius: 0; padding: 0;
  margin-left: 6px; vertical-align: 0;
  font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.02em; text-transform: uppercase;
  color: var(--ink-pmuted);
}
.badge::before { content: "["; }
.badge::after { content: "]"; }
.badge-officiel { color: var(--officiel); }
.badge-wind { color: var(--compute); }
.badge-lab { color: var(--lab); }
/* firms / effis / manual / live stay neutral on purpose */

.count-pill {
  display: inline-block; margin-left: 5px; padding: 0;
  background: none; border-radius: 0;
  color: var(--ink-pmuted); font-size: 11px; font-weight: 600;
  letter-spacing: 0; text-transform: none; font-variant-numeric: tabular-nums;
}
.count-pill::before { content: "("; }
.count-pill::after { content: ")"; }

/* ---------- legend ----------
   Swatch colours key the map, so they never change with the theme; on paper
   each gets an inset ink edge so light swatches keep a shape. */
.legend-block { margin-bottom: 14px; }
.legend-title { font-size: 13px; font-weight: 600; color: var(--ink-p); margin-bottom: 5px; }
.legend-row { display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--ink-p2); margin: 3px 0; }
.dot { width: 11px; height: 11px; border-radius: 50%; flex: none; }
.dot-sm { width: 7px; height: 7px; }
.dot-lg { width: 14px; height: 14px; margin-left: -2px; }
.dot-ring { width: 11px; height: 11px; border-radius: 50%; flex: none; border: 1.5px solid #e06c2e; background: transparent; }
.dot, .dot-ring, .poly-swatch, .alert-swatch, .evac-swatch, .ramp-swatch {
  box-shadow: inset 0 0 0 1px rgba(28, 26, 23, 0.25);
}
.poly-swatch {
  width: 18px; height: 12px; flex: none; border-radius: 0;
  border: 1.5px dashed var(--burnt);
  background: rgba(144, 133, 233, 0.14);
}
.alert-swatch {
  width: 18px; height: 12px; flex: none; border-radius: 0;
  border: 2px solid #d03b3b; background: rgba(208, 59, 59, 0.15);
}
.evac-swatch {
  width: 18px; height: 12px; flex: none; border-radius: 0;
  border: 2px solid #d03b3b; background: rgba(208, 59, 59, 0.22);
}
.evac-swatch.partial { border-style: dashed; border-width: 1.5px; background: rgba(208, 59, 59, 0.07); }
/* The chip swatch previews a map chip on paper: same shape, but paper-legible
   green — the map keeps its own colour on dark. */
.chip-swatch {
  font-size: 10px; padding: 1px 7px; border-radius: 0;
  background: rgba(46, 107, 70, 0.10); color: var(--ok); border: 1px solid var(--ok);
}
.chip-media { border-style: dashed; opacity: 0.85; }
/* The aircraft pictograms are drawn for the dark map (the Canadair is pure
   yellow); on paper they get a small dark chip that previews that context. */
.legend-row img {
  background: #232322;
  padding: 2px;
  box-shadow: inset 0 0 0 1px rgba(28, 26, 23, 0.25);
}
.legend-arrow { color: var(--compute); font-size: 14px; width: 12px; text-align: center; flex: none; }
.legend-num {
  color: var(--compute); font-size: 11px; font-weight: 700; width: 16px; text-align: center; flex: none;
  font-variant-numeric: tabular-nums;
}

/* Météo des forêts levels (official Météo-France scale colours, icon+label always paired) */
.mdf-row { display: flex; align-items: center; gap: 8px; padding: 5px 0; font-size: 12.5px; color: var(--ink-p2); }
.mdf-level {
  padding: 2px 9px; border-radius: 2px; font-weight: 650; font-size: 11px;
  border: 1px solid rgba(28, 26, 23, 0.3); color: #0b0b0b;
}
.mdf-1 { background: #7ec97e; } .mdf-2 { background: #f3d251; }
.mdf-3 { background: #f0a24c; } .mdf-4 { background: #e66767; }

/* ---------- freshness: dotted leaders, like a printed table of contents ---------- */
.fresh-row { display: flex; justify-content: space-between; gap: 8px; font-size: 12px; padding: 3px 0; border-bottom: 1px dotted var(--hairline-p); }
.fresh-row:last-child { border-bottom: 0; }
.fresh-row .k { color: var(--ink-p2); }
.fresh-row .v { color: var(--ink-pmuted); text-align: right; font-variant-numeric: tabular-nums; }
/* A snapshot old enough to be misleading stops looking like ordinary metadata. */
.fresh-row .v-stale { color: var(--stale); font-weight: 600; }

/* ---------- speculative model projection — styled to look unmistakably unlike data ---------- */
.lab-warning {
  background: none;
  border: 1px dashed var(--lab);   /* dashed = simulated, like the hatched zone */
  border-radius: 0;
  padding: 10px 12px;
  font-size: 12px;
  color: var(--lab);
  margin-bottom: 12px;
}
.lab-warning strong { color: var(--lab); }
.ramp-row { display: flex; align-items: center; gap: 0; margin: 4px 0 2px; }
.ramp-swatch { flex: 1; height: 12px; }
.ramp-labels { display: flex; justify-content: space-between; font-size: 12px; color: var(--ink-pmuted); }
#lab-meta { margin-top: 8px; }
#lab-meta .fresh-row .v { color: var(--lab); }

.stale-box {
  margin-top: 16px;
  background: none;
  border: 1px solid var(--stale);
  border-left-width: 4px;
  border-radius: 0;
  padding: 9px 12px;
  font-size: 12px;
  color: var(--stale);
}

/* ---------- veille (press watch): live-blog rows ---------- */
.veille-item {
  display: block; padding: 8px 0; margin: 0;
  background: none; border-radius: 0; border-left: none;
  border-bottom: 1px solid var(--hairline-p);
  text-decoration: none; color: inherit;
}
.veille-meta { display: flex; gap: 6px; align-items: baseline; font-size: 12px; color: var(--ink-pmuted); margin-bottom: 2px; }
.veille-src { color: var(--ink-p); font-weight: 700; font-size: 12px; }
.veille-time { font-variant-numeric: tabular-nums; color: var(--ink-p2); }
.veille-title { font-size: 13px; line-height: 1.35; color: var(--ink-p2); }
.veille-item:hover .veille-title { color: var(--ink-p); text-decoration: underline; text-underline-offset: 2px; }
.veille-communes { margin-top: 3px; font-size: 11px; color: var(--ink-pmuted); }

/* ---------- figures extracted from the press — proposals, never official ---------- */
.xtr-item {
  display: block; padding: 8px 0; margin: 0;
  background: none; border-radius: 0;
  border-bottom: 1px solid var(--hairline-p);
  text-decoration: none; color: inherit;
}
.xtr-item:hover { background: var(--paper-2); }
/* Divergence from the official recap is an official-data integrity flag: it
   earns the red rule. */
.xtr-item.diverges { border-left: 3px solid var(--officiel); padding-left: 10px; }
.xtr-head { display: flex; gap: 6px; align-items: baseline; justify-content: space-between; }
.xtr-label { font-size: 11px; color: var(--ink-pmuted); letter-spacing: 0; text-transform: none; }
.xtr-value { font-size: 15px; font-weight: 650; color: var(--ink-p); font-variant-numeric: lining-nums tabular-nums; }
.xtr-official { font-size: 11px; color: var(--ink-pmuted); margin-top: 2px; }
.xtr-official strong { color: var(--officiel); font-weight: 600; }
.xtr-quote {
  margin-top: 5px; padding-left: 7px; border-left: 2px solid var(--hairline-p);
  font-size: 12px; line-height: 1.35; color: var(--ink-p2); font-style: italic;
}
.xtr-src { margin-top: 4px; font-size: 11px; color: var(--ink-pmuted); }

/* ---------- honesty: the one framed block in the document ---------- */
.honesty {
  background: none;
  border: 1px solid var(--ink-p);
  border-radius: 0;
  padding: 12px 14px;
}
.honesty h2 { border-top: 0; padding-top: 0; color: var(--ink-p); }
.honesty p { margin: 0; font-size: 12.5px; color: var(--ink-p2); }

/* ---------- map + timebar (dark side — unchanged tokens) ---------- */
#map-wrap { position: relative; flex: 1; min-width: 0; }
#map { position: absolute; inset: 0; background: #101011; }

#panel-toggle {
  position: absolute; z-index: 1000; top: 12px; left: 12px;
  width: 34px; height: 34px; border-radius: 4px;
  background: var(--surface); color: var(--ink-2);
  border: 1px solid var(--hairline); cursor: pointer; font-size: 15px;
}
#panel-toggle:hover { color: var(--ink); }

/* No backdrop blur: it is a GPU cost on hot phones in the field, and the
   92% surface is opaque enough to read against every basemap tile. */
#timebar {
  position: absolute; z-index: 1000; left: 14px; right: 14px; bottom: 12px;
  background: rgba(13, 13, 13, 0.92);
  border: 1px solid var(--hairline);
  border-radius: 4px;
  padding: 10px 14px 8px;
}
.timebar-top { display: flex; align-items: center; gap: 12px; }
.btn-icon { width: 34px; height: 30px; flex: none; text-align: center; padding: 0; }
#time-readout { flex: 1; min-width: 0; }
#time-current { font-weight: 650; font-size: 14.5px; font-variant-numeric: tabular-nums; }
#time-count { margin-left: 8px; }
.timebar-controls { display: flex; gap: 10px; align-items: center; }
.timebar-controls label { font-size: 11px; color: var(--muted); display: flex; gap: 5px; align-items: center; }
.timebar-controls select { padding: 3px 6px; font-size: 12px; }

#histo-wrap { position: relative; height: 56px; margin-top: 8px; }
#histo { position: absolute; inset: 0; width: 100%; height: 100%; }
#scrubber {
  position: absolute; inset: 0; width: 100%; height: 100%;
  margin: 0; -webkit-appearance: none; appearance: none;
  background: transparent; cursor: ew-resize;
}
#scrubber::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 3px; height: 56px; border-radius: 2px;
  background: var(--ink); box-shadow: 0 0 0 1px rgba(0,0,0,0.6);
}
#scrubber::-moz-range-thumb {
  width: 3px; height: 56px; border: 0; border-radius: 2px;
  background: var(--ink); box-shadow: 0 0 0 1px rgba(0,0,0,0.6);
}
.timebar-bottom { display: flex; justify-content: space-between; margin-top: 4px; font-variant-numeric: tabular-nums; }
#histo-hover { color: var(--ink-2); }

/* Aerial imagery is dimmed and desaturated so the overlays keep their footing
   on it. This is a compromise, not a fix on its own: measured on a real IGN
   tile over this fire, even brightness 0.4 leaves the oldest ash dot at
   2.72:1 against bright ground. The dots carry a dark halo as well — see
   HALO_ALPHA in js/maplayer.js. 0.72 is where the imagery is still legible as
   terrain while everything drawn on it stays readable. */
.basemap-satellite .basemap-tiles { filter: brightness(0.72) saturate(0.85); }
/* The label overlay must NOT be dimmed with the imagery underneath it — that
   is the whole reason it is a separate layer rather than part of the basemap. */
.basemap-labels { filter: none; }
/* The department outlines are drawn for the dark basemap and read as noise
   over a photograph, where real boundaries are already visible. */
.basemap-satellite .leaflet-overlay-pane path[stroke="#898781"] { opacity: 0.35; }

/* leaflet dark tweaks */
.leaflet-container { font: inherit; }
.leaflet-control-zoom a {
  background: var(--surface); color: var(--ink-2); border-color: var(--hairline);
}
.leaflet-control-zoom a:hover { background: var(--surface-2); color: var(--ink); }
.leaflet-control-attribution {
  background: rgba(13, 13, 13, 0.75); color: var(--muted); font-size: 10px;
}
.leaflet-control-attribution a { color: var(--ink-2); }
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
  background: var(--surface); color: var(--ink);
  border-radius: 4px; box-shadow: 0 6px 24px rgba(0,0,0,0.5);
}
.leaflet-popup-content { margin: 10px 14px; font: 12.5px/1.5 var(--font-body); }
.leaflet-popup-content .p-illus {
  display: block; width: 100%; max-width: 100%; height: auto;
  border-radius: 3px; margin-bottom: 5px;
  /* pure-white hairline, never a tinted neutral, so the edge does not pick up
     the surface colour and read as dirt on the image */
  outline: 1px solid rgba(255, 255, 255, 0.10); outline-offset: -1px;
}
.leaflet-popup-content .p-illus-cap {
  font-size: 10.5px; line-height: 1.35; color: var(--muted);
  margin: -2px 0 7px;
}
.leaflet-popup-content .p-title { font-weight: 650; margin-bottom: 3px; }
.leaflet-popup-content .p-kv { display: flex; justify-content: space-between; gap: 12px; }
.leaflet-popup-content .p-kv .k { color: var(--muted); }
.leaflet-popup-content a { color: #b3aaf0; }
.leaflet-popup-close-button { color: var(--muted); }

/* annotation chips on map (dark side) — square like their legend preview */
.note-chip {
  background: rgba(13, 13, 13, 0.85);
  border: 1px solid rgba(25, 158, 112, 0.55);
  color: #4cc496;
  border-radius: 0;
  padding: 2px 8px;
  font-size: 10.5px; font-weight: 600; white-space: nowrap;
  box-shadow: 0 2px 8px rgba(0,0,0,0.4);
}
.note-chip.dimmed { opacity: 0.45; }
.note-chip.stale, .evac-label.stale, .alert-zone-label.stale {
  width: 14px !important;
  height: 14px !important;
  padding: 0 !important;
  min-width: 14px !important;
  border-radius: 50% !important;
  color: transparent !important;
  overflow: hidden !important;
  opacity: 0.6;
}
.note-chip.kind-media { border-style: dashed; font-weight: 500; }
.note-chip.kind-retour { border-color: rgba(126, 201, 126, 0.7); color: #8fd48f; }
.note-chip.kind-route { border-color: rgba(240, 162, 76, 0.6); color: #f0b06c; }

.evac-label {
  background: rgba(13, 13, 13, 0.88);
  border: 1px solid rgba(208, 59, 59, 0.75);
  color: #f0a0a0;
  border-radius: 4px;
  padding: 2px 8px;
  font-size: 11px; font-weight: 700; white-space: nowrap;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
  transform: translate(-50%, -50%);
  display: inline-block;
  pointer-events: none;
}
.evac-label.partial { border-style: dashed; font-weight: 600; opacity: 0.9; }

.alert-zone-label {
  background: rgba(13, 13, 13, 0.86);
  border: 1px solid rgba(208, 59, 59, 0.65);
  color: #ef8a8a;
  border-radius: 4px;
  padding: 2px 7px;
  font-size: 10.5px; font-weight: 650; white-space: nowrap;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.5);
  /* the divIcon anchors top-left; centre the chip on the place instead */
  transform: translate(-50%, -50%);
  display: inline-block;
  pointer-events: none;
}

/* wind grid on map (dark side) */
/* 44px tap target around a 24px pictogram: a fingertip is nearer 40px, and the
   misses used to land on the evacuation polygon underneath. */
.aircraft-hit {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
/* An aircraft position older than the site's own refresh cycle is not a
   position any more. Past 2 h it fades, on the same rule the hotspot ramp and
   the freshness table use. */
.aircraft-marker.stale { opacity: 0.45; }

.wind-icon { text-align: center; color: #9ec5f4; font-variant-numeric: tabular-nums; }
.wind-marker { display: block; width: 24px; height: 24px; margin: 0 auto; transition: transform 0.3s ease; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.6)); }
.wind-spd { font-size: 11px; font-weight: 700; text-shadow: 0 1px 3px #000, 0 0 2px #000; margin-top: -3px; }

/* The sheet handle only exists on phones; on a desktop the panel is a column. */
#sheet-handle { display: none; }

@media (max-width: 760px) {
  /* ---- phone layout: the map is the page, the panel is a bottom sheet ----
     Before this, #panel was an opaque 320px column at z-index 1100 covering
     85% of a 375px screen, and #panel-toggle sat *under* it at z-index 1000 —
     so a visitor on a phone landed on a wall of text with no way to reach the
     map. The sheet fixes that by never covering the whole map and by putting
     its own control inside itself, where nothing can stack on top of it. */

  #app { display: block; position: relative; }

  /* The map fills the viewport; the sheet floats over it. */
  #map-wrap { position: absolute; inset: 0; }

  #panel {
    position: fixed;
    left: 0; right: 0; bottom: 0; top: auto;
    width: auto; flex: none;
    height: 92dvh;
    z-index: 1100;
    padding: 0 14px 22px;
    border-right: none;
    border-top: none;                 /* the handle's red strip is the edge */
    border-radius: 12px 12px 0 0;
    box-shadow: 0 -10px 34px rgba(0, 0, 0, 0.55);
    /* Peeked by default: just the handle, so the map stays fully visible. */
    transform: translateY(calc(92dvh - var(--sheet-peek)));
    transition: transform 0.26s cubic-bezier(0.32, 0.72, 0, 1);
    overscroll-behavior: contain;
  }
  #app.sheet-open #panel { transform: translateY(0); }

  /* What the peek shows is decided here, not by document order. A phone gets
     the 112 notice and the headline figures first; the site title and its
     subtitle are the least useful 50px on a screen this size, so they move
     below the fold rather than pushing the figures off it. Flex `order` does
     this without touching the markup, so the reading order for a screen reader
     and the desktop column both stay as authored. */
  #panel { display: flex; flex-direction: column; }
  #sheet-handle { order: -3; }
  #panel .alert-box { order: -2; margin: 8px -14px 0; padding: 12px 14px; }
  #panel #situation-section { order: -1; margin-top: 14px; }
  #panel .panel-head { margin-top: 18px; }
  #panel .panel-head h1 { font-size: 19px; }

  /* Desktop's hide-the-panel mode does not apply: on a phone the 112 notice
     must never be one tap away from invisible. */
  #app.panel-hidden #panel { display: flex; }

  /* The red strip on the handle pairs with the 112 band: the two solid-red
     objects on screen both mean "emergency channel", and the strip stays
     visible in sunlight when the sheet is peeked. */
  #sheet-handle {
    display: flex;
    position: sticky; top: 0; z-index: 2;
    align-items: center; justify-content: center; gap: 9px;
    /* Full bleed past the panel's 14px side padding, like the 112 band —
       otherwise the red strip stops short of the sheet's rounded corners. */
    width: auto; align-self: stretch;
    min-height: 46px; padding: 10px 0 8px;
    margin: 0 -14px 2px;
    background: var(--paper);
    border: none;
    border-top: 4px solid var(--officiel);
    border-radius: 12px 12px 0 0;
    color: var(--ink-p2); font: inherit; font-size: 12.5px; font-weight: 600;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
  }
  .sheet-grip {
    width: 34px; height: 4px; border-radius: 99px;
    background: var(--ink-p); opacity: 0.35;
  }

  /* The old toggle collided pixel-for-pixel with Leaflet's zoom control
     (both top-left, both 34px) and is redundant now. */
  #panel-toggle { display: none; }

  /* All three controls are available on a phone — hiding "pas" and "vitesse"
     removed playback speed, which is half the point of the scrubber. They wrap
     instead, and the labels stay small (a <label> is not a form control, so it
     does not trigger the iOS focus-zoom that forces 16px on the selects). */
  /* The controls shared a flex row with the play button and the readout, so
     they had ~140px to fit three labelled selects in and stacked three deep
     (80px). Given the full width as their own row they sit on one line. */
  .timebar-top { flex-wrap: wrap; }
  .timebar-controls { display: flex; flex: 1 0 100%; justify-content: space-between; gap: 6px; }
  .timebar-controls label { font-size: 11px; gap: 3px; }
  .timebar-controls select { padding: 2px 4px; }

  /* The bar was 168px of a 812px screen, on top of a 300px sheet — together
     more than half the map. The histogram is the bulk of it, and on touch it is
     decorative: the scrubber covers the canvas, so its hover readout can never
     fire. Drop the canvas, keep the slider, and tighten the chrome. */
  #timebar { padding: 7px 10px 5px; }
  #histo { display: none; }
  #histo-wrap { height: 30px; margin-top: 4px; }
  #histo-hover { display: none; }
  .timebar-top { gap: 8px; }
  /* The readout wrapped to two lines ("6 943 détections affichées"), and the
     min/max range labels repeat what the scrubber ends already imply. */
  #time-readout { display: flex; align-items: baseline; gap: 6px; overflow: hidden; }
  #time-current { font-size: 13.5px; white-space: nowrap; }
  #time-count { margin-left: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .timebar-bottom { display: none; }

  /* The timebar has to sit above the peeked sheet, and is covered — harmlessly —
     once the sheet is open, since the visitor is reading the panel then. */
  #timebar { bottom: calc(var(--sheet-peek) + 10px); }
  #app.sheet-open #timebar { opacity: 0; pointer-events: none; }

  /* Outdoors, in daylight, on a phone: nothing under 12px earns its place.
     These are only bumped on narrow screens so the desktop density is kept. */
  .fine, .sit-sub, .xtr-src, .veille-communes, .legend-num,
  .sit-label, .xtr-label, .xtr-official, .sit-status,
  .layer-sub, .veille-src, .veille-time, .field-label,
  .fresh-row .k, .fresh-row .v, .mdf-level,
  .layer-item .layer-sub, .sit-value .unit, .legend-num { font-size: 12px; }
  /* Credits and counts are short labels next to text, not text to be read at
     length; 11px keeps them from crowding the line they sit on. */
  .badge, .count-pill, .chip-swatch { font-size: 11px; }
  .legend-row, .veille-title, .xtr-quote { font-size: 13px; }
  .panel-section h2 { font-size: 14px; }
  /* iOS zooms the whole page when a control under 16px receives focus, and on
     this page that means the map jumps as soon as you touch the trail picker.
     .timebar-controls select needs the class-level selector to be beaten. */
  select, input, .btn,
  .timebar-controls select,
  #dataset-select { font-size: 16px; }

  /* Fingers are not mouse pointers. */
  .btn-refresh, #panel .btn-refresh { width: 44px; height: 44px; font-size: 17px; }
  #timebar select, #dataset-select { min-height: 38px; }
  #play { min-width: 44px; min-height: 44px; }
  .layer-row { padding-top: 7px; padding-bottom: 7px; }
}
