/* ═══════════════════════════════════════════════════════════
   CAC SPORT — auth screen, share cards, scope pickers
   ═══════════════════════════════════════════════════════════ */

/* ── AUTH / FATAL SCREEN ───────────────────────────────────── */
.auth-overlay{position:fixed;inset:0;z-index:var(--z-auth);display:flex;align-items:center;justify-content:center;
  padding:24px;background:radial-gradient(ellipse at 50% 0%,#0f1828,#04060d 70%);overflow-y:auto}
.auth-card{width:100%;max-width:392px;background:rgba(12,19,34,.92);border:1px solid rgba(148,163,184,.2);
  border-radius:18px;padding:34px 30px;box-shadow:0 24px 64px rgba(0,0,0,.6);text-align:center;
  animation:fadeUp .35s ease-out}
.auth-logo{height:62px;width:auto;object-fit:contain;background:#fff;border-radius:12px;padding:7px 13px;margin-bottom:20px}
.auth-card h2{font-family:'Space Grotesk','Inter',sans-serif;font-size:19px;font-weight:700;color:#e8eefc;
  margin-bottom:6px;letter-spacing:-.3px;line-height:1.3}
.auth-card p{font-size:13px;color:#9fb0cc;margin-bottom:22px;line-height:1.5}
.auth-card .field{text-align:left;margin-bottom:14px}
.auth-card .field label{color:#9fb0cc}
.auth-card .field input{background:rgba(255,255,255,.06);border:1px solid rgba(148,163,184,.26);color:#e8eefc}
.auth-card .field input:focus{border-color:#f59e0b}
.auth-card .err{display:none;text-align:left;font-size:12px;color:#f87171;margin-bottom:12px}
.auth-submit{width:100%;margin-top:6px}
.pw-wrap{position:relative}
.pw-wrap input{padding-right:48px}
.pw-toggle{position:absolute;right:4px;top:50%;transform:translateY(-50%);width:40px;height:40px;
  display:flex;align-items:center;justify-content:center;background:none;border:none;cursor:pointer;color:#9fb0cc}
.pw-toggle:hover{color:#e8eefc}
.pw-toggle svg{width:18px;height:18px}
.link-btn{display:block;width:100%;margin-top:14px;background:none;border:none;color:#f59e0b;
  font-family:inherit;font-size:13px;font-weight:600;cursor:pointer;padding:10px;min-height:44px}
.link-btn:hover{color:#fbbf24;text-decoration:underline}
.auth-msg{display:flex;gap:9px;align-items:flex-start;text-align:left;background:rgba(245,158,11,.12);
  border:1px solid rgba(245,158,11,.34);border-radius:9px;padding:11px 13px;margin-bottom:18px;
  font-size:12px;color:#fcd34d;line-height:1.45}
.auth-msg svg{width:16px;height:16px;flex-shrink:0;margin-top:1px}
.auth-lang{display:flex;justify-content:center;gap:3px;margin-top:20px;padding-top:18px;
  border-top:1px solid rgba(148,163,184,.14)}
.auth-lang .lang-btn{color:#64748b}
.auth-lang .lang-btn.active{background:linear-gradient(135deg,#f59e0b,#fbbf24);color:#0b1120}

/* ── WHO BUILT THIS, ON THE DOOR ───────────────────────────────
   The boot splash's .boot-maker, in the auth card. Same lockup, same
   white horizontal version — this card is dark in both themes — and
   deliberately quieter than the language strip above it: it is a
   signature, not a control. It IS clickable (it opens the same panel
   the header's does), so it gets a hover and a focus ring, but nothing
   that reads as a button at rest.
   No border-top of its own: the strip above already draws the line, and
   a second one would box the bottom of the card in. */
.auth-maker{display:flex;flex-direction:column;align-items:center;gap:6px;
  margin:16px auto 0;padding:4px 8px;background:none;border:0;border-radius:8px;
  cursor:pointer;opacity:.72;transition:opacity .15s}
.auth-maker:hover{opacity:1}
.auth-maker span{font-size:9px;font-weight:700;text-transform:uppercase;
  letter-spacing:.1em;color:rgba(232,238,252,.45)}
.auth-maker img{width:112px;max-width:42vw;height:auto;display:block}
@media (prefers-reduced-motion:reduce){ .auth-maker{transition:none} }

/* ── THE PERMITS MAP ───────────────────────────────────────────
   A card in a scrolling page, so it gets a fixed height rather than the
   viewport arithmetic the full-screen maps use — and cooperativeGestures
   on the map itself, so a wheel over it scrolls the page. */
.pm-map-card{margin-bottom:16px}
.pm-map-shell{position:relative;height:clamp(300px,42vh,460px);margin-top:12px;
  border-radius:12px;overflow:hidden;background:var(--bg3);border:1px solid var(--border)}
.pm-map{position:absolute;inset:0}
/* The switches, over the map. Same furniture as the road works map — its
   .rw-map-btn is already icon-only at every width, so it is borrowed
   rather than restyled. Top right, clear of the zoom and fullscreen
   controls, which sit bottom left on this one for exactly that reason. */
.pm-map-tools{position:absolute;top:10px;right:10px;z-index:3;display:flex;gap:6px;flex-wrap:wrap;
  justify-content:flex-end;max-width:calc(100% - 20px)}
.pm-map-key{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:10px;
  font-size:12px;color:var(--text2)}
.pm-key{display:inline-flex;align-items:center;gap:6px}
.pm-key i{width:10px;height:10px;border-radius:50%;flex-shrink:0}
.pm-map-none{color:var(--text3);font-style:italic}
/* The pin: the status colour is the whole message, so it is the fill and
   not a detail on it. White ring so a red pin still reads on a dark
   satellite tile and an amber one on a pale street tile. */
.pm-pin{width:19px;height:19px;border-radius:50% 50% 50% 2px;transform:rotate(-45deg);
  background:var(--pmc,#64748b);border:2.5px solid #fff;cursor:pointer;
  box-shadow:0 2px 7px rgba(0,0,0,.45);transition:transform .12s}
.pm-pin:hover{transform:rotate(-45deg) scale(1.18)}
.pm-pop{font-size:13px;line-height:1.5;min-width:150px}
.pm-pop-where{color:var(--text3);font-size:12px}
.pm-pop-acts{margin-top:9px}
.pm-pop-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:8px;
  border:1px solid var(--border2);background:var(--bg3);color:var(--text);
  font:inherit;font-size:12px;font-weight:700;cursor:pointer;text-decoration:none}
.pm-pop-btn:hover{background:var(--bg4);border-color:var(--gold-border)}
.pm-pop-btn svg{width:14px;height:14px}

/* THE HEADING THE LINK LIST NEVER HAD. It began with a bulk-select bar
   and ran on from the card above it, so live links read as page
   furniture and the pencil on every row went unfound. See renderShares(). */
.sh-listhd{margin:0 0 12px}
.sh-listhd h3{display:flex;align-items:center;gap:9px;margin:0 0 3px;
  font-family:'Space Grotesk','Inter',sans-serif;font-size:15px;font-weight:800;
  text-transform:uppercase;letter-spacing:.05em;color:var(--text)}
.sh-listn{display:inline-flex;align-items:center;justify-content:center;min-width:22px;
  height:22px;padding:0 7px;border-radius:11px;background:var(--gold-bg);
  border:1px solid var(--gold-border);color:var(--gold2);
  font-family:inherit;font-size:12px;font-weight:800;letter-spacing:0}
body.light .sh-listn{color:var(--gold)}
.sh-listhd .c-sub{margin:0}

/* ── THE "BUILT BY" NOTE ───────────────────────────────────────
   The lockup on its own dark plate, because the artwork is white and the
   modal is not. See openMakerModal() in js/app.js. */
.mk-note{text-align:center}
.mk-logo{width:150px;max-width:60%;height:auto;display:block;margin:2px auto 16px;
  background:#0b2233;border-radius:12px;padding:14px 18px}
.mk-line{font-size:15px;font-weight:800;color:var(--text);margin:0 0 12px}
.mk-body{font-size:13.5px;line-height:1.55;color:var(--text2);margin:0 0 12px;text-align:left}
.mk-promise{font-size:13px;line-height:1.5;color:var(--text3);font-style:italic;margin:0 0 18px}
.mk-acts{display:flex;gap:9px;justify-content:center;flex-wrap:wrap}
.mk-acts .btn{text-decoration:none}

/* ── PORTAL (edition picker) ───────────────────────────────── */
body.portal #sidebar{display:none}
body.portal #nav-collapse-toggle{display:none}
body.portal #menuBtn{display:none!important}

.portal-hero{text-align:center;max-width:560px;margin:16px auto 30px}
.portal-logo{height:64px;width:auto;object-fit:contain;background:#fff;border-radius:12px;padding:7px 14px;margin-bottom:18px}
.portal-hero h2{font-family:'Space Grotesk','Inter',sans-serif;font-size:26px;font-weight:700;
  color:var(--text);letter-spacing:-.5px;margin-bottom:6px;line-height:1.25}
.portal-hero p{font-size:14px;color:var(--text2)}

.proj-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(290px,100%),1fr));gap:16px;
  max-width:1100px;margin:0 auto}

/* ── The host-city dashboard on the portal ─────────────────────
   Same width as the edition cards above it; everything inside reuses
   the house cards and charts. */
.hc-wrap{text-align:left}
.hc-wrap .page-hd-text p em{color:var(--text3);font-style:normal;font-size:12px;display:block;margin-top:2px}
.hc-tabs{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px}
.hc-tabs-years{margin-bottom:18px}
.hc-pill{font-family:inherit;cursor:pointer;border:1px solid var(--border);border-radius:999px;
  background:var(--bg2);color:var(--text2);font-size:13px;font-weight:700;padding:7px 15px;
  transition:border-color .2s,color .2s,box-shadow .2s}
body.light .hc-pill{background:#fff}
.hc-pill:hover{border-color:var(--gold-border);color:var(--text)}
.hc-pill.on{border-color:var(--gold);color:var(--text);box-shadow:var(--glow-gold)}
.hc-pill.sm{font-size:12px;padding:5px 12px}
.hc-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px;margin-bottom:16px}
.hc-stat{background-color:var(--bg2);background-image:linear-gradient(160deg,rgba(255,255,255,.045),rgba(255,255,255,.012) 55%);
  border:1px solid var(--border);border-radius:var(--radius);padding:14px 16px;display:flex;flex-direction:column;gap:3px}
body.light .hc-stat{background:#fff}
.hc-stat-v{font-family:var(--font-display);font-stretch:var(--display-stretch);font-size:24px;font-weight:700;color:var(--text)}
.hc-stat-l{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--text3)}
.hc-stat-s{font-size:12px;color:var(--text2)}
.hc-stat-s b.up{color:var(--green,#34d399)}
.hc-stat-s b.down{color:var(--red)}
.hc-card{margin:16px 0;padding:16px}
.hc-st{display:inline-block;font-size:11px;font-weight:800;padding:3px 9px;border-radius:999px;
  color:var(--st);border:1px solid color-mix(in srgb,var(--st) 45%,transparent);
  background:color-mix(in srgb,var(--st) 12%,transparent);white-space:nowrap}
.hc-doclink{vertical-align:middle}
.hc-note{font-size:12px;color:var(--text3);max-width:260px}
.hc-cell{display:inline-block;min-width:38px;text-align:center;font-weight:800;font-size:12px;
  padding:3px 7px;border-radius:7px;color:var(--st);
  border:1px solid color-mix(in srgb,var(--st) 45%,transparent);
  background:color-mix(in srgb,var(--st) 12%,transparent)}
.hc-cell-none{color:var(--text3);text-align:center}
.hc-chks{display:flex;gap:14px;flex-wrap:wrap}
/* THE DASHBOARD IN TWO COLUMNS. The numbers read down the left, the
   map holds the right for its whole height — it used to be a 380 px
   band under the charts, which is enough to show that Belgium exists
   and not enough to see where the towns are. Below 1100 px they stack
   and the map takes a fixed height again. */
.hc-cols{display:flex;gap:16px;align-items:stretch;margin-bottom:4px}
.hc-col-data{flex:1 1 0;min-width:0}
.hc-col-map{flex:1.35 1 0;min-width:340px;display:flex}
.hc-col-map .hc-card{margin:16px 0;display:flex;flex-direction:column;flex:1}
.hc-col-map .hc-map-wrap{flex:1;min-height:420px}
/* One chart per row: the three-across grid squeezed to a third of a
   half-screen renders a donut the size of a coin. */
.hc-col-data .ch-grid{grid-template-columns:1fr}
/* The count of towns in talks beside the year bars: the number is a
   narrow thing, the bars want the rest. */
.hc-row-talks{display:flex;gap:12px;align-items:stretch;margin-bottom:14px}
.hc-row-talks .hc-stat{flex:0 0 190px;justify-content:center}
.hc-row-talks .ch-card{flex:1;min-width:0;margin:0}
@media (max-width:640px){
  .hc-row-talks{display:block}
  .hc-row-talks .hc-stat{margin-bottom:12px}
}
.hc-map-wrap{position:relative}
#hc-map-shell{height:100%;min-height:420px;border-radius:12px;overflow:hidden;margin-top:4px}
@media (max-width:1100px){
  .hc-cols{display:block}
  .hc-col-map .hc-map-wrap{min-height:0}
  #hc-map-shell{height:420px}
  .hc-col-data .ch-grid{grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr))}
}
/* Terrain / street / satellite behind a map icon: three buttons parked
   on the map permanently ate a corner of it. The dashboard map has no
   overlay group of its own, so the control positions itself there; on
   the prospection map it sits inside the top-right group beside the
   magnifier and lets that flex row place it. */
.hc-basemap-sw{position:absolute;right:10px;top:10px;z-index:6}

.hc-basemap-toggle{width:38px;height:38px;border:0;border-radius:10px;cursor:pointer;
  background:#fff;color:#333;box-shadow:0 1px 5px rgba(0,0,0,.35);
  display:flex;align-items:center;justify-content:center}
.hc-basemap-toggle svg{width:17px;height:17px}
.hc-basemap-toggle:hover{color:#000}
.hc-basemap-sw.open .hc-basemap-toggle{background:#0f3d2a;color:#fff}
.hc-basemap-menu{display:none;position:absolute;right:0;top:44px;min-width:150px;
  background:#fff;border-radius:10px;overflow:hidden;box-shadow:0 4px 14px rgba(0,0,0,.3)}
.hc-basemap-sw.open .hc-basemap-menu{display:block}
.hc-basemap-btn{display:flex;align-items:center;gap:8px;width:100%;border:0;background:none;
  cursor:pointer;font-family:inherit;font-size:12.5px;font-weight:700;color:#444;
  padding:9px 12px;text-align:left}
.hc-basemap-btn + .hc-basemap-btn{border-top:1px solid rgba(0,0,0,.08)}
.hc-basemap-btn:hover{background:rgba(0,0,0,.06);color:#000}
/* The tick marks the live one; the others keep its width so the labels
   do not shuffle sideways as the choice moves. */
.hc-basemap-btn svg{width:14px;height:14px;flex:none;opacity:0;stroke-width:3}
.hc-basemap-btn.on{color:#0f3d2a}
.hc-basemap-btn.on svg{opacity:1}
#hc-map-shell .map-fallback{height:100%;display:flex;align-items:center;justify-content:center;gap:8px;color:var(--text3)}
.hc-pin{display:block;width:16px;height:16px;border-radius:50%;background:var(--st);
  border:2.5px solid #fff;box-shadow:0 1px 6px rgba(0,0,0,.35);cursor:pointer}
/* THE SIGNED TOWNS ANNOUNCE THEMSELVES. A green dot on green terrain at
   country zoom is a speck you have to hunt for, and these are the towns
   the whole screen is about — so they wear their name and a pulsing
   ring. Never `position` on a marker element: Mapbox positions it
   absolutely and a same-specificity rule here would drift the pin off
   its town (a marker rule with `position` on it once drifted every pin off its town). */
.hc-pin-signed{width:19px;height:19px;
  box-shadow:0 1px 8px rgba(0,0,0,.45),0 0 0 4px color-mix(in srgb,var(--st) 30%,transparent)}
.hc-pin-signed::after{content:'';position:absolute;inset:-6px;border-radius:50%;
  border:2px solid var(--st);animation:hc-pin-pulse 1.9s ease-out infinite;pointer-events:none}
.hc-pin-tag{position:absolute;left:50%;bottom:calc(100% + 7px);transform:translateX(-50%);
  white-space:nowrap;font-size:10.5px;font-weight:800;letter-spacing:.02em;color:#fff;
  background:rgba(8,17,13,.86);border:1px solid color-mix(in srgb,var(--st) 55%,transparent);
  border-radius:999px;padding:2px 8px;pointer-events:none}
@media (prefers-reduced-motion:reduce){.hc-pin-signed::after{animation:none;opacity:.55}}

/* The hospital finder's offer: one row per door, the tick on the left,
   the distance under the name, the badges pushed to the right. */
.med-find-list{display:flex;flex-direction:column;gap:6px;max-height:52vh;overflow-y:auto}
.med-find-row{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--border);
  border-radius:9px;background:var(--bg2);cursor:pointer}
body.light .med-find-row{background:#fff}
.med-find-row:hover{border-color:var(--gold-border)}
.med-find-row.dup{opacity:.55;cursor:default}
.med-find-row .mf-body{flex:1;min-width:0}
.med-find-row .mf-body strong{display:block;font-size:13px;color:var(--text)}
.med-find-row .mf-body small{font-size:11px;color:var(--text3)}
.med-find-row .mf-badges{display:flex;gap:4px;flex-wrap:wrap;justify-content:flex-end}
.med-find-row .tag{font-size:9.5px}

/* ── comparing two years ──────────────────────────────────────── */
.hc-cmp-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:2px 0 12px}
.hc-cmp-pick{font-family:inherit;font-size:13px;font-weight:700;padding:6px 10px;
  border-radius:9px;border:1px solid var(--border2);background:var(--bg3);color:var(--text)}
.hc-cmp-vs{color:var(--text3);font-weight:800}
.hc-cmp-tot{margin-left:auto;font-size:13.5px;color:var(--text2)}
.hc-cmp-tot b{color:var(--text3);margin:0 2px}
.hc-cmp-tot em{font-style:normal;font-weight:800;margin-left:6px}
.hc-cmp-tot em.up,.hc-cmp .up{color:var(--primary,#f59e0b)}
.hc-cmp-tot em.down,.hc-cmp .down{color:#f87171}
body.light .hc-cmp-tot em.down,body.light .hc-cmp .down{color:#dc2626}
@media (max-width:600px){.hc-cmp-tot{margin-left:0;width:100%}}

/* The ring list carries a table, so its dialogue is allowed to be
   wider than the house 560 px — otherwise the municipality's own name
   is the first thing to scroll off the left edge. */
.modal.modal-wide{max-width:860px}


/* ── the prospection tab ─────────────────────────────────────── */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0,0,0,0);white-space:nowrap;border:0}

@keyframes hc-pin-pulse{
  0%{transform:scale(.55);opacity:.95}
  70%{transform:scale(1.7);opacity:0}
  100%{transform:scale(1.7);opacity:0}
}

.mf-hd-right{margin-left:auto;display:flex;align-items:center;gap:10px}
.mf-hd-right b{font-size:13px;color:var(--primary)}

/* The live-link count on the header's share button — the sidebar badge,
   shrunk to sit on an icon's shoulder. Fixed bright green on purpose:
   the header stays dark in BOTH themes, and the theme's own gold turns
   dark in light mode — a dark dot on a dark bar. */
#hdr-shares{position:relative}
/* The bell and the panel it drops. The wrapper is what the panel hangs
   off, so it — not the button — carries the positioning context. */
/* The two headings that split the entry-link list: the federations that
   have entered, and every other African one under them. */
/* ── HOW MANY CARS TO ORDER — see fleetDemandHtml() in js/fleet.js ──
   Above the fleet list, because the number it answers is the one
   somebody types into a hire company's form while looking at the cars
   they already have. */
.fl-demand{margin-bottom:14px}
.fl-demand .acc-stats{margin:10px 0 0}
.fl-pairs{display:flex;flex-direction:column;gap:6px;margin-top:8px}
.fl-pair{display:flex;align-items:center;gap:10px;padding:8px 11px;border-radius:9px;
  background:var(--bg3);font-size:13px;color:var(--text2)}
.fl-pair-n{flex-shrink:0;min-width:26px;text-align:center;font-weight:800;font-size:12px;
  padding:2px 7px;border-radius:999px;background:var(--bg4);color:var(--text);
  font-variant-numeric:tabular-nums}
.fl-pair-t{min-width:0;overflow-wrap:anywhere}
.fl-pair-t small{color:var(--text3)}
.fl-pair-t b{color:var(--text3);font-weight:700;margin:0 2px}
/* ── A CAR FOR EVERY FEDERATION — see fleetFedCarsHtml() in js/fleet.js ──
   One line per federation: who, how many riders, what the rule says,
   which car, and with whom. On a phone the line folds into two. */
.ffc-hd{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}
.ffc-hd h3{margin:0}
.ffc-acts{display:flex;gap:8px;flex-wrap:wrap}
.ffc .hint{margin:8px 0 0}
.ffc-list{display:flex;flex-direction:column;margin-top:14px;border-top:1px solid var(--border)}
.ffc-row{display:grid;grid-template-columns:minmax(150px,1.3fr) 76px 132px minmax(200px,1.6fr) minmax(150px,1.2fr);
  align-items:center;gap:12px;padding:8px 2px;border-bottom:1px solid var(--border)}
.ffc-fed{display:flex;align-items:center;gap:9px;min-width:0}
.ffc-fed strong{font-size:13.5px;overflow-wrap:anywhere}
.ffc-flag{width:22px;height:16px;flex-shrink:0}
.ffc-n{font-weight:800;font-size:15px;font-variant-numeric:tabular-nums;color:var(--text)}
.ffc-n small{font-weight:600;font-size:11px;color:var(--text3);margin-left:4px}
.ffc-rule{justify-self:start;font-size:11px;font-weight:700;padding:3px 9px;border-radius:999px;white-space:nowrap;border:1px solid}
.ffc-rule.is-own{color:var(--blue);background:var(--blue-bg);border-color:var(--blue-border)}
.ffc-rule.is-share{color:var(--purple,#a78bfa);background:color-mix(in srgb,var(--purple,#a78bfa) 12%,transparent);
  border-color:color-mix(in srgb,var(--purple,#a78bfa) 35%,transparent)}
.ffc-pick{width:100%;min-height:36px;font-size:12.5px}
.ffc-car{font-size:12.5px;color:var(--text2)}
.ffc-note{display:flex;flex-direction:column;gap:2px;font-size:12px;min-width:0}
.ffc-with{display:inline-flex;align-items:center;gap:5px;color:var(--text2);font-weight:600}
.ffc-with svg{width:13px;height:13px;flex-shrink:0}
.ffc-sug{color:var(--text3);font-style:italic}
.ffc-none{color:var(--text3)}
.ffc-warn{color:var(--amber,#d97706);font-weight:600}
.ffc-row:not(.has-car) .ffc-fed strong{color:var(--text2)}
.ffc-pickw{display:flex;align-items:center;gap:6px;min-width:0}
.ffc-pickw .ffc-pick{flex:1;min-width:0}
.ffc-status{display:flex;flex-wrap:wrap;gap:4px 10px;margin-top:2px}
.ffc-status span{display:inline-flex;align-items:center;gap:4px;font-weight:600}
.ffc-status svg{width:12px;height:12px;flex-shrink:0;color:var(--text3)}
.ffc-status .is-ok,.fl-contract.is-ok{color:var(--green)}
.ffc-status .is-no,.fl-contract.is-no{color:var(--amber,#d97706)}
.fl-contract{font-size:11.5px;font-weight:700}
/* The federation car form: its federations across the top. */
.fcm-fedpick{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:6px}
.fcm-fedchk .chk-t{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}
.fcm-fedchk .flag{width:20px;height:15px;margin-left:2px}
.fcm-fedchk small{color:var(--text3);font-weight:700}
.fcm-fedchk em{font-style:normal;font-size:11px;color:var(--amber,#d97706)}
.fcm-contract{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;
  padding:10px 12px;border-radius:10px;background:var(--bg3);margin-bottom:8px;font-size:13px;font-weight:600}
.fcm-contract > span{display:inline-flex;align-items:center;gap:6px}
.fcm-contract svg{width:15px;height:15px}
.fcm-contract .is-ok{color:var(--green)} .fcm-contract .is-no{color:var(--text2)}
/* The contract dialogue: two signature pads side by side, stacked on a phone. */
.fct-sum p{margin:4px 0 0;font-size:13px;color:var(--text2)}
.fct-miss{display:flex;align-items:center;gap:6px;color:var(--amber,#d97706);font-weight:600;font-size:12.5px;margin:8px 0 0}
.fct-miss svg{width:14px;height:14px;flex-shrink:0}
.fct-pads{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18px}
@media (max-width:700px){ .fct-pads{grid-template-columns:minmax(0,1fr)} }
.fsp-canvas{display:block;width:100%;background:#ffffff;border:1.5px dashed var(--border2,#94a3b8);border-radius:10px;
  touch-action:none;cursor:crosshair}
.fsp-acts{display:flex;justify-content:flex-end;margin-top:4px}

/* ── THE LOAN CONTRACT ON PAPER — fedContractHtml() in js/fleet.js ──
   A4 portrait, ink only (no theme variable reaches the sheet). */
.fct-doc{width:794px;min-height:1100px;background:#ffffff;color:#0f172a;padding:34px 44px 26px;
  font-family:inherit;font-size:11.5px;line-height:1.45;letter-spacing:normal;display:flex;flex-direction:column}
.fct-doc *{box-sizing:border-box}
.fct-hd{display:flex;align-items:center;gap:16px;padding-bottom:12px;border-bottom:3px solid #0f172a}
.fct-mark{height:36px;width:auto}
.fct-hd-t{flex:1;min-width:0}
.fct-hd-t h1{margin:0;font-size:22px;font-weight:800;color:#0f172a;line-height:1.15}
.fct-hd-t p{margin:3px 0 0;font-size:11px;font-weight:700;color:#475569;text-transform:uppercase;letter-spacing:.05em}
.fct-ev{height:48px;width:auto;max-width:150px;object-fit:contain}
.fct-ev.fct-wide{height:46px;max-width:260px}
.fct-parties{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin:16px 0 12px}
.fct-parties > div{border:1px solid #e2e8f0;border-radius:8px;padding:10px 12px;background:#f8fafc}
.fct-doc h2{margin:0 0 4px;font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:#64748b}
.fct-parties p{margin:0;color:#334155}
.fct-parties strong{font-size:14px;color:#0f172a}
.fct-cols{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.fct-tbl{width:100%;border-collapse:collapse}
.fct-tbl caption{text-align:left;font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:#64748b;padding-bottom:4px}
.fct-tbl th{width:38%;text-align:left;font-weight:600;color:#475569;padding:4px 8px 4px 0;border-bottom:1px solid #e2e8f0;vertical-align:top}
.fct-tbl td{padding:4px 0;border-bottom:1px solid #e2e8f0;font-weight:600;color:#0f172a}
.fct-when{margin-top:12px}
.fct-when th{width:18%}
.fct-blank{display:inline-block;width:150px;border-bottom:1px dotted #94a3b8;height:1em;vertical-align:bottom}
.fct-h{margin-top:16px!important}
.fct-terms{margin:0;padding-left:18px;color:#0f172a}
.fct-terms li{margin:0 0 5px}
.fct-note{margin:8px 0 0;color:#334155}
.fct-sigs{display:grid;grid-template-columns:1fr 1fr;gap:22px;margin-top:auto;padding-top:18px}
.fct-sig{border-top:2px solid #0f172a;padding-top:6px}
.fct-sig-t{font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:#64748b}
.fct-sig-area{height:80px;display:flex;align-items:center}
.fct-sigimg{height:70px;width:auto}
.fct-sig-l{display:flex;justify-content:space-between;gap:10px;color:#334155}
.fct-ft{display:flex;justify-content:space-between;gap:12px;margin-top:14px;padding-top:6px;border-top:1px solid #e2e8f0;font-size:9px;color:#64748b}
/* ── THE CAR INSPECTOR & THE DAMAGE REPORT — js/carcheck.js ──
   Thumb-sized on a phone at the car park: big tiles, big buttons, the
   camera one tap away. */
.ffc-cost{color:var(--red);font-weight:700}
/* The sticker numbers of a series, set by hand. */
.fnm-series{display:flex;gap:6px;flex-wrap:wrap}
.fnm-series small{opacity:.7;font-weight:600}
.fnm-tools{display:flex;justify-content:flex-end;margin-bottom:8px}
.fnm-list{display:flex;flex-direction:column;border-top:1px solid var(--border);max-height:55vh;overflow:auto}
.fnm-row{display:flex;align-items:center;gap:10px;padding:6px 2px;border-bottom:1px solid var(--border)}
.fnm-row.is-dup{background:color-mix(in srgb,var(--red) 8%,transparent)}
.fnm-row.is-dup .fnm-nr{border-color:var(--red)}
.fnm-row .fnm-nr{width:74px;max-width:74px;flex:0 0 74px;min-height:38px;text-align:center;font-weight:800;font-size:15px}
.fnm-t{flex:1;min-width:0}
.fnm-t strong{display:block;font-size:13.5px}
.fnm-t small{display:block;font-size:11.5px;color:var(--text2)}
.fnm-mv{display:flex;gap:4px}
/* The windscreen sticker in the forms and the table. */
.fl-stk-warn{margin:4px 0 0;font-size:12px;font-weight:700;color:var(--red)}
.fl-stk-nr input.is-clash{border-color:var(--red)}
.fl-series{white-space:nowrap}
.fl-dup{font-size:10.5px;font-weight:800;color:var(--red);text-transform:uppercase;letter-spacing:.04em}
/* Folded: title, buttons and figures; the hint and the list go. */
.ffc.is-folded > .hint,.ffc.is-folded .ffc-list{display:none}
.ffc-hd{gap:8px}
.ffc-hd h3{margin-right:auto}
.fl-acts{display:inline-flex;gap:4px}
.cci-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:10px;margin-top:12px}
.cci-tile{display:flex;align-items:center;gap:12px;width:100%;text-align:left;padding:12px 14px;border-radius:12px;
  border:1px solid var(--border);background:var(--bg2);color:var(--text);cursor:pointer;font:inherit;min-height:64px}
.cci-tile:hover{border-color:var(--gold-border);background:var(--bg3)}
.cci-nr{flex-shrink:0;min-width:46px;text-align:center;font-weight:800;font-size:13px;padding:6px 8px;border-radius:9px;background:var(--bg4)}
.cci-t{flex:1;min-width:0}
.cci-t strong{display:block;font-size:15px}
.cci-t small{display:block;font-size:12px;color:var(--text2);overflow-wrap:anywhere}
.cci-st{display:flex;flex-direction:column;gap:3px;flex-shrink:0}
.cci-st i{font-style:normal;font-size:10.5px;font-weight:700;padding:2px 7px;border-radius:99px;background:var(--bg4);color:var(--text3);text-align:center}
.cci-st i.is-ok{background:color-mix(in srgb,var(--green) 18%,transparent);color:var(--green)}
/* The home bar: at the top of the form and the thank-you, IN the page
   rather than stuck over it. Sticky, it slid over the form on a phone
   with the share banner above it (Janny, 8 Oct 2026: "it stays and
   comes over the rest — pin it at the top"). */
.cci-top{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  margin:0 0 12px;padding:0 0 10px;border-bottom:1px solid var(--border)}
.cci-top .cci-home{min-height:44px}
.cci-top-t{font-weight:800;font-size:15px}
.cci-thanks{text-align:center;padding:28px 18px}
.cci-thanks > svg{width:44px;height:44px;color:var(--green)}
.cci-thanks h3{justify-content:center;margin:8px 0 4px}
.cci-thanks p{color:var(--text2);margin:0 0 16px}
.cci-thanks-acts{display:flex;justify-content:center;gap:10px;flex-wrap:wrap}
.cci-thanks-acts .btn{min-height:48px;padding:0 22px}
.cci-progress{display:flex;gap:16px;flex-wrap:wrap;margin:0 0 10px;font-size:13px;color:var(--text2)}
.cci-progress b{font-size:18px;color:var(--text)}
.cci-tile.is-done{opacity:.72}
/* The return day board. */
.crb-stats{margin-bottom:10px}
.crb-lang{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:0 0 10px;font-size:12.5px;color:var(--text2)}
.crb-lang a.btn{margin-left:auto}
.crb-list{display:flex;flex-direction:column;border-top:1px solid var(--border)}
.crb-row{display:grid;grid-template-columns:minmax(150px,1.2fr) minmax(130px,1fr) 150px minmax(0,1.4fr);gap:10px;align-items:center;
  padding:8px 4px;border-bottom:1px solid var(--border)}
.crb-row.is-miss{background:color-mix(in srgb,var(--amber,#d97706) 8%,transparent)}
.crb-car strong{display:block;font-size:13.5px}
.crb-car small,.crb-who small{display:block;font-size:11.5px;color:var(--text2)}
.crb-who{font-size:13px}
.crb-st{justify-self:start;font-size:11.5px;font-weight:700;padding:3px 9px;border-radius:99px;background:var(--bg4);color:var(--text3)}
.crb-st.is-back{background:color-mix(in srgb,var(--green) 16%,transparent);color:var(--green)}
.crb-st.is-miss{background:color-mix(in srgb,var(--amber,#d97706) 18%,transparent);color:var(--amber,#d97706)}
.crb-acts{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end;align-items:center}
.crb-none{font-size:11.5px;color:var(--text3)}
@media (max-width:760px){ .crb-row{grid-template-columns:minmax(0,1fr) auto} .crb-who,.crb-acts{grid-column:1 / -1} .crb-acts{justify-content:flex-start} }
/* QR stickers on paper: 8 to an A4, ink only. */
.cqr-doc{width:794px;background:#fff;color:#0f172a;font-family:inherit}
.cqr-page{padding:30px 34px;min-height:1100px;box-sizing:border-box}
.cqr-hd{display:flex;align-items:center;gap:10px;font-size:10px;font-weight:700;color:#64748b;text-transform:uppercase;letter-spacing:.06em;margin-bottom:12px}
.cqr-hd img{height:22px;width:auto}
.cqr-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.cqr-tag{display:flex;align-items:center;gap:12px;height:236px;padding:14px 16px;border:1.5px dashed #94a3b8;border-radius:12px;box-sizing:border-box;break-inside:avoid}
.cqr-l{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
.cqr-nr{font-size:38px;font-weight:800;line-height:1;color:#0f172a}
.cqr-plate{font-size:18px;font-weight:800;letter-spacing:.04em;color:#0f172a}
.cqr-car{font-size:11.5px;color:#475569}
.cqr-who{font-size:13px;font-weight:700;color:#a84d08}
.cqr-hint{margin-top:auto;font-size:9.5px;color:#64748b;text-transform:uppercase;letter-spacing:.05em}
.cqr-qr{width:150px;height:150px;flex-shrink:0;image-rendering:pixelated}
.cqr-noqr{display:flex;align-items:center;justify-content:center;border:1px solid #cbd5e1;color:#94a3b8}
/* The damage per federation — on screen. */
.cdo-wrap{overflow-x:auto}
.cdo-tbl{width:100%;border-collapse:collapse;font-size:13px}
.cdo-tbl th{text-align:left;font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;color:var(--text3);
  padding:6px 8px;border-bottom:2px solid var(--border2,var(--border))}
.cdo-tbl td{padding:7px 8px;border-bottom:1px solid var(--border);vertical-align:top}
.cdo-tbl .r{text-align:right;white-space:nowrap}
.cdo-tbl small{display:block;font-size:11px;color:var(--text3)}
.cdo-tbl ul{margin:0;padding-left:16px}
.cdo-tbl tr.has-cost b{color:var(--red)}
.cdo-tbl tfoot td{font-weight:800;border-top:2px solid var(--border2,var(--border));border-bottom:0}
.cdo-fed{white-space:nowrap}
.cdo-fed .flag{width:20px;height:15px;margin-right:6px;vertical-align:-2px}
.cdo-yes{color:var(--green);font-weight:800}
.cdo-no{color:var(--text3)}
.cdo-wait{color:var(--amber,#d97706)!important;font-weight:700}
/* ...and on paper: ink only. */
.cdo-doc{width:794px;background:#fff;color:#0f172a;padding:34px 40px 26px;font-family:inherit;font-size:11px}
.cdo-doc .cdo-tbl{margin-top:16px;font-size:11px}
.cdo-doc .cdo-tbl th{color:#475569;border-bottom-color:#0f172a}
.cdo-doc .cdo-tbl td{border-bottom-color:#e2e8f0}
.cdo-doc .cdo-tbl small,.cdo-doc .cdo-no{color:#64748b}
.cdo-doc .cdo-yes{color:#15803d}
.cdo-doc .cdo-tbl tr.has-cost b{color:#b91c1c}
.cdo-doc .cdo-tbl tfoot td{border-top-color:#0f172a}
.cdo-ft{margin-top:14px;font-size:9.5px;color:#64748b}
.cci-form .cci-car{display:flex;flex-direction:column;gap:2px;margin-bottom:10px}
.cci-form .cci-car strong{font-size:17px}
.cci-form .cci-car span{font-size:13px;color:var(--text2)}
.cci-kind{display:flex;gap:8px;margin-bottom:12px;flex-wrap:wrap}
.cci-kind .btn{flex:1;min-height:44px}
.cci-pics{display:flex;flex-wrap:wrap;gap:8px;margin:6px 0}
.cci-pic{position:relative;width:84px;height:84px;border-radius:9px;overflow:hidden;background:var(--bg4)}
.cci-pic img{width:100%;height:100%;object-fit:cover;cursor:zoom-in}
.cci-x{position:absolute;top:3px;right:3px;width:24px;height:24px;border-radius:50%;border:0;background:rgba(0,0,0,.65);color:#fff;font-size:16px;line-height:1;cursor:pointer}
.cci-shoot{cursor:pointer;min-height:44px}
.cci-dmg{border:1px solid var(--border);border-radius:10px;padding:10px;margin-bottom:8px;display:flex;flex-direction:column;gap:6px;background:var(--bg3)}
.cci-dmg-hd{display:flex;gap:8px}
.cci-dmg-hd select{flex:1}
.cci-send{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:14px}
.cci-send .btn{min-height:48px;padding:0 22px}
.cci-status{font-size:13px;color:var(--text2)}
.cci-prevs{margin:10px 0}
.cci-prev{font-size:13px;color:var(--text2);margin-top:6px}
.cci-prev ul{margin:4px 0 0;padding-left:18px}
.cci-prev p{margin:2px 0 0}
.cci-contract{margin-top:14px;padding:12px;border:1px solid var(--gold-border);border-radius:12px;background:var(--gold-bg)}
.cci-parties{margin:0 0 6px;font-size:13.5px}
.cci-terms .fct-terms{margin:0 0 10px;padding-left:18px;font-size:12.5px;color:var(--text);line-height:1.45}
.cci-terms .fct-terms li{margin-bottom:4px}
.cdm-hd{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:12px}
.cdm-hd strong{display:block;font-size:15px}
.cdm-hd span{display:block;font-size:12.5px;color:var(--text2)}
.cdm-total{text-align:right;padding:8px 12px;border-radius:10px;background:var(--bg3)}
.cdm-total span{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--text3)}
.cdm-total b{display:block;font-size:20px}
.cdm-total.has b{color:var(--red)}
.cdm-total small{display:block;font-size:11.5px;color:var(--text2)}
.cdm-cols{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}
@media (max-width:760px){ .cdm-cols{grid-template-columns:minmax(0,1fr)} }
.cdm-check{position:relative;border:1px solid var(--border);border-radius:10px;padding:10px 46px 10px 10px;margin-bottom:10px}
.cdm-del{position:absolute;top:6px;right:6px}
.cdm-add{display:flex;gap:8px;flex-wrap:wrap;justify-content:space-between}
.cdm-meta{font-size:12px;color:var(--text2);margin-bottom:6px}
.cdm-pics{display:flex;flex-wrap:wrap;gap:6px;margin:4px 0}
.cdm-pic{padding:0;border:0;background:none;cursor:zoom-in;width:72px;height:72px;border-radius:8px;overflow:hidden}
.cdm-pic img{width:100%;height:100%;object-fit:cover}
.cdm-dmgs{list-style:none;margin:6px 0 0;padding:0;display:flex;flex-direction:column;gap:8px}
.cdm-dmgs li{padding:8px;border-radius:8px;background:var(--bg3)}
.cdm-dmg-t{font-size:13px}
.cdm-assess{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:6px}
.cdm-cost{width:120px;min-height:36px}
.cdm-note{font-size:12.5px;color:var(--text2);margin:6px 0 0;font-style:italic}
.cdm-add{margin-top:6px}
.fl-choices{display:grid;gap:10px}
.fl-choice{display:flex;align-items:center;gap:14px;width:100%;text-align:left;padding:14px 16px;border-radius:12px;
  border:1px solid var(--border2,var(--border));background:var(--bg3);color:var(--text);cursor:pointer;font:inherit}
.fl-choice:hover{border-color:var(--gold-border);background:var(--bg4)}
.fl-choice-i{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:10px;
  background:var(--gold-bg);color:var(--gold2);flex-shrink:0}
.fl-choice-i svg{width:20px;height:20px}
.fl-choice-t strong{display:block;font-size:14.5px}
.fl-choice-t small{display:block;font-size:12.5px;color:var(--text2);margin-top:2px}
.ffc-pickw .icon-btn.is-signed{color:var(--green);border-color:color-mix(in srgb,var(--green) 40%,transparent)}
.cr-grid.fcm-2{grid-template-columns:repeat(2,minmax(0,1fr))}
@media (max-width:520px){ .cr-grid.fcm-2{grid-template-columns:minmax(0,1fr)} }
.fcm-feds{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;font-weight:700;font-size:14px}
.fcm-fed{display:inline-flex;align-items:center;gap:6px}
.fcm-feds b{color:var(--text3)}
.ffc-clash{display:inline-flex;align-items:center;gap:5px;color:var(--red);font-weight:700}
.ffc-clash svg{width:13px;height:13px;flex-shrink:0}
/* One country in two cars — see fleetFedDupes() in js/fleet.js. */
.ffc-dupe{display:flex;align-items:center;flex-wrap:wrap;gap:8px 10px;margin:0 0 12px;padding:9px 12px;
  border:1px solid var(--amber,#d97706);border-radius:10px;background:rgba(217,119,6,.08);
  color:var(--text);font-size:13px;font-weight:600}
.ffc-dupe svg{width:15px;height:15px;flex-shrink:0;color:var(--amber,#d97706)}
.ffc-dupe span{flex:1;min-width:200px}
/* The "never in one car together" list in the rule dialogue. */
.ffr-avoid{display:flex;flex-direction:column;gap:6px;margin-bottom:10px}
.ffr-pair{display:flex;align-items:center;gap:8px;padding:6px 6px 6px 10px;border-radius:9px;background:var(--bg3);font-size:13px;font-weight:600}
.ffr-pair b{color:var(--red);margin:0 4px}
.ffr-pair .icon-btn{margin-left:auto}
.ffr-empty{margin:0}
.ffr-add{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr) auto;gap:8px;align-items:center}
.ffr-add > span{color:var(--text3);font-weight:700}
@media (max-width:560px){ .ffr-add{grid-template-columns:minmax(0,1fr) auto minmax(0,1fr)} .ffr-add .btn{grid-column:1 / -1} }
@media (max-width:900px){
  .ffc-row{grid-template-columns:minmax(0,1fr) auto auto;gap:6px 10px}
  .ffc-pickw{grid-column:1 / -1}
  .ffc-note{grid-column:1 / -1}
}
/* Under a car in the vehicle list: the federations that drive it. */
.fl-feds{display:inline-flex;align-items:center;flex-wrap:wrap;gap:4px 6px;margin-top:3px;font-size:12px;color:var(--text2);font-weight:600}
.fl-feds .flag{width:18px;height:13px}
.fl-feds b{color:var(--text3);font-weight:700}
.fl-rate{display:flex;align-items:center;justify-content:space-between;gap:12px;
  flex-wrap:wrap;margin-top:12px;padding-top:12px;border-top:1px solid var(--border);
  font-size:12.5px;color:var(--text3)}
/* The two figures under the sharing tick on the entry form. */
.fed-price{font-size:13.5px;color:var(--text2);margin-top:8px}
.fed-price strong{color:var(--gold2,#d97706);font-size:15px}
body.light .fed-price strong{color:var(--gold)}
.fed-price-was{text-decoration:line-through;color:var(--text3);margin-left:6px}

/* The age picker beside a podium place, shown only for a race run for
   more than one category — see openHonourModal() in js/honours.js. */
.hon-age{display:contents}
.hon-age-sel{min-width:150px}
@media (max-width:640px){ .hon-age-sel{min-width:0;width:100%} }

/* The flag standing in for a jersey nobody has uploaded — same box as
   the shirt so a mixed list does not stagger. */
.fed-flag{width:26px;height:20px;flex-shrink:0;border-radius:3px;object-fit:cover;
  border:1px solid var(--border)}

/* The rule above the one item in a ⋮ drawer that takes something away. */
.sched-menu-sep{height:1px;margin:5px 4px;background:var(--border)}
.sched-menu-list button.danger,.sched-menu-list button.danger svg{color:#ef4444}
.sched-menu-list button.danger:hover{background:color-mix(in srgb,#ef4444 12%,transparent)}

/* The press block on the request form, and what it produces on the desk. */
.areq-press h3 svg{width:17px;height:17px}
.areq-card-prev{display:flex;align-items:center;justify-content:center;
  width:120px;height:76px;flex-shrink:0;border-radius:9px;overflow:hidden;
  border:1px solid var(--border);background:var(--bg3);color:var(--text3)}
.areq-card-prev img{width:100%;height:100%;object-fit:cover;display:block}
.areq-card-prev svg{width:24px;height:24px}
.areq-media svg{width:13px;height:13px;vertical-align:-2px}
/* The organiser's line, told apart from the applicant's at a glance. */
.areq-desknote{border-left:3px solid var(--gold,#f59e0b);padding-left:9px}
.areq-desknote svg{width:12px;height:12px;vertical-align:-1px;color:var(--gold2,#d97706)}
.areq-cardimg{display:block;max-width:100%;border-radius:10px;border:1px solid var(--border)}

/* ── THE WAY BACK IN — see fedKeptBandHtml() in js/fedentry.js ──
   The band at the top of an entry form that has already been used once,
   on the device that used it. Amber while it can still be changed, grey
   and shut once the deadline has passed. */
.fed-kept{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:14px;
  border-color:var(--gold-border)}
.fed-kept.shut{border-color:var(--border);opacity:.85}
.fed-kept-ico{display:flex;flex-shrink:0;color:var(--gold2,#d97706)}
.fed-kept.shut .fed-kept-ico{color:var(--text3)}
.fed-kept-ico svg{width:20px;height:20px}
.fed-kept-t{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.fed-kept-t strong{font-size:14px;color:var(--text)}
.fed-kept-t small{font-size:12px;color:var(--text2)}
.fed-kept-ref{font-family:ui-monospace,Menlo,Consolas,monospace;letter-spacing:.04em;
  color:var(--text3)!important}
.fed-kept-shut{flex-basis:100%;font-size:12.5px;color:var(--text3)}
/* A submission a newer one has overtaken: still readable, no longer a job. */
.areq-row.superseded{opacity:.6}
.areq-row.superseded .areq-acts .btn.primary{display:none}

/* The one card in Settings that cannot be undone, marked as such. */
.danger-card{border-color:rgba(239,68,68,.45)}
.danger-card h3{color:#ef4444}

.fedlink-hd{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;
  color:var(--text3);margin:12px 0 4px;padding:0 2px}
.fedlink-list > .fedlink-hd:first-child{margin-top:4px}

.hdr-alerts{position:relative;display:flex}
.hdr-alerts .icon-btn{position:relative}
.hdr-pop{position:absolute;top:calc(100% + 8px);right:0;z-index:40;
  width:320px;max-width:calc(100vw - 24px);display:flex;flex-direction:column;gap:4px;
  background:var(--bg2);border:1px solid var(--border);border-radius:12px;
  box-shadow:var(--shadow-md);padding:8px;text-align:left}
body.light .hdr-pop{background:#fff}
.hdr-pop-hd{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;
  color:var(--text3);padding:4px 8px 2px}

/* The sound switch beside that heading, and the badge that says the
   pile it counts is not paperwork. Shadow-only pulse: the badge sits in
   a flex row and animating transform would walk it out of the bar. */
.hdr-pop-hd{display:flex;align-items:center;justify-content:space-between;gap:10px}
.hdr-pop-snd{border:0;background:none;cursor:pointer;font-size:14px;line-height:1;
  padding:2px 4px;border-radius:6px;opacity:.85}
.hdr-pop-snd:hover{background:rgba(255,255,255,.1);opacity:1}
.hdr-badge.urgent{background:#dc2626;color:#fff;animation:hdr-urgent 1.9s ease-in-out infinite}
@keyframes hdr-urgent{
  0%,100%{ box-shadow:0 0 0 0 rgba(220,38,38,.6) }
  50%    { box-shadow:0 0 0 7px rgba(220,38,38,0) }
}
.hdr-pop-row{display:flex;align-items:center;gap:10px;width:100%;padding:10px;border-radius:9px;
  border:none;background:none;font-family:inherit;text-align:left;cursor:pointer;color:var(--text2)}
.hdr-pop-row:hover{background:var(--bg3);color:var(--text)}
.hdr-pop-row > svg{width:17px;height:17px;flex-shrink:0;color:var(--text3)}
.hdr-pop-row.has > svg{color:var(--gold2)}
body.light .hdr-pop-row.has > svg{color:var(--gold)}
.hdr-pop-t{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.hdr-pop-t strong{font-size:13px;font-weight:700;color:var(--text);letter-spacing:-.1px}
.hdr-pop-t small{font-size:11px;color:var(--text3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hdr-pop-n{flex-shrink:0;min-width:22px;text-align:center;font-size:11px;font-weight:800;
  padding:2px 7px;border-radius:20px;background:var(--gold);color:#0b1120;
  font-variant-numeric:tabular-nums}
.hdr-pop-row:not(.has) .hdr-pop-n{background:var(--bg4);color:var(--text3)}
/* On a phone the bell is not the rightmost thing in the bar, so a panel
   hung off its own right edge starts 79 px off the left of the screen.
   Letting the wrapper go static hands the anchoring to #header, which is
   already positioned — the panel then spans the bar and cannot escape it
   whatever else moves in beside it. */
/* ── THE GEAR'S DRAWER ─────────────────────────────────────────
   Same panel as the bell's, hung off the same bar. On a phone the two
   controls it holds are removed from the bar itself — that is the whole
   point of the drawer — but ONLY once the gear is actually there to hold
   them (#header.has-more), or a narrow window with no gear would have no
   light switch at all.

   THIS BLOCK HAS TO STAND ABOVE THE PHONE MEDIA QUERY BELOW. Both say
   `position` on .hdr-more at the same specificity, so whichever is
   written last wins — with it underneath, the panel kept hanging off a
   44 px button at the end of the bar and ran off the right of the
   screen exactly the way the bell's used to. */
.hdr-more{position:relative;display:flex}
.hdr-more .icon-btn{position:relative}
.hdr-more-pop{width:280px}
.hdr-more-pop .hdr-pop-row{padding:11px 10px}

@media (max-width:560px){
  .hdr-alerts,.hdr-more{position:static}
  .hdr-pop{left:12px;right:12px;width:auto;max-width:none}
  #header.has-more #hdr-shares,
  #header.has-more #theme-btn{display:none}
}
.hdr-badge{position:absolute;top:-4px;right:-6px;font-size:9px;font-weight:800;
  padding:1px 5px;border-radius:20px;background:#59ef83;color:#0b2b26;line-height:1.5;
  border:1.5px solid #0b2b26;pointer-events:none}

.proj-card{position:relative;overflow:hidden;text-align:left;font-family:inherit;cursor:pointer;
  background-color:var(--bg2);background-image:linear-gradient(160deg,rgba(255,255,255,.05),rgba(255,255,255,.012) 60%);
  border:1px solid var(--border);border-radius:var(--radius);padding:20px;
  transition:transform .25s,box-shadow .25s,border-color .25s;box-shadow:var(--shadow);
  display:flex;flex-direction:column;gap:7px;min-height:44px}
body.light .proj-card{background:#fff}
.proj-card:hover{border-color:var(--gold-border);transform:translateY(-4px);box-shadow:var(--shadow-md),var(--glow-gold)}
.proj-card.is-active{border-color:var(--gold);box-shadow:var(--shadow-md),var(--glow-gold)}
.proj-card.is-active::before{content:'';position:absolute;top:0;left:0;right:0;height:3px;
  background:linear-gradient(90deg,var(--gold),var(--gold2))}
.pc-year{font-family:'Space Grotesk','Inter',sans-serif;font-size:34px;font-weight:700;line-height:1;
  letter-spacing:-1.2px;color:var(--gold2);font-variant-numeric:tabular-nums}
body.light .pc-year{color:var(--gold)}
.proj-card h3{font-size:15px;font-weight:700;color:var(--text);letter-spacing:-.2px;line-height:1.35}
.pc-meta{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--text2)}
.pc-meta svg{width:13px;height:13px;flex-shrink:0;color:var(--text3)}
.pc-stats{display:flex;gap:8px;margin-top:8px;padding-top:12px;border-top:1px solid var(--border)}
.pc-stat{flex:1;display:flex;flex-direction:column;gap:1px;font-size:10px;font-weight:700;
  text-transform:uppercase;letter-spacing:.06em;color:var(--text3)}
.pc-stat b{font-family:'Space Grotesk','Inter',sans-serif;font-size:17px;font-weight:700;
  color:var(--text);letter-spacing:-.3px;font-variant-numeric:tabular-nums}
/* The ⋮ in the card's corner, and the little menu it unfolds. */
.pc-actions{position:absolute;top:12px;right:12px}
.pc-actions .icon-btn{min-width:34px;min-height:34px;border-color:var(--border);background:var(--bg3);color:var(--text2)}
.pc-actions .icon-btn:hover{border-color:var(--gold-border);color:var(--gold2);background:var(--bg4)}
body.light .pc-actions .icon-btn:hover{color:var(--gold)}
.pc-actions .icon-btn svg{width:16px;height:16px}
.pc-menu{position:absolute;top:38px;right:0;z-index:30;min-width:220px;display:flex;flex-direction:column;
  background:var(--bg2);border:1px solid var(--border);border-radius:10px;box-shadow:var(--shadow-md);
  padding:5px;text-align:left}
body.light .pc-menu{background:#fff}
.pc-menu-item{display:flex;align-items:center;gap:9px;padding:9px 11px;border-radius:7px;
  font-size:13px;font-weight:600;color:var(--text2);cursor:pointer;white-space:nowrap}
.pc-menu-item:hover{background:var(--bg3);color:var(--text)}
.pc-menu-item svg{width:15px;height:15px;flex-shrink:0}
.pc-menu-item.danger:hover{color:var(--red)}

.new-proj{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;
  min-height:200px;padding:22px;border:2px dashed var(--border2);border-radius:var(--radius);
  background:none;cursor:pointer;font-family:inherit;color:var(--text2);text-align:center;
  transition:border-color .2s,background .2s,color .2s}
.new-proj:hover{border-color:var(--gold);background:var(--gold-bg);color:var(--gold2)}
body.light .new-proj:hover{color:var(--gold)}
.np-plus{width:46px;height:46px;border-radius:50%;border:1px solid currentColor;display:flex;
  align-items:center;justify-content:center}
.np-plus svg{width:22px;height:22px}
.np-t{font-size:14px;font-weight:700;color:var(--text)}
.new-proj:hover .np-t{color:inherit}
.np-d{font-size:12px;line-height:1.4;max-width:200px}

/* Edition name trailing a page heading */
.hd-ev{font-family:'Inter',sans-serif;font-size:13px;font-weight:600;color:var(--text3);
  letter-spacing:0;white-space:nowrap}

/* ── SHARE PRESETS ─────────────────────────────────────────── */
.preset-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(210px,100%),1fr));gap:11px}
.preset{display:flex;flex-direction:column;align-items:flex-start;gap:6px;text-align:left;
  padding:15px 16px;border-radius:11px;border:1px solid var(--border);background:var(--bg3);
  cursor:pointer;font-family:inherit;transition:border-color .18s,transform .18s,background .18s;min-height:44px}
.preset:hover{border-color:var(--gold-border);background:var(--bg4);transform:translateY(-2px)}
.preset:disabled{opacity:.5;cursor:wait}
.preset-ico{width:34px;height:34px;border-radius:9px;background:var(--gold-bg);color:var(--gold2);
  display:flex;align-items:center;justify-content:center;margin-bottom:2px}
body.light .preset-ico{color:var(--gold)}
.preset-ico svg{width:17px;height:17px}
/* STRETCHED, NOT SHRINK-TO-FIT. The card is a column with
   align-items:flex-start, which sizes every child to its own content —
   and a scope chip reading "INSCHRIJVINGSFORMULIER FEDERATIES" has no
   space in it to break at, so the row grew wider than the card and the
   text ran out over the border into the card beside it. Stretched to the
   card's width, the chips wrap inside it and the sentences with them. */
.preset-t,.preset-d,.preset-scopes{align-self:stretch;min-width:0;max-width:100%}
.preset-t{font-size:14px;font-weight:700;color:var(--text);overflow-wrap:anywhere}
.preset-d{font-size:12px;color:var(--text2);line-height:1.4;overflow-wrap:anywhere}
.preset-scopes{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
.preset-scopes > *{max-width:100%;overflow-wrap:anywhere;white-space:normal}

/* ── SCOPE PICKER (share builder) ──────────────────────────── */
.scope-grid{display:grid;gap:8px}
.scope{display:flex;align-items:flex-start;gap:11px;padding:13px 14px;border-radius:10px;cursor:pointer;
  border:1px solid var(--border2);background:var(--bg3);transition:all .16s;min-height:44px}
.scope.on{background:var(--gold-bg);border-color:var(--gold-border)}
.scope input{width:18px;height:18px;accent-color:var(--gold);flex-shrink:0;margin-top:2px}
.scope-ico{width:32px;height:32px;border-radius:8px;background:var(--bg4);display:flex;align-items:center;
  justify-content:center;color:var(--text2);flex-shrink:0}
.scope.on .scope-ico{background:rgba(245,158,11,.2);color:var(--gold2)}
body.light .scope.on .scope-ico{color:var(--gold)}
.scope-ico svg{width:16px;height:16px}
.scope-b{display:flex;flex-direction:column;gap:2px;min-width:0}
.scope-b strong{font-size:14px;font-weight:700;color:var(--text)}
.scope-b small{font-size:12px;color:var(--text2);line-height:1.4}

/* ── SHARE CARDS ───────────────────────────────────────────── */
.share-list{display:grid;gap:12px}
.share-card{background:var(--bg2);border:1px solid var(--border);border-radius:var(--radius);
  padding:16px 18px;box-shadow:var(--shadow);transition:border-color .2s}
.share-card:hover{border-color:var(--border2)}
.share-card.off{opacity:.6}
/* A protected link: a gold edge, a small shield beside the state, the
   shield button lit; the buttons that stand down are greyed. */
.share-card.pinned{border-color:var(--gold-border,rgba(180,83,9,.32))}
.sc-pin{display:inline-flex;align-items:center;gap:4px;margin-left:6px;padding:1px 7px;border-radius:999px;
  font-size:10.5px;font-weight:800;letter-spacing:.03em;text-transform:uppercase;
  color:var(--gold2,#b45309);background:var(--gold-bg,rgba(180,83,9,.10));border:1px solid var(--gold-border,rgba(180,83,9,.32))}
.sc-pin svg{width:11px;height:11px}
.sc-actions .icon-btn.pinned{color:var(--gold2,#b45309);background:var(--gold-bg,rgba(180,83,9,.10));border-color:var(--gold-border,rgba(180,83,9,.32))}
.sc-actions .icon-btn[disabled]{opacity:.35;cursor:not-allowed}
.sc-top{display:flex;align-items:flex-start;gap:11px;flex-wrap:wrap}
.sc-state{width:9px;height:9px;border-radius:50%;flex-shrink:0;margin-top:7px}
.sc-state.on{background:var(--green);color:var(--green);animation:livePulse 2.6s ease-out infinite}
.sc-state.off{background:var(--text3)}
.sc-title{flex:1;min-width:180px}
.sc-title h4{font-size:15px;font-weight:700;color:var(--text);letter-spacing:-.2px}
.sc-sub{font-size:12px;color:var(--text2);margin-top:2px}
.sc-actions{display:flex;gap:5px;flex-wrap:wrap}
.sc-actions .icon-btn{min-width:38px;min-height:38px;border-color:var(--border);background:var(--bg3);color:var(--text2)}
.sc-actions .icon-btn:hover{border-color:var(--gold-border);color:var(--gold2);background:var(--bg4)}
body.light .sc-actions .icon-btn:hover{color:var(--gold)}
.sc-actions .icon-btn svg{width:16px;height:16px}
.sc-scopes{display:flex;flex-wrap:wrap;gap:5px;margin-top:12px}
.sc-scopes .tag{padding:4px 9px}
.sc-scopes .tag svg{width:11px;height:11px}
.sc-url{margin-top:11px;padding:9px 12px;border-radius:8px;background:var(--bg3);border:1px solid var(--border);
  overflow-x:auto;scrollbar-width:thin}
.sc-url code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;color:var(--text2);white-space:nowrap}
.sc-note{margin-top:9px;font-size:12px;color:var(--text3);font-style:italic}

@media (max-width:520px){
  .auth-card{padding:26px 20px}
  .preset-grid{grid-template-columns:1fr}
  .proj-grid{grid-template-columns:1fr}
  .proj-card{padding:16px}
  .portal-hero h2{font-size:21px}
  .sc-actions{width:100%}
}

/* ═══════════════════════════════════════════════════════════
   LIVE RACE PROGRESS
   A rail from start to finish. The filled part is where the bunch
   is, the translucent band is the spread between the leader and the
   last rider, and the two ticks are those two projections. The rider
   is nudged half its own width so it sits ON the position, not after it.
   ═══════════════════════════════════════════════════════════ */
.lp-card{background:var(--bg2);border:1px solid var(--border);border-radius:var(--radius);
  padding:18px 20px;margin-top:14px;box-shadow:var(--shadow)}
.lp-hd{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:16px}
.lp-hd h3{font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:var(--text)}
.lp-race{font-size:13px;color:var(--text2);margin-top:3px}
.lp-none{font-size:13px;color:var(--text2)}

.lp-track{display:flex;align-items:center;gap:12px}
.lp-end{display:flex;flex-direction:column;align-items:center;gap:2px;flex-shrink:0;
  font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--text3)}
.lp-end svg{width:15px;height:15px}
.lp-start svg{color:var(--green)}
.lp-finish svg{color:var(--red)}

.lp-rail{position:relative;flex:1;min-width:0;height:12px;border-radius:99px;
  background:var(--bg4);border:1px solid var(--border);overflow:visible}
.lp-band{position:absolute;top:0;bottom:0;background:var(--gold-bg);border-radius:99px}
.lp-fill{position:absolute;top:0;bottom:0;left:0;border-radius:99px;
  background:linear-gradient(90deg,var(--gold),var(--gold2));transition:width .9s linear}
.lp-tick{position:absolute;top:-4px;width:2px;height:20px;border-radius:2px;transition:left .9s linear}
.lp-tick-fast{background:var(--green)}
.lp-tick-slow{background:var(--red)}
.lp-rider{position:absolute;top:50%;transform:translate(-50%,-50%) scaleX(-1);display:inline-block;font-size:22px;line-height:1;
  transition:left .9s linear;filter:drop-shadow(0 2px 4px rgba(0,0,0,.45));pointer-events:none}

.lp-stats{display:flex;flex-wrap:wrap;gap:22px;margin-top:16px;padding-top:14px;border-top:1px solid var(--border)}
.lp-stat dt{font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--text3)}
.lp-stat dd{font-size:17px;font-weight:700;color:var(--text);margin-top:2px;
  font-variant-numeric:tabular-nums;font-family:'Space Grotesk','Inter',sans-serif}
.lp-stat dd.c-fast{color:var(--green)}
.lp-stat dd.c-slow{color:var(--red)}
.lp-note{font-size:11.5px;color:var(--gold2);margin-top:10px;font-weight:600}
body.light .lp-note{color:var(--gold)}

.lp-admin{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;
  margin-top:14px;padding-top:14px;border-top:1px dashed var(--border2)}
.lp-admin-lbl{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:var(--text3)}
.lp-admin-btns{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.lp-pace-val{min-width:52px;text-align:center;font-size:14px;font-weight:800;color:var(--gold2);
  font-variant-numeric:tabular-nums}
body.light .lp-pace-val{color:var(--gold)}

/* On the dark press-room monitor the card must not turn into a light slab. */
.lt-progress-slot .lp-card{background:rgba(255,255,255,.03);border-color:rgba(255,255,255,.08);
  box-shadow:none;margin-top:16px}
.lt-progress-slot .lp-rail{background:rgba(255,255,255,.07);border-color:rgba(255,255,255,.12)}
body.light .lt-progress-slot .lp-card{background:var(--bg3);border-color:var(--border)}
body.light .lt-progress-slot .lp-rail{background:var(--bg4);border-color:var(--border)}

@media (max-width:640px){
  .lp-stats{gap:14px}
  .lp-stat dd{font-size:15px}
  .lp-end span:last-child{display:none}
}

.fed-note{font-size:11.5px;color:var(--text3);margin-top:10px;line-height:1.5}

/* ═══════════════════════════════════════════════════════════
   LIVE DEVICE TRACKING
   ═══════════════════════════════════════════════════════════ */
.tk-card{margin-top:14px}
.tk-hd{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;flex-wrap:wrap}
.tk-hd h3{margin-bottom:2px}
.tk-status{margin-top:12px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.tk-on{display:inline-flex;align-items:center;gap:7px;font-weight:800;color:var(--green)}
.tk-off{color:var(--text3);font-weight:700}
.tk-wait{color:var(--gold2);font-weight:700}
body.light .tk-wait{color:var(--gold)}
.tk-bad{color:var(--red);font-weight:700}
.tk-meta{color:var(--text2);font-variant-numeric:tabular-nums}
.tk-others{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.tk-chip{font-size:11px;font-weight:700;padding:3px 9px;border-radius:20px;
  background:var(--bg4);border:1px solid var(--border);color:var(--text2)}
.tk-note{font-size:11.5px;color:var(--text3);margin-top:10px;line-height:1.5}
.lp-note.lp-gps{color:var(--green)}

/* ── THE MOVING MARKER, AND WHERE IT ACTUALLY IS ───────────────
   A LABELLED MARKER MUST NOT BE A BOX. Mapbox places a marker element by
   centring it on the coordinate — translate(-50%, -50%) — so a flex row
   of "dot + name" put the MIDDLE OF THE WHOLE ROW on the position and
   the dot itself half a label to the left of it. That error is a fixed
   number of PIXELS, so it looks harmless zoomed in and lands a village
   away zoomed out, which is exactly how it was reported: "zoom in and it
   goes to the right place".

   So the element itself is 0 × 0 — centring nothing on the coordinate is
   the coordinate — and the dot and the label are hung off it absolutely.
   The dot is pulled back by exactly half its own size, the label sits
   beside it, and the name may now be as long as it likes without ever
   moving the position it belongs to. */
.tk-marker{position:relative;width:0;height:0;cursor:pointer}
.tk-dot{position:absolute;left:-10px;top:-10px;width:21px;height:21px;box-sizing:border-box;
  border-radius:50%;background:#22c55e;border:3px solid #fff;
  box-shadow:0 0 0 0 rgba(34,197,94,.7);animation:tk-pulse 1.8s infinite}
.tk-label{position:absolute;left:16px;top:-10px;font-size:11px;font-weight:700;color:#fff;
  background:rgba(8,12,24,.86);border:1px solid rgba(148,163,184,.3);border-radius:10px;
  padding:2px 7px;white-space:nowrap}
@keyframes tk-pulse{
  0%{box-shadow:0 0 0 0 rgba(34,197,94,.7)}
  70%{box-shadow:0 0 0 12px rgba(34,197,94,0)}
  100%{box-shadow:0 0 0 0 rgba(34,197,94,0)}
}

/* ═══════════════════════════════════════════════════════════
   VIP / TV BROADCAST MODE
   Always dark: it goes on a television in a dim room, and the
   light theme would glare. Sizes are in vw/vh so it scales from a
   laptop preview to a 65" screen without a media query per size.
   ═══════════════════════════════════════════════════════════ */
#bc-screen{position:fixed;inset:0;z-index:2000;background:#05080f;color:#f8fafc}
#bc-screen[hidden]{display:none}
body.bc-open{overflow:hidden}
body.bc-idle #bc-screen{cursor:none}
body.bc-idle .bc-exit{opacity:0}

/* The stage is the television. Every block is placed on it as a percentage
   of that surface — arranged on a laptop, cast onto whatever is on the wall,
   and it lands in the same place. Gaps come from each block's own inset, so
   two touching blocks still read as two. */
.bc-stage{position:relative;width:100%;height:100%;padding:clamp(6px,.7vw,12px)}
.bc-block{position:absolute;padding:clamp(3px,.4vw,7px);display:flex;min-width:0;min-height:0}
.bc-block > *{flex:1;min-width:0;min-height:0}

.bc-hd{display:flex;align-items:center;gap:clamp(10px,1.4vw,20px)}
.bc-logo{height:clamp(34px,3.6vw,58px);background:#fff;border-radius:10px;padding:4px 8px}
.bc-titles{min-width:0;flex:1}
.bc-titles h1{font-family:'Space Grotesk','Inter',sans-serif;font-size:clamp(16px,2vw,34px);
  font-weight:800;letter-spacing:.4px;line-height:1.1;overflow-wrap:anywhere}
.bc-titles p{font-size:clamp(10px,.95vw,16px);color:#f59e0b;font-weight:700;
  text-transform:uppercase;letter-spacing:.06em;margin-top:2px}
.bc-clock{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:clamp(22px,3vw,52px);
  font-weight:800;color:#38bdf8;letter-spacing:1px;font-variant-numeric:tabular-nums;flex-shrink:0}
/* On the stage, not in the header: the header is one of the blocks that can
   be switched off, and a full-screen television with no way out of it is one
   nobody can reclaim. */
.bc-exit{position:absolute;top:clamp(8px,1vw,16px);right:clamp(8px,1vw,16px);z-index:5;
  width:40px;height:40px;border-radius:9px;border:1px solid rgba(255,255,255,.2);
  background:rgba(255,255,255,.08);color:#fff;font-size:18px;cursor:pointer;transition:opacity .4s}

.bc-video{position:relative;background:#000;border-radius:12px;overflow:hidden;border:1px solid rgba(255,255,255,.1)}
.bc-video iframe,.bc-video video{position:absolute;inset:0;width:100%;height:100%;border:0;object-fit:contain;background:#000}
.bc-novideo{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  text-align:center;padding:24px;color:#94a3b8;font-size:clamp(12px,1.1vw,18px);line-height:1.6}

.bc-side{background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.1);border-radius:12px;
  padding:clamp(12px,1.3vw,22px);display:flex;flex-direction:column;gap:clamp(10px,1.2vw,20px);overflow:hidden}
.bc-none{color:#94a3b8;font-size:14px}
.bc-badge{display:inline-block;font-size:clamp(9px,.75vw,13px);font-weight:800;letter-spacing:.08em;
  padding:3px 10px;border-radius:20px;background:rgba(148,163,184,.18);color:#cbd5e1}
.bc-badge.racing{background:rgba(34,197,94,.2);color:#4ade80}
.bc-badge.finished{background:rgba(148,163,184,.2);color:#cbd5e1}
.bc-race h2{font-family:'Space Grotesk','Inter',sans-serif;font-size:clamp(17px,1.8vw,32px);
  font-weight:800;margin-top:6px;line-height:1.15;overflow-wrap:anywhere}
.bc-race p{font-size:clamp(11px,.95vw,17px);color:#94a3b8;margin-top:3px}

.bc-rail{position:relative;height:clamp(10px,.8vw,16px);border-radius:99px;
  background:rgba(255,255,255,.09);border:1px solid rgba(255,255,255,.12)}
.bc-fill{position:absolute;top:0;bottom:0;left:0;border-radius:99px;
  background:linear-gradient(90deg,#f59e0b,#fbbf24);transition:width .9s linear}
.bc-tick{position:absolute;top:-5px;width:2px;height:calc(100% + 10px);border-radius:2px;transition:left .9s linear}
.bc-tick.fast{background:#4ade80}
.bc-tick.slow{background:#f87171}
.bc-rider{position:absolute;top:50%;transform:translate(-50%,-50%) scaleX(-1);display:inline-block;font-size:clamp(20px,1.9vw,34px);
  line-height:1;transition:left .9s linear;filter:drop-shadow(0 2px 6px rgba(0,0,0,.7))}
.bc-railnums{display:flex;justify-content:space-between;margin-top:8px;
  font-size:clamp(10px,.9vw,15px);color:#cbd5e1;font-variant-numeric:tabular-nums}

.bc-stats{display:grid;grid-template-columns:1fr 1fr;gap:clamp(8px,1vw,16px)}
.bc-stats dt{font-size:clamp(8.5px,.65vw,11px);font-weight:800;text-transform:uppercase;
  letter-spacing:.07em;color:#64748b}
.bc-stats dd{font-family:'Space Grotesk','Inter',sans-serif;font-size:clamp(15px,1.5vw,28px);
  font-weight:800;margin-top:2px;font-variant-numeric:tabular-nums}
.bc-stats dd.fast{color:#4ade80}
.bc-stats dd.slow{color:#f87171}
.bc-stats dd.cd{color:#38bdf8;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
.bc-src{font-size:clamp(10px,.85vw,14px);color:#4ade80;font-weight:700;margin-top:auto}

.bc-ticker{background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.1);
  border-radius:12px;padding:clamp(8px,.8vw,14px) clamp(10px,1.1vw,18px);overflow:hidden}
.bc-tick-rail{display:flex;gap:clamp(16px,2vw,36px);white-space:nowrap;overflow-x:auto;
  scrollbar-width:none;font-size:clamp(11px,1vw,18px)}
.bc-tick-rail::-webkit-scrollbar{display:none}
.bc-tick-item b{color:#fbbf24;font-family:'Space Grotesk','Inter',sans-serif;margin-right:6px}
.bc-tick-item i{font-style:normal;font-size:.8em;font-weight:800;letter-spacing:.06em;
  background:rgba(245,158,11,.18);color:#fbbf24;padding:2px 7px;border-radius:5px;margin-right:6px}

@media (max-width:900px){
  .bc-stats{grid-template-columns:repeat(4,1fr)}
}

/* The WhatsApp hand-off button sits with the ticker's edit controls. */
.icon-btn.wa-btn{font-size:17px;line-height:1}
.lt-bc-btn{flex-shrink:0}

/* ═══════════════════════════════════════════════════════════
   OPERATIONS BOOKLET & QR SHEETS
   Print surfaces, not app surfaces: fixed colours rather than the
   theme variables, because html2canvas photographs the DOM and a
   booklet exported from the dark theme still has to come out on
   white paper.
   ═══════════════════════════════════════════════════════════ */
.modal-bg.wide .modal{max-width:860px}

.bk-scroll{overflow-x:auto;margin:-20px;padding:20px;background:#e2e8f0;border-radius:10px}
.bk-doc{width:720px;margin:0 auto;background:#fff;color:#0f172a;
  font-family:'Inter',system-ui,sans-serif;font-size:12.5px;line-height:1.5}
.bk-doc *{box-sizing:border-box}

/* ── ONE A4, CUT HERE ──
   The booklet is packed into pages in js/booklet.js and each is
   photographed on its own, so a page is a real A4 box with the sheet
   centred in it. The overflow is clipped because nothing should ever
   reach it: where the cut falls was decided by measuring. */
.bk-page{position:relative;width:794px;height:1123px;overflow:hidden;background:#fff}
.bk-pfoot{position:absolute;left:30px;right:30px;bottom:12px;display:flex;
  justify-content:space-between;gap:12px;font-size:8.5px;font-weight:700;color:#94a3b8;
  text-transform:uppercase;letter-spacing:.05em;
  border-top:1px solid #e2e8f0;padding-top:6px;font-family:'Inter',system-ui,sans-serif}

.bk-cover,.bk-sec{padding:26px 30px;page-break-inside:auto}
.bk-cover{min-height:400px}

.bk-logos{display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding-bottom:16px;border-bottom:2px solid #e2e8f0;margin-bottom:22px}
.bk-logos img{height:52px;width:auto;object-fit:contain}
.bk-logos .bk-golazo{height:30px}
.bk-logos.small img{height:38px}
.bk-logos.small .bk-golazo{height:22px}

.bk-kicker{font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:.14em;color:#b45309}
.bk-doc h1{font-family:'Space Grotesk','Inter',sans-serif;font-size:26px;font-weight:700;
  letter-spacing:-.5px;color:#0f172a;margin:6px 0 20px}

.bk-cover-meta{display:grid;grid-template-columns:1fr 1fr;gap:10px 24px;margin-bottom:22px}
.bk-cover-meta div{border-top:1px solid #e2e8f0;padding-top:7px;font-size:13px}
.bk-cover-meta b{display:block;font-size:9.5px;font-weight:800;text-transform:uppercase;
  letter-spacing:.09em;color:#64748b;margin-bottom:2px}

.bk-toc{margin:0 0 20px;padding:0 0 0 20px}
.bk-toc li{margin-bottom:6px}
.bk-toc b{font-weight:700}
.bk-toc span{display:block;font-size:11.5px;color:#64748b}

.bk-warn{font-size:11.5px;color:#92400e;background:#fef3c7;border:1px solid #fcd34d;
  border-radius:8px;padding:9px 12px;margin:0}

.bk-head{border-bottom:2px solid #0f172a;padding-bottom:8px;margin-bottom:16px}
.bk-head h2{font-family:'Space Grotesk','Inter',sans-serif;font-size:18px;font-weight:700;
  letter-spacing:-.3px;color:#0f172a;margin:0}
.bk-head span{display:block;font-size:12px;color:#64748b;margin-top:2px}
.bk-sub{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;
  color:#64748b;margin:20px 0 8px}

/* ── THE SCHEDULE SHEET, INSIDE THE BOOKLET ──
   The same cards from the same builder — see bkSchedule(). The sheet's
   own frame is dropped: the booklet section already provides the page's
   margins, and a second white box inside the first reads as a printout
   pasted onto a page. */
.bk-sec .bk-sp{width:auto;margin:0;padding:0}
.bk-sec .bk-sp .sp-day{margin-bottom:0}

/* ── WHERE THE BADGE IS COLLECTED ──
   A card per desk: the name it is called by, then the lines somebody
   standing in a car park needs. The PPO is boxed inside it, because it
   belongs to that desk and is not a fourth line of it. */
.bk-acc{border:1px solid #cbd5e1;border-left:5px solid #f59e0b;border-radius:8px;
  padding:12px 14px;margin-bottom:10px;page-break-inside:avoid;break-inside:avoid}
.bk-acc-n{font-size:13.5px;font-weight:800;color:#0f172a;margin-bottom:5px}
.bk-acc-r{display:flex;gap:10px;font-size:11.5px;line-height:1.45;margin-top:2px}
.bk-acc-r b{flex:0 0 92px;font-size:9px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;color:#64748b;padding-top:2px}
.bk-acc-r span{flex:1;min-width:0;color:#0f172a}
.bk-acc-ppo{margin-top:10px;padding-top:9px;border-top:1px dashed #cbd5e1}
.bk-acc-ppo .bk-acc-n{font-size:11.5px;color:#334155}

.bk-tbl{width:100%;border-collapse:collapse}
.bk-tbl th{text-align:left;font-size:9.5px;font-weight:800;text-transform:uppercase;
  letter-spacing:.08em;color:#475569;background:#f1f5f9;
  border-bottom:1px solid #cbd5e1;padding:7px 9px}
.bk-tbl td{padding:7px 9px;border-bottom:1px solid #e2e8f0;vertical-align:top}
.bk-tbl tr{page-break-inside:avoid}
.bk-tbl .r{text-align:right}
.bk-tbl .num{font-variant-numeric:tabular-nums;white-space:nowrap}
.bk-tbl tr.bk-shut td{background:#fef2f2}
.bk-tbl tr.bk-open td{background:#f0fdf4}
.bk-dim{font-size:11px;color:#64748b}

/* Profiles on paper. The booklet prints on white whatever theme the app is
   in, so the shared .rp-* rules — which follow the theme variables — are
   pinned to print colours here rather than inheriting a dark palette. */
.bk-prof{margin-top:18px;page-break-inside:avoid}
.bk-prof h3{font-size:13px;font-weight:800;color:#0f172a;margin:0}
.bk-prof-src{font-size:10.5px;color:#64748b;margin:2px 0 6px}
.bk-prof .rp-svg{height:96px;border-bottom:1px solid #e2e8f0}
.bk-prof .elev-grid{stroke:#e2e8f0}
.bk-prof .rp-stats{gap:18px;margin-top:7px}
.bk-prof .rp-stat dt{color:#64748b}
.bk-prof .rp-stat dd{color:#0f172a;font-size:12.5px}

.bk-pill{display:inline-block;font-size:9.5px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;padding:2px 7px;border-radius:20px}
.bk-pill.shut{background:#fee2e2;color:#b91c1c;border:1px solid #fca5a5}
.bk-pill.open{background:#dcfce7;color:#15803d;border:1px solid #86efac}

.bk-swatch{display:inline-block;width:11px;height:11px;border-radius:3px;margin-top:3px}
.bk-note{font-size:11.5px;color:#64748b;margin:10px 0 0}
.bk-empty{font-size:12.5px;color:#64748b;font-style:italic;margin:0}

.bk-contacts{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:6px}
.bk-contact{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  border:1px solid #cbd5e1;border-left:3px solid #dc2626;border-radius:7px;padding:8px 11px;
  page-break-inside:avoid}
.bk-contact-l{font-size:11.5px;color:#475569}
.bk-contact-p{font-family:'Space Grotesk','Inter',sans-serif;font-size:15px;font-weight:700;
  font-variant-numeric:tabular-nums;color:#0f172a;white-space:nowrap}

.bk-doclist{display:flex;flex-direction:column;gap:10px}
.bk-docrow{display:flex;align-items:center;gap:14px;border:1px solid #e2e8f0;border-radius:9px;
  padding:10px 12px;page-break-inside:avoid}
.bk-docmeta{min-width:0;display:flex;flex-direction:column;gap:2px}
.bk-docmeta code{font-size:10px;color:#64748b;word-break:break-all}

.bk-qrgrid{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.bk-qrcard{border:1px solid #cbd5e1;border-radius:10px;padding:14px;text-align:center;
  page-break-inside:avoid}
.bk-qrcard-t{font-size:13px;font-weight:700;color:#0f172a;margin-bottom:10px}
.bk-qrcard-s{font-size:11px;color:#0284c7;font-weight:600;margin-top:10px}
/* The sentence for whoever holds the phone, under the scope labels. */
.bk-qrcard-h{font-size:10.5px;color:#64748b;margin-top:6px;line-height:1.35}
.bk-qrcard code{display:block;font-size:9.5px;color:#94a3b8;word-break:break-all;margin-top:5px}

.bk-qr{display:flex;align-items:center;justify-content:center}
.bk-qr img,.bk-qr canvas{display:block;margin:0 auto}
.bk-qr.sm{flex-shrink:0;width:86px;height:86px}
/* Capped and clipped. A fallback is by definition the moment something has
   already gone wrong, and it must not take the surrounding layout with it —
   an unbroken 300-character string in a flex row squeezes its siblings to
   one character wide, which is exactly what the business card did. */
.qr-fallback{display:block;max-width:100%;max-height:120px;overflow:hidden;
  font-size:10px;color:#b91c1c;word-break:break-all;text-align:center}

@media (max-width:900px){
  .bk-doc{width:100%;min-width:520px}
}

/* ═══════════════════════════════════════════════════════════
   REGULATIONS & ROLL OF HONOUR
   ═══════════════════════════════════════════════════════════ */
.reg-card .c-sub{margin-bottom:14px}
.reg-table td:nth-child(3),.reg-table td:nth-child(4),
.reg-table th:nth-child(3),.reg-table th:nth-child(4){text-align:center;width:1%;white-space:nowrap}

/* Reigning champions: title · rider · is the jersey back this year. */
.hon-reign{display:flex;flex-direction:column;gap:2px;margin-top:14px}
.hon-reign-row{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1.2fr) auto;
  gap:14px;align-items:center;padding:10px 0;border-bottom:1px solid var(--border)}
.hon-reign-row:last-child{border-bottom:0}
.hon-reign-ttl{font-size:12.5px;font-weight:700;color:var(--text2);min-width:0}
.hon-reign-ttl small{display:block;font-size:11px;font-weight:600;color:var(--text3);margin-top:2px}
.hon-reign-who{display:flex;align-items:center;gap:9px;flex-wrap:wrap;min-width:0}
.hon-reign-who strong{font-size:13.5px}
.hon-reign-back{font-size:11px;font-weight:700;color:var(--text3);white-space:nowrap;
  border:1px solid var(--border);border-radius:20px;padding:3px 10px}
.hon-reign-back.yes{color:var(--green);border-color:var(--green-border);background:var(--green-bg)}

.hon-table td{vertical-align:top}
.hon-win{display:block;font-weight:700;margin-bottom:3px}
.hon-table .nat-pill{font-size:10.5px}

@media (max-width:640px){
  .hon-reign-row{grid-template-columns:1fr;gap:5px;padding:12px 0}
  .hon-reign-back{justify-self:start}
}

/* ═══════════════════════════════════════════════════════════
   ROAD WORKS
   The worklist handed to the road crew: what, where, by when.
   ═══════════════════════════════════════════════════════════ */
/* ICONS ONLY, AT EVERY WIDTH, IN THE HEADING'S OWN CORNER. What was a
   row of five labelled buttons standing between the title and the list is
   five icons beside the title — see rwTool() in js/roadworks.js, which
   keeps every name on the tooltip and the accessible name. */
.rw-tools{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:0;
  justify-content:flex-end}
.rw-tools .btn{padding:0;width:40px;height:40px;min-height:40px;justify-content:center}
.rw-tools .btn span{display:none}
.rw-tools .btn svg{width:17px;height:17px;margin:0}
/* On a phone the five of them are icons in one row — see .icon-only-m,
   which drops the label. Square, or a button with nothing but an icon in
   it keeps the width its vanished words were asking for. */
@media (max-width:640px){
  /* A thumb wants 44 px. The buttons are icons at every width now, so this
     is only about the size of the target, not about hiding the labels. */
  .rw-tools .btn{width:44px;height:44px;min-height:44px;flex:none}
  .rw-tools .btn svg{width:18px;height:18px}
}

.rw-tabs{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:14px}
.rw-tab{display:inline-flex;align-items:center;gap:7px;padding:7px 13px;border-radius:20px;
  border:1px solid var(--border2);background:var(--bg3);color:var(--text2);cursor:pointer;
  font-family:inherit;font-size:12.5px;font-weight:700;transition:all .16s}
.rw-tab:hover{border-color:var(--gold-border);color:var(--text)}
.rw-tab.active{background:var(--gold-bg);border-color:var(--gold-border);color:var(--gold2)}
.rw-tab.late{color:var(--red);border-color:var(--red-border)}
.rw-tab-n{font-size:11px;font-weight:800;background:var(--bg4);border-radius:10px;padding:1px 7px}

/* Map on the left, photo drop on the right. Both are ways of getting a job
   onto the page, and stacked they used the whole first screen between them
   while the list — the actual point of the page — started below the fold. */
.rw-top{display:grid;grid-template-columns:minmax(0,1fr) minmax(min(280px,100%),340px);
  gap:14px;align-items:stretch;margin-bottom:16px}
.rw-top.solo{grid-template-columns:1fr}
.rw-top .rw-map-card{margin-bottom:0}
/* Scoped to .rw-top so it outranks .drop-zone's own margin in map.css,
   which loads after this file and would otherwise inset it by 10px and
   leave it standing a little short of the map beside it. */
.rw-top .rw-drop{margin:0;display:flex;flex-direction:column;align-items:center;justify-content:center}

.rw-map-card{padding:0;overflow:hidden;margin-bottom:16px}
.rw-map-shell{position:relative;height:520px}
.rw-map{position:absolute;inset:0}
/* While a point is being picked the map is the only thing to click. */
.rw-map.picking{cursor:crosshair;box-shadow:inset 0 0 0 3px var(--gold2)}
.rw-map-hint{padding:9px 14px;margin:0;border-top:1px solid var(--border)}

/* Photograph left, everything else right. Without one the text simply takes
   the full width — an empty column reserved for a photo that may never come
   is the same wasted space by another name. */
.rw-card{margin-bottom:12px;display:grid;grid-template-columns:minmax(0,1fr);
  gap:16px;align-items:start}
.rw-card.has-photo{grid-template-columns:210px minmax(0,1fr)}
.rw-card.late{border-left:3px solid var(--red)}
.rw-body{min-width:0;display:flex;flex-direction:column}
.rw-photos{min-width:0}
.rw-lead{display:block;width:100%;aspect-ratio:4/3;padding:0;overflow:hidden;
  border:1px solid var(--border2);border-radius:10px;background:var(--bg3);cursor:pointer}
.rw-lead.static{cursor:default}
.rw-lead img{width:100%;height:100%;object-fit:cover;display:block}
.rw-lead:hover{border-color:var(--gold-border)}
.rw-more{display:flex;gap:6px;flex-wrap:wrap;margin-top:6px}
.rw-more .rw-shot{width:52px;height:52px}
.rw-hd{display:flex;align-items:flex-start;gap:11px;flex-wrap:wrap}
.rw-ico{font-size:20px;line-height:1.2;flex-shrink:0}
/* A drawn sign in place of the emoji. Sized to the glyph it replaces so a
   list mixing the two keeps one baseline, and `contain` so a sign that is
   not square is letterboxed rather than squashed. */
.rw-ico-img{width:22px;height:22px;object-fit:contain;flex-shrink:0;display:block}
.rw-hd-text{flex:1;min-width:150px}
.rw-hd-text strong{font-size:14.5px;font-weight:700;display:block}
.rw-hd-text .c-sub{margin:2px 0 0}
.rw-badge{font-size:10.5px;font-weight:800;letter-spacing:.03em;text-transform:uppercase;
  color:var(--rwc);border:1px solid var(--rwc);border-radius:20px;padding:3px 10px;white-space:nowrap}
.rw-acts{display:flex;gap:6px}
.rw-acts .icon-btn{min-width:36px;min-height:36px}
.rw-acts .icon-btn svg{width:17px;height:17px}

.rw-notes{font-size:13px;color:var(--text2);margin:10px 0 0;line-height:1.5}
.rw-facts{display:flex;gap:8px 16px;flex-wrap:wrap;margin-top:10px}
.rw-fact{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;
  color:var(--text2);text-decoration:none}
a.rw-fact:hover{color:var(--gold2)}
.rw-fact.late{color:var(--red)}
.rw-fact svg{width:14px;height:14px}

.rw-shots{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}
.rw-shot{width:74px;height:74px;padding:0;border-radius:10px;overflow:hidden;cursor:pointer;
  border:1px solid var(--border2);background:var(--bg3);color:var(--text3);
  display:flex;align-items:center;justify-content:center}
.rw-shot.static{cursor:default}
.rw-shot img{width:100%;height:100%;object-fit:cover;display:block}
.rw-shot:hover{border-color:var(--gold-border)}

.rw-status-row{display:flex;gap:6px;flex-wrap:wrap;align-items:center;margin-top:13px;
  padding-top:12px;border-top:1px solid var(--border)}
.rw-st{padding:5px 12px;border-radius:8px;border:1px solid var(--border2);background:var(--bg3);
  color:var(--text2);font-family:inherit;font-size:12px;font-weight:700;cursor:pointer;transition:all .16s}
.rw-st:hover{border-color:var(--rwc);color:var(--rwc)}
.rw-st.on{background:var(--rwc);border-color:var(--rwc);color:#0b1120}
.rw-status-row .btn{margin-left:auto}

/* Map pin: the type at a glance, the status in its ring. A plain disc, not
   a teardrop — a dozen jobs on one street turn into a heap of overlapping
   tails, and the point of the tail (which exact pixel it marks) is lost as
   soon as they touch. The face stays near-white in both themes: these sit
   on satellite imagery, where a dark pin disappears into the tarmac. */
.rw-pin{width:30px;height:30px;border-radius:50%;
  background:#fff;border:2.5px solid var(--rwc);box-shadow:0 2px 7px rgba(0,0,0,.45);
  display:flex;align-items:center;justify-content:center;cursor:pointer}
.rw-pin span{font-size:15px;line-height:1;
  /* Emoji ignore `color`, so the fallback for a glyph the platform has no
     picture for is a dark one — not white on white. */
  color:#0b1120}
/* Smaller than in the list: the pin is a 30px disc with a 2.5px status ring,
   and a sign filling it edge to edge leaves the ring nothing to show. */
.rw-pin .rw-ico-img{width:20px;height:20px}
.rw-pin.late{animation:rw-late 1.6s infinite}
@keyframes rw-late{0%,100%{box-shadow:0 2px 7px rgba(0,0,0,.45)}
  50%{box-shadow:0 2px 7px rgba(0,0,0,.45),0 0 0 7px rgba(248,113,113,.28)}}
/* Answering "Show on map": which of the pins on this street was asked for. */
.rw-pin.found{animation:rw-found 1.3s ease-out 2;z-index:5}
@keyframes rw-found{0%{box-shadow:0 2px 7px rgba(0,0,0,.45),0 0 0 0 rgba(245,158,11,.75)}
  100%{box-shadow:0 2px 7px rgba(0,0,0,.45),0 0 0 22px rgba(245,158,11,0)}}

/* A button that reads as one of the fact links beside it. */
.rw-fact.link{border:0;background:none;padding:0;font-family:inherit;cursor:pointer}
.rw-fact.link:hover{color:var(--gold2)}

.rw-latlng{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.rw-photo-view{position:relative;min-height:200px;display:flex;align-items:center;
  justify-content:center;background:var(--bg3);border-radius:10px;overflow:hidden}
.rw-photo-view img{max-width:100%;display:block}
.rw-photo-view img.blurred{filter:blur(9px);opacity:.6}
.rw-photo-view .spin{position:absolute}

@media (max-width:1100px){
  .rw-top{grid-template-columns:1fr}
  .rw-map-shell{height:360px}
  .rw-drop{padding:18px 14px}
}
@media (max-width:820px){
  /* Below this the photo column squeezes the title onto four lines. */
  .rw-card.has-photo{grid-template-columns:1fr}
  .rw-lead{aspect-ratio:16/9}
}
@media (max-width:640px){
  .rw-map-shell{height:280px}
  .rw-latlng{grid-template-columns:1fr}
  .rw-status-row .btn{margin-left:0}
}

/* The map's own controls, inside the map container so they come along into
   fullscreen. On a phone that is the only size the map is usable at, and
   everything used to be left behind on the page underneath. */
.rw-map-tools{position:absolute;top:10px;right:10px;z-index:3;display:flex;gap:6px;flex-wrap:wrap;
  justify-content:flex-end;max-width:calc(100% - 20px)}
/* The same on the map. Each label was most of its button's width, and
   five of them ran across the top edge of the picture they sit on — on a
   satellite view that is the half of the map worth looking at. */
.rw-map-btn{display:inline-flex;align-items:center;justify-content:center;gap:0;
  padding:0;width:38px;height:38px;border-radius:9px;
  border:1px solid rgba(148,163,184,.35);background:rgba(8,12,24,.82);color:#cbd5e1;
  backdrop-filter:blur(8px);cursor:pointer;font-family:inherit;font-size:12px;font-weight:700}
.rw-map-btn svg{width:16px;height:16px}
.rw-map-btn .rmb-t{display:none}
.rw-map-btn:hover{border-color:var(--gold2);color:#fff}
.rw-map-btn.on{background:var(--gold);border-color:var(--gold);color:#0b1120}

/* Roll of honour: a podium line is a name and a three-letter nation. */
.hon-place{display:grid;grid-template-columns:minmax(0,1fr) 190px;gap:8px;align-items:center}
.hon-place select{min-width:0}
@media (max-width:520px){ .hon-place{grid-template-columns:1fr} }

/* A block of tick-boxes folded behind its own answer. Collapsed, it is one
   line saying what is chosen; open, it is the full grid. */
.cat-fold{border:1px solid var(--border);border-radius:10px;background:var(--bg3);
  margin-bottom:14px;overflow:hidden}
.cat-fold>summary{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:11px 14px;cursor:pointer;list-style:none;min-height:44px}
.cat-fold>summary::-webkit-details-marker{display:none}
.cat-fold>summary::after{content:'';flex-shrink:0;width:8px;height:8px;border-right:2px solid var(--text3);
  border-bottom:2px solid var(--text3);transform:rotate(45deg) translate(-2px,-2px);transition:transform .18s}
.cat-fold[open]>summary::after{transform:rotate(-135deg) translate(-2px,-2px)}
.cat-fold>summary:hover{background:var(--bg4)}
.cf-label{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:var(--text2)}
.cf-sel{flex:1;text-align:right;font-size:13px;font-weight:700;color:var(--text);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cat-fold .field{margin:0;padding:0 14px 12px}

.rw-modal-shots{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}

/* ── QUOTA EDITOR (Art. 02) ──────────────────────────────────── */
.quota-edit{display:flex;flex-direction:column;gap:2px}
.qe-hd,.qe-row{display:grid;grid-template-columns:minmax(0,1fr) 92px 92px;gap:10px;align-items:center}
.qe-hd{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;
  color:var(--text2);padding-bottom:6px;border-bottom:1px solid var(--border);margin-bottom:4px}
.qe-hd span:not(:first-child){text-align:center}
.qe-row{padding:6px 0;border-bottom:1px solid var(--border)}
.qe-row:last-child{border-bottom:0}
.qe-name{font-size:12.5px;font-weight:600;min-width:0}
.qe-f{display:flex;flex-direction:column;align-items:center;gap:2px}
.qe-f input{width:100%;min-height:38px;text-align:center;background:var(--bg3);
  border:1px solid var(--border2);border-radius:8px;color:var(--text);padding:6px 4px;
  font-family:inherit;font-size:14px;font-weight:700;font-variant-numeric:tabular-nums;outline:none}
.qe-f input:focus{border-color:var(--gold)}
/* The printed value, so a change is always visible as a change. */
.qe-f small{font-size:10px;color:var(--text3);font-variant-numeric:tabular-nums}
@media (max-width:520px){
  .qe-hd,.qe-row{grid-template-columns:minmax(0,1fr) 70px 70px;gap:7px}
  .qe-name{font-size:11.5px}
}

.rw-usage{display:flex;align-items:center;gap:7px;margin:-6px 0 12px}
.rw-usage svg{width:14px;height:14px}

.kml-facts{list-style:none;margin:12px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}
.kml-facts li{font-size:13px;font-weight:600;color:var(--text2);padding:8px 12px;
  background:var(--bg3);border:1px solid var(--border);border-radius:8px}

/* The big + : add a job at the middle of the view. Sized for a thumb, and
   the only control that has to be findable without reading anything. */
.rw-fab{position:absolute;right:16px;bottom:26px;z-index:4;width:60px;height:60px;border-radius:50%;
  border:none;background:linear-gradient(135deg,var(--gold),var(--gold2));color:#0b1120;
  box-shadow:0 6px 18px rgba(0,0,0,.45);cursor:pointer;display:flex;align-items:center;
  justify-content:center;transition:transform .16s,box-shadow .16s}
.rw-fab svg{width:30px;height:30px;stroke-width:2.6}
.rw-fab:hover{transform:scale(1.06);box-shadow:0 8px 24px rgba(0,0,0,.55)}
.rw-fab:active{transform:scale(.94)}
/* Locked onto the blue dot: the + will drop the job on your own position
   rather than on the middle of the map, and says so with the same blue. */
.rw-fab.at-me{box-shadow:0 6px 18px rgba(0,0,0,.45),0 0 0 3px #1da1f2,0 0 0 6px rgba(29,161,242,.28)}
/* Fullscreen is where it matters most, so it grows rather than shrinks. */
.rw-map:fullscreen .rw-fab{width:72px;height:72px;right:22px;bottom:34px}
.rw-map:fullscreen .rw-fab svg{width:36px;height:36px}

/* Marker popup: the facts, then what you can do about them. */
.rw-pop{font-size:12px;line-height:1.45;min-width:150px}
/* Two by two: with Mobility beside Edit, Maps and Street View the row
   ran out of the popup (Janny, 25 Sep 2026). */
.rw-pop-acts{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-top:9px;padding-top:8px;border-top:1px solid var(--border)}
.rw-pop-acts .rw-pop-btn{justify-content:center;white-space:nowrap}
.rw-pop-btn{display:inline-flex;align-items:center;gap:5px;padding:6px 10px;border-radius:8px;
  border:1px solid var(--border2);background:var(--bg3);color:var(--text);cursor:pointer;
  font-family:inherit;font-size:11.5px;font-weight:700;text-decoration:none;min-height:34px}
.rw-pop-btn:hover{border-color:var(--gold-border);color:var(--gold2)}
.rw-pop-btn svg{width:13px;height:13px}

/* Map style picker, in the map's own toolbar so it follows into fullscreen. */
.rw-style-wrap{position:relative}
.rw-style-menu{position:absolute;top:calc(100% + 6px);right:0;z-index:6;min-width:150px;
  display:flex;flex-direction:column;gap:2px;padding:5px;border-radius:10px;
  background:rgba(8,12,24,.94);border:1px solid rgba(148,163,184,.35);
  backdrop-filter:blur(8px);box-shadow:0 10px 26px rgba(0,0,0,.5)}
/* The `hidden` attribute is only `display:none` from the browser's own
   stylesheet, and the `display:flex` above outranks it — so the menu stood
   permanently open however carefully the attribute was set. Every other
   panel in this app already carries this line; this one did not. */
.rw-style-menu[hidden]{display:none}
.rw-style-opt{padding:9px 12px;border:0;border-radius:7px;background:none;color:#cbd5e1;
  cursor:pointer;font-family:inherit;font-size:12px;font-weight:700;text-align:left;min-height:38px}
.rw-style-opt:hover{background:rgba(255,255,255,.1);color:#fff}
.rw-style-opt.on{background:var(--gold);color:#0b1120}

/* All / none beside a field heading. */
.field-hd.bk-hd{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%}
.bk-all{display:flex;gap:4px}
.link-sm{border:1px solid var(--border2);background:var(--bg3);color:var(--text2);
  border-radius:20px;padding:3px 11px;font-family:inherit;font-size:10px;font-weight:800;
  text-transform:uppercase;letter-spacing:.05em;cursor:pointer;min-height:26px}
.link-sm:hover{border-color:var(--gold-border);color:var(--gold2)}

/* A map control whose effect depends on another being on. */
.rw-map-btn.off{opacity:.55}

/* ── HOSPITAL & TRAUMA CENTRES ─────────────────────────────────
   One card per hospital: who they are, then where, what they can do
   and how to drive there. It was a single nowrap row of name, badge
   and two icon buttons — the buttons do not shrink, so on a phone the
   name was squeezed into a four-character column and every word of it
   wrapped onto its own line. */
/* Two abreast when the column is wide enough for a readable pair;
   auto-fit drops back to one on its own below that. */
.hosp-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(min(100%,340px),1fr))}
/* The medical map beside the hospital list: the canvas holds its ground
   on the left, the cards stack in one column beside it, and the pair
   folds to map-then-list on a narrow screen. */
.med-hosp-layout{display:grid;gap:14px;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);align-items:start}
/* Folded: the list is gone and the map takes the card — and grows, because
   a map given the whole width and the old 560 px reads as a letterbox. */
.med-hosp-layout.list-off{grid-template-columns:1fr}
.med-hosp-layout.list-off .med-hosp-list{display:none}
/* clamp, not min: on a short window 72vh is LESS than the 560 px the
   map already had, and folding the list away must never shrink it. */
.med-hosp-layout.list-off .med-map-shell{height:clamp(560px,72vh,780px)}
.med-hosp-list{grid-template-columns:1fr;max-height:560px;overflow-y:auto;padding-right:4px}
.med-map-shell{position:relative;height:560px;border-radius:12px;overflow:hidden;
  border:1px solid var(--border);background:var(--bg3)}
.med-map{position:absolute;inset:0}
@media (max-width:980px){
  .med-hosp-layout{grid-template-columns:1fr}
  .med-hosp-layout.list-off .med-map-shell{height:clamp(340px,70vh,560px)}
  .med-map-shell{height:340px}
  .med-hosp-list{max-height:none;overflow:visible}
}
/* How many are still without a time — per category, and once for the
   whole afternoon. Amber while anybody is out, green when the last one
   is in: it is the line the finish line reads from across the room. */
.crr-out{display:inline-flex;align-items:center;gap:4px;font-size:11px;font-weight:800;
  padding:1px 8px;border-radius:20px;background:rgba(245,158,11,.16);
  border:1px solid rgba(245,158,11,.45);color:#b45309;white-space:nowrap}
body:not(.light) .crr-out{color:#fbbf24}
.crr-out b{font-weight:700;opacity:.75}
.crr-in{font-size:11px;font-weight:800;color:var(--green)}
.crr-tot{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin:10px 0 4px;
  padding:10px 14px;border-radius:10px;background:rgba(245,158,11,.12);
  border:1px solid rgba(245,158,11,.4)}
.crr-tot strong{font-size:17px;font-weight:800;color:var(--text);font-variant-numeric:tabular-nums}
.crr-tot span{font-size:12px;color:var(--text2)}
.crr-tot.done{background:rgba(52,211,153,.12);border-color:rgba(52,211,153,.45)}

/* Where a live category is being timed, beside its name. */
.crr-at{font-size:11px;font-weight:800;color:var(--gold2);white-space:nowrap}

/* The Live TV card's warning about a link that is a page, not a player. */
.tv-warn{display:flex;gap:10px;align-items:flex-start;margin-top:12px;padding:11px 13px;
  border-radius:10px;background:rgba(245,158,11,.12);border:1px solid rgba(245,158,11,.45);
  font-size:12.5px;line-height:1.5;color:var(--text2)}
.tv-warn strong{color:var(--text)}

/* And, on the television itself, the way out of a page that will not
   play: fades with the cursor like the rest of that screen. */
.bc-popout{position:absolute;right:14px;bottom:14px;z-index:4;
  border:1px solid rgba(255,255,255,.35);background:rgba(3,37,42,.88);color:#fff;
  border-radius:22px;padding:9px 16px;min-height:44px;font-family:inherit;font-size:13px;
  font-weight:800;cursor:pointer;backdrop-filter:blur(8px);transition:opacity .3s}
body.bc-idle .bc-popout{opacity:0;pointer-events:none}

/* A championship's final classification: one block per category, each
   with its own podium. They wrap into columns on a wide screen and
   stack on a phone — thirteen of them is a long read either way. */
.fc-cats{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:10px;margin-top:4px}
.fc-cat{background:var(--bg3);border:1px solid var(--border);border-radius:10px;padding:10px 12px}
.fc-cat .ce-lbl{display:block;margin-bottom:6px}
.fc-cat .ce-lbl b{color:var(--text3);font-weight:700}
.fc-cat .hon-row{padding:2px 0}

/* Which race the live screen is following. Sits under the race name in
   its own box, quiet until somebody uses it. */
.lt-follow{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:10px}
.lt-follow select{flex:1 1 200px;min-width:0;min-height:40px;background:var(--bg3);color:var(--text);
  border:1px solid var(--border2);border-radius:9px;padding:0 10px;font-family:inherit;
  font-size:12px;font-weight:700}
.lt-follow-auto{flex:0 0 auto;min-height:40px;padding:0 12px;border-radius:9px;cursor:pointer;
  background:none;border:1px solid var(--gold-border);color:var(--gold2);
  font-family:inherit;font-size:11.5px;font-weight:800}
.lt-follow-auto:hover{background:rgba(212,175,55,.12)}

/* ── THE COVERAGE SCAN ────────────────────────────────────────
   Three numbers across the top, then the stretches worth looking at,
   each one a button that flies the map there. */
.med-cov-sum{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:6px 0 4px}
.med-cov-sum > div{background:var(--bg3);border:1px solid var(--border);border-radius:10px;
  padding:9px 11px;display:flex;flex-direction:column;gap:1px;min-width:0}
.med-cov-sum span{font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;
  color:var(--text3)}
.med-cov-sum strong{font-size:17px;font-weight:800;color:var(--text);font-variant-numeric:tabular-nums}
.med-cov-sum small{font-size:10.5px;color:var(--text2)}
/* The name of the course a block was measured on — two races on one day
   are two lines and two sets of kilometres, and a stretch of "km 88" is
   only a place if you know which line it is on. */
.med-cov-course{display:flex;align-items:center;gap:7px;margin:14px 0 2px;
  font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--text2)}
.med-cov-course:first-child{margin-top:0}
.med-cov-course svg{width:13px;height:13px;color:var(--gold2)}
.med-cov-course small{margin-left:auto;font-size:11px;font-weight:700;
  text-transform:none;letter-spacing:0;color:var(--text3)}
.med-cov-list{display:flex;flex-direction:column;gap:6px;margin-top:10px}
.med-cov-row{display:flex;align-items:flex-start;gap:10px;width:100%;text-align:left;cursor:pointer;
  background:var(--bg3);border:1px solid var(--border);border-left:4px solid var(--gold2);
  border-radius:10px;padding:10px 12px;font-family:inherit;color:var(--text);min-height:44px}
.med-cov-row:hover{border-color:var(--gold-border)}
.med-cov-km{font-size:12px;font-weight:800;color:var(--gold2);white-space:nowrap;
  font-variant-numeric:tabular-nums}
.med-cov-t{font-size:12px;color:var(--text2);line-height:1.45;min-width:0}
.med-cov-t strong{color:var(--text)}
.med-cov-t small{display:block;font-size:11px;color:var(--text3);margin-top:2px}
@media (max-width:520px){
  .med-cov-sum{grid-template-columns:1fr}
  .med-cov-row{flex-direction:column;gap:3px}
}

/* Which doctors' link to copy, when a race cut more than one. */
.med-link-list{display:flex;flex-direction:column;gap:6px}
.med-link-row{display:flex;align-items:center;gap:10px;width:100%;text-align:left;cursor:pointer;
  min-height:48px;padding:10px 14px;border-radius:10px;background:var(--bg3);
  border:1px solid var(--border);color:var(--text);font-family:inherit;font-size:13px;font-weight:700}
.med-link-row:hover{border-color:var(--gold-border);color:var(--gold2)}
.med-link-row svg{width:15px;height:15px;flex-shrink:0}

/* ── THE INCIDENT FORM'S TWO NEW HALVES ───────────────────────
   The timeline is open and tight: four clocks and a pre-alert, each with
   its own "now", sized so all five fit a phone in two rows rather than
   pushing the note field off the screen. */
.med-chain{border:1px solid var(--border);border-radius:10px;padding:10px 12px 12px;margin-bottom:12px;
  background:var(--bg3)}
.med-chain-hd{display:block;font-size:11px;font-weight:800;text-transform:uppercase;
  letter-spacing:.07em;color:var(--text2);margin-bottom:8px}
.med-chain-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(132px,1fr));gap:8px}
.med-chain-row + .med-chain-row{margin-top:8px}
.med-chain-f label{display:block;font-size:10px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;color:var(--text3);margin-bottom:4px}
.med-chain-in{display:flex;gap:4px;align-items:stretch}
.med-chain-in input{flex:1 1 auto;min-width:0;min-height:40px;background:var(--bg2);color:var(--text);
  border:1px solid var(--border2);border-radius:8px;padding:0 8px;font-family:inherit;font-size:13px}
.med-chain-in .btn{flex:0 0 auto;min-height:40px;width:40px;padding:0;justify-content:center}
.med-chain-in .btn svg{width:15px;height:15px}
.med-chain-wide{grid-column:1 / -1}
.med-prealert-call{flex:0 0 auto;min-height:40px;white-space:nowrap}
.med-prealert-call[hidden]{display:none}

/* The folded halves: read months later, never at the roadside, so they
   are closed until somebody asks for them. */
.med-fold{border:1px solid var(--border);border-radius:10px;padding:0;margin-bottom:12px;
  background:var(--bg3)}
.med-fold > summary{cursor:pointer;padding:11px 12px;font-size:12px;font-weight:800;
  color:var(--text);list-style:none;min-height:44px;display:flex;align-items:center;gap:6px}
.med-fold > summary::-webkit-details-marker{display:none}
.med-fold > summary::after{content:'▾';margin-left:auto;color:var(--text3);font-size:11px}
.med-fold[open] > summary::after{content:'▴'}
.med-fold[open] > summary{border-bottom:1px solid var(--border)}
.med-fold > *:not(summary){margin-left:12px;margin-right:12px}
.med-fold > *:not(summary):last-child{margin-bottom:12px}
.med-fold .field-hd{display:block;font-size:10px;font-weight:800;text-transform:uppercase;
  letter-spacing:.07em;color:var(--text3);margin:12px 12px 6px}
.med-fold .chk-grid{margin-bottom:4px}

/* What those two halves become on the log card and in the report. */
.med-line{font-size:11.5px;color:var(--text2);margin-top:5px;display:flex;flex-wrap:wrap;gap:4px 10px;
  align-items:center}
.med-km{font-weight:800;color:var(--gold2);font-variant-numeric:tabular-nums}
.med-who-tag{font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;
  padding:2px 7px;border-radius:20px;background:var(--bg4);border:1px solid var(--border);color:var(--text2)}
.med-prot-tag{font-size:9.5px;font-weight:800;padding:2px 7px;border-radius:20px;
  background:rgba(220,38,38,.14);border:1px solid rgba(220,38,38,.45);color:#dc2626}
body.light .med-prot-tag{color:#b91c1c}
.med-span{font-variant-numeric:tabular-nums}

/* HOW GOOD A PIN IS. A coarse fix is not an error, it is a warning:
   the report is real, the place is a neighbourhood. Said in red on the
   form before sending, and in amber beside the pin at the desk. */
.mrq-fix-bad{color:var(--red);font-weight:700}
.med-acc{color:var(--text3);font-variant-numeric:tabular-nums}
.med-acc-bad{color:var(--gold);font-weight:800;font-variant-numeric:tabular-nums}
body.light .med-acc-bad{color:#a16207}

/* Where an incident was logged: amber, small, unmistakably not a hospital. */
.med-inc-pin{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  background:#f59e0b;color:#231502;font-size:13px;font-weight:900;line-height:1;cursor:pointer;
  border:2px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,.4)}

/* A report from the doctors' link, not yet adopted: red and beating —
   the same alarm as the emergency button, because it is the same "look
   here first". Turns amber the moment the desk adopts it.

   Its OWN keyframes, shadow only, and that is load-bearing: Mapbox
   places a marker by writing `transform: translate(…)` on this very
   element, and the emergency button's pulse animates transform — on a
   marker that override tore the pin off its coordinates and left it
   glued to the map's top-left corner. A pin may beat; it may not move. */
.med-req-pin{width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  background:#dc2626;color:#fff;font-size:13px;font-weight:900;line-height:1;cursor:pointer;
  border:2px solid #fff;
  animation:medreq-pulse 1.9s ease-in-out infinite}
@keyframes medreq-pulse{
  0%,100%{ box-shadow:0 2px 8px rgba(0,0,0,.45), 0 0 0 0 rgba(220,38,38,.55) }
  50%    { box-shadow:0 2px 8px rgba(0,0,0,.45), 0 0 0 9px rgba(220,38,38,0) }
}

/* The road-works +, recoloured for what it files here. The shape and the
   placement are the .rw-fab's — one thumb-sized ball, bottom right. */
.med-fab{background:linear-gradient(135deg,#dc2626,#b91c1c);color:#fff}
.med-fab svg{stroke:#fff}
/* ARMED, at the desk: the next click on the map files an incident there,
   and a button that looked the same either way would be a trap. Amber
   with a white ring, and it beats — shadow only, like every other pulse
   on a map: Mapbox positions this element with its own transform. */
.med-fab.armed{background:linear-gradient(135deg,#f59e0b,#d97706);
  outline:3px solid rgba(255,255,255,.9);outline-offset:2px;
  animation:medfab-armed 1.6s ease-in-out infinite}
@keyframes medfab-armed{
  0%,100%{ box-shadow:0 6px 18px rgba(0,0,0,.45), 0 0 0 0 rgba(245,158,11,.55) }
  50%    { box-shadow:0 6px 18px rgba(0,0,0,.45), 0 0 0 14px rgba(245,158,11,0) }
}

/* Your own report, landed: green tick where the red beating pin would be
   presumptuous — this phone knows it was sent, not what the desk did
   with it. */
.med-sent-pin{background:#16a34a;color:#fff;font-size:12px}

/* THE MAP-ONLY DOCTORS' SCREEN. The content pane hands over its padding
   and its scroll, and the shell fills every pixel left under the header
   — this is the "full screen" the link promises, with no gesture needed.
   The fab grows the way it does under :fullscreen on the road-works map:
   this screen is only ever a thumb's screen. */
/* NO READ-ONLY STRIP ON THE MELDKAART. It is the right thing to say on
   a shared page somebody is reading — and this screen is not that: it
   is a working tool with a red + on it, held by a doctor at the
   roadside, on a phone where that strip took a fifth of the map and
   said something they already know. The medical screen behind it still
   carries it. */
body.medmap-view #ro-banner{display:none!important}
body.medmap-view #content{padding:0;overflow:hidden}
/* THE DOCTOR'S SCREEN IS THE MAP AND NOTHING ELSE. This link opens on
   the report map, and whoever follows it is standing over somebody on
   the road with a phone in one hand — the one thing to do is drop a pin
   and file. A navigation rail beside that offers a choice nobody in that
   moment wants to make, and it was eating 236 px of the map on a phone
   held sideways. Same treatment the portal already gets, two rules up. */
body.medmap-view #sidebar{display:none}
body.medmap-view #menuBtn,body.medmap-view #sidebar-scrim{display:none!important}
#v-medmap{position:relative;height:100%}
.med-map-shell.medmap-full{position:absolute;inset:0;height:auto;border-radius:0;border:none}
.medmap-full .med-fab{width:72px;height:72px;right:22px;bottom:34px}
.medmap-full .med-fab svg{width:36px;height:36px}

/* ── THE MAP-ONLY SCREEN'S OWN CHROME ──────────────────────────
   Painted onto the canvas by medPaintMapOnly() — medmap view only.
   Dark glass like the rw-style-menu, not theme tokens: these float on
   the map canvas, which has no theme. Controls sit clear of a phone's
   camera cutout and home bar via the safe-area insets. */
.medmap-full .mapboxgl-ctrl-top-left{padding-top:env(safe-area-inset-top)}

/* The numbers behind one icon, bottom-left, opposite the red +. The
   container is anchored by its bottom so the panel grows upward. */
/* ── THE TWO ROUND BUTTONS, TOP RIGHT ─────────────────────────
   The numbers (📞) and the beacon (📡) used to sit bottom-left, where
   on a phone they stood on top of Mapbox's own zoom and compass stack
   — Janny's screenshot had the beacon over the + and the phone over
   the −. Top right now, one under the other, from the top edge: the
   waypoint button that held that corner went to the map's own stack
   bottom-left, so the row above them is empty. On every width: the
   red + keeps the bottom-right corner, the map stack the bottom-left,
   and nothing stands on anything. */
.med-sos{position:absolute;right:16px;top:calc(12px + env(safe-area-inset-top));z-index:5;
  display:flex;flex-direction:column-reverse;align-items:flex-end;gap:10px}
.med-sos-btn{width:52px;height:52px;border-radius:50%;border:none;background:#fff;
  font-size:22px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;
  box-shadow:0 6px 18px rgba(0,0,0,.45);transition:transform .16s}
.med-sos-btn:active{transform:scale(.94)}
.med-sos-pop{min-width:230px;max-width:min(78vw,320px);max-height:min(55vh,420px);overflow-y:auto;
  padding:8px;border-radius:12px;background:rgba(3,37,42,.95);border:1px solid rgba(125,190,188,.35);
  backdrop-filter:blur(8px);box-shadow:0 10px 26px rgba(0,0,0,.5)}
.med-sos-pop[hidden]{display:none}
.med-sos-row{display:flex;align-items:center;gap:6px;min-height:44px}
.med-sos-tel{flex:1;min-width:0;display:flex;align-items:center;justify-content:space-between;gap:14px;padding:10px 12px;
  border-radius:8px;text-decoration:none;color:#e2e8f0;font-size:13px;font-weight:700;min-height:44px}
.med-sos-tel:hover{background:rgba(255,255,255,.08)}
.med-sos-n{font-family:monospace;font-size:14px;font-weight:800;color:#fff;white-space:nowrap}
/* The same number on WhatsApp: a green round button at the end of the
   row, the brand's own green so a thumb finds it without reading. */
.med-sos-wa,.med-ec-wa{flex:0 0 auto;width:36px;height:36px;border-radius:50%;display:inline-flex;
  align-items:center;justify-content:center;background:#25d366;color:#fff;text-decoration:none}
.med-sos-wa svg,.med-ec-wa svg{width:18px;height:18px}
.med-sos-wa:hover,.med-ec-wa:hover{background:#1ebe5b}
.med-ec-wa{width:28px;height:28px;margin-left:8px;vertical-align:middle}
.med-ec-wa svg{width:15px;height:15px}

/* The basemap icon rides in the course map's own toolbar — .map-tools
   and .map-pop from css/map.css — inside the map container so it follows
   into fullscreen and onto the map-only screen. See medPaintMapTools().
   On that screen it clears the camera cutout, and the stage chips stop
   short of it. */
.medmap-full .med-map-tools{top:calc(12px + env(safe-area-inset-top))}
/* Armed to drop a pin: the cursor says so, and so does the lit button. */
.med-map.picking .mapboxgl-canvas-container,
.med-map.picking .mapboxgl-canvas{cursor:crosshair}
/* The stage chips stop short of the round buttons, not of the old row. */
.medmap-full .med-day-ovl{right:80px}

/* The "turn my position on" pill, under the stage chips. Green while it
   is an invitation, amber once the browser has refused — at which point
   it stops being a button that fixes it and becomes one that explains
   it. See medPaintGeoInvite(). */
.med-geo-pill{position:absolute;top:calc(58px + env(safe-area-inset-top));left:50%;
  transform:translateX(-50%);z-index:6;max-width:calc(100% - 24px);
  border:1px solid rgba(125,190,188,.45);background:rgba(3,37,42,.92);color:#e2e8f0;
  backdrop-filter:blur(8px);border-radius:22px;padding:9px 16px;min-height:44px;
  font-family:inherit;font-size:13px;font-weight:800;cursor:pointer;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;box-shadow:0 6px 18px rgba(0,0,0,.4)}
.med-geo-pill:active{transform:translateX(-50%) scale(.97)}
.med-geo-pill.bad{background:rgba(120,53,15,.94);border-color:rgba(245,158,11,.6);color:#fde68a}

/* The stage chips along the top, clear of the control stack on the left. */
.med-day-ovl{position:absolute;top:calc(10px + env(safe-area-inset-top));left:56px;right:10px;z-index:5;
  display:flex;gap:6px;justify-content:center;flex-wrap:wrap;pointer-events:none}
.med-day-ovl .btn{pointer-events:auto;box-shadow:0 3px 10px rgba(0,0,0,.35)}
.med-day-ovl .btn.ghost{background:rgba(3,37,42,.88);color:#e2e8f0;border-color:rgba(125,190,188,.4)}

/* ── THE MEDICAL CREW'S BEACON AND ITS MARKERS ────────────────
   The button lives on the map-only screen, stacked above the emergency
   numbers on the same left rail, thumb-sized like everything else there.
   Dark and grey when off; white-hot with a red beating ring when the
   command post can see you — the state has to be readable at arm's
   length, through a visor. */
.med-beacon{position:absolute;right:16px;top:calc(76px + env(safe-area-inset-top));z-index:5;
  width:52px;height:52px;border-radius:50%;border:none;background:rgba(3,37,42,.92);
  color:#fff;font-size:22px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;
  box-shadow:0 6px 18px rgba(0,0,0,.45);transition:transform .16s,background .2s;
  border:1px solid rgba(125,190,188,.35)}
.med-beacon:active{transform:scale(.94)}
/* The emoji is flattened to a silhouette in both states: grey on the
   dark glass when the beacon is off, solid white on the red when it is
   on. Its own colours read as neither at a glance through a visor. */
.med-beacon .med-beacon-ico{filter:grayscale(1) opacity(.6)}
.med-beacon.on{background:#dc2626;border-color:#fff;animation:mc-beacon 1.9s ease-in-out infinite}
.med-beacon.on .med-beacon-ico{filter:grayscale(1) brightness(0) invert(1)}
.med-beacon.waiting{opacity:.8}
/* The three states, behind a lit beacon. Anchored to the beacon's own
   corner and growing upward, like the numbers panel opposite it. */
.med-beacon-menu{position:absolute;right:16px;top:calc(136px + env(safe-area-inset-top));z-index:6;
  min-width:210px;max-width:min(76vw,300px);padding:6px;border-radius:12px;
  background:rgba(3,37,42,.95);border:1px solid rgba(125,190,188,.35);
  backdrop-filter:blur(8px);box-shadow:0 10px 26px rgba(0,0,0,.5);
  display:flex;flex-direction:column;gap:2px}
.med-beacon-menu[hidden]{display:none}
.med-bm-row{display:flex;align-items:center;gap:9px;min-height:44px;padding:8px 11px;border:0;
  border-radius:8px;background:none;color:#e2e8f0;font-family:inherit;font-size:13px;font-weight:700;
  text-align:left;cursor:pointer}
.med-bm-row:hover{background:rgba(255,255,255,.1)}
.med-bm-row.on{background:rgba(255,255,255,.14);color:#fff}
.med-bm-row.stop{color:#fca5a5;border-top:1px solid rgba(125,190,188,.25);border-radius:0 0 8px 8px}
.med-bm-dot{width:11px;height:11px;border-radius:50%;flex-shrink:0}
@keyframes mc-beacon{
  0%,100%{ box-shadow:0 6px 18px rgba(0,0,0,.45), 0 0 0 0 rgba(220,38,38,.55) }
  50%    { box-shadow:0 6px 18px rgba(0,0,0,.45), 0 0 0 12px rgba(220,38,38,0) }
}

/* The crew on the map: a red cross, not the tracker's green dot — the
   two mean different things and a command post reads them at a glance.
   Shadow-only animation, like .med-req-pin: Mapbox positions a marker
   by writing transform on this very element, so a pin may beat but it
   may never move. A fix past its freshness is dimmed rather than
   dropped; the label carries its age. */
/* Zero-size anchor, same contract as .tk-marker above — the cross sits
   ON the crew's position however long the name beside it is. */
.mc-marker{position:relative;width:0;height:0;cursor:pointer}
.mc-marker.stale{opacity:.55}
.mc-dot{position:absolute;left:-11px;top:-11px;width:22px;height:22px;box-sizing:border-box;
  border-radius:7px;display:flex;align-items:center;justify-content:center;
  background:#dc2626;color:#fff;font-size:16px;font-weight:900;line-height:1;
  border:2px solid #fff;animation:mc-pulse 2s ease-in-out infinite}
.mc-marker.stale .mc-dot{animation:none;box-shadow:0 2px 8px rgba(0,0,0,.45)}
.mc-label{position:absolute;left:16px;top:-10px;font-size:11px;font-weight:700;color:#fff;
  background:rgba(3,37,42,.86);border:1px solid rgba(220,38,38,.45);border-radius:10px;
  padding:2px 7px;white-space:nowrap}
@keyframes mc-pulse{
  0%,100%{ box-shadow:0 2px 8px rgba(0,0,0,.45), 0 0 0 0 rgba(220,38,38,.5) }
  50%    { box-shadow:0 2px 8px rgba(0,0,0,.45), 0 0 0 10px rgba(220,38,38,0) }
}

/* ── A WAYPOINT, ON ANY MAP ────────────────────────────────────
   The roadbook's own emoji on a zero-size anchor, so the icon sits
   exactly ON its coordinate. No label: forty names beside forty pins
   hid the course they sit on — the name is in the popup and in the
   hover title. Used by the medical map, the dashboard map and the
   road-works map; the course map draws its own symbol layer, which is
   the right thing for the screen they are edited on. */
.poi-pin{position:relative;width:0;height:0;cursor:pointer}
.poi-pin-dot{position:absolute;left:-13px;top:-13px;width:26px;height:26px;box-sizing:border-box;
  border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;line-height:1;
  background:rgba(3,37,42,.92);border:2px solid rgba(255,255,255,.85);
  box-shadow:0 2px 8px rgba(0,0,0,.45);transition:transform .12s}
.poi-pin-dot:hover{transform:scale(1.15)}
/* A roadbook sign on a pin: the drawing is dark on light, so the dot
   turns white under it. */
.poi-pin-dot.has-img{background:#fff;border-color:rgba(3,37,42,.55)}
.poi-pin-img{width:18px;height:18px;object-fit:contain;display:block}
.poi-pop-img{width:16px;height:16px;object-fit:contain;display:inline-block;vertical-align:-3px}

/* ── THE LAYER PANEL ───────────────────────────────────────────
   One kind per row with its count, inside whichever map panel opened
   it — the course map's .map-pop, the road-works menu, the medical
   map's. It borrows the panel's dark glass rather than the page's
   colours: these all float over a canvas. */
/* ALLE / GEEN, AND THE MANAGE LINK, ON DARK GLASS. They were .btn ghost
   — a page button, which is transparent with a grey label and reads as
   disabled the moment it floats over a map panel. Inside .map-pop they
   get their own skin: the panel's own border, the panel's own text. */
.poi-lay-all{display:flex;gap:6px;margin-bottom:6px}
.poi-lay-all .btn{flex:1 1 auto;justify-content:center;min-height:38px;
  background:rgba(125,190,188,.14);border:1px solid rgba(125,190,188,.4);color:#e8eefc;
  font-weight:800}
.poi-lay-all .btn:hover:not(:disabled){background:rgba(125,190,188,.26);color:#fff}
.poi-lay-all .btn:disabled{opacity:.4;cursor:default}
.map-pop .mo-label,.rw-poi-menu .mo-label{color:rgba(232,238,252,.8)}
.poi-lay-list{display:flex;flex-direction:column;gap:3px;max-height:min(46vh,300px);overflow-y:auto}
.poi-lay{display:flex;align-items:center;gap:9px;padding:7px 9px;border-radius:8px;cursor:pointer;
  border:1px solid transparent;font-size:12px;font-weight:700;color:rgba(232,238,252,.72);min-height:40px}
.poi-lay:hover{background:rgba(255,255,255,.08);color:#fff}
.poi-lay.on{background:rgba(125,190,188,.16);border-color:rgba(125,190,188,.4);color:#fff}
.poi-lay input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent-fill)}
.poi-lay-ico{font-size:14px;line-height:1;flex-shrink:0}
/* Wrapping, not truncating: "Gevaarlijke afdaling" is the name of the
   layer somebody is looking for, and half of it is not. */
.poi-lay-t{flex:1 1 auto;min-width:0;white-space:normal;line-height:1.25}
.poi-lay b{font-variant-numeric:tabular-nums;color:rgba(232,238,252,.6);font-size:11px}
.poi-lay.on b{color:#fff}
/* .btn.poi-lay-edit, not .poi-lay-edit: `.btn.ghost` is two classes and
   would otherwise outrank it and paint this transparent grey again. */
.btn.poi-lay-edit{width:100%;justify-content:center;margin-top:8px;min-height:40px;
  background:rgba(255,255,255,.07);border:1px solid rgba(125,190,188,.35);color:#e8eefc;
  font-weight:800}
.btn.poi-lay-edit:hover{background:rgba(255,255,255,.14);color:#fff}
.btn.poi-lay-edit svg{width:14px;height:14px}
/* The road-works menu is narrower than the map panels; the layer rows
   need the width more than the menu needs to be tight. */
.rw-poi-menu{min-width:230px;padding:9px}

/* Making a layer: an emoji, a name, how many points hold it, and a bin.
   The built-in six are listed as chips underneath — visible, so nobody
   invents a second "first aid", and unreachable, because the importer
   and the descent scan write them by name. */
.poi-tp-row{display:flex;align-items:center;gap:8px;margin-bottom:6px}
/* The badge is a button that opens the picker — see openIconPicker() in
   js/map.js — and it wears whatever the layer wears: an emoji, one of
   the roadbook drawings, or an uploaded picture. */
.poi-tp-ico{width:56px;min-height:44px;flex:0 0 auto;display:flex;align-items:center;
  justify-content:center;font-size:18px;cursor:pointer;
  background:var(--bg3);color:var(--text);border:1px solid var(--border2);border-radius:9px}
.poi-tp-ico:hover{border-color:var(--gold-border);background:var(--bg4)}
.poi-ico-img{width:24px;height:24px;object-fit:contain;display:block}

/* The picker, laid over the dialogue that opened it. */
.poi-ico-pick{margin:0 0 12px;padding:10px;border-radius:12px;
  background:var(--bg3);border:1px solid var(--border2)}
.pip-hd{display:flex;align-items:center;justify-content:space-between;
  font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;
  color:var(--text3);margin-bottom:8px}
.pip-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:10px}
.pip-row .input{width:90px;min-height:38px;text-align:center;font-size:16px}
.pip-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(46px,1fr));gap:6px;
  max-height:46vh;overflow-y:auto;padding:2px}
.pip-ico{padding:4px;border-radius:9px;border:1px solid transparent;background:var(--bg2);
  cursor:pointer;display:flex;align-items:center;justify-content:center}
.pip-ico:hover{border-color:var(--gold);background:var(--gold-bg)}
.pip-ico img{width:32px;height:32px;object-fit:contain;display:block}
body.light .pip-ico{background:#fff}
.poi-tp-name{flex:1 1 auto;min-width:0}
.poi-tp-row input{min-height:44px;background:var(--bg3);color:var(--text);
  border:1px solid var(--border2);border-radius:9px;padding:0 10px;font-family:inherit;font-size:13px}
.poi-tp-n{flex:0 0 auto;min-width:26px;text-align:right;font-size:11px;font-weight:800;
  color:var(--text3);font-variant-numeric:tabular-nums}
.poi-tp-fixed{display:flex;flex-wrap:wrap;gap:6px}
.poi-tp-chip{display:inline-flex;align-items:center;gap:6px;padding:5px 10px;border-radius:20px;
  background:var(--bg3);border:1px solid var(--border);font-size:11.5px;font-weight:700;color:var(--text2)}
.poi-tp-chip b{color:var(--text3);font-variant-numeric:tabular-nums}

/* And the same grouping in the waypoint LIST beside the course map, so
   what you tick on the canvas and what you read in the panel are the
   same six kinds. */
.poi-grp-hd{display:flex;align-items:center;gap:7px;padding:9px 12px 5px;font-size:10px;
  font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:var(--text3);
  cursor:pointer;user-select:none;min-height:34px}
.poi-grp-hd:hover{color:var(--text2)}
.poi-grp-hd > span{font-size:13px;text-transform:none;letter-spacing:0}
/* A layer's badge may be a drawing rather than an emoji — the heading
   used to print the file reference as words. Sized to sit on the same
   line as a glyph of the same weight. */
.poi-grp-ico{width:16px;height:16px;object-fit:contain;display:block}
.poi-grp-hd b{margin-left:auto;font-variant-numeric:tabular-nums;color:var(--text2)}
/* Folded: the rows go, the heading stays — with its count, so a layer
   put away still says how much it is holding. */
.poi-grp-caret{display:inline-flex;color:var(--text3);transition:transform .16s}
.poi-grp-caret svg{width:13px;height:13px}
.poi-grp.is-shut .poi-grp-rows{display:none}
.poi-grp.is-shut .poi-grp-caret{transform:rotate(-90deg)}
.poi-grp.is-shut .poi-grp-hd{opacity:.7}

/* Reading a file of points into one layer: which layer, then the file. */
.poi-imp{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.poi-imp select{flex:1 1 180px;min-width:0;min-height:44px;background:var(--bg3);color:var(--text);
  border:1px solid var(--border2);border-radius:9px;padding:0 10px;font-family:inherit;font-size:13px}
.poi-imp .btn{flex:0 0 auto;cursor:pointer}

/* And the strip on the medical screen: who is out there, how long ago
   they were heard from, and one press to fly the map to them. */
.mc-card{margin-bottom:14px;border-left:4px solid #dc2626}
.mc-hd{display:flex;align-items:center;gap:10px}
.mc-hd h3{margin:0;font-size:14px}
.mc-count{font-size:11px;font-weight:800;padding:2px 8px;border-radius:20px;
  background:#dc2626;color:#fff}
.mc-list{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.mc-chip{display:flex;align-items:center;gap:8px;padding:6px 12px;border-radius:22px;
  background:var(--bg4);border:1px solid var(--border);color:var(--text);cursor:pointer;
  font-size:12px;font-weight:700;min-height:36px}
.mc-chip:hover{border-color:#dc2626}
.mc-chip.stale{opacity:.6}
.mc-chip-dot{width:9px;height:9px;border-radius:50%;background:#dc2626;flex-shrink:0}
.mc-chip.stale .mc-chip-dot{background:var(--text3)}
.mc-chip-m{color:var(--text2);font-weight:600;font-variant-numeric:tabular-nums}
.mc-note{font-size:11.5px;color:var(--text3);margin-top:10px;line-height:1.5}

/* The red cross on the map — the sign every ambulance driver reads. */
.med-pin{width:26px;height:26px;border-radius:8px;display:flex;align-items:center;justify-content:center;
  background:#dc2626;color:#fff;font-size:18px;font-weight:900;line-height:1;cursor:pointer;
  border:2px solid #fff;box-shadow:0 2px 8px rgba(0,0,0,.45)}
.hosp-near:empty{display:none}
.hosp-near{color:var(--text2)}
.hosp-near strong{color:var(--text)}

/* The share list's bulk bar and row ticks. */
.share-bulk{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0 0 10px;
  padding:10px 14px;background:var(--bg2);border:1px solid var(--border);border-radius:10px;font-size:13px}
.share-bulk-all{display:flex;align-items:center;gap:8px;font-weight:700;color:var(--text);cursor:pointer}
.share-bulk-n{font-weight:800;color:var(--text)}
.share-bulk-hint{color:var(--text3);font-size:12px}
.share-bulk input[type=checkbox],.sc-check input{width:18px;height:18px;accent-color:var(--primary,#f59e0b);cursor:pointer}
.sc-check{display:flex;align-items:center;flex-shrink:0;margin-right:2px}
.hosp-card{background:var(--bg3);border:1px solid var(--border);border-radius:12px;
  padding:16px;display:flex;flex-direction:column;gap:10px}
.hosp-top{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
/* The name takes the room that is left, and is allowed to be narrower than
   its longest word — without min-width:0 a flex item never shrinks past that. */
.hosp-id{flex:1;min-width:0}
.hosp-id h4{margin:0 0 4px;font-size:15px;font-weight:700;color:var(--text);line-height:1.3}
.hosp-meta{font-size:12px;color:var(--text2)}
.hosp-actions{display:flex;align-items:center;gap:6px;flex-shrink:0}
.hosp-badge{color:#fff;font-size:10px;border-color:transparent}
.hosp-addr{font-size:12.5px;color:var(--text)}
.hosp-feats{display:flex;flex-wrap:wrap;gap:6px}
.hosp-feats .tag{font-size:10px}
/* What it can RECEIVE, apart from the free-text services beside it: this is
   the line that decides where an ambulance drives, so it reads first and in
   the red of the medical screen rather than as one more grey service tag. */
.hosp-feats .hosp-care{font-weight:800;letter-spacing:.02em;
  background:rgba(239,68,68,.12);border-color:rgba(239,68,68,.4);color:#ef4444}
.hosp-nav{display:flex;gap:8px;margin-top:4px;flex-wrap:wrap}
.hosp-nav .btn{font-size:11px;padding:4px 10px}

@media (max-width:640px){
  /* Name across the full width, badge and buttons on their own line under it.
     Nothing competes for the same row, so nothing gets squeezed. */
  .hosp-card{padding:14px;gap:9px}
  .hosp-top{flex-direction:column;align-items:stretch;gap:8px}
  .hosp-id h4{font-size:15.5px}
  .hosp-actions{justify-content:flex-start}
  .hosp-actions .icon-btn{min-width:38px;min-height:38px;margin-left:auto}
  .hosp-actions .icon-btn + .icon-btn{margin-left:0}
  .hosp-nav .btn{flex:1;justify-content:center}
}

/* ── LIVE TV PAGE ──────────────────────────────────────────────
   Two cards of setting-up, then the button that takes over the room. */
.tv-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr));gap:16px}
/* TWO SCREENS ONCE SHARED tv-row AND tv-acts: this page, and the
   arrivals board in js/travel.js. Nothing here is scoped to a container,
   so the rules ran together — and the one that did not get overridden,
   `margin-top:14px` on .tv-acts, pushed the arrivals row's Ride button
   and pencil a notch below the head count and the flight chip beside
   them. It read as sloppy alignment and was a name collision. This page
   carries its own bc- prefix everywhere else; these three now do too. */
.bc-rows{margin-top:12px;display:flex;flex-direction:column;gap:1px;
  border-radius:10px;overflow:hidden;border:1px solid var(--border)}
.bc-row{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding:10px 12px;background:var(--bg3)}
.bc-row dt{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;
  color:var(--text3);flex-shrink:0}
.bc-row dd{font-size:13px;font-weight:700;color:var(--text);text-align:right;min-width:0;
  overflow-wrap:anywhere}
.bc-row dd.ok{color:#16a34a}
.bc-row dd.bad{color:#dc2626}
.bc-row dd.none{color:var(--text2);font-weight:600}
.tv-count{margin-top:12px;font-size:26px;font-weight:800;color:var(--text);
  font-family:'Space Grotesk','Inter',sans-serif;font-variant-numeric:tabular-nums}
.bc-acts{margin-top:14px;display:flex;gap:8px;flex-wrap:wrap}
.bc-acts .btn{flex:1 1 auto;justify-content:center}
.tv-go{margin-top:16px;display:flex;align-items:center;justify-content:space-between;
  gap:16px;flex-wrap:wrap}
.tv-go .c-sub{margin-top:3px}
.tv-go .btn.lg{font-size:15px;padding:12px 22px;min-height:48px}
@media (max-width:640px){
  .tv-go{flex-direction:column;align-items:stretch;text-align:center}
  .tv-go .btn.lg{width:100%;justify-content:center}
}

/* ── ROAD STATUS ON THE TELEVISION ─────────────────────────────
   Read from across a room: one line per zone, the state as a word and
   a dot, and nothing else competing for the space. */
.bc-roads{background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.1);
  border-radius:12px;padding:clamp(10px,1.1vw,18px);display:flex;flex-direction:column;
  gap:clamp(6px,.7vw,12px);overflow:hidden}
.bc-roads-hd{font-size:clamp(10px,.85vw,14px);font-weight:800;text-transform:uppercase;
  letter-spacing:.09em;color:#94a3b8;flex-shrink:0}
.bc-roads-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;
  gap:clamp(5px,.6vw,10px);overflow:hidden;min-height:0}
.bc-roads-list li{display:flex;align-items:center;gap:clamp(7px,.8vw,13px);
  font-size:clamp(12px,1.15vw,22px);line-height:1.25;min-width:0}
.bc-r-dot{width:.65em;height:.65em;border-radius:50%;flex-shrink:0}
.bc-roads-list li.open  .bc-r-dot{background:#4ade80;box-shadow:0 0 10px rgba(74,222,128,.7)}
.bc-roads-list li.shut  .bc-r-dot{background:#f87171;box-shadow:0 0 10px rgba(248,113,113,.7);
  animation:marker-pulse 2.4s infinite;--mk:rgba(248,113,113,.55)}
.bc-r-zone{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#e2e8f0}
.bc-r-state{font-weight:800;letter-spacing:.05em;font-size:.8em;flex-shrink:0}
.bc-roads-list li.open  .bc-r-state{color:#4ade80}
.bc-roads-list li.shut  .bc-r-state{color:#f87171}

/* ── THE LIVE TV PLANNER ───────────────────────────────────────
   A scale drawing of the television, blocks dragged around on it. The
   stage keeps 16:9 whatever width it lands in, so what is arranged here
   is the shape that ends up on the wall. */
.tv-plan-card{margin-top:16px}
.tv-plan-hd{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;flex-wrap:wrap}
.tv-plan-acts{display:flex;gap:8px;flex-shrink:0}
.tv-stage-wrap{margin-top:14px;border-radius:12px;padding:10px;background:var(--bg3);
  border:1px solid var(--border)}
.tv-stage{position:relative;aspect-ratio:16/9;width:100%;border-radius:8px;background:#05080f;
  border:1px solid #1e293b;overflow:hidden;touch-action:none;
  background-image:linear-gradient(rgba(255,255,255,.05) 1px,transparent 1px),
                   linear-gradient(90deg,rgba(255,255,255,.05) 1px,transparent 1px);
  background-size:10% 10%}
.tv-blk{position:absolute;border-radius:6px;border:1.5px solid var(--bc);
  background:color-mix(in srgb,var(--bc) 22%,transparent);cursor:grab;
  display:flex;align-items:center;justify-content:center;overflow:hidden;
  transition:box-shadow .15s}
.tv-blk:hover{box-shadow:0 0 0 2px color-mix(in srgb,var(--bc) 45%,transparent)}
.tv-blk.dragging{cursor:grabbing;box-shadow:0 0 0 2px var(--bc);z-index:3}
.tv-blk-name{font-size:11px;font-weight:800;letter-spacing:.04em;color:#f8fafc;
  text-align:center;padding:2px 6px;text-shadow:0 1px 3px rgba(0,0,0,.7);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;pointer-events:none}
/* Bottom-right, the corner every resize handle has ever been in. */
.tv-blk-grip{position:absolute;right:0;bottom:0;width:16px;height:16px;cursor:nwse-resize;
  background:linear-gradient(135deg,transparent 45%,var(--bc) 45%)}

/* One colour per block, used by the drawing and by the swatch in the list. */
.tv-blk-header{--bc:#38bdf8}
.tv-blk-video {--bc:#f59e0b}
.tv-blk-data  {--bc:#a78bfa}
.tv-blk-roads {--bc:#4ade80}
.tv-blk-ticker{--bc:#f472b6}

.tv-blocks{list-style:none;margin:14px 0 0;padding:0;display:flex;flex-direction:column;gap:1px;
  border:1px solid var(--border);border-radius:10px;overflow:hidden}
.tv-blk-row{display:flex;align-items:center;gap:10px;padding:9px 12px;background:var(--bg3)}
.tv-blk-row.off .tv-blk-label,.tv-blk-row.off .tv-swatch{opacity:.42}
.tv-swatch{width:12px;height:12px;border-radius:3px;background:var(--bc);flex-shrink:0}
.tv-blk-label{flex:1;min-width:0;font-size:13px;font-weight:700;color:var(--text);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tv-blk-geo{font-size:11.5px;color:var(--text3);font-variant-numeric:tabular-nums;flex-shrink:0}
.tv-blk-toggle{flex-shrink:0;min-height:28px;padding:0 11px;border-radius:999px;cursor:pointer;
  border:1px solid var(--border2);background:var(--bg4);color:var(--text2);
  font-family:inherit;font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:.05em}
.tv-blk-toggle.on{border-color:color-mix(in srgb,var(--green) 55%,transparent);
  background:color-mix(in srgb,var(--green) 16%,transparent);color:var(--green)}
.tv-plan-acts .btn:disabled{opacity:.45;cursor:default}
@media (max-width:640px){
  .tv-blk-geo{display:none}
  .tv-blk-name{font-size:9.5px}
}

/* ── RACE SCHEDULE ON PAPER ────────────────────────────────────
   Printed on white whatever theme the app is in, so nothing here reads
   a theme variable — the same reason the booklet pins its own colours. */
.sp-doc{width:720px;margin:0 auto;background:#fff;color:#0f172a;padding:30px 34px;
  font-family:Inter,Arial,sans-serif;letter-spacing:normal;line-height:1.45}
/* Every day starts a fresh page. The standalone programme is drawn now —
   js/schedvec.js decides its own page breaks — so what is left here is
   the day as the operations booklet prints it, and the browser's own
   Print, which both see one tall document. */
.sp-day{margin-bottom:22px;page-break-inside:auto}
.sp-day + .sp-day{page-break-before:always;break-before:page;padding-top:6px}
/* WRAPS, AND THE NAME WINS. The meta line was pinned to one line, so on a
   day called "Mercredi — Courses sur route et contre-la-montre" it took the
   width it wanted and left the name a column four characters wide: the
   title came out of the exporter running down the page one word per line.
   The two share the row when both fit and the meta drops under the name
   when they do not. */
/* ONE LINE UNDER THE OTHER, NOT BESIDE IT. The name and the meta shared a
   row and pushed each other about: on a preparation day the counts wrapped
   onto a second line of their own and sat hard against the right edge,
   ragged, under a title that had the rest of the band to itself. Stacked,
   the name is the name and the line under it reads as one sentence — date,
   what kind of day it is, and what is on it. */
.sp-dayhd{background:#0f172a;color:#fff;border-radius:10px;padding:15px 18px 16px;
  margin-bottom:16px;border-left:6px solid #f59e0b;
  page-break-after:avoid;page-break-inside:avoid}
.sp-dayname{overflow-wrap:anywhere;
  font-family:'Space Grotesk',Inter,sans-serif;font-size:20px;font-weight:800;
  letter-spacing:-.3px}
.sp-daymeta{font-size:12px;font-weight:700;color:#fbbf24;margin-top:4px;
  text-transform:uppercase;letter-spacing:.06em}
.sp-empty{font-size:12px;color:#64748b;padding:4px 2px 14px}

/* One race, never split across a page: half a start block on paper is worse
   than a shorter page. */
/* Each race carries its course's own colour down its leading edge, the way
   the race cards in the app do — on a five-race day that is what tells two
   blocks apart at arm's length. */
.sp-race{border:1px solid #cbd5e1;border-left:5px solid var(--rc,#f59e0b);
  border-radius:8px;padding:13px 15px 14px;margin-bottom:11px;
  page-break-inside:avoid;break-inside:avoid}
.sp-rhd{display:flex;align-items:flex-start;gap:14px}
.sp-time{font-family:'Space Grotesk',Inter,sans-serif;font-size:22px;font-weight:800;
  letter-spacing:-.6px;font-variant-numeric:tabular-nums;line-height:1;flex-shrink:0;min-width:66px;
  white-space:nowrap;color:var(--rc,#0f172a)}
/* A training is a window, not a moment, so its stamp is twice as long —
   at the race size it eats the room the session name needs. */
.sp-trn-card .sp-time{font-size:17px}
.sp-rname{flex:1;min-width:0}
.sp-rname h3{font-size:14px;font-weight:800;margin:0;line-height:1.25}
.sp-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:5px}
.sp-pill{display:inline-block;font-size:9px;font-weight:800;text-transform:uppercase;
  letter-spacing:.05em;padding:2px 7px;border-radius:20px;border:1px solid}
.sp-disc{background:#eef2ff;border-color:#c7d2fe;color:#4338ca}
.sp-cat{background:#fff;border-color:var(--cc);color:var(--cc)}
.sp-trk{background:#f8fafc;border-color:#cbd5e1;color:#64748b;text-transform:none;letter-spacing:0}

/* EIGHT FACTS DO NOT FIT ON ONE LINE. This was a single table row of cells
   set to nowrap, and a time trial fills it: start, both towns, km 0, laps,
   distance and the two estimated finishes. The row simply grew past the
   sheet — 250 px past it in English and 420 in French — and the export
   photographs the page, so those columns were not squeezed, they were cut
   off. A grid wraps onto a second line instead, and the labels wrap inside
   their own cell rather than widening it. */
.sp-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(118px,1fr));
  gap:9px 14px;margin-top:11px}
.sp-fact{min-width:0}
.sp-k{display:block;font-size:8.5px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;color:#94a3b8;overflow-wrap:anywhere;line-height:1.3}
.sp-v{display:block;font-size:13px;font-weight:700;font-variant-numeric:tabular-nums;
  margin-top:2px;overflow-wrap:anywhere;line-height:1.25}

/* The course beside its profile: where, then how hard. */
.sp-lower{display:flex;gap:14px;align-items:flex-start;margin-top:12px;
  padding-top:10px;border-top:1px solid #e2e8f0}
.sp-map{margin:0;flex:0 0 auto;width:260px}
.sp-map img{display:block;width:260px;height:176px;border:1px solid #cbd5e1;border-radius:8px}
.sp-map figcaption{font-size:8.5px;color:#64748b;margin-top:3px;text-align:center;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* The profile, pinned to print colours the same way the booklet's is. */
.sp-prof{flex:1;min-width:0}
.sp-prof .rp-svg{height:82px}
.sp-prof .elev-grid{stroke:#e2e8f0}
.sp-prof .rp-yax,.sp-prof .rp-xax{color:#64748b}
.sp-prof .rp-stats{gap:16px;margin-top:8px}
.sp-prof .rp-stat dt{color:#64748b}
.sp-prof .rp-stat dd{color:#0f172a;font-size:12.5px}

.sp-foot{font-size:10px;color:#64748b;margin-top:18px;padding-top:10px;border-top:1px solid #e2e8f0}
.tv-plan-dirty{align-self:center;font-size:11px;font-weight:800;text-transform:uppercase;
  letter-spacing:.05em;color:var(--gold2);white-space:nowrap}

.sp-sec-title{display:flex;align-items:center;gap:8px;font-family:'Space Grotesk',Inter,sans-serif;font-size:15px;font-weight:800;color:#0f172a;margin:18px 0 10px;padding-bottom:4px;border-bottom:2px solid #e2e8f0;page-break-after:avoid;break-after:avoid}
.sp-pill.sp-close{background:#fff7ed;border-color:#ffedd5;color:#c2410c}
.sp-trn-note{font-size:11px;color:#64748b;margin-top:5px}
.sp-act-loc{display:flex;align-items:center;gap:5px;font-size:12px;color:#334155;margin-top:4px}
/* An address that can be tapped says so. The tap itself is a PDF link
   annotation laid over the finished page — see pdfLinkRects(). */
.sp-tap{font-size:8.5px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;
  color:#1d4ed8;border:1px solid #bfdbfe;border-radius:20px;padding:1px 6px;white-space:nowrap}
.sp-acc-card .sp-time{font-size:15px}
.sp-act-note{font-size:11px;color:#475569;margin-top:4px}
.sp-act-loc svg{color:#64748b;flex-shrink:0}
.sp-dim{color:#64748b}

.bk-prof-row td{padding:8px 12px 14px!important;background:#f8fafc;border-bottom:2px solid #e2e8f0}
.bk-prof-inline{margin-top:4px}
.bk-prof-inline .rp-plot{margin-bottom:8px}


/* ── CALENDAR SUBSCRIPTION ───────────────────────────────────
   The subscription address, on the share card and in the calendar modal.
   Given its own tinted row rather than a second line of the same block: it
   is a different URL from the share link above it, and an organiser pasting
   the wrong one into a mail to a federation is the failure this styling
   exists to prevent. */
.sc-url.cal{display:flex;align-items:center;gap:9px;margin-top:7px;
  background:var(--gold-bg);border-color:var(--gold-border)}
.sc-url-tag{display:inline-flex;align-items:center;gap:5px;flex-shrink:0;
  font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;color:var(--gold2)}
.sc-url-tag svg{width:12px;height:12px}
.sc-url.cal code{color:var(--text2);min-width:0}
/* The map row's copy button keeps to the right edge, clear of the URL. */
.sc-url.cal .icon-btn{flex-shrink:0;margin-left:auto}

.cal-sub{padding:13px 14px;border-radius:10px;background:var(--gold-bg);
  border:1px solid var(--gold-border);margin-bottom:14px}
.cal-sub-hd{display:flex;align-items:center;gap:7px;margin-bottom:5px;
  font-size:13px;font-weight:700;color:var(--gold2)}
.cal-sub-hd svg{width:15px;height:15px}
.cal-sub .hint{margin:0 0 9px;font-size:12px;color:var(--text2);line-height:1.45}
.cal-sub-url{display:block;padding:8px 10px;margin-bottom:9px;border-radius:7px;
  background:var(--bg3);border:1px solid var(--border);
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;color:var(--text2);
  overflow-x:auto;white-space:nowrap}
.cal-or{display:flex;align-items:center;gap:10px;margin:0 0 12px;
  font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--text3)}
.cal-or::before,.cal-or::after{content:'';flex:1;height:1px;background:var(--border)}

/* ═══════════════════════════════════════════════════════════
   PORTED FROM THE GOLAZO SPORTS MANAGER — accreditation centre,
   fleet manager, hotels, badge studio, caravan exports and the
   directory upgrades. Extracted as the selectors CAC did not have
   yet; the brand accents mapped onto CAC's amber & gold on the way in.
   ═══════════════════════════════════════════════════════════ */
.auth-mark{position:relative;display:flex;align-items:center;justify-content:center;
  height:104px;margin:-8px 0 14px;overflow:hidden}
.auth-mark .auth-logo{position:relative;z-index:2;margin:0;height:38px;
  animation:golazoWipe .85s cubic-bezier(.22,1,.36,1) .12s both}
.auth-rings{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  pointer-events:none;z-index:1}
.auth-rings i{position:absolute;border-radius:999px;
  width:104px;height:58px;border:1.5px solid rgba(245,158,11,.55);
  opacity:0;transform:scale(var(--r));
  animation:golazoRipple 2.4s cubic-bezier(.16,.84,.44,1) both,
            golazoIdle 7s ease-in-out infinite}
.auth-rings i:nth-child(1){--r:1.06; animation-delay:0s,   2.6s}
.auth-rings i:nth-child(2){--r:1.62; animation-delay:.12s, 2.8s}
.auth-rings i:nth-child(3){--r:2.24; animation-delay:.24s, 3.0s}
.auth-rings i:nth-child(4){--r:2.92; animation-delay:.36s, 3.2s}
@keyframes golazoRipple{
  0%   {opacity:0;   transform:scale(.3)}
  20%  {opacity:.9;  transform:scale(calc(var(--r) * .55))}
  /* It thins out as it goes rather than stopping — a wave leaving the
     frame, not one hitting a wall. */
  65%  {opacity:.3;  transform:scale(calc(var(--r) * .92))}
  100% {opacity:.13; transform:scale(var(--r))}
}
@keyframes golazoIdle{
  0%,100%{opacity:.13; transform:scale(var(--r))}
  50%    {opacity:.22; transform:scale(calc(var(--r) * 1.035))}
}
@keyframes golazoWipe{
  0%  {opacity:0; clip-path:inset(0 100% 0 0); transform:translateY(6px) skewX(-9deg)}
  55% {opacity:1}
  100%{opacity:1; clip-path:inset(0 0 0 0);   transform:none}
}
.pc-head{display:flex;align-items:center;gap:13px;min-width:0}
.pc-titles{min-width:0;display:flex;flex-direction:column;gap:3px}
.pc-logo{width:56px;height:56px;object-fit:contain;flex-shrink:0}
.pc-head.has-logo h3{font-size:23px}
@media (max-width:760px){
  .rw-map-tools{top:calc(10px + env(safe-area-inset-top,0px));right:10px;gap:5px;flex-wrap:nowrap}
  /* Square and thumb-sized. Four of these plus the gaps still take under
     half the width, where the labelled row took two rows of all of it. */
  .rw-map-btn{padding:0;width:42px;height:42px;border-radius:11px}
  .rw-map-btn .rmb-t{display:none}
  .rw-map-btn svg{width:18px;height:18px}
  /* The style menu hangs off a 38px button, so it can no longer be as wide
     as the button it is aligned to — it is pinned to the right edge and
     given its own width. */
  .rw-style-menu{min-width:132px}
}
.rw-map:fullscreen .rw-map-tools{top:calc(10px + env(safe-area-inset-top,0px))}
.imgf{display:flex;align-items:center;gap:13px}
.imgf-prev{width:78px;height:78px;flex-shrink:0;border-radius:10px;overflow:hidden;
  border:1px solid var(--border2);display:flex;align-items:center;justify-content:center;
  background-color:var(--bg3);
  background-image:linear-gradient(45deg,rgba(150,178,228,.13) 25%,transparent 25%,transparent 75%,rgba(150,178,228,.13) 75%),
                   linear-gradient(45deg,rgba(150,178,228,.13) 25%,transparent 25%,transparent 75%,rgba(150,178,228,.13) 75%);
  background-size:14px 14px;background-position:0 0,7px 7px}
.imgf-prev img{width:100%;height:100%;object-fit:contain}
.imgf-prev.empty{color:var(--text3)}
.imgf-prev.empty svg{width:26px;height:26px}
.imgf-acts{display:flex;flex-direction:column;gap:6px;align-items:flex-start}
.imgf-acts .btn[hidden]{display:none}
.lt-live-link{display:flex;align-items:center;gap:13px;margin-bottom:13px;padding:14px 18px;
  border-radius:12px;text-decoration:none;min-height:56px;
  border:1px solid var(--accent-fill);background:var(--gold-bg);color:var(--text);
  transition:background .16s,transform .16s}
.lt-live-link:hover{background:var(--gold-light);transform:translateY(-1px)}
.lt-live-link > svg:first-child{width:22px;height:22px;flex-shrink:0;color:var(--gold2)}
body.light .lt-live-link > svg:first-child{color:var(--gold)}
.lt-live-link > svg:last-child{width:15px;height:15px;flex-shrink:0;margin-left:auto;color:var(--text3)}
.ltl-t{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:17px;font-weight:700;letter-spacing:-.2px}
.ltl-h{font-size:12px;color:var(--text2);font-variant-numeric:tabular-nums}
@media (max-width:640px){
.lt-live-link{flex-wrap:wrap;gap:4px 11px}
.ltl-h{width:100%;padding-left:35px}
}
.team-cell{display:inline-flex;align-items:center;gap:9px;min-width:0}
.team-cell > span{min-width:0;overflow:hidden;text-overflow:ellipsis}
.jersey{width:26px;height:26px;object-fit:contain;flex-shrink:0}

/* The teams on this race, and what each one is wearing. */
.jt-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(280px,100%),1fr));gap:9px}
.jt-row{display:flex;align-items:center;gap:12px;padding:9px 12px;border-radius:10px;
  border:1px solid var(--border);background:var(--bg3)}
body.light .jt-row{background:#fff}
.jt-row.unmatched{border-color:var(--amber-border);background:var(--amber-bg)}
.jt-shirt{width:44px;height:44px;flex-shrink:0;display:flex;align-items:center;justify-content:center;
  color:var(--text3)}
.jt-shirt img{width:100%;height:100%;object-fit:contain}
.jt-shirt svg{width:22px;height:22px}
.jt-txt{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.jt-txt strong{font-size:13.5px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.jt-txt small{font-size:11px;color:var(--text2)}
.jt-row .btn{flex-shrink:0}
.jl-acts{display:flex;gap:8px;margin:4px 0 14px}
.jl-cat{margin-top:16px}
.jl-cat-hd{display:flex;align-items:center;gap:9px;font-family:var(--font-display);
  font-stretch:var(--display-stretch);font-size:13px;font-weight:800;letter-spacing:.06em;
  text-transform:uppercase;color:var(--text2);padding-bottom:7px;margin-bottom:10px;
  border-bottom:1px solid var(--border)}
.jl-cat-hd span{font-family:var(--font-body);font-size:11px;font-weight:700;letter-spacing:0;
  padding:1px 8px;border-radius:20px;background:var(--bg4);color:var(--text3)}
.jl-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(108px,1fr));gap:11px}
.jl-card{position:relative;display:flex;flex-direction:column;align-items:center;gap:5px;
  padding:11px 8px 9px;border-radius:10px;border:1px solid var(--border);background:var(--bg3);
  text-align:center}
body.light .jl-card{background:#fff}
.jl-shirt{width:66px;height:66px}
.jl-shirt img{width:100%;height:100%;object-fit:contain}
.jl-name{font-size:11px;font-weight:600;line-height:1.25;color:var(--text)}
.jl-code{font-size:10px;font-weight:800;letter-spacing:.06em;color:var(--text3)}
.jl-del{position:absolute;top:3px;right:3px;opacity:0;transition:opacity .16s}
.jl-card:hover .jl-del,.jl-del:focus-visible{opacity:1}
.jp-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:9px;
  max-height:52vh;overflow-y:auto;padding:2px}
.jp-card{display:flex;flex-direction:column;align-items:center;gap:5px;padding:10px 6px;
  border-radius:10px;border:1px solid var(--border);background:var(--bg3);cursor:pointer;
  font-family:inherit;font-size:10.5px;font-weight:600;color:var(--text);text-align:center;line-height:1.25}
.jp-card:hover{border-color:var(--gold-border)}
.jp-card.on{border-color:var(--accent-fill);background:var(--gold-bg)}
.jp-shirt{width:58px;height:58px;display:flex;align-items:center;justify-content:center}
.jp-shirt img{width:100%;height:100%;object-fit:contain}
.jp-shirt.none{color:var(--text3)}
.jp-shirt.none svg{width:24px;height:24px}
.jl-queue{margin-top:11px;display:flex;flex-direction:column;gap:4px}
.jq-row{display:flex;align-items:center;gap:9px;padding:6px 10px;border-radius:8px;
  background:var(--bg3);font-size:12px}
.jq-row.ok{color:var(--green)}
.jq-row.bad{color:var(--red)}
.jq-n{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text2)}
.jq-s{font-weight:700;font-variant-numeric:tabular-nums}

/* ── TEAM PRESENTATION ─────────────────────────────────────────
   The printed running order and the screen are one artefact, so this
   sheet is styled to survive html2pdf: white ground, black text, no
   theme variables inside the table. What the venue is handed and what
   the organiser sees while building it can then never disagree.
   ──────────────────────────────────────────────────────────── */
.pres-card{padding:0;overflow:hidden;background:#ffffff;color:#0f172a}
.pres-sheet{background:#ffffff;color:#0f172a;padding:10px 12px}
/* The event's mark leads on the left and is given room; Golazo signs off
   small on the right. Only on this sheet — the start list keeps its own. */
.pres-hd{gap:12px;align-items:center}
.pres-hd .ssh-logo{max-height:56px}
.pres-tbl{width:100%;border-collapse:collapse;font-size:11px}
.pres-tbl th{text-align:left;font-weight:800;color:#0f172a;padding:5px 8px;
  background:#f1f5f9;border-bottom:2px solid #cbd5e1;white-space:nowrap}
.pres-tbl td{padding:4px 8px;border-bottom:1px solid #e2e8f0;color:#0f172a;vertical-align:middle}
.pres-tbl tr{page-break-inside:avoid;break-inside:avoid}
.pres-tbl tr:nth-child(even) td{background:#f8fafc}
.pres-tbl .c-hours{font-variant-numeric:tabular-nums;white-space:nowrap;width:110px}
.pres-tbl .c-country{width:110px}
.pres-tbl .c-class{width:130px;white-space:nowrap}
/* The controls live ON the white sheet, so they cannot borrow the app's
   dark chrome — an .icon-btn here painted a dark teal block on white paper.
   These are drawn for the sheet: no fill, slate strokes, and they only
   gain a background on hover. */
.pres-tbl .c-ord{width:78px;white-space:nowrap;text-align:right}
.pres-grip,.pres-edit{display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;border-radius:7px;border:0;background:none;color:#94a3b8;
  vertical-align:middle}
.pres-grip svg,.pres-edit svg{width:15px;height:15px}
.pres-grip{cursor:grab}
.pres-edit{cursor:pointer;font-family:inherit}
.pres-edit:hover,.pres-grip:hover{background:#e2e8f0;color:#0f172a}

/* Dragging. The row being carried fades; the row under the pointer shows a
   line on the edge the team will land against, so the drop is never a
   guess. */
.pres-tbl tr[draggable="true"]{cursor:grab}
.pres-tbl tr.dragging{opacity:.4;cursor:grabbing}
.pres-tbl tr.dragging .pres-grip{cursor:grabbing}
.pres-tbl tr.drag-over td{box-shadow:inset 0 2px 0 0 #b45309}
.pres-tbl tr.drag-under td{box-shadow:inset 0 -2px 0 0 #b45309}
/* The name starts at the same place on every row, flag or no flag: the
   cell is a two-column grid rather than a row that shrinks to its
   contents. Without it the federations with no flag read as a staircase
   down the page. */
.pres-tbl .team-cell{display:grid;grid-template-columns:22px minmax(0,1fr);
  align-items:center;gap:8px}
/* The empty slot. Faint, not invisible — it is also the list of
   federations whose nation code nothing recognised. */
.pres-tbl .flag-none{width:22px;height:16px;border-radius:3px;
  border:1px dashed #cbd5e1;background:#f8fafc}
.pres-tbl .nat-pill{background:#e2e8f0;border-color:#cbd5e1;color:#0f172a}
.pres-tbl .flag{width:22px;height:auto;box-shadow:none;border:1px solid #cbd5e1}
.pres-tbl-wrap{overflow-x:auto}
.pres-tbl .jersey-none{width:22px;height:22px;border-radius:4px;
  border:1px dashed #cbd5e1;background:#f8fafc}
.pres-tbl .jersey{width:22px;height:22px}
/* ── THE SPONSOR STRIP SITS ON THE FOOT OF THE PAGE ────────────
   Not under the last row. The presentation running order is twenty-two
   lines on a sheet with room for forty, so the strip used to stop
   somewhere in the middle of the paper with a hand's width of nothing
   below it — which reads as a page that was cut off, not as a page that
   finished.

   Nothing here does the pushing, and that is deliberate. The obvious way
   is to make .pres-sheet a flex column and give this margin-top:auto, and
   that is exactly what broke the export: turning the sheet into a flex
   container re-lays-out every child of it at once — the masthead, the
   table wrapper, the strip — and the photographed page came back with the
   sheet shrunk into a corner. A page-fitting trick is not worth a layout
   model change on a sheet that was laying out correctly.

   So the space is put in by the export instead, as one spacer element of a
   measured height, and only in the copy that is about to be printed. See
   padToPageFoot(); [data-page-foot] on this element is what it aims at.
   The margin below is the breathing space on a sheet that already fills
   its page and gets no spacer at all. */
.pres-footer-wrap{margin-top:18px}
/* The reorder buttons are a working tool, not part of the sheet. They
   carry data-html2canvas-ignore, which the PDF capture honours natively;
   this is the same exclusion for the browser's own print dialog. */
@media print{ .pres-tbl .c-ord{display:none} }


/* ── THE TEAM SHEET ON PAPER ───────────────────────────────────
   Exact A4 at 96 dpi — the unit html2canvas photographs in — and a
   fixed height rather than a minimum: this document is one page by
   construction, and .ts-body is whatever is left between the masthead
   and the footer. Everything inside the grid is sized in em off the
   grid's own font-size, so slFitTeamSheet() shrinking that one number
   shrinks the whole field proportionally instead of reflowing it.

   Nothing here reads a theme variable. It is printed on white whatever
   the app is set to, the same rule the schedule sheet and the booklet
   above it follow — and the reason the edition's logo needs no light
   plate on this page.
   ──────────────────────────────────────────────────────────── */
.ts-doc{width:794px;height:1120px;background:#ffffff;color:#0f172a;padding:18px 22px;
  display:flex;flex-direction:column;overflow:hidden;
  font-family:inherit;letter-spacing:normal;line-height:1.35}
.ts-doc *{box-sizing:border-box}

.ts-hd{display:flex;align-items:center;gap:14px;padding-bottom:10px;margin-bottom:10px;
  border-bottom:3px solid #0f172a;flex-shrink:0}
.ts-hd-mark{height:26px;width:auto;flex-shrink:0}
.ts-hd-t{flex:1;min-width:0}
/* Set open rather than tight: at this size a negative track ran the
   edition name together into one word. */
.ts-hd-t h1{font-size:20px;font-weight:800;letter-spacing:.02em;margin:0;line-height:1.2}
.ts-hd-t p{font-size:11px;color:#334155;margin:2px 0 0;font-weight:700;
  text-transform:uppercase;letter-spacing:.05em}
.ts-hd-t span{display:block;font-size:10.5px;color:#64748b;margin-top:2px}
.ts-hd-ev{height:42px;width:auto;max-width:140px;object-fit:contain;flex-shrink:0}

/* The organiser's own line. Set apart from the masthead so it reads as
   something added rather than as part of the race's title. */
.ts-note{font-size:10.5px;line-height:1.4;color:#334155;background:#f8fafc;
  border-left:3px solid #0f172a;border-radius:0 6px 6px 0;padding:6px 9px;
  margin-bottom:8px;flex-shrink:0;white-space:pre-wrap}

.ts-body{flex:1;min-height:0;display:flex;overflow:hidden}
.ts-grid{width:100%;display:grid;gap:6px;align-content:start;
  font-size:calc(10px * var(--ts-fit,1))}

/* A dark cap on each card: on a page of twenty-two blocks it is what
   separates one team from the next at arm's length, before any of the
   words are read. */
.ts-team{border:1px solid #cbd5e1;border-top:3px solid #0f172a;border-radius:5px;
  padding:.4em .5em .35em;display:flex;flex-direction:column}
.ts-team-hd{display:flex;align-items:center;gap:.4em;padding-bottom:.3em;margin-bottom:.3em;
  border-bottom:1px solid #e2e8f0}
.ts-shirt{width:2.4em;height:2.4em;object-fit:contain;flex-shrink:0}
.ts-shirt-none{border:1px dashed #cbd5e1;border-radius:4px}
.ts-team-t{flex:1;min-width:0}
.ts-team-t strong{display:block;font-size:.92em;font-weight:800;line-height:1.15;
  text-transform:uppercase;max-height:2.3em;overflow:hidden}
.ts-team-t span{display:flex;align-items:center;gap:.3em;font-size:.78em;
  color:#64748b;font-weight:700;margin-top:.1em}
.ts-team-t span img{width:1.2em;height:auto;border-radius:1px}
.ts-ds{font-size:.78em;color:#334155;line-height:1.3;margin:-.1em 0 .25em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ts-ds b{font-weight:800;color:#0f172a;letter-spacing:.04em}
.ts-riders{list-style:none;margin:0;padding:0}
.ts-riders li{display:flex;align-items:baseline;gap:.4em;font-size:.9em;
  line-height:1.4;white-space:nowrap;overflow:hidden}
.ts-bib{flex-shrink:0;min-width:2em;font-weight:800;color:#0f172a;
  font-variant-numeric:tabular-nums}
.ts-rn{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}
.ts-rnat{flex-shrink:0;font-size:.82em;color:#94a3b8;font-weight:700}
/* With a flag the cell becomes a little row of its own so the flag and the
   code sit on one baseline. Sized in em off the grid, like everything else
   on this sheet, so slFitTeamSheet() shrinks it with the rest. */
.ts-rnat.has-flag{display:inline-flex;align-items:center;gap:.3em}
.ts-rnat .flag{width:1.35em;height:auto;border-radius:1px;box-shadow:none;
  border:.5pt solid #cbd5e1}

/* The masthead pickers in the team-sheet dialog. Its own row across the
   whole dialog: dropped into the three-column field grid as a fourth item
   it took the first cell and squeezed the header, footer and column
   pickers into a stack of slivers. */
.ts-fields .ts-head-pick{grid-column:1 / -1;min-width:0}
.ts-hd-opts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:2px 16px}
.ts-hd-opt{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--text2);
  cursor:pointer;min-height:26px;min-width:0}
.ts-hd-opt input{width:15px;height:15px;flex-shrink:0;accent-color:var(--gold2);margin:0}
.ts-hd-opt span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ── PARTICIPANTS PER FEDERATION, ON PAPER ─────────────────────
   Two landscape A4 pages (fedSheetHtml in js/startlists.js): the
   overview, then the table across the full width. Ink only — no theme
   variable reaches these pages — and the house amber for the bars and
   the totals. Everything in a body is sized in em off --pfs-fit, so
   fsFitSheet() shrinks a page's type as one. No text-overflow ellipsis
   anywhere: html2canvas drew "ME/MU23 RR" as "ME/ MU23RR" through it. */
.pfs-pages{width:1122px}
.pfs-doc{width:1122px;height:792px;background:#ffffff;color:#0f172a;padding:24px 30px 18px;
  display:flex;flex-direction:column;overflow:hidden;font-family:inherit;letter-spacing:normal;line-height:1.3}
.pfs-doc *{box-sizing:border-box}
.pfs-hd{display:flex;align-items:center;gap:16px;padding-bottom:12px;border-bottom:3px solid #0f172a;flex-shrink:0}
.pfs-mark{height:34px;width:auto;flex-shrink:0}
.pfs-hd-t{flex:1;min-width:0}
.pfs-hd-t h1{margin:0;font-size:22px;font-weight:800;line-height:1.15;color:#0f172a}
.pfs-hd-t h1 em{font-style:normal;font-weight:600;color:#64748b}
.pfs-hd-t p{margin:3px 0 0;font-size:11.5px;font-weight:700;color:#475569;text-transform:uppercase;letter-spacing:.05em}
.pfs-ev{height:46px;width:auto;max-width:150px;object-fit:contain;flex-shrink:0}

.pfs-kpis{display:flex;gap:0;margin:14px 0 16px;border:1px solid #e2e8f0;border-radius:8px;flex-shrink:0;background:#f8fafc}
.pfs-kpi{flex:1;padding:10px 16px;min-width:0}
.pfs-kpi + .pfs-kpi{border-left:1px solid #e2e8f0}
.pfs-kpi b{display:block;font-size:28px;font-weight:800;line-height:1.1;color:#0f172a;font-variant-numeric:tabular-nums}
.pfs-kpi span{display:block;font-size:10.5px;font-weight:700;color:#64748b;text-transform:uppercase;letter-spacing:.06em;margin-top:3px}

.pfs-body{flex:1;min-height:0;display:grid;gap:30px}
.pfs-ov{grid-template-columns:minmax(0,1fr) minmax(0,1.15fr)}
.pfs-tb{grid-template-columns:minmax(0,1fr);margin-top:14px}
.pfs-main,.pfs-col{min-height:0;min-width:0;overflow:hidden}

/* PAGE 2 — the table. */
.pfs-tbl{width:100%;border-collapse:collapse;font-size:calc(13px * var(--pfs-fit,1))}
.pfs-tbl th{font-size:.74em;font-weight:800;text-transform:uppercase;letter-spacing:.03em;color:#475569;
  text-align:left;padding:.45em .45em;border-bottom:2px solid #0f172a;vertical-align:bottom;line-height:1.2}
.pfs-tbl td{padding:.42em .45em;border-bottom:1px solid #e2e8f0;vertical-align:middle}
.pfs-tbl tbody tr:nth-child(even) td{background:#f8fafc}
.pfs-tbl .pfs-n{width:2.2em;color:#94a3b8;font-weight:700;font-variant-numeric:tabular-nums;text-align:right;padding-right:.7em}
.pfs-tbl .pfs-r{text-align:center;font-variant-numeric:tabular-nums}
.pfs-tbl th.pfs-r{text-align:center;overflow-wrap:anywhere;min-width:3.2em}
.pfs-tbl td.pfs-r.zero{color:#cbd5e1}
.pfs-tbl .pfs-t{text-align:right;font-weight:800;font-variant-numeric:tabular-nums;white-space:nowrap;color:#a84d08;padding-left:.9em}
.pfs-tbl th.pfs-t{color:#475569}
.pfs-tbl .pfs-t small{display:block;font-size:.75em;font-weight:600;color:#64748b}
.pfs-unit{display:flex;align-items:center;gap:.6em;min-width:0}
.pfs-flag{width:1.75em;height:auto;flex-shrink:0;border-radius:2px;border:.5pt solid #cbd5e1;box-shadow:none}
.pfs-flag-none{display:inline-block;height:1.2em;background:#f1f5f9}
.pfs-unit-t{min-width:0;display:flex;align-items:baseline;gap:.5em;white-space:nowrap}
.pfs-unit-t strong{font-weight:700;color:#0f172a}
.pfs-unit-t small{flex-shrink:0;font-size:.78em;font-weight:700;color:#94a3b8;letter-spacing:.02em}
.pfs-total td{border-top:2px solid #0f172a;border-bottom:0;font-weight:800;background:#ffffff!important}
.pfs-total .pfs-u{text-transform:uppercase;letter-spacing:.06em;font-size:.85em}
.pfs-total .pfs-t{color:#0f172a}

/* PAGE 1 — the bars. */
.pfs-col{display:flex;flex-direction:column;font-size:calc(14px * var(--pfs-fit,1))}
.pfs-col h2{margin:0 0 .8em;font-size:.8em;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:#475569;
  padding-bottom:.5em;border-bottom:2px solid #0f172a}
.pfs-bars{display:flex;flex-direction:column;gap:.6em;min-width:0}
.pfs-bars-2{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:0 1.6em}
.pfs-bar{display:grid;grid-template-columns:10em minmax(0,1fr) 2.4em;align-items:center;gap:.7em}
.pfs-bars-2 .pfs-bar{grid-template-columns:8em minmax(0,1fr) 2.2em}
.pfs-bar-l{display:flex;align-items:center;gap:.5em;min-width:0;font-weight:700;color:#0f172a;font-size:.92em;line-height:1.2}
.pfs-bar-l .pfs-flag{width:1.5em}
.pfs-bar-track{height:.8em;background:#f1f5f9;border-radius:99px;overflow:hidden}
.pfs-bar-track i{display:block;height:100%;background:#d97706;border-radius:99px}
.pfs-bars-nat .pfs-bar-track i{background:#0f172a}
.pfs-bar b{text-align:right;font-variant-numeric:tabular-nums;font-weight:800}

.pfs-ft{display:flex;justify-content:space-between;gap:16px;margin-top:10px;padding-top:8px;border-top:1px solid #e2e8f0;
  font-size:9.5px;color:#64748b;flex-shrink:0}
.ts-head-pick input[type="text"]{width:100%;box-sizing:border-box}
/* The nationality picker sits under the two overrides, label beside the
   select rather than above it — the block is already six ticks tall. */
.ts-hd-nat{display:flex;align-items:center;gap:10px;margin-top:8px;flex-wrap:wrap}
.ts-hd-nat > span{font-size:11px;font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;color:var(--text3)}
.ts-hd-nat select{flex:1;min-width:160px;max-width:320px}
@media (max-width:900px){ .ts-hd-opts{grid-template-columns:repeat(2,minmax(0,1fr))} }
@media (max-width:520px){ .ts-hd-opts{grid-template-columns:1fr} }

.ts-ft{display:flex;align-items:flex-end;justify-content:space-between;gap:14px;
  border-top:1px solid #cbd5e1;padding-top:6px;margin-top:8px;flex-shrink:0;
  font-size:9px;color:#64748b}
.ts-ft-l{min-width:0;white-space:pre-wrap}
.ts-ft-r{flex-shrink:0;white-space:nowrap}
/* A sponsor banner is not a footnote: it runs the full width of the sheet,
   the same width as the field of teams above it, with the print stamp
   tucked underneath rather than stealing a column from it. */
.ts-ft.has-banner{display:block}
.ts-ft.has-banner .ts-footer-banner{width:100%}
.ts-ft.has-banner .ts-footer-banner img{width:100%;height:auto;display:block}
.ts-ft.has-banner .ts-ft-r{display:block;text-align:right;margin-top:3px}

/* ── THE DIALOG AROUND IT ──────────────────────────────────────
   The preview is the page itself at full size, scaled down by a
   transform. A transform does not change the box the layout reserves,
   so the wrapper carries the scaled-down dimensions and clips to them. */
/* minmax(0,…) on every track. Without it a grid item is floored at the
   width of its own content, and one long label pushed the row — and the
   dialogue with it — into a sideways scroll. */
/* THREE COLUMNS, AND ONLY THE TOP ROW USES THEM. The third track was
   `auto`, so the countries filter — thirty tick-chips in one column —
   set the height of the whole row: a tall thin ladder of country codes
   beside two mostly empty columns. The filters span the width now and
   lay their chips out in a wrapping grid, which is what a list of
   thirty three-letter codes wants to be. */
.ts-fields{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr) minmax(0,190px);
  gap:12px 14px;margin-bottom:14px;max-width:100%;align-items:start}
.ts-fields > .field{min-width:0}
.ts-fields input,.ts-fields select{max-width:100%;box-sizing:border-box}
/* The upload buttons carry a whole sentence — "Upload footer / sponsor
   banner" — and pushed their own column wider than the grid. They may
   shrink, and the label ends in an ellipsis rather than in the column
   next door. */
.ts-fields .btn{min-width:0;max-width:100%}
.ts-fields .btn span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.ts-facet{grid-column:1 / -1}
.ts-facet .chk-grid{grid-template-columns:repeat(auto-fill,minmax(96px,1fr))}
/* Only the COUNTRIES list is capped. A race has a handful of categories
   and they all fit; the field of a championship brings thirty nations,
   and thirty chips is a dialogue you scroll past to reach the buttons.
   Capping both meant the five-chip category row drew a scrollbar for a
   single sub-pixel of overflow. */
#i-ts-nats{max-height:176px;overflow:hidden auto}
.ts-facet .chk{padding:7px 9px;gap:7px;min-height:38px}
.ts-facet .chk-t{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (max-width:820px){ .ts-fields{grid-template-columns:minmax(0,1fr) minmax(0,1fr)} }
@media (max-width:640px){ .ts-fields{grid-template-columns:1fr} }
.ts-prev{background:#e2e8f0;border-radius:10px;padding:15px;display:flex;
  justify-content:center;overflow:auto}
.ts-prev-box{width:calc(794px * var(--ts-k,.5));height:calc(1120px * var(--ts-k,.5));
  overflow:hidden;flex-shrink:0;border-radius:2px;box-shadow:0 6px 20px rgba(15,23,42,.28)}
/* 1120, not 1123: A4's own proportion, less the two pixels that were
   costing a blank second page. Kept in step with TS_PAGE_H in
   js/startlists.js. */
.ts-prev-in{width:794px;height:1120px;transform:scale(var(--ts-k,.5));transform-origin:top left}

/* ── PRINTING ONE SHEET AS VECTOR ──────────────────────────────
   printSheetVector() in js/utils.js drops a copy of a sheet in here and
   hands the page to the browser's own printer, which writes the text as
   text rather than as a photograph of text. Off-screen the rest of the
   time: it must not be display:none, because a hidden element has no
   layout and images inside it are never fetched. */
#print-root{position:fixed;left:-20000px;top:0;width:794px;z-index:-1;background:#fff}

@media print{
  body.printing-sheet > *:not(#print-root){display:none!important}
  /* display:block, because the app's body is a flex column. #print-root as a
     flex item measured 0 wide and the sheet only landed on the paper by
     starting at the left edge; as a block it fills the page and the sheet's
     own `margin:0 auto` centres it, whatever width the sheet was built to. */
  body.printing-sheet{background:#fff!important;height:auto;overflow:visible;display:block}
  body.printing-sheet #print-root{position:static;left:auto;top:auto;z-index:auto;
    width:auto;display:block!important}
  /* The sheets already carry their own inner padding and are built to the
     printable width, so the page itself gives none away. */
  body.printing-sheet #print-root.pad{padding:6mm}
  @page{size:A4 portrait;margin:0}
}

/* ── THE EMERGENCY BUTTON ──────────────────────────────────────
   "Log medical incident" is pressed with a rider on the ground and a
   phone in the other hand. In the house colour it read as one more action
   among the eight underneath it, so it is red and it beats — the two
   things an eye finds without being aimed.

   The pulse is a shadow and a hair of scale, never a colour flash: a
   button that blinks between two colours is hard to read at the moment
   it matters most. */
.btn.btn-emergency{
  background:#dc2626;
  border:1px solid #ef4444;
  color:#ffffff;
  font-weight:800;
  animation:emergency-pulse 1.9s ease-in-out infinite;
}
/* The link and the handset beside it: icon buttons, square, never
   labelled. Labelled they gave the title of this screen a third line on
   a phone before anything on it had been read. */
.med-hd-actions{gap:8px;margin-left:auto}
/* Beside the title, not wrapped under it. The heading is two lines long
   on a phone, and wrapped the buttons landed at the far LEFT of a third
   line — the corner is where a heading's actions belong. */
.page-hd-medical{flex-wrap:nowrap;align-items:flex-start}
.page-hd-medical > div:first-child{flex:1;min-width:0}
/* The Field tracker button carries a label now, so this row is allowed to
   wrap again — nowrap squeezed it to an ellipsis on a narrow desk. */
.page-hd-medical .med-hd-actions{flex-wrap:wrap;justify-content:flex-end}
.med-hd-actions .btn.icon-only{padding:0;width:40px;height:40px;justify-content:center}
.med-hd-actions .btn.icon-only svg{width:17px;height:17px}

/* ── THE NUMBERS BEHIND THE HANDSET ────────────────────────────
   One row per contact inside the ⋮ drawer: the label in the colour it
   carries, the number under it and dialable, the pencil and the bin at
   the end. The card version of this was the tallest block on the
   screen and stood between the title and the map. */
.med-ec-menu{min-width:268px}
.med-ec-hd{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;
  color:var(--text3);padding:4px 10px 2px}
.med-ec-row{display:flex;align-items:center;gap:8px;padding:8px 10px;border-radius:9px;
  border-left:3px solid var(--border);background:var(--bg3);margin-top:4px}
.med-ec-t{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.med-ec-t strong{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.03em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.med-ec-num{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:14.5px;font-weight:800;
  color:var(--text);text-decoration:none}
.med-ec-num:hover{text-decoration:underline}
.med-ec-acts{display:flex;gap:2px;flex-shrink:0}

/* ── THE NUMBERS ON THE SURFACE (desk) ─────────────────────────
   One low strip of chips under the title, not the four full-width cards
   this screen used to open with — the hospitals still have to start
   above the fold. See medContactsBarHtml(). */
.med-ec-bar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  margin:0 0 14px;padding:10px 12px;border-radius:12px;
  background:var(--bg2);border:1px solid var(--border)}
.med-ec-bar-k{display:inline-flex;align-items:center;gap:6px;flex-shrink:0;
  font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;
  color:var(--text3);padding-right:4px}
.med-ec-bar-k svg{width:14px;height:14px}
.med-ec-chip{display:inline-flex;align-items:center;gap:6px;min-width:0;
  padding:5px 9px;border-radius:9px;background:var(--bg3);
  border:1px solid var(--border);border-left:3px solid var(--border2)}
.med-ec-chip .med-ec-t{gap:0}
.med-ec-chip .med-ec-num{font-size:13.5px}
.med-ec-bar-none{font-size:12.5px;color:var(--text3)}
.med-ec-add{flex-shrink:0}
/* The chip's own edit and delete stay quiet until the chip is under the
   cursor — four numbers each carrying two live icons read as a toolbar,
   and this strip is meant to be read, not operated. */
.med-ec-chip .med-ec-acts{opacity:0;transition:opacity .15s}
.med-ec-chip:hover .med-ec-acts,
.med-ec-chip:focus-within .med-ec-acts{opacity:1}

/* RED, ON THE PHONE. The drawer behind this handset is opened when
   somebody is down on the road. See medContactsMenuHtml(). */
.med-ec-btn{background:linear-gradient(135deg,#dc2626,#ef4444);border-color:#ef4444;color:#fff}
.med-ec-btn svg{color:#fff}
.med-ec-btn:hover,.med-ec-btn:focus-visible{background:linear-gradient(135deg,#b91c1c,#dc2626);
  border-color:#f87171;color:#fff}

/* THE DOCTORS' LINK, ASKING TO BE NOTICED. Handed out five times on a
   race morning and, as a grey chain in the corner, never found. Named,
   red, and breathing — the pulse stops for anyone who asked their system
   for less motion, the colour and the name do not. */
.med-fieldlink{background:linear-gradient(135deg,#dc2626,#ef4444);border-color:#ef4444;color:#fff;
  animation:medFieldPulse 2.4s ease-in-out infinite}
.med-fieldlink svg{color:#fff}
.med-fieldlink:hover,.med-fieldlink:focus-visible{background:linear-gradient(135deg,#b91c1c,#dc2626);
  border-color:#f87171;color:#fff}
@keyframes medFieldPulse{
  0%,100%{box-shadow:0 0 0 0 rgba(239,68,68,.5)}
  70%{box-shadow:0 0 0 9px rgba(239,68,68,0)}
}
@media (prefers-reduced-motion:reduce){.med-fieldlink{animation:none}}

/* THE MAP CARD'S DRAWER, UNFOLDED. Icons only — the names ride the
   tooltip and the aria-label. See medMapActionsHtml(). */
.med-map-acts{display:flex;align-items:center;gap:6px;flex-shrink:0}
.med-map-acts .btn span{display:none}

/* ── A CARD'S OWN HEADING ROW ──────────────────────────────────
   Title left, one control right, and the control never wraps under the
   title — that wrap is what put three rows of buttons above a map. */
.med-card-hd{display:flex;align-items:flex-start;justify-content:space-between;
  gap:10px;margin-bottom:10px}
.med-card-hd h3{margin:0;min-width:0}
.med-card-hd .sched-menu,.med-card-hd > .btn{flex-shrink:0}
.med-card-hd .btn.icon-only{padding:0;width:34px;height:34px;justify-content:center}
.med-card-hd .btn.icon-only svg{width:16px;height:16px}

/* ── WHICH DAY ────────────────────────────────────────────────
   The chosen day is FILLED, not merely un-ghosted: the two old button
   states differed by a border that vanished in daylight, so the bar
   read as five identical chips. Today carries its own mark, because
   "which of these is now" should not need the dates read. */
.med-daybar{display:flex;gap:6px;overflow-x:auto;margin:10px 0 12px;padding-bottom:2px;
  scrollbar-width:none;-ms-overflow-style:none}
.med-daybar::-webkit-scrollbar{display:none}
.med-day{flex:none;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;
  padding:7px 13px;border-radius:999px;border:1px solid var(--border);background:var(--bg3);
  color:var(--text2);font-family:inherit;font-size:12.5px;font-weight:700;cursor:pointer;
  transition:background .15s,color .15s,border-color .15s}
.med-day:hover{border-color:var(--gold-border);color:var(--text)}
.med-day.is-on{background:linear-gradient(135deg,var(--accent-fill),var(--accent-fill2));
  border-color:transparent;color:var(--on-accent);box-shadow:var(--shadow)}
.md-today{font-size:9px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;
  padding:1px 6px;border-radius:999px;background:var(--gold);color:#0b1120}
.med-day.is-on .md-today{background:rgba(255,255,255,.24);color:inherit}
.btn.btn-emergency:hover,.btn.btn-emergency:focus-visible{
  background:#b91c1c;border-color:#f87171;color:#fff;
}
.btn.btn-emergency svg{stroke:#ffffff}

@keyframes emergency-pulse{
  0%,100%{ box-shadow:0 0 0 0 rgba(220,38,38,.55); transform:scale(1) }
  50%    { box-shadow:0 0 0 10px rgba(220,38,38,0); transform:scale(1.025) }
}

/* On a phone it is the call to action of the screen, so it takes the full
   width under the heading rather than sitting in the corner of it. */
@media (max-width:640px){
  .btn.btn-emergency{width:100%;justify-content:center;min-height:48px;font-size:15px}
}

/* Somebody who has asked for less movement still gets the colour, which is
   what carries the meaning; the beating stops. */
@media (prefers-reduced-motion:reduce){
  .btn.btn-emergency{animation:none;box-shadow:0 0 0 3px rgba(220,38,38,.35)}
}

.acc-top{display:flex;gap:12px;align-items:stretch;margin-bottom:18px;flex-wrap:wrap}
/* The deck asks for a little more of the row than the single card did:
   a desk and its PPO side by side is what saves the height, and under
   ~1280 px they stack again. */
.acc-top .acc-centre-bar{flex:1.4 1 420px;min-width:0;margin-bottom:0}
.acc-top .acc-stats{flex:2 1 460px;min-width:0;margin-bottom:0;
  grid-template-columns:repeat(2,minmax(0,1fr));align-content:start}
.acc-top.no-centre .acc-stats{flex:1 1 100%;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,190px),1fr))}
@media (min-width:1500px){
  /* Wide enough for one unbroken row of four beside the card. */
  .acc-top .acc-stats{grid-template-columns:repeat(4,minmax(0,1fr))}
}
@media (max-width:1100px){
.acc-top{display:block}
.acc-top .acc-centre-bar{margin-bottom:12px}
.acc-top .acc-stats{grid-template-columns:repeat(auto-fit,minmax(min(100%,190px),1fr))}
}
.acc-stats{display:grid;gap:12px;margin-bottom:18px;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,190px),1fr))}
.acc-stat{position:relative;display:flex;flex-direction:column;gap:1px;
  background:var(--bg2);border:1px solid var(--border);border-radius:12px;
  padding:14px 16px 13px 18px;box-shadow:var(--shadow);overflow:hidden}
.acc-stat::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;
  background:var(--text3)}
.acc-stat.t-blue::before{background:#3b82f6}
.acc-stat.t-violet::before{background:#8b5cf6}
.acc-stat.t-green::before{background:var(--primary,#f59e0b)}
.acc-stat-n{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:26px;font-weight:800;line-height:1.05;color:var(--text)}
.acc-stat-l{font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  color:var(--text2)}
.acc-stat-s{font-size:11px;color:var(--text3)}
/* The budget tile is a switch as well as a number. */
.ht-stat-cur{cursor:pointer;user-select:none}
.ht-stat-cur:hover{border-color:var(--primary,#f59e0b)}
.ht-stat-cur .acc-stat-s{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.acc-tabs{display:flex;gap:2px;flex-wrap:wrap;margin-bottom:16px;
  border-bottom:1px solid var(--border)}
.acc-tab{display:inline-flex;align-items:center;gap:7px;
  background:none;border:0;border-bottom:2px solid transparent;margin-bottom:-1px;
  padding:9px 14px;cursor:pointer;color:var(--text2);
  font-family:inherit;font-size:13px;font-weight:700;
  transition:color .14s,border-color .14s}
.acc-tab svg{width:15px;height:15px}
.acc-tab:hover{color:var(--text)}
.acc-tab.on{color:var(--primary,#f59e0b);border-bottom-color:var(--primary,#f59e0b)}
.acc-search{display:flex;align-items:center;gap:10px;
  padding:4px 14px;margin-bottom:12px}
.acc-search-ico{display:flex;color:var(--text3);flex-shrink:0}
.acc-search-ico svg{width:17px;height:17px}
.acc-search .input{flex:1;min-width:0;border:0;background:none;box-shadow:none;
  padding:10px 0;font-size:14px}
.acc-search .input:focus{outline:none;box-shadow:none}
.acc-search:focus-within{border-color:var(--primary,#f59e0b);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--primary,#f59e0b) 18%,transparent)}
.acc-pills{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px}
.acc-pills.sub{margin-bottom:18px}
.acc-pills .btn{white-space:nowrap}
.acc-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}
.acc-tbl-wrap{padding:0;overflow-x:auto}
.acc-tbl{width:100%;border-collapse:collapse;font-size:13px}
.acc-tbl th{position:sticky;top:0;z-index:1;text-align:left;white-space:nowrap;
  padding:10px 12px;font-size:10px;font-weight:800;letter-spacing:.06em;
  text-transform:uppercase;color:var(--text3);
  background:var(--bg2);border-bottom:1px solid var(--border)}
.acc-tbl td{padding:10px 12px;border-bottom:1px solid var(--border);vertical-align:top}
.acc-tbl tbody tr:last-child td{border-bottom:0}
.acc-tbl tbody tr:hover td{background:var(--bg3)}
.acc-tbl tr.is-done td{opacity:.55}
.acc-tbl .c-nr{width:76px;white-space:nowrap}
.acc-tbl .c-nr strong{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:15px;font-weight:800}
.acc-nr-box{display:inline-flex;flex-direction:column;align-items:center;
  min-width:52px;max-width:100%;padding:2px 6px 3px;border:2px solid currentColor;
  border-radius:6px;background:color-mix(in srgb,currentColor 8%,transparent);
  line-height:1.05}
.acc-series{display:block;max-width:100%;font-size:9px;font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;margin-top:1px;opacity:.85;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.acc-tbl .c-cat{width:120px}
.acc-tbl .c-plate{width:110px}
.acc-tbl .c-stick{width:130px}
.acc-tbl .c-chk{width:48px;text-align:center}
.acc-tbl .c-act{width:76px;white-space:nowrap;text-align:right}
.acc-sub{font-size:11.5px;color:var(--text3)}
/* The chip that stands for the rest of a badge cell. A button, not a
   span: it is the one thing in that cell anybody clicks. */
.acc-more{display:inline-flex;align-items:center;gap:2px;padding:2px 7px;border-radius:6px;
  border:1px dashed var(--border2);background:transparent;color:var(--text3);
  font-family:inherit;font-size:10.5px;font-weight:700;cursor:pointer;line-height:1.5}
.acc-more:hover{border-style:solid;border-color:var(--gold);color:var(--text)}
/* The UCI id reads as a number, so it is set as one — tabular figures
   line up under each other and a transposed digit shows. */
.c-uci{white-space:nowrap}
.acc-uci{display:block;font-variant-numeric:tabular-nums;font-size:12px;color:var(--text)}
.c-uci .acc-sub{font-variant-numeric:tabular-nums}
.acc-none{color:var(--text3)}
.acc-plate{display:inline-block;font-family:ui-monospace,Menlo,Consolas,monospace;
  font-size:12px;font-weight:700;letter-spacing:.02em;
  background:var(--bg3);border:1px solid var(--border2,var(--border));
  border-radius:5px;padding:2px 6px;white-space:nowrap}
.acc-creds{display:flex;flex-wrap:wrap;gap:4px}
.acc-cred{display:inline-flex;align-items:center;gap:4px;
  font-size:11px;font-weight:600;line-height:1.5;
  border-radius:5px;padding:2px 7px 2px 4px;
  background:var(--bg3);border:1px solid var(--border);color:var(--text2)}
.acc-cred b{display:inline-flex;align-items:center;justify-content:center;
  min-width:16px;height:16px;border-radius:4px;font-size:10px;font-weight:800;
  background:var(--text3);color:var(--bg2)}
.acc-cred.k-doc b{background:#3b82f6}
.acc-cred.k-badge b{background:#8b5cf6}
.acc-cred.k-radio b{background:#f59e0b}
.acc-cred.k-stick b{background:var(--primary,#f59e0b);color:#0b1120}
.acc-sticks{display:flex;flex-wrap:wrap;gap:3px}
.acc-stick{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11px;font-weight:700;
  background:var(--bg3);border:1px solid var(--border);border-radius:4px;padding:1px 5px}
.acc-stick.rn{background:color-mix(in srgb,var(--primary,#f59e0b) 14%,transparent);
  border-color:color-mix(in srgb,var(--primary,#f59e0b) 40%,transparent)}
.acc-tot-hd{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;
  flex-wrap:wrap;margin-bottom:14px}
.acc-tot-wrap{overflow-x:auto;border:1px solid var(--border);border-radius:10px}
.acc-tot{width:100%;border-collapse:collapse;font-size:12.5px}
.acc-tot th,.acc-tot td{padding:8px 10px;border-bottom:1px solid var(--border);
  text-align:right;white-space:nowrap}
.acc-tot th{font-size:10px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  color:var(--text3);background:var(--bg2);vertical-align:bottom}
.acc-tot th span{display:inline-block;writing-mode:vertical-rl;transform:rotate(180deg);
  max-height:120px;text-align:left}
.acc-tot .c-cat,.acc-tot th.c-cat{position:sticky;left:0;z-index:2;
  text-align:left;font-weight:700;background:var(--bg2);
  border-right:1px solid var(--border);min-width:150px}
.acc-tot th.c-cat span{writing-mode:horizontal-tb;transform:none}
.acc-tot td.z{color:var(--border2,var(--text3));opacity:.5}
.acc-tot .c-tot{font-weight:800;color:var(--text)}
.acc-tot tfoot td{border-top:2px solid var(--border);border-bottom:0;
  font-weight:800;background:var(--bg2)}
.acc-clash{border-left:4px solid #ef4444;margin-bottom:16px}
.acc-clash h3{display:flex;align-items:center;gap:8px;color:#ef4444}
.acc-clash ul{margin:10px 0 0;padding-left:18px;font-size:13px;line-height:1.7}
.acc-blocks{display:grid;gap:12px;margin-bottom:16px;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr))}
.acc-block-range{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:20px;font-weight:800;color:var(--text);margin:2px 0 6px}
.acc-block-meta{display:flex;gap:14px;font-size:12px;color:var(--text2);margin-bottom:8px}
.acc-block-meta b{color:var(--text);font-weight:800}
.acc-block-cats{font-size:11px;color:var(--text3);margin-bottom:8px}
.acc-block h3 .acc-block-kind{font-size:10px;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;color:var(--text3)}
.acc-gaps{display:flex;flex-wrap:wrap;gap:4px}
.acc-gap{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11px;font-weight:700;
  background:var(--bg3);border:1px dashed var(--border2,var(--border));border-radius:4px;
  padding:1px 5px;color:var(--text2)}
.acc-gap.on{border-style:solid;
  background:color-mix(in srgb,var(--primary,#f59e0b) 14%,transparent);color:var(--text)}
.acc-gap.more{border:0;color:var(--text3)}
.acc-gaps.used{max-height:120px;overflow-y:auto}
.cr-grid{display:grid;gap:12px;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,160px),1fr))}
.cr-h{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:13px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;
  color:var(--text2);margin:20px 0 2px;padding-top:14px;
  border-top:1px solid var(--border)}
.cr-checks{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
/* THE DIRECTORY TICKS, UNDER A NEW PERSON. Three rows that stack, and
   the two about the card are indented under the one that files it —
   they were flush against each other and against the button below,
   which read as five unrelated controls in a heap. */
.cr-dir-opts{display:grid;gap:6px;margin-top:12px}
#cr-dir-sub{display:grid;gap:6px;margin-left:16px;
  border-left:2px solid var(--border2);padding-left:10px}
#cr-dir-sub[hidden]{display:none}
.cr-creds{display:grid;gap:8px;margin-top:10px;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,150px),1fr))}
.cr-cred{display:flex;align-items:center;gap:8px;
  background:var(--bg3);border:1px solid var(--border);border-radius:8px;padding:5px 8px}
.cr-cred span{flex:1;min-width:0;font-size:11.5px;color:var(--text2);line-height:1.25}
.cr-cred .input{width:52px;flex-shrink:0;text-align:center;padding:5px 4px;font-size:13px;
  font-weight:700}
.cd-row{display:flex;align-items:center;gap:8px;margin-bottom:8px}
.cd-row .input{flex:1;min-width:0}
@media (max-width:640px){
  .acc-tbl .c-cat,.acc-tbl .c-stick{display:none}
  .acc-tot th span{max-height:90px}

  /* THE ROW OF EMPTY CELLS. The documents column had no width of its own,
     so on a phone it got whatever was left — barely one chip wide — and a
     car carrying nine credentials became nine stacked lines. Every other
     cell in that row is two or three lines and top-aligned, so the rest of
     the row was white space taller than the screen.

     Given a width the chips pack three abreast instead of one, which is the
     same information in a third of the height. */
  .acc-tbl .c-creds{min-width:186px;max-width:186px}
  .acc-tbl .c-creds .acc-cred{font-size:10px;padding:1px 5px 1px 3px;gap:3px}
  .acc-tbl .c-creds .acc-cred b{min-width:14px;height:14px;font-size:9px}
  .acc-tbl .c-creds .acc-zn{font-size:10px;padding:1px 5px}
}
/* ══════════════ THE BADGE ══════════════
   64 × 101 mm at 96 dpi — a lanyard card, not a business card. Pinned to
   white and black with the category colour on the foot, no theme
   variables inside it: what is on the screen and what comes off the
   printer can then never disagree. */
.bdg-sheet{display:flex;flex-wrap:wrap;gap:10px;justify-content:center;
  background:#e2e8f0;padding:14px;border-radius:10px}
/* THE CARD'S GEOMETRY IS NO LONGER HERE. Size, colours and every block
   on it are millimetres in the design and arrive as inline styles from
   badgeHtml() — a stylesheet that also had an opinion would be a second
   layout for the same card, and the printer would pick one of them. What
   is left is what cannot be expressed per element. */
.bdg{letter-spacing:normal;line-height:1.15;
  page-break-inside:avoid;break-inside:avoid}
.bdg *{box-sizing:border-box}

.bdg-hd{width:100%;display:flex;align-items:center;gap:8px;padding:8px 10px;
  border-bottom:1px solid #e2e8f0;flex-shrink:0}
.bdg-logo{height:24px;width:auto;max-width:74px;object-fit:contain;flex-shrink:0}
.bdg-hd-t{min-width:0;display:flex;flex-direction:column}
.bdg-hd-t strong{font-size:11px;font-weight:800;line-height:1.15;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bdg-hd-t span{font-size:9px;color:#64748b;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.bdg-photo{width:104px;height:126px;margin:12px 0 8px;border-radius:8px;overflow:hidden;
  background:#f1f5f9;border:1px solid #e2e8f0;flex-shrink:0;
  display:flex;align-items:center;justify-content:center}
.bdg-photo img{width:100%;height:100%;object-fit:cover}
.bdg-photo-none{font-size:30px;font-weight:800;color:#94a3b8}

.bdg-who{width:100%;padding:0 12px;text-align:center;flex-shrink:0}
.bdg-who strong{display:block;font-size:15px;font-weight:800;line-height:1.15;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bdg-org{display:block;font-size:10.5px;font-weight:700;color:#475569;margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bdg-role{display:block;font-size:9.5px;color:#64748b;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Access takes the middle of the card and grows into whatever is left,
   because it is the one thing a steward at a barrier actually reads. */
.bdg-zones{flex:1;width:100%;padding:8px 10px 4px;display:flex;flex-direction:column;
  align-items:center;justify-content:flex-start;gap:3px;min-height:0;overflow:hidden}
.bdg-zones-t{font-size:7.5px;font-weight:800;letter-spacing:.09em;color:#94a3b8}
.bdg-zone-row{display:flex;flex-wrap:wrap;gap:3px;justify-content:center}
.bdg-zone{padding:2px 6px;border-radius:4px;font-size:8.5px;font-weight:800;
  background:#0f172a;color:#ffffff;white-space:nowrap}
.bdg-zone.none{background:none;color:#94a3b8;font-weight:600;border:1px dashed #cbd5e1}

.bdg-qr{width:54px;height:54px;margin:0 0 4px;flex-shrink:0}
.bdg-qr img,.bdg-qr canvas{width:54px;height:54px;display:block}
.bdg-centre{width:100%;padding:0 10px 4px;text-align:center;font-size:8px;color:#64748b;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}

.bdg-ft{width:100%;padding:6px 12px;display:flex;align-items:center;justify-content:space-between;
  gap:8px;flex-shrink:0;color:#ffffff}
.bdg-ft span{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bdg-ft b{font-size:13px;font-weight:800;font-variant-numeric:tabular-nums;flex-shrink:0}

/* On paper the grey mount goes: the sheet is the cards and nothing else. */
@media print{ .bdg-sheet{background:none;padding:0} }

/* ── THE ACCREDITATION CENTRES, ACROSS THE TOP ─────────────────
   Full width and first on the day, because it is read by somebody who has
   just arrived in a town and is looking for a building. Several desks sit
   side by side and wrap to their own rows on a phone — an edition with a
   second one at the finish had no way to say so while this was a single
   card in the side column. See accredCentreBarHtml(). */
.acc-centre-bar{background:var(--bg2);border:1px solid var(--border);
  border-left:4px solid var(--gold2);border-radius:12px;
  padding:12px 16px;margin-bottom:16px;box-shadow:var(--shadow)}
.acc-centre-bar-hd{display:flex;align-items:center;justify-content:space-between;gap:10px;
  margin-bottom:10px}
.acc-centre-bar-hd span{font-size:11px;font-weight:800;letter-spacing:.06em;
  text-transform:uppercase;color:var(--gold2)}

/* Auto-fit rather than a fixed count: one desk takes the width and reads as
   a headline, three share it and read as a list. */
.acc-centre-row{display:grid;gap:12px;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr))}
.acc-centre-card{display:flex;flex-direction:column;gap:2px;min-width:0}
/* The PPO card: the address the GPS gets. Its own left accent so the
   desk and the driving instruction never read as one block. */
.acc-centre-card.ppo{border-left:3px solid #62daff;padding-left:12px}
.acc-centre-card strong{font-size:14px;font-weight:800;color:var(--text);line-height:1.25}
.acc-centre-hours{font-size:12px;font-weight:700;color:var(--gold2)}
.acc-centre-addr{font-size:13px;color:var(--text);line-height:1.4}
.acc-centre-note{font-size:12px;color:var(--text2);line-height:1.4}
/* The navigation buttons come with their own inline margin-top; a second
   one here would push them off the card on a phone. */
.acc-centre-card .acc-actions{margin-top:8px!important}

/* ── THE DESKS AS A DECK ──────────────────────────────────────
   Five start towns meant five desks and five PPOs drawn one under
   another — a page and a half of addresses, with the four counters
   beside them stretched to match. One slide per centre instead, its PPO
   beside it, with arrows, a counter and dots.

   The paging is the scroller's: slides snap, so a thumb drag on a phone
   and the arrows on a desktop move the same thing. See
   accredCentreBarHtml() in js/accreditation.js. */
.acc-cc-nav{display:flex;align-items:center;gap:4px;flex-shrink:0}
.acc-cc-nav .icon-btn{width:28px;height:28px}
.acc-cc-nav .icon-btn svg{width:15px;height:15px}
.acc-cc-count{font-size:11px;font-weight:800;letter-spacing:.04em;color:var(--text3);
  font-variant-numeric:tabular-nums;min-width:34px;text-align:center}
.acc-cc-count b{color:var(--gold2)}
.acc-cc-track{display:flex;overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory;scroll-behavior:smooth;
  scrollbar-width:none;-ms-overflow-style:none}
/* No scrollbar under the cards: the dots already say how many there are,
   and a grey bar across the address is noise. */
.acc-cc-track::-webkit-scrollbar{display:none}
.acc-cc-slide{flex:0 0 100%;min-width:0;scroll-snap-align:start}
/* Inside a slide there are only ever two cards — the desk and its PPO —
   so they may sit closer together than the auto-fit for a whole page of
   centres allowed. */
.acc-cc-slide .acc-centre-row{grid-template-columns:repeat(auto-fit,minmax(min(100%,245px),1fr))}
.acc-cc-dots{display:flex;justify-content:center;align-items:center;gap:6px;margin-top:12px}
/* The one showing stretches rather than merely brightening — a 7 px dot
   changing shade is invisible at arm's length in a race truck. */
.acc-cc-dot{width:7px;height:7px;padding:0;border:0;border-radius:50%;cursor:pointer;
  background:var(--border2,var(--border));
  transition:width .18s,background .18s,border-radius .18s}
.acc-cc-dot:hover{background:var(--text3)}
.acc-cc-dot.on{width:20px;border-radius:4px;background:var(--gold2)}
@media (prefers-reduced-motion:reduce){
  .acc-cc-track{scroll-behavior:auto}
  .acc-cc-dot{transition:none}
}

/* On the accreditation screen the bar sits under the four counters, where
   it is reference rather than headline — so it is quieter there. */
/* The day strip breathes before the desk deck under it. It is mounted
   bare on this screen — without the schedule topbar whose own margin
   spaces the same strip there — so the gap has to be its own. */
.acc-daybar{margin-bottom:14px}
#v-accreditation .acc-centre-bar{margin-bottom:14px}

/* Where a badge is collected, in the table. */
.acc-tbl .c-centre{max-width:180px}
.acc-centre{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;vertical-align:bottom;font-size:12px;color:var(--text2);
  border-bottom:1px dotted var(--border2);cursor:help}

/* ══════════════ READING A RESULTS PDF ══════════════
   The review table before anything is written. See js/results-import.js. */

/* The podium first and big: it is the part that leaves this dialog and
   goes into the medal table, and it is what somebody checks against the
   sheet in their hand before pressing Import. */
.ri-podium{display:grid;gap:8px;margin-bottom:14px;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr))}
.ri-pod{display:flex;align-items:center;gap:10px;min-width:0;
  background:var(--bg3);border:1px solid var(--border);border-radius:10px;padding:9px 12px}
.ri-pod-m{font-size:20px;flex-shrink:0;line-height:1}
.ri-pod-t{min-width:0;display:flex;flex-direction:column;gap:2px}
.ri-pod-t strong{font-size:13px;font-weight:800;line-height:1.2;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ri-pod-t small{display:flex;align-items:center;gap:5px;font-size:11px;color:var(--text2)}
.ri-pod-t em{font-size:12px;color:var(--text3)}
.ri-warn{color:#fbbf24}

/* Capped and scrolling: a classification is a hundred and fifty rows and
   the dialog must not become a page. The head stays put so the columns
   are still named at row ninety. */
.ri-wrap{max-height:46vh;overflow:auto;border:1px solid var(--border);border-radius:10px}
.ri-tbl{width:100%;border-collapse:collapse;font-size:12.5px}
.ri-tbl th{position:sticky;top:0;z-index:1;text-align:left;white-space:nowrap;
  padding:7px 10px;font-size:10px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  color:var(--text3);background:var(--bg2);border-bottom:1px solid var(--border)}
.ri-tbl td{padding:5px 10px;border-bottom:1px solid var(--border);vertical-align:middle}
.ri-tbl tbody tr:hover td{background:var(--bg3)}
.ri-tbl .c-chk{width:34px}
.ri-tbl .flag{width:18px}
/* An unticked row stays readable but stops competing with the ones that
   are going in. */
.ri-tbl tr:has(.ri-pick:not(:checked)) td{opacity:.42}

/* ══════════════ CARAVAN & FLEET MANAGER STYLES ══════════════ */
.acc-h { margin-bottom: 16px; flex-wrap: wrap; gap: 12px; }
.kpi-card { background: var(--bg2); border: 1px solid var(--border); border-radius: 8px; transition: transform 0.15s, border-color 0.15s; }
.kpi-card:hover { border-color: var(--gold); transform: translateY(-1px); }
.badge-pass-card { box-shadow: 0 4px 12px rgba(0,0,0,0.15); }
/* NO `body * { visibility: hidden }` HERE. There was, once — the
   isolate-one-card trick, meant to keep a lanyard card alone on the paper
   when the badge screen was printed from the browser. Nothing ever carried
   .badge-pass-card, so the reveal half of the pair never matched anything
   and the hide half applied to every print in the app: the team sheet, the
   presentation sheet, the booklet. Each one laid itself out correctly,
   filled its page, and came out of the printer white, because a blanked
   page and an empty one are the same picture.

   Badges do not go through the browser's printer at all — bdgPrint() in
   js/caravan-badges.js photographs .bdg-doc with html2pdf. Anything that
   does print through the browser goes in #print-root, which hides its
   siblings by display and touches nothing inside itself. */

/* ══════════════ DIRECTORY CONTACT CARDS SPACING ══════════════ */
.dir-grid { grid-template-columns: repeat(auto-fill, minmax(min(300px,100%), 1fr)) !important; gap: 14px !important; }
.dir-card { padding: 16px !important; }
.dir-card-top { display: flex !important; align-items: center !important; justify-content: space-between !important; gap: 12px !important; margin-bottom: 8px !important; }
.dir-who { flex: 1 1 auto !important; min-width: 0 !important; }
.dir-name { font-size: 16px !important; font-weight: 800 !important; color: var(--text) !important; line-height: 1.3 !important; overflow-wrap: break-word !important; word-break: break-word !important; }
.dir-details-full { margin-top: 6px !important; margin-bottom: 8px !important; width: 100% !important; clear: both !important; }
.dir-role { font-size: 13.5px !important; color: var(--gold2) !important; font-weight: 600 !important; margin-top: 2px !important; line-height: 1.35 !important; width: 100% !important; display: block !important; word-break: break-word !important; }
.dir-org { font-size: 13px !important; color: var(--text2) !important; margin-top: 2px !important; line-height: 1.35 !important; width: 100% !important; display: block !important; word-break: break-word !important; }
.dir-actions { display: flex !important; align-items: center !important; gap: 4px !important; flex-shrink: 0 !important; margin-left: 8px !important; align-self: flex-start !important; }
.dir-actions { display: flex !important; align-items: center !important; gap: 4px !important; flex-shrink: 0 !important; margin-left: 6px !important; align-self: flex-start !important; }



/* ══════════════ THE FLEET MANAGER ══════════════
   The same rows as the accreditation centre, read from the vehicle side,
   so it borrows that screen's counters, search and pills wholesale. Only
   what is peculiar to a car is below. See js/fleet.js. */

/* Twelve columns is a wide table; it scrolls rather than squeezing every
   column into illegibility. */
.fleet-tbl{min-width:1100px}
.fleet-tbl td{vertical-align:top}

/* A tick, not the word "yes" — the column heading already asks the
   question and the eye scans a column of marks far faster than a column
   of words. */
/* ══════════════ THE HOTEL BUDGET ══════════════
   The two charts inside the budget dialogue. Side by side where there is
   room, stacked on a phone — the donut answers "on what" and the bars
   answer "where", and they are read together. */
.hb-charts{margin:14px 0 18px}
.hb-charts .ch-card h4{margin:0 0 10px;font-size:11px;font-weight:800;
  letter-spacing:.06em;text-transform:uppercase;color:var(--text3)}

/* ── THE FINANCIAL PLAN, ON PAPER ─────────────────────────────
   A landscape A4 at 96 dpi. Printed on white whatever the app is set to,
   the same rule the team sheet and the caravan list follow — and the
   light values are set as VARIABLES rather than as colours on each
   element, because the chart helpers inside this sheet draw their track
   and their labels from var(--border) and var(--text). Redefining the
   tokens here dresses the charts for paper without giving them a
   PDF-only code path to disagree with the screen. */
.htb-doc{width:1122px;background:#fff;padding:24px 30px 28px;box-sizing:border-box;
  font-family:'Work Sans',system-ui,sans-serif;
  --bg2:#ffffff; --bg3:#f8fafc; --bg4:#f1f5f9;
  --border:#e2e8f0; --border2:#cbd5e1;
  --text:#0f172a; --text2:#475569; --text3:#64748b;
  /* The donut writes its figure in --bright, which on the dark theme is
     white — and white on this sheet is invisible. Ink here. */
  --bright:#0f172a;
  color:#0f172a}
.htb-doc *{box-sizing:border-box}
.htb-doc .rep-hd{border-bottom:3px solid #0f172a;padding-bottom:12px;margin-bottom:16px}
/* The plan's letterhead: the wide print logo at a size worth the paper,
   the confederation's emblem at the other end. */
.htb-doc .htb-lh .rep-hd-l{gap:18px}
.htb-logo{height:70px;width:auto;max-width:380px;object-fit:contain;object-position:left center;flex-shrink:0}
.htb-cac{height:44px;width:auto;flex-shrink:0}
.htb-empty{font-size:11px;color:#64748b;margin:4px 0 10px}

/* The headline figure, and the four things it is made of. */
.htb-top{display:flex;align-items:stretch;gap:18px;margin-bottom:16px;flex-wrap:wrap}
.htb-total{flex:0 0 auto;min-width:220px;padding:12px 16px;border-radius:10px;
  background:#0f172a;color:#fff;display:flex;flex-direction:column;justify-content:center}
.htb-total span{font-size:10px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;
  color:#94a3b8}
.htb-total strong{font-family:'Archivo','Work Sans',sans-serif;font-size:28px;font-weight:800;
  line-height:1.1;margin:2px 0}
.htb-total em{font-style:normal;font-size:10.5px;color:#cbd5e1}
.htb-parts{flex:1;min-width:0;display:grid;gap:6px 18px;align-content:center;
  grid-template-columns:repeat(2,minmax(0,1fr))}
.htb-part{display:flex;align-items:center;gap:8px;font-size:12px}
.htb-part i{width:11px;height:11px;border-radius:3px;flex-shrink:0}
.htb-part span{flex:1;min-width:0;color:#475569}
.htb-part b{font-variant-numeric:tabular-nums;color:#0f172a}

.htb-doc .ch-grid{margin:0 0 18px}
.htb-doc .ch-card{background:#f8fafc;border:1px solid #e2e8f0}

/* One block per hotel, kept whole on the page where it can be. */
.htb-hotel{margin-bottom:14px;page-break-inside:avoid;break-inside:avoid}
.htb-hd{display:flex;align-items:baseline;gap:12px;padding:6px 9px;border-radius:7px 7px 0 0;
  background:#f1f5f9;border:1px solid #e2e8f0;border-bottom:none}
.htb-hd strong{font-size:14px;font-weight:800;color:#0f172a}
.htb-hd span{flex:1;min-width:0;font-size:11px;color:#64748b}
.htb-hd b{font-size:14px;font-variant-numeric:tabular-nums;color:#0f172a}
.htb-tbl{width:100%;border-collapse:collapse;font-size:11.5px;
  border:1px solid #e2e8f0;border-top:none}
.htb-tbl th{text-align:left;padding:5px 9px;font-size:8.5px;font-weight:800;
  letter-spacing:.04em;text-transform:uppercase;color:#475569;background:#fafcfe;
  border-bottom:1px solid #cbd5e1}
.htb-tbl td{padding:4px 9px;border-bottom:1px solid #eef2f6;color:#0f172a}
.htb-tbl .n{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.htb-tbl tbody tr:nth-child(even) td{background:#fafcfe}
.htb-tbl tfoot td{border-top:1.5px solid #0f172a;font-weight:800;background:#f1f5f9}
.htb-warn{margin:5px 0 0;font-size:10.5px;color:#b45309}
.htb-note{margin:14px 0 0;font-size:10px;color:#64748b;line-height:1.45}
/* What comes back: the nights outside the allocations, amber like the
   sheet's own line, and the total said net of them. */
.htb-back-note{color:#92400e;font-weight:700}
.htb-back .htb-hd{background:#fffbeb;border-color:#fde68a}
.htb-back .htb-hd b{color:#92400e}
.htb-back .htb-tbl tfoot td{background:#fef3c7;border-top-color:#d97706;color:#78350f}

/* ── THE TEAM'S OWN STAFF, ON THE TEAMS SCREEN ────────────────
   Two or three people per team, each a name, a role and a number. Kept
   narrow: this column sits beside a rider count, not instead of it. */
.fed-staff{display:flex;flex-direction:column;gap:5px}
.fed-staff-p{display:flex;flex-direction:column;line-height:1.25}
.fed-staff-p strong{font-size:12.5px;font-weight:700;color:var(--text)}
.fed-staff-p em{font-style:normal;font-size:10.5px;color:var(--text3)}
.fed-staff-p a,.fed-staff-p span{font-size:11.5px;color:var(--text2);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.fed-staff-p a{color:var(--gold2);text-decoration:none}
.fed-staff-p a:hover{text-decoration:underline}
.fed-matrix-table td.fed-staff-cell{min-width:190px}

.fed-card-staff{margin-top:8px;padding-top:8px;border-top:1px solid var(--border)}
.fed-card-staff-t{display:block;margin-bottom:4px;font-size:9.5px;font-weight:800;
  letter-spacing:.07em;text-transform:uppercase;color:var(--text3)}
.fed-card-staff a{color:var(--gold2);text-decoration:none;font-variant-numeric:tabular-nums}

/* ── THE DOCTORS, ON THE MEDICAL DASHBOARD ────────────────────
   Directory cards worn thin: name and role, then the ways to reach them.
   The numbers are links — this screen is read with a phone in hand. */
.med-docs{display:flex;flex-direction:column;gap:8px}
.med-doc{display:flex;align-items:flex-start;gap:10px;padding:9px 11px;
  background:var(--bg3);border:1px solid var(--border);border-radius:9px}
.med-doc-t{flex:1;min-width:0}
.med-doc-t strong{display:block;font-size:13px;font-weight:800;color:var(--text)}
.med-doc-role{display:block;font-size:11px;color:var(--gold2);font-weight:700}
.med-doc-sub{display:block;font-size:10.5px;color:var(--text3);margin-top:1px}
.med-doc-c{display:flex;flex-direction:column;gap:2px;align-items:flex-end;flex-shrink:0}
.med-doc-c a{font-size:11.5px;color:var(--text2);text-decoration:none;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.med-doc-c a:first-child{color:var(--green);font-weight:700}
.med-doc-c a:hover{text-decoration:underline}

/* ── THE MEDICAL PLAN, ON PAPER ───────────────────────────────
   Landscape A4, printed on white whatever the app is set to — the same
   rule every sheet follows. See medPlanSheetHtml() in js/views.js. */
.mh-doc{width:1122px;background:#fff;color:#0f172a;padding:24px 30px 28px;
  box-sizing:border-box;font-family:'Work Sans',system-ui,sans-serif}
.mh-doc *{box-sizing:border-box}
.mh-doc .rep-hd{border-bottom:3px solid #0f172a;padding-bottom:12px;margin-bottom:12px}
.mh-scope{display:flex;align-items:baseline;justify-content:space-between;gap:14px;
  margin-bottom:12px}
.mh-scope span{font-size:14px;font-weight:800;color:#0f172a}
.mh-scope em{font-style:normal;font-size:11px;color:#64748b}
.mh-tbl{width:100%;border-collapse:collapse;font-size:11px;table-layout:fixed;
  border:1px solid #e2e8f0}
.mh-tbl th{text-align:left;padding:6px 8px;font-size:8px;font-weight:800;
  letter-spacing:.03em;text-transform:uppercase;color:#475569;background:#f8fafc;
  border-bottom:1.5px solid #0f172a;line-height:1.25;
  word-wrap:break-word;overflow-wrap:break-word}
.mh-tbl td{padding:5px 8px;border-bottom:1px solid #eef2f6;vertical-align:top;
  word-wrap:break-word;overflow-wrap:break-word;line-height:1.35}
.mh-tbl .n{font-variant-numeric:tabular-nums;white-space:nowrap}
.mh-tbl tbody tr:nth-child(even) td{background:#fafcfe}
.mh-badge{display:inline-block;font-size:8px;font-weight:800;color:#fff;
  border-radius:4px;padding:1px 6px;vertical-align:middle;letter-spacing:.04em}
.mh-h{font-family:'Archivo','Work Sans',sans-serif;font-size:13px;font-weight:800;
  letter-spacing:.04em;text-transform:uppercase;color:#0f172a;margin:16px 0 6px}
.mh-ec{display:grid;gap:6px 18px;grid-template-columns:repeat(3,minmax(0,1fr))}
.mh-ec-i{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  padding:6px 9px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:7px}
.mh-ec-i span{font-size:10.5px;color:#475569;min-width:0}
.mh-ec-i b{font-size:12px;font-variant-numeric:tabular-nums;white-space:nowrap}
.mh-none{font-size:12px;color:#64748b}

/* ── MY DAY ───────────────────────────────────────────────────
   The personal link, read on a phone in a car park at half six. Big
   numbers, one block per thing, nothing that needs a second tap. */
.md-sec{margin:22px 0 10px;font-size:13px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--text3)}
.md-badges{display:flex;flex-wrap:wrap;gap:10px;margin:8px 0}
.md-big{display:flex;flex-direction:column;align-items:center;min-width:96px;
  padding:8px 14px;border-radius:11px;background:var(--bg3);border:1px solid var(--border)}
.md-big b{font-size:24px;font-weight:900;line-height:1.1;color:var(--text);
  font-variant-numeric:tabular-nums}
.md-big i{font-style:normal;font-size:9.5px;font-weight:800;letter-spacing:.06em;
  text-transform:uppercase;color:var(--text3);margin-top:2px}
.md-sub{font-size:12.5px;color:var(--text2);margin:2px 0 0}
.md-tags{display:flex;flex-wrap:wrap;gap:5px;align-items:center;margin:8px 0 0;font-size:12px;color:var(--text3)}
.md-day .ms-hd{margin-bottom:4px}
.md-block{margin-top:12px;padding:10px 12px;border-radius:10px;
  background:var(--bg3);border:1px solid var(--border);border-left:3px solid var(--gold2)}
.md-block strong{display:block;font-size:11.5px;font-weight:800;color:var(--text);margin-bottom:3px}
.md-block span{display:block;font-size:12.5px;color:var(--text2);line-height:1.45}
.md-emg-list{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr))}
.md-emg-i{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  padding:10px 12px;border-radius:10px;background:var(--bg3);border:1px solid var(--border);
  text-decoration:none}
.md-emg-i span{font-size:12px;color:var(--text2);min-width:0}
.md-emg-i b{font-size:15px;font-weight:800;color:var(--green);white-space:nowrap;
  font-variant-numeric:tabular-nums}

/* The "my day" link, made from the share screen: type a name, press the
   button beside it. Same row shape as the hotel screen's person list. */
.md-share-find{margin-top:10px}
.md-share-find .input{width:100%;min-height:40px;padding:8px 12px;background:var(--bg3);
  border:1px solid var(--field-border);border-radius:9px;color:var(--text);
  font-size:13.5px;outline:none}
.md-share-list{display:flex;flex-direction:column;margin-top:8px}
.md-share-row{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:8px 0;border-bottom:1px solid var(--border)}
.md-share-row:last-child{border-bottom:0}
.md-share-t{display:flex;flex-direction:column;min-width:0}
.md-share-t strong{font-size:13.5px;color:var(--text)}
.md-share-t small{font-size:11.5px;color:var(--text3)}

/* ── MUNICIPAL PERMITS ────────────────────────────────────────
   One row per town: the name with its windows under it, then the file's
   reference, the contact and the status. Worked through with a
   telephone, so the status is the column the eye lands on. */
.pm-list{display:flex;flex-direction:column}
.pm-row{display:grid;gap:4px 12px;align-items:center;padding:9px 0;
  grid-template-columns:minmax(0,1.6fr) minmax(0,120px) minmax(0,1fr) 122px 44px;
  border-bottom:1px solid var(--border)}
.pm-row:last-child{border-bottom:0}
/* On a published link the contact column is not written at all — the
   snapshot never carries the official's name. Four columns then, or the
   status pill and the edit button slide left into the gap it left. */
body.is-share .pm-row{grid-template-columns:minmax(0,1.6fr) minmax(0,120px) minmax(0,1fr) 122px}
.pm-town{min-width:0;display:flex;flex-direction:column;gap:2px}
.pm-town strong{font-size:13.5px;color:var(--text)}
/* One line per day, and inside it one chip per closure — the periods
   the municipality is actually being asked to grant. */
.pm-day{display:flex;flex-wrap:wrap;align-items:baseline;gap:3px 7px;
  font-size:11.5px;color:var(--text2);font-variant-numeric:tabular-nums}
.pm-day b{font-weight:800;color:var(--text3);min-width:46px}
.pm-day i{font-style:normal;background:var(--bg3);border:1px solid var(--border);
  border-radius:6px;padding:0 6px;line-height:1.7}
.pm-lbl{color:#64748b}
.pm-ref,.pm-contact{font-size:12px;color:var(--text2);min-width:0;
  overflow:hidden;text-overflow:ellipsis}
.pm-ref span{display:block;font-size:10.5px;color:var(--text3)}
.pm-ref em,.pm-contact em{font-style:normal;color:var(--text3)}
.pm-st{justify-self:start;font-size:10.5px;font-weight:800;line-height:1.7;
  border-radius:20px;padding:1px 10px;white-space:nowrap;color:#fff;background:var(--c)}
@media (max-width:820px){
  /* The name and its windows own the first line; everything else is
     small print under it, the way the rooming rows already behave. */
  .pm-row{display:flex;flex-wrap:wrap;gap:4px 10px}
  .pm-town{flex:1 1 100%}
  .pm-st{order:2}
  .pm-ref,.pm-contact{order:3;font-size:11.5px}
}

/* One file, several stages. Filtered to Wednesday, a town crossed again
   on Friday has to say so or the row reads as the whole truth. */
.pm-also{font-size:11px;color:var(--text3);font-style:italic}

/* The teams a price sheet books in, in the import preview: a chip apiece,
   because "is Movistar in there twice" is read at a glance and never
   counted down a column. See openHotelPriceImport(). */
.hp-teams{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px}
.hp-team{font-size:11px;font-weight:700;line-height:1.6;border-radius:20px;padding:1px 9px;
  background:var(--bg3);border:1px solid var(--border2);color:var(--text2)}

/* ── THE NIGHTS BAR, ABOVE EVERYTHING IT DECIDES ──────────────
   The hotels screen is read one night at a time: the map pins, the five
   counters and every rooming list under them mean "on this night". The
   bar therefore opens the page. An extra night — one the caravan sleeps
   but the race does not ride — is dashed, so a glance tells a booked
   arrival night from a stage. See hotelNights() in js/hotels.js. */
.ht-nights{margin-bottom:14px}
.ht-nights .btn.ht-night-x{border-style:dashed}
.ht-nights .ht-night-add{opacity:.75;font-weight:800}
.ht-nights .ht-night-add:hover{opacity:1}
.ht-nights .ht-night-del svg{width:14px;height:14px}
.ht-nights .ht-night-del[disabled]{opacity:.4;cursor:not-allowed}
/* The stage buttons reuse the hotel and accreditation day bar; only the
   labels are longer here, because a date alone does not say which stage. */
/* THE COURSE WALK'S OWN CARD. The line under it counts something real —
   points asked, not stages done — because a scan of six stages otherwise
   sits on "reading…" for half a minute with nothing to show it is alive.
   See permitScanCardHtml() in js/permit-scan.js. */
.pm-scan{margin-bottom:16px}
.pm-scan-line{display:flex;align-items:center;gap:10px;margin-top:10px}
.pm-scan-bar{flex:0 0 120px;height:5px;border-radius:3px;background:var(--bg4);overflow:hidden}
.pm-scan-bar span{display:block;height:100%;border-radius:3px;
  background:linear-gradient(90deg,var(--accent-fill),var(--accent-fill2));
  transition:width .3s ease-out}
.pm-daybar .btn{max-width:280px;overflow:hidden;text-overflow:ellipsis}

/* ── THE LEVEL CROSSINGS ──────────────────────────────────────
   Infrabel's register against the stage's own course, with the trains
   iRail knows about. The table is read on the phone at a barrier as
   often as at a desk, so it scrolls sideways rather than wrapping the
   protection column into three lines. See js/rail.js. */
.pm-rail{margin-top:16px;border-left:4px solid #62daff}
.pm-rail-hd{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;
  flex-wrap:wrap;margin-bottom:10px}
.pm-rail-act{display:flex;gap:8px;flex-shrink:0}
.pm-rail-msg{font-size:12px;color:var(--text2);line-height:1.45;margin-bottom:10px}
/* The horizon is not an error and the passive crossing is not a note:
   one is amber, the other is how the table is read. */
.pm-rail-msg.warn{color:var(--gold2)}
.pm-rail-msg.err{color:#ef4444}
.pm-rail-wrap{overflow-x:auto;border:1px solid var(--border);border-radius:10px}
.pm-rail-tbl{width:100%;border-collapse:collapse;font-size:12.5px}
.pm-rail-tbl th{position:sticky;top:0;z-index:1;text-align:left;white-space:nowrap;
  padding:8px 10px;font-size:10px;font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;color:var(--text3);
  background:var(--bg2);border-bottom:1px solid var(--border)}
.pm-rail-tbl td{padding:8px 10px;border-bottom:1px solid var(--border);vertical-align:top}
.pm-rail-tbl tbody tr:last-child td{border-bottom:0}
.pm-rail-tbl tbody tr:hover td{background:var(--bg3)}
/* The kilometre is what a road captain briefs from, so it is set like
   the course numbers elsewhere and the town rides under it. */
.pm-rail-km{white-space:nowrap}
.pm-rail-km strong{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:14px;font-weight:800}
.pm-rail-km span{display:block;font-size:10.5px;color:var(--text3)}
/* No at-grade crossing is allowed in the last fifty kilometres — a
   flat statement, not a graded risk, so it wears the same red as a
   train actually clashing with the race rather than the muted grey
   the town/offset lines above it use. */
.pm-rail-km .pm-rail-late{display:inline-block;margin-top:2px;padding:1px 6px;border-radius:5px;
  font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.03em;
  background:rgba(239,68,68,.16);color:#ef4444}
.pm-rail-line{font-family:ui-monospace,Menlo,Consolas,monospace;font-weight:700;
  white-space:nowrap;color:var(--text2)}
/* Protection carries its own colour: passive is a St Andrew's cross and
   nothing else, and that has to be visible from across a room. */
.pm-rail-type{display:inline-block;font-size:10.5px;font-weight:800;line-height:1.7;
  white-space:nowrap;border-radius:20px;padding:1px 9px;
  color:var(--c);border:1px solid var(--c);
  background:color-mix(in srgb,var(--c) 12%,transparent)}
.pm-rail-tr{min-width:180px}
.pm-rail-train{display:inline-flex;align-items:baseline;gap:5px;margin:0 4px 4px 0;
  font-size:11px;color:var(--text2);
  background:var(--bg3);border:1px solid var(--border);border-radius:5px;padding:1px 7px}
.pm-rail-train b{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11.5px;
  font-weight:800;color:var(--text)}
/* A cancelled train still tells the crew something — that the barrier
   they were warned about will not come down. */
.pm-rail-train.off{opacity:.5;text-decoration:line-through}
/* THE TRAIN THAT MEETS THE RACE. Red is the barrier down while the
   peloton is due; amber is within twenty minutes of it. Both have to
   read from across the room, so red is a filled chip, not a border. */
.pm-rail-train.danger{background:#ef4444;border-color:#ef4444;color:#fff;font-weight:700}
.pm-rail-train.danger b{color:#fff}
.pm-rail-train.near{border-color:#f59e0b;color:#b45309;
  background:color-mix(in srgb,#f59e0b 16%,transparent)}
.pm-rail-train.near b{color:#b45309}
body:not(.light) .pm-rail-train.near,body:not(.light) .pm-rail-train.near b{color:#fbbf24}
.pm-rail-tbl tr.danger td:first-child{box-shadow:inset 3px 0 0 #ef4444}
/* The race's own passage at the crossing: one window per race, per lap. */
.pm-rail-pass-td{white-space:nowrap}
.pm-rail-pass{display:block;line-height:1.5}
.pm-rail-pass b{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12px;font-weight:800}
.pm-rail-pass i{display:block;font-style:normal;font-size:10.5px;color:var(--text3)}
/* The bold time is the recommended closure window (±10 min either
   side of the fast/slow spread); this is the three raw estimates it
   was built from, kept small and allowed to wrap since the parent
   cell itself stays nowrap for the bold line above it. */
.pm-rail-pass-detail{display:block;white-space:normal;font-size:10px;color:var(--text3);opacity:.85}
.pm-rail-legend{margin-top:10px;font-size:11px;line-height:1.9;color:var(--text3)}
.pm-rail-legend strong{color:var(--text2)}
.pm-rail-legend.hot strong{color:#ef4444}
.pm-rail-legend .pm-rail-train{margin:0 2px 0 0;font-size:10px;padding:0 6px}
.pm-rail-foot{margin-top:10px;font-size:11px;color:var(--text3)}

/* ── A WAY ROUND A CROSSING ───────────────────────────────────
   The sixth column holds the button; the candidates land in a row of
   their own under the crossing, one card each, best first. See
   js/rail-detour.js. */
.pm-rd-cell{white-space:nowrap}
.pm-rd-cell .icon-btn{margin-left:4px;vertical-align:middle}
.pm-rd-busy,.pm-rd-sum{font-size:11.5px;color:var(--text2)}
.pm-rail-tbl tr.pm-rail-alt td{background:var(--bg2);padding:10px 12px 12px}
.pm-rail-tbl tr.pm-rail-alt:hover td{background:var(--bg2)}
.pm-rd-list{display:flex;flex-direction:column;gap:8px}
.pm-rd-cand{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;
  padding:8px 10px;border:1px solid var(--border);border-radius:10px;background:var(--bg3)}
body.light .pm-rd-cand{background:#fff}
/* The best one wears the gold; the one on the map wears its ring. */
.pm-rd-cand.best{border-color:var(--gold2)}
.pm-rd-cand.shown{box-shadow:inset 0 0 0 2px #f2c14e}
.pm-rd-letter{width:24px;height:24px;border-radius:50%;flex:none;
  display:inline-flex;align-items:center;justify-content:center;
  font-weight:800;font-size:12px;background:var(--bg2);border:1px solid var(--border)}
.pm-rd-cand.best .pm-rd-letter{background:var(--gold2);color:#0b1016;border-color:var(--gold2)}
.pm-rd-verdict{display:inline-flex;align-items:center;gap:5px;font-size:11px;font-weight:800;
  line-height:1.7;white-space:nowrap;border-radius:20px;padding:1px 9px;
  color:var(--c);border:1px solid var(--c);background:color-mix(in srgb,var(--c) 12%,transparent)}
.pm-rd-km{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:15px;font-weight:800;white-space:nowrap;line-height:1.1}
.pm-rd-km span{display:block;font-family:var(--font);font-size:10.5px;font-weight:600;
  color:var(--text3);white-space:nowrap}
.pm-rd-facts{display:flex;flex-wrap:wrap;gap:3px 12px;font-size:11.5px;color:var(--text2);
  flex:1 1 260px;line-height:1.5}
.pm-rd-facts b{color:var(--text)}
.pm-rd-facts i{font-style:normal;color:var(--text3)}
.pm-rd-obst{display:inline-flex;align-items:center;gap:4px;color:#ef4444}
.pm-rd-obst svg{width:12px;height:12px;flex:none}
.pm-rd-act{display:flex;gap:6px;flex-shrink:0;margin-left:auto}
.pm-rd-foot{font-size:10.5px;color:var(--text3);margin-top:8px;line-height:1.45}
@media (max-width:640px){
  .pm-rd-act{margin-left:0;width:100%}
  .pm-rd-act .btn{flex:1}
}

/* ── THE DAILY COMMUNIQUÉ ─────────────────────────────────────
   Portrait, and typewriter-plain on purpose: what the timing partner
   pastes into their template is the same text this sheet prints, so it
   must survive being copied without a stylesheet. See js/communique.js. */
.cq-doc{width:794px;background:#fff;color:#0f172a;padding:26px 32px 30px;
  box-sizing:border-box;font-family:'Work Sans',system-ui,sans-serif}
.cq-doc .rep-hd{border-bottom:3px solid #0f172a;padding-bottom:12px;margin-bottom:14px}
.cq-body{margin:0;white-space:pre-wrap;word-break:break-word;
  font-family:ui-monospace,'Cascadia Mono',Consolas,monospace;
  font-size:11px;line-height:1.55;color:#0f172a}
/* The live preview inside the editor: the same text, on the app's own
   ground rather than on paper. */
.cq-prev{margin:0;white-space:pre-wrap;word-break:break-word;max-height:260px;overflow:auto;
  padding:10px 12px;border:1px solid var(--border);border-radius:9px;background:var(--bg3);
  font-family:ui-monospace,'Cascadia Mono',Consolas,monospace;
  font-size:11.5px;line-height:1.5;color:var(--text2)}
/* What the app already knows, shown rather than asked again. */
.cq-known{display:flex;flex-wrap:wrap;gap:4px 14px;margin-bottom:12px;padding:10px 12px;
  border:1px solid var(--border);border-left:3px solid var(--gold2);border-radius:9px;
  background:var(--bg3)}
.cq-known strong{flex:1 1 100%;font-size:9.5px;font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;color:var(--text3)}
.cq-known span{font-size:12px;color:var(--text2)}

/* ── THE INTERVENTIONS REPORT ─────────────────────────────────
   Same white sheet as the plan; only the summary strip and the
   sign-off are its own. See medIncidentReportHtml() in js/views.js. */
.mh-ec.mh-sum{grid-template-columns:repeat(5,minmax(0,1fr));margin-bottom:4px}
.mh-sign{display:flex;gap:30px;margin-top:26px}
.mh-sign div{flex:1;border-top:1px solid #94a3b8;padding-top:5px;
  font-size:9.5px;letter-spacing:.03em;text-transform:uppercase;color:#64748b}

/* ── HOSPITALS PER STAGE ──────────────────────────────────────
   The filter row above the list, and the stages one hospital is pinned
   to. Both scroll sideways rather than wrapping into a block: a ten-day
   race would otherwise push the first card half a screen down. */
.hosp-daybar{display:flex;gap:6px;overflow-x:auto;padding:2px 0 10px;
  scrollbar-width:none}
.hosp-daybar::-webkit-scrollbar{display:none}
.hosp-daybar .btn{flex-shrink:0;white-space:nowrap}
.hosp-days{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}

.fl-yes{display:inline-flex;color:var(--primary,#f59e0b)}
.fl-yes svg{width:16px;height:16px}

/* Where the keys are collected. A chip rather than another grey line: it
   is one of two fixed answers, and the morning of the handover is planned
   by sorting the list into the two piles. */
.fl-pickup{display:inline-block;margin-bottom:3px;padding:1px 7px;border-radius:11px;
  font-size:11px;font-weight:800;letter-spacing:.02em;
  background:var(--gold-light);border:1px solid var(--gold-border);color:var(--gold2)}
body.light .fl-pickup{color:var(--gold)}

/* How a car is driven, coloured because it is the column somebody scans
   when they are working out where the chargers have to go. */
.fl-drive{display:inline-block;font-size:11px;font-weight:700;line-height:1.5;
  border-radius:5px;padding:2px 7px;
  background:var(--bg3);border:1px solid var(--border);color:var(--text2)}
.fl-drive.ev{background:color-mix(in srgb,var(--primary,#f59e0b) 16%,transparent);
  border-color:color-mix(in srgb,var(--primary,#f59e0b) 45%,transparent);color:var(--text)}
.fl-drive.hy{background:color-mix(in srgb,#8b5cf6 16%,transparent);
  border-color:color-mix(in srgb,#8b5cf6 45%,transparent);color:var(--text)}

/* The central park, in the modal: one line per car, the two actions on
   the right where they are in every other list in this app. */
.fl-mrow{display:flex;align-items:center;gap:10px;padding:8px 0;
  border-bottom:1px solid var(--border)}
.fl-mrow:last-child{border-bottom:0}
.fl-mcar{flex:1;min-width:0;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.fl-mcar strong{font-size:13px}

/* ── THE SHUTTLE PLANNER ──────────────────────────────────────
   The fleet screen's second tab. See js/shuttles.js. */

/* The one thing on the screen that is WRONG rather than unfinished: a
   car promised to two people at once. Red and above the filters, because
   filtering it out of sight would not make it stop being true. */
.sh-warn{display:flex;align-items:center;gap:10px;margin-bottom:14px;
  padding:11px 14px;font-size:13px;font-weight:600;
  background:var(--red-bg);border:1px solid var(--red-border);color:var(--text)}
.sh-warn > svg{width:17px;height:17px;color:var(--red);flex-shrink:0}

/* The group rows — one per day, or one per car. A band across the table
   rather than a heading above it: the columns have to keep lining up. */
.sh-grp > td{padding:9px 14px !important;background:var(--bg4,var(--bg3));
  border-top:1px solid var(--border)}
.sh-grp strong{font-size:13px}
.sh-grp.warn > td{background:var(--gold-light);
  box-shadow:inset 3px 0 0 var(--gold2)}
.sh-grp-n{float:right;font-size:11px;font-weight:700;color:var(--text3);
  letter-spacing:.03em;text-transform:uppercase}
.sh-clash{display:inline-flex;align-items:center;gap:4px;margin-left:8px;
  font-size:11px;font-weight:800;color:var(--red)}
.sh-clash svg{width:13px;height:13px}
.sh-tbl tr.sh-bad > td{background:var(--red-bg)}

.sh-time{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:15px;letter-spacing:.01em}
.sh-pax{display:inline-block;min-width:24px;padding:1px 7px;border-radius:11px;
  font-size:11px;font-weight:800;text-align:center;
  background:var(--gold-light);border:1px solid var(--gold-border);color:var(--gold2)}
body.light .sh-pax{color:var(--gold)}
.sh-arrow{color:var(--text3);font-weight:800}
.sh-wa{color:#25d366;display:inline-flex;vertical-align:-2px}
.sh-wa svg{width:13px;height:13px}
/* The car is chosen from the row itself — the action this screen is
   opened for — so the select has to fit a table cell. */
.sh-assign{height:30px;padding:2px 6px;font-size:12px;max-width:210px}

/* Where a ride has got to. The same five states the driver's two taps
   move it through. */
.sh-st{display:inline-flex;align-items:center;gap:5px;padding:2px 8px;border-radius:11px;
  font-size:11px;font-weight:800;white-space:nowrap;
  background:var(--bg3);border:1px solid var(--border);color:var(--text2)}
.sh-st svg{width:12px;height:12px}
.sh-st.t-gold{background:var(--gold-light);border-color:var(--gold-border);color:var(--gold2)}
body.light .sh-st.t-gold{color:var(--gold)}
.sh-st.t-green{background:var(--green-bg,var(--gold-light));
  border-color:var(--green-border,var(--gold-border));color:var(--green)}
.sh-st.t-blue{background:var(--blue-bg);border-color:var(--blue-border);color:var(--blue)}
.sh-st.t-red{background:var(--red-bg);border-color:var(--red-border);color:var(--red)}

/* The prefilled message, before a human presses send. Monospaced so the
   line breaks that will reach the passenger are the ones on screen. */
.sh-preview{max-height:260px;overflow:auto;margin:0 0 12px;padding:12px 14px;
  border-radius:10px;background:var(--bg3);border:1px solid var(--border);
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;
  line-height:1.55;color:var(--text2);white-space:pre-wrap;word-break:break-word}
.sh-notify{display:flex;gap:8px;flex-wrap:wrap}

/* Attaching a ride to a real person, inside the ride form. Inline rather
   than a second dialogue: openModal() replaces the one modal instead of
   stacking, so a picker opened from here would take the half-filled ride
   with it. */
.sh-pick{margin:4px 0 14px;padding:12px 14px;border-radius:10px;
  background:var(--bg3);border:1px solid var(--border)}
.sh-pick-hd{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.sh-pick-state{flex:1;min-width:0;font-size:11px;color:var(--text3)}
.sh-pick .btn.hidden{display:none}
.sh-pick-list{margin-top:8px}
.sh-pick-list:empty{margin-top:0}
.sh-pick-list .cp-row{border:1px solid var(--border);border-radius:8px;margin-bottom:4px;
  background:var(--bg2)}
.sh-pick-list .cp-row:last-child{margin-bottom:0}
/* What the accreditation desk holds about the linked person, under the
   search box: the number, the role, the car and the bed. It is read to
   check the link found the right human, so it stays one quiet line. */
.sh-pick-facts{margin-top:8px;padding-top:8px;border-top:1px solid var(--border);
  font-size:11.5px;line-height:1.5;color:var(--text2);word-break:break-word}
.sh-pick-facts.hidden,.sh-pick-facts:empty{display:none}
.sh-pick-facts .hint{margin:0}

/* On somebody's own personal link. Which side of the wheel they are on
   is the first thing the card says — a driver and a passenger read the
   same fields for opposite reasons. */
.sh-role{margin-left:auto;font-size:11px;font-weight:800;letter-spacing:.04em;
  text-transform:uppercase;color:var(--gold2)}
body.light .sh-role{color:var(--gold)}
.sh-card h3{font-size:15px}

/* The import drop zone, shared shape with the other imports in this app. */
.ci-drop{display:flex;flex-direction:column;align-items:center;gap:5px;
  padding:26px 18px;margin-bottom:14px;cursor:pointer;text-align:center;
  border:2px dashed var(--border2,var(--border));border-radius:12px;
  background:var(--bg3);transition:border-color .14s,background .14s}
.ci-drop:hover,.ci-drop.on{border-color:var(--primary,#f59e0b);
  background:color-mix(in srgb,var(--primary,#f59e0b) 8%,transparent)}
.ci-drop svg{width:24px;height:24px;color:var(--text3)}
.ci-drop strong{font-size:13px}
.ci-drop span{font-size:11.5px;color:var(--text3)}
.ci-sum{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:12px}
.ci-sum strong{font-size:13px}
.ci-sum span{font-size:11px;font-weight:700;border-radius:20px;padding:3px 10px;
  background:var(--bg3);border:1px solid var(--border);color:var(--text2)}
.ci-acts{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:14px}

/* The category editor: name, sticker series, block start, row count, bin. */
.cat-head,.cat-row{display:grid;gap:8px;align-items:center;
  grid-template-columns:minmax(0,1fr) minmax(0,110px) 84px 40px 34px}
.cat-head{margin-bottom:6px}
.cat-head span{font-size:10px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  color:var(--text3)}
.cat-row{margin-bottom:8px}
.cat-row .input{min-width:0}
/* How many rows would be orphaned by deleting this one. */
.cat-n{display:inline-flex;align-items:center;justify-content:center;
  height:22px;border-radius:11px;padding:0 8px;font-size:11px;font-weight:800;
  background:var(--bg3);border:1px solid var(--border);color:var(--text2)}
/* The bin refused: a flash, so the toast is not the only thing that says so. */
.cat-row.cat-blocked .cat-n{background:#ef4444;border-color:#ef4444;color:#fff}

/* ── A COLOUR PER SERIES ──────────────────────────────────────
   The picker, the series' name, and a sample of the box the numbers will
   actually appear in — the sample is the point: a hex value in a swatch
   does not tell you whether ORG 1 will be legible in it. */
/* minmax(0,auto) on the sample, not auto: a series name is typed by hand
   and "VIP - GENODIGDEN 1" in the sample was squeezing the name beside it
   down to "V…". The sample gives way first — it is the colour that is
   being judged there, not the wording. */
.sc-row{display:grid;grid-template-columns:44px minmax(0,1fr) minmax(0,auto);gap:10px;
  align-items:center;margin-bottom:8px;cursor:pointer}
.sc-col{width:44px;height:30px;padding:2px;border:1px solid var(--border);
  border-radius:6px;background:var(--bg2);cursor:pointer}
.sc-name{font-size:12.5px;font-weight:700;color:var(--text);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.sc-eg{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11px;font-weight:800;
  border:2px solid currentColor;border-radius:6px;padding:2px 7px;white-space:nowrap;
  background:color-mix(in srgb,currentColor 8%,transparent);
  min-width:0;overflow:hidden;text-overflow:ellipsis}

/* The line under the numbers in the row editor: which colour these come
   out in, and where it is changed. */
.cr-seriescol{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  margin:-4px 0 12px;font-size:12px;color:var(--text2)}
.cr-seriescol-sw{width:16px;height:16px;border-radius:4px;flex-shrink:0;
  border:1px solid rgba(0,0,0,.25)}
.cr-seriescol em{font-style:normal;color:var(--text3);font-size:11.5px}
@media (max-width:560px){
  .cat-head{display:none}
  .cat-row{grid-template-columns:minmax(0,1fr) 40px 34px}
  .cat-row .cat-sticker,.cat-row .cat-from{grid-column:1/-1}
}

/* ══════════════ EXPORTING THE CARAVAN ══════════════
   The dialogue. See js/caravan-export.js. */
.ce-sec{margin-bottom:14px}
.ce-lbl{display:block;margin-bottom:6px;font-size:10px;font-weight:800;letter-spacing:.06em;
  text-transform:uppercase;color:var(--text3)}
.ce-sec .acc-pills{margin-bottom:0}
/* Twenty-odd column ticks: dense, two or three to a row, and readable. */
.ce-cols{display:grid;gap:6px;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,140px),1fr));
  max-height:34vh;overflow-y:auto;padding:2px}
.ce-col{display:flex;align-items:center;gap:7px;cursor:pointer;
  background:var(--bg3);border:1px solid var(--border);border-radius:8px;padding:6px 9px;
  font-size:12px;color:var(--text2);transition:border-color .12s,color .12s}
.ce-col.on{border-color:var(--primary,#f59e0b);color:var(--text)}
.ce-col input{accent-color:var(--primary,#f59e0b);flex-shrink:0}
.ce-col span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ce-count{font-size:12px;color:var(--text2);padding-top:10px;border-top:1px solid var(--border)}
.ce-count strong{color:var(--text);font-weight:800}

/* ══════════════ THE PRINTED SHEET ══════════════
   Landscape A4. Pinned to black on white with no theme variables inside
   it: what is on the screen and what comes off the printer can then
   never disagree — the same rule as the badge. */
.ce-doc{width:1122px;background:#fff;color:#111;padding:24px 30px 28px;
  font-family:'Work Sans',system-ui,sans-serif;box-sizing:border-box}
.ce-doc *{box-sizing:border-box}

/* ── THE LETTERHEAD ───────────────────────────────────────────
   Golazo's mark left, the edition's own right, the words between — the
   arrangement every printed sheet in this app uses, so a page off a
   clipboard is recognised before it is read.

   `align-items:center` and not flex-start: the two logos are different
   heights and different shapes, and hanging both from the top line left
   the taller one looking dropped. */
.ce-hd{display:flex;align-items:center;gap:22px;
  padding-bottom:13px;margin-bottom:0;border-bottom:3px solid #0f172a}
.ce-hd-golazo{height:30px;width:auto;flex-shrink:0}
/* The edition's own mark is whatever it was uploaded as, so it is bounded
   on both sides rather than trusted to be a sensible shape. */
.ce-hd-ev{height:42px;width:auto;max-width:170px;object-fit:contain;flex-shrink:0}
.ce-hd-t{flex:1;min-width:0}
.ce-hd h1{font-family:'Archivo','Work Sans',sans-serif;font-size:23px;font-weight:800;
  line-height:1.1;margin:0 0 3px;color:#0f172a;letter-spacing:.01em}
.ce-hd p{font-size:12px;color:#475569;margin:0;font-weight:600}
.ce-hd-r{display:flex;flex-direction:column;align-items:flex-end;gap:4px;
  flex-shrink:0;white-space:nowrap}
/* The date and the count as chips rather than grey text: they are the two
   things somebody checks before trusting a printed list. */
.ce-chip{font-size:10px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  color:#0f172a;background:#f1f5f9;border:1px solid #cbd5e1;border-radius:11px;padding:3px 10px}
/* A hair of house green under the rule — the sheet's only colour besides
   the series bands, and enough to say whose document this is. */
.ce-hd + .ce-tbl{margin-top:0}
.ce-doc .ce-hd{border-image:linear-gradient(90deg,#0f172a 0 78%,#16a34a 78% 100%) 1;
  border-bottom-style:solid}

/* A landscape A4 is 297 mm of paper for 1122 px of layout, so a point of
   type here lands a point on the page. Read at arm's length off a
   clipboard: 11 px body, and rows given air rather than packed. */
.ce-tbl{width:100%;border-collapse:collapse;font-size:11px;table-layout:fixed;margin-top:14px}
/* The heading wraps and, if it must, breaks. table-layout is fixed, so a
   single long word in a narrow column does not widen it — it runs straight
   over the heading beside it, which is how "Tankkaart" and "Afhalen /
   retour" came out of the printer as one word. */
.ce-tbl th{text-align:left;padding:6px 7px;font-size:8px;font-weight:800;
  letter-spacing:.02em;text-transform:uppercase;color:#334155;background:#f8fafc;
  border-bottom:1.5px solid #0f172a;vertical-align:bottom;line-height:1.25;
  word-wrap:break-word;overflow-wrap:break-word;hyphens:auto}
.ce-tbl td{padding:5px 7px;border-bottom:1px solid #e6eaef;vertical-align:top;
  word-wrap:break-word;overflow-wrap:break-word;line-height:1.35}
/* Zebra, because a wide sheet is read across and the eye loses the row. */
.ce-tbl tbody tr:nth-child(even) td{background:#f7f9fb}
/* A rule where the series changes — ORG 1–130 then MOTO 1–100 otherwise
   reads as one run of numbers going backwards. The colour comes in on the
   element, from caravanSeriesColour(): the band matches the box the same
   numbers are printed in everywhere else. White on it, because these are
   dark house colours and the band is a label, not a highlight. */
.ce-tbl tr.ce-ser td{color:#fff;font-weight:800;font-size:9.5px;
  letter-spacing:.09em;text-transform:uppercase;padding:4px 7px;border-bottom:none}
.ce-tot td,.ce-tot th{text-align:right}
.ce-tot td:first-child,.ce-tot th:first-child{text-align:left;font-weight:700}
.ce-tot tfoot td{border-top:2px solid #111;font-weight:800;background:#f0f0f0}

/* ── LINKED TO THE DIRECTORY ──────────────────────────────────
   The mark on a row whose person comes from the phone list rather than
   being typed here. See caravanContact() in js/caravan.js. */
.acc-link{display:inline-flex;vertical-align:-2px;color:var(--primary,#f59e0b);opacity:.75}
.acc-link svg{width:12px;height:12px}
.acc-link.broken{color:#ef4444;opacity:1}

.cr-person{margin-top:12px}
.cr-linked{display:flex;align-items:center;gap:10px;
  background:color-mix(in srgb,var(--primary,#f59e0b) 10%,transparent);
  border:1px solid color-mix(in srgb,var(--primary,#f59e0b) 40%,transparent);
  border-radius:10px;padding:9px 12px}
.cr-linked-ico{display:flex;color:var(--primary,#f59e0b);flex-shrink:0}
.cr-linked-t{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.cr-linked-t strong{font-size:13px}
.cr-linked-t small{font-size:11px;color:var(--text2);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}

/* The picker: eighty names, searched rather than scrolled. */
.cp-list{max-height:46vh;overflow-y:auto;border:1px solid var(--border);border-radius:10px}
.cp-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px 12px;width:100%;
  align-items:center;text-align:left;cursor:pointer;
  background:none;border:0;border-bottom:1px solid var(--border);
  padding:9px 12px;font-family:inherit;color:var(--text)}
.cp-row:last-child{border-bottom:0}
.cp-row:hover{background:var(--bg3)}
.cp-name{font-size:13px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cp-sub{grid-column:1;font-size:11px;color:var(--text3);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cp-tel{grid-row:1/3;font-size:11.5px;color:var(--text2);white-space:nowrap}

/* Ordered against assigned, at the foot of the totals. See the note in
   accTotalsHtml(): the rows say what is spoken for, the order says what
   exists, and the gap is the number anybody actually wants. */
.acc-tot .acc-ord input{width:100%;min-width:44px;max-width:64px;
  background:var(--bg3);border:1px solid var(--border);border-radius:5px;
  padding:3px 5px;text-align:right;font-size:12px;font-weight:700;
  color:var(--text);font-family:inherit}
.acc-tot .acc-ord input:focus{outline:none;border-color:var(--primary,#f59e0b)}
.acc-tot tfoot tr td{border-top:0}
.acc-tot tfoot tr:first-child td{border-top:2px solid var(--border)}
/* Short stops a race; surplus is only money. */
.acc-tot .acc-gap td.short{color:#ef4444;font-weight:800}
.acc-tot .acc-gap td.over{color:var(--text3)}
.acc-tot .acc-gap td.ok{color:var(--primary,#f59e0b);font-weight:800}

/* ══════════════ HOTELS ══════════════
   One card per hotel with its rooming list under it. See js/hotels.js. */
.hotel-bar{border-left-color:#8b5cf6}
.hotel-bar .acc-centre-bar-hd span{color:#8b5cf6}

/* A CARD IS ITS OWN STACKING CONTEXT, and that is what put the guest
   row's ⋮ menu behind the next hotel. `.card` carries backdrop-filter,
   and any filter at all makes one — so the menu's z-index:40 ranked it
   only INSIDE its own card: above everything there, and nothing at all
   against the card below, which paints later and drew straight over it.
   Nothing a child sets can climb out of a context its parent made, so
   the card itself is lifted for as long as one of its menus is open.
   Positioned always rather than only while open, so opening a menu can
   never move an absolutely-placed child underneath it. */
.ht-card{margin-bottom:14px;position:relative}
.ht-card.menu-open{z-index:60}
/* The card's face: the first photo, big enough to recognise the building
   from the parking. Name and address read beside it. */
.ht-hero{flex:0 0 auto;display:block;width:128px;height:128px;border-radius:12px;overflow:hidden;
  border:1px solid var(--border)}
.ht-hero img{width:100%;height:100%;object-fit:cover;display:block}
@media (max-width:720px){.ht-hero{width:84px;height:84px}}
/* The ⋮ overflow: everything occasional, with a label each. */
.ht-more{position:relative}
.ht-more-btn{font-size:19px;font-weight:800;line-height:1}
.ht-more-btn.drift{color:var(--gold2);border-color:var(--gold-border)}
.ht-more-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:40;min-width:250px;
  background:var(--bg2);border:1px solid var(--border);border-radius:11px;box-shadow:var(--shadow);
  padding:6px;display:flex;flex-direction:column;gap:2px}
.ht-mi{display:flex;align-items:center;gap:10px;padding:9px 11px;border:none;background:none;
  border-radius:8px;cursor:pointer;font-family:inherit;font-size:13px;color:var(--text);text-align:left}
.ht-mi svg{width:15px;height:15px;flex-shrink:0;color:var(--text2)}
.ht-mi:hover{background:var(--bg3)}
.ht-mi.danger,.ht-mi.danger svg{color:#ef4444}
.ht-mi.drift,.ht-mi.drift svg{color:var(--gold2)}
/* On a phone the menu must never leave the viewport. The old rule flipped
   EVERY menu to the left, which pushed the toolbar ⋮ — a button already at
   the right edge — clean off the screen. The side is picked at open time
   now by clampMenuToViewport(); here the width is merely capped. */
@media (max-width:640px){
  .ht-more-menu{max-width:calc(100vw - 36px)}
}
/* The guest rows' 176px action column shrinks to one ⋮ now. */
.ht-guest .ht-acts .ht-more{position:relative}
.ht-hd{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;
  flex-wrap:wrap;margin-bottom:10px}
.ht-hd-t{flex:1;min-width:0}
.ht-hd-t h3{margin-bottom:3px}
/* Nine buttons: they WRAP. Kept on one unshrinkable line they ran off
   the right edge of the card on a phone, and the mail button — the one
   that writes to the whole hotel — was the one that fell off. */
.ht-hd-a{display:flex;align-items:center;gap:6px;flex-shrink:0;flex-wrap:wrap}
/* ONE HEIGHT ACROSS THE ROW. The labelled buttons are .btn.sm at 36px
   and the pencil and the ⋮ are .icon-btn at 44px, so the row read as
   two rows of buttons that had been pushed together. */
.ht-hd-a .btn.sm,.ht-hd-a .icon-btn{min-height:36px;height:36px}
.ht-hd-a .icon-btn{min-width:36px;width:36px}
@media (max-width:720px){
  .ht-hd-a{flex:1 1 100%;min-width:0}
}
.ht-meta{display:flex;flex-wrap:wrap;gap:12px;font-size:12px;color:var(--text2)}
.ht-notes{font-size:12px;color:var(--text3);margin:5px 0 0}

/* The rooming list. Room first and in its own column, because that is
   the column a reception desk reads down. */
.ht-guests{border-top:1px solid var(--border)}
/* The last column is FIXED, not auto: every row is its own grid, and a
   row with a mail button grew a wider actions column than its neighbour
   without one — which slid every fr column with it and left the group
   pills ragged down the page. One width, one straight line of pills. */
/* Name, room, group, nights, NOTES, phone, ⋮ — the notes take the
   stretch the nights used to leave empty. */
.ht-guest{display:grid;gap:4px 12px;align-items:center;
  grid-template-columns:minmax(0,1.5fr) 64px minmax(0,110px) minmax(0,120px) minmax(0,1fr) minmax(0,110px) 56px;
  padding:8px 0;border-bottom:1px solid var(--border)}
.ht-guest .ht-acts{display:flex;justify-content:flex-end;gap:6px}
.ht-guest:last-child{border-bottom:0}
/* The app's own face, not a terminal's: the room label read as code in
   monospace and earned a complaint. Same size, ordinary letters. */
.ht-room{display:flex;flex-direction:column;
  font-size:13px;font-weight:700;color:var(--text)}
.ht-room small{font-family:inherit;font-size:9px;font-weight:700;letter-spacing:.04em;
  text-transform:uppercase;color:var(--text3)}
.ht-room em{color:var(--text3);font-weight:400}
.ht-who{min-width:0;display:flex;flex-direction:column;gap:1px}
.ht-who strong{font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ht-who small{font-size:11px;color:var(--text3);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ht-nights{font-size:11.5px;color:var(--text2);white-space:nowrap}
.ht-tel{font-size:11.5px;color:var(--text3);white-space:nowrap}
.ht-note{min-width:0;font-size:11.5px;color:var(--text2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ht-acts{display:flex;gap:4px;justify-content:flex-end}
.hg-pick{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}

/* ── THE ROW ON A PHONE: THE PERSON FIRST ─────────────────────
   A reception desk reads down the room column; a phone is read by
   somebody looking for a NAME. Six columns on a 400px screen gave the
   room label a two-line block of its own and squeezed "Stijn
   Carnot…" into an ellipsis, so on a phone the row becomes three
   lines: the name, then the small print (room, group, nights, phone),
   then the buttons. */
@media (max-width:720px){
  /* position:relative so the ⋮ can be pinned to the corner below. */
  .ht-guest{display:flex;flex-wrap:wrap;align-items:center;gap:3px 8px;padding:10px 0;
    position:relative}
  /* The name owns the first line — the checkbox shares it when the
     bulk bar is armed, which is the only thing that comes before it.
     Room is kept clear on the right for the ⋮ in the corner. */
  .ht-who{flex:1 1 100%;order:2;padding-right:48px}
  .ht-guests.sel .ht-who{flex:1 1 calc(100% - 28px)}
  .ht-selbox{order:1}
  .ht-who strong{font-size:15.5px;font-weight:800;
    white-space:normal;overflow:visible;text-overflow:clip}
  .ht-who small{font-size:11.5px;white-space:normal}
  /* Everything that was a column is small print on the second line. */
  .ht-room{order:3;flex-direction:row;align-items:baseline;gap:5px;
    font-size:11.5px;font-weight:700;color:var(--text2)}
  .ht-room small{font-size:9.5px}
  .ht-grp{order:4;min-width:0}
  .ht-nights{order:5;font-size:11px}
  .ht-note{order:6;flex:1 1 100%;font-size:11px;white-space:normal}
  .ht-note:empty{display:none}
  .ht-tel{order:7;font-size:11px}
  /* THE ⋮ SITS IN THE ROW'S TOP-RIGHT CORNER. As a flex item on a line of
     its own (order:7, flex:1 0 100%) it pushed every row a button taller,
     and because the small print above it is short the space between the two
     read as a hole down the whole list. Lifted out of the flow it costs no
     height at all, and it lands beside the name — which is the row it
     belongs to and the one a thumb aims at. */
  .ht-guest .ht-acts{position:absolute;top:6px;right:0;z-index:5;
    flex:0 0 auto;justify-content:flex-end}
}

/* How full a hotel is, and the warning when the block is too small. */
.ht-occ{font-weight:700}
.ht-occ.tight{color:#f59e0b}
.ht-occ.over{color:#ef4444}
.ht-warn{font-size:12px;font-weight:700;color:#ef4444;margin:6px 0 0}
.ht-warn.soft{color:#f59e0b;font-weight:600}

/* The directory group a guest belongs to, on the rooming row. */
.ht-grp{min-width:0}
.ht-grp-c{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;font-size:10.5px;font-weight:700;line-height:1.6;
  border-radius:20px;padding:1px 9px;
  background:color-mix(in srgb,var(--c) 16%,transparent);
  border:1px solid color-mix(in srgb,var(--c) 45%,transparent);color:var(--text)}

/* The printed rooming list. */
.ht-doc{width:794px}
.ht-doc-sub{font-size:11px;color:#555;margin:-6px 0 12px}
.ht-doc-notes{font-size:11px;color:#555;margin-top:12px;padding-top:8px;border-top:1px solid #ddd}
/* The group leader's sheet: a heading per group, black on white like
   everything else that leaves the building on paper. */
.htg-grp{font-size:15px;font-weight:800;margin:18px 0 6px;color:#000}
.htg-grp small{font-weight:600;color:#555;font-size:11px}

/* Stars, facilities and the outward links on a hotel card. */
.ht-stars{color:#f59e0b;font-size:13px;letter-spacing:1px}
.ht-facs{display:flex;flex-wrap:wrap;gap:4px;margin-top:7px}
.ht-fac-c{font-size:10.5px;font-weight:600;line-height:1.6;border-radius:5px;padding:1px 7px;
  background:var(--bg3);border:1px solid var(--border);color:var(--text2)}
.ht-links{display:flex;flex-wrap:wrap;gap:10px;margin-top:7px}
.ht-links a{font-size:11.5px;font-weight:700;color:var(--primary,#f59e0b);text-decoration:none}
.ht-links a:hover{text-decoration:underline}
/* Fourteen facility ticks: dense, and scannable. */
.ht-fac{display:grid;gap:6px;margin-top:8px;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,150px),1fr))}
.cp-row[disabled]{opacity:.45;cursor:default}
.cp-row[disabled]:hover{background:none}

/* ── WHO TO RING, AT THE TOP OF A HOTEL ───────────────────────
   The person on the desk, in reach rather than buried in an edit
   dialogue: this is what somebody needs at 23:40 when the door is
   locked. See the note in renderHotels(). */
/* A line, not a banner: it used to run the full width of the card in
   amber with two full-size buttons, and on a card with nobody in it that
   was the biggest thing on the screen. It is as wide as its words now,
   on the card's own grey, with the phone icon as the one touch of
   colour so it is still found at 23:40. */
.ht-mgr{display:inline-flex;align-items:center;gap:10px;max-width:100%;
  flex-wrap:wrap;margin-top:8px;padding:4px 6px 4px 10px;border-radius:9px;
  background:var(--bg3);border:1px solid var(--border)}
.ht-mgr-t{display:flex;align-items:center;gap:7px;min-width:0;flex-wrap:wrap}
.ht-mgr-t svg{width:13px;height:13px;color:var(--primary,#f59e0b);flex-shrink:0}
.ht-mgr-t strong{font-size:12px}
.ht-mgr-t span{font-size:11.5px;color:var(--text2);font-family:ui-monospace,Menlo,Consolas,monospace}
/* Shrinkable, so the three buttons wrap onto their own lines on a narrow
   phone. flex-shrink:0 held the row at its max-content width — the mail
   button then hung past the right edge of the screen. */
.ht-mgr-a{display:flex;gap:5px;flex-wrap:wrap;min-width:0;justify-content:flex-end}
.ht-mgr-a .btn{text-decoration:none;min-height:26px;padding:0 8px;font-size:11px;gap:4px;border-radius:7px}
.ht-mgr-a .btn svg{width:12px;height:12px}

/* ── ONE PERSON, ONE LINK ─────────────────────────────────────
   The summary a name search answers with, above the hotel cards their
   week is spread over. See renderHotels(). */
.ht-people h3{display:flex;align-items:center;gap:7px;font-size:14px}
.ht-people h3 svg{width:16px;height:16px;color:var(--primary,#f59e0b)}
.ht-people .hint{margin:2px 0 8px}
.ht-person{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:8px 0;border-top:1px solid var(--border)}
.ht-person-t{display:flex;flex-direction:column;gap:1px;min-width:0}
.ht-person-t strong{font-size:13.5px}
.ht-person-t small{font-size:11.5px;color:var(--text3);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ht-person .btn{flex-shrink:0;text-decoration:none}

/* ── THE GENERAL START LIST ───────────────────────────────────
   The whole field above the stage picker: who rides this race at all,
   with no times on it. See slFieldCardHtml(). */
.slf-hd{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;flex-wrap:wrap}
.slf-hd-t{min-width:0}
.slf-hd-t h3{display:flex;align-items:center;gap:7px;font-size:15px}
.slf-hd-t h3 svg{width:17px;height:17px;color:var(--primary,#f59e0b)}
.slf-hd-t p{font-size:12px;color:var(--text2);margin-top:2px}
.slf-hd-a{display:flex;gap:6px;flex-wrap:wrap;flex-shrink:0}
.slf-teams{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(232px,100%),1fr));
  gap:12px;margin-top:14px}
.slf-team{border:1px solid var(--border);border-radius:12px;padding:10px 11px;background:var(--bg2)}
.slf-team-hd{display:flex;align-items:center;gap:9px;min-width:0}
.slf-shirt{width:30px;height:30px;object-fit:contain;flex-shrink:0}
.slf-team-t{display:flex;flex-direction:column;gap:1px;min-width:0}
.slf-team-t strong{font-size:12.5px;line-height:1.2;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.slf-team-t small{display:flex;align-items:center;gap:5px;font-size:10.5px;color:var(--text3)}
.slf-team-t small img{width:15px;height:11px;object-fit:cover;border-radius:2px}
.slf-ds{display:flex;align-items:baseline;gap:6px;margin-top:7px;font-size:11px;color:var(--text2);
  padding-top:6px;border-top:1px solid var(--border)}
.slf-ds span{font-size:9px;font-weight:800;letter-spacing:.06em;color:var(--primary,#f59e0b);flex-shrink:0}
.slf-riders{list-style:none;margin:8px 0 0;padding:0}
.slf-riders li{display:flex;align-items:center;gap:7px;padding:2px 0;font-size:12px;min-width:0}
.slf-riders b{flex:0 0 26px;font-variant-numeric:tabular-nums;font-size:11px;color:var(--text3);font-weight:700}
.slf-riders span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.slf-riders em{display:flex;align-items:center;gap:4px;font-style:normal;font-size:10px;
  color:var(--text3);flex-shrink:0}
.slf-riders em img{width:14px;height:10px;object-fit:cover;border-radius:2px}
@media (max-width:720px){
  .slf-teams{grid-template-columns:1fr}
  .slf-hd-a{width:100%}
}

/* ── THE FORM GUIDE ───────────────────────────────────────────
   PCS season points and wins for the riders on this start list. The
   list replaces a donut that showed the same number per stage. */
.pcs-empty{display:flex;flex-direction:column;gap:10px;align-items:flex-start;padding:6px 0}
.pcs-empty p{font-size:12.5px;color:var(--text2);line-height:1.5}
.pcs-list{display:flex;flex-direction:column}
.pcs-row{display:flex;align-items:center;gap:10px;padding:6px 0;
  border-bottom:1px solid var(--border);min-width:0}
.pcs-row:last-child{border-bottom:0}
.pcs-pos{flex:0 0 22px;height:22px;border-radius:7px;display:flex;align-items:center;
  justify-content:center;font-size:11px;font-weight:800;
  background:color-mix(in srgb,var(--primary,#f59e0b) 14%,transparent);
  border:1px solid color-mix(in srgb,var(--primary,#f59e0b) 40%,transparent)}
.pcs-row:nth-child(n+4) .pcs-pos{background:var(--bg3);border-color:var(--border);color:var(--text2)}
.pcs-who{flex:1;min-width:0;display:flex;flex-direction:column;gap:0}
.pcs-who strong{font-size:12.5px;display:flex;align-items:center;gap:6px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* The name is a link to the rider's PCS profile — dressed as a name,
   not as a blue URL; the underline arrives on hover to say so. */
.pcs-rider{color:inherit;text-decoration:none}
.pcs-rider:hover{color:var(--primary,#f59e0b);text-decoration:underline}
.pcs-who strong img{width:15px;height:11px;object-fit:cover;border-radius:2px}
.pcs-who small{font-size:10.5px;color:var(--text3);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pcs-who small.pcs-last{color:var(--text2)}
.pcs-who small.pcs-hist{color:var(--text2);font-weight:600}
.pcs-nums{display:flex;gap:5px;flex-shrink:0}
.pcs-chip{font-size:11px;font-weight:800;padding:2px 8px;border-radius:12px;
  background:var(--bg3);border:1px solid var(--border);font-variant-numeric:tabular-nums}
.pcs-chip.pts{background:color-mix(in srgb,var(--primary,#f59e0b) 12%,transparent);
  border-color:color-mix(in srgb,var(--primary,#f59e0b) 38%,transparent)}
.pcs-foot{display:flex;align-items:center;justify-content:space-between;gap:10px;
  flex-wrap:wrap;margin-top:10px;font-size:11px;color:var(--text3)}
.pcs-foot a{color:var(--text2)}

/* ── EDITING A TEAM ───────────────────────────────────────────
   The modal behind the pencil on the Teams screen. */
.tf-ds{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:6px 0;border-bottom:1px solid var(--border);font-size:12.5px}
.tf-ds.new span::after{content:' •';color:var(--primary,#f59e0b)}
.tf-ds-add{display:flex;gap:7px;margin-top:9px}
.tf-ds-add .input{flex:1;min-width:0}
.tf-ds-add .btn{flex-shrink:0}
@media (max-width:520px){ .tf-ds-add{flex-wrap:wrap} .tf-ds-add .input{flex:1 1 100%} }

/* ── THE BOOKING'S LIFE AROUND THE PLANNING ───────────────────
   Status pill on the name, the still-empty-rooms line, the drift
   since the rooming list went out, the delta modal, the hours grid.
   See "THE BOOKING'S LIFE" in js/hotels.js. */
.ht-st{display:inline-block;vertical-align:middle;font-size:10px;font-weight:800;
  letter-spacing:.05em;text-transform:uppercase;border-radius:20px;padding:2px 9px;
  margin-left:6px;color:var(--text);
  background:color-mix(in srgb,var(--c) 16%,transparent);
  border:1px solid color-mix(in srgb,var(--c) 48%,transparent)}
.ht-free{font-size:12px;color:var(--text2);font-weight:600;margin:6px 0 0}
.ht-free.urgent{color:#f59e0b;font-weight:700}
.ht-sentline{font-size:12px;color:var(--text3);margin:4px 0 0}
.ht-sentline.drift{color:#f59e0b;font-weight:600}
.icon-btn.drift{border-color:#f59e0b;color:#f59e0b}
.ht-delta{max-height:44vh;overflow-y:auto;margin-top:6px}
.ht-delta-l{font-size:12.5px;padding:4px 0;border-bottom:1px solid var(--border);margin:0}
.ht-delta-l.add{color:var(--primary,#f59e0b)}
.ht-delta-l.cut{color:#ef4444}
/* Everybody's own link, one row each — see htBulkLinks(). */
.hl-list{max-height:52vh;overflow-y:auto;margin-top:6px}
.hl-row{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:7px 0;border-bottom:1px solid var(--border)}
.hl-row:last-child{border-bottom:0}
.hl-who{display:flex;flex-direction:column;gap:1px;min-width:0}
.hl-who strong{font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hl-who small{font-size:11px;color:var(--text3)}
.hl-acts{display:flex;gap:5px;flex-shrink:0}
.hl-acts .btn{text-decoration:none}
.hl-progress{font-size:12px;color:var(--text2);margin:6px 0 0}
.hl-progress strong{color:var(--primary,#f59e0b);font-size:14px}
.hl-row.done{opacity:.55}
.hl-row.done .hl-sent{color:var(--primary,#f59e0b);font-weight:700}

.ht-times{display:flex;flex-direction:column;gap:5px}
.ht-times-r{display:grid;grid-template-columns:74px 1fr 1fr 1fr;gap:6px;align-items:center}
.ht-times-r > span{font-size:11px;font-weight:700;color:var(--text2)}
.ht-times-r.hd > span{font-size:9.5px;font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;color:var(--text3)}
.ht-times-r .input{min-height:34px;padding:5px 8px;font-size:12.5px}

/* ── PHOTOS OF THE BUILDING ───────────────────────────────────
   On the card a strip to recognise the place by; in the form a row of
   chips with the link behind each one. Both are links to somebody
   else's server — see hotelInfoSheetHtml(). */
.ht-shots{display:flex;gap:6px;margin-top:9px;overflow-x:auto;padding-bottom:2px;
  scrollbar-width:thin}
.ht-shots a{flex:0 0 auto;display:block;border-radius:9px;overflow:hidden;
  border:1px solid var(--border);line-height:0}
.ht-shots img{height:74px;width:auto;max-width:132px;object-fit:cover;display:block}
@media (max-width:720px){ .ht-shots img{height:62px;max-width:104px} }

.htp-edit{display:flex;flex-direction:column;gap:8px}
.htp-strip{display:flex;flex-wrap:wrap;gap:7px}
.htp-strip:empty{display:none}
.htp-chip{position:relative;display:block;width:86px;height:60px;border-radius:9px;
  overflow:hidden;border:1px solid var(--border);background:var(--bg3)}
.htp-chip img{width:100%;height:100%;object-fit:cover;display:block}
.htp-x{position:absolute;top:2px;right:2px;width:20px;height:20px;border-radius:6px;
  border:0;cursor:pointer;font-size:11px;line-height:1;
  background:rgba(3,37,42,.78);color:#fff}
.htp-x:hover{background:#ef4444}
.htp-add{display:flex;gap:7px}
.htp-add .input{flex:1;min-width:0}
.htp-add .btn{flex-shrink:0}

/* ── THE HOTEL FICHE ──────────────────────────────────────────
   Black on white like every other sheet that leaves the building. The
   width comes from .ht-doc (794 px = A4 portrait). */
.hs-doc .hs-stars{color:#f59e0b;font-size:17px;letter-spacing:1px}
.hs-photos{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-top:14px}
.hs-photos.one{grid-template-columns:1fr}
.hs-photo{border-radius:8px;overflow:hidden;border:1px solid #e2e8f0;line-height:0;height:104px}
/* The first picture is the building itself: it gets the width of the
   page and the height to be worth printing. */
.hs-photo.lead{grid-column:1/-1;height:236px}
.hs-photos.one .hs-photo.lead{height:268px}
.hs-photo img{width:100%;height:100%;object-fit:cover;display:block}

.hs-h{font-family:'Archivo','Work Sans',sans-serif;font-size:13px;font-weight:800;
  text-transform:uppercase;letter-spacing:.04em;color:#0f172a;
  margin:18px 0 7px;padding-bottom:4px;border-bottom:1.5px solid #cbd5e1}
.hs-grid{display:grid;grid-template-columns:1fr 1fr;gap:7px 18px;margin-top:14px}
.hs-grid.hs-half{margin-top:0;grid-template-columns:1fr;align-content:start}
.hs-fact{display:flex;flex-direction:column;gap:1px;padding:6px 9px;border-radius:7px;
  background:#f8fafc;border:1px solid #e6eaef;min-width:0}
.hs-fact span{font-size:8.5px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;color:#64748b}
.hs-fact strong{font-size:12px;color:#0f172a;font-weight:700;word-break:break-word}
.hs-chips{display:flex;flex-wrap:wrap;gap:5px}
.hs-chips span{font-size:10px;font-weight:700;color:#0f172a;background:#eef2f6;
  border:1px solid #cbd5e1;border-radius:20px;padding:2px 9px}
.hs-note{font-size:11px;color:#334155;margin:6px 0 0;line-height:1.45}
.hs-cols{display:grid;grid-template-columns:1.1fr 1fr;gap:18px;align-items:start}
.hs-price{margin-top:0}
.hs-price td{font-size:11.5px}
.hs-num{text-align:right;font-variant-numeric:tabular-nums;font-weight:700}
.hs-tot td{border-top:1.5px solid #0f172a;font-weight:800;background:#f1f5f9}

/* ── THE HOTEL GUIDE FOR THE FEDERATIONS ──────────────────────
   One real A4 per page, photographed on its own — js/hotel-guide.js.
   Black on white with no theme variable anywhere in it: the guide is
   read by twenty federations who never see the app, and the printer
   must agree with the screen. Inter for the body and Space Grotesk for
   the headings, the pair the booklet already prints in. */
.gd-page{position:relative;width:794px;height:1123px;overflow:hidden;background:#fff;
  color:#0f172a;padding:36px 40px 62px;font-family:'Inter',system-ui,sans-serif;
  font-size:12px;line-height:1.45;box-sizing:border-box}
.gd-page *{box-sizing:border-box}
.gd-body{position:relative}
.gd-lh{display:flex;align-items:center;justify-content:space-between;gap:16px;padding-bottom:12px}
.gd-lh-cac{height:40px;width:auto}
/* The edition's own mark leads the letterhead at a size worth the
   paper; beside it the confederation's emblem drops to a signature. */
.gd-lh-ev{height:84px;width:auto;max-width:460px;object-fit:contain;object-position:left center}
.gd-lh.own .gd-lh-cac{height:48px}
.gd-lh.small{padding-bottom:8px}
.gd-lh.small .gd-lh-cac{height:40px}
.gd-lh.small .gd-lh-ev{height:64px;max-width:360px}
.gd-lh.small.own .gd-lh-cac{height:40px}
.gd-hh-logo.own{height:58px;max-width:300px}
/* What the rate includes, and the terms under the card. */
.gd-incl{margin:0 0 6px;font-size:11.5px;font-weight:700;color:#166534}
.gd-rates th{padding:4px 8px}
.gd-rates td.gd-fx{font-weight:600;color:#475569;white-space:nowrap}
.gd-rates th.gd-num{text-align:right}
.gd-terms{display:flex;flex-direction:column;gap:4px;margin-top:8px;font-size:10.5px;line-height:1.4;color:#1e293b}
/* The online road: a code and its address, in the contact card. */
.gd-online{display:flex;align-items:center;gap:12px;margin-top:10px;padding-top:10px;border-top:1px solid rgba(255,255,255,.18)}
.gd-qr{width:92px;height:92px;flex:none;background:#fff;padding:4px;border-radius:6px;line-height:0}
.gd-qr canvas,.gd-qr img{width:84px;height:84px;display:block}
.gd-online-t{display:flex;flex-direction:column;gap:2px;min-width:0;font-size:11px;color:#e2e8f0}
.gd-online-t strong{font-size:12.5px;color:#fff}
.gd-online-t .gd-link{color:#fbbf24;word-break:break-all}
/* The letterhead's rule: dark, with a hair of house green at the end —
   two spans rather than a border-image, which the camera cannot draw. */
.gd-rule{display:flex;height:3px;margin-bottom:18px}
.gd-rule span:first-child{flex:1;background:#0f172a}
.gd-rule span:last-child{width:22%;background:#16a34a}

.gd-kicker{font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:.12em;
  color:#b45309;margin:0 0 6px}
.gd-page h1{font-family:'Space Grotesk','Inter',sans-serif;font-size:34px;font-weight:700;
  letter-spacing:-.6px;line-height:1.05;margin:0 0 6px;color:#0f172a}
.gd-sub{font-size:14px;font-weight:600;color:#475569;margin:0 0 16px}
.gd-intro{font-size:12.5px;line-height:1.55;color:#1e293b;margin:0 0 16px}
.gd-h2{font-family:'Space Grotesk','Inter',sans-serif;font-size:22px;font-weight:700;
  letter-spacing:-.3px;margin:0 0 10px;color:#0f172a}
.gd-h{font-family:'Space Grotesk','Inter',sans-serif;font-size:11px;font-weight:700;
  text-transform:uppercase;letter-spacing:.08em;color:#0f172a;
  margin:14px 0 7px;padding-bottom:4px;border-bottom:1.5px solid #cbd5e1}
.gd-body > .gd-h:first-child,.gd-col .gd-h:first-child{margin-top:0}

/* How to book, and whom to write to: side by side, the two boxes a
   federation manager photographs with a phone. */
.gd-two{display:grid;grid-template-columns:1.15fr 1fr;gap:14px;margin-bottom:6px}
.gd-howto,.gd-contact{border-radius:9px;padding:12px 14px;min-width:0}
.gd-howto{background:#f8fafc;border:1px solid #e2e8f0;border-left:4px solid #16a34a}
.gd-howto ol{margin:6px 0 0;padding:0;list-style:none}
.gd-howto li{margin-bottom:5px;line-height:1.45;display:grid;grid-template-columns:16px 1fr;gap:2px}
.gd-li-n{font-weight:800;color:#16a34a}
.gd-contact{background:#0f172a;color:#fff;display:flex;flex-direction:column;gap:2px}
.gd-contact-k{display:block;font-size:9px;font-weight:800;letter-spacing:.1em;
  text-transform:uppercase;color:#64748b;margin-bottom:4px}
.gd-contact .gd-contact-k{color:#94a3b8}
.gd-contact strong{font-family:'Space Grotesk','Inter',sans-serif;font-size:17px;font-weight:700;line-height:1.15}
.gd-contact em{font-style:normal;font-size:11px;color:#cbd5e1}
.gd-contact-l{display:flex;flex-direction:column;gap:2px;margin-top:8px;font-size:12px;font-weight:600}
.gd-contact-l span{word-break:break-word}
.gd-deadline{margin:8px 0 0;padding-top:8px;border-top:1px solid rgba(255,255,255,.18);font-size:11px;color:#e2e8f0}
.gd-deadline strong{font-size:11px;font-family:'Inter',system-ui,sans-serif;color:#fbbf24}

/* Tables: the same bones as .ce-tbl, one size up for a page that is
   read in the hand. */
.gd-tbl{width:100%;border-collapse:collapse;font-size:11.5px;table-layout:fixed;margin-top:4px}
.gd-tbl th{text-align:left;padding:6px 7px;font-size:8.5px;font-weight:800;letter-spacing:.04em;
  text-transform:uppercase;color:#334155;background:#f8fafc;border-bottom:1.5px solid #0f172a;
  vertical-align:bottom;line-height:1.25;word-wrap:break-word;overflow-wrap:break-word}
.gd-tbl td{padding:6px 7px;border-bottom:1px solid #e6eaef;vertical-align:top;
  word-wrap:break-word;overflow-wrap:break-word;line-height:1.35}
.gd-tbl tbody tr:nth-child(even) td{background:#f7f9fb}
.gd-num{text-align:right;font-variant-numeric:tabular-nums;font-weight:700;white-space:nowrap}
.gd-glance .gd-pg{text-align:right;color:#64748b;font-variant-numeric:tabular-nums}
.gd-tbl-note{font-size:9.5px;color:#64748b;margin:6px 0 0}
.gd-glance-box{margin-top:12px}
.gd-stars{color:#f59e0b;font-size:15px;letter-spacing:1px;white-space:nowrap}
.gd-stars.sm{font-size:11px}

/* ── THE HOTEL PAGE ── */
.gd-hh{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;
  padding-bottom:10px;border-bottom:3px solid #0f172a;margin-bottom:12px}
.gd-hh-t{flex:1;min-width:0}
.gd-hh h2{font-family:'Space Grotesk','Inter',sans-serif;font-size:24px;font-weight:700;
  letter-spacing:-.4px;line-height:1.1;margin:0 0 4px;color:#0f172a}
.gd-hh-logo{height:38px;width:auto;max-width:150px;object-fit:contain;flex-shrink:0}
.gd-addr{font-size:11.5px;color:#334155;margin:0}
/* The building first, at a size worth the paper: the lead picture takes
   the page's width, the rest sit in a strip beneath it. Fixed heights
   with the picture cropped to cover, so a portrait phone shot and a
   wide banner off the hotel's site land in the same frame. The fit pass
   in hgFitHotel() lowers these when a page runs long. */
.gd-photos{margin-bottom:12px}
.gd-photo{border-radius:8px;overflow:hidden;border:1px solid #e2e8f0;line-height:0;height:112px;background:#f1f5f9}
.gd-photo img{width:100%;height:100%;object-fit:cover;display:block}
.gd-photo.lead{height:360px;margin-bottom:6px}
.gd-photo.lead.alone{height:420px;margin-bottom:0}
.gd-thumbs{display:grid;gap:6px}
.gd-thumbs.few .gd-photo{height:190px}
.gd-thumbs.three .gd-photo{height:130px}
/* Two photos: side by side at one height, never one stretched under the other. */
.gd-photos.pair{display:grid;grid-template-columns:1fr 1fr;gap:6px}
.gd-photos.pair .gd-photo.lead{height:240px;margin-bottom:0}
/* The organisation's grade on paper, beside the stars — the screen's pill, in print sizes. */
.gd-tier{display:inline-block;vertical-align:middle;padding:2px 8px;border-radius:999px;margin-left:8px;
  font-family:'Inter',system-ui,sans-serif;font-size:10px;font-weight:800;letter-spacing:.04em;
  text-transform:uppercase;color:#fff;background:var(--c,#64748b);line-height:1.4}
.gd-tier.sm{font-size:8px;padding:1px 6px;margin-left:5px}
/* Fully booked, on paper: ink colours, never the theme's. */
.gd-soldout{display:inline-block;vertical-align:middle;padding:2px 8px;border-radius:999px;margin-left:8px;
  font-family:'Inter',system-ui,sans-serif;font-size:10px;font-weight:800;letter-spacing:.04em;
  text-transform:uppercase;color:#fff;background:#b91c1c;line-height:1.4}
.gd-soldout.sm{font-size:8px;padding:1px 6px;margin-left:5px}
.gd-soldout-line{margin:6px 0 0;padding:6px 10px;border-radius:7px;font-size:11px;font-weight:700;
  color:#991b1b;background:#fef2f2;border:1px solid #fecaca}
.gd-hotel.soldout .gd-photo img{filter:grayscale(1);opacity:.6}
.gd-glance tr.soldout td{color:#94a3b8}
.gd-glance tr.soldout td strong{color:#64748b}
.gd-cols{display:grid;grid-template-columns:1.1fr 1fr;gap:20px;align-items:start}
.gd-col{min-width:0}
.gd-facts{display:grid;grid-template-columns:1fr;gap:5px}
.gd-fact{display:flex;flex-direction:column;gap:1px;padding:5px 9px;border-radius:7px;
  background:#f8fafc;border:1px solid #e6eaef;min-width:0}
.gd-fact span{font-size:8.5px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;color:#64748b}
.gd-fact strong{font-size:12px;color:#0f172a;font-weight:700;word-break:break-word}
.gd-link{color:#1d4ed8;text-decoration:underline;text-underline-offset:2px}
.gd-dist{display:flex;flex-direction:column;gap:3px;margin-top:8px;font-size:11.5px;font-weight:600;color:#1e293b}
.gd-chips{display:flex;flex-wrap:wrap;gap:5px}
.gd-chips span{font-size:10.5px;font-weight:700;color:#0f172a;background:#eef2f6;
  border:1px solid #cbd5e1;border-radius:20px;padding:2px 9px}
.gd-small{font-size:10px;color:#475569;margin:6px 0 0;line-height:1.45}
.gd-rates{margin-top:0}
.gd-rates td{font-size:12px;padding:6px 7px}
.gd-rates tr.room td{font-weight:600}
.gd-book{margin-top:12px;padding:10px 12px;border-radius:8px;background:#f0fdf4;border:1px solid #bbf7d0;
  display:flex;flex-direction:column;gap:2px}
.gd-book strong{font-size:11.5px;color:#14532d}
.gd-book span{font-size:11px;color:#166534;font-weight:600;word-break:break-word}
.gd-note{margin:12px 0 0;padding:10px 12px;border-radius:8px;background:#fffbeb;border:1px solid #fde68a;
  font-size:12px;line-height:1.5;color:#78350f;white-space:pre-line}

/* ── THE REQUEST FORM ── boxes to write in, with the label tucked in
   the top-left corner the way a printed form has it. */
.gd-form-sub{font-size:12px;color:#334155;margin:0 0 4px}
.gd-fgrid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:2px}
.gd-f{position:relative;height:44px;border:1px solid #94a3b8;border-radius:6px;padding:16px 8px 0}
.gd-f.wide{grid-column:1/-1}
.gd-f.tall{height:74px}
.gd-f span{position:absolute;top:4px;left:8px;font-size:8.5px;font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;color:#64748b}
.gd-sign .gd-f{height:56px;margin-top:4px}
/* The paper form has to fit under the wide letterhead: a shade tighter
   than the hotel pages, which have air to spare. */
.gd-form .gd-f{height:40px}
.gd-form .gd-f.tall{height:60px}
.gd-form .gd-h{margin:9px 0 5px}
.gd-form .gd-fgrid{gap:6px}
.gd-ftbl{margin-top:10px}
.gd-ftbl th{text-align:center}
.gd-ftbl td{height:40px;border:1px solid #94a3b8}
/* The list of persons: ruled lines a pen can write in. */
.gd-pfed{margin-bottom:10px}
.gd-ptbl{margin-top:0}
.gd-ptbl th{text-align:left}
.gd-ptbl td{height:29px;padding:4px 6px;border:1px solid #94a3b8}
.gd-ptbl .gd-pn{text-align:right;color:#94a3b8;font-size:9.5px;font-variant-numeric:tabular-nums}
.gd-ptbl tbody tr:nth-child(even) td{background:#fff}
.gd-ticks{display:flex;flex-wrap:wrap;gap:18px;margin:4px 0 8px;font-size:12px;font-weight:600}
.gd-tick{display:inline-flex;align-items:center;gap:7px}
.gd-tick i{display:inline-block;width:14px;height:14px;border:1.5px solid #0f172a;border-radius:3px}

/* Every page's foot: the document, the person to write to, the page. */
.gd-foot{position:absolute;left:40px;right:40px;bottom:16px;display:flex;justify-content:space-between;
  gap:14px;font-size:8.5px;font-weight:700;color:#64748b;text-transform:uppercase;letter-spacing:.05em;
  border-top:1px solid #e2e8f0;padding-top:6px}
.gd-foot span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.gd-foot-c{text-transform:none;letter-spacing:0;font-weight:600}
.gd-foot-n{flex-shrink:0}

/* ── ONE FEDERATION, ON PAPER ── the confirmation sheet, in the guide's
   clothes but flowing rather than boxed: it runs as long as the
   federation is big, and html2pdf cuts it between the rows. */
.gd-sheet{width:794px;background:#fff;color:#0f172a;padding:36px 40px 40px;
  font-family:'Inter',system-ui,sans-serif;font-size:12px;line-height:1.45;box-sizing:border-box}
.gd-sheet *{box-sizing:border-box}
.fs-hd{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:10px}
.fs-hd-t{flex:1;min-width:0}
/* Not a flex row: html2canvas lays a flex heading's words out one by
   one and "South Africa" came off the camera as "S outhA frica". The
   flag sits inline instead, on the baseline of the name. */
.fs-hd h1{font-family:'Space Grotesk','Inter',sans-serif;font-size:28px;font-weight:700;
  line-height:1.15;margin:0 0 4px;color:#0f172a}
.fs-flag{width:34px;height:26px;border-radius:4px;object-fit:cover;box-shadow:0 0 0 1px #cbd5e1;
  vertical-align:-3px;margin-right:10px}
.fs-hd-r{display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex-shrink:0}
.fs-meta{display:flex;flex-direction:column;gap:3px;margin:0 0 6px;padding:9px 12px;border-radius:8px;
  background:#f8fafc;border:1px solid #e6eaef;font-size:11.5px;color:#1e293b}
.fs-hotel{margin-top:18px}
.fs-facts{display:flex;flex-direction:column;gap:3px;margin:0 0 4px;font-size:11.5px;color:#1e293b}
.fs-tbl{margin-top:4px}
.fs-tbl td small{color:#64748b;font-size:10px}
.fs-nights{margin-top:6px}
.fs-est{margin-top:4px}
.fs-tot td{border-top:1.5px solid #0f172a;font-weight:800;background:#f1f5f9}
.fs-book{margin-top:16px}
.fs-doc .gd-note{margin-top:14px}
/* A body on an allocation: what it was given and what it used, above
   the hotels; amber when something is outside it, which is the line the
   organisation invoices back. */
.fs-alloc{display:flex;flex-direction:column;gap:2px;margin:0 0 6px;padding:9px 12px;border-radius:8px;
  background:#f0fdf4;border:1px solid #bbf7d0;font-size:11.5px;color:#14532d}
.fs-alloc strong{font-size:8.5px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;color:#166534}
.fs-alloc.warn{background:#fffbeb;border-color:#fde68a;color:#78350f}
.fs-alloc.warn strong{color:#92400e}
.fs-split td{padding-top:9px;font-size:8.5px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;
  color:#92400e;background:#fff !important;border-bottom:1px solid #fde68a}
.fs-pass td{font-size:11px;color:#1e293b;background:#fffdf5 !important}
.fs-tot.fs-back td{background:#fef3c7;border-top-color:#d97706;color:#78350f}

/* ── RIGHT TO LEFT ── An Arabic page: the same boxes, mirrored by the
   attribute; numbers stay at the end of their row whichever end that
   is; and a face that has Arabic glyphs, which Inter has not. */
.gd-page[dir=rtl],.gd-sheet[dir=rtl],#v-hotelreq[dir=rtl]{
  font-family:'Segoe UI','Noto Sans Arabic','Noto Naskh Arabic',Tahoma,Arial,sans-serif}
.gd-page[dir=rtl] h1,.gd-page[dir=rtl] h2,.gd-page[dir=rtl] .gd-h,.gd-page[dir=rtl] .gd-h2,
.gd-sheet[dir=rtl] h1,.gd-sheet[dir=rtl] h2,.gd-sheet[dir=rtl] .gd-h{
  font-family:'Segoe UI','Noto Sans Arabic','Noto Naskh Arabic',Tahoma,Arial,sans-serif;letter-spacing:0}
.gd-tbl th{text-align:start}
.gd-num,.gd-glance .gd-pg,.gd-rates th.gd-num{text-align:end}
.gd-page[dir=rtl] .gd-lh-ev{object-position:right center}
.gd-page[dir=rtl] .gd-howto{border-left:1px solid #e2e8f0;border-right:4px solid #16a34a}
/* No letter-spacing and no break-word anywhere on the Arabic page:
   html2canvas paints a spaced word one letter at a time, and reads
   overflow-wrap:break-word as leave to break between any two letters,
   which it then does — and a letter on its own loses the joined form
   the word gave it. */
.gd-page[dir=rtl] *{letter-spacing:0;overflow-wrap:normal;word-break:normal}
.gd-page[dir=rtl] .gd-f span{left:auto;right:8px}
.gd-more{margin:12px 0 4px}
.gd-more summary{cursor:pointer;font-size:12.5px;font-weight:700;color:var(--text2);padding:6px 0}

/* The dialogue's hotel list: two columns of ticks on a wide screen. */
.gd-pick{display:grid;gap:6px;margin-top:8px;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr))}

/* Feedback: what it was actually like. */
.hf-avg{display:flex;align-items:baseline;gap:10px;margin-bottom:12px}
.hf-avg strong{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:28px;font-weight:800}
.hf-avg span{color:#f59e0b;font-size:15px;letter-spacing:1px}
.hf-avg small{font-size:11.5px;color:var(--text3)}
.hf-list{max-height:34vh;overflow-y:auto}
.hf-item{padding:9px 0;border-bottom:1px solid var(--border)}
.hf-item:last-child{border-bottom:0}
.hf-hd{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin-bottom:2px}
.hf-hd strong{font-size:12.5px}
.hf-hd small{font-size:11px;color:var(--text3);margin-left:auto}
.hf-item p{font-size:12.5px;color:var(--text2);margin:0;line-height:1.5}

/* ── WHO MAY SEE AND CHANGE WHAT ──────────────────────────────
   Three states per area rather than a tick: hidden, read-only, editable.
   A checkbox could only ever say what may be changed, and said nothing
   about what may be seen. See userModal() in js/admin.js. */
.perm-list{display:flex;flex-direction:column;gap:8px;max-height:44vh;overflow-y:auto;padding:2px}
.perm-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  background:var(--bg3);border:1px solid var(--border);border-radius:10px;padding:9px 12px}
.perm-ico{display:flex;color:var(--text3);flex-shrink:0}
.perm-ico svg{width:17px;height:17px}
.perm-b{flex:1;min-width:140px;display:flex;flex-direction:column;gap:1px}
.perm-b strong{font-size:13px}
.perm-b small{font-size:11px;color:var(--text3);line-height:1.35}
/* A segmented control: the three states are exclusive and reading them
   as one row is the point. */
.perm-opts{display:inline-flex;flex-shrink:0;border:1px solid var(--border);
  border-radius:8px;overflow:hidden}
.perm-opt{position:relative;cursor:pointer;padding:5px 11px;font-size:11.5px;font-weight:700;
  user-select:none;-webkit-user-select:none;
  color:var(--text2);border-right:1px solid var(--border);transition:background .12s,color .12s}
.perm-opt:last-child{border-right:0}
.perm-opt input{position:absolute;opacity:0;pointer-events:none}
.perm-opt:hover{background:var(--bg2)}
.perm-opt.on{background:var(--primary,#f59e0b);color:#04240f}
/* Hidden is a removal, so it reads as one rather than as a third colour. */
.perm-row .perm-opt.on:first-child{background:#ef4444;color:#fff}
@media (max-width:560px){
  .perm-opts{width:100%}
  .perm-opt{flex:1;text-align:center}
}

/* The place search: a line while it thinks, and a line when it finds
   nothing — an empty dropdown leaves somebody wondering whether they
   mistyped. */
.search-busy{padding:10px 12px;font-size:12px;color:var(--text3)}

/* ══════════════ THE ROOM PLAN ══════════════
   A board: people without a bed on the left, rooms on the right. See
   js/hotels.js — every move works by dragging and by tapping twice,
   because HTML5 drag and drop does not fire on the tablet somebody
   actually carries at a race. */
.rp-cols{display:grid;gap:12px;grid-template-columns:minmax(0,220px) minmax(0,1fr);
  align-items:start}
.rp-pool,.rp-room{background:var(--bg3);border:1px solid var(--border);border-radius:10px;
  padding:9px 10px;transition:border-color .12s,background .12s}
.rp-pool{position:sticky;top:0;max-height:56vh;overflow-y:auto}
.rp-rooms{display:grid;gap:10px;
  grid-template-columns:repeat(auto-fill,minmax(min(100%,190px),1fr));
  max-height:56vh;overflow-y:auto;padding:2px}

.rp-hd{display:flex;align-items:center;gap:6px;margin-bottom:7px}
.rp-hd strong{font-size:13px;font-weight:800;min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.rp-n{margin-left:auto;font-size:11px;font-weight:800;border-radius:20px;padding:1px 8px;
  background:var(--bg2);border:1px solid var(--border);color:var(--text2)}
.rp-n.over{background:#ef4444;border-color:#ef4444;color:#fff}
.rp-type{font-size:11px;padding:2px 4px;border-radius:6px;max-width:82px;
  background:var(--bg2);border:1px solid var(--border);color:var(--text2);font-family:inherit}

.rp-drop{display:flex;flex-direction:column;gap:5px;min-height:34px}
.rp-empty{font-size:11px;color:var(--text3);margin:0;padding:5px 2px}

/* A person. Grab-able, and big enough to hit with a thumb. */
.rp-p{display:flex;flex-direction:column;gap:1px;cursor:grab;
  background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:6px 9px}
.rp-p:hover{border-color:var(--text3)}
.rp-p strong{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rp-p small{font-size:10.5px;color:var(--text3);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.rp-p.dragging{opacity:.4}
/* Picked up by tapping: the same state dragging shows, held still. */
.rp-p.picked{border-color:var(--primary,#f59e0b);
  background:color-mix(in srgb,var(--primary,#f59e0b) 16%,transparent)}
/* In this room, but not tonight: visible so the pairing stays readable,
   dimmed so tonight's count is the one the eye trusts. */
.rp-p.dim{opacity:.45}

/* The planner's own bar: hotel, block summary, and the add-rooms row. */
.rp-bar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  padding:10px 12px;margin-bottom:12px}
.rp-hotel{flex:1;min-width:180px;max-width:340px;font-weight:700}
.rp-block{font-size:12px;font-weight:700;color:var(--text2);white-space:nowrap}
.rp-addrow{display:flex;align-items:center;gap:6px;margin-left:auto}
.rp-addrow input{width:58px;text-align:center}
.rp-addrow select{width:auto}

/* The hotel's own number, typed at check-in and not a day before. */
.rp-nr{width:100%;margin-top:7px;font-size:11px;padding:4px 8px;
  background:var(--bg2);border:1px solid var(--border);border-radius:6px;
  color:var(--text2);font-family:inherit}
.rp-nr::placeholder{color:var(--text3)}

/* On the race tonight, in no hotel at all: the list under the pool that
   the caravan answers for. + folds them in; ✕ excuses them tonight. */
.rp-bedless{margin-top:12px;padding-top:10px;border-top:1px dashed var(--border)}
.rp-bedless .rp-hd strong{color:#f59e0b}
.rp-bl{display:flex;align-items:center;gap:4px;padding:3px 0}
.rp-bl-t{flex:1;min-width:0;display:flex;flex-direction:column}
.rp-bl-t strong{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rp-bl-t small{font-size:10.5px;color:var(--text3)}
.rp-bl .icon-btn{font-size:11px}

/* The screen's own double check, above the hotel cards. Foldable, and
   every line is a button that goes to the situation it names. */
.ht-checks{border-left:3px solid #f59e0b;margin-bottom:14px}
.ht-checks.folded{padding-top:12px;padding-bottom:12px}
.ht-checks-hd{display:flex;align-items:center;gap:8px;font-size:13px;margin-bottom:8px;cursor:pointer}
.ht-checks.folded .ht-checks-hd{margin-bottom:0}
.ht-checks-hd svg{color:#f59e0b}
.ht-checks-n{font-size:11px;font-weight:800;color:#f59e0b;
  background:color-mix(in srgb,#f59e0b 14%,transparent);
  border:1px solid color-mix(in srgb,#f59e0b 40%,transparent);
  border-radius:11px;padding:1px 8px}
.ht-checks-hd .icon-btn{margin-left:auto}
.ht-check-l{display:block;width:100%;text-align:left;font-size:12.5px;color:var(--text2);
  line-height:1.5;background:none;border:0;border-radius:7px;padding:4px 7px;margin:1px -7px;
  cursor:pointer;font-family:inherit}
.ht-check-l:hover{background:color-mix(in srgb,#f59e0b 10%,transparent);color:var(--text)}
/* The card a warning walked you to, lit for a breath. */
.ht-card.flash{animation:htFlash 2.4s ease-out}
@keyframes htFlash{
  0%,55%{outline:2px solid var(--primary,#f59e0b);
    box-shadow:0 0 0 5px color-mix(in srgb,var(--primary,#f59e0b) 25%,transparent)}
  100%{outline:2px solid transparent;box-shadow:0 0 0 5px transparent}
}

/* The morning drive, on a card under a night filter. */
.ht-dist{color:var(--text2);font-weight:600}

/* ══════════════ THE BULK BAR ══════════════
   Tick names, act once. The bar sticks to the bottom of the scroll so
   the fortieth tick does not require a hike back up. */
.ht-guests.sel .ht-guest{grid-template-columns:20px minmax(0,1.5fr) 64px minmax(0,110px)
  minmax(0,120px) minmax(0,1fr) minmax(0,110px) 56px}
.ht-selbox{width:16px;height:16px;accent-color:var(--primary,#f59e0b);cursor:pointer}

/* The head of the rooming list: the select-all box, and the column
   names beside it. Quiet on purpose — it labels the list, it is not a
   row of it, so it carries no hover and no pair colour. */
.ht-guests-hd{padding:6px 0;border-bottom:1px solid var(--border2,var(--border))}
.ht-guests-hd span{font-size:9.5px;font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;color:var(--text3);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
@media (max-width:720px){
  /* The phone row is a flex stack with its own order; a header of column
     names has nothing to label there. */
  .ht-guests-hd span{display:none}
  .ht-guests-hd{padding:4px 0}
}
.ht-bulkbar{position:sticky;bottom:12px;z-index:5;display:none;align-items:center;gap:8px;
  flex-wrap:wrap;padding:10px 14px;margin-top:14px;border-radius:12px;
  background:var(--bg2);border:1px solid var(--primary,#f59e0b);
  box-shadow:0 8px 24px rgba(0,0,0,.35)}
.ht-bulkbar.show{display:flex}
.ht-bulk-n{font-size:12.5px;color:var(--text2);margin-right:4px}
.ht-bulk-n strong{font-size:15px;color:var(--primary,#f59e0b)}
/* Under 720px the row is the flex stack above, where the tick simply
   sits on the name's line — see "THE ROW ON A PHONE". */

/* ══════════════ THE HOTEL MAP ══════════════
   Every bed on one map, tonight's hotels green. Same shell pattern as
   the road-works map: the canvas node survives re-renders. */
.ht-map-card{padding:0;overflow:hidden;margin-bottom:14px}

/* ── THE TOP OF THE HOTELS SCREEN ─────────────────────────────
   The map on the left, the counters stacked beside it — the same split
   the accreditation screen makes with .acc-top: the picture and the
   numbers share the fold instead of pushing the list below it. The
   counters stretch to the map's height so the two columns close on one
   line. */
.ht-top{display:flex;gap:14px;align-items:stretch;margin-bottom:14px}
.ht-top .ht-map-card{flex:2 1 560px;min-width:0;margin-bottom:0;
  display:flex;flex-direction:column}
/* Taller (Janny, 12 Oct 2026: "kan je de map van de hotels groter maken? hoger"):
   most of the screen's height, within reason either way. */
.ht-top .ht-map-shell{flex:1;height:auto;min-height:clamp(520px,62vh,760px)}
.ht-top-stats{flex:1 1 260px;min-width:0}
.ht-top-stats .acc-stats{height:100%;margin-bottom:0;align-content:stretch;
  grid-template-columns:repeat(2,minmax(0,1fr))}
@media (max-width:1100px){
  .ht-top{display:block}
  .ht-top .ht-map-card{margin-bottom:12px}
  .ht-top-stats .acc-stats{height:auto;margin-bottom:14px;
    grid-template-columns:repeat(auto-fit,minmax(min(100%,190px),1fr))}
}
@media (max-width:640px){.ht-top .ht-map-shell{min-height:360px}}

/* The pins: a badge with the sleeper count, coloured by situation —
   see htPinState(). S and F wear the letters every roadbook uses. */
.ht-pin{min-width:26px;height:26px;padding:0 6px;border-radius:14px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  font-size:11.5px;font-weight:800;font-family:inherit;color:#02150a;
  background:var(--pin,#f59e0b);border:2px solid rgba(2,6,15,.55);
  box-shadow:0 2px 8px rgba(0,0,0,.45)}
.ht-pin.s-on{--pin:#f59e0b}
.ht-pin.s-free{--pin:#f59e0b}
.ht-pin.s-off{--pin:#a7adb8;opacity:.75}
.ht-pin.s-far{--pin:#ef4444;color:#fff}
.ht-sf{width:26px;height:26px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;font-size:13px;font-weight:900;font-family:inherit;
  border:2px solid #02060f;box-shadow:0 2px 8px rgba(0,0,0,.45);pointer-events:none}
.ht-sf.start{background:#f59e0b;color:#02150a}
.ht-sf.finish{background:#0f172a;color:#fff;border-color:#f59e0b}
.htp-photo{width:100%;height:96px;object-fit:cover;border-radius:8px;margin-bottom:6px;display:block}
.htp-far{color:#ef4444;font-weight:700}
.htp .ht-st{font-size:9px}
.ht-map-shell{position:relative;height:clamp(520px,62vh,760px)}
.ht-map{position:absolute;inset:0}
/* The two route toggles over the map, right of the zoom controls. Each
   wears the colour of the thread it draws, filled only while it is on —
   the button doubles as the legend. */
.ht-route-btns{position:absolute;top:12px;left:52px;z-index:5;display:flex;gap:6px;flex-wrap:wrap}
.ht-route-btn{display:inline-flex;align-items:center;gap:5px;padding:6px 11px;border-radius:9px;
  font-size:12px;font-weight:700;font-family:inherit;cursor:pointer;
  background:rgba(2,6,15,.82);color:#e2e8f0;border:1.5px solid rgba(255,255,255,.22);
  box-shadow:0 2px 8px rgba(0,0,0,.35);backdrop-filter:blur(6px)}
.ht-route-btn.s-start.on{background:#e11d2e;border-color:#e11d2e;color:#fff}
.ht-route-btn.s-finish.on{background:#2563eb;border-color:#2563eb;color:#fff}
@media (max-width:640px){.ht-route-btns{left:50px;top:10px}
  .ht-route-btn{padding:5px 9px;font-size:11px}}
.ht-map-hint{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:9px 14px;margin:0;border-top:1px solid var(--border)}
@media (max-width:640px){.ht-map-shell{height:360px}}

/* The pin's card: the hotel, who is in it, and the two ways to drive
   there. Rendered inside a Mapbox popup, which map.css already themes. */
.htp{display:flex;flex-direction:column;gap:3px;padding:2px 4px;min-width:190px}
.htp strong{font-size:13.5px}
.htp small{font-size:11.5px;color:var(--text2)}
.htp-a{display:flex;gap:6px;flex-wrap:wrap;margin-top:7px}
.htp-a .btn{text-decoration:none}

/* The import preview's hotel chips: ✓ already in this race, + new. */
.hi-hotels{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.hi-h{font-size:11.5px;font-weight:700;border-radius:20px;padding:3px 10px;
  background:var(--bg3);border:1px solid var(--border);color:var(--text2)}
.hi-h.known{border-color:var(--primary,#f59e0b);color:var(--primary,#f59e0b)}

/* ══════════════ MY STAY ══════════════
   The personal link's page: one card per night, tonight's lit. Read on
   a phone in a moving car, so everything is big and the buttons are the
   point. See renderMyStay() in js/hotels.js. */
.ms-night{max-width:560px;margin-bottom:14px}
.ms-night.tonight{border-color:var(--primary,#f59e0b);
  box-shadow:0 0 0 1px var(--primary,#f59e0b)}
.ms-hd{display:flex;align-items:center;gap:10px;margin-bottom:6px}
.ms-day{font-size:12px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  color:var(--text3)}
.ms-badge{font-size:11px;font-weight:800;border-radius:20px;padding:2px 10px;
  background:var(--primary,#f59e0b);color:#06220f}
.ms-night h3{margin:0 0 4px;font-size:17px}
.ms-addr,.ms-room,.ms-mates,.ms-meals{font-size:13px;color:var(--text2);margin:3px 0}
.ms-extra{font-size:12px;color:var(--text3);margin:3px 0}
.ms-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}

/* A target, while something is in hand. */
.rp-pool.armed,.rp-room.armed{cursor:pointer;border-style:dashed}
.rp-pool.hot,.rp-room.hot{border-color:var(--primary,#f59e0b);
  background:color-mix(in srgb,var(--primary,#f59e0b) 10%,transparent)}
.rp-room.over{border-color:#ef4444}

@media (max-width:640px){
  .rp-cols{grid-template-columns:minmax(0,1fr)}
  .rp-pool{position:static;max-height:30vh}
}

/* ══════════════ THE HOTEL BUDGET ══════════════
   Worked out live from the rooms, the stays and the rates — see
   hotelBudget() in js/hotels.js. Nothing here is stored, so nothing
   here can be stale. */
.hb-total{display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;
  padding:14px 16px;margin-bottom:14px;border-radius:12px;
  background:color-mix(in srgb,var(--primary,#f59e0b) 10%,transparent);
  border:1px solid color-mix(in srgb,var(--primary,#f59e0b) 35%,transparent)}
.hb-total-l{display:flex;flex-direction:column;gap:8px}
.hb-total span{font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  color:var(--text2)}
.hb-total-r{display:flex;flex-direction:column;align-items:flex-end;gap:3px;text-align:right}
.hb-total strong{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:26px;font-weight:800;line-height:1.05}
.hb-total small{font-size:11.5px;color:var(--text2);font-weight:600}
.hb-total small.hb-rate{font-size:10.5px;color:var(--text3);font-weight:500}
/* The currency, as a segmented control: the base the rates were typed
   in, then the two the invoices and the bank statements come in. */
.hb-curs{display:inline-flex;border:1px solid var(--border);border-radius:9px;overflow:hidden;
  background:var(--bg3);width:max-content}
.hb-cur{border:0;background:transparent;color:var(--text2);font:inherit;font-size:12px;font-weight:800;
  padding:5px 12px;cursor:pointer;letter-spacing:.02em}
.hb-cur+.hb-cur{border-left:1px solid var(--border)}
.hb-cur.on{background:var(--primary,#f59e0b);color:#111}
.hb-cur:disabled{opacity:.4;cursor:not-allowed}
.hb-charts .ch-bar-val{white-space:nowrap}

.hb-hotel{margin-bottom:10px;padding:12px 14px;border-radius:12px;
  background:var(--bg3);border:1px solid var(--border)}
.hb-hd{display:flex;align-items:center;gap:10px;margin-bottom:8px;flex-wrap:wrap}
.hb-hd strong:first-child{font-size:14px;color:var(--text)}
.hb-sub{display:flex;gap:6px;flex:1;flex-wrap:wrap}
.hb-sub i{font-style:normal;font-size:10.5px;font-weight:700;color:var(--text2);
  background:var(--bg2);border:1px solid var(--border);border-radius:20px;padding:2px 8px;white-space:nowrap}
.hb-tbl{width:100%;border-collapse:collapse;font-size:12.5px}
.hb-tbl td{padding:5px 0;color:var(--text2);border-top:1px solid color-mix(in srgb,var(--border) 60%,transparent)}
.hb-tbl tr:first-child td{border-top:0}
.hb-tbl td b{color:var(--text);font-weight:700}
.hb-tbl small{color:var(--text3)}
.hb-tbl tr.hb-vat td{color:var(--text3)}
.hb-eur{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap;
  font-weight:700;color:var(--text)}
.hb-hd .hb-eur{font-size:15px}
.hb-empty{font-size:11.5px;color:var(--text3);margin:4px 0 10px;line-height:1.5}
.hb-warn{font-size:11.5px;color:#f59e0b;margin:7px 0 0;line-height:1.5}

/* The subtotal on a hotel card, beside the other meta. */
.hb-chip{font-weight:800;color:var(--primary,#f59e0b)}

/* Bulk-adding the caravan to a hotel: the picker rows, tickable. Reuses
   the cp-* text styles; `taken` is somebody already in this hotel. */
.hb-row{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:2px 10px;
  align-items:center;cursor:pointer;padding:8px 12px;
  border-bottom:1px solid var(--border)}
.hb-row:last-child{border-bottom:0}
.hb-row:hover{background:var(--bg3)}
.hb-row input{grid-row:1/3;accent-color:var(--primary,#f59e0b)}
.hb-row .cp-name{grid-column:2}
.hb-row .cp-sub{grid-column:2}
.hb-row .cp-tel{grid-row:1/3;grid-column:3}
.hb-row.taken{opacity:.45;cursor:default}

/* WHO SHARES A ROOM. Two rows wearing one colour read as a pair without
   comparing room numbers; singles stay uncoloured or the signal becomes
   wallpaper. Same palette on the room plan's shared cards. */
.ht-guest.shared{border-left:3px solid var(--pair);padding-left:9px;
  background:color-mix(in srgb,var(--pair) 6%,transparent)}
.ht-guest.shared .ht-room{color:var(--pair)}
.rp-room.shared{border-left:3px solid var(--pair)}
.rp-room.shared .rp-hd strong{color:var(--pair)}

/* ══════════════ THE BADGE STUDIO ══════════════
   A window the size of the screen in three columns: the controls, the
   card on its desk, the names. The controls are the film editor's
   arrangement (.fly-tabs in css/map.css) — small icon buttons, and under
   them only the options of the one pressed. The preview is the print —
   same builder, same CSS — magnified to fill the desk. See
   js/caravan-badges.js. */
.modal.bdg-modal{width:min(1320px,96vw);max-width:none;height:min(940px,94vh);max-height:none}
.bdg-modal .modal-bd{padding:0;overflow:hidden;display:flex;min-height:0}
.bdg-studio{flex:1;min-height:0;display:grid;grid-template-columns:292px minmax(0,1fr) 330px}

/* ── the controls ── */
.bdg-ctl{min-width:0;min-height:0;overflow:auto;padding:12px 14px 16px;border-right:1px solid var(--border)}
.bdg-tabs{position:sticky;top:-12px;z-index:2;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:4px;
  margin:-12px -14px 12px;padding:12px 14px 10px;background:var(--bg2);border-bottom:1px solid var(--border)}
.bdg-tabs button{height:48px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  padding:4px 2px;border-radius:9px;border:1px solid var(--border2);background:var(--bg3);color:var(--text2);cursor:pointer}
.bdg-tabs button svg{width:17px;height:17px}
.bdg-tabs button span{font-size:10px;font-weight:700;line-height:1.1;max-width:100%;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bdg-tabs button:hover{color:var(--text);border-color:var(--gold-border)}
.bdg-tabs button.on{background:var(--gold);border-color:var(--gold);color:#0c0b08}
.bdg-pane[hidden]{display:none}
.bdg-pane .field{margin-bottom:12px}
.bdg-pane .field input{min-height:38px}
.bdg-sub{display:block;margin:12px 0 6px;font-size:10px;font-weight:800;letter-spacing:.07em;
  text-transform:uppercase;color:var(--text3)}
.bdg-hint{margin:0 0 10px;font-size:11.5px;line-height:1.45}

/* Which block: a wrap of small buttons. Struck through when the block is
   switched off — the card can be read from this list without opening
   each one. */
.bdg-blocks{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px}
.bdg-blk{height:26px;padding:0 9px;border-radius:7px;border:1px solid var(--border2);background:var(--bg3);
  color:var(--text2);font-size:11.5px;font-weight:700;cursor:pointer}
.bdg-blk:hover{color:var(--text);border-color:var(--gold-border)}
.bdg-blk.sel{background:var(--gold-bg);border-color:var(--gold);color:var(--gold2)}
.bdg-blk.off{opacity:.55;text-decoration:line-through}
.bdg-grid{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin-bottom:4px}
.bdg-grid .bdg-n:nth-child(3):last-child{grid-column:1 / -1}
.bdg-n{display:flex;flex-direction:column;gap:3px;min-width:0}
.bdg-n span{font-size:10px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--text3)}
.bdg-n .input{min-height:32px;padding:4px 8px;font-size:13px}
.bdg-n input[type=color]{width:100%;height:32px;padding:2px;border-radius:8px;
  background:var(--bg3);border:1px solid var(--border2);cursor:pointer}
.bdg-on{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--text2);margin:2px 0 6px;cursor:pointer}
.bdg-seg{display:grid;grid-template-columns:repeat(3,1fr);margin:10px 0 12px;border:1px solid var(--border2);
  border-radius:8px;overflow:hidden}
.bdg-seg-b{height:30px;border:0;background:var(--bg3);color:var(--text2);font-size:12px;font-weight:700;cursor:pointer}
.bdg-seg-b + .bdg-seg-b{border-left:1px solid var(--border2)}
.bdg-seg-b.on{background:var(--gold-bg);color:var(--gold2)}
.bdg-reset{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}

/* The logo pane: the mark as it is, on white, large enough to judge. */
.bdg-logo-box{height:110px;display:flex;align-items:center;justify-content:center;padding:12px;
  background:#fff;border:1px solid var(--border);border-radius:10px;margin-bottom:6px}
.bdg-logo-box img{max-width:100%;max-height:100%;object-fit:contain}
.bdg-logo-note{margin:0 0 10px;font-size:11.5px}
.bdg-logo-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:10px}

/* One colour well per category. The native input does the picking. */
.bdg-cols{display:grid;gap:6px;grid-template-columns:minmax(0,1fr)}
.bdg-col{display:flex;align-items:center;gap:8px;cursor:pointer;
  background:var(--bg3);border:1px solid var(--border);border-radius:8px;padding:5px 8px}
.bdg-col input{width:30px;height:22px;border:0;padding:0;background:none;cursor:pointer}
.bdg-col span{font-size:11.5px;color:var(--text2);min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ── THE DESK. The card on a dotted ground, as large as the space allows
   (bdgFit() magnifies it), and the block being edited outlined on top —
   preview furniture that never reaches the printer, because it is drawn
   here and not in badgeHtml(). ── */
.bdg-desk{min-width:0;min-height:0;display:flex;flex-direction:column;
  background:radial-gradient(circle,var(--border2) 1px,transparent 1.2px) 0 0/16px 16px,var(--bg);}
.bdg-prev{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;padding:12px;overflow:hidden}
.bdg-fit{position:relative;flex-shrink:0}
.bdg-stage{position:absolute;left:0;top:0;touch-action:none;cursor:grab;user-select:none;
  box-shadow:0 10px 30px rgba(2,6,15,.28);border-radius:4px}
.bdg-stage:active{cursor:grabbing}
.bdg-marker{position:absolute;pointer-events:none;border:1px dashed var(--search,#ffb020);
  box-shadow:0 0 0 1px rgba(255,176,32,.25);border-radius:1px}
.bdg-marker span{position:absolute;left:-1px;bottom:100%;margin-bottom:1px;padding:0 3px;border-radius:2px 2px 0 0;
  background:var(--search,#ffb020);color:#111;font:700 6px/1.5 'Inter',sans-serif;white-space:nowrap}
.bdg-desk-hint{margin:0;padding:8px 14px 10px;font-size:11.5px;color:var(--text3);text-align:center}

/* ── ONE ROW PER NAME. A click puts that person on the card; the arrow
   on the right downloads just their badge. ── */
.bdg-side{min-width:0;min-height:0;display:flex;flex-direction:column;gap:8px;padding:12px 14px;
  border-left:1px solid var(--border)}
.bdg-search{margin-bottom:0;flex-shrink:0}
.bdg-pills{margin-bottom:0;flex-shrink:0}
.bdg-pills .btn{padding:4px 9px;font-size:11.5px}
.bdg-list{flex:1;min-height:0;overflow:auto;border:1px solid var(--border);border-radius:10px}
.bdg-list-hd{position:sticky;top:0;z-index:1;padding:7px 10px;
  font-size:10px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  color:var(--text3);background:var(--bg2);border-bottom:1px solid var(--border)}
.bdg-row{display:flex;align-items:center;gap:10px;padding:5px 6px 5px 10px;
  border-bottom:1px solid var(--border);cursor:pointer}
.bdg-row:last-child{border-bottom:0}
.bdg-row:hover{background:var(--bg3)}
.bdg-row.on{background:var(--gold-bg);box-shadow:inset 3px 0 0 var(--gold)}
.bdg-row-nr{flex-shrink:0;min-width:58px;font-family:ui-monospace,Menlo,Consolas,monospace;
  font-size:11px;font-weight:800}
.bdg-row-n{flex:1;min-width:0;font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bdg-row-n em{font-style:normal;color:var(--text3);margin-left:6px;font-size:11px}
.bdg-row-dl{flex-shrink:0;width:30px;height:30px}

@media (max-width:1100px){
  .bdg-studio{grid-template-columns:260px minmax(0,1fr)}
  .bdg-side{grid-column:1 / -1;border-left:0;border-top:1px solid var(--border);max-height:38vh}
  .bdg-modal .modal-bd{overflow:auto}
  .bdg-studio{grid-template-rows:minmax(480px,1fr) auto}
}
@media (max-width:700px){
  .modal.bdg-modal{height:auto;max-height:94vh}
  .bdg-studio{grid-template-columns:minmax(0,1fr);grid-template-rows:auto}
  .bdg-ctl{border-right:0;border-bottom:1px solid var(--border);max-height:none}
  .bdg-desk{min-height:420px}
}

/* THE NUMBER WHERE THE PHOTO SAT. A caravan row has no portrait, and what
   a steward reads at a windscreen is the series and the number — so it
   gets the photo's place and the distance-readable size. */
.bdg-nr{display:flex;flex-direction:column;align-items:center;margin:14px 0 6px;flex-shrink:0}
.bdg-nr b{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:64px;font-weight:800;line-height:1}
.bdg-nr span{font-size:11px;font-weight:800;letter-spacing:.14em;color:#64748b;margin-top:2px}

/* The print sheets: exactly one A4 each, so html2pdf's page slicing lands
   between the cards and never through one. */
.bdg-doc{background:#ffffff}
/* The page's width, height, margin and gap come from bdgSheetHtml() in
   millimetres, because how many cards fit depends on how big the card
   has been made. What stays here is that a page is a page. */
.bdg-page{background:#ffffff;box-sizing:border-box;
  display:flex;flex-wrap:wrap;align-content:flex-start;justify-content:center;
  page-break-after:always;break-after:page}
.bdg-page:last-child{page-break-after:auto;break-after:auto}

.acc-zn{display:inline-flex;align-items:center;font-size:11px;font-weight:700;line-height:1.5;
  border-radius:5px;padding:2px 7px;
  background:color-mix(in srgb,var(--primary,#f59e0b) 12%,transparent);
  border:1px solid color-mix(in srgb,var(--primary,#f59e0b) 40%,transparent);color:var(--text)}
.acc-bulkbar{display:flex;align-items:center;gap:10px;margin-bottom:10px;
  padding:8px 14px;border-radius:10px;
  background:color-mix(in srgb,var(--primary,#f59e0b) 10%,transparent);
  border:1px solid color-mix(in srgb,var(--primary,#f59e0b) 38%,transparent)}
.acc-bulkbar.empty{visibility:hidden}
.acc-bulkbar strong{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:17px;font-weight:800}
.acc-bulkbar span{font-size:12px;color:var(--text2);flex:1}
.acc-tbl .acc-sel,#acc-sel-all{accent-color:var(--primary,#f59e0b);width:15px;height:15px}
.hon-year{margin-bottom:12px}
.hon-hd{display:flex;align-items:center;gap:12px;margin-bottom:10px}
.hon-y{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:24px;font-weight:800}
.hon-note{flex:1;font-size:12px;color:var(--text3)}
.hon-grid{display:grid;gap:10px 24px;grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr))}
.hon-row{display:flex;align-items:center;gap:9px;padding:4px 0}
.hon-jersey{display:flex;flex-direction:column;gap:2px;padding:4px 0;min-width:0}
.hon-jersey .ce-lbl{margin:0}
.hon-m{font-size:16px;flex-shrink:0}
.hon-p{min-width:0;display:flex;flex-direction:column}
.hon-p strong{font-size:13.5px;line-height:1.25;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.hon-p small{display:flex;align-items:center;gap:5px;font-size:11px;color:var(--text2)}
.hon-block .ce-lbl{margin-bottom:4px}

/* The action strip across the top of a directory card: buttons right,
   small, out of the name's way. Negative top margin folds it into the
   card's own padding so the card barely grows. */
/* The pencil and the bin float in the card's top-right corner instead of
   claiming a bar of their own — the bar pushed every name a full row down,
   leaving the card's most-scanned line under a strip of empty space. The
   name block reserves their width, so long names still wrap cleanly. */
.dir-card{position:relative}
.dir-card .dir-card-top{padding-right:56px}
.dir-card-bar{position:absolute;top:16px;right:16px;display:flex;align-items:center;justify-content:flex-end;gap:3px;
  margin:-8px -8px 2px 0}
.dir-card-bar .icon-btn{width:22px;height:22px;border-radius:6px}
.dir-card-bar .icon-btn svg{width:11px;height:11px}
.dir-live{display:inline-flex;align-items:center;justify-content:center;
  width:20px;height:20px;border-radius:50%;margin-right:auto;flex-shrink:0;
  background:var(--primary,#f59e0b);color:#0b1120;
  box-shadow:0 0 0 3px color-mix(in srgb,var(--primary,#f59e0b) 25%,transparent)}
.dir-live svg{width:10px;height:10px}


/* ══════════════════════════════════════════════════════════
   PORTED FROM THE GOLAZO BUILD
   The screens that arrived with this port bring their own rules:
   wind and heat on the map, the medical plan, municipal permits,
   the daily communique, the personal day page, the hotel record
   and the jersey library. Palette mapped onto the CAC amber; the
   sheets above are untouched.
   ══════════════════════════════════════════════════════════ */
/* ── HOSPITAL & TRAUMA CENTRES ─────────────────────────────────
   One card per hospital: who they are, then where, what they can do
   and how to drive there. It was a single nowrap row of name, badge
   and two icon buttons — the buttons do not shrink, so on a phone the
   name was squeezed into a four-character column and every word of it
   wrapped onto its own line. */
/* Two abreast when the column is wide enough for a readable pair;
   auto-fit drops back to one on its own below that. */
.hosp-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(min(100%,340px),1fr))}
/* The medical map beside the hospital list: the canvas holds its ground
   on the left, the cards stack in one column beside it, and the pair
   folds to map-then-list on a narrow screen. */
.med-hosp-layout{display:grid;gap:14px;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);align-items:start}
.med-hosp-list{grid-template-columns:1fr;max-height:560px;overflow-y:auto;padding-right:4px}
.med-map-shell{position:relative;height:560px;border-radius:12px;overflow:hidden;
  border:1px solid var(--border);background:var(--bg3)}
.med-map{position:absolute;inset:0}
@media (max-width:980px){
  .med-hosp-layout{grid-template-columns:1fr}
  .med-map-shell{height:340px}
  .med-hosp-list{max-height:none;overflow:visible}
}
/* Where an incident was logged: amber, small, unmistakably not a hospital. */
.med-inc-pin{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  background:#f59e0b;color:#231502;font-size:13px;font-weight:900;line-height:1;cursor:pointer;
  border:2px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,.4)}
/* The red cross on the map — the sign every ambulance driver reads. */
.med-pin{width:26px;height:26px;border-radius:8px;display:flex;align-items:center;justify-content:center;
  background:#dc2626;color:#fff;font-size:18px;font-weight:900;line-height:1;cursor:pointer;
  border:2px solid #fff;box-shadow:0 2px 8px rgba(0,0,0,.45)}
.hosp-near:empty{display:none}
.hosp-near{color:var(--text2)}
.hosp-near strong{color:var(--text)}
/* The share list's bulk bar and row ticks. */
.share-bulk{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0 0 10px;
  padding:10px 14px;background:var(--bg2);border:1px solid var(--border);border-radius:10px;font-size:13px}
.share-bulk-all{display:flex;align-items:center;gap:8px;font-weight:700;color:var(--text);cursor:pointer}
.share-bulk-n{font-weight:800;color:var(--text)}
.share-bulk-hint{color:var(--text3);font-size:12px}
.share-bulk input[type=checkbox],.sc-check input{width:18px;height:18px;accent-color:#f59e0b;cursor:pointer}
.sc-check{display:flex;align-items:center;flex-shrink:0;margin-right:2px}
/* ── LIVE TRACKING LINK ────────────────────────────────────────
   The one control on the monitor screen that leaves the app, so it says
   where it goes: the wording on one line, the host underneath. Wide and
   tappable, because on race day this is reached for in a hurry.
   ──────────────────────────────────────────────────────────── */
/* The three doors of the day, in a real GRID — equal columns that wrap
   whole, never three flex guests overlapping each other's laps. */
.lt-doors{display:grid;gap:18px;grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr));
  align-items:start}
.lt-doors > *{min-width:0}
.lt-doors .lt-live-link{align-self:center;flex-wrap:wrap}
/* The medical heading holds the panic button beside the title instead of
   letting it float over the line below. The pulse rings need air, hence
   the row's own margins — a beating shadow clipped against neighbouring
   text reads as a rendering glitch, not an alarm. */
.page-hd-medical{display:flex;align-items:center;justify-content:space-between;
  gap:20px;flex-wrap:wrap;max-width:none;margin-bottom:28px}
.page-hd-medical .btn-emergency{flex-shrink:0;margin:8px 12px 8px 0}
/* The schedule's top row: accreditation + PPO wide, the doping station
   beside them — the three addresses the day is entered through. */
.sched-topcards{display:flex;align-items:stretch;gap:14px;flex-wrap:wrap;margin-bottom:16px}
.sched-topcards .acc-centre-bar{flex:2 1 560px;min-width:0;margin-bottom:0}
.sched-topcards .dope-card{flex:1 1 300px;min-width:0;margin-bottom:0}
/* THE house text field. Half the modals write class="input" believing
   this rule existed; it never did, and those fields rendered as the
   browser's bare white boxes beside fully dressed neighbours. */
.input{width:100%;min-height:40px;padding:8px 12px;border-radius:9px;
  background:var(--bg3);border:1px solid var(--field-border);color:var(--text);
  font-family:inherit;font-size:13.5px;outline:none;transition:border-color .16s}
.input:focus{border-color:var(--gold)}
/* NO `body *{ visibility: hidden }
/* ── MY DAY ───────────────────────────────────────────────────
   The personal link, read on a phone in a car park at half six. Big
   numbers, one block per thing, nothing that needs a second tap. */
.md-sec{margin:22px 0 10px;font-size:13px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--text3)}
.md-badges{display:flex;flex-wrap:wrap;gap:10px;margin:8px 0}
.md-big{display:flex;flex-direction:column;align-items:center;min-width:96px;
  padding:8px 14px;border-radius:11px;background:var(--bg3);border:1px solid var(--border)}
.md-big b{font-size:24px;font-weight:900;line-height:1.1;color:var(--text);
  font-variant-numeric:tabular-nums}
.md-big i{font-style:normal;font-size:9.5px;font-weight:800;letter-spacing:.06em;
  text-transform:uppercase;color:var(--text3);margin-top:2px}
.md-sub{font-size:12.5px;color:var(--text2);margin:2px 0 0}
.md-tags{display:flex;flex-wrap:wrap;gap:5px;align-items:center;margin:8px 0 0;font-size:12px;color:var(--text3)}
.md-day .ms-hd{margin-bottom:4px}
.md-block{margin-top:12px;padding:10px 12px;border-radius:10px;
  background:var(--bg3);border:1px solid var(--border);border-left:3px solid var(--gold2)}
.md-block strong{display:block;font-size:11.5px;font-weight:800;color:var(--text);margin-bottom:3px}
.md-block span{display:block;font-size:12.5px;color:var(--text2);line-height:1.45}
.md-emg-list{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr))}
.md-emg-i{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  padding:10px 12px;border-radius:10px;background:var(--bg3);border:1px solid var(--border);
  text-decoration:none}
.md-emg-i span{font-size:12px;color:var(--text2);min-width:0}
.md-emg-i b{font-size:15px;font-weight:800;color:var(--green);white-space:nowrap;
  font-variant-numeric:tabular-nums}
/* The "my day" link, made from the share screen: type a name, press the
   button beside it. Same row shape as the hotel screen's person list. */
.md-share-find{margin-top:10px}
.md-share-find .input{width:100%;min-height:40px;padding:8px 12px;background:var(--bg3);
  border:1px solid var(--field-border);border-radius:9px;color:var(--text);
  font-size:13.5px;outline:none}
.md-share-list{display:flex;flex-direction:column;margin-top:8px}
.md-share-row{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:8px 0;border-bottom:1px solid var(--border)}
.md-share-row:last-child{border-bottom:0}
.md-share-t{display:flex;flex-direction:column;min-width:0}
.md-share-t strong{font-size:13.5px;color:var(--text)}
.md-share-t small{font-size:11.5px;color:var(--text3)}
/* ── MUNICIPAL PERMITS ────────────────────────────────────────
   One row per town: the name with its windows under it, then the file's
   reference, the contact and the status. Worked through with a
   telephone, so the status is the column the eye lands on. */
.pm-list{display:flex;flex-direction:column}
.pm-row{display:grid;gap:4px 12px;align-items:center;padding:9px 0;
  grid-template-columns:minmax(0,1.6fr) minmax(0,120px) minmax(0,1fr) 122px 44px;
  border-bottom:1px solid var(--border)}
.pm-row:last-child{border-bottom:0}
.pm-town{min-width:0;display:flex;flex-direction:column;gap:2px}
.pm-town strong{font-size:13.5px;color:var(--text)}
/* One line per day, and inside it one chip per closure — the periods
   the municipality is actually being asked to grant. */
.pm-day{display:flex;flex-wrap:wrap;align-items:baseline;gap:3px 7px;
  font-size:11.5px;color:var(--text2);font-variant-numeric:tabular-nums}
.pm-day b{font-weight:800;color:var(--text3);min-width:46px}
.pm-day i{font-style:normal;background:var(--bg3);border:1px solid var(--border);
  border-radius:6px;padding:0 6px;line-height:1.7}
.pm-lbl{color:#64748b}
.pm-ref,.pm-contact{font-size:12px;color:var(--text2);min-width:0;
  overflow:hidden;text-overflow:ellipsis}
.pm-ref span{display:block;font-size:10.5px;color:var(--text3)}
.pm-ref em,.pm-contact em{font-style:normal;color:var(--text3)}
.pm-st{justify-self:start;font-size:10.5px;font-weight:800;line-height:1.7;
  border-radius:20px;padding:1px 10px;white-space:nowrap;color:#fff;background:var(--c)}
@media (max-width:820px){
  /* The name and its windows own the first line; everything else is
     small print under it, the way the rooming rows already behave. */
  .pm-row{display:flex;flex-wrap:wrap;gap:4px 10px}
  .pm-town{flex:1 1 100%}
  .pm-st{order:2}
  .pm-ref,.pm-contact{order:3;font-size:11.5px}
}

/* One file, several stages. Filtered to Wednesday, a town crossed again
   on Friday has to say so or the row reads as the whole truth. */
.pm-also{font-size:11px;color:var(--text3);font-style:italic}

/* ── THE NIGHTS BAR, ABOVE EVERYTHING IT DECIDES ──────────────
   The hotels screen is read one night at a time: the map pins, the five
   counters and every rooming list under them mean "on this night". The
   bar therefore opens the page. An extra night — one the caravan sleeps
   but the race does not ride — is dashed, so a glance tells a booked
   arrival night from a stage. See hotelNights() in js/hotels.js. */
.ht-nights{margin-bottom:14px}
.ht-nights .btn.ht-night-x{border-style:dashed}
.ht-nights .ht-night-add{opacity:.75;font-weight:800}
.ht-nights .ht-night-add:hover{opacity:1}
.ht-nights .ht-night-del svg{width:14px;height:14px}
.ht-nights .ht-night-del[disabled]{opacity:.4;cursor:not-allowed}
/* The stage buttons reuse the hotel and accreditation day bar; only the
   labels are longer here, because a date alone does not say which stage. */
.pm-daybar .btn{max-width:280px;overflow:hidden;text-overflow:ellipsis}


/* ── THE DAILY COMMUNIQUÉ ─────────────────────────────────────
   Portrait, and typewriter-plain on purpose: what the timing partner
   pastes into their template is the same text this sheet prints, so it
   must survive being copied without a stylesheet. See js/communique.js. */
.cq-doc{width:794px;background:#fff;color:#0f172a;padding:26px 32px 30px;
  box-sizing:border-box;font-family:'Work Sans',system-ui,sans-serif}
.cq-doc .rep-hd{border-bottom:3px solid #0f172a;padding-bottom:12px;margin-bottom:14px}
.cq-body{margin:0;white-space:pre-wrap;word-break:break-word;
  font-family:ui-monospace,'Cascadia Mono',Consolas,monospace;
  font-size:11px;line-height:1.55;color:#0f172a}
/* The live preview inside the editor: the same text, on the app's own
   ground rather than on paper. */
.cq-prev{margin:0;white-space:pre-wrap;word-break:break-word;max-height:260px;overflow:auto;
  padding:10px 12px;border:1px solid var(--border);border-radius:9px;background:var(--bg3);
  font-family:ui-monospace,'Cascadia Mono',Consolas,monospace;
  font-size:11.5px;line-height:1.5;color:var(--text2)}
/* What the app already knows, shown rather than asked again. */
.cq-known{display:flex;flex-wrap:wrap;gap:4px 14px;margin-bottom:12px;padding:10px 12px;
  border:1px solid var(--border);border-left:3px solid var(--gold2);border-radius:9px;
  background:var(--bg3)}
.cq-known strong{flex:1 1 100%;font-size:9.5px;font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;color:var(--text3)}
.cq-known span{font-size:12px;color:var(--text2)}
/* ── THE INTERVENTIONS REPORT ─────────────────────────────────
   Same white sheet as the plan; only the summary strip and the
   sign-off are its own. See medIncidentReportHtml() in js/views.js. */
.mh-ec.mh-sum{grid-template-columns:repeat(5,minmax(0,1fr));margin-bottom:4px}
.mh-sign{display:flex;gap:30px;margin-top:26px}
.mh-sign div{flex:1;border-top:1px solid #94a3b8;padding-top:5px;
  font-size:9.5px;letter-spacing:.03em;text-transform:uppercase;color:#64748b}
/* The card's face: the first photo, big enough to recognise the building
   from the parking. Name and address read beside it. */
.ht-hero{flex:0 0 auto;display:block;width:128px;height:128px;border-radius:12px;overflow:hidden;
  border:1px solid var(--border)}
.ht-hero img{width:100%;height:100%;object-fit:cover;display:block}
@media (max-width:720px){
  .ht-hero{width:84px;height:84px}
}
/* The ⋯ overflow: everything occasional, with a label each. */
.ht-more{position:relative}
.ht-more-btn{font-size:19px;font-weight:800;line-height:1}
.ht-more-btn.drift{color:var(--gold2);border-color:var(--gold-border)}
.ht-more-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:40;min-width:250px;
  background:var(--bg2);border:1px solid var(--border);border-radius:11px;box-shadow:var(--shadow);
  padding:6px;display:flex;flex-direction:column;gap:2px}
.ht-mi{display:flex;align-items:center;gap:10px;padding:9px 11px;border:none;background:none;
  border-radius:8px;cursor:pointer;font-family:inherit;font-size:13px;color:var(--text);text-align:left}
.ht-mi svg{width:15px;height:15px;flex-shrink:0;color:var(--text2)}
.ht-mi:hover{background:var(--bg3)}
.ht-mi.danger,.ht-mi.danger svg{color:#ef4444}
.ht-mi.drift,.ht-mi.drift svg{color:var(--gold2)}
@media (max-width:640px){
  .ht-more-menu{right:auto;left:0;max-width:calc(100vw - 36px)}
  .ht-acts .ht-more-menu{left:auto;right:0}
}
/* The guest rows' 176px action column shrinks to one ⋯ now. */
.ht-guest .ht-acts .ht-more{position:relative}
/* ONE HEIGHT ACROSS THE ROW. The labelled buttons are .btn.sm at 36px
   and the pencil and the ⋯ are .icon-btn at 44px, so the row read as
   two rows of buttons that had been pushed together. */
.ht-hd-a .btn.sm,.ht-hd-a .icon-btn{min-height:36px;height:36px}
.ht-hd-a .icon-btn{min-width:36px;width:36px}
.ht-guest .ht-acts{display:flex;justify-content:flex-end;gap:6px}
/* The head of the rooming list: the select-all box, and the column
   names beside it. Quiet on purpose — it labels the list, it is not a
   row of it, so it carries no hover and no pair colour. */
.ht-guests-hd{padding:6px 0;border-bottom:1px solid var(--border2,var(--border))}
.ht-guests-hd span{font-size:9.5px;font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;color:var(--text3);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
@media (max-width:720px){
  /* The phone row is a flex stack with its own order; a header of column
     names has nothing to label there. */
  .ht-guests-hd span{display:none}
  .ht-guests-hd{padding:4px 0}
}
/* The two route toggles over the map, right of the zoom controls. Each
   wears the colour of the thread it draws, filled only while it is on —
   the button doubles as the legend. */
.ht-route-btns{position:absolute;top:12px;left:52px;z-index:5;display:flex;gap:6px;flex-wrap:wrap}
.ht-route-btn{display:inline-flex;align-items:center;gap:5px;padding:6px 11px;border-radius:9px;
  font-size:12px;font-weight:700;font-family:inherit;cursor:pointer;
  background:rgba(2,6,15,.82);color:#e2e8f0;border:1.5px solid rgba(255,255,255,.22);
  box-shadow:0 2px 8px rgba(0,0,0,.35);backdrop-filter:blur(6px)}
.ht-route-btn.s-start.on{background:#e11d2e;border-color:#e11d2e;color:#fff}
.ht-route-btn.s-finish.on{background:#2563eb;border-color:#2563eb;color:#fff}
@media (max-width:640px){
  .ht-route-btns{left:50px;top:10px}
  .ht-route-btn{padding:5px 9px;font-size:11px}
}
/* ══════════════ THE ROLL OF HONOUR ══════════════
   One card per year, newest first: the overall podium left, the jerseys
   right. See js/honours.js — the championship table this replaces
   belonged to the UEC tool. */
/* Years abreast, and every card in a row the SAME height — a cancelled
   year with three dashes must not stand shorter than its neighbours. */
.hon-list{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(min(100%,460px),1fr))}
body.light .hon-y{color:var(--gold)}
.hon-year .hon-grid{padding:0 16px 16px}
.hon-hd .ht-acts{margin-left:auto;flex-shrink:0}
/* The live light: round, green, filled — a status, not a button. It sits
   at the left end of the strip so it cannot be mistaken for an action. */
/* Live on the share links: a breathing green light pinned to the
   avatar's shoulder — where a status light lives on every messenger. */
.dir-ava-wrap{position:relative;display:inline-flex;flex-shrink:0}
.dir-live-dot{position:absolute;right:8px;bottom:-2px;width:12px;height:12px;border-radius:50%;
  background:#22c55e;border:2px solid var(--bg2);
  animation:dir-live-pulse 1.9s ease-in-out infinite}
body.light .dir-live-dot{border-color:#fff}
@keyframes dir-live-pulse{
  0%,100%{box-shadow:0 0 0 0 rgba(34,197,94,.55)}
  50%{box-shadow:0 0 0 5px rgba(34,197,94,0)}
}


/* ══════════════════════════════════════════════════════════
   THE SHUTTLE PLANNER
   The fleet screen's second tab — see js/shuttles.js. Ported from
   the Golazo build with the module; palette on CAC's own tokens.
   ══════════════════════════════════════════════════════════ */
/* ── THE SHUTTLE PLANNER ──────────────────────────────────────
   The fleet screen's second tab. See js/shuttles.js. */

/* The one thing on the screen that is WRONG rather than unfinished: a
   car promised to two people at once. Red and above the filters, because
   filtering it out of sight would not make it stop being true. */
.sh-warn{display:flex;align-items:center;gap:10px;margin-bottom:14px;
  padding:11px 14px;font-size:13px;font-weight:600;
  background:var(--red-bg);border:1px solid var(--red-border);color:var(--text)}
.sh-warn > svg{width:17px;height:17px;color:var(--red);flex-shrink:0}
/* The group rows — one per day, or one per car. A band across the table
   rather than a heading above it: the columns have to keep lining up. */
.sh-grp > td{padding:9px 14px !important;background:var(--bg4,var(--bg3));
  border-top:1px solid var(--border)}
.sh-grp strong{font-size:13px}
.sh-grp.warn > td{background:var(--gold-light);
  box-shadow:inset 3px 0 0 var(--gold2)}
.sh-grp-n{float:right;font-size:11px;font-weight:700;color:var(--text3);
  letter-spacing:.03em;text-transform:uppercase}
.sh-clash{display:inline-flex;align-items:center;gap:4px;margin-left:8px;
  font-size:11px;font-weight:800;color:var(--red)}
.sh-clash svg{width:13px;height:13px}
.sh-tbl tr.sh-bad > td{background:var(--red-bg)}
.sh-time{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:15px;letter-spacing:.01em}
.sh-pax{display:inline-block;min-width:24px;padding:1px 7px;border-radius:11px;
  font-size:11px;font-weight:800;text-align:center;
  background:var(--gold-light);border:1px solid var(--gold-border);color:var(--gold2)}
.sh-arrow{color:var(--text3);font-weight:800}
.sh-wa{color:#25d366;display:inline-flex;vertical-align:-2px}
.sh-wa svg{width:13px;height:13px}
/* The car is chosen from the row itself — the action this screen is
   opened for — so the select has to fit a table cell. */
.sh-assign{height:30px;padding:2px 6px;font-size:12px;max-width:210px}
/* Where a ride has got to. The same five states the driver's two taps
   move it through. */
.sh-st{display:inline-flex;align-items:center;gap:5px;padding:2px 8px;border-radius:11px;
  font-size:11px;font-weight:800;white-space:nowrap;
  background:var(--bg3);border:1px solid var(--border);color:var(--text2)}
.sh-st svg{width:12px;height:12px}
.sh-st.t-gold{background:var(--gold-light);border-color:var(--gold-border);color:var(--gold2)}
.sh-st.t-green{background:var(--green-bg,var(--gold-light));
  border-color:var(--green-border,var(--gold-border));color:var(--green)}
.sh-st.t-blue{background:var(--blue-bg);border-color:var(--blue-border);color:var(--blue)}
.sh-st.t-red{background:var(--red-bg);border-color:var(--red-border);color:var(--red)}
/* The prefilled message, before a human presses send. Monospaced so the
   line breaks that will reach the passenger are the ones on screen. */
.sh-preview{max-height:260px;overflow:auto;margin:0 0 12px;padding:12px 14px;
  border-radius:10px;background:var(--bg3);border:1px solid var(--border);
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;
  line-height:1.55;color:var(--text2);white-space:pre-wrap;word-break:break-word}
.sh-notify{display:flex;gap:8px;flex-wrap:wrap}
/* Attaching a ride to a real person, inside the ride form. Inline rather
   than a second dialogue: openModal() replaces the one modal instead of
   stacking, so a picker opened from here would take the half-filled ride
   with it. */
.sh-pick{margin:4px 0 14px;padding:12px 14px;border-radius:10px;
  background:var(--bg3);border:1px solid var(--border)}
.sh-pick-hd{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.sh-pick-state{flex:1;min-width:0;font-size:11px;color:var(--text3)}
.sh-pick .btn.hidden{display:none}
.sh-pick-list{margin-top:8px}
.sh-pick-list:empty{margin-top:0}
.sh-pick-list .cp-row{border:1px solid var(--border);border-radius:8px;margin-bottom:4px;
  background:var(--bg2)}
.sh-pick-list .cp-row:last-child{margin-bottom:0}
/* What the accreditation desk holds about the linked person, under the
   search box: the number, the role, the car and the bed. It is read to
   check the link found the right human, so it stays one quiet line. */
.sh-pick-facts{margin-top:8px;padding-top:8px;border-top:1px solid var(--border);
  font-size:11.5px;line-height:1.5;color:var(--text2);word-break:break-word}
.sh-pick-facts.hidden,.sh-pick-facts:empty{display:none}
.sh-pick-facts .hint{margin:0}
/* On somebody's own personal link. Which side of the wheel they are on
   is the first thing the card says — a driver and a passenger read the
   same fields for opposite reasons. */
.sh-role{margin-left:auto;font-size:11px;font-weight:800;letter-spacing:.04em;
  text-transform:uppercase;color:var(--gold2)}
.sh-card h3{font-size:15px}
/* ── THE PROCYCLINGSTATS CARD ──────────────────────────────────
   On the Live Track Screen, under the progress track: the same race as
   somebody standing at the roadside sees it. Four numbers, the groups on
   the road, and PCS's own wire. Built to sit beside .lt-box rather than
   replace it, so it inherits the screen's card look and only adds what is
   its own. See js/pcs-live.js. */
.lt-pcs-slot{margin-top:16px}
.pcsl{padding:18px}
.pcsl .lt-box-hd{align-items:flex-start;flex-wrap:wrap;margin-bottom:12px}
.pcsl-tools{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.pcsl-none{font-size:12px;color:var(--text2);margin:8px 0 0}

/* The four numbers. Same shape as the track's own read-outs underneath,
   deliberately: two rows of figures about one race should not look like
   two different products. */
.pcsl-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));
  gap:12px;margin:0 0 14px}
.pcsl-stat dt{font-size:10px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;
  color:var(--text3)}
.pcsl-stat dd{margin:2px 0 0;font-size:19px;font-weight:800;color:var(--text);
  font-family:var(--font-display);font-stretch:var(--display-stretch)}
.pcsl-stat small{display:block;font-size:11px;color:var(--text2);margin-top:1px}

/* The situation. One row per group, the front of the race first; the gap
   is the number an organiser reads first, so it sits hard right where the
   eye can run down it. */
.pcsl-situ-hd,.pcsl-tl-hd{font-size:10px;font-weight:800;letter-spacing:.09em;
  text-transform:uppercase;color:var(--text3);margin:0 0 6px}
.pcsl-situ{list-style:none;margin:0 0 14px;padding:0;display:flex;flex-direction:column;gap:8px}
.pcsl-group{background:var(--bg3);border-radius:10px;padding:9px 12px}
.pcsl-group-hd{display:flex;align-items:center;gap:8px}
.pcsl-bol{display:inline-flex;align-items:center;justify-content:center;
  min-width:22px;height:22px;padding:0 5px;border-radius:50px;flex-shrink:0;
  background:var(--primary,#f59e0b);color:#0b1120;font-size:11px;font-weight:800}
.pcsl-gname{font-size:14px;font-weight:700;color:var(--text)}
.pcsl-n{font-size:11px;color:var(--text2)}
.pcsl-gap{margin-left:auto;font-size:14px;font-weight:800;color:var(--gold2,#e0a800);
  font-variant-numeric:tabular-nums}

.pcsl-riders{list-style:none;margin:7px 0 0;padding:0;
  display:grid;grid-template-columns:repeat(auto-fill,minmax(min(210px,100%),1fr));gap:4px 12px}
.pcsl-riders li{display:flex;align-items:center;gap:6px;min-width:0;font-size:12px}
.pcsl-riders .flag{width:16px;height:12px;flex-shrink:0;border-radius:2px}
.pcsl-bib{display:inline-flex;align-items:center;justify-content:center;
  min-width:24px;padding:1px 4px;border-radius:4px;flex-shrink:0;
  background:var(--bg2);border:1px solid var(--line);
  font-size:10px;font-weight:800;color:var(--text2);font-variant-numeric:tabular-nums}
.pcsl-name{font-weight:700;color:var(--text);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.pcsl-team{font-size:11px;color:var(--text3);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}

/* PCS's wire. Their sentences, their kilometre marker, and nothing of the
   statistics tables that hang off them on their own site. */
.pcsl-tl{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
.pcsl-tl li{display:flex;align-items:baseline;gap:8px;font-size:12px;line-height:1.4;
  padding-bottom:6px;border-bottom:1px solid var(--line)}
.pcsl-tl li:last-child{border-bottom:0;padding-bottom:0}
.pcsl-tl-km{flex-shrink:0;min-width:52px;font-size:11px;font-weight:800;color:var(--text3);
  font-variant-numeric:tabular-nums}
.pcsl-tl-txt{flex:1;min-width:0;color:var(--text)}
.pcsl-tl-ago{flex-shrink:0;font-size:10px;color:var(--text3)}

.pcsl-credit{margin:12px 0 0;font-size:10.5px;color:var(--text3)}
.pcsl-credit a{color:var(--text2);text-decoration:underline}

/* The progress track's own note when the kilometre came from PCS rather
   than from the schedule or our car — the same voice as .lp-gps. */
.lp-note.lp-pcs{color:var(--gold2,#e0a800)}

@media (max-width:600px){
  .pcsl-riders{grid-template-columns:1fr}
  .pcsl-team{display:none}
}

/* "Follow PCS" — the one action that answers the line it sits on, so it is
   part of the sentence rather than a button parked under it. Inside the
   fragment the progress ticker redraws every second; its click is caught on
   the card. See wireLiveProgress(). */
.lp-follow{margin-left:6px;padding:1px 8px;border-radius:50px;cursor:pointer;
  background:transparent;border:1px solid currentColor;color:inherit;
  font:inherit;font-size:11px;font-weight:800;line-height:1.6}
.lp-follow:hover{background:color-mix(in srgb,currentColor 15%,transparent)}
/* ON A PHONE IT IS A BUTTON, NOT A WORD. Inline in the sentence the pill is
   a 21-pixel tap target halfway down a line of text — findable with a mouse,
   not with a thumb at the roadside. Below the card's own breakpoint it keeps
   the same words and gets the room to be pressed: its own place on the line,
   and forty pixels of height. */
@media (max-width:640px){
  .lp-note.lp-pcs{display:flex;flex-wrap:wrap;align-items:center;gap:10px}
  .lp-follow{margin-left:0;min-height:40px;padding:0 16px;font-size:12px}
}

/* ── WEATHER ON THE COURSE ─────────────────────────────────────
   One block per end of the race — its start town and its finish town,
   which on a long stage is two different afternoons. Side by side on a
   desk, stacked on a phone. See ltWeatherHtml() in js/views.js. */
.ltwx{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr));gap:14px;margin-top:12px}
.ltwx-end{background:var(--bg3);border-radius:10px;padding:12px 14px}
.ltwx-hd{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin-bottom:10px}
.ltwx-role{font-size:10px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;
  color:var(--text3);flex-shrink:0}
.ltwx-place{font-size:14px;font-weight:800;color:var(--text);min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ltwx-wait{font-size:12px;color:var(--text2)}
.ltwx-none{font-size:12px;color:var(--text2);margin:8px 0 0}

.ltwx-figs{display:grid;grid-template-columns:repeat(auto-fit,minmax(88px,1fr));gap:12px;margin:0}
.ltwx-c dt{font-size:10px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;color:var(--text3)}
.ltwx-c dd{margin:2px 0 0;font-size:19px;font-weight:800;color:var(--text);
  font-family:var(--font-display);font-stretch:var(--display-stretch)}
/* Wrapping, not clipped: "Bewolkt · gevoel 20°" in a 110-pixel column on a
   phone became "Bewolkt · gevoelstemperatu…", which is a caption that has
   stopped saying anything. Two short lines are the better answer. */
.ltwx-c small{display:block;font-size:11px;color:var(--text2);margin-top:2px;line-height:1.35}
/* The first figure is the one read at a glance from across the room. */
.ltwx-c:first-child dd{color:var(--gold2)}

.ltwx-credit{margin:12px 0 0;font-size:10.5px;color:var(--text3)}
.ltwx-credit a{color:var(--text2);text-decoration:underline}

/* ── OUT OF THE RACE ───────────────────────────────────────────
   A rider marked DNS or DNF stays where they were on the sheet — the start
   order is published and does not shuffle up when somebody abandons — but
   the row reads as past tense: a pale red wash, the text stood down, and
   the badge saying which of the two it was. Deliberately a wash rather
   than a strikethrough: the bib and the name still have to be READ, at a
   finish line, on a phone, in the sun. See SL_OUT in js/startlists.js. */
.sl-tbl tr.sl-row-out > td{background:rgba(220,38,38,.09);color:var(--text2)}
body.light .sl-tbl tr.sl-row-out > td{background:rgba(220,38,38,.07)}
.sl-tbl tr.sl-row-out .c-name,
.sl-tbl tr.sl-row-out .bib{opacity:.75}
.sl-tbl tr.sl-row-out .team-cell img{filter:grayscale(1);opacity:.6}
/* The three arrival columns carry their own colours, and a dash in green
   still reads as a time that is coming. */
.sl-tbl tr.sl-row-out .c-eta{color:var(--text3) !important;opacity:.8}

.sl-out-badge{display:inline-block;margin-left:7px;padding:1px 7px;border-radius:50px;
  vertical-align:middle;font-size:10px;font-weight:800;letter-spacing:.04em;
  background:rgba(220,38,38,.16);color:#e0524b;border:1px solid rgba(220,38,38,.35)}
body.light .sl-out-badge{color:#b91c1c}
/* What seeded a rider on a time trial ordered off the UCI ranking: the
   points in a quiet pill, the medal of last year's podium beside the
   three who leave last. See slSeedBadge() in js/startlists.js. */
.sl-seed{display:inline-block;margin-left:7px;padding:1px 7px;border-radius:50px;vertical-align:middle;
  font-size:10px;font-weight:700;letter-spacing:.02em;font-variant-numeric:tabular-nums;
  background:var(--bg3);color:var(--text2);border:1px solid var(--border)}
.sl-seed.sl-seed-pod{background:none;border:0;padding:0 2px;font-size:14px;line-height:1}
.sl-seeding{margin:8px 0 0}
.sl-seeding b{color:var(--text)}
.sl-seeding .cp-link{margin-left:6px}
/* Specificity, not decoration: `body.light .sl-out-badge` outranks the
   plain `.sl-out-badge.sl-out-dns` below it, so on the light theme both
   badges came out the same red and the two statuses stopped being
   distinguishable at a glance — which is the only job they have. */
body.light .sl-out-badge.sl-out-dns{color:#64748b}
/* Four ways off the list, and a glance down the sheet has to separate
   them: DNF is the road (red), DNS never left the start house (grey),
   DSQ is a decision (amber), OTL is the clock (violet). The row behind
   them stays the same pale red for all four — out is out. */
.sl-out-badge.sl-out-dsq{background:rgba(224,168,0,.16);color:#e0a800;
  border-color:rgba(224,168,0,.38)}
body.light .sl-out-badge.sl-out-dsq{color:#a16207}
.sl-out-badge.sl-out-otl{background:rgba(167,139,250,.16);color:#a78bfa;
  border-color:rgba(167,139,250,.38)}
body.light .sl-out-badge.sl-out-otl{color:#6d28d9}

/* The bulk marker in the sheet footer. A select and not a button: it
   carries five answers, and one of them is the way back into the race. */
.sl-mark{align-items:center;height:30px;padding:0 10px;border-radius:8px;
  background:var(--bg3);border:1px solid var(--border2);color:var(--text);
  font-size:12px;font-weight:700;cursor:pointer}
/* DNS never left the start house; DNF was in the race. Same family, one
   step apart, so a glance down the sheet separates them. */
.sl-out-badge.sl-out-dns{background:rgba(148,163,184,.16);color:#94a3b8;
  border-color:rgba(148,163,184,.35)}

/* ── THE COMMUNIQUÉ IMPORT (js/communique-import.js) ─────────────
   Six blocks, each a tick, a title and a fold of what was found. The
   dialogue is a review, so everything in it reads as a summary rather
   than a form — the only inputs are the day pickers. */
.cqi-block{border:1px solid var(--border);border-radius:10px;margin-bottom:10px;overflow:hidden}
.cqi-hd{display:flex;align-items:center;gap:9px;padding:10px 12px;cursor:pointer;
  background:var(--bg3)}
.cqi-hd svg{width:15px;height:15px;color:var(--gold2);flex-shrink:0}
body.light .cqi-hd svg{color:var(--gold)}
.cqi-hd .cqi-t{font-size:13px;font-weight:800;color:var(--text)}
.cqi-hd small{margin-left:auto;font-size:11.5px;color:var(--text3);white-space:nowrap}
.cqi-bd{padding:12px;border-top:1px solid var(--border)}
/* An unticked block stays readable — it is the evidence for the decision
   not to import it — but says so at a glance. */
.cqi-block:has(.cqi-pick:not(:checked)) .cqi-bd{opacity:.45}
.cqi-pod{display:flex;flex-direction:column;gap:5px;margin-bottom:10px;font-size:13px}
.cqi-pod small{color:var(--text3)}
.cqi-row{display:flex;align-items:center;gap:10px;margin-bottom:8px;font-size:12.5px}
.cqi-row > span{width:110px;flex-shrink:0;font-weight:700;color:var(--text2)}
.cqi-sel{flex:1;min-width:0;min-height:36px;background:var(--bg2);border:1px solid var(--border);
  border-radius:8px;padding:4px 10px;color:var(--text);font-size:13px}
.cqi-list{display:flex;flex-direction:column;gap:4px;max-height:34vh;overflow:auto}
.cqi-li{display:flex;align-items:baseline;gap:8px;font-size:12.5px;padding:3px 0;
  border-bottom:1px solid var(--border)}
.cqi-li:last-child{border-bottom:none}
.cqi-li > span{width:64px;flex-shrink:0;color:var(--text3);font-variant-numeric:tabular-nums}
.cqi-li strong{color:var(--text)}
.cqi-li small{margin-left:auto;color:var(--text3);white-space:nowrap}
.cqi-warn{color:var(--gold2);font-weight:700}
body.light .cqi-warn{color:var(--gold)}

/* The jury's text, exactly as written — a <pre> that wraps. */
.cqi-jury{white-space:pre-wrap;font-family:inherit;font-size:12.5px;line-height:1.5;
  color:var(--text2);background:var(--bg3);border:1px solid var(--border);
  border-radius:10px;padding:12px;margin:0}
.cqi-jury-day{margin-top:14px}
.cqi-jury-hd{display:flex;align-items:center;gap:8px;font-size:12px;font-weight:800;
  color:var(--text2);margin-bottom:7px}

/* The car order's team cell wears its shirt, same size as the
   presentation sheet's. */
.cqi-team{display:flex;align-items:center;gap:8px}
.cqi-shirt{width:22px;height:22px;object-fit:contain;flex-shrink:0}

/* The hand editor: a numbered list with two arrows and a phone field. */
.cqi-edit-row{display:flex;align-items:center;gap:8px;padding:5px 0;
  border-bottom:1px solid var(--border)}
.cqi-edit-row:last-child{border-bottom:none}
.cqi-pos{width:26px;flex-shrink:0;text-align:right;font-size:12px;font-weight:800;
  color:var(--text3);font-variant-numeric:tabular-nums}
.cqi-edit-row strong{flex:1;min-width:0;font-size:12.5px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.cqi-tel{width:130px;flex-shrink:0;min-height:32px;background:var(--bg2);
  border:1px solid var(--border);border-radius:8px;padding:3px 8px;
  color:var(--text);font-size:12px}

/* ── THE ACCREDITATION CENTRE'S LOADING BEAT ───────────────
   Shown for one frame while the 380-row table is built — see
   renderAccreditation(). */
.acc-loading{display:flex;flex-direction:column;align-items:center;gap:14px;
  padding:64px 20px;color:var(--text3);font-size:13px;font-weight:600}
.acc-loading svg{width:30px;height:30px;opacity:.5}
.acc-loading-wheel{width:26px;height:26px;border-radius:50%;
  border:3px solid var(--border2);border-top-color:var(--gold2);
  animation:spin .8s linear infinite}
body.light .acc-loading-wheel{border-top-color:var(--gold)}

/* The page counter under the communiqué reader's wheel. Tabular so
   "page 9 / 19" does not wobble into "page 10 / 19". */
.cqi-load-pages{font-size:12px;color:var(--text3);font-variant-numeric:tabular-nums;min-height:1em}

/* The GO wheel: the app's mark with a ring turning around it. The ring
   is its own element rather than a border on the mark, so the logo sits
   still while the ring moves — a spinning logo reads as an error. */
.cqi-go-loading{display:flex;flex-direction:column;align-items:center;gap:16px;padding:56px 20px}
.cqi-go-mark{position:relative;width:88px;height:88px;display:flex;align-items:center;justify-content:center}
.cqi-go-mark img{width:56px;height:56px;border-radius:14px;display:block}
.cqi-go-ring{position:absolute;inset:0;border-radius:50%;
  border:3px solid var(--border2);border-top-color:var(--gold2);
  animation:spin .9s linear infinite}
body.light .cqi-go-ring{border-top-color:var(--gold)}
.cqi-go-msg{font-size:13px;font-weight:700;color:var(--text2)}

/* The road-works course chips: one per stage, in the course's own
   colour, under the status chips. */
.rw-tabs-course{margin-top:6px}
.rw-tab-course{display:inline-flex;align-items:center;gap:7px}
.rw-tab-sw{width:10px;height:10px;border-radius:3px;background:var(--tc);flex-shrink:0}
.rw-tab-course.active{border-color:var(--tc)}

/* The climb report's favourites block: the app's card colours, not a
   hard-coded dark panel. The old one was grey-on-grey in the light
   theme — team names all but invisible. */
.climb-fav{margin:0 0 12px;padding:11px 13px;background:var(--bg3);
  border:1px solid var(--border);border-radius:10px}
.climb-fav-hd{font-size:12px;color:var(--text);margin:0 0 7px}
.climb-fav-list{margin:0;padding-left:20px;font-size:13px;color:var(--text)}
.climb-fav-list li{margin:3px 0}
.cf-name{font-weight:700;color:var(--text)}
.cf-team{font-size:11.5px;color:var(--text2)}
.cf-pts{margin-left:6px;font-variant-numeric:tabular-nums;color:var(--gold2,#eab308)}
.climb-fav-note{font-size:11px;color:var(--text2);margin:8px 0 0;line-height:1.45}
/* the tick column in the climb table */
.climb-pick,#climb-pick-all{width:16px;height:16px;cursor:pointer;accent-color:var(--ok,#22c55e)}

/* ═══════════════════════════════════════════════════════════
   THE ACCREDITATION REQUEST — the form an outsider fills in, and
   the pile it lands on. See js/accreq.js.

   Two audiences, one set of names. The form is read once, on a phone,
   by somebody who has never seen this app; the pile is read every
   morning by the desk. So the form leans on the cards and fields the
   rest of the app already has and adds only spacing, and the pile is
   the one thing here with markup of its own — a row that has to show a
   face, a name and two decisions without wrapping into a wall.
   ═══════════════════════════════════════════════════════════ */
.areq-card{margin-bottom:14px}
.areq-card h3{margin:0 0 4px}
.areq-card .cr-grid+.cr-grid{margin-top:2px}
.areq-deadline{display:flex;align-items:center;gap:8px;margin:-6px 0 14px;
  padding:9px 13px;border-radius:10px;font-size:13px;font-weight:700;
  background:var(--gold-bg);color:var(--gold2,#d97706);
  border:1px solid var(--gold-border)}
.areq-deadline svg{width:15px;height:15px;flex-shrink:0}
.areq-desk .acc-centre-card+.acc-centre-card{margin-top:8px}
.areq-send{display:flex;flex-direction:column;align-items:center;gap:8px;
  margin:20px 0 40px;text-align:center}
.areq-send .btn{min-width:240px;justify-content:center}
.areq-closed{border-color:var(--red-border)}
.areq-closed h3{color:var(--red)}

/* The receipt. Deliberately a full card and not a toast: the reference
   is the one thing the applicant has to keep, and a message that fades
   after four seconds is a reference nobody wrote down. */
.areq-receipt{text-align:center;padding:26px 20px 24px}
.areq-tick{display:inline-flex;align-items:center;justify-content:center;
  width:52px;height:52px;border-radius:50%;margin-bottom:12px;
  background:color-mix(in srgb,var(--ok,#22c55e) 16%,transparent);color:var(--ok,#22c55e)}
.areq-tick svg{width:26px;height:26px;stroke-width:2.6}
.areq-receipt h3{margin:0 0 12px}
.areq-ref{display:inline-flex;flex-direction:column;gap:3px;margin:0 auto 12px;
  padding:10px 22px;border-radius:10px;background:var(--bg3);border:1px solid var(--border)}
.areq-ref span{font-size:11px;font-weight:800;letter-spacing:.06em;
  text-transform:uppercase;color:var(--text3)}
.areq-ref strong{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:24px;letter-spacing:.08em;color:var(--text)}
.areq-receipt .btn{margin-top:14px}

/* ── THE PILE ─────────────────────────────────────────────── */
.areq-howto h3{margin:0 0 6px}
.areq-howto .btn{margin-top:10px}
.areq-list{display:flex;flex-direction:column;gap:10px}
.areq-row{display:flex;gap:14px;align-items:flex-start;
  background:var(--bg2);border:1px solid var(--border);border-radius:12px;
  padding:13px 15px;box-shadow:var(--shadow)}
/* The colour is the state, on the left edge, so a pile scanned from the
   top says what is still waiting before a single word is read. */
.areq-row{position:relative;overflow:hidden}
.areq-row::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;
  background:var(--gold,#f59e0b)}
.areq-row.s-approved::before{background:var(--ok,#22c55e)}
.areq-row.s-refused::before{background:var(--text3)}
.areq-row.s-refused{opacity:.72}
.areq-face{flex-shrink:0}
.areq-body{flex:1;min-width:0}
.areq-hd{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.areq-hd strong{font-size:15px;color:var(--text)}
.areq-st{font-size:10.5px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  padding:2px 8px;border-radius:999px;
  background:var(--gold-bg);color:var(--gold2,#d97706);border:1px solid var(--gold-border)}
.areq-st.approved{background:color-mix(in srgb,var(--ok,#22c55e) 14%,transparent);
  color:var(--ok,#22c55e);border-color:color-mix(in srgb,var(--ok,#22c55e) 34%,transparent)}
.areq-st.refused{background:var(--bg3);color:var(--text3);border-color:var(--border)}
.areq-code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:11.5px;letter-spacing:.06em;color:var(--text3)}
.areq-fn{font-size:13.5px;font-weight:700;color:var(--text2);margin-top:2px}
.areq-meta{font-size:12.5px;color:var(--text2);margin-top:2px;word-break:break-word}
.areq-note{font-size:12.5px;color:var(--text);margin:7px 0 0;padding:8px 10px;
  background:var(--bg3);border-radius:8px;line-height:1.45}
.areq-note.areq-why{color:var(--red)}
.areq-when{font-size:11px;color:var(--text3);margin-top:6px}
.areq-acts{display:flex;flex-direction:column;gap:6px;align-items:stretch;flex-shrink:0}
.areq-acts .btn{justify-content:center;white-space:nowrap}
@media (max-width:720px){
.areq-row{flex-wrap:wrap}
.areq-acts{flex-direction:row;flex-wrap:wrap;width:100%}
.areq-acts .btn{flex:1}
}

/* ═══════════════════════════════════════════════════════════
   THE FEDERATION ENTRY FORM — see js/fedentry.js.

   A form that is mostly a TABLE, which the rest of this app has almost
   none of on a public page. It is typed into on a laptop by a federation
   secretary with forty riders to enter, so the cells are dense, the
   inputs are borderless until focused, and the whole thing scrolls
   sideways inside its own box rather than pushing the page wide.
   ═══════════════════════════════════════════════════════════ */
.fed-bound{display:flex;align-items:center;gap:11px;margin-bottom:14px;
  padding:11px 14px;border-radius:10px;background:var(--bg3);border:1px solid var(--border)}
.fed-bound svg{width:19px;height:19px;color:var(--primary,#f59e0b);flex-shrink:0}
.fed-bound-t{display:flex;flex-direction:column;gap:1px;min-width:0}
.fed-bound-t strong{font-size:15px;color:var(--text)}
.fed-bound-t small{font-size:12px;color:var(--text2)}

/* ── THE HOTEL REQUEST FORM — js/hotelreq.js ──
   The hotels as the guide shows them: a picture, the name, the rate.
   A federation picks off the card the way it picked off the PDF. */
.hr-hotels{display:grid;gap:10px;margin:10px 0 14px;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr))}
.hr-hotel{display:flex;gap:12px;padding:10px;border-radius:10px;
  background:var(--bg3);border:1px solid var(--border);min-width:0;overflow:hidden}
.hr-hotel-t{flex:1 1 auto}
.hr-hotel img,.hr-nophoto{width:96px;height:72px;border-radius:8px;object-fit:cover;flex-shrink:0;
  background:var(--bg2);display:flex;align-items:center;justify-content:center;color:var(--text3)}
.hr-nophoto svg{width:24px;height:24px}
.hr-hotel-t{display:flex;flex-direction:column;gap:2px;min-width:0}
.hr-hotel-t strong{font-size:14px;color:var(--text);line-height:1.2}
.hr-hotel-t small{font-size:11.5px;color:var(--text2);line-height:1.35}
.hr-hotel-t .hr-rates{color:var(--text);font-weight:700}
.hr-hotel-t .hr-note{color:var(--gold2,#fbbf24)}
/* The sheet's download, at the foot of the card: a quiet button in the
   gold the link's own actions wear, sized for a thumb. */
/* NO WIDER THAN ITS COLUMN. A button does not wrap (.btn is nowrap),
   and "Download hotel information" is wider than the text column of a
   card in a five-across grid, so it stuck out of the card on every
   row (Janny, 18 Sep 2026: "knoppen staan er uit"). The button takes
   the column's width and its words wrap onto a second line when the
   column is narrower than they are — a card is read, not scanned. */
.hr-hotel-t .hr-hotel-pdf{align-self:stretch;max-width:100%;min-width:0;justify-content:flex-start;
  margin-top:6px;min-height:32px;padding:5px 10px 5px 8px;white-space:normal;text-align:left;line-height:1.2;
  border:1px solid var(--gold-border,rgba(245,158,11,.35));color:var(--gold2,#fbbf24);gap:6px}
.hr-hotel-t .hr-hotel-pdf span{min-width:0;white-space:normal}
[dir=rtl] .hr-hotel-t .hr-hotel-pdf{text-align:right}
.hr-hotel-t .hr-hotel-pdf svg{width:15px;height:15px;flex-shrink:0}
.hr-hotel-t .hr-hotel-pdf:hover{background:var(--gold-bg,rgba(245,158,11,.12));color:var(--gold2,#fbbf24)}
[dir=rtl] .hr-hotel-t .hr-hotel-pdf{padding:0 8px 0 10px}

/* An official hotel says so beside its name, and the desk's own two
   buttons sit apart from the visitor links above them. */
.ht-official{display:inline-flex;align-items:center;gap:4px;vertical-align:middle;
  padding:2px 8px 2px 6px;border-radius:999px;font-size:11px;font-weight:800;
  letter-spacing:.02em;text-transform:uppercase;
  background:var(--green-bg,rgba(52,211,153,.12));color:var(--green,#16a34a);
  border:1px solid var(--green-border,rgba(52,211,153,.35))}
.ht-official svg{width:12px;height:12px}
/* Fully booked: the desk's badge, and on the request link a greyed card
   that says so in words. */
.ht-soldout{display:inline-flex;align-items:center;gap:4px;vertical-align:middle;
  padding:2px 8px 2px 6px;border-radius:999px;font-size:11px;font-weight:800;
  letter-spacing:.02em;text-transform:uppercase;
  background:var(--red-bg,rgba(239,68,68,.12));color:var(--red,#dc2626);
  border:1px solid var(--red-border,rgba(239,68,68,.35))}
.ht-soldout svg{width:12px;height:12px}
.hr-hotel.soldout img,.hr-hotel.soldout .hr-nophoto{filter:grayscale(1);opacity:.55}
.hr-hotel.soldout .hr-hotel-t strong{color:var(--text2)}
.hr-hotel-t .hr-soldout{align-self:flex-start;margin:2px 0;padding:2px 8px;border-radius:6px;
  font-size:11px;font-weight:800;letter-spacing:.02em;text-transform:uppercase;
  background:var(--red-bg,rgba(239,68,68,.12));color:var(--red,#dc2626);
  border:1px solid var(--red-border,rgba(239,68,68,.35))}
/* A federation's own hotel, on the hotels screen: theirs, not a proposal.
   Not .ht-own — that name once belonged to the row of "Mark as official /
   Sign-up link" links under the card, and a pill drawn round it made the
   two one; the row is .ht-acts now, and the name stays retired. */
.ht-theirs{display:inline-flex;align-items:center;gap:4px;vertical-align:middle;
  padding:2px 8px 2px 6px;border-radius:999px;font-size:11px;font-weight:800;
  letter-spacing:.02em;text-transform:uppercase;
  background:var(--gold-bg,rgba(180,83,9,.10));color:var(--gold2,#b45309);
  border:1px solid var(--gold-border,rgba(180,83,9,.32))}
.ht-theirs svg{width:12px;height:12px}
/* The own-hotel option on the request form, and a line's box marked red. */
.hr-own{margin-top:14px;padding-top:12px;border-top:1px dashed var(--border,#e2e8f0)}
/* A journey of two hotels on one link: "Stay 1 / Stay 2" on the cards,
   a tick column per stay in the people table. */
.hr-stay-k{display:inline-block;margin-bottom:3px;padding:1px 7px;border-radius:999px;
  font-size:10px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  color:var(--gold2,#b45309);background:var(--gold-bg,rgba(180,83,9,.10));border:1px solid var(--gold-border,rgba(180,83,9,.32))}
.hr-seq-hint{margin-top:10px}
.hr-s-hint{margin:2px 0 0;min-height:1em}
.hr-stay-th,.hr-stay-td{text-align:center;width:72px}
.hr-stay-tick{width:18px;height:18px;accent-color:var(--primary,#f59e0b);cursor:pointer}
.hr-own .hint{margin:6px 0 0}
#hr-own-box{margin-top:10px}
.fed-tbl input.invalid,.fed-tbl select.invalid{border-color:var(--red,#dc2626);box-shadow:0 0 0 2px rgba(220,38,38,.15)}
/* An allocation: what a body was given, said on the form and counted
   back at the desk. The warning colour is a flag, not a refusal. */
.hr-quota{display:flex;flex-direction:column;gap:2px;margin:10px 0 0;padding:11px 13px;
  border-radius:10px;background:var(--green-bg,rgba(52,211,153,.10));
  border:1px solid var(--green-border,rgba(52,211,153,.30));font-size:13.5px;line-height:1.5}
.hr-quota strong{color:var(--green,#16a34a);font-size:11.5px;font-weight:800;
  letter-spacing:.06em;text-transform:uppercase}
.hr-quota small{color:var(--text3,#64748b);font-size:12px}
.hr-quota-use{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 10px;
  margin:8px 0 0;padding:9px 12px;border-radius:9px;font-size:13px;
  background:var(--bg4,#f1f5f9);border:1px solid var(--line,#e2e8f0)}
.hr-quota-use.warn{background:var(--gold-bg,rgba(180,83,9,.09));
  border-color:var(--gold-border,rgba(180,83,9,.32))}
.hr-quota-use strong{font-weight:800;letter-spacing:.04em}
.hr-quota-use small{flex:1 0 100%;color:var(--text3,#64748b);font-size:12px}
/* THE ALLOCATIONS EDITOR. One card per body, and inside it the tiers
   — "so many rooms, so many days early" — indented under their own
   line, so a row of numbers reads as belonging to the body above it
   and not as three more settings of its own. The empty card at the
   end is how a body is added, so it is drawn dashed, not hidden. */
.hq-row{margin:12px 0 0;padding:12px 14px 6px;border-radius:12px;
  background:var(--bg3,rgba(255,255,255,.03));border:1px solid var(--border,#e2e8f0)}
.hq-row[hidden]{display:none}
.hq-row.hq-blank{background:transparent;border-style:dashed}
.hq-row .cr-grid{gap:10px}
.hq-3{grid-template-columns:repeat(auto-fit,minmax(min(100%,132px),1fr))}
.hq-tiers-h{margin:8px 0 2px}
.hq-tier{margin-top:2px;padding-left:12px;border-left:3px solid var(--border,#e2e8f0)}
.hq-tier .field label{font-size:11px}
.hq-row .hr-quota-use{margin-bottom:6px}
.hq-drop{margin:6px 0 2px;text-align:right}

/* The organisation's own grading, beside the building's stars. */
.ht-tier{display:inline-block;vertical-align:middle;padding:2px 9px;border-radius:999px;
  font-size:11px;font-weight:800;letter-spacing:.03em;text-transform:uppercase;
  color:#fff;background:var(--c,#64748b)}
/* The two things a hotel is to the organisation, as the app's own
   buttons under the links — they were underlined links, which read as
   nothing else on this screen does. Its own class: .ht-acts is the
   card's right-hand row of Person / Group / Rooms, and sharing the name
   sent these two to the right and spread that row out. Sized to the
   11.5 px link line above them, not to a form. */
.ht-marks{display:flex;flex-wrap:wrap;justify-content:flex-start;gap:6px;margin-top:8px}
.ht-marks .btn{min-height:28px;padding:0 9px;font-size:11.5px;gap:5px;border-radius:7px}
.ht-marks .btn svg{width:12px;height:12px}
.ht-marks .btn[disabled]{opacity:.5;cursor:default}
.ht-link-url code{display:block;word-break:break-all;padding:10px 12px;border-radius:8px;
  background:var(--bg4,#f1f5f9);font-size:13px}
.ht-chain{margin-top:14px;padding-top:10px;border-top:1px dashed var(--border,#e2e8f0)}
.ht-chain summary{cursor:pointer;font-weight:700;font-size:13px;color:var(--text2)}
.ht-chain .hint{margin:8px 0 10px}
.ht-chain p:last-child{margin:8px 0 0}
/* Which link the dialogue is showing: the one already out, or a new one. */
.ht-link-note{display:flex;align-items:flex-start;gap:9px;margin:0 0 12px;padding:10px 12px;border-radius:9px;
  font-size:13px;line-height:1.45;font-weight:600;
  background:var(--gold-bg,rgba(180,83,9,.10));border:1px solid var(--gold-border,rgba(180,83,9,.32));color:var(--gold2,#b45309)}
.ht-link-note.new{background:var(--green-bg,rgba(52,211,153,.10));border-color:var(--green-border,rgba(52,211,153,.30));color:var(--green,#16a34a)}
.ht-link-note svg{width:15px;height:15px;flex-shrink:0;margin-top:2px}
.ht-link-note small{display:block;font-weight:500;opacity:.8}

/* The profile download dialogue's ticks: one row each, the tick beside
   the name and the explanation under it — the panel's own .cp-sw is a
   grid chip and runs the three of them into one line in a modal. */
.cp-dlsws{display:flex;flex-direction:column;margin-top:14px;
  border-top:1px solid var(--line,#e2e8f0);padding-top:6px}
.cp-dlsw{display:flex;align-items:flex-start;gap:10px;padding:9px 2px;cursor:pointer}
.cp-dlsw + .cp-dlsw{border-top:1px solid var(--line,#e2e8f0)}
.cp-dlsw input{margin-top:3px;flex:none}
.cp-dlsw strong{display:block;font-size:13.5px;font-weight:600;color:var(--text)}
.cp-dlsw small{display:block;margin-top:1px;font-size:12px;color:var(--text3,#64748b)}
/* THE PAPER BLOCK of the two download dialogues — the paper and the
   white margins a PDF is set in (cpOnPaper). Shown for the PDF, folded
   away for a picture; the four margin fields are the panel's own
   .cp-margins row, given a little air in a modal. */
.cp-dl-paper{margin-top:4px;padding:10px 12px 11px;border-radius:9px;
  background:var(--bg3);border:1px solid var(--border)}
.cp-dl-paper[hidden]{display:none}
.cp-dl-paper .fl{margin-bottom:8px}
.cp-dl-lbl{display:block;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;
  color:var(--text3,#64748b);margin:0 0 6px}
.cp-dl-paper .cp-margins .input{font-size:13px;padding:6px 6px}
.cp-dl-note{display:block;margin-top:8px;font-size:12px;line-height:1.45;color:var(--text3,#64748b)}

/* WHO PAYS THE HOTEL. The one commercial fact a federation must not be
   able to miss — said beside the rates and again above the send button,
   in a box rather than in the grey hint it used to share with them. */
.hr-pay{display:flex;gap:10px;align-items:flex-start;margin:10px 0 14px;padding:11px 13px;
  border-radius:10px;background:var(--gold-bg,rgba(180,83,9,.09));
  border:1px solid var(--gold-border,rgba(180,83,9,.32));
  color:var(--text);font-size:13.5px;line-height:1.5}
.hr-pay strong{color:var(--gold2,#d97706);white-space:nowrap}
#v-hotelreq[dir=rtl] .hr-pay{flex-direction:row}

/* The quota panel — the answer to "how many are we allowed". */
.fed-quota-list{display:flex;flex-direction:column;gap:4px;margin-top:8px}
.fed-q-row{display:flex;align-items:center;gap:10px;padding:6px 10px;border-radius:8px;
  background:var(--bg3);font-size:13px}
.fed-q-lbl{flex:1;min-width:0;color:var(--text2)}
.fed-q-lbl small{color:var(--text3)}
.fed-q-n{font-variant-numeric:tabular-nums;font-weight:800;color:var(--text)}
.fed-q-row.over{background:var(--red-bg)}
.fed-q-row.over .fed-q-n{color:var(--red)}
/* A row counted per gender — the mixed relay's five men and five women —
   carries words where the others carry a figure. On a phone they do not
   fit beside the race name, so the row wraps and the count takes the
   line under it rather than printing across it. */
.fed-q-row.split{flex-wrap:wrap;row-gap:2px}
.fed-q-row.split .fed-q-lbl{flex:1 1 150px}
.fed-q-row.split .fed-q-n{flex:0 1 auto;min-width:0;margin-left:auto;text-align:right}
.fed-q-row.split .fed-q-n small{font-weight:600;color:inherit;opacity:.75}

.fed-count{display:inline-block;min-width:22px;padding:1px 7px;border-radius:999px;
  font-size:12px;font-weight:800;font-variant-numeric:tabular-nums;
  background:var(--gold-bg);color:var(--gold2,#d97706);border:1px solid var(--gold-border);
  vertical-align:middle;margin-left:6px}

.fed-tbl-wrap{overflow-x:auto;margin:10px 0 10px;border:1px solid var(--border);border-radius:10px}
.fed-tbl{width:100%;border-collapse:collapse;font-size:13px}
.fed-tbl th{position:sticky;top:0;z-index:1;text-align:left;white-space:nowrap;
  padding:9px 8px;background:var(--bg3);color:var(--text2);
  font-size:11px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  border-bottom:1px solid var(--border)}
.fed-tbl td{padding:3px 5px;border-bottom:1px solid var(--border);vertical-align:middle}
.fed-tbl tr:last-child td{border-bottom:0}
.fed-tbl .fed-n{width:34px;text-align:right;padding-right:8px;
  color:var(--text3);font-variant-numeric:tabular-nums}
.fed-tbl .fed-tick{width:44px;text-align:center}
.fed-tbl .fed-tick input{width:16px;height:16px;cursor:pointer;accent-color:var(--primary,#f59e0b)}
.fed-tbl .fed-x{width:38px;text-align:center}
.fed-tbl .input{width:100%;min-width:110px;border:1px solid transparent;background:transparent;
  box-shadow:none;padding:6px 7px;font-size:13px;border-radius:6px}
.fed-tbl .input:hover{border-color:var(--border)}
.fed-tbl .input:focus{border-color:var(--primary,#f59e0b);background:var(--bg2);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--primary,#f59e0b) 16%,transparent);outline:none}
.fed-tbl select.input{min-width:130px}
.fed-tbl input[type=date].input{min-width:140px}

/* The read-back column: which start lists this one rider lands on. */
.fed-races-h{width:96px}
.fed-tbl td.fed-races{white-space:nowrap;padding-left:8px}
.fed-race-chip{display:inline-block;margin-right:4px;padding:1px 6px;border-radius:5px;
  font-size:10.5px;font-weight:800;letter-spacing:.03em;
  background:color-mix(in srgb,var(--ok,#22c55e) 15%,transparent);color:var(--ok,#22c55e)}
.fed-race-none{font-size:11px;font-weight:700;color:var(--gold2,#d97706)}

.fed-tbl-acts{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.fed-tbl-acts .hint{margin:0}
.fed-paste{margin-top:12px;padding:12px;border-radius:10px;
  background:var(--bg3);border:1px solid var(--border)}
.fed-paste .code-ta{width:100%;margin:0 0 10px}

/* ── THE PILE, ON THE FEDERATIONS SCREEN ─────────────────────
   A banner rather than a tab: it is empty most of the year, and a tab
   that says nothing eleven months out of twelve trains people not to
   look at it. */
.fed-inbox{display:flex;align-items:center;gap:13px;margin-bottom:18px;padding:14px 16px;
  border-left:3px solid var(--gold,#f59e0b)}
.fed-inbox.done{border-left-color:var(--ok,#22c55e)}
.fed-inbox-ico{display:flex;flex-shrink:0;color:var(--gold2,#d97706)}
.fed-inbox.done .fed-inbox-ico{color:var(--ok,#22c55e)}
.fed-inbox-ico svg{width:20px;height:20px}
.fed-inbox-t{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.fed-inbox-t strong{font-size:14px;color:var(--text)}
.fed-inbox-t small{font-size:12px;color:var(--text2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* The pile as rows: one request a line, its buttons on the right. */
.fed-inbox.hr-pile{display:block}
.hr-pile-hd{display:flex;align-items:center;gap:13px}
.hr-pile-rows{display:flex;flex-direction:column;gap:6px;margin-top:10px}
.hr-pile-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:7px 10px;border-radius:9px;
  background:var(--bg3);border:1px solid var(--border)}
.hr-pile-t{flex:1;min-width:220px;display:flex;flex-direction:column;gap:1px}
.hr-pile-t strong{font-size:13px;color:var(--text)}
.hr-pile-t small{font-size:11.5px;color:var(--text2)}
.hr-pile-a{display:flex;gap:6px;flex-wrap:wrap}
.hr-pile-a .btn{min-height:30px;padding:0 10px;font-size:12px}
.hr-pile-a .btn svg{width:13px;height:13px}

/* ── THE REVIEW ───────────────────────────────────────────── */
.fedrev-hd{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:10px}
.fedrev-hd strong{font-size:16px;color:var(--text)}
.fedrev-hd span{font-size:12.5px;color:var(--text2)}
.fedrev-warn{padding:11px 13px;border-radius:10px;margin-bottom:12px;
  background:var(--gold-bg);border:1px solid var(--gold-border)}
.fedrev-warn strong{display:block;font-size:12.5px;color:var(--gold2,#d97706);margin-bottom:5px}
.fedrev-warn ul{margin:0;padding-left:18px;font-size:12.5px;color:var(--text)}
.fedrev-warn li{margin:2px 0}
.fedrev-ok{display:flex;align-items:center;gap:8px;margin-bottom:12px;padding:9px 13px;
  border-radius:10px;font-size:13px;font-weight:700;
  background:color-mix(in srgb,var(--ok,#22c55e) 12%,transparent);color:var(--ok,#22c55e)}
.fedrev-ok svg{width:16px;height:16px}
.fedrev-tbl{max-height:320px;overflow-y:auto}
.fedrev-tbl .fed-tbl td{padding:6px 8px}
.fedrev-bad td{background:var(--red-bg)}

/* ── ONE LINK PER FEDERATION ─────────────────────────────── */
.fedlink-list{display:flex;flex-direction:column;gap:6px;max-height:60vh;overflow-y:auto}
.fedlink-row{display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:9px;
  background:var(--bg3);border:1px solid var(--border)}
.fedlink-row.open{border-color:var(--gold-border);background:var(--gold-bg)}
.fedlink-t{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.fedlink-t strong{font-size:13.5px;color:var(--text)}
.fedlink-t small{font-size:11.5px;color:var(--text3)}
.fedlink-acts{display:flex;gap:6px;align-items:center;flex-shrink:0}

/* ═══════════════════════════════════════════════════════════
   ARRIVALS & DEPARTURES — see js/travel.js.

   Read like a board at an airport, which is what it is: time on the
   left in the biggest type on the row, because the whole screen is
   scanned for "what is next" and nothing else. The second line under it
   is the time a CAR has to be there, which is the number the reader
   actually acts on.
   ═══════════════════════════════════════════════════════════ */
.tv-board{display:flex;flex-direction:column;gap:20px}
.tv-day-hd{margin:0 0 8px;font-size:12px;font-weight:800;letter-spacing:.07em;
  text-transform:uppercase;color:var(--text3)}
.tv-cluster{display:flex;flex-direction:column;gap:6px}
/* A cluster only draws a box around itself when there is something to
   say — one flight in a frame labelled "1 movement" is furniture. */
.tv-cluster.many{padding:10px;border-radius:12px;
  background:var(--bg3);border:1px dashed var(--gold-border)}
.tv-cluster-hd{display:flex;align-items:center;gap:9px;padding:0 4px 8px;
  font-size:12.5px;font-weight:700;color:var(--gold2,#d97706)}
.tv-cluster-hd svg{width:16px;height:16px;flex-shrink:0}
.tv-cluster-hd span{flex:1;min-width:0}

.tv-row{display:flex;align-items:center;gap:13px;padding:11px 14px;
  background:var(--bg2);border:1px solid var(--border);border-radius:11px;
  box-shadow:var(--shadow);position:relative;overflow:hidden}
.tv-row::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;
  background:var(--gold,#f59e0b)}
.tv-row.met::before{background:var(--ok,#22c55e)}
.tv-time{display:flex;flex-direction:column;gap:0;min-width:74px;flex-shrink:0}
.tv-time strong{font-family:var(--font-display);font-stretch:var(--display-stretch);
  font-size:20px;line-height:1.05;color:var(--text);font-variant-numeric:tabular-nums}
.tv-time small{font-size:10.5px;font-weight:700;color:var(--gold2,#d97706);
  font-variant-numeric:tabular-nums}
.tv-dir{display:flex;flex-shrink:0;color:var(--text3)}
.tv-dir svg{width:17px;height:17px}
.tv-row.d-in .tv-dir{color:var(--ok,#22c55e)}
.tv-row.d-out .tv-dir{color:#3b82f6}
.tv-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.tv-main strong{font-size:14.5px;color:var(--text)}
.tv-sub{font-size:12.5px;color:var(--text2)}
.tv-note{font-size:11.5px;color:var(--text3)}
.tv-pax{display:inline-flex;align-items:center;gap:5px;flex-shrink:0;
  padding:4px 9px;border-radius:999px;background:var(--bg3);
  font-size:13px;color:var(--text2);font-variant-numeric:tabular-nums}
.tv-pax svg{width:14px;height:14px}
.tv-pax b{color:var(--text);font-weight:800}
.tv-rides{display:flex;flex-direction:column;gap:4px;flex-shrink:0}
.tv-ride{display:inline-flex;align-items:center;gap:6px;cursor:pointer;
  padding:5px 10px;border-radius:8px;font-family:inherit;font-size:12px;font-weight:700;
  background:color-mix(in srgb,var(--ok,#22c55e) 13%,transparent);color:var(--ok,#22c55e);
  border:1px solid color-mix(in srgb,var(--ok,#22c55e) 32%,transparent)}
.tv-ride svg{width:14px;height:14px}
.tv-ride:hover{background:color-mix(in srgb,var(--ok,#22c55e) 22%,transparent)}
/* THE RIGHT-HAND CLUSTER IS FOUR CONTROLS OF FOUR DIFFERENT HEIGHTS —
   a 26 px head-count pill, a 26 px flight chip, a 36 px button and a
   44 px pencil — and centring each one against the row is not the same
   as lining them up with each other. The pencil is brought down to the
   button's height so the four read as one strip. */
.tv-acts{display:flex;gap:6px;align-items:center;flex-shrink:0}
.tv-acts .btn.sm,.tv-acts .icon-btn{min-height:32px;height:32px}
.tv-acts .icon-btn{min-width:32px;width:32px}
.tv-acts .icon-btn svg{width:16px;height:16px}
.tv-pax,.tv-fl,.tv-ride{min-height:32px;box-sizing:border-box}
.tv-cov{margin-top:20px}
.tv-cov h3{margin:0 0 4px}
@media (max-width:760px){
.tv-row{flex-wrap:wrap;gap:9px}
.tv-main{flex-basis:100%;order:3}
.tv-rides,.tv-acts{flex-basis:100%;order:4;flex-direction:row;flex-wrap:wrap}
.tv-acts .btn{flex:1;justify-content:center}
}

/* ── WHERE THE AEROPLANE IS — see js/flighttrack.js ──────────
   The chip sits between the head count and the ride, and its colour is
   the whole message: amber it is flying, green it is down, grey nobody
   can hear it. Grey is deliberately NOT red — no signal is missing
   information, not a problem. */
.tv-fl{display:inline-flex;align-items:center;gap:6px;flex-shrink:0;cursor:pointer;
  padding:5px 10px;border-radius:999px;font-family:inherit;font-size:12px;font-weight:700;
  border:1px solid var(--border);background:var(--bg3);color:var(--text2);
  font-variant-numeric:tabular-nums;transition:background .14s,color .14s}
.tv-fl svg{width:14px;height:14px}
.tv-fl:hover{color:var(--text)}
.tv-fl:disabled{opacity:.5;cursor:default}
.tv-fl.air{background:var(--gold-bg);color:var(--gold2,#d97706);border-color:var(--gold-border)}
.tv-fl.down{background:color-mix(in srgb,var(--ok,#22c55e) 13%,transparent);
  color:var(--ok,#22c55e);border-color:color-mix(in srgb,var(--ok,#22c55e) 32%,transparent)}
.tv-fl.none{color:var(--text3)}
.tv-fl.idle{border-style:dashed}

.fl-facts{display:flex;flex-direction:column;gap:3px;margin-bottom:12px;font-size:13px;color:var(--text2)}
.fl-facts b{color:var(--text)}
.fl-facts .fl-age{font-size:11.5px;color:var(--text3)}
.fl-map{height:min(52vh,380px);border-radius:12px;overflow:hidden;
  border:1px solid var(--border);background:var(--bg3)}
.fl-map.is-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:8px;height:180px;color:var(--text3);font-size:13px}
.fl-map.is-empty svg{width:26px;height:26px}
.fl-marker{display:flex;align-items:center;justify-content:center;width:30px;height:30px;
  border-radius:50%;background:var(--gold,#f59e0b);color:#0f172a;
  box-shadow:0 2px 8px rgba(0,0,0,.35)}
.fl-marker svg{width:17px;height:17px;stroke-width:2}
.fl-dest{display:flex;align-items:center;justify-content:center;width:24px;height:24px;
  color:var(--ok,#22c55e)}
.fl-dest svg{width:22px;height:22px;stroke-width:2.2}

/* ── A SCAN REPORT, DOCKED ─────────────────────────────────────
   The climb and descent reports are ordinary modals until somebody
   presses a row: then the dialogue moves to the side of the screen and
   the backdrop comes off it, so the map underneath is readable and the
   list is still there to work through. See scanPeek() in
   js/climb-scan.js — the state is a class on #modal-bg, and closeModal()
   takes it off again.

   pointer-events is the whole trick: the backdrop stops catching clicks
   so the map can be panned and zoomed with the list open, and the panel
   itself takes them back. It also means modalBackdrop() cannot fire
   while docked, which is correct — a click on the map is a click on the
   map, not a request to throw the report away. */
.modal-bg.peek{background:transparent;backdrop-filter:none;pointer-events:none;
  justify-content:flex-end;align-items:stretch;padding:0;overflow:hidden}
.modal-bg.peek .modal{pointer-events:auto;width:min(460px,94vw);max-width:none;
  max-height:100%;height:100%;border-radius:0;border-top:0;border-right:0;border-bottom:0;
  box-shadow:-18px 0 44px rgba(0,0,0,.5)}
.modal-bg.peek .modal-hd{padding:13px 16px}
.modal-bg.peek .modal-bd{padding:14px 16px;font-size:12.5px}
.modal-bg.peek .modal-ft{padding:11px 16px;gap:7px}
.modal-bg.peek .modal-ft .btn{padding:6px 11px;font-size:12px}
/* On a phone there is no side to dock to: the report becomes the bottom
   half of the screen, the map the top half — the same split the map
   overlays already use. */
@media (max-width:720px){
  .modal-bg.peek{align-items:flex-end;justify-content:center}
  .modal-bg.peek .modal{width:100%;height:56%;border-radius:16px 16px 0 0;
    border:1px solid var(--border2);box-shadow:0 -14px 34px rgba(0,0,0,.5)}
}
/* A LOOK AT THE SPOT, FROM A POPUP ON THE PERMITS MAP. An anchor, not
   a button: it leaves the app. It still has to READ as a button inside
   a Mapbox popup, which underlines links and gives them a colour of
   their own — hence the explicit rules rather than .btn.ghost, which is
   borderless and disappears on the popup's pale ground. */
.pm-sv-btn{display:inline-flex;align-items:center;gap:6px;margin-top:9px;
  padding:5px 10px;border-radius:8px;border:1px solid var(--border2);background:var(--bg3);
  color:var(--text)!important;font-size:11.5px;font-weight:600;text-decoration:none!important;
  line-height:1.5;white-space:nowrap}
.pm-sv-btn:hover{background:var(--bg4);border-color:var(--gold-border)}
.pm-sv-btn svg{width:14px;height:14px;flex:none}

/* ── THE FEED ZONE FINDER ──────────────────────────────────────
   The candidates wear letters on the map and in the report, in the
   colour of their rank: the best green, then lime, then amber, the
   rest grey. See js/feed-scan.js. NEVER give the marker `position` —
   Mapbox positions it, see .pm-obst-pin. */
.feed-pin{display:flex;align-items:center;justify-content:center;width:24px;height:24px;
  border-radius:50%;background:var(--c);color:#0b1016;font-size:12px;font-weight:800;
  border:2px solid #fff;box-shadow:0 1px 6px rgba(0,0,0,.45);cursor:pointer}
.feed-letter{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;
  border-radius:50%;background:var(--c);color:#0b1016;font-size:11.5px;font-weight:800}
/* A candidate the strict straightness rule would have rejected — kept
   only because "allow softer bends" is switched on. */
.feed-soft-tag{display:inline-block;margin-left:6px;padding:1px 6px;border-radius:5px;
  font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;
  background:rgba(245,158,11,.16);color:#d97706}
body:not(.light) .feed-soft-tag{color:#fbbf24}

/* ── THE WHOLE-COURSE OBSTACLE SCAN ────────────────────────────
   See js/course-scan.js. Obstacle pins wear the same badge shape the
   feed-zone letters do, coloured per kind; the cobblestone marker is
   a bare emoji, like the finish scan's own furniture pins, since a
   brick has its own colour already. */
.cscan-pin{display:flex;align-items:center;justify-content:center;width:22px;height:22px;
  border-radius:50%;background:var(--c);color:#0b1016;font-size:12px;font-weight:800;
  border:2px solid #fff;box-shadow:0 1px 6px rgba(0,0,0,.45);cursor:default}
.cscan-pin-cobble{width:auto;height:auto;background:none;border:0;box-shadow:none;
  font-size:20px;filter:drop-shadow(0 1px 3px rgba(0,0,0,.5))}
/* The roadbook's own sign, dropped on the map as it is drawn: the white
   disc and the coloured ring belong to the drawing, so the marker adds
   nothing but a shadow to lift it off the tiles. */
.cscan-pin-img{display:block;width:30px;height:30px;cursor:default;
  filter:drop-shadow(0 1px 3px rgba(0,0,0,.45))}
.cscan-row-ico{width:22px;height:22px;vertical-align:-6px;margin-right:6px}
/* Which layer the obstacles are filed under, above the list they are
   picked from — including typing a new one, which appears in place
   rather than in a second dialogue. */
/* ── THE FEED-ZONE REPORT'S TABLE ───────────────────────────────
   Seven columns. In a full dialogue they all fit; docked beside the map
   at 460 px they used to squeeze until a stretch read as a tower of
   single words — "1000 m ·" over "dead" over "straight". So the two
   columns a first read does not need go away down there, the km range
   never breaks across lines, and what is left still scrolls sideways
   rather than compressing any further. */
.feed-tbl-wrap{overflow-x:auto}
.feed-tbl{border-collapse:collapse;width:100%;min-width:560px}
.feed-tbl .fz-km{white-space:nowrap}
.modal-bg.peek .feed-tbl{min-width:0}
.modal-bg.peek .feed-tbl .fz-c-offset,
.modal-bg.peek .feed-tbl .fz-c-wide{display:none}

.cscan-layer-bar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0 0 8px}
.cscan-layer-bar label{font-size:11px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;color:var(--text3)}
.cscan-layer-bar select{font:inherit;font-size:12.5px;padding:6px 8px;border-radius:8px;
  background:var(--bg2);color:var(--text);border:1px solid var(--border);max-width:230px}
.cscan-layer-bar .input{max-width:190px;padding:6px 8px;font-size:12.5px}
.cscan-layer-bar #cscan-add-all{margin-left:auto}
/* Which row the map is showing. Held rather than flashed: while the map
   flies and settles, the answer to "which one did I just press" has to
   still be on screen. */
.scan-row-on td{background:rgba(245,158,11,.14)}
.scan-row-on td:first-child{box-shadow:inset 3px 0 0 var(--gold)}

/* The panel a failed screen leaves behind — see renderView() in
   js/app.js. Deliberately plain and deliberately quotable. */
.view-error{margin:28px auto;max-width:760px;display:flex;flex-direction:column;gap:10px;
  padding:20px 22px;border-radius:12px;background:var(--bg2);
  border:1px solid var(--red-border)}
.view-error strong{font-size:15px;color:var(--red)}
.view-error code{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12.5px;
  color:var(--text);background:var(--bg3);border-radius:8px;padding:9px 11px;
  white-space:pre-wrap;word-break:break-word}
.view-error small{font-size:11px;color:var(--text3);word-break:break-word}

/* ── WHICH LANGUAGE DOES THE PAPER SPEAK? ──────────────────────
   The question in front of every PDF — js/utils.js, pdfLangAsk(). It
   carries its own backdrop rather than borrowing #modal-bg, because most
   of these exports are fired from inside a dialogue that is already open;
   so it needs to sit above one, not replace it. */
.pdflang-bg{z-index:calc(var(--z-modal) + 5)}
.pdflang{max-width:430px}
.pdflang-hint{font-size:12.5px;color:var(--text2);line-height:1.55;margin:0 0 14px}
.pdflang-opts{display:flex;flex-direction:column;gap:9px}
/* The one thing besides the language a sheet is asked about: whether it
   carries the code to its live version. Under the three choices, because
   it is a detail of whichever one is pressed — the choice itself is still
   one click. */
/* The currency row under the languages — the same three pills the
   budget dialogue wears. */
.pdflang-cur{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:14px 2px 0}
.pdflang-cur>span{font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:var(--text2)}
.pdflang-curs{display:inline-flex;border:1px solid var(--border);border-radius:9px;overflow:hidden;background:var(--bg3)}
.pdflang-c{border:0;background:transparent;color:var(--text2);font:inherit;font-size:12px;font-weight:800;
  padding:6px 13px;cursor:pointer}
.pdflang-c+.pdflang-c{border-left:1px solid var(--border)}
.pdflang-c.on{background:var(--primary,#f59e0b);color:#111}
/* The request link's download asks WHAT before it asks how sharp —
   this hotel's page or the whole guide — so its switch stands above
   the two choices, not under them, and the hint between them says
   what the switch means. */
.pdflang-cur.hr-what{margin:0 2px 12px}
[dir=rtl] .pdflang-c+.pdflang-c{border-left:0;border-right:1px solid var(--border)}
.pdflang-qr{display:flex;align-items:center;gap:9px;margin:14px 2px 0;
  font-size:12.5px;color:var(--text2);cursor:pointer}
.pdflang-qr input{width:16px;height:16px;accent-color:var(--gold2);cursor:pointer;flex-shrink:0}

/* Each option is the whole answer: one press writes the file. So it is
   sized like a decision rather than a row in a list, and says in its own
   second line what comes out of it. */
.pdflang-opt{display:flex;align-items:center;gap:13px;width:100%;text-align:left;
  padding:13px 14px;border-radius:11px;border:1px solid var(--border2);
  background:var(--bg3);color:var(--text);font-family:inherit;cursor:pointer;
  transition:background .16s,border-color .16s,transform .16s}
.pdflang-opt:hover{background:var(--bg4);border-color:var(--gold-border)}
.pdflang-opt:active{transform:scale(.99)}
.pdflang-opt:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
/* The one used last time. Not a selection — nothing is selected here,
   every button fires — but where the keyboard lands, so Enter repeats it. */
.pdflang-opt.on{border-color:var(--gold-border);background:var(--bg4)}

/* One fixed width for all three, so the names start on the same line.
   Sized on min-width it was the EN+FR row that set its own, and the
   third option sat a centimetre right of the other two. */
.pdflang-code{flex:0 0 62px;width:62px;text-align:center;padding:5px 4px;border-radius:7px;
  font-family:'Space Grotesk',Inter,sans-serif;font-size:12.5px;font-weight:800;
  letter-spacing:.04em;background:var(--bg2);border:1px solid var(--border);color:var(--text2)}
.pdflang-opt.on .pdflang-code{color:var(--gold2);border-color:var(--gold-border)}
.pdflang-txt{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.pdflang-txt b{font-size:13.5px;font-weight:700;line-height:1.2}
/* Wraps. A two-language line is long in French and this is a 430 px box —
   the version of this that held it on one line pushed the arrow off. */
.pdflang-txt i{font-style:normal;font-size:11.5px;color:var(--text2);line-height:1.4;
  white-space:normal;overflow-wrap:anywhere}
.pdflang-arrow{flex:0 0 auto;color:var(--text3,var(--text2));opacity:.7}
.pdflang-arrow svg{width:17px;height:17px;display:block}
.pdflang-opt:hover .pdflang-arrow{color:var(--gold2);opacity:1}

@media (max-width:480px){
  .pdflang-code{flex-basis:54px;width:54px;font-size:11.5px}
  .pdflang-txt b{font-size:13px}
}

/* ── A PICTURE, LOOKED AT ──────────────────────────────────────
   js/utils.js, openLightbox(). Nearly black behind the picture in both
   themes, on purpose: a photograph is judged against dark, and the page
   it came from must not compete with it. Its own backdrop, one step
   above #modal-bg, because the hotel editor and the guide preview both
   show pictures from inside an open dialogue. */
.lb-bg{position:fixed;inset:0;z-index:calc(var(--z-modal) + 6);display:flex;align-items:center;
  justify-content:center;padding:18px;background:rgba(2,6,15,.92);backdrop-filter:blur(8px);
  animation:fadeUp .18s ease-out;cursor:zoom-out;touch-action:pinch-zoom}
.lb-fig{margin:0;display:flex;flex-direction:column;align-items:center;gap:12px;
  max-width:min(1280px,100%);max-height:100%;cursor:default}
.lb-stage{display:flex;align-items:center;justify-content:center;min-width:200px;min-height:160px;
  max-width:100%;cursor:default}
.lb-stage img{display:block;max-width:min(1280px,94vw);max-height:80vh;width:auto;height:auto;
  border-radius:14px;box-shadow:0 24px 70px rgba(0,0,0,.65);animation:lbIn .22s ease-out;
  -webkit-user-drag:none;user-select:none}
@keyframes lbIn{from{opacity:0;transform:scale(.97)}to{opacity:1;transform:none}}
.lb-stage .spin{width:30px;height:30px;border:3px solid rgba(255,255,255,.28);border-top-color:#fff;
  border-radius:50%;animation:spin .7s linear infinite}
.lb-err{margin:0;max-width:360px;padding:16px 18px;border-radius:12px;text-align:center;
  font-size:13.5px;line-height:1.5;color:rgba(255,255,255,.85);background:rgba(255,255,255,.08);
  border:1px solid rgba(255,255,255,.16)}
/* The caption: what it is, which one of how many, and the way out to the
   full file — one quiet line under the picture, never over it. */
.lb-cap{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:6px 14px;
  max-width:94vw;padding:0 4px;color:rgba(255,255,255,.9);font-size:13.5px;cursor:default}
.lb-title{font-family:'Space Grotesk','Inter',sans-serif;font-weight:700;letter-spacing:-.1px}
.lb-n{font-variant-numeric:tabular-nums;color:rgba(255,255,255,.62)}
.lb-orig{display:inline-flex;align-items:center;gap:5px;color:rgba(255,255,255,.62);
  text-decoration:none;font-size:12.5px;border-radius:7px;padding:3px 7px;
  transition:color .16s,background .16s}
.lb-orig:hover{color:#fff;background:rgba(255,255,255,.1)}
.lb-orig svg{width:14px;height:14px}
/* The buttons: white on the dark, big enough for a thumb, and the arrows
   pinned to the edges so the eye keeps its place between pictures. */
.lb-x,.lb-nav{position:absolute;display:inline-flex;align-items:center;justify-content:center;
  width:46px;height:46px;border-radius:50%;border:1px solid rgba(255,255,255,.18);
  background:rgba(255,255,255,.1);color:#fff;cursor:pointer;
  transition:background .16s,border-color .16s,transform .16s}
.lb-x:hover,.lb-nav:hover{background:rgba(255,255,255,.22);border-color:rgba(255,255,255,.38)}
.lb-x:active,.lb-nav:active{transform:scale(.94)}
.lb-x:focus-visible,.lb-nav:focus-visible,.lb-orig:focus-visible{outline:2px solid var(--gold2);outline-offset:2px}
.lb-x svg,.lb-nav svg{width:22px;height:22px}
.lb-x{top:16px;right:16px}
.lb-nav{top:50%;transform:translateY(-50%)}
.lb-nav:active{transform:translateY(-50%) scale(.94)}
.lb-prev{left:16px}
.lb-next{right:16px}
@media (max-width:720px){
  .lb-bg{padding:12px}
  .lb-stage img{max-width:96vw;max-height:70vh;border-radius:10px}
  .lb-x,.lb-nav{width:40px;height:40px}
  .lb-x{top:10px;right:10px}
  .lb-prev{left:8px}
  .lb-next{right:8px}
  .lb-cap{font-size:12.5px;gap:4px 10px}
}
@media print{ .lb-bg{display:none} }

/* ── THE SECOND LANGUAGE STARTS ON ITS OWN PAGE ────────────────
   Set both ways on purpose: html2pdf reads the computed style in its css
   pass and the class in its legacy one, and which of the two it acts on
   depends on options set far from here. Cheap to state twice, expensive
   to find out it was stated in the wrong one. The @media print copy is
   for printSheetVector(), which goes through the browser's own printer
   and never sees html2pdf at all. */
.pdf-langbreak,.html2pdf__page-break{page-break-before:always;break-before:page}
@media print{
  #print-root .pdf-langbreak{page-break-before:always;break-before:page}
}

/* ── THE MASTHEAD ON A PRINTED SHEET, IN INK ───────────────────
   reportHeaderHtml() is shared between the screen and the paper, and its
   two lines read var(--text) and var(--text2). On the screen that is
   right. On these sheets — which are white whatever theme the app is
   wearing — it meant the edition's own name came out at 232,238,252 on
   white: a ratio of 1.16, which is not faint, it is absent. The subtitle
   under it was 2.2. Four documents were handed over with no title on
   them and nobody could see why.

   The Golazo mark had the same fault from the other end: the dark theme
   shows the WHITE version, so the corner of the sheet held a white logo
   on white paper. The sheet picks the green one whatever the app is in. */
.mh-doc .rep-t strong,.cq-doc .rep-t strong,.htb-doc .rep-t strong,
.ce-doc .rep-t strong,.ht-doc .rep-t strong{color:#0f172a}
.mh-doc .rep-t span,.cq-doc .rep-t span,.htb-doc .rep-t span,
.ce-doc .rep-t span,.ht-doc .rep-t span{color:#475569}
.mh-doc .golazo-dark,.cq-doc .golazo-dark,.htb-doc .golazo-dark,
.ce-doc .golazo-dark,.ht-doc .golazo-dark{display:none}
.mh-doc .golazo-light,.cq-doc .golazo-light,.htb-doc .golazo-light,
.ce-doc .golazo-light,.ht-doc .golazo-light{display:inline-block}

/* The micro-labels above each value. Slate-400 is a screen grey: printed
   at eight and a half point it is 2.6 to 1 on white, which survives a
   monitor and not a photocopier. One step darker reads on paper and is
   still plainly secondary to the value under it. */
.sp-k,.vcard-row span,.vcard-qr p{color:#64748b}
/* ═══════════ TEAMS & RESULTS — THE HUB ═══════════
   Five sidebar lines folded into one door, and this is behind it. Every
   tile carries a figure AND a little picture drawn from the same
   numbers — which races have a list and how big, who the big teams are,
   which podiums are in. A tile with a number and nothing else has to be
   clicked to be understood, and the point of the hub is to be
   understood before it is clicked. See js/sport-hub.js. */
.hub-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(352px,1fr));gap:16px}
.hub-card{display:flex;flex-direction:column;gap:12px;min-height:286px;
  width:100%;text-align:left;font:inherit;cursor:pointer;position:relative;overflow:hidden;
  background:var(--bg2);border:1px solid var(--border);border-radius:18px;padding:20px 20px 18px;
  transition:border-color .16s,transform .16s,box-shadow .16s}
.hub-card:hover{border-color:color-mix(in srgb,var(--tone,var(--accent2)) 45%,transparent);
  transform:translateY(-2px);box-shadow:0 12px 28px rgba(0,0,0,.11)}
.hub-card:focus-visible{outline:2px solid var(--accent2);outline-offset:2px}
.hub-top{display:flex;align-items:center;gap:12px}
/* Each card in its own colour, set as --tone on the card itself, so a
   glance at the screen separates entries from results from the
   palmarès before a word is read. */
.hub-ico{display:flex;align-items:center;justify-content:center;width:42px;height:42px;
  flex:0 0 auto;border-radius:13px;color:var(--tone,var(--accent2));
  background:color-mix(in srgb,var(--tone,var(--accent2)) 13%,transparent)}
.hub-ico svg{width:21px;height:21px}
.hub-name{flex:1 1 auto;min-width:0;font-size:17px;font-weight:800;color:var(--text);
  letter-spacing:-.01em;line-height:1.2}
.hub-go{flex:0 0 auto;color:var(--text3);display:flex;align-self:flex-start;margin-top:2px}
.hub-go svg{width:15px;height:15px}
.hub-card:hover .hub-go{color:var(--tone,var(--accent2))}
.hub-desc{font-size:12.5px;font-weight:600;color:var(--text3);line-height:1.45}
.hub-chart{flex:1 1 auto;display:flex;flex-direction:column;justify-content:center;
  gap:6px;min-height:0}
.hub-chart:empty{min-height:8px}

/* The big teams, as bars. Names are truncated rather than wrapped: five
   rows of one line each is a shape, five rows of two is a paragraph. */
.hub-bars{display:flex;flex-direction:column;gap:5px}
.hub-bar-row{display:grid;grid-template-columns:88px 1fr 26px;align-items:center;gap:8px}
.hub-bar-lbl{font-size:10.5px;font-weight:700;color:var(--text2);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.hub-bar-track{height:8px;border-radius:99px;background:var(--bg3);overflow:hidden}
.hub-bar-track > i{display:block;height:100%;border-radius:99px;
  background:var(--tone,var(--accent2))}
.hub-bar-n{font-size:10.5px;font-weight:800;color:var(--text3);text-align:right;
  font-variant-numeric:tabular-nums}

/* One block per race — filled when it is done, hollow when it is not.
   The point is the shape of the row: four full and one empty is a gap
   somebody can point at across a desk. */
.hub-strip{display:flex;gap:5px;flex-wrap:wrap}
.hub-cell{flex:0 0 auto;width:38px;display:flex;flex-direction:column;align-items:center;gap:3px}
.hub-cell > i{display:block;width:100%;height:26px;border-radius:7px;background:var(--bg3);
  border:1px solid var(--border)}
.hub-cell.on > i{background:var(--tone,var(--accent2));border-color:transparent}
.hub-cell > b{font-size:9.5px;font-weight:800;color:var(--text3);font-variant-numeric:tabular-nums}
.hub-strip-note{font-size:9.5px;font-weight:700;color:var(--text3);text-transform:uppercase;
  letter-spacing:.05em}

/* THE PODIUM, IN THE THREE COLOURS IT IS EVERYWHERE IN THE SPORT. Gold,
   silver and bronze say "results" without a word, and they are the only
   place on this screen those colours appear. */
.hub-medals{display:flex;gap:6px;align-items:center}
.hub-medal{width:26px;height:26px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;background:var(--m);box-shadow:inset 0 -2px 4px rgba(0,0,0,.22)}
.hub-medal b{font-size:11px;font-weight:800;color:rgba(0,0,0,.6)}

/* The years a race has been run, newest first — this one picked out. */
.hub-years{display:flex;gap:5px;flex-wrap:wrap}
.hub-years > span{font-size:11px;font-weight:800;color:var(--text2);background:var(--bg3);
  border-radius:7px;padding:4px 7px;font-variant-numeric:tabular-nums}
.hub-years > span.on{background:var(--tone,var(--accent2));color:#fff}

/* The way back out of a hub, in the heading of each screen it opens. */
.hub-back{align-self:flex-start;margin-bottom:6px}

/* The figure sits on the floor of the card with its gauge under it, so
   five cards read as one row of dials however long the words above
   them are. */
.hub-stat{display:flex;flex-direction:column;gap:8px;margin-top:auto}
.hub-fig{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap}
.hub-fig b{font-size:32px;font-weight:800;color:var(--text);line-height:1;
  font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.hub-fig b i{font-style:normal;font-size:17px;font-weight:700;color:var(--text3)}
.hub-fig b.hub-dash{color:var(--text3)}
.hub-fig > span{font-size:10px;font-weight:800;color:var(--text3);text-transform:uppercase;
  letter-spacing:.06em;line-height:1.3}
.hub-fig > em{font-style:normal;font-size:11.5px;font-weight:700;color:var(--text2);
  margin-left:auto}
.hub-gauge{display:block;height:6px;border-radius:99px;background:var(--bg3);overflow:hidden}
.hub-gauge > i{display:block;height:100%;border-radius:99px;background:var(--tone,var(--accent2));
  transition:width .3s ease}
/* Everything in is everything done, and that is worth seeing across a
   room. */
.hub-card.done .hub-fig b{color:var(--tone,var(--accent2))}
@media (max-width:720px){
  .hub-grid{grid-template-columns:1fr;gap:10px}
  .hub-card{min-height:0;padding:15px;gap:9px}
  .hub-desc,.hub-chart{display:none}
  .hub-fig b{font-size:25px}
}

/* ═══════════ THE SIGN LIBRARY, AS SIGNS ═══════════
   A hundred and thirty file names in a dropdown is a library nobody can
   shop in. The whole folder as pictures, with a search over it, at
   roughly the size they print. See openSignPicker() in js/map.js. */
.sp-wrap{display:flex;flex-direction:column;gap:10px}
.sp-find{width:100%}
.sp-none{font:inherit;font-size:12.5px;font-weight:700;text-align:left;cursor:pointer;
  background:var(--bg3);border:1px solid var(--border);border-radius:9px;
  padding:9px 12px;color:var(--text2)}
.sp-none:hover{border-color:var(--gold-border);color:var(--text)}
.sp-none.on{border-color:var(--accent2);color:var(--text)}
/* One scroller, two shelves inside it: the signs this race already uses,
   then everything else. */
.sp-scroll{max-height:52vh;overflow-y:auto;padding:2px}
.sp-sec{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;
  color:var(--text3);margin:2px 0 6px}
.sp-sec + .sp-grid{margin-bottom:14px}
.sp-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(88px,1fr));gap:8px}
.sp-cell{display:flex;flex-direction:column;align-items:center;gap:5px;cursor:pointer;
  background:#fff;border:1px solid var(--border);border-radius:10px;padding:9px 5px 7px;
  font:inherit}
.sp-cell:hover{border-color:var(--gold-border);transform:translateY(-1px)}
.sp-cell.on{border-color:var(--accent2);box-shadow:0 0 0 2px color-mix(in srgb,var(--accent2) 28%,transparent)}
.sp-cell img{width:40px;height:40px;object-fit:contain;display:block}
.sp-cell span{font-size:9px;font-weight:700;color:#64748b;line-height:1.2;text-align:center;
  overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;
  -webkit-box-orient:vertical;word-break:break-word}

/* The waypoint editor's two fields that are not plain inputs: which
   courses it stands on, and which of the road book's own signs it
   wears. (This block went missing once — see the audit sweep.) */
.poi-tracks{display:flex;flex-direction:column;gap:0;max-height:186px;overflow-y:auto}
.poi-track{display:flex;align-items:center;gap:9px;padding:4px 4px;border-radius:6px;
  font-size:13px;font-weight:600;color:var(--text2);cursor:pointer;line-height:1.25}
/* The one that stands above the list, and the list it folds away. */
.poi-all{margin-bottom:4px;padding-bottom:7px;border-bottom:1px solid var(--border);
  border-radius:0}
.poi-track:hover{background:var(--bg3);color:var(--text)}
.poi-track input{width:15px;height:15px;flex-shrink:0;accent-color:var(--accent2)}
.poi-track i{width:12px;height:12px;flex-shrink:0;border-radius:4px;display:block}
.poi-sign{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.poi-sign-face{flex:0 0 auto;width:38px;height:38px;display:flex;align-items:center;
  justify-content:center;background:#fff;border:1px solid var(--border);border-radius:9px}
.poi-sign-face img{max-width:30px;max-height:30px;display:block}


/* ═══════════ THE BROOM WAGON'S BOARD ═══════════
   Read at the wheel, so there is exactly one thing to read: the
   kilometre, at the size of the screen. Everything else is a caption
   under it. The colour is the whole message at a glance — green means
   carry on, amber means you are ahead of your own schedule, red means
   there are riders behind you on a road that is about to reopen. */
.swp{max-width:560px;margin:0 auto;padding:10px 12px 28px;display:flex;
  flex-direction:column;gap:12px}
.swp-hd{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.swp-t{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.09em;
  color:var(--text3)}
.swp-race{font-size:13px;font-weight:700;color:var(--text2);min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.swp-hd select{margin-left:auto;max-width:60%}
.swp-board{border-radius:14px;padding:22px 18px 18px;text-align:center;
  border:1px solid var(--border);background:var(--bg2)}
.swp-km{display:flex;align-items:baseline;justify-content:center;gap:8px;
  font-variant-numeric:tabular-nums}
.swp-km b{font-size:68px;line-height:1;font-weight:800;letter-spacing:-.03em}
.swp-km span{font-size:17px;font-weight:700;color:var(--text3)}
.swp-line{margin:12px 0 0;font-size:16px;font-weight:700}
.swp-sub{margin:6px 0 0;font-size:11.5px;font-weight:600;color:var(--text3)}
/* On schedule, ahead, behind, and the two states that are neither. */
.swp-board.is-ok{border-color:#16a34a;background:rgba(22,163,74,.10)}
.swp-board.is-ok .swp-line{color:#16a34a}
.swp-board.is-ahead{border-color:#d97706;background:rgba(217,119,6,.10)}
.swp-board.is-ahead .swp-line{color:#d97706}
.swp-board.is-behind{border-color:#dc2626;background:rgba(220,38,38,.12)}
.swp-board.is-behind .swp-line{color:#dc2626}
.swp-board.is-done .swp-line,.swp-board.is-wait .swp-line{color:var(--text2)}
.swp-rows{display:flex;flex-direction:column;gap:6px}
.swp-row{display:flex;align-items:center;gap:10px;padding:10px 13px;
  border:1px solid var(--border);border-radius:9px;background:var(--bg2);
  font-variant-numeric:tabular-nums}
.swp-row.next{border-color:var(--gold-border,#b8894a);background:var(--bg3)}
.swp-row-km{flex:1 1 auto;font-size:13px;font-weight:700;color:var(--text2)}
.swp-row b{font-size:17px;font-weight:800}
.swp-tag{font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;
  color:var(--text3);border:1px solid var(--border);border-radius:99px;padding:2px 7px}
.swp-note{margin:2px 0 0;font-size:11px;color:var(--text3);text-align:center}
/* ── THE MAP, THE TWO DOTS AND THE GLOW ──
   The driver is a filled disc with a ring, the hare is hollow and
   pulsing: one of them is where you are and one is where you should be,
   and a driver has to tell them apart at a glance in daylight. */
.swp-map{height:46vh;min-height:230px;border-radius:12px;overflow:hidden;
  border:1px solid var(--border)}
.swp-pin{width:20px;height:20px;border-radius:50%;box-sizing:border-box}
.swp-pin-me{background:#2563eb;border:3px solid #fff;box-shadow:0 0 0 2px rgba(37,99,235,.5)}
/* THE PULSE IS ON A CHILD, NOT ON THE PIN. Mapbox places a marker by
   writing an inline transform on the element; an animation that also
   writes transform on that same element wins the cascade, and the hare
   sat pulsing in the top-left corner of every map — at the origin,
   where an element with no translate goes. */
.swp-pin-hare{background:transparent}
.swp-pin-hare::after{content:'';position:absolute;inset:0;border-radius:50%;
  border:4px solid #f59e0b;box-shadow:0 0 0 3px rgba(245,158,11,.35);
  animation:swp-pulse 1.6s ease-in-out infinite}
@keyframes swp-pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.25)}}
/* The bubbles' key, on every map that draws them. */
.swp-dot.z-closed{background:#dc2626}
.swp-dot.z-sweeping{background:#f59e0b}
.swp-dot.z-open{background:#16a34a}
.swp-zone-legend{margin-top:8px}
.swp-zone-legend:empty{display:none}
.swp-desk-zone{display:flex;align-items:center;gap:6px;font-size:11.5px;font-weight:700;color:var(--text3)}
.swp-desk-zone select{font-size:12px;padding:2px 6px}
.swp-legend{display:flex;gap:16px;justify-content:center;font-size:11.5px;
  font-weight:700;color:var(--text3)}
.swp-legend span{display:flex;align-items:center;gap:6px}
.swp-dot{width:11px;height:11px;border-radius:50%;display:block}
.swp-dot.me{background:#2563eb}
.swp-dot.hare{border:3px solid #f59e0b;box-sizing:border-box}
/* THE SCREEN IS THE ALARM. A driver watching the road reads a glow at
   the edge of their vision; they do not read a chip. Behind is red
   because it is the direction that leaves riders on a live road; ahead
   is amber because it is only early. */
#v-sweep.swp-warn{background:radial-gradient(120% 60% at 50% 0%,
  rgba(220,38,38,.28),transparent 70%)}
#v-sweep.swp-early{background:radial-gradient(120% 60% at 50% 0%,
  rgba(217,119,6,.22),transparent 70%)}
.swp-beacon{width:100%;justify-content:center}
.swp-beacon.on{background:linear-gradient(135deg,var(--accent-fill),var(--accent-fill2));
  border-color:transparent;color:var(--on-accent)}


/* ═══════════ THE BROOM WAGON, FROM THE DESK ═══════════
   A row per race and a map under it. The row is coloured by the only
   thing the desk acts on: behind is red, because it is the direction
   that leaves runners on a road that has already reopened. */
.swp-desk{padding:14px 16px 16px}
.swp-desk-hd{display:flex;align-items:center;gap:8px;font-size:11px;font-weight:800;
  text-transform:uppercase;letter-spacing:.08em;color:var(--text2);margin-bottom:10px}
.swp-desk-hd svg{width:16px;height:16px}
.swp-desk-sub{margin-left:auto;text-transform:none;letter-spacing:0;font-weight:700;
  color:var(--text3)}
.swp-desk-map{height:260px;border-radius:10px;overflow:hidden;border:1px solid var(--border)}
.swp-desk-rows{display:flex;flex-direction:column;gap:6px;margin-bottom:10px}
.swp-desk-row{display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  padding:9px 12px;border:1px solid var(--border);border-radius:9px;background:var(--bg2);
  font-size:12.5px;font-variant-numeric:tabular-nums}
.swp-desk-row.late{border-color:#dc2626;background:rgba(220,38,38,.10)}
.swp-desk-row.early{border-color:#d97706;background:rgba(217,119,6,.08)}
.swp-desk-name{flex:1 1 160px;min-width:0;font-weight:800;color:var(--text)}
.swp-desk-km,.swp-desk-fin{color:var(--text3);font-weight:600}
.swp-desk-km b,.swp-desk-fin b{color:var(--text2)}
.swp-desk-gap{font-weight:800}
.swp-desk-row.late .swp-desk-gap{color:#dc2626}
.swp-desk-row.early .swp-desk-gap{color:#d97706}


/* A discipline's badge when it is a picture rather than an app icon. */
.disc-ico-img{width:18px;height:18px;object-fit:contain;display:block}

.swp-beacon-st{margin:6px 0 0;font-size:11.5px;font-weight:700;text-align:center;color:var(--text3)}
.swp-beacon-st.ok{color:#16a34a}
.swp-beacon-st.bad{color:#dc2626}


/* ═══════════ THE WAVES ON A RACE CARD ═══════════
   A chip per wave, read left to right in the order they leave. The real
   gun is marked, because a card read at eleven in the morning is read
   for what happened, not for what was planned. */
.rc-waves{display:flex;align-items:center;flex-wrap:wrap;gap:6px 8px;
  padding:9px 0 2px;border-top:1px solid var(--border);margin-top:8px}
.rc-waves-t{display:flex;align-items:center;gap:5px;font-size:10px;font-weight:800;
  text-transform:uppercase;letter-spacing:.08em;color:var(--text3);margin-right:4px}
.rc-waves-t svg{width:13px;height:13px}
.rc-wave{display:inline-flex;align-items:center;gap:7px;padding:4px 9px;border-radius:999px;
  border:1px solid var(--border);background:var(--bg2);font-size:11.5px;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.rc-wave b{font-weight:800;color:var(--text)}
.rc-wave-t{font-weight:700;color:var(--text2)}
.rc-wave-p{color:var(--text3)}
.rc-wave-n{color:var(--text3)}
.rc-wave-n::before{content:'· ';}
.rc-wave.actual{border-color:#16a34a;background:rgba(22,163,74,.08)}
.rc-wave.actual .rc-wave-t{color:#16a34a}
.rc-waves-last{margin-left:auto;font-size:11.5px;font-weight:700;color:var(--text2);
  white-space:nowrap}


/* ═══════════ THE BROOM WAGON, FULL-BLEED ═══════════
   Same treatment as the report map: on this screen the header, the
   sidebar and the read-only strip are room taken from the map, and a
   phone in a bracket has none to spare. */
body.sweep-view #ro-banner{display:none!important}
body.sweep-view #content{padding:0;overflow:auto}
body.sweep-view #sidebar{display:none}
body.sweep-view #menuBtn,body.sweep-view #sidebar-scrim{display:none!important}
body.sweep-view .swp{max-width:none;padding:8px 10px 24px}
body.sweep-view .swp-map{height:52vh;min-height:280px}
/* The layer drawer under the map, folded until wanted. */
.swp-layers{border:1px solid var(--border);border-radius:10px;background:var(--bg2)}
.swp-layers summary{display:flex;align-items:center;gap:8px;padding:10px 12px;cursor:pointer;
  font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;
  color:var(--text2);list-style:none}
.swp-layers summary::-webkit-details-marker{display:none}
.swp-layers summary svg{width:14px;height:14px}
.swp-layers .mo-group{padding:4px 12px 12px}
.swp-layers .mo-label{display:none}
/* A waypoint on the driver's map: the app's own pin, with the badge
   inside it, whether that badge is a glyph or a drawing. */
.swp-poi .poi-pin-dot{display:flex;align-items:center;justify-content:center}
.swp-poi-img{width:16px;height:16px;object-fit:contain;display:block}


/* ═══════════ RACE RADIO ═══════════
   Short, dated, never edited. On the driver's phone the newest desk
   message is the biggest thing after the kilometre, and its arrival
   flashes the box, because a line quietly appearing under a map is a
   line nobody in a moving car reads. */
.swp-msgbox{border:1px solid var(--border);border-radius:12px;background:var(--bg2);
  padding:10px 12px 12px;display:flex;flex-direction:column;gap:8px;transition:box-shadow .3s}
.swp-msgbox.flash{box-shadow:0 0 0 4px rgba(37,99,235,.45)}
.swp-msgbox-hd{display:flex;align-items:center;gap:6px;font-size:10px;font-weight:800;
  text-transform:uppercase;letter-spacing:.08em;color:var(--text3)}
.swp-msgbox-hd svg{width:13px;height:13px}
.swp-msg{display:flex;gap:10px;align-items:baseline;padding:6px 0;border-top:1px solid var(--border)}
.swp-msg:first-child{border-top:0}
.swp-msg.latest .swp-msg-x{font-size:17px;font-weight:800;color:var(--text)}
.swp-msg-t{flex:0 0 auto;font-size:11px;font-weight:700;color:var(--text3);
  font-variant-numeric:tabular-nums}
.swp-msg-x{font-size:13px;font-weight:600;color:var(--text2)}
.swp-msg-none{margin:0;font-size:12px;color:var(--text3)}
.swp-canned{display:flex;flex-wrap:wrap;gap:6px}
.swp-canned .btn{flex:1 1 46%;justify-content:center;min-height:40px}
.swp-free{display:flex;gap:6px}
.swp-free .input{flex:1 1 auto;min-width:0}
.swp-desk-msgbox{display:flex;flex-direction:column;gap:6px;margin-top:10px}
.swp-dmsg{display:flex;gap:8px;align-items:baseline;font-size:12px;padding:5px 9px;
  border-radius:8px;background:var(--bg3)}
.swp-dmsg.sweep{border-left:3px solid #2563eb}
.swp-dmsg.desk{border-left:3px solid #16a34a;opacity:.85}
.swp-dmsg b{flex:0 0 auto;color:var(--text)}


/* Partners and barriers — js/branding.js. */
.br-p{padding:8px 0;border-bottom:1px dashed var(--border)}
.br-p-hd{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:13.5px}
.br-p-hd small{color:var(--text3)}
.br-sw{width:12px;height:12px;border-radius:3px;display:block;flex-shrink:0}
.br-p-n{margin-left:auto;font-size:12px;color:var(--text3);font-variant-numeric:tabular-nums}
.br-bar{height:8px;border-radius:999px;background:rgba(148,163,184,.25);overflow:hidden;margin-top:5px}
.br-bar i{display:block;height:100%}
.br-owe{color:#b45309;font-weight:700}
.br-z{padding:10px 0;border-bottom:1px dashed var(--border)}
.br-z-hd{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:13.5px}
.br-z-hd small{color:var(--text3)}
.br-z-n{margin-left:auto;font-size:12px;color:var(--text3);font-variant-numeric:tabular-nums}
.br-strip{display:flex;height:42px;border-radius:6px;overflow:hidden;border:1px solid var(--border);margin-top:7px}
.br-seg{display:flex;flex-direction:column;justify-content:center;padding:0 5px;color:#fff;overflow:hidden;
  border-right:1px solid rgba(255,255,255,.5)}
.br-seg b{font-size:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.br-seg small{font-size:9px;opacity:.85}
.br-seg.free{background:repeating-linear-gradient(45deg,rgba(148,163,184,.15),rgba(148,163,184,.15) 6px,transparent 6px,transparent 12px);
  color:var(--text3)}
.br-slots{display:flex;flex-wrap:wrap;gap:5px;margin-top:6px}
.br-chip{display:flex;align-items:center;gap:5px;font-size:11.5px;padding:2px 6px;border-radius:999px;border:1px solid var(--border)}
.br-chip i{width:9px;height:9px;border-radius:2px;display:block}
.br-chip button{border:none;background:none;cursor:pointer;color:var(--text3);font-size:12px;padding:0 2px}
.br-form{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.br-form .input{flex:1 1 160px;min-width:120px}
.br-form #br-m{flex:0 0 90px}
.br-eq{font-size:12px;color:var(--text3);font-weight:700}

/* The delegation table on the accreditation form: a passport-photo
   thumb per line, pressed to choose one. See accreqPartyHtml(). */
.areq-party-pick{background:none;border:0;padding:0;cursor:pointer;border-radius:50%;display:inline-flex}
.areq-party-pick:focus-visible{outline:2px solid var(--primary,#f59e0b);outline-offset:2px}
.dir-avatar.areq-party-face{width:30px;height:30px;margin:0;font-size:11px;flex-shrink:0}
.areq-party{color:var(--gold2,#d97706);font-weight:600}

.mo-sub{display:flex;gap:4px;margin:2px 0 6px 26px}

/* ═══════════════════════════════════════════════════════════
   THE MOBILITY PLAN — ported from Golazo on 18 Sep 2026 and cut to
   the roads and the closures. What follows is the plan's own screen
   (.mob-), its map (.mobm-), the side-street and detour cards (.ss-,
   .dp-, and the .ts-* look the readings share), the posts (.vr-), the
   fold every long card takes (.pm-fold) and the plan on paper (.mpr-).
   See js/mobility.js.
   ═══════════════════════════════════════════════════════════ */

/* The map card's host, the same wrapper the permits map upstream has. */
.pm-map-wrap{position:relative}
/* Every card on the mobility plan folds under its heading — see
   permitWireFold() in js/permits.js. The chevron turns; the body goes;
   the heading stays. */
.pm-fold-hd{cursor:pointer;user-select:none}
.pm-fold-btn{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;margin-right:4px;
  border:1px solid var(--border2);border-radius:6px;background:var(--bg3);color:var(--text2);cursor:pointer;
  vertical-align:middle;transition:transform .15s}
.pm-fold-btn:hover{color:var(--gold2);border-color:var(--gold-border)}
/* At the right: the last item of a header row, or floated to the edge of a bare heading. */
.pm-fold-btn.pm-fold-end{margin:0 0 0 auto;align-self:flex-start;flex-shrink:0}
.pm-fold-hd.pm-fold-row{display:flex;align-items:center;gap:8px}
.pm-fold-btn.pm-fold-float{margin:0 0 0 auto;flex-shrink:0}
.card.pm-folded > :not(.pm-fold-keep){display:none!important}
.card.pm-folded .pm-fold-btn{transform:rotate(-90deg)}
.card.pm-folded .pm-fold-keep{margin-bottom:0}

/* The people on the road (js/mob-posts.js): the police chip that says
   who holds a national-road junction, the count with its reliefs under
   the post boxes, and the list that goes to the police as a plain
   printed table. */
/* The plan on paper (js/mob-print.js): an A4 report — a cover, an
   overview map on a page of its own, one numbered chapter per page.
   Printed through #print-root; colours are asked for explicitly
   because browsers drop backgrounds on paper. */
.mpr-sheet{font-family:Arial,Helvetica,sans-serif;color:#111;background:#fff;padding:26px 30px;-webkit-print-color-adjust:exact;print-color-adjust:exact;font-size:11px;line-height:1.35}
.mpr-page{break-before:page}
.mpr-cover{min-height:900px;display:flex;flex-direction:column;justify-content:flex-start;padding-top:120px;border-left:8px solid #111827;padding-left:26px}
.mpr-eyebrow{font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:#555}
.mpr-sheet h1{font-size:40px;margin:6px 0 4px;letter-spacing:-.01em}
.mpr-sub{font-size:18px;font-weight:700}
.mpr-regime{font-size:12px;color:#444;margin-top:10px;max-width:60ch}
.mpr-tiles{display:flex;flex-wrap:wrap;gap:10px;margin:22px 0 6px}
.mpr-tiles>div{border:1px solid #bbb;border-radius:6px;padding:8px 14px;min-width:96px}
.mpr-tiles b{display:block;font-size:22px;line-height:1.1}
.mpr-tiles span{font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:#555}
.mpr-toc{margin:28px 0 0;padding-left:22px;font-size:13px;line-height:1.7;columns:2;column-gap:24px}
.mpr-meta{margin-top:auto;font-size:10.5px;color:#555;padding-top:24px}
.mpr-mappage h2{margin-bottom:8px}
.mpr-map{margin:0 0 8px}
.mpr-map img{width:100%;display:block;border:1px solid #ccc}
.mpr-map.small{margin:6px 0 0}
.mpr-map.sector{margin:10px 0 0;break-inside:avoid}
.mpr-map.sector figcaption{font-weight:700;color:#333}
.mpr-map.small img{border-color:#ddd}
.mpr-map figcaption,.mpr-credit{font-size:9.5px;color:#666;margin:3px 0 0}
.mpr-legend{display:flex;flex-wrap:wrap;gap:6px 16px;font-size:10.5px;margin:6px 0 0}
.mpr-legend i{display:inline-block;vertical-align:middle;margin-right:5px}
.mpr-legend i.ln{width:22px;height:4px;border-radius:2px}
.mpr-legend i.pt{width:10px;height:10px;border-radius:50%;border:1.5px solid #fff;box-shadow:0 0 0 1px #888}
.mpr-sheet h2{font-size:18px;margin:0 0 10px;padding:0 0 6px;border-bottom:2px solid #111827;break-after:avoid;display:flex;align-items:center;gap:10px}
.mpr-no{display:inline-block;min-width:26px;height:26px;border-radius:6px;background:#111827;color:#fff;font-size:13px;line-height:26px;text-align:center}
.mpr-sheet h3{font-size:12.5px;margin:12px 0 5px;break-after:avoid}
.mpr-sheet h3 small{font-weight:400;color:#666;font-size:11px}
.mpr-lead{margin:0 0 8px;font-size:12px;color:#333}
.mpr-verdict{border-left:3px solid #111827;background:#f3f4f6;padding:8px 12px;margin:0 0 10px;font-size:11px}
.mpr-verdict p{margin:0}
.mpr-verdict p+p{margin-top:4px}
.mpr-tbl{border-collapse:collapse;width:100%;font-size:10.5px;margin-bottom:6px}
.mpr-tbl th,.mpr-tbl td{border-bottom:1px solid #d1d5db;padding:4px 6px;text-align:left;vertical-align:top}
.mpr-tbl th{background:#f3f4f6;font-size:9.5px;text-transform:uppercase;letter-spacing:.04em;border-bottom:1.5px solid #9ca3af}
.mpr-tbl tbody tr:nth-child(even) td{background:#fafafa}
.mpr-tbl tr{break-inside:avoid}
.mpr-tbl td i{display:block;font-size:9.5px;color:#555;font-style:normal;margin-top:1px}
.mpr-tbl.mpr-half{width:55%}
.mpr-kind{white-space:nowrap}
.mpr-kind i{display:inline-block;width:8px;height:8px;border-radius:2px;margin-right:5px;vertical-align:0}
.mpr-st{display:inline-block;padding:0 6px;border-radius:999px;border:1px solid var(--c,#64748b);color:var(--c,#64748b);font-size:9.5px;font-weight:700;line-height:15px;white-space:nowrap}
.mpr-cat{display:inline-block;min-width:16px;text-align:center;background:#1e293b;color:#fff;border-radius:3px;padding:0 4px}
.mpr-need{display:inline-block;background:#fee2e2;color:#991b1b;border-radius:3px;padding:0 5px}
.mpr-letter{display:inline-block;width:20px;height:20px;border-radius:50%;background:#facc15;color:#713f12;font-weight:800;font-size:11px;line-height:20px;text-align:center;border:1.5px solid #713f12;vertical-align:middle}
.mpr-detour{margin-top:12px;break-inside:avoid}
.mpr-note{margin:0 0 6px;font-size:10.5px;color:#333}
.mpr-list{margin:0 0 6px;padding-left:18px}
.mpr-list li{margin:2px 0}
/* ── THE PLAN AS A DECK (js/mob-deck.js) ──
   Fixed pages at A4, portrait or landscape, in the championship's red,
   green and black; every page carries the logo, a map with its own rows
   beside or under it, and a foot with the page number. */
.mdk-doc{font-family:Arial,Helvetica,sans-serif;color:#111;background:#fff;-webkit-print-color-adjust:exact;print-color-adjust:exact}
.mdk-page{position:relative;box-sizing:border-box;width:794px;height:1123px;padding:0 34px 44px;overflow:hidden;
  break-after:page;page-break-after:always;display:flex;flex-direction:column;background:#fff}
.mdk-page.landscape{width:1123px;height:794px}
.mdk-doc > .mdk-page:last-child{break-after:auto;page-break-after:auto}
.mdk-hd{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:14px 0 9px;border-bottom:3px solid #a8262b;
  box-shadow:0 3px 0 #2e6b35;margin-bottom:14px;flex:0 0 auto}
.mdk-hd img{height:34px;width:auto}
.mdk-hd-t{display:flex;flex-direction:column;align-items:flex-end;font-size:10px;color:#555}
.mdk-hd-t b{font-size:12px;color:#111}
.mdk-bd{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}
.mdk-ft{position:absolute;left:34px;right:34px;bottom:14px;display:flex;justify-content:space-between;font-size:9px;color:#777;
  border-top:1px solid #ddd;padding-top:5px}
.mdk-page h2{font-size:19px;margin:0 0 6px;display:flex;align-items:center;gap:10px;line-height:1.2}
.mdk-page h2.sub{font-size:15px}
.mdk-no{display:inline-block;min-width:26px;height:26px;border-radius:6px;background:#a8262b;color:#fff;font-size:13px;line-height:26px;text-align:center}
.mdk-page h2.sub .mdk-no{background:#111;min-width:22px;height:22px;line-height:22px;font-size:11px}
.mdk-lead{font-size:11.5px;color:#333;margin:0 0 8px}
.mdk-map{margin:0 0 8px}
.mdk-map img{width:100%;display:block;border:1px solid #ccc;border-radius:4px}
.mdk-map figcaption{font-size:8.5px;color:#777;margin-top:2px}
.mdk-split{display:flex;flex-direction:column;gap:6px;min-height:0}
/* A map alone on its page is held to the page: full width on A4 upright,
   and on a landscape page as high as the page allows, centred. */
.mdk-bd > .mdk-map img{max-height:720px;width:auto;max-width:100%;margin:0 auto}
.landscape .mdk-bd > .mdk-map img{max-height:490px}
.mdk-bd > .mdk-map figcaption{text-align:center}
.landscape .mdk-split{flex-direction:row;align-items:flex-start;gap:14px}
.landscape .mdk-split > .mdk-map,.landscape .mdk-split > .mdk-mapcol{flex:0 0 58%}
.mdk-mapcol{min-width:0}
.mdk-key{display:flex;flex-wrap:wrap;gap:3px 12px;font-size:9px;color:#333;margin:0 0 8px}
.mdk-key span{display:inline-flex;align-items:center;gap:5px}
.mdk-key i{display:inline-block;flex:0 0 auto}
.mdk-key i.ln{width:18px;height:4px;border-radius:2px}
.mdk-key i.pt{width:9px;height:9px;border-radius:50%;box-shadow:0 0 0 1.5px #fff,0 0 0 2.5px rgba(0,0,0,.25)}
.mdk-side{flex:1 1 auto;min-width:0}
.mdk-tbl{width:100%;border-collapse:collapse;font-size:10px;table-layout:fixed}
.mdk-tbl th{background:#111;color:#fff;text-align:left;padding:4px 6px;font-size:8.5px;text-transform:uppercase;letter-spacing:.04em}
.mdk-tbl td{padding:3px 6px;border-bottom:1px solid #e5e7eb;vertical-align:top;overflow-wrap:anywhere}
.mdk-tbl tr:nth-child(even) td{background:#f6f6f4}
.mdk-tbl td i{display:block;font-style:normal;font-size:8.5px;color:#666;margin-top:1px}
.mdk-chip{display:inline-block;padding:0 6px;border-radius:999px;border:1px solid var(--c,#64748b);color:var(--c,#64748b);
  font-size:8.5px;font-weight:700;line-height:14px;white-space:nowrap}
.mdk-note{font-size:9.5px;color:#444;margin:6px 0 0}
.mdk-photos{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin:0 0 8px}
.mdk-photos img{width:100%;height:150px;object-fit:cover;border-radius:4px;border:1px solid #ddd}
.landscape .mdk-photos img{height:120px}
/* a page of photographs alone (road works: every photo of a job) */
.mdk-photos.big{grid-template-columns:repeat(2,1fr);gap:10px}
.mdk-photos.big img{height:270px;object-fit:contain;background:#f3f4f6}
.landscape .mdk-photos.big{grid-template-columns:repeat(3,1fr)}
.landscape .mdk-photos.big img{height:250px}
/* a wide picture shown whole (the race schedule: the profile under the map) */
.mdk-photos.wide{grid-template-columns:1fr}
.mdk-photos.wide img,.landscape .mdk-photos.wide img{height:auto;object-fit:contain}
.mdk-cover{padding:110px 64px 54px 90px}
.mdk-cover.landscape{padding:56px 70px 40px 96px}
.mdk-cover-band{position:absolute;left:0;top:0;bottom:0;width:18px;background:linear-gradient(#a8262b 0 34%,#111 34% 66%,#2e6b35 66%)}
.mdk-cover-logo{width:400px;max-width:72%;height:auto;margin-bottom:44px;align-self:flex-start}
.mdk-cover.landscape .mdk-cover-logo{width:340px;margin-bottom:26px}
.mdk-eyebrow{font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:#555}
.mdk-cover h1{font-size:42px;margin:6px 0 4px;line-height:1.1}
.mdk-sub{font-size:18px;font-weight:700;color:#a8262b}
.mdk-regime{font-size:12px;color:#444;max-width:64ch;margin:14px 0 0}
.mdk-flags{font-size:12px;font-weight:700;color:#2e6b35;max-width:64ch;margin:8px 0 0}
.mdk-tiles{display:flex;flex-wrap:wrap;gap:10px;margin:24px 0 6px}
.mdk-tiles > div{border:1px solid #ddd;border-top:4px solid #a8262b;border-radius:6px;padding:8px 14px;min-width:104px}
.mdk-tiles > div:nth-child(2){border-top-color:#111}
.mdk-tiles > div:nth-child(3){border-top-color:#2e6b35}
.mdk-tiles b{display:block;font-size:24px;line-height:1.1}
.mdk-tiles span{font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:#555}
.mdk-toc{margin:26px 0 0;padding-left:22px;font-size:13px;line-height:1.8;columns:2;column-gap:28px}
.mdk-meta{margin-top:auto;font-size:10.5px;color:#555}
.vr-logo{height:38px;width:auto;display:block;margin:0 0 8px}
.mpr-foot{margin-top:16px;padding-top:6px;border-top:1px solid #999;font-size:9.5px;color:#666}
/* The detour plan (js/detour-plan.js): the letter of a detour as the
   round badge the boards carry. */
.dp-letter{display:inline-block;width:24px;height:24px;border-radius:50%;background:#facc15;color:#713f12;font-weight:800;font-size:12px;line-height:24px;text-align:center;border:1.5px solid #713f12}
.vr-cat{display:inline-block;min-width:18px;padding:0 5px;border-radius:4px;background:#1e293b;color:#fff;font-size:11px;font-weight:800;text-align:center;line-height:18px}
.vr-chip{display:inline-block;padding:0 7px;border-radius:999px;background:#fef3c7;color:#92400e;font-size:11px;font-weight:800;line-height:18px;margin-left:4px}
.vr-chip.pro{background:#fee2e2;color:#991b1b}
.vr-chip.ok{background:#dcfce7;color:#166534}
.vr-hint{color:#991b1b;font-weight:600}
.vr-staff{display:flex;flex-wrap:wrap;gap:6px 14px;margin-top:10px;font-size:12.5px;color:var(--text2)}
.vr-warn{color:#991b1b;font-weight:700}
.ss-cat{width:56px;min-width:0;padding:2px 4px}

/* ── THE MOBILITY PLAN ─────────────────────────────────────────
   Two halves that have to read as one: a map somebody points at in a
   meeting, and a table somebody works down on a Monday. The colours are
   the measures' own — set inline from MOB_KINDS, because a traffic plan
   whose red is not the red on the map is a plan read twice. See
   js/mobility.js. */
.mob-actions{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 12px}
.mob-flags{margin-top:6px;font-size:13px;font-weight:700;color:var(--text2)}
.mob-mapcard{padding:14px;margin-bottom:14px;position:relative}
.mobm-selbox{position:absolute;z-index:5;pointer-events:none;border:2px dashed #eab308;background:rgba(250,204,21,.18);border-radius:3px}
.mob-selwrap{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap;margin-left:auto}
.mob-selhint{font-size:12px;color:var(--text3)}
.mob-selbar{font-size:12.5px;color:var(--text2);padding:0 4px}
.mob-selbar b{color:var(--text);font-size:14px}
.mob-row.is-sel td{background:rgba(250,204,21,.18)!important}
.mob-row.is-sel td:first-child{box-shadow:inset 3px 0 0 #eab308}
.mob-fab{display:none}
.mob-mapcard.is-full .mob-fab{display:inline-flex;align-items:center;gap:8px;position:absolute;left:50%;bottom:34px;transform:translateX(-50%);z-index:8;
  padding:12px 20px 12px 16px;border:0;border-radius:999px;background:linear-gradient(135deg,var(--accent-fill),var(--accent-fill2));color:var(--on-accent);
  font:800 14px/1 var(--font-body);box-shadow:0 6px 20px rgba(0,0,0,.35);cursor:pointer}
.mob-mapcard.is-full .mob-fab svg{width:22px;height:22px}
.mob-mapcard.is-full .mob-fab:hover{filter:brightness(1.08)}
/* The plan map full screen (mobFull): the card over the page, under the
   measure window's layer (--z-modal 100), the map filling what is left. */
.mob-fullbar{position:absolute;top:12px;right:52px;z-index:3;display:flex;gap:6px;align-items:center}
.mob-mapcard.is-full{position:fixed;inset:0;z-index:90;margin:0;border-radius:0;display:flex;flex-direction:column;padding:10px 14px 12px;background:var(--bg2)}
.mob-mapcard.is-full .mob-fullbar{right:14px;top:10px}
.mob-mapcard.is-full .mob-maphd{padding-right:340px}
.mob-mapcard.is-full #mob-map-mount{flex:1 1 auto;min-height:0;display:flex}
.mob-mapcard.is-full .mob-map-wrap{flex:1 1 auto;display:flex;flex-direction:column;width:100%;min-height:0}
.mob-mapcard.is-full .mob-map-wrap #mob-map-shell{height:auto;flex:1 1 auto;min-height:0}
body:has(#v-mobility.active .mob-mapcard.is-full){overflow:hidden}
@media (max-width:760px){.mob-fullbar{position:static;margin:0 0 8px;justify-content:flex-end}.mob-mapcard.is-full .mob-maphd{padding-right:0}}
.mob-maphd{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;
  flex-wrap:wrap;margin-bottom:8px}
.mob-maphd h3{margin:0 0 2px;font-size:14px;font-weight:800}
.mob-maptools{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
/* The name of what is being drawn, so the toolbar can never be about a
   measure the person has stopped thinking about. */
.mob-drawing{font-size:11.5px;font-weight:800;color:var(--text2);
  padding:3px 8px;border-radius:999px;background:var(--bg3)}
.mob-map-wrap #mob-map-shell{height:clamp(460px,62vh,760px);border-radius:12px;
  overflow:hidden;margin-top:4px}
.mob-map-wrap #mob-map-shell .map-fallback{height:100%;display:flex;align-items:center;
  justify-content:center;gap:8px;color:var(--text3)}
.mob-map-wrap:fullscreen{background:var(--bg,#0c1116)}
.mob-map-wrap:fullscreen #mob-map-shell{height:100%;border-radius:0;margin:0}

/* The legend over the plan map that is also its switches — see
   MOBM_GROUPS. A chip off is a chip greyed, and its layers are gone. */
.mobm-layers{position:absolute;left:10px;bottom:10px;z-index:6;display:flex;flex-wrap:wrap;gap:4px;max-width:calc(100% - 20px)}
.mobm-layer{display:inline-flex;align-items:center;gap:5px;padding:3px 8px 3px 6px;border-radius:999px;
  border:1px solid rgba(15,23,42,.18);background:rgba(255,255,255,.94);color:#0f172a;font:700 10.5px/1.3 var(--font-body);
  cursor:pointer;box-shadow:0 1px 3px rgba(0,0,0,.18)}
.mobm-layer i{width:10px;height:10px;border-radius:50%;background:var(--c);flex-shrink:0}
.mobm-layer i.ring{background:#fff;border:2.5px solid var(--c)}
.mobm-layer i.dash{border-radius:2px;height:4px;background:repeating-linear-gradient(90deg,var(--c) 0 3px,transparent 3px 5px)}
.mobm-layer.off{opacity:.55;background:rgba(255,255,255,.8);text-decoration:line-through}
.mobm-layer:hover{border-color:#0f172a}
/* The key: what every line, dot and disc on the plan map is. */
.mobm-key{position:absolute;right:10px;bottom:30px;z-index:6;max-width:min(300px,calc(100% - 20px));max-height:calc(100% - 70px);
  overflow:auto;background:rgba(255,255,255,.96);color:#0f172a;border:1px solid rgba(15,23,42,.18);border-radius:10px;
  box-shadow:0 2px 8px rgba(0,0,0,.2);font:600 11px/1.3 var(--font-body)}
.mobm-key[hidden]{display:none}
.mobm-key-hd{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;padding:6px 10px;border:0;background:none;
  color:#0f172a;font:800 10.5px/1.2 var(--font-body);text-transform:uppercase;letter-spacing:.06em;cursor:pointer}
.mobm-key.shut .mobm-key-hd{padding:5px 10px}
.mobm-key-bd{padding:0 10px 8px;display:flex;flex-direction:column;gap:3px}
.mobm-key-row{display:flex;align-items:center;gap:7px}
.mobm-key-sw{flex:0 0 auto}
.mobm-eye{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border:0;border-radius:6px;
  background:none;color:#334155;cursor:pointer;padding:0}
.mobm-eye:hover{background:rgba(15,23,42,.08)}
.mobm-key-row.off > .mobm-key-sw,.mobm-key-row.off > span{opacity:.38}
.mobm-key-row.off .mobm-eye{color:#94a3b8}
@media (max-width:640px){.mobm-key{bottom:52px}}
/* The card a click on the plan map answers with. */
.mobm-pop .mapboxgl-popup-content{padding:12px 14px!important}
.mobm-pop-body{font-size:12px;line-height:1.45;min-width:200px}
.mobm-pop-hd{display:flex;align-items:center;gap:6px;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--text3);margin-bottom:3px}
.mobm-pop-hd i{width:10px;height:10px;border-radius:50%;flex-shrink:0;border:2px solid transparent}
.mobm-pop-hd i.ring{background:#fff;border-width:2.5px}
.mobm-pop-hd i.dash{border-radius:2px;height:4px}
.mobm-pop-body strong{display:block;font-size:13px;margin-bottom:4px}
.mobm-pop-sub{margin:-2px 0 6px;color:var(--text2)}
.mobm-pop-post{display:inline-block;min-width:22px;padding:0 5px;border-radius:4px;background:#f59e0b;color:#fff;text-align:center;font-weight:800}
.mobm-pop-row{display:flex;gap:10px;justify-content:space-between;padding:2px 0;border-top:1px solid var(--border)}
.mobm-pop-row span{color:var(--text3);white-space:nowrap}
.mobm-pop-row b{font-weight:600;text-align:right}
.mobm-pop-note{margin:6px 0 0;color:var(--text2);font-style:italic}
.mobm-pop-acts{margin-top:8px;padding-top:8px;border-top:1px solid var(--border);display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.mobm-pop-acts .hint{font-size:11px}
.mob-filters{display:flex;gap:6px;flex-wrap:wrap;align-items:center;margin:0 0 12px}
.mob-filters .btn b{margin-left:4px;opacity:.7}

.mob-card{padding:0;overflow:hidden}
/* The table card has no padding of its own — the table fills it — so
   its heading carries the same padding every other card's does, and
   folded it reads as the same bar. */
.mob-card-hd{padding:14px 14px 8px;margin-bottom:0}
.mob-card.pm-folded .mob-card-hd{padding-bottom:14px}
.mob-tbl{border-collapse:collapse;width:100%;min-width:820px}
.mob-tbl th{text-align:left;font-size:9.5px;text-transform:uppercase;letter-spacing:.06em;
  color:var(--text3);padding:10px 12px 6px;white-space:nowrap;border-bottom:1px solid var(--border)}
.mob-tbl td{padding:9px 12px;font-size:12px;color:var(--text);vertical-align:top;
  border-bottom:1px solid var(--border)}
.mob-row{cursor:pointer}
/* The hover is the same faint lift every other table gives a row — the
   token this borrowed did not exist on the light theme, and its dark
   fallback painted the row black under black text (Janny, 16 Sep 2026). */
.mob-row:hover td{background:var(--bg3)}
/* A closure that came off the course is shown, not offered: it is read
   here and changed somewhere else, and it has to look it. */
.mob-row.is-derived{opacity:.62}
.mob-row.is-derived:hover{background:transparent;cursor:default}
.mob-kind{white-space:nowrap;font-weight:700}
.mob-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:6px;
  vertical-align:middle}
.mob-title b{display:block;font-weight:700}
.mob-title i{display:block;font-style:normal;font-size:11px;color:var(--text3);margin-top:2px}
.mob-when{white-space:nowrap;color:var(--text2)}
.mob-when i{display:block;font-style:normal;font-size:10.5px;color:var(--text3)}
.mob-posts{white-space:nowrap;font-weight:700}
.mob-none{color:var(--text3)}
.mob-act{text-align:right;white-space:nowrap}

.mob-chip{display:inline-block;padding:2px 8px;border-radius:999px;font-size:10.5px;
  font-weight:800;color:var(--c);border:1px solid var(--c);background:transparent;
  white-space:nowrap}
.mob-chip.is-btn{cursor:pointer}
.mob-chip.is-btn:hover{background:var(--c);color:#0b0f14}

.mob-open{padding:14px;margin-top:14px}
.mob-openrow{display:flex;gap:12px;align-items:flex-start;padding:7px 0;
  border-bottom:1px solid var(--border)}
.mob-openrow:last-child{border-bottom:0}
.mob-openrow>b{min-width:180px;font-size:12px}
.mob-opentags{display:flex;gap:5px;flex-wrap:wrap}

.mob-posts-card,.mob-signs{padding:14px;margin-top:14px}
.mob-postgrid{display:flex;gap:10px;flex-wrap:wrap;margin-top:8px}
.mob-postbox{display:flex;flex-direction:column;gap:1px;padding:8px 14px;border-radius:10px;
  background:var(--bg3);min-width:120px}
.mob-postbox b{font-size:20px;font-weight:800;line-height:1}
.mob-postbox span{font-size:11px;color:var(--text2)}
.mob-postbox i{font-style:normal;font-size:10px;color:var(--text3);letter-spacing:.06em}

/* The headcount boxes in the measure dialogue: four roles, one number
   each, because that is the shape of the order that leaves the office. */
/* The pin under the street field: where the measure is on the map, and
   the one button that puts it there. */
.mob-pinrow{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;margin:-6px 0 14px}
.mob-pinsay{font-size:12.5px;color:var(--text2)}
.mob-pinbtns{display:flex;gap:6px;flex-wrap:wrap}
#mob-corner{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:-8px 0 12px}
#mob-corner[hidden]{display:none}
.mob-postedit{display:flex;gap:8px;flex-wrap:wrap}
.mob-postin{display:flex;flex-direction:column;gap:2px;min-width:96px}
.mob-postin span{font-size:11px;font-weight:800;letter-spacing:.06em}
.mob-postin i{font-style:normal;font-size:10px;color:var(--text3)}
.mob-swatches{display:flex;align-items:center;gap:8px;margin:-6px 0 12px;flex-wrap:wrap}
.mob-swatch{width:26px;height:26px;border-radius:50%;border:2px solid #fff;background:var(--c);box-shadow:0 0 0 1px rgba(0,0,0,.25);cursor:pointer}
.mob-swatch:hover{box-shadow:0 0 0 2px var(--text)}
.mob-swatch-hint{font-size:11.5px;color:var(--text3)}
.mob-postin > label{display:flex;flex-direction:column;gap:2px;cursor:pointer}
.mob-step{display:flex;align-items:stretch;gap:0}
.mob-step input{width:100%;min-width:34px;text-align:center;border-radius:0}
.mob-step-b{flex:0 0 28px;border:1px solid var(--border);background:var(--bg3);color:var(--text);font:800 15px/1 var(--font-body);cursor:pointer}
.mob-step-b:first-child{border-radius:8px 0 0 8px;border-right:0}
.mob-step-b:last-child{border-radius:0 8px 8px 0;border-left:0}
.mob-step-b:hover{background:var(--gold-bg);color:var(--gold2)}

@media (max-width:640px){
  .mob-tbl{min-width:640px}
  .mob-openrow{flex-direction:column;gap:4px}
  .mob-openrow>b{min-width:0}
}


/* ── THE READINGS' OWN LOOK ────────────────────────────────────
   The side-street and detour cards wear the .ts-* classes the
   public-transport reading gave them upstream: a card, a small
   uppercase heading, a table that scrolls sideways on a phone, a
   street with its class under it, a kilometre column. The names stay
   so a card that comes over from Golazo needs no re-teaching. */
.ts-card{padding:14px;margin-top:14px}
/* The side-street card: the sign, the post and the count chosen once
   above the list; a street already on the plan reads as done. */
.ss-opts{display:flex;align-items:flex-end;gap:12px;flex-wrap:wrap;margin:12px 0 4px}
.ss-opts label{display:flex;flex-direction:column;gap:3px;font-size:10.5px;font-weight:800;
  text-transform:uppercase;letter-spacing:.06em;color:var(--text3)}
.ss-opts .input.sm{min-width:150px}
.ss-opts .ss-n{width:64px;min-width:0}
.ss-count{margin:6px 0 4px}
.ss-tick{width:24px}
.ss-tick input{width:16px;height:16px}
.ss-done td{color:var(--text3)}
.ss-done .ts-stop b{color:var(--text2)}
.ts-h{margin:14px 0 6px;font-size:11px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;color:var(--text3)}
.ts-tbl{border-collapse:collapse;width:100%;min-width:640px}
.ts-tbl th{text-align:left;font-size:9.5px;text-transform:uppercase;letter-spacing:.06em;
  color:var(--text3);padding:0 10px 5px 0;white-space:nowrap;border-bottom:1px solid var(--border)}
.ts-tbl td{padding:7px 10px 7px 0;font-size:12px;color:var(--text);vertical-align:middle;
  border-bottom:1px solid var(--border)}
.ts-stop b{display:block;font-weight:700}
.ts-stop i{display:block;font-style:normal;font-size:11px;color:var(--text3);margin-top:1px}
.ts-km,.ts-d{white-space:nowrap;color:var(--text2)}
.ts-credit{color:var(--text3);font-size:10.5px}
/* The tables scroll inside their card on a phone rather than pushing
   the page sideways. */
.tbl-wrap{overflow-x:auto}
@media (max-width:640px){ .ts-tbl{min-width:560px} }

/* The line at the top of a shared mobility plan saying whose half it
   is. A filtered list that does not say it is filtered reads as a
   complete one. See mobSharedNoteHtml() in js/mobility.js. */
.mob-shared{padding:10px 14px;margin:0 0 12px;font-size:12px;color:var(--text2);
  border-left:3px solid var(--primary,#59ef83)}
.mob-shared b{color:var(--text)}
/* A read-only plan: the rows are rows, not doors. */
.mob-card.is-ro .mob-row{cursor:default}
.mob-card.is-ro .mob-row:hover{background:transparent}

/* ── THE ORGANISATION'S ONE LINK ───────────────────────────────
   The stays on the accreditation-and-bed form (js/staffreq.js): a
   place, two dates and the nights they make on one row, the row
   folding to two columns on a phone with the place across the top. */
.sr-stay{display:grid;grid-template-columns:1.4fr 1fr 1fr auto;gap:10px;align-items:end;margin-bottom:4px}
.sr-stay .field{margin:0}
/* A flight: which way, when, the number, the airport — one row. */
.sr-leg{display:grid;grid-template-columns:1.3fr .9fr .7fr .8fr 1.2fr auto;gap:10px;align-items:end;margin-bottom:4px}
.sr-leg .field{margin:0}
.sr-stay-x{display:flex;align-items:center;gap:8px;min-height:40px;padding-bottom:2px;white-space:nowrap}
.sr-stay .input.invalid{border-color:#dc2626;box-shadow:0 0 0 2px rgba(220,38,38,.18)}
@media (max-width:640px){
  .sr-stay{grid-template-columns:1fr 1fr}
  .sr-stay > .field:first-child{grid-column:1 / -1}
  .sr-stay-x{grid-column:1 / -1;min-height:0}
  .sr-leg{grid-template-columns:1fr 1fr}
  .sr-leg > .field:first-child{grid-column:1 / -1}
}

/* ── THE PRIVACY NOTICE: the tick on the public forms, and the link
   under the maker's mark. consentHtml() in js/utils.js draws the block;
   it turns red like any field (markInvalid), and the link sits beside
   the label rather than in it, or opening the notice would toggle the
   box. The notice itself is privacy.html. (Compliance round, 20 Sep
   2026.) */
.field.consent{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;
  margin:6px 0 14px;padding:10px 12px;border:1px solid var(--line,rgba(232,238,252,.14));
  border-radius:10px;background:var(--surface2,rgba(232,238,252,.04))}
.field.consent .chk{flex:1 1 260px;margin:0}
.field.consent .chk-t{font-size:13px;line-height:1.45}
.field.consent .hint{flex-basis:100%;margin:2px 0 0;font-size:12px}
.field.consent.invalid{border-color:var(--red,#dc2626);box-shadow:0 0 0 2px rgba(220,38,38,.15)}
.consent-link{font-size:13px;font-weight:600;color:var(--accent,#f59e0b);text-decoration:underline;
  text-underline-offset:3px;white-space:nowrap}
.auth-privacy{display:block;margin:10px auto 0;font-size:11px;color:rgba(232,238,252,.5);
  text-decoration:underline;text-underline-offset:3px;text-align:center}
.auth-privacy:hover{color:rgba(232,238,252,.85)}

/* ── THE PLAYER WAITS FOR A PRESS (js/broadcast.js, mountStream) ── */
.bc-consent{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:10px;padding:24px;background:none;border:0;color:#e8eefc;cursor:pointer;text-align:center;font:inherit}
.bc-consent-play{width:72px;height:72px;border-radius:50%;background:#f59e0b;color:#0b1120;
  display:flex;align-items:center;justify-content:center;font-size:30px;padding-left:6px;
  box-shadow:0 8px 30px rgba(245,158,11,.35)}
.bc-consent:hover .bc-consent-play{transform:scale(1.06)}
.bc-consent-t{font-size:clamp(14px,1.4vw,22px);font-weight:700}
.bc-consent-s{max-width:520px;font-size:clamp(11px,1vw,15px);color:#94a3b8;line-height:1.5}
.bc-consent-link{position:absolute;left:50%;bottom:18px;transform:translateX(-50%);z-index:3;
  font-size:12px;color:#fbbf24;text-decoration:underline;text-underline-offset:3px}

/* ── The road-works budget meter, under the map (js/roadworks.js
   rwMeterHtml) — one bar in the status colours against the envelope,
   then a row per party. ── */
.rw-meter{border:1px solid var(--border2);background:var(--bg2);border-radius:14px;padding:14px 16px;margin:0 0 14px}
.rw-meter-empty{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;color:var(--text2);font-size:13px}
.rw-meter-hd{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap;margin-bottom:10px}
.rw-meter-hd>div:first-child{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;flex:1 1 260px;min-width:0}
.rw-meter-k{width:100%;font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:var(--text3)}
.rw-meter-v{font-size:22px;font-weight:800;color:var(--text)}
.rw-meter-alt{font-size:14px;font-weight:700;color:var(--text2)}
.rw-meter-of{font-size:12.5px;color:var(--text2)}
.rw-meter-left{display:flex;flex-direction:column;align-items:flex-end;text-align:right}
.rw-meter-left span{font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:var(--text3)}
.rw-meter-left strong{font-size:17px;color:var(--green,#34d399)}
.rw-meter-left small{font-size:12px;color:var(--text2)}
.rw-meter-left.over strong{color:var(--red)}
.rw-meter-bar{position:relative;display:flex;height:14px;border-radius:8px;background:var(--bg4);overflow:visible}
.rw-meter-seg{display:block;height:100%}
.rw-meter-seg:first-child{border-radius:8px 0 0 8px}
.rw-meter-seg:last-of-type{border-top-right-radius:8px;border-bottom-right-radius:8px}
.rw-meter-cap{position:absolute;top:-4px;bottom:-4px;width:2px;margin-left:-1px;background:var(--text);border-radius:1px}
.rw-meter.over .rw-meter-cap{background:var(--red)}
.rw-meter-legend{display:flex;gap:14px;flex-wrap:wrap;margin-top:9px;font-size:12px;color:var(--text2)}
.rw-meter-legend i{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:6px;vertical-align:-1px}
.rw-meter-parties{display:grid;gap:4px;margin-top:12px;padding-top:10px;border-top:1px solid var(--border2)}
.rw-meter-row{display:grid;grid-template-columns:minmax(90px,170px) 1fr auto;align-items:center;gap:12px;padding:6px 8px;border:1px solid transparent;
  border-radius:9px;background:none;color:var(--text);font-family:inherit;font-size:12.5px;text-align:left;cursor:pointer}
.rw-meter-row:hover{background:var(--bg3)}
.rw-meter-row.active{background:var(--gold-bg);border-color:var(--gold-border)}
.rw-meter-name{font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rw-meter-mini{height:7px;border-radius:4px;background:var(--bg4);overflow:hidden}
.rw-meter-mini span{display:block;height:100%;background:var(--gold2);border-radius:4px}
.rw-meter-amt{font-weight:700;white-space:nowrap}
.rw-meter-amt small{font-weight:600;color:var(--text2);margin-left:4px}
@media (max-width:560px){
  .rw-meter-row{grid-template-columns:1fr auto}
  .rw-meter-mini{grid-column:1 / -1;order:3}
}

/* ── Road works: the route for the crew, under the map (js/rw-route.js) ── */
.rw-route{padding:14px 16px;margin:0 0 14px}
.rw-route-hd{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:10px}
.rw-route-hd>div:first-child{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1 1 280px}
.rw-route-k{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:#2563eb}
.rw-route-k svg{width:14px;height:14px}
.rw-route-hd strong{font-size:16px;color:var(--text)}
.rw-route-sub{font-size:12.5px;color:var(--text2)}
.rw-route-acts{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.rw-route-list{display:grid;gap:2px;max-height:420px;overflow:auto;border-top:1px solid var(--border2);padding-top:6px}
.rw-route-row{display:grid;grid-template-columns:28px 54px minmax(0,1fr) auto 10px;align-items:center;gap:10px;padding:7px 8px;border:1px solid transparent;
  border-radius:9px;background:none;color:var(--text);font-family:inherit;font-size:12.5px;text-align:left;cursor:pointer;width:100%}
.rw-route-row:hover{background:var(--bg3)}
.rw-route-row.end{cursor:default;opacity:.85}
.rw-route-n{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:50%;background:#2563eb;color:#fff;font-weight:800;font-size:11.5px}
.rw-route-t{font-weight:800;display:flex;flex-direction:column;line-height:1.15}
.rw-route-t small,.rw-route-w small,.rw-route-leg small{font-weight:600;color:var(--text2);font-size:11px}
.rw-route-w{display:flex;flex-direction:column;min-width:0}
.rw-route-w b,.rw-route-w small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rw-route-leg{display:flex;flex-direction:column;align-items:flex-end;font-weight:700;white-space:nowrap}
.rw-route-st{width:9px;height:9px;border-radius:50%}
@media (max-width:560px){
  .rw-route-row{grid-template-columns:24px 46px minmax(0,1fr) auto;gap:8px}
  .rw-route-st{display:none}
}

/* ── Medical: the reach key and its switch (js/med-reach.js) ── */
.med-reach-key{position:absolute;left:10px;bottom:30px;z-index:3;display:flex;flex-direction:column;gap:3px;
  padding:8px 10px;border-radius:9px;background:rgba(255,255,255,.94);color:#0f172a;font-size:11.5px;font-weight:700;
  box-shadow:0 1px 6px rgba(15,23,42,.25);pointer-events:none;max-width:220px}
.med-reach-key b{font-size:10.5px;letter-spacing:.04em;text-transform:uppercase;color:#334155}
.med-reach-key span{display:flex;align-items:center;gap:6px}
.med-reach-key i{display:inline-block;width:14px;height:10px;border-radius:3px;opacity:.75}
.med-reach-key small{font-weight:600;color:#64748b}
#med-reach-btn.on{background:var(--gold-bg);border-color:var(--gold-border);color:var(--gold2)}

/* ── The communications plan (js/comms.js) ── */
.comms-sec{margin-bottom:14px}
.comms-sec-hd{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:10px}
.comms-sec-hd h3{margin:0}
.comms-none{color:var(--text2);font-size:13px;margin:4px 0}
.comms-table{display:grid;gap:2px}
.comms-tr{display:grid;grid-template-columns:minmax(120px,1.2fr) minmax(70px,.6fr) minmax(120px,1.2fr) minmax(120px,1.2fr) auto;gap:10px;align-items:center;
  padding:7px 8px;border-radius:8px;font-size:13px}
.comms-table.radios .comms-tr{grid-template-columns:60px minmax(160px,2fr) minmax(80px,.8fr) minmax(90px,.8fr) auto}
.comms-tr:not(.comms-th):hover{background:var(--bg3)}
.comms-th{font-size:11px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;color:var(--text3)}
.comms-ch{font-weight:800;color:var(--gold2)}
.comms-acts{display:flex;gap:2px;justify-content:flex-end}
.comms-tree{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:10px}
.comms-step{border:1px solid var(--border2);border-radius:10px;padding:10px 12px;background:var(--bg2)}
.comms-step-hd{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-bottom:4px}
.comms-step ol{margin:0;padding-left:20px;font-size:13px;line-height:1.5;color:var(--text)}
.comms-nums{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:8px}
.comms-num{display:grid;grid-template-columns:1fr auto;gap:2px 8px;align-items:center;border:1px solid var(--border2);border-radius:10px;padding:9px 11px;background:var(--bg2);font-size:13px}
.comms-num a{font-weight:800;color:var(--text);text-decoration:none;white-space:nowrap}
.comms-num small{grid-column:1 / -1;color:var(--text3);font-size:11px}
.comms-num .comms-acts{grid-column:1 / -1;justify-content:flex-start}
.comms-st{font-weight:700;color:var(--text3)}
.comms-st.out{color:var(--gold2)}
.comms-st.back{color:var(--green)}
@media (max-width:640px){
  .comms-tr,.comms-table.radios .comms-tr{grid-template-columns:1fr auto}
  .comms-th{display:none}
  .comms-tr > span:not(:first-child):not(.comms-acts){grid-column:1 / 2;font-size:12px;color:var(--text2)}
}
.comms-num.example{border-color:var(--red-border);background:linear-gradient(var(--red-bg),var(--red-bg)),var(--bg2)}
.comms-num.example small{color:var(--red);font-weight:700}

/* ── Communications plan: fallback, decisions, levels, coverage map (js/comms.js) ── */
.comms-sec-btns{display:flex;gap:6px;flex-wrap:wrap}
.comms-table.pace .comms-tr{grid-template-columns:minmax(110px,1fr) repeat(4,minmax(100px,1fr)) auto}
.comms-table.dec .comms-tr{grid-template-columns:minmax(140px,1.3fr) minmax(120px,1.1fr) minmax(110px,1fr) minmax(110px,1fr) minmax(110px,1fr) auto}
.comms-table.cov .comms-tr{grid-template-columns:minmax(140px,1.2fr) 90px minmax(110px,1fr) minmax(120px,1.4fr) auto}
.comms-todo{color:var(--red);font-weight:800}
.comms-cov{display:inline-flex;align-items:center;gap:5px;font-weight:700}
.comms-cov::before{content:'';width:9px;height:9px;border-radius:50%;background:var(--c)}
.comms-cov-sum{margin:8px 0 6px}
.comms-levels{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:10px}
.comms-level{border:1px solid var(--border2);border-left:5px solid #94a3b8;border-radius:10px;padding:10px 12px;background:var(--bg2);font-size:13px}
.comms-level p{margin:4px 0 0}
.comms-level.lv1{border-left-color:#16a34a}
.comms-level.lv2{border-left-color:#f59e0b}
.comms-level.lv3{border-left-color:#dc2626}
.comms-map-shell{position:relative;height:340px;border-radius:12px;overflow:hidden;border:1px solid var(--border2);margin-bottom:6px;background:var(--bg3)}
.comms-map{position:absolute;inset:0}
.comms-map.picking .mapboxgl-canvas{cursor:crosshair}
.comms-place{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:-4px 0 12px}
.comms-pickrow{margin-top:-8px}
@media (max-width:640px){ .comms-map-shell{height:260px} }

/* ── Communications plan: call signs, protocol, radio checks (js/comms.js) ── */
.comms-table.cs .comms-tr{grid-template-columns:minmax(110px,.8fr) minmax(160px,1.6fr) minmax(110px,1fr) auto}
.comms-sign{font-weight:800;letter-spacing:.01em}
.comms-proto{border:1px solid var(--border2);border-radius:10px;padding:10px 12px;background:var(--bg2);margin-top:10px;font-size:13px}
.comms-proto ol{margin:6px 0 0;padding-left:20px}
.comms-proto li{margin:3px 0}
.comms-mob{margin:8px 0 0}
.comms-checks{display:grid;gap:12px}
.comms-check{border:1px solid var(--border2);border-radius:12px;padding:10px 12px;background:var(--bg2)}
.comms-check-hd{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.comms-check-hd>div:first-child{flex:1;min-width:160px;display:flex;flex-direction:column}
.comms-check-sum{display:inline-flex;gap:10px;font-size:12px;font-weight:700;color:var(--text3)}
.comms-check-sum .ok{color:#16a34a}
.comms-check-sum .no{color:var(--red)}
.comms-roll{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:6px;margin-top:10px}
.comms-roll-row{display:grid;grid-template-columns:auto 1fr auto auto auto;align-items:center;gap:8px;padding:6px 8px;border-radius:8px;background:var(--bg3);border-left:4px solid transparent;font-size:13px}
.comms-roll-row .c-sub{margin:0;line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.comms-roll-row.ok{border-left-color:#16a34a}
.comms-roll-row.none{border-left-color:var(--red);background:color-mix(in srgb,var(--red) 10%,var(--bg3))}
.comms-roll-at{font-size:11px;color:var(--text3);font-variant-numeric:tabular-nums}
.comms-tick{width:30px;height:30px;border-radius:8px;border:1px solid var(--border2);background:var(--bg2);color:var(--text3);font-weight:800;cursor:pointer}
.comms-tick.ok.on{background:#16a34a;border-color:#16a34a;color:#fff}
.comms-tick.no.on{background:var(--red);border-color:var(--red);color:#fff}
@media (max-width:640px){ .comms-table.cs .comms-tr{grid-template-columns:1fr 1fr auto} .comms-table.cs .comms-tr>span:nth-child(3){display:none} }

/* ── TIME-TRIAL FLOW — js/tt-flow.js ── */
.ttf-wrap{display:flex;flex-direction:column;gap:14px;min-width:0}
.ttf-empty{padding:22px;color:var(--text2)}
.ttf-days{display:flex;gap:6px;flex-wrap:wrap}
.ttf-day{min-height:40px;padding:0 14px;border-radius:999px;border:1px solid var(--border2);background:var(--bg2);color:var(--text2);font-weight:700;cursor:pointer}
.ttf-day.on{background:var(--gold);border-color:var(--gold);color:#111}
.ttf-plan{padding:12px 14px}
.ttf-plan-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
.ttf-tbl{width:100%;border-collapse:collapse;font-size:13px}
.ttf-tbl th{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;color:var(--text3);text-align:left;padding:6px 8px;border-bottom:1px solid var(--border);white-space:nowrap}
.ttf-tbl td{padding:7px 8px;border-bottom:1px solid var(--border);vertical-align:middle}
.ttf-tbl .num{text-align:right;font-variant-numeric:tabular-nums}
.ttf-tbl td.num small,.ttf-on small{display:block;font-size:11px;color:var(--text3);font-weight:500}
.ttf-tbl tr.off td{opacity:.5}
.ttf-tbl td.warn{color:var(--warn,#f59e0b);font-weight:700}
.ttf-tbl td.bad{color:var(--red);font-weight:700}
.ttf-tbl tr.best td{background:color-mix(in srgb,var(--green,#16a34a) 10%,transparent)}
.ttf-on{display:flex;align-items:center;gap:8px;cursor:pointer;min-width:190px}
.ttf-on > i{width:12px;height:12px;border-radius:50%;flex:none}
.ttf-in{width:74px;min-height:36px;padding:0 8px;border-radius:8px;border:1px solid var(--field-border,var(--border2));background:var(--bg3);color:var(--text);font:inherit}
.ttf-in.sm{width:58px}
.ttf-sel{min-height:36px;padding:0 8px;border-radius:8px;border:1px solid var(--field-border,var(--border2));background:var(--bg3);color:var(--text);font:inherit}
.ttf-wv{white-space:nowrap}
.ttf-none{color:var(--text3)}
/* A reserve on a start list: over the maximum of starters per nation. */
.sl-reserve{display:inline-block;padding:1px 7px;border-radius:999px;border:1px dashed var(--border2);color:var(--text3);font-size:11px;font-weight:700;font-family:inherit}
/* A calculation's own course, laps and lap length, under the race's name. */
.ttf-course{display:flex;flex-wrap:wrap;align-items:center;gap:4px 8px;margin:6px 0 0 20px;font-size:12px;color:var(--text2)}
.ttf-course .ttf-sel{min-height:30px;max-width:220px;font-size:12px}
.ttf-course .ttf-in.sm{width:56px;min-height:30px}
.ttf-course small{flex-basis:100%}
/* Saved calculations: the one on show, and the way to keep, start again or bring one back. */
.ttf-sc{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:0 0 10px;padding-bottom:10px;border-bottom:1px solid var(--border)}
.ttf-sc-now{display:inline-flex;align-items:center;gap:6px;margin-right:auto;font-size:13px;color:var(--text)}
.ttf-sc-now svg{width:15px;height:15px;color:var(--gold2)}
.ttf-sc-now em{font-style:normal;color:var(--warn,#b45309);font-size:12px;font-weight:700}
/* The race schedule's notice: the flow on this device says something the
   programme does not. */
.ttf-nudge{display:flex;align-items:flex-start;justify-content:space-between;flex-wrap:wrap;gap:10px 16px;margin:0 0 12px;padding:12px 14px;
  border:1px solid var(--gold-border);border-left:4px solid var(--gold);border-radius:12px;background:var(--gold-bg);color:var(--text)}
.ttf-nudge-t{display:flex;gap:10px;min-width:0;flex:1 1 360px}
.ttf-nudge-t > svg{flex:none;width:18px;height:18px;margin-top:2px;color:var(--gold2)}
.ttf-nudge-t ul{margin:6px 0 4px;padding-left:18px;font-size:13px;line-height:1.5}
.ttf-nudge-t small{font-size:12px;color:var(--text3)}
.ttf-nudge-a{display:flex;gap:8px;flex-wrap:wrap}
.ttf-opts{display:flex;flex-wrap:wrap;align-items:center;gap:10px 18px;margin-top:10px;font-size:13px;color:var(--text2)}
.ttf-opts label{display:flex;align-items:center;gap:6px}
.ttf-note{font-size:12px;color:var(--text3)}
.ttf-main{display:grid;grid-template-columns:minmax(0,1.45fr) minmax(360px,1fr);gap:14px;align-items:stretch;height:clamp(560px,76vh,880px)}
/* The map with the player under it; beside them the race cards, which
   take all the height left, and the curve at the foot. */
.ttf-mapcol,.ttf-col{display:flex;flex-direction:column;gap:10px;min-width:0;min-height:0}
.ttf-mapcol .ttf-mapbox{flex:1 1 auto;min-height:300px}
.ttf-col .ttf-side{flex:1 1 auto;min-height:0;max-height:none}
.ttf-col .ttf-tl{flex:0 0 auto}
.ttf-mapcol .ttf-bar,.ttf-col .ttf-tl{margin:0}
.ttf-mapbox{position:relative;border-radius:14px;overflow:hidden;border:1px solid var(--border);min-height:460px;background:var(--bg3)}
.ttf-map{position:absolute;inset:0}
.ttf-legend{position:absolute;left:10px;bottom:10px;display:flex;flex-wrap:wrap;gap:6px 12px;max-width:calc(100% - 20px);padding:6px 10px;border-radius:10px;background:rgba(11,18,32,.78);color:#fff;font-size:12px;pointer-events:none}
.ttf-legend span{display:flex;align-items:center;gap:6px}
.ttf-legend i{width:10px;height:10px;border-radius:50%;border:1.5px solid #fff}
.ttf-legend i.ring{background:transparent;border:3px solid #f59e0b}
.ttf-side{display:flex;flex-direction:column;gap:10px;max-height:340px;overflow:auto}
.ttf-day-kpi{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.ttf-day-kpi > div,.ttf-kpis > div{background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:8px 10px}
.ttf-day-kpi b,.ttf-kpis b{display:block;font-size:20px;font-variant-numeric:tabular-nums;color:var(--bright,var(--text))}
.ttf-day-kpi small,.ttf-kpis small{font-size:11px;color:var(--text3);line-height:1.25;display:block}
.ttf-rc{border:1px solid var(--border);border-left:4px solid var(--rc);border-radius:12px;padding:10px 12px;background:var(--bg2)}
.ttf-rc-hd{display:flex;align-items:center;gap:8px;margin-bottom:8px}
.ttf-rc-hd > i{width:10px;height:10px;border-radius:50%;background:var(--rc)}
.ttf-rc-hd b{flex:1;min-width:0}
.ttf-kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;margin-bottom:8px}
.ttf-kpis b{font-size:16px}
.ttf-rc p{font-size:13px;color:var(--text2);line-height:1.45}
.ttf-pill{display:inline-block;font-size:11px;font-weight:800;padding:2px 8px;border-radius:999px;background:var(--bg3);color:var(--text2);white-space:nowrap}
.ttf-pill.ok{background:color-mix(in srgb,#16a34a 18%,transparent);color:#16a34a}
.ttf-pill.warn{background:color-mix(in srgb,#f59e0b 20%,transparent);color:#b45309}
.ttf-pill.bad{background:color-mix(in srgb,var(--red) 18%,transparent);color:var(--red)}
.ttf-bar{display:flex;align-items:center;flex-wrap:wrap;gap:10px;padding:10px 12px}
.ttf-clock{font-size:20px;font-variant-numeric:tabular-nums;min-width:96px}
.ttf-now{flex:1;min-width:200px;font-size:13px;color:var(--text2)}
.ttf-tl,.ttf-body{padding:12px 14px}
.ttf-tl-hd,.ttf-sec-hd{display:flex;align-items:baseline;flex-wrap:wrap;gap:6px 12px;margin-bottom:8px}
.ttf-tl-hd small,.ttf-sec-hd small{font-size:12px;color:var(--text3)}
.ttf-svg{display:block;width:100%;height:150px;cursor:crosshair}
.ttf-ladder{height:300px}
.ttf-grid{stroke:var(--border);stroke-width:1}
.ttf-ax{font-size:11px;fill:var(--text3)}
.ttf-cap{stroke:#f59e0b;stroke-width:1.5;stroke-dasharray:6 5}
.ttf-head{stroke:var(--gold);stroke-width:2}
rect.ttf-hbar{fill:var(--blue,#3b82f6)}
rect.ttf-hbar.hot{fill:#f59e0b;opacity:1}
.ttf-rl{fill:none;stroke-width:1.2;opacity:.75}
.ttf-rl.test{stroke-dasharray:3 3}
.ttf-tabs{display:flex;gap:6px;flex-wrap:wrap}
.ttf-tab{min-height:38px;padding:0 14px;border-radius:10px;border:1px solid var(--border2);background:var(--bg2);color:var(--text2);font-weight:700;cursor:pointer}
.ttf-tab.on{background:var(--bg4,var(--bg3));color:var(--text);border-color:var(--gold)}
.ttf-pass-scroll{max-height:420px;overflow:auto}
.ttf-pass tr{cursor:pointer}
.ttf-pass tr.slow td{background:color-mix(in srgb,#f59e0b 10%,transparent)}
.ttf-dot{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:6px;vertical-align:middle}
.ttf-advice{font-size:14px;margin:4px 0 10px;color:var(--text)}
.ttf-muted{font-size:12px;color:var(--text3);margin-top:8px}
.ttf-pop{display:flex;flex-direction:column;gap:3px;font-size:12px;color:#111}
.ttf-pop b{font-size:13px}
.ttf-pop .flag{width:16px;height:12px;vertical-align:-1px}
@media (max-width:900px){ .ttf-main{grid-template-columns:1fr;height:auto} .ttf-col .ttf-side{max-height:none} .ttf-side{max-height:none} .ttf-mapbox{min-height:340px} .ttf-kpis{grid-template-columns:repeat(2,1fr)} }
@media (max-width:520px){ .ttf-day-kpi{grid-template-columns:1fr 1fr 1fr} .ttf-day-kpi b{font-size:16px} .ttf-svg{height:120px} .ttf-ladder{height:240px} }
.ttf-h4{font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;color:var(--text3);margin:14px 0 4px}
.ttf-in.ttf-time{width:104px}
.ttf-on small.ttf-spd{color:var(--text2)}
.ttf-maptog{position:absolute;top:10px;right:10px;z-index:2;display:flex;align-items:center;gap:6px;min-height:36px;padding:0 12px;border-radius:10px;border:1px solid rgba(255,255,255,.25);background:rgba(11,18,32,.78);color:#fff;font-weight:700;font-size:13px;cursor:pointer}
.ttf-maptog svg{width:16px;height:16px}
.ttf-maptog.on{background:#dc2626;border-color:#dc2626}
.ttf-hl{display:inline-flex;align-items:center;flex-wrap:wrap;gap:4px 10px;font-size:12px}
.ttf-hl span{display:inline-flex;align-items:center;gap:5px}
.ttf-hl i{width:14px;height:8px;border-radius:2px;border:0 !important}
.ttf-hl small{color:inherit;opacity:.75}
.ttf-heat-words{font-size:13px;color:var(--text);margin:0 0 6px}
.ttf-heat{cursor:crosshair}
.ttf-grid-faint{stroke-opacity:.45}
.ttf-lapline{flex-basis:100%;display:flex;flex-direction:column;gap:4px}
/* The time line to drag, under the buttons: the two ends, and a mark at
   every start and every wave's gun. */
.ttf-scrub{flex-basis:100%;display:flex;align-items:center;gap:8px}
.ttf-scrub-t{font-size:11px;font-variant-numeric:tabular-nums;color:var(--text3);flex:none}
.ttf-scrub-track{position:relative;flex:1;min-width:0;padding-top:12px}
.ttf-scrub-track input{display:block;width:100%;margin:0;accent-color:var(--gold);cursor:pointer;height:22px}
.ttf-scrub-marks{position:absolute;left:8px;right:8px;top:0;height:12px;pointer-events:none}
.ttf-scrub-marks i{position:absolute;top:6px;width:2px;height:8px;margin-left:-1px;border-radius:1px}
.ttf-scrub-marks i b{position:absolute;bottom:7px;left:50%;transform:translateX(-50%);font-size:9px;font-weight:800;line-height:1;white-space:nowrap}
.ttf-scrub-marks i.peak{width:0;height:0;top:4px;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:7px solid #dc2626;border-radius:0;background:none}
.ttf-wrap.ttf-present .ttf-scrub-t{color:#cbd5e1}
/* The moments, top centre on the map while the presentation plays. */
.ttf-moments{position:absolute;top:12px;left:50%;transform:translateX(-50%);z-index:3;display:flex;flex-direction:column;align-items:center;gap:8px;pointer-events:none;width:max-content;max-width:calc(100% - 140px)}
.ttf-moment{display:flex;flex-direction:column;gap:2px;padding:10px 16px 10px 18px;border-radius:12px;background:rgba(255,255,255,.96);color:#0f172a;
  box-shadow:0 8px 24px rgba(2,6,15,.35);border-left:6px solid var(--mc,#f59e0b);animation:ttfMoment .35s ease-out}
.ttf-moment b{font-size:17px;font-weight:800;line-height:1.2}
.ttf-moment span{font-size:13px;color:#475569}
@keyframes ttfMoment{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
#ttf-rec.rec-on{background:#dc2626;border-color:#dc2626;color:#fff}
.ttf-lapline:empty{display:none}
.ttf-lapg{display:flex;align-items:center;flex-wrap:wrap;gap:4px 6px;font-size:12px;color:var(--text2)}
.ttf-lapg > i{width:10px;height:10px;border-radius:50%;flex:none}
.ttf-lapg > b{margin-right:4px;color:var(--text)}
.ttf-lapg em{font-style:normal;padding:2px 8px;border-radius:999px;background:var(--bg3);white-space:nowrap}
.ttf-lapg em.on{background:color-mix(in srgb,var(--gold) 22%,var(--bg3));color:var(--text)}
/* Which wave is going off — said before the laps, in the race's line. */
.ttf-lapg em.ttf-wave{font-weight:800;border:1px dashed var(--border2)}
.ttf-lapg em.ttf-wave.on{background:#16a34a;border-color:#16a34a;color:#fff}
.ttf-basemap{right:10px;top:10px}
.ttf-maptog{right:56px}
.ttf-in.ttf-time.moved{border-color:var(--gold);color:var(--gold)}
.ttf-moved{display:block;font-size:11px;color:var(--gold);margin-top:3px;white-space:nowrap}
.ttf-gone{display:block;font-size:11px;color:var(--red);margin-top:3px;max-width:260px;white-space:normal;font-weight:600}
/* Centred and lifted clear of the Mapbox mark and the (i) — Janny 8 Oct: "nu staat het Mapbox logo erover". */
.ttf-legend{left:50%;right:auto;transform:translateX(-50%);bottom:38px;justify-content:center;width:max-content;max-width:calc(100% - 24px)}
.ttf-grp{display:block;font-size:11px;color:var(--text3);margin-top:3px}
/* THE PRESENTER — as Golazo's flow: dark, full, the map takes what the
   play bar and the timeline leave; the desk work steps out. */
.ttf-exit{display:none}
.ttf-wrap.ttf-present{position:fixed;inset:0;z-index:1200;background:#0b1220;padding:12px;gap:8px;height:100vh;box-sizing:border-box;overflow:hidden;display:flex;flex-direction:column}
.ttf-wrap.ttf-present:fullscreen{width:100vw;height:100vh}
.ttf-wrap.ttf-present > :not(.ttf-main):not(.ttf-bar):not(.ttf-tl){display:none}
.ttf-wrap.ttf-present .ttf-main{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;gap:8px}
.ttf-wrap.ttf-present .ttf-main{height:auto}
.ttf-wrap.ttf-present .ttf-mapcol{flex:1 1 auto;gap:8px}
.ttf-wrap.ttf-present .ttf-col{flex:0 0 auto;gap:8px}
.ttf-wrap.ttf-present .ttf-side{display:none}
.ttf-wrap.ttf-present .ttf-mapbox{flex:1 1 auto;min-height:0;border-color:#1e293b}
.ttf-wrap.ttf-present .ttf-bar,.ttf-wrap.ttf-present .ttf-tl{background:#111827;border-color:#1e293b;color:#e2e8f0;flex:0 0 auto}
.ttf-wrap.ttf-present .ttf-tl{padding:6px 12px}
.ttf-wrap.ttf-present .ttf-tl .ttf-svg{height:96px}
.ttf-wrap.ttf-present .ttf-tl-hd{display:none}
.ttf-wrap.ttf-present .ttf-clock{font-size:30px;color:#f8fafc}
.ttf-wrap.ttf-present .ttf-now{color:#cbd5e1;font-size:15px}
.ttf-wrap.ttf-present .ttf-lapg{color:#cbd5e1;font-size:13px}
.ttf-wrap.ttf-present .ttf-lapg > b{color:#f8fafc}
.ttf-wrap.ttf-present .ttf-lapg em{background:#1e293b}
.ttf-wrap.ttf-present #ttf-present,.ttf-wrap.ttf-present #ttf-peak{display:none}
.ttf-wrap.ttf-present .ttf-exit{display:inline-flex}
.ttf-wrap.ttf-present .ttf-legend{font-size:14px}
body.ttf-presenting{overflow:hidden}
.ttf-on small.ttf-lapt{color:var(--text3);font-variant-numeric:tabular-nums}
/* The Cyclist flow on paper — in ink, never theme colours. */
.ttf-pdf{margin-left:auto}
.ttfp-doc{width:794px;background:#ffffff;color:#0f172a;padding:30px 40px 24px;font-size:11px;line-height:1.45;box-sizing:border-box}
.ttfp-doc *{box-sizing:border-box}
/* A top and bottom margin on every page, not only the first and last —
   same reason and same cure as the weather sheet's (see .wxdp-doc). */
@media print{
  .ttfp-doc{page:ttfp}
  @page ttfp{size:A4 portrait;margin:10mm 0}
  body.printing-sheet #print-root.pad:has(.ttfp-doc){padding-top:0;padding-bottom:0}
}
.ttfp-hd{display:flex;align-items:center;gap:16px;padding-bottom:10px;border-bottom:3px solid #0f172a;margin-bottom:10px}
.ttfp-hd-t{flex:1;min-width:0}
.ttfp-hd-t h1{margin:0;font-size:20px;font-weight:800;color:#0f172a;line-height:1.15}
.ttfp-hd-t p{margin:3px 0 0;font-size:11px;font-weight:700;color:#475569;text-transform:uppercase;letter-spacing:.05em}
.ttfp-logo{max-height:46px;max-width:220px;object-fit:contain}
.ttfp-sum{display:flex;flex-wrap:wrap;gap:6px 18px;font-size:11px;color:#334155;margin-bottom:12px}
.ttfp-sum b{color:#0f172a}
.ttfp-race{break-inside:avoid;page-break-inside:avoid;border:1px solid #cbd5e1;border-left:5px solid var(--rc,#0f172a);border-radius:6px;padding:10px 12px;margin-bottom:12px}
.ttfp-race h2{display:flex;align-items:center;gap:8px;margin:0 0 6px;font-size:14px;font-weight:800;color:#0f172a}
.ttfp-race h2 i{width:10px;height:10px;border-radius:50%;background:var(--rc,#0f172a)}
.ttfp-race h3{margin:10px 0 3px;font-size:9px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:#64748b}
.ttfp-facts{border-collapse:collapse;margin-bottom:6px}
.ttfp-facts th{text-align:left;font-weight:700;color:#64748b;padding:1px 12px 1px 0;white-space:nowrap;vertical-align:top}
.ttfp-facts td{color:#0f172a;padding:1px 0}
.ttfp-verdict{margin:4px 0;color:#334155}
.ttfp-advice{margin:6px 0;padding:6px 8px;background:#f1f5f9;border-radius:4px;color:#0f172a}
.ttfp-tbl{width:100%;border-collapse:collapse;font-size:10px}
.ttfp-tbl th{text-align:left;font-size:8.5px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;color:#64748b;border-bottom:1px solid #94a3b8;padding:3px 6px}
.ttfp-tbl td{border-bottom:1px solid #e2e8f0;padding:3px 6px;color:#0f172a;vertical-align:top}
.ttfp-tbl .num{text-align:right;font-variant-numeric:tabular-nums}
.ttfp-tbl tr.best td{background:#ecfdf5;font-weight:700}
.ttfp-tbl td.warn{color:#b45309;font-weight:700}
.ttfp-tbl td.bad{color:#b91c1c;font-weight:700}
.ttfp-tag{font-size:8px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;color:#475569;border:1px solid #cbd5e1;border-radius:999px;padding:0 5px}
.ttfp-tag.on{color:#047857;border-color:#047857}
.ttfp-list{margin:2px 0 0 16px;padding:0}
.ttfp-foot{margin-top:10px;font-size:9px;color:#64748b}
.ttfp-tbl td:first-child{white-space:nowrap}
.ttfp-heat{display:block;width:100%;height:auto;margin-top:4px}
.ttfp-doc .ttf-grid{stroke:#e2e8f0;stroke-width:1}
.ttfp-doc .ttf-grid-faint{stroke:#f1f5f9}
.ttfp-doc .ttf-ax{fill:#475569;font-size:11px}
.ttfp-race h2 small{margin-left:auto;font-size:10px;font-weight:700;color:#64748b}
.ttfp-dayheat{border-left-color:#0f172a}
/* The whole simulation on paper (ttfReportHtml in js/tt-flow.js): the
   map, the plan, the three charts, then the races. Ink, never theme. */
.ttfp-h{margin:14px 0 4px;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:#0f172a;break-after:avoid;page-break-after:avoid}
.ttfp-h small{margin-left:6px;font-size:9px;font-weight:600;text-transform:none;letter-spacing:0;color:#64748b}
.ttfp-svg{display:block;width:100%;height:auto;break-inside:avoid;page-break-inside:avoid}
.ttfp-doc .ttf-cap{stroke:#f59e0b;stroke-width:1.5;stroke-dasharray:6 5}
.ttfp-doc rect.ttf-hbar{fill:#2563eb}
.ttfp-doc rect.ttf-hbar.hot{fill:#f59e0b}
.ttfp-map{margin:0 0 10px;break-inside:avoid;page-break-inside:avoid}
.ttfp-map img{display:block;width:100%;height:auto;border:1px solid #cbd5e1;border-radius:6px}
.ttfp-map figcaption{margin-top:4px;font-size:9.5px;color:#475569}
.ttfp-map .ttfp-hl i{width:9px;height:9px;border-radius:50%;display:inline-block}
.ttfp-plan td{vertical-align:middle}
.ttfp-plan td:first-child i{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:5px;vertical-align:-1px}
.ttfp-plan td:first-child small{display:block;margin-left:14px;font-size:8.5px;color:#64748b}
.ttfp-plan td:first-child{white-space:normal;min-width:150px}
.ttfp-plan td:first-child small{white-space:nowrap}
.ttfp-plan td:first-child .ttfp-pill{margin-left:4px}
.ttfp-plan td:nth-child(2){min-width:96px}
.ttfp-plan td:nth-child(5){min-width:140px}
.ttfp-plan td:nth-child(6){min-width:92px}
.ttfp-pill{display:inline-block;font-size:8px;font-weight:800;text-transform:uppercase;letter-spacing:.03em;border-radius:999px;padding:1px 6px;white-space:nowrap;border:1px solid #cbd5e1;color:#475569}
.ttfp-pill.ok{color:#047857;border-color:#047857}
.ttfp-pill.warn{color:#b45309;border-color:#b45309}
.ttfp-pill.bad{color:#b91c1c;border-color:#b91c1c}
.ttf-wrap.ttf-present #ttf-report{display:none}
.ttfp-hl{display:inline-flex;align-items:center;flex-wrap:wrap;gap:4px 10px}
.ttfp-hl span{display:inline-flex;align-items:center;gap:4px}
.ttfp-hl i{width:14px;height:8px;border-radius:2px}
.ttfp-hl small{color:#64748b}
.ttf-sec-hd .ttf-pdf{margin-left:auto}

/* ── WEATHER FORECAST — js/weather-desk.js ── */
.wxd-wrap{display:flex;flex-direction:column;gap:14px;min-width:0}
.wxd-empty{padding:22px;color:var(--text2)}
.wxd-days{display:flex;gap:6px;flex-wrap:wrap}
.wxd-day{min-height:40px;padding:0 14px;border-radius:999px;border:1px solid var(--border2);background:var(--bg2);color:var(--text2);font-weight:700;cursor:pointer}
.wxd-day.on{background:var(--gold);border-color:var(--gold);color:#111}
.wxd-glance,.wxd-chart,.wxd-models,.wxd-tablecard,.wxd-mapcard,.wxd-outlook,.wxd-sources{padding:12px 14px}
.wxd-sec-hd{display:flex;align-items:baseline;flex-wrap:wrap;gap:6px 12px;margin-bottom:10px}
.wxd-sec-hd small{font-size:12px;color:var(--text3)}
.wxd-sec-hd > span:last-child{margin-left:auto}
.wxd-muted{font-size:12px;color:var(--text3);margin-top:8px}
.wxd-advice{font-size:14px;color:var(--text);margin:4px 0 10px}
.wxd-kpis{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:8px}
.wxd-kpis.sm{grid-template-columns:repeat(auto-fit,minmax(118px,1fr))}
.wxd-kpis > div{background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:8px 10px;min-width:0}
.wxd-kpis b{display:block;font-size:19px;font-variant-numeric:tabular-nums;color:var(--bright,var(--text))}
.wxd-kpis.sm b{font-size:16px}
.wxd-kpis small{display:block;font-size:11px;color:var(--text3);line-height:1.25}
.wxd-big{font-size:22px;line-height:1;margin-right:4px;float:right}
.wxd-arrow{display:inline-block;font-style:normal;font-weight:800;color:var(--blue,#3b82f6)}
.wxd-races{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:12px}
.wxd-race{padding:12px 14px}
.wxd-race-hd{display:flex;align-items:center;flex-wrap:wrap;gap:6px 10px;margin-bottom:8px}
.wxd-race-hd small{color:var(--text3);font-variant-numeric:tabular-nums}
.wxd-zone{margin-left:auto;font-size:11px;font-weight:800;padding:2px 8px;border-radius:999px;color:var(--z);border:1px solid var(--z)}
.wxd-race-p{font-size:13px;color:var(--text2);line-height:1.45;margin:8px 0 0}
.wxd-race-acts{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px}
.wxd-key{display:inline-flex;flex-wrap:wrap;align-items:center;gap:4px 10px;font-size:12px;color:var(--text2)}
.wxd-key i{display:inline-block;width:16px;height:4px;border-radius:2px;margin-right:2px}
.wxd-key i.t{background:#ef4444}.wxd-key i.f{background:#f97316;height:2px}.wxd-key i.r{background:#3b82f6;height:8px;width:8px}
.wxd-key i.p{background:rgba(59,130,246,.22);height:8px;width:10px}.wxd-key i.w{background:#14b8a6}.wxd-key i.g{background:#14b8a6;height:2px;opacity:.6}
.wxd-svg{display:block;max-width:100%;height:auto;cursor:crosshair}
.wxd-grid{stroke:var(--border);stroke-width:1}
.wxd-ax{font-size:11px;fill:var(--text3)}
.wxd-prob{fill:rgba(59,130,246,.09)}
.wxd-rain{fill:#3b82f6}
.wxd-temp{fill:none;stroke:#ef4444;stroke-width:2.5}
.wxd-feel{fill:none;stroke:#f97316;stroke-width:1.5;stroke-dasharray:5 4}
.wxd-tdot{fill:#ef4444}
.wxd-wind{fill:none;stroke:#14b8a6;stroke-width:2.5}
.wxd-gust{fill:none;stroke:#14b8a6;stroke-width:1.5;stroke-dasharray:3 3;opacity:.7}
.wxd-wdir{font-size:15px;font-weight:800;fill:#0d9488}
.wxd-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
.wxd-tbl{width:100%;border-collapse:collapse;font-size:13px}
.wxd-tbl th{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;color:var(--text3);text-align:left;padding:6px 8px;border-bottom:1px solid var(--border);white-space:nowrap}
.wxd-tbl td{padding:6px 8px;border-bottom:1px solid var(--border);white-space:nowrap}
.wxd-tbl .num{text-align:right;font-variant-numeric:tabular-nums}
.wxd-tbl td.wet{color:#3b82f6;font-weight:700}
.wxd-tbl tr.race td{background:color-mix(in srgb,var(--gold) 9%,transparent)}
.wxd-tbl th.wxd-mrace{color:var(--text);text-transform:none;font-size:12px;padding-top:12px}
.wxd-tablecard summary{cursor:pointer;font-weight:800;padding:2px 0;list-style-position:inside}
.wxd-tablecard[open] summary{margin-bottom:10px}
.wxd-mapbox{position:relative;border-radius:12px;overflow:hidden;border:1px solid var(--border);height:420px;background:var(--bg3)}
.wxd-mapbox.tall{height:480px}
.wxd-map{position:absolute;inset:0}
.wxd-legend{position:absolute;left:50%;transform:translateX(-50%);bottom:38px;display:flex;flex-wrap:wrap;gap:6px 14px;padding:6px 12px;border-radius:10px;background:rgba(11,18,32,.8);color:#fff;font-size:12px;pointer-events:none;width:max-content;max-width:calc(100% - 24px)}
.wxd-legend:empty{display:none}
.wxd-legend span{display:flex;align-items:center;gap:6px}
.wxd-legend i{width:16px;height:5px;border-radius:2px}
.wxd-windsum{font-size:13px;color:var(--text2);margin-top:8px}
#wxd-wind-ctl{display:inline-flex;align-items:center;gap:10px}
#wxd-wind-ctl input[type=range]{width:180px}
.wxd-sel{min-height:34px;padding:0 8px;border-radius:8px;border:1px solid var(--field-border,var(--border2));background:var(--bg3);color:var(--text);font:inherit}
.wxd-tabs{display:inline-flex;flex-wrap:wrap;gap:6px}
.wxd-tab{min-height:34px;padding:0 12px;border-radius:999px;border:1px solid var(--border2);background:var(--bg2);color:var(--text2);font-weight:700;font-size:12px;cursor:pointer}
.wxd-tab.on{background:var(--gold);border-color:var(--gold);color:#111}
.wxd-windy{position:relative;border-radius:12px;overflow:hidden;border:1px solid var(--border);height:640px;background:var(--bg3)}
.wxd-windy iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.wxd-strip{display:flex;gap:6px;min-width:max-content}
.wxd-col{display:flex;flex-direction:column;align-items:center;gap:2px;min-width:64px;padding:8px 6px;border-radius:10px;background:var(--bg2);border:1px solid var(--border);font-size:12px;color:var(--text2)}
.wxd-col b{font-size:16px;color:var(--text)}
.wxd-col small{font-size:11px;color:var(--text3)}
.wxd-col small.wet{color:#3b82f6}
.wxd-col .wxd-big{float:none;margin:2px 0}
.wxd-col.race{border-color:var(--gold);font-weight:800}
.wxd-col.norm{opacity:.7;border-style:dashed}
.wxd-src{margin:0 0 0 18px;padding:0;font-size:13px;color:var(--text2);line-height:1.6}
.wxd-src a{color:var(--gold2,var(--gold))}
@media (max-width:900px){ .wxd-kpis{grid-template-columns:repeat(3,minmax(0,1fr))} .wxd-mapbox{height:340px} .wxd-mapbox.tall{height:380px} .wxd-windy{height:420px} }
@media (max-width:520px){ .wxd-kpis,.wxd-kpis.sm{grid-template-columns:repeat(2,minmax(0,1fr))} .wxd-races{grid-template-columns:1fr} #wxd-wind-ctl input[type=range]{width:120px} }
/* The weather forecast on paper. The theme's tokens are redefined to ink
   inside the sheet, so the very pieces the tab draws print dark on white. */
.wxd-pdfs{display:inline-flex;gap:6px;margin-left:auto;flex-wrap:wrap}
/* The WhatsApp message to the teams: language, races, the text itself. */
.wxd-wa-langs{display:flex;gap:6px;flex-wrap:wrap;margin:0 0 10px}
#wxd-wa-races,#wxd-wa-linkslot{margin:0 0 10px}
#wxd-wa-linkbox{grid-template-columns:1fr}
.wxd-wa-mk{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.wxd-wa-mk small{color:var(--text3);font-size:12px;flex:1 1 220px}
.wxd-wa-text{width:100%;min-height:320px;background:var(--bg3);border:1px solid var(--field-border);border-radius:9px;color:var(--text);
  padding:10px 12px;font:13px/1.45 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;resize:vertical;box-sizing:border-box}
.wxd-wa-text:focus{border-color:var(--gold);outline:none}
@media (max-width:640px){ .wxd-wa-text{font-size:16px;min-height:260px} }
.wxdp-doc{--text:#0f172a;--text2:#334155;--text3:#64748b;--bright:#0f172a;--bg:#ffffff;--bg2:#ffffff;--bg3:#f8fafc;--bg4:#f1f5f9;
  --border:#e2e8f0;--border2:#cbd5e1;--gold:#b45309;--gold2:#92400e;--blue:#2563eb;--field-border:#cbd5e1;
  width:794px;background:#ffffff;color:#0f172a;padding:28px 36px 24px;font-size:11px;box-sizing:border-box;display:flex;flex-direction:column;gap:10px}
.wxdp-doc *{box-sizing:border-box}
.wxdp-doc .card{background:#ffffff;background-image:none;box-shadow:none;border:1px solid #cbd5e1;border-radius:8px;padding:10px 12px;break-inside:avoid;page-break-inside:avoid}
.wxdp-doc .wxd-kpis > div{background:#f8fafc;border-color:#e2e8f0;padding:6px 8px}
.wxdp-doc .wxd-kpis b{font-size:15px}
.wxdp-doc .wxd-kpis.sm b{font-size:13px}
.wxdp-doc .wxd-races{grid-template-columns:1fr 1fr;gap:8px}
.wxdp-doc .wxd-race{padding:8px 10px}
.wxdp-doc .wxd-race-acts{display:none}
.wxdp-doc .wxd-race-p{font-size:10.5px}
.wxdp-doc .wxd-svg{width:100%;height:auto;cursor:default}
.wxdp-doc .wxd-tbl{font-size:9.5px}
.wxdp-doc .wxd-tbl th{font-size:8px;padding:3px 4px}
.wxdp-doc .wxd-tbl td{padding:2px 4px}
.wxdp-doc .wxd-scroll{overflow:visible}
.wxdp-doc .wxd-strip{flex-wrap:wrap;min-width:0}
.wxdp-doc .wxd-col{min-width:56px;padding:5px 4px}
.wxdp-doc .wxd-src a{color:#0f172a}
.wxdp-day{display:flex;flex-direction:column;gap:10px}
.wxdp-break{page-break-before:always;break-before:page}
.wxdp-break2{display:flex;flex-direction:column;gap:10px;page-break-before:always;break-before:page}
/* Every page its own top and bottom margin. The print root's 6 mm only
   pads the start of the first page and the end of the last, because the
   shared @page has none — so page two began with a race card flush
   against the paper's edge. A named page gives this sheet margins of its
   own without touching the sheets that are built to fill A4 exactly. */
@media print{
  .wxdp-doc{page:wxdp}
  @page wxdp{size:A4 portrait;margin:10mm 0}
  body.printing-sheet #print-root.pad:has(.wxdp-doc){padding-top:0;padding-bottom:0}
}
.wxdp-hd{display:flex;align-items:center;gap:16px;padding-bottom:10px;border-bottom:3px solid #0f172a}
.wxdp-hd-t{flex:1;min-width:0}
.wxdp-hd-t h1{margin:0;font-size:20px;font-weight:800;color:#0f172a;line-height:1.15}
.wxdp-hd-t p{margin:3px 0 0;font-size:11px;font-weight:700;color:#475569;text-transform:uppercase;letter-spacing:.05em}
.wxdp-logo{max-height:46px;max-width:220px;object-fit:contain}
.wxd-chartwrap{position:relative}
.wxd-hover{stroke:var(--gold);stroke-width:1.5;stroke-dasharray:4 3}
.wxd-tip{position:absolute;top:26px;width:230px;z-index:3;display:flex;flex-direction:column;gap:3px;padding:10px 12px;border-radius:10px;background:var(--bg2);border:1px solid var(--border2);box-shadow:0 8px 24px rgba(0,0,0,.25);font-size:12px;color:var(--text2);pointer-events:none}
.wxd-tip[hidden]{display:none}
.wxd-tip b{color:var(--text)}
.wxd-tip > b:first-child{font-size:14px}
.wxd-tip small{color:var(--text3)}
.wxd-tip .wxd-tip-hint{margin-top:4px;font-style:italic}
/* On the high point: a block of its own inside the race card. */
.wxd-top{margin-top:10px;padding:10px;border-radius:10px;background:color-mix(in srgb,#60a5fa 9%,transparent);border:1px solid color-mix(in srgb,#60a5fa 35%,transparent)}
.wxd-top-hd{display:flex;align-items:center;flex-wrap:wrap;gap:4px 8px;margin-bottom:8px}
.wxd-top-hd svg{width:16px;height:16px;color:#60a5fa}
.wxd-top-hd small{color:var(--text3);font-size:11px}
.wxd-top-warn{margin:8px 0 0;font-size:12px;font-weight:700;color:#2563eb}
/* The race card: a verdict band, a bulletin block, dials, a time bar, lamps
   (Janny, 8 Oct 2026: "mix van B en F en D", "E ook nog"). */
.wxd-rc2{padding:0;overflow:hidden}
.wxd-rc2 > :not(.wxd-verdict):not(.wxd-bull){margin-left:12px;margin-right:12px}
.wxd-rc2 > .wxd-race-acts{margin-bottom:12px}
.wxd-verdict{display:flex;align-items:center;gap:8px;padding:9px 12px;font-size:13px;font-weight:700}
.wxd-verdict svg{width:16px;height:16px;flex:none}
.wxd-verdict.red{background:#FCEBEB;color:#791F1F}
.wxd-verdict.orange{background:#FAEEDA;color:#633806}
.wxd-verdict.green{background:#EAF3DE;color:#27500A}
.wxd-bull{display:grid;grid-template-columns:118px minmax(0,1fr);border-bottom:1px solid var(--border)}
.wxd-hero{color:#fff;padding:12px;display:flex;flex-direction:column;justify-content:center;gap:2px}
.wxd-hero-i{font-size:28px;line-height:1}
.wxd-hero-t{font-size:40px;font-weight:800;line-height:1.05;font-variant-numeric:tabular-nums}
.wxd-hero small{font-size:12px;opacity:.9}
.wxd-facts{padding:10px 12px;display:flex;flex-direction:column;gap:4px;font-size:12.5px;min-width:0}
.wxd-facts-n{font-size:14px;color:var(--text);margin-bottom:2px}
.wxd-facts div{display:flex;justify-content:space-between;gap:10px;border-bottom:1px solid var(--border);padding-bottom:4px}
.wxd-facts div:last-child{border-bottom:0}
.wxd-facts span{color:var(--text3)}
.wxd-facts b{color:var(--text);text-align:right;font-weight:700}
.wxd-dials{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;text-align:center;margin-top:12px}
.wxd-dials small{display:block;font-size:11px;color:var(--text3);line-height:1.25}
.wxd-dial{width:68px;height:68px}
.wxd-dial-bg{stroke:var(--border)}
.wxd-dial-v{font-size:13px;font-weight:800;fill:var(--text)}
.wxd-dial-s{font-size:9.5px;font-weight:700;fill:var(--text)}
.wxd-dial-n{font-size:8px;fill:var(--text3)}
.wxd-tbar{margin-top:12px;display:flex;flex-direction:column;gap:3px}
.wxd-tbar-row,.wxd-tbar-bar{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;text-align:center}
.wxd-tbar-row{font-size:11.5px;color:var(--text2)}
.wxd-tbar-row.t{font-weight:800;color:var(--text);font-size:12.5px}
.wxd-tbar-row.h{color:var(--text3);font-size:10.5px}
.wxd-tbar-bar{height:28px;border-radius:8px;overflow:hidden}
.wxd-tbar-bar span{display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:800}
.wxd-lamps{display:flex;flex-wrap:wrap;gap:6px 12px;margin-top:12px;padding-top:10px;border-top:1px solid var(--border)}
.wxd-lamp{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--text)}
.wxd-lamp i{width:11px;height:11px;border-radius:50%;flex:none}
.wxd-lamp small{color:var(--text3);font-size:11px}
.wxdp-doc .wxd-hero-t{font-size:30px}
.wxdp-doc .wxd-dial{width:54px;height:54px}
.wxdp-doc .wxd-bull{grid-template-columns:96px minmax(0,1fr)}
.wxd-temp-area{fill:#E24B4A;opacity:.12}
.wxd-wind-area{fill:#1D9E75;opacity:.1}
.wxd-temp{stroke-width:3;stroke-linecap:round}
.wxd-wind{stroke-width:3;stroke-linecap:round}
.wxd-prob{fill:rgba(55,138,221,.13)}
.wxd-rain{fill:#378ADD}
/* The animated weather map: the stage (the map, the colour, the wind)
   and its timeline under it; the whole stage goes full screen. */
.wxd-anim-stage{display:flex;flex-direction:column;gap:8px;background:var(--bg2)}
.wxd-anim-view{position:relative;height:520px;border-radius:12px;overflow:hidden;border:1px solid var(--border);background:#0b1220}
.wxd-anim-field,.wxd-anim-wind{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
.wxd-anim-layers{display:flex;flex-wrap:wrap;align-items:center;gap:8px 18px}
.wxd-anim-grp{display:inline-flex;flex-wrap:wrap;align-items:center;gap:6px}
.wxd-anim-grp>small{font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:var(--text3);margin-right:2px}
.wxd-anim-zoom{display:inline-flex;align-items:center;gap:6px;margin-left:auto}
.wxd-anim-zoom svg{width:14px;height:14px}
.wxd-anim-key{display:flex;flex-wrap:wrap;gap:4px 10px;margin-top:6px;padding-top:6px;border-top:1px solid rgba(255,255,255,.15)}
.wxd-anim-legend .wxd-anim-key span{margin:0;color:#e2e8f0;justify-content:flex-start;display:inline-flex;align-items:center;gap:5px}
.wxd-anim-legend .wxd-anim-key i{display:inline-block;width:14px;height:4px;border-radius:2px}
.wxd-anim-read{position:absolute;left:10px;bottom:30px;padding:8px 12px;border-radius:12px;background:rgba(11,18,32,.82);color:#fff;font-size:12px;pointer-events:none;max-width:calc(100% - 20px);backdrop-filter:blur(4px)}
.wxd-anim-read>b{font-size:26px;font-weight:800;letter-spacing:-.02em;font-variant-numeric:tabular-nums;margin-right:8px}
.wxd-anim-read>em{font-style:normal;font-weight:700;color:#fbbf24}
.wxd-anim-read>div{font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:#94a3b8;margin-top:2px}
.wxd-anim-read p,.wxd-anim-tip p{margin:2px 0 0;display:flex;flex-wrap:wrap;gap:4px 10px;font-variant-numeric:tabular-nums}
.wxd-anim-read p span:first-child{font-weight:800}
.wxd-anim-tip{position:absolute;padding:6px 10px;border-radius:10px;background:rgba(248,250,252,.95);color:#0b1220;font-size:12px;pointer-events:none;box-shadow:0 4px 14px rgba(0,0,0,.3);max-width:260px}
.wxd-anim-tip p{margin:0}
.wxd-anim-tip .wxd-arrow,.wxd-anim-read .wxd-arrow{display:inline-block;font-style:normal}
.wxd-anim-legend{position:absolute;right:10px;bottom:30px;padding:7px 10px;border-radius:10px;background:rgba(11,18,32,.82);color:#fff;font-size:11px;pointer-events:none;width:220px;max-width:calc(100% - 20px)}
.wxd-anim-legend b{display:block;font-weight:700;margin-bottom:4px}
.wxd-anim-legend i{display:block;height:8px;border-radius:4px}
.wxd-anim-legend span{display:flex;justify-content:space-between;margin-top:2px;color:#cbd5e1;font-variant-numeric:tabular-nums}
.wxd-anim-legend em{font-style:normal}
.wxd-anim-msg{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);padding:12px 16px;border-radius:12px;background:rgba(11,18,32,.88);color:#fff;font-size:13px;text-align:center;max-width:min(420px,calc(100% - 40px))}
.wxd-anim-bar{display:flex;align-items:center;gap:10px}
.wxd-anim-track{position:relative;flex:1;min-width:0;padding-top:12px;padding-bottom:12px}
.wxd-anim-track input{width:100%;margin:0;position:relative;z-index:1;background:transparent}
.wxd-anim-bands{position:absolute;inset:0;pointer-events:none}
.wxd-anim-bands i{position:absolute;top:4px;bottom:14px;border-radius:6px;background:rgba(245,158,11,.28);border:1px solid rgba(245,158,11,.6);pointer-events:auto}
.wxd-anim-bands em{position:absolute;bottom:-2px;transform:translateX(-50%);font-style:normal;font-size:10px;color:var(--text3);font-variant-numeric:tabular-nums}
.wxd-anim-clock{font-size:18px;font-weight:800;font-variant-numeric:tabular-nums;min-width:56px;text-align:right}
.wxd-anim-stage:fullscreen{padding:12px;background:#0b1220;color:#fff}
.wxd-anim-stage:fullscreen .wxd-anim-view{flex:1;height:auto}
.wxd-anim-stage:fullscreen .wxd-anim-bands em{color:#94a3b8}
@media (max-width:900px){ .wxd-anim-view{height:420px} .wxd-anim-legend{width:170px} .wxd-anim-read>b{font-size:20px} }
@media (max-width:560px){ .wxd-anim-view{height:380px} .wxd-anim-legend{top:10px;bottom:auto;right:10px;width:150px} .wxd-anim-zoom{margin-left:0} }
.wxd-anim-read .wxd-anim-storm,.wxd-anim-tip .wxd-anim-storm{color:#fbbf24;font-weight:800}
.wxd-anim-tip .wxd-anim-storm{color:#b45309}
/* The start's wet spells on the map's timeline; the heat layer's zones. */
.wxd-anim-bands .wxd-anim-wet{position:absolute;bottom:10px;height:4px;border-radius:2px;background:#3b82f6;opacity:.85;pointer-events:auto}
.wxd-anim-zones{display:flex;flex-direction:column;gap:3px}
.wxd-anim-legend .wxd-anim-zones span{display:flex;align-items:center;gap:6px;justify-content:flex-start;margin:0;color:#e2e8f0}
.wxd-anim-zones i{display:inline-block;width:14px;height:8px;border-radius:2px}
/* The lightning watch at the top of the weather tab. */
.wxd-bolt{display:flex;align-items:flex-start;gap:12px;padding:12px 14px;border-left:5px solid #94a3b8}
.wxd-bolt.red{border-left-color:#ef4444;background:rgba(239,68,68,.1)}
.wxd-bolt.amber{border-left-color:#f59e0b;background:rgba(245,158,11,.1)}
.wxd-bolt.near{border-left-color:#facc15}
.wxd-bolt.clear{border-left-color:#22c55e}
.wxd-bolt-l{flex:none;width:34px;height:34px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:18px;background:#94a3b8;color:#0b1220}
.wxd-bolt-l.red{background:#ef4444;color:#fff;animation:wxd-bolt-pulse 1.6s ease-in-out infinite}
.wxd-bolt-l.amber{background:#f59e0b}
.wxd-bolt-l.near{background:#facc15}
.wxd-bolt-l.clear{background:#22c55e;color:#fff}
.wxd-bolt b{display:block;font-size:15px}
.wxd-bolt p{margin:2px 0 0;font-size:13px;color:var(--text2)}
.wxd-bolt small{display:block;margin-top:4px;font-size:11px;color:var(--text3)}
@keyframes wxd-bolt-pulse{0%,100%{box-shadow:0 0 0 0 rgba(239,68,68,.5)}50%{box-shadow:0 0 0 8px rgba(239,68,68,0)}}
@media (prefers-reduced-motion:reduce){.wxd-bolt-l.red{animation:none}}
/* The dark hours on the map's timeline, sunrise and sunset. */
.wxd-anim-bands .wxd-anim-night{position:absolute;top:2px;bottom:12px;background:rgba(15,23,42,.35);border-radius:4px;text-decoration:none}
.wxd-anim-bands .wxd-anim-sun{position:absolute;top:-12px;transform:translateX(-50%);font-size:10px;color:var(--text3);text-decoration:none;white-space:nowrap}
.wxd-anim-read .wxd-anim-dark{font-style:normal;margin-left:8px;color:#a5b4fc;font-size:11px}
.wxd-anim-track{padding-top:16px}
/* The 3D button on the weather map. */
.wxd-anim-3d{display:inline-flex;align-items:center;gap:6px}
.wxd-anim-3d svg{width:14px;height:14px}
.wxd-anim-3d.on{background:#f8fafc;color:#0b1220;border-color:#f8fafc}
.wxd-anim-legend .wxd-anim-boltkey{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:50%;background:radial-gradient(circle,rgb(192,38,211) 0,rgb(88,28,135) 70%);color:#fff;font-size:10px;line-height:1}
/* THE RACE CARDS ON ONE LINE — Janny, 9 Oct 2026: "kunnen we zien dat
   alles altijd op dezelfde lijn staat?". Every card is eight blocks (the
   band, the bulletin, the dials, the time bar, the lamps, the lines, the
   summit, the buttons) and takes its rows from the grid they share, so
   a two-line warning in one card lowers the bulletin in all of them. */
@supports (grid-template-rows: subgrid) {
  .wxd-races > .wxd-rc2{display:grid;grid-row:span 8;grid-template-rows:subgrid;row-gap:0;align-content:start}
  .wxd-races > .wxd-rc2 > .wxd-verdict{align-items:flex-start}
  .wxd-races > .wxd-rc2 > .wxd-race-p:empty, .wxd-races > .wxd-rc2 > .wxd-top-slot:empty{margin:0}
  .wxd-races > .wxd-rc2 > .wxd-race-acts{align-self:end}
}

/* NOW LIVE on the weather map — js/weather-desk.js (Janny, 9 Oct 2026:
   "een NOW LIVE button … wat weer het is in Kisumu"). A red dot that
   beats while the map follows the place's clock; the satellite and radar
   pictures on a line of their own, opened by one button. */
.wxd-anim-now{display:inline-flex;align-items:center;gap:7px;font-weight:800;letter-spacing:.03em}
.wxd-anim-now .wxd-now-dot{width:9px;height:9px;border-radius:50%;background:#ef4444;box-shadow:0 0 0 0 rgba(239,68,68,.6);flex:none}
.wxd-anim-now.on{background:#dc2626;border-color:#dc2626;color:#fff}
.wxd-anim-now.on .wxd-now-dot{background:#fff}
.wxd-anim-now.following .wxd-now-dot{animation:wxd-now-beat 1.6s ease-out infinite}
@keyframes wxd-now-beat{0%{box-shadow:0 0 0 0 rgba(255,255,255,.75)}70%{box-shadow:0 0 0 7px rgba(255,255,255,0)}100%{box-shadow:0 0 0 0 rgba(255,255,255,0)}}
@media (prefers-reduced-motion: reduce){ .wxd-anim-now.following .wxd-now-dot{animation:none} }
.wxd-anim-satbtn{display:inline-flex;align-items:center;gap:6px}
.wxd-anim-satbtn svg{width:15px;height:15px}
.wxd-anim-satbtn .wxd-anim-caret{font-size:10px;opacity:.7}
.wxd-anim-sats{flex-basis:100%}
.wxd-anim-read .wxd-anim-livetag{display:inline-flex;align-items:center;gap:6px;font-style:normal;font-weight:800;font-size:11px;letter-spacing:.06em;color:#fecaca;background:rgba(220,38,38,.35);border:1px solid rgba(248,113,113,.6);border-radius:999px;padding:2px 9px;margin-right:8px;vertical-align:4px}
.wxd-anim-read .wxd-anim-livetag i{width:7px;height:7px;border-radius:50%;background:#ef4444}
.wxd-anim-read .wxd-anim-livetag.off{color:#cbd5e1;background:rgba(148,163,184,.2);border-color:rgba(148,163,184,.45)}
.wxd-anim-bands .wxd-anim-nowmark{position:absolute;top:2px;bottom:2px;width:2px;margin-left:-1px;background:#ef4444;border-radius:2px;text-decoration:none;box-shadow:0 0 0 1px rgba(11,18,32,.5);z-index:2}
.wxd-anim-clock.live{color:#ef4444}
/* the route kept for the course film — js/tracker.js (10 Oct 2026) */
.tk-trail{display:flex;align-items:flex-start;gap:8px;margin-top:10px;font-size:12.5px;color:var(--text2);cursor:pointer}
.tk-trail input{margin-top:2px;flex:none}
