/* ═══════════════════════════════════════════════════════════
   CAC SPORT — course map view
   ═══════════════════════════════════════════════════════════ */

/* Two columns and two rows: the course list on the left running the full
   height of both, the map above and its elevation profile directly under it
   on the right.

   The profile belongs in that column and nowhere else. Hovering it walks a
   marker along the road on the map above — with the profile below the fold,
   the marker it moves was always the one thing scrolled off the top.

   The whole block ends where the window does, and the map row takes whatever
   the profile leaves. --map-top is how far down the page the block starts,
   measured by syncMapHeight() rather than hard-coded: this was a flat 200 px
   and the real header is nearer 118, so the profile hung 80 px below the fold
   on every screen — the exact thing the layout exists to prevent. The header
   also wraps at some widths and loses a subtitle in one language, so there is
   no constant to be right about.

   Below `minmax`'s floor the block outgrows the window and the page scrolls,
   which is honest, rather than squeezing the map into a letterbox. */
.map-layout{display:grid;grid-template-columns:300px 1fr;grid-template-rows:minmax(280px,1fr) auto;
  gap:14px;height:calc(100vh - var(--map-top,200px) - 18px);min-height:560px}
@supports (height:100dvh){
  .map-layout{height:calc(100dvh - var(--map-top,200px) - 18px)}
}
/* THE PLANNER IS THE MAP, so it takes the whole pane. Its own height
   rather than the --map-top arithmetic above: that measures how far down
   the page the block starts, and syncMapHeight() only ever measures the
   course map's copy — the planner was left on the 200px fallback and so
   ran short of the fold whatever was above it. With no heading left there
   is nothing to measure around. Doubled class because the @supports block
   below restates .map-layout and would otherwise win. */
/* THE PLANNER'S MARKUP ENDS AT ITS LAYOUT — nothing follows it — so it can
   take the pane whole and stop the pane scrolling. */
body.planner-view #content{padding:10px 12px 12px;overflow:hidden}
body.planner-view #v-planner{height:100%}
.map-layout.pl-layout{height:100%;min-height:0}

/* THE COURSE MAP CANNOT, AND THIS IS WHY THE VIDEO WENT MISSING. That view
   holds the layout AND the recce video card after it. Giving it 100% of a
   pane with overflow:hidden made the map exactly one screen and put the
   video below the cut with no way to scroll to it — a section deleted by a
   stylesheet.

   So this screen takes back only its padding. The map's height stays the
   --map-top arithmetic on .map-layout, which measures how far down the page
   the block starts and is kept fresh by syncMapHeight() — and with the
   heading gone that measurement is simply smaller, which IS the taller map
   that was wanted. The video scrolls up underneath it, as it always did. */
body.mapfull-view #content{padding:10px 12px 24px}
.map-layout > .map-panel{grid-column:1;grid-row:1 / -1}
.map-layout > .map-shell{grid-column:2;grid-row:1}
.map-layout > .elev-card{grid-column:2;grid-row:2;margin-top:0}

/* ── TRACK PANEL ───────────────────────────────────────────── */
/* ONE SCROLL SURFACE, NOT THREE. The panel used to hide its overflow
   and hand each list its own scrollbar, so the courses took the room
   and the waypoints underneath were squeezed into a two-line window —
   forty-six of them behind a 30 px slot. The panel scrolls as a whole
   now and every list sizes to its content. */
.map-panel{background:var(--bg2);border:1px solid var(--border);border-radius:var(--radius);
  display:flex;flex-direction:column;overflow-y:auto;overflow-x:hidden;box-shadow:var(--shadow)}
.mp-hd{padding:14px 16px;border-bottom:1px solid var(--border);
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  position:sticky;top:0;z-index:2;background:var(--bg2)}
body.light .mp-hd{background:#fff}
/* the sub-headings ride along under the first one */
.mp-hd-sub{position:sticky;top:0;z-index:1}
.mp-hd h3{font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;color:var(--text)}
/* THE FOLD IS ON EVERY SCREEN. A list folded on a phone stays folded
   (remembered per browser), and a fold whose button only a phone could
   see left a desktop with a heading, a count and no courses. */
.mp-fold{display:inline-flex;align-items:center;flex-shrink:0;min-height:30px;padding:0 11px;border-radius:8px;
  border:1px solid var(--border2);background:var(--bg3);color:var(--text2);
  font-family:inherit;font-size:11px;font-weight:800;text-transform:uppercase;
  letter-spacing:.05em;cursor:pointer}
.mp-fold:hover{color:var(--text);border-color:var(--gold2)}
.map-panel.tracks-off .mp-tracks{display:none}
/* The import stays when the list folds: adding a course is not the same
   question as seeing the ones already there. */
.mp-list{flex:0 0 auto;overflow:visible;padding:8px}
/* The course list sizes to its own content so every imported track is
   visible at a glance; the waypoint list underneath takes whatever is left
   and is the one that scrolls. */
.mp-tracks{flex:0 1 auto}
.mp-hd-sub{border-top:1px solid var(--border)}
/* The panel's two verbs, under each other at the top — see renderMap().
   Full width like the import card above it, so the pair reads as one
   block rather than a button loose beside a list. */
.mp-foot{padding:10px 12px;border-top:1px solid var(--border);background:var(--bg2)}
body.light .mp-foot{background:#fff}
.mp-foot .btn{width:100%;justify-content:center}

/* THE SAME CARD AS #app-busy. A dashed box says "drop here", which is
   true on a desktop and meaningless on a phone; a solid card with the
   mark in a ring says "this is where a course comes in" on both, and it
   is the shape the overlay wears while the terrain model is being read.
   The ring stays put — it only turns once there is work to show. */
.drop-zone{display:flex;align-items:center;gap:14px;margin:10px;padding:14px 16px;
  border:1px solid var(--border2);border-radius:16px;background:var(--bg2);color:var(--text2);
  text-align:left;cursor:pointer;box-shadow:var(--shadow-md);
  transition:border-color .18s,background .18s,color .18s}
body.light .drop-zone{background:#fff}
.drop-zone:hover,.drop-zone.drag{border-color:var(--gold);background:var(--gold-bg);color:var(--gold2)}
body.light .drop-zone:hover,body.light .drop-zone.drag{color:var(--gold)}
.dz-mark{width:38px;height:38px;flex:none;display:flex;align-items:center;justify-content:center;
  border-radius:50%;color:var(--primary,#f59e0b);
  border:2px solid color-mix(in srgb,var(--primary,#f59e0b) 30%,transparent)}
.drop-zone:hover .dz-mark,.drop-zone.drag .dz-mark{color:inherit;border-color:currentColor}
.drop-zone svg{width:20px;height:20px;margin:0}
.dz-body{min-width:0}
.drop-zone .dz-title{display:block;font-size:13px;font-weight:700;color:var(--text);margin-bottom:2px}
.drop-zone .dz-hint{display:block;font-size:11px;line-height:1.4}

.trk{display:flex;align-items:flex-start;gap:10px;padding:11px 12px;border-radius:9px;cursor:pointer;
  transition:background .16s;margin-bottom:2px;border:1px solid transparent}
.trk:hover{background:var(--bg3)}
.trk.active{background:var(--gold-bg);border-color:var(--gold-border)}
.trk-sw{width:5px;align-self:stretch;min-height:34px;border-radius:3px;background:var(--tc,#f59e0b);flex-shrink:0}
.trk-body{flex:1;min-width:0;position:relative}
/* The card's own two, in the card's own corner — see the note in
   trackListHtml(). The name keeps clear of them rather than wrapping
   under them, which is what a long course name would otherwise do. */
.trk-corner{position:absolute;top:0;right:0;display:flex;gap:6px}
.trk-name{font-size:13px;font-weight:700;color:var(--text);line-height:1.35;word-break:break-word;
  padding-right:72px}
.trk-corner:empty + .trk-name{padding-right:0}
.trk-meta{font-size:11px;color:var(--text2);margin-top:2px;font-variant-numeric:tabular-nums}
.trk-cats{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}
.trk-actions{display:flex;align-items:center;flex-wrap:wrap;gap:6px;margin-top:8px}
.trk-vis{width:30px;height:30px;border-radius:7px;border:1px solid var(--border);background:var(--bg3);
  display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text2);flex-shrink:0}
.trk-vis:hover{border-color:var(--border2);color:var(--text)}
.trk-vis svg{width:14px;height:14px}
.trk.hidden-track .trk-body{opacity:.42}

/* ── ADD WAYPOINT ACTIVE MODE & POI LIST ───────────────────── */
.btn.adding-mode {
  background: var(--gold) !important;
  color: #0b1120 !important;
  border-color: var(--gold2) !important;
  animation: pulse-border 1.8s infinite;
  box-shadow: 0 0 12px rgba(245,158,11,0.5) !important;
}
/* ── PULSING MAP MARKERS ───────────────────────────────────────
   Never animate `transform` on a Mapbox marker element. Mapbox positions
   its markers by writing `transform: translate(...)` inline on that same
   element, and a running animation on transform beats an inline style —
   so the marker sits at the canvas origin and pulses away in the top-left
   corner of the map, wherever it was actually told to go. That is what
   both of these did while they borrowed the badge animations, which scale.
   The glow here is a box-shadow and nothing else. */
@keyframes marker-pulse{
  0%  {box-shadow:0 0 0 0    var(--mk),0 0 14px var(--mk)}
  70% {box-shadow:0 0 0 11px rgba(0,0,0,0),0 0 14px var(--mk)}
  100%{box-shadow:0 0 0 0    rgba(0,0,0,0),0 0 14px var(--mk)}
}
.map-dot{border-radius:50%;border:3px solid #fff;cursor:pointer;
  animation:marker-pulse 1.5s infinite}
.map-dot.scrub{width:18px;height:18px;background:var(--gold,#f59e0b);--mk:rgba(245,158,11,.8)}
.map-dot.peloton{width:22px;height:22px;background:#f43f5e;--mk:rgba(244,63,94,.8)}

@keyframes pulse-border {
  0% { box-shadow: 0 0 0 0 rgba(245,158,11,0.7); }
  70% { box-shadow: 0 0 0 8px rgba(245,158,11,0); }
  100% { box-shadow: 0 0 0 0 rgba(245,158,11,0); }
}

.poi-item {
  transition: background .16s, border-color .16s;
}
.poi-item:hover {
  background: var(--bg3);
}

/* ── PICKING WAYPOINTS OFF THE LIST ────────────────────────────
   The tick and the bar it reports to. Deliberately quiet: the row is read
   far more often than it is picked, so the box sits at the same weight as
   the icon beside it and the delete button is absent until something is
   ticked. */
.poi-pick{flex-shrink:0;width:14px;height:14px;margin:0 2px 0 0;accent-color:var(--gold2);cursor:pointer}
.poi-selbar{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap;
  padding:4px 6px 6px;margin-bottom:2px;border-bottom:1px dashed var(--border)}
.poi-selall{display:flex;align-items:center;gap:6px;font-size:10.5px;font-weight:700;
  letter-spacing:.03em;text-transform:uppercase;color:var(--text3);cursor:pointer;min-width:0}
.poi-selall input{width:14px;height:14px;margin:0;accent-color:var(--gold2);cursor:pointer}
.poi-seldel{font-size:11px;padding:3px 9px}
.poi-seldel[hidden]{display:none}
.poi-seldel b{font-variant-numeric:tabular-nums}

/* ── MAP CANVAS ────────────────────────────────────────────── */
.map-shell{position:relative;border-radius:var(--radius);overflow:hidden;border:1px solid var(--border);
  background:var(--bg3);box-shadow:var(--shadow);width:100%;height:100%;
  /* No floor of its own: the grid row it sits in carries the minimum, and a
     500 px floor here pushed the row past the viewport once the profile was
     stacked under it. The stacked phone layout sets its own height. */
  min-height:0}
#cacMap{position:absolute;inset:0;width:100%;height:100%}
.map-fallback{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:10px;color:var(--text2);font-size:14px;text-align:center;padding:24px}
.map-fallback svg{width:34px;height:34px;color:var(--text3)}

.map-tools{position:absolute;top:12px;right:12px;z-index:6;display:flex;gap:8px;
  align-items:center;justify-content:flex-end;flex-wrap:wrap;max-width:calc(100% - 24px)}
.style-tabs{display:flex;background:rgba(8,12,24,.86);backdrop-filter:blur(10px);
  border:1px solid rgba(148,163,184,.28);border-radius:9px;padding:3px;gap:2px}
.style-tab{min-height:36px;padding:0 11px;border-radius:7px;border:none;background:none;cursor:pointer;
  font-family:inherit;font-size:11px;font-weight:700;color:rgba(232,238,252,.65);transition:all .16s}
.style-tab.active{background:linear-gradient(135deg,var(--gold),var(--gold2));color:#0b1120}
.style-tab:hover:not(.active){background:rgba(255,255,255,.1);color:#fff}

/* ── THE MAP TOOLBAR AND ITS MENUS ─────────────────────────────
   Five square icon buttons, each opening its own small menu: settings,
   basemap, overlapping courses, wind, weather. Square and unlabelled
   because this row is on top of the map — the labelled version was most
   of the width of the road on a phone, and one button hiding all five
   decisions put three unrelated things on screen at once. The name lives
   on the title and the aria-label. */
.map-tool-btn{display:inline-flex;align-items:center;justify-content:center;
  width:36px;height:36px;flex-shrink:0;
  border-radius:9px;border:1px solid rgba(148,163,184,.28);background:rgba(8,12,24,.86);
  backdrop-filter:blur(10px);color:rgba(232,238,252,.9);cursor:pointer;
  transition:background .16s,color .16s,border-color .16s}
.map-tool-btn svg{width:16px;height:16px}
.map-tool-btn:hover{background:rgba(20,28,48,.94);color:#fff}
.map-tool-btn.open{background:linear-gradient(135deg,var(--gold),var(--gold2));
  color:#0b1120;border-color:var(--gold2)}
/* ONE DRESS FOR EVERY FLOATING CONTROL ON EVERY MAP. Mapbox's own stack
   answers the theme — navy in the dark one, white in the light one,
   see the .mapboxgl-ctrl-group rules further down — while this row stayed
   dark in both. On a light screen that put two different sets of buttons
   a finger apart on the same canvas. The class is shared, so this is the
   course map, the route planner, the medical map, the dashboard's mini-map
   and the race card all at once.

   Excludes `.open` and `.is-on`, because those two states are the accent
   and this rule would otherwise outrank them on specificity and paint the
   button of an open menu white like all the rest. */
body.light .map-tool-btn:not(.open):not(.is-on){background:rgba(255,255,255,.96);
  border-color:rgba(15,23,42,.14);color:#0f172a;
  box-shadow:0 1px 4px rgba(15,23,42,.16)}
body.light .map-tool-btn:not(.open):not(.is-on):hover{background:#fff;
  border-color:rgba(15,23,42,.3);color:#0b1120}

/* `right` is set inline when a menu opens, so it hangs under its own
   button instead of always under the end of the row. */
.map-pop{position:absolute;top:56px;right:12px;z-index:7;width:236px;
  max-width:calc(100vw - 24px);
  background:rgba(8,12,24,.94);backdrop-filter:blur(14px);border:1px solid rgba(148,163,184,.28);
  border-radius:12px;padding:12px;display:flex;flex-direction:column;gap:12px;
  box-shadow:0 12px 30px rgba(0,0,0,.45)}
.map-pop[hidden]{display:none}
.mo-group{display:flex;flex-direction:column;gap:6px}
.mo-label{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;
  color:rgba(232,238,252,.55)}
/* ── THE BASEMAPS, ONE UNDER THE OTHER ──────────────────────
   Seven basemaps wrapped across a 236 px menu came out as two and a
   half ragged rows of half-words. A menu is a list: one row each, full
   width, the chosen one marked — which is also what makes it usable
   with a thumb on a phone. */
.map-pop .style-tabs{flex-direction:column;flex-wrap:nowrap;gap:2px;
  background:rgba(148,163,184,.12);border-color:rgba(148,163,184,.2)}
.map-pop .style-tabs .style-tab{width:100%;text-align:left;padding:7px 10px;
  border-radius:7px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.map-pop .style-tab{flex:1 1 auto;min-height:32px;padding:0 9px}
.map-pop .mo-btn{width:100%;justify-content:flex-start;gap:7px;height:34px;
  font-size:11px;padding:0 10px;border-radius:8px;cursor:pointer}
.mo-hint{font-size:10.5px;line-height:1.45;color:rgba(232,238,252,.5);margin:0}
.map-pop .mo-warn{color:#fbbf24}

/* A toggle that is on says so by filling, not by a colour typed into a
   style attribute in the handler — which is how the old pair of weather
   buttons did it, and why they forgot their state whenever the markup
   was rebuilt. */
.map-pop .mo-toggle{background:rgba(148,163,184,.12);border:1px solid rgba(148,163,184,.24);
  color:rgba(232,238,252,.82)}
.map-pop .mo-toggle svg{width:14px;height:14px;flex-shrink:0}
.map-pop .mo-toggle:hover{background:rgba(148,163,184,.2);color:#fff}
.map-pop .mo-toggle.on{background:linear-gradient(135deg,var(--gold),var(--gold2));
  color:#0b1120;border-color:var(--gold2)}

/* Bottom centre by default. The bottom-left corner belongs to Mapbox's scale
   bar and the bottom-right to the attribution, so the legend sat on top of one
   or the other wherever it was cornered. */
.map-legend{position:absolute;bottom:12px;left:50%;transform:translateX(-50%);z-index:5;
  background:rgba(8,12,24,.86);backdrop-filter:blur(10px);border:1px solid rgba(148,163,184,.28);
  border-radius:10px;padding:6px 10px;font-size:11px;color:rgba(232,238,252,.85);
  max-width:min(260px,calc(100% - 100px))}
.map-legend .ml-title{display:flex;align-items:center;justify-content:center;gap:6px;cursor:pointer;list-style:none;
  font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;opacity:.75;
  padding:2px 0;white-space:nowrap}
.map-legend .ml-title::-webkit-details-marker{display:none}
.map-legend .ml-title svg{width:13px;height:13px;flex-shrink:0}
.map-legend .ml-title::after{content:'▾';font-size:9px;opacity:.7;margin-left:2px;transition:transform .16s}
.map-legend[open] .ml-title::after{transform:rotate(180deg)}
.map-legend .ml-body{margin-top:6px;padding-bottom:2px;max-height:34vh;overflow-y:auto}
.map-legend .ml-row{display:flex;align-items:center;gap:8px;margin-top:4px}
.map-legend .ml-row:first-child{margin-top:0}
.map-legend .ml-sw{width:16px;height:3px;border-radius:2px;flex-shrink:0}
.map-legend .ml-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ── DASHBOARD MINI-MAP ────────────────────────────────────── */
.mini-map-shell{position:relative;min-height:580px;border-radius:10px;overflow:hidden;
  border:1px solid var(--border);background:var(--bg3)}
.mini-map-shell #dashMap{position:absolute;inset:0}
.mini-map-shell .map-legend{bottom:10px;max-width:min(260px,calc(100% - 100px))}
/* Desktop: out of the bottom of the map and into the free top-left corner.
   Centred along the bottom edge it sat over the course itself — which on
   this map is usually the finish, the part being looked at. The corner is
   free here because this map's zoom and fullscreen controls are top-right;
   the course map's are top-left, so that one keeps the legend at the bottom. */
@media (min-width:641px){
  .mini-map-shell .map-legend{top:10px;left:10px;bottom:auto;transform:none}
}
@media (max-width:1100px){ .mini-map-shell{min-height:480px} }
/* On a phone this was a 300 px letterbox — a course drawn inside it was
   a squiggle rather than a route. Tied to the viewport so it fills a
   real part of the screen on a tall phone without swallowing a short
   one, and capped so it never runs past the card it sits in. */
@media (max-width:640px){ .mini-map-shell{min-height:clamp(340px,56vh,520px)} }

/* ── THE DASHBOARD TOOL ROW, FOLDED ────────────────────────────
   Seven icons across the top of that map reached corner to corner on a
   phone. Here they live behind one button and slide out to its left;
   on a desktop the row is simply always out and the button is absent. */
.dash-tools-items{display:flex;align-items:center;gap:6px}
.dash-tools-toggle{display:none}
@media (max-width:640px){
  .dash-map-tools{flex-wrap:nowrap}
  .dash-map-tools .dash-tools-toggle{display:inline-flex}
  .dash-map-tools .dash-tools-items{max-width:0;opacity:0;pointer-events:none;
    overflow:hidden;flex-wrap:nowrap;
    transition:max-width .3s ease,opacity .2s ease}
  .dash-map-tools.open .dash-tools-items{max-width:calc(100vw - 96px);opacity:1;pointer-events:auto}
}

/* ── ELEVATION PROFILE ─────────────────────────────────────── */
/* "Scanned 28 Aug 14:12" under a course in the track list. Quiet: it is
   a state, not an action — the buttons beside it are the actions. */
.trk-scan{display:flex;align-items:center;gap:5px;margin-top:5px;
  font-size:10.5px;font-weight:700;color:var(--ok,#22c55e)}
.trk-scan svg{width:12px;height:12px;flex-shrink:0}
.trk-scan span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.elev-card{margin-top:14px}
/* The scrubbable profile with its scales: altitudes down the left, kilometres
   along the bottom, the drawing itself in the cell between them. A grid rather
   than padding, so the marks under the plot line up with the plot at every
   width — the same arrangement the schedule card uses. */
.elev-wrap{position:relative;height:130px;cursor:crosshair;touch-action:none;
  display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-rows:1fr auto;column-gap:8px}
.elev-canvas{grid-column:2;grid-row:1;min-width:0;min-height:0;position:relative}
.elev-wrap svg{width:100%;height:100%;display:block;overflow:visible}
/* Altitudes ON their own gridlines rather than at the two ends of a
   flex column — see the same move on .rp-yax, and drawElevationPanel()
   for where the numbers come from. */
.elev-yax{grid-column:1;grid-row:1;position:relative;min-width:36px;
  font-size:10px;font-weight:700;color:var(--text3);
  font-variant-numeric:tabular-nums;white-space:nowrap;text-align:right}
.elev-ytick{position:absolute;right:0;transform:translateY(-50%)}
.elev-xax{grid-column:2;grid-row:2;position:relative;height:15px;margin-top:4px;
  font-size:10px;font-weight:700;color:var(--text3);font-variant-numeric:tabular-nums}
.elev-tick{position:absolute;top:0;white-space:nowrap}
.elev-tick-end{font-weight:800;color:var(--text2)}
.elev-tick-zero{color:#f59e0b}
@media (max-width:520px){
  /* Half the marks: at this width the numbers run into each other.
     Which half is decided where they are made. */
  .elev-tick.alt{display:none}
}
.elev-grid{stroke:var(--border);stroke-width:1}
/* Fill and stroke are set per SVG, not here. Several profiles share a page
   and each carries its course's colour on the path itself; a declaration in
   CSS beats a presentation attribute, so anything set here would repaint
   every profile in one colour and undo the point of drawing them per race. */
.elev-area{stroke:none}
.elev-line{fill:none;stroke-width:2;stroke-linejoin:round}
.elev-lbl{font-size:10px;fill:var(--text3);font-weight:700}
.elev-stats{display:flex;flex-wrap:wrap;gap:20px;margin-top:12px;padding-top:12px;border-top:1px solid var(--border)}
.elev-stat dt{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--text3)}
.elev-stat dd{font-size:16px;font-weight:700;color:var(--text);font-variant-numeric:tabular-nums;margin-top:2px}

/* ── RACE PROFILE BLOCK ───────────────────────────────────────
   The same picture wherever it appears — schedule card, map view,
   share link, printed booklet. Static: no scrubber, no listeners. */
.rp-block{margin-top:14px;padding-top:12px;border-top:1px solid var(--border)}
.rp-hd{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px;margin-bottom:8px}
.rp-hd strong{font-size:13.5px;font-weight:800;color:var(--text)}
.rp-hd span{font-size:11.5px;color:var(--text3)}
.rp-svg{width:100%;height:84px;display:block;overflow:visible}
/* Altitudes down the left, kilometres along the bottom, both outside the
   drawing. The y labels are a column of their own so the plot and the km
   marks under it start at the same x — a padding guess would drift. */
.rp-plot{display:grid;grid-template-columns:auto minmax(0,1fr);column-gap:8px;align-items:stretch}
/* The altitudes stand ON their own gridlines rather than at the top and
   bottom of a flex column: two numbers said how tall the picture was
   and nothing about the hill in the middle of it. */
/* ── ROOM FOR A SECOND ROW OF SIGNS ───────────────────────────
   --rp-sky is empty space over the top of the picture, set on .rp-plot
   by elevProfileFigure() and only when two waypoints land close enough
   to stand on each other. It is added as PADDING above the drawing
   rather than as more headroom inside it: .rp-svg is drawn at the
   height fixed below and its viewBox is stretched to fill that, so a
   wider band would have flattened the hill to make room for the signs
   instead of making the strip taller. Nothing here moves when it is 0,
   which is every profile that has never had two signs in one place.

   The altitudes gutter takes the same distance as a MARGIN. It is a
   stretched grid item, so a margin shortens it by exactly what the
   canvas gained — and its numbers, which are placed as percentages of
   their own box, stay level with the lines they name. Padding here
   instead would have left the box the taller one and walked every
   altitude down the page. */
.rp-yax{position:relative;min-width:34px;margin-top:var(--rp-sky,0px);
  font-size:9.5px;font-weight:700;color:var(--text3);
  font-variant-numeric:tabular-nums;white-space:nowrap;text-align:right}
.rp-ytick{position:absolute;right:0;transform:translateY(-50%)}
.rp-canvas{min-width:0;position:relative;padding-top:var(--rp-sky,0px)}

/* ── THE NEUTRALISED START, ON THE PICTURE ──────────────────
   Left of the flag the race has not begun: the ground is shaded, the
   flag itself is a rule, and the roadbook's own 0 km sign stands on it.
   From there the kilometre marks count from zero — see
   elevProfileFigure() in js/elevation.js. */
.elev-neutral{fill:currentColor;opacity:.12}
/* A relay's two legs under the hill, and the changeover between them. */
.elev-leg{opacity:.16}
.elev-leg-rule{stroke:#0f172a;stroke-width:2;stroke-dasharray:4 3;fill:none;opacity:.7}
body.light .elev-leg-rule{stroke:#0f172a}
.elev-leg-lbl{position:absolute;top:3px;transform:translateX(-50%);pointer-events:none;
  font-size:9.5px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;line-height:1;
  padding:2px 6px;border-radius:999px;background:var(--c);color:#0f172a;white-space:nowrap}
.elev-zero{stroke:#f59e0b;stroke-width:2;stroke-dasharray:4 3;fill:none}
/* The two ends, hard against the two ends — see the note in
   elevProfileFigure(). Not centred on the edge, which would hang half
   of each sign off the picture.

   THEY STAND IN THE SKY AND POINT DOWN, the way the waypoint signs do:
   on the line a 19-pixel disc covers the first and last kilometres,
   which is the stretch a finger is on when somebody asks about the
   finish. Anchored top AND bottom so the dotted leader simply fills
   whatever is left under the sign — the same trick .rp-mark uses, and
   for the same reason: a stem of a fixed length stops in mid-air and
   leaves the eye to guess the rest of the drop. */
.rp-end{position:absolute;top:1px;bottom:0;pointer-events:none;line-height:0;z-index:2;
  display:flex;flex-direction:column;align-items:center}
/* CENTRED ON THE EDGE, not tucked inside it. Anchored, the start stood
   ten pixels into the race and the finish nine short of it, and the
   dotted leader landed there with them — a quarter of a kilometre out
   on a 20 km sheet, in the two places a race map has to be exact. Half
   of each sign hangs outside the plot now: on the left into the 34 px
   altitude gutter, on the right into the 14 px of padding the profile
   band already carries, and every container between here and the sheet
   is overflow:visible. */
.rp-end.start{left:0;transform:translateX(-50%)}
.rp-end.finish{right:0;transform:translateX(50%)}
/* The blow-up panel is 46 px tall with no sky to stand in: there the
   sign is pinned to the ceiling and carries no stem at all. */
.rp-end.top{bottom:auto;top:0;display:block}
.rp-end img{display:block;width:19px;height:19px;order:1;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.45))}
/* On a blow-up panel the picture is 46 px tall and the sign is 19, so
   it is drawn smaller there rather than covering a third of the road. */
.cp-zoom .rp-end img{width:15px;height:15px}
.rp-km0{position:absolute;top:1px;bottom:0;transform:translateX(-50%);
  pointer-events:none;line-height:0;display:flex;flex-direction:column;align-items:center}
.rp-km0 img{display:block;width:19px;height:19px;order:1;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.45))}
/* ── THE LEADER UNDER A SIGN ──────────────────────────────────
   Dotted rather than solid, and the same dotted line under all three
   kinds of sign — a waypoint, the two ends, and the roadbook's own 0 km.
   A solid hairline reads as part of the drawing, which on a picture
   whose only other vertical lines are the kilometre guides is one line
   too many; a dotted one reads as a pointer, which is what it is.

   Drawn as a repeating gradient rather than a dashed border because a
   1-pixel column with a border on it renders as a smear at print
   resolution, and these sheets are photographed at three times size. */
.rp-mark > i, .rp-end > i, .rp-km0 > i{display:block;width:1px;flex:1 1 auto;min-height:14px;
  order:2;opacity:.45;
  background-image:repeating-linear-gradient(to bottom,
    currentColor 0 2px, transparent 2px 5px);
  background-repeat:repeat-y;background-size:1px 5px}
/* The blow-up panel keeps its sign inside the picture: it is 46 px tall
   and less than a third of the sheet wide, and half a disc hanging off
   the side of a panel that small reads as a mistake rather than as a
   mark on the road. */
.rp-end.top.start,.rp-end.top.finish{transform:none}
.rp-tick-zero{color:#f59e0b}
.rp-tick-off{display:none}
/* A profile that follows the course on the map above it is something
   you point at, so it says so. Only where one is wired up — see
   wireProfileScrub(); a profile in a share with no map beside it is
   still just a picture. */
.rp-plot[data-scrub-wired] .rp-canvas{cursor:crosshair}
.rp-xax{grid-column:2;position:relative;height:14px;margin-top:3px;
  font-size:9.5px;font-weight:700;color:var(--text3);font-variant-numeric:tabular-nums}
.rp-tick{position:absolute;top:0;white-space:nowrap}
.rp-tick-end{font-weight:800;color:var(--text2)}
.elev-grid.vg{opacity:.5}
.elev-grid.hg{opacity:.75}
@media (max-width:420px){
  /* Half the marks: the strip is a third of the width here and the
     numbers run into each other. Which half is decided where they are
     made — see elevProfileFigure(). */
  .rp-tick.alt{display:none}
}
@media (max-width:520px){
  /* Shorter on a phone: the plot is a third of the width it has on a laptop,
     so the same height turns every rise into a spike. */
  .rp-svg{height:66px}
}
.rp-stats{display:flex;flex-wrap:wrap;gap:16px;margin-top:8px}
.rp-stat dt{font-size:9.5px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;color:var(--text3)}
.rp-stat dd{font-size:13.5px;font-weight:700;color:var(--text);
  font-variant-numeric:tabular-nums;margin-top:1px}

/* ── MAPBOX POPUP THEMING ──────────────────────────────────── */
.mapboxgl-popup-content{background:var(--bg2)!important;color:var(--text)!important;
  border:1px solid var(--border2);border-radius:10px!important;padding:12px 14px!important;
  box-shadow:var(--shadow-md)!important;font-family:'Inter',sans-serif}
.mapboxgl-popup-tip{border-top-color:var(--bg2)!important;border-bottom-color:var(--bg2)!important}
.mapboxgl-popup-close-button{color:var(--text2)!important;font-size:18px!important;padding:4px 8px!important}
.mp-pop-t{font-size:13px;font-weight:700;margin-bottom:4px}
.mp-pop-m{font-size:11px;color:var(--text2);font-variant-numeric:tabular-nums}
/* Zoom / compass / fullscreen. Mapbox ships these glyphs as dark-on-light
   background images, so dark mode inverts them. Light mode must then also
   drop the dark plate — inverting the icon back without restoring the plate
   left dark arrows on a dark square, i.e. invisible buttons. */
.mapboxgl-ctrl-group{background:rgba(8,12,24,.86)!important;border:1px solid rgba(148,163,184,.28)!important}
.mapboxgl-ctrl-group button+button{border-top-color:rgba(148,163,184,.22)!important}
.mapboxgl-ctrl-group button .mapboxgl-ctrl-icon{filter:invert(1) brightness(1.6)}
.mapboxgl-ctrl-group button:hover{background-color:rgba(255,255,255,.12)!important}

body.light .mapboxgl-ctrl-group{background:rgba(255,255,255,.96)!important;
  border-color:rgba(15,23,42,.16)!important;box-shadow:0 2px 8px rgba(15,23,42,.14)!important}
body.light .mapboxgl-ctrl-group button+button{border-top-color:rgba(15,23,42,.12)!important}
body.light .mapboxgl-ctrl-group button .mapboxgl-ctrl-icon{filter:none}
body.light .mapboxgl-ctrl-group button:hover{background-color:rgba(15,23,42,.06)!important}
body.light .mapboxgl-ctrl-group button:disabled .mapboxgl-ctrl-icon{opacity:.3}

/* The 3D corner button: an inline SVG rather than Mapbox's own
   background-image icon convention, so it needs its own color rule
   instead of the invert-filter above. Thinner stroke and a smaller
   glyph than ico()'s default 16px/2px — next to the hairline zoom and
   locate icons a 3D cube at full weight read as the boldest thing on
   the map. Dimmed until switched on, same as the toolbar's own toggles. */
.map-3d-btn{width:29px;height:29px;display:flex;align-items:center;justify-content:center;
  background:transparent;border:0;padding:0;cursor:pointer;color:#e2e8f0;opacity:.68}
/* Drawn at the size Mapbox's own zoom and locate glyphs are drawn at —
   at 14 px it was the one small icon in a stack of full-sized ones. */
.map-3d-btn svg{width:19px;height:19px;stroke-width:1.8}
.map-3d-btn:hover{opacity:.9}
.map-3d-btn.on{color:#59ef83;opacity:1}
/* The basemap button lives in the same stack and wears the same dress;
   `open` is its "this menu is showing" state. */
.map-corner-btn.open{color:#59ef83;opacity:1}
body.light .map-corner-btn.open{color:#16a34a}
body.light .map-3d-btn{color:#334155}
body.light .map-3d-btn.on{color:#16a34a}

/* ── ACCREDITATION PIN ─────────────────────────────────────────
   A real dropped pin: the teardrop's tip is the coordinate, so the marker
   is anchored 'bottom'. 30px rotated 45° reaches ~37px tall, which is why
   the wrapper is that height and not 30. */
.acc-pin{position:relative;width:32px;height:37px;cursor:pointer}
.acc-pin .acc-pin-head{position:absolute;top:0;left:1px;width:30px;height:30px;
  border-radius:50% 50% 50% 0;transform:rotate(-45deg);
  background:linear-gradient(135deg,#fbbf24,#d97706);border:2.5px solid #fff;
  box-shadow:0 4px 12px rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;
  transition:transform .16s}
.acc-pin:hover .acc-pin-head{transform:rotate(-45deg) scale(1.1)}
.acc-pin .acc-pin-head svg{width:15px;height:15px;color:#1a1204;transform:rotate(45deg)}

/* start / finish markers */
.trk-pin{width:26px;height:26px;border-radius:50%;border:2px solid #fff;display:flex;align-items:center;
  justify-content:center;font-size:11px;font-weight:800;color:#0b1120;box-shadow:0 2px 8px rgba(0,0,0,.5);cursor:pointer}
.trk-pin.start{background:#34d399}
.trk-pin.finish{background:#f87171}
/* The official 0 km: the roadbook's own sign rather than a lettered
   dot, because that is the drawing everybody in the convoy already
   reads. No chip behind it — the sign has its own white ground. */
/* The changeover of a relay: the two colours meeting in one dot, the
   kilometre beside it. */
.rm-relay-pin{display:flex;align-items:center;gap:6px;pointer-events:none}
.rm-relay-dot{width:16px;height:16px;border-radius:50%;flex-shrink:0;border:2px solid #fff;
  background:linear-gradient(90deg,var(--m) 50%,var(--w) 50%);box-shadow:0 1px 4px rgba(0,0,0,.45)}
.rm-relay-pin b{font-size:10.5px;font-weight:800;color:#0f172a;background:rgba(255,255,255,.92);
  padding:2px 7px;border-radius:999px;white-space:nowrap;box-shadow:0 1px 4px rgba(0,0,0,.3)}
.rm-km0-pin{line-height:0;cursor:default;
  filter:drop-shadow(0 2px 5px rgba(0,0,0,.5))}
.rm-km0-pin img{display:block;width:30px;height:30px}

@media (max-width:900px){
  /* Stacked: map, then list, then profile, each taking its own height.
     THE MAP GOES FIRST. Beside each other the list is a column and the
     map is the page; stacked, the list is ten rows of names and an
     import box between the heading and the one thing this screen is
     opened for. The map is what you came for — the courses are what you
     scroll to afterwards. */
  .map-layout{grid-template-columns:1fr;grid-template-rows:auto;min-height:0;height:auto}
  /* Stacked, the planner scrolls like every other screen: a full-height
     grid here would put the panel below the fold with no way down. */
  .map-layout.pl-layout{height:auto}
  body.planner-view #content,body.mapfull-view #content,
  body.print-view #content{padding:12px 14px 40px;overflow-y:auto}
  body.planner-view #v-planner{height:auto}
  .map-layout > .map-panel,.map-layout > .map-shell,.map-layout > .elev-card{grid-column:1;grid-row:auto}
  .map-layout > .map-shell{order:1}
  .map-layout > .map-panel{order:2;margin-top:14px}
  .map-layout > .elev-card{order:3;margin-top:0}
  .map-shell{height:60vh;min-height:340px}

  /* The panel is the whole screen here, so it is sized by what is in it
     rather than capped at a height the list then has to fight for. */
  .map-panel{max-height:none}
  .mp-fold{display:inline-flex;align-items:center}

  /* Import, compacted to one line. It was a 120 px dashed box holding a
     drop target and a hint about dragging files — neither of which is a
     thing anyone does on a phone, where it is a browse button — and it sat
     between the heading and the courses, pushing all ten off the screen. */
  .drop-zone{margin:8px;padding:9px 12px;justify-content:center;gap:10px;border-radius:13px}
  .dz-mark{width:28px;height:28px;border-width:2px}
  .drop-zone svg{width:16px;height:16px;margin:0;flex-shrink:0}
  .drop-zone .dz-title{font-size:12px;margin:0}
  .drop-zone .dz-hint{display:none}

  /* And the courses get a real window of their own, scrolling inside it. */
  .mp-tracks{flex:0 1 auto;max-height:44vh;min-height:132px}
  #poi-list{max-height:30vh}
  /* SCROLLING INSIDE IT, as said: .mp-list is overflow:visible everywhere
     else, so a capped list spilled its courses over the waypoints under
     it — the two read through each other on a phone and on the map link
     (Janny, 26 Sep 2026). */
  .mp-tracks,#poi-list{overflow-y:auto;overscroll-behavior:contain}
}
/* The course map's own fold. Six of the eight icons live in .mt-items;
   on a phone that box shuts to nothing and slides back out to the left
   of the ⋮ beside it. Desktop draws them all and hides the toggle. */
.mt-items{display:flex;align-items:center;gap:8px}
.mt-toggle{display:none}
@media (max-width:640px){
  /* Mapbox puts zoom and fullscreen at the top *left* of the course map, so
     the tools stay hard right — moving them left ran them over the +/− stack.
     Even hard right, eight icons and a plus reached across the canvas and
     landed on that stack anyway; hence the fold. */
  .course-map-tools .mt-toggle{display:inline-flex}
  .course-map-tools .mt-items{max-width:0;opacity:0;pointer-events:none;overflow:hidden;
    gap:5px;flex-wrap:nowrap;transition:max-width .3s ease,opacity .2s ease}
  /* OPEN, THE DRAWER TAKES A ROW OF ITS OWN. Squeezed onto the same line
     as the three that never fold plus the round +, the six of them had
     about 150 px between them: the row shrank, `overflow:hidden` cut the
     last one down the middle, and a button half drawn is a button
     nobody presses. `order` keeps the permanent three on top and drops
     the drawer underneath them, which is also the direction it slid
     out from. */
  .course-map-tools.open{flex-wrap:wrap;justify-content:flex-end}
  .course-map-tools.open .mt-items{flex:1 1 100%;max-width:100%;order:1;
    flex-wrap:wrap;justify-content:flex-end;opacity:1;pointer-events:auto}
  .map-tools{top:12px;right:12px;left:auto;justify-content:flex-end;flex-wrap:nowrap}
  /* Five icons and the add-waypoint button have to share one row here, so
     the icons tighten rather than wrap onto the course. */
  .map-tool-btn{width:32px;height:32px;border-radius:8px}
  .map-tool-btn svg{width:15px;height:15px}
  .map-pop{width:min(236px,calc(100vw - 24px));top:54px}
  .map-legend{bottom:10px;max-width:calc(100% - 90px)}
  .map-legend .ml-body{max-height:28vh}
}

/* ═══════════ COURSE VIDEO ═══════════
   The recce lap, under the elevation profile. 16:9 and fluid: on a
   phone it is the width of the screen, on a desktop it stops before
   it turns into a cinema. */
.video-card{margin-top:16px}
.vc-hd{display:flex;justify-content:space-between;align-items:flex-start;gap:10px;
  flex-wrap:wrap;margin-bottom:12px}
.vc-hd h3{display:flex;align-items:center;gap:8px}
.vc-hd .c-sub{margin:3px 0 0}
/* One block per video: name, line of context, player.
   Placed 2 per row on tablet/desktop, stacked on mobile. */
.vc-list{display:grid;grid-template-columns:1fr;gap:20px}
@media (min-width: 640px){
  .vc-list{grid-template-columns:repeat(2, 1fr)}
}
.vc-item{display:flex;flex-direction:column;background:var(--bg3);border:1px solid var(--border);
  border-radius:12px;padding:16px;height:100%}
.vc-item-hd{display:flex;justify-content:space-between;align-items:flex-start;
  gap:10px;margin-bottom:12px}
.vc-item-txt strong{display:block;font-size:14.5px;font-weight:800;color:var(--text)}
.vc-item-txt p{margin:3px 0 0;font-size:12.5px;line-height:1.5;color:var(--text2)}
/* Which course the film was shot on — only on a share link, where the
   card carries every film the event has. See showCourseVideo(). */
.vc-item-txt p.vc-where{display:flex;align-items:center;gap:6px;margin-top:5px;
  font-size:12px;font-weight:700;color:var(--gold2)}
.vc-item-txt p.vc-where svg{width:14px;height:14px;flex-shrink:0}
.vc-item-act{display:flex;gap:6px;flex-shrink:0}

.vc-frame{position:relative;width:100%;aspect-ratio:16/9;
  border-radius:10px;overflow:hidden;background:#000;border:1px solid var(--border)}
.vc-frame iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.vc-open{display:inline-flex;align-items:center;gap:7px;margin-top:auto;padding-top:10px;font-size:12.5px;
  font-weight:700;color:var(--gold2);text-decoration:none;align-self:flex-start}
.vc-open:hover{text-decoration:underline}
.vc-open svg{width:15px;height:15px}

/* ── SIDE PANEL FOLD ─────────────────────────────────────────
   The layout is a grid with a fixed 300 px first track, so folding is a
   change to the TRACK, not to the panel's width — width:0 on a grid item
   leaves the 300 px column standing empty behind it.

   Folded it becomes a 46 px rail rather than nothing, so it is visible that
   there is a panel there and what it holds. */
.map-layout{position:relative;transition:grid-template-columns .22s}
.map-layout.panel-off{grid-template-columns:46px 1fr}
.map-layout.panel-off .map-panel{border-width:0;opacity:0;pointer-events:none}
.map-layout.panel-off .map-panel-toggle{display:none}
.map-panel{transition:opacity .18s}

/* Halfway down the seam, not at its head: the planner's top corners are
   full of map tools a tab would sit under, and a control that means the
   same thing on both screens should be in the same place on both. The
   planner's pair (.pl-panel-toggle below) wears this exact dress. */
.map-panel-toggle{position:absolute;top:50%;transform:translateY(-50%);left:300px;z-index:8;
  width:22px;height:52px;
  border:1px solid var(--border2);border-left:0;border-radius:0 8px 8px 0;
  background:var(--bg2);color:var(--green);cursor:pointer;font-size:15px;font-weight:800;
  font-family:inherit;line-height:1;padding:0;transition:left .22s,background .16s,color .16s}
.map-panel-toggle:hover{background:var(--green);color:var(--on-accent)}
body.light .map-panel-toggle{background:#fff}
body.light .map-panel-toggle:hover{background:var(--green);color:var(--on-accent)}

.map-rail{position:absolute;left:0;top:0;bottom:0;width:46px;z-index:8;display:none;
  flex-direction:column;align-items:center;gap:8px;padding:10px 0;
  background:var(--bg2);border:1px solid var(--border);border-radius:var(--radius);
  box-shadow:var(--shadow)}
body.light .map-rail{background:#fff}
.map-layout.panel-off .map-rail{display:flex}
.rail-btn{width:34px;height:34px;border-radius:9px;border:1px solid var(--border);
  background:var(--bg3);color:var(--text2);cursor:pointer;display:flex;align-items:center;
  justify-content:center;font-family:inherit;font-size:15px;font-weight:800;line-height:1;padding:0}
.rail-btn:hover{border-color:var(--gold-border);color:var(--gold2)}
.rail-btn svg{width:16px;height:16px}
.rail-count{margin-top:auto;font-size:11px;font-weight:800;color:var(--text3);
  font-variant-numeric:tabular-nums}

/* ── THE COURSE MAP, MIRRORED ──────────────────────────────────
   The track list to the right, the map's own tools to the left. The map
   is what this screen is for and it now opens at the left edge, where a
   European eye starts reading — and the tools sit over the corner of it
   that is furthest from the list they act on, instead of tucked under it.

   Scoped to #v-map on purpose. The route planner mounts the same
   .map-layout and is NOT mirrored: there the panel is the drawing form,
   the thing you work down while the map answers, and a form belongs on
   the side you start from. Two screens that look alike are not the same
   screen. Say the word and the planner follows.

   Every rule here is id-scoped, which outranks the .map-layout rules
   above and the ones in the stacked breakpoint below — so that
   breakpoint gets its own mirror-off block rather than being quietly
   overridden into a broken two-column phone layout. */
#v-map .map-layout{grid-template-columns:1fr 300px}
#v-map .map-layout > .map-panel{grid-column:2;grid-row:1 / -1}
#v-map .map-layout > .map-shell{grid-column:1;grid-row:1}
#v-map .map-layout > .elev-card{grid-column:1;grid-row:2}
#v-map .map-layout.panel-off{grid-template-columns:1fr 46px}
/* The seam furniture flips with the seam: the tab hangs off the panel's
   left edge now, so its open side, its missing border and its corners
   all swap over. */
#v-map .map-panel-toggle{left:auto;right:300px;
  border-left:1px solid var(--border2);border-right:0;
  border-radius:8px 0 0 8px;
  transition:right .22s,background .16s,color .16s}
#v-map .map-rail{left:auto;right:0}
#v-map .course-map-tools{left:12px;right:auto;justify-content:flex-start}
#v-map .course-map-tools.open{justify-content:flex-start}
#v-map .course-map-tools.open .mt-items{justify-content:flex-start}
/* And the menus follow the buttons. openMapPop() sets the exact offset
   inline once it knows which icon was pressed; this is the side they
   start on, so a menu never opens against the far edge first. */
#v-map #map-pop{left:12px;right:auto}

@media (max-width:900px){
  /* Stacked layout: the panel sits above the map, so a seam arrow has no seam. */
  .map-panel-toggle,.map-rail{display:none}
  .map-layout.panel-off{grid-template-columns:1fr}
  .map-layout.panel-off .map-panel{border-width:1px;opacity:1;pointer-events:auto}
  .map-layout.panel-off .map-rail{display:none}
  /* THE MIRROR COMES OFF HERE. Stacked, there is no left and right to
     swap — one column, map first — and the id-scoped rules above would
     otherwise hold a 1fr/300px grid on a phone. */
  #v-map .map-layout,#v-map .map-layout.panel-off{grid-template-columns:1fr}
  #v-map .map-layout > .map-panel,
  #v-map .map-layout > .map-shell,
  #v-map .map-layout > .elev-card{grid-column:1;grid-row:auto}
}

/* ── THE DASHBOARD'S PROFILE ───────────────────────────────────
   Under the mini-map, inside the same card: one course at a time, with
   the others a press away. No panel of its own — on the dashboard this
   is a glance, not a workbench. */
.dash-elev{margin-top:14px;padding-top:12px;border-top:1px solid var(--border)}
.dash-elev .elev-wrap{height:104px}
.dash-elev .elev-stats{gap:16px;margin-top:10px;padding-top:10px}
.dash-elev .c-sub{margin:8px 0 2px}
.dash-elev-chips{display:flex;flex-wrap:wrap;gap:7px}
.dash-trk-chip{display:inline-flex;align-items:center;gap:6px;padding:5px 11px;
  border-radius:999px;border:1px solid var(--border2);background:var(--bg3);
  color:var(--text2);font-size:12px;font-weight:700;cursor:pointer;line-height:1.3;
  max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dash-trk-chip::before{content:"";width:8px;height:8px;border-radius:50%;
  background:var(--c,var(--gold2));flex-shrink:0}
.dash-trk-chip:hover{color:var(--text);border-color:var(--c,var(--gold2))}
.dash-trk-chip.on{color:var(--text);border-color:var(--c,var(--gold2));
  background:color-mix(in srgb,var(--c,#f59e0b) 14%,transparent)}
@media (max-width:640px){
  .dash-elev .elev-wrap{height:86px}
  .dash-elev .elev-stats{gap:12px}
}

/* ── WAYPOINTS UNDER THEIR COURSE ──────────────────────────────
   Indented and hung off the course above by a rule down the left, so a
   glance down the panel reads courses first and their waypoints as
   detail — rather than one flat hundred-row list where every row had to
   name its own course. */
.trk-pois{margin:-2px 0 8px 14px;padding-left:10px;
  border-left:2px solid var(--border2);display:flex;flex-direction:column;gap:2px}
.trk-pois-hd{display:flex;align-items:center;gap:6px;padding:6px 6px 4px;
  font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;
  color:var(--text3);cursor:pointer;user-select:none;border-radius:5px;
  transition:background .15s ease, color .15s ease}
.trk-pois-hd:hover{color:var(--text);background:var(--bg3)}
.trk-pois-hd svg{width:11px;height:11px;flex-shrink:0}
.trk-pois-hd b{margin-left:auto;font-variant-numeric:tabular-nums;color:var(--text2)}
.trk-pois-hd .trk-pois-toggle{display:inline-flex;align-items:center;justify-content:center;
  margin-left:4px;color:var(--text3);transition:transform .2s ease}
.trk-pois-hd .trk-pois-toggle svg{width:12px;height:12px}
.trk-vis-poi{display:inline-flex;align-items:center;justify-content:center;
  width:20px;height:20px;border-radius:4px;border:none;background:none;
  color:var(--text3);cursor:pointer;margin-left:4px;padding:0;
  transition:color .15s ease, background .15s ease}
.trk-vis-poi:hover{color:var(--text);background:var(--bg4)}
.trk-vis-poi.off{color:#64748b;opacity:0.5}
.trk-vis-poi svg{width:13px;height:13px}
.trk-pois.is-collapsed .trk-pois-toggle{transform:rotate(-90deg)}
.trk-pois.is-collapsed .trk-poi-list{display:none}
/* Lighter than a course row: these are subordinate to the one above them. */
.trk-pois .poi-item{padding:5px 6px;border-radius:7px;background:none;border:none}
.trk-pois .poi-item:hover{background:var(--bg4)}

/* ── THE COURSE MAP ON A RACE CARD ─────────────────────────────
   Sits above the profile in the schedule and carries one course: see
   js/racemap.js. Deliberately the same visual weight as the profile
   block under it — the two are one answer to "what is this race", not a
   map with a chart bolted on. */
.rm-block{margin-top:14px;padding-top:12px;border-top:1px solid var(--border)}
.rm-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:8px}
.rm-name{display:flex;align-items:center;gap:6px;font-size:11px;font-weight:800;
  letter-spacing:.06em;text-transform:uppercase;color:var(--text3);min-width:0}
.rm-name svg{width:14px;height:14px;flex-shrink:0}
.rm-name span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rm-tools{display:flex;align-items:center;gap:6px;margin-left:auto;flex-wrap:wrap}
.rm-style{min-height:30px;padding:3px 8px;font-size:11.5px;border-radius:7px;
  background:var(--bg3);border:1px solid var(--border2);color:var(--text)}
.rm-tools .btn{min-height:30px;padding:4px 9px;font-size:11.5px}
.rm-tools .rm-wind.is-on{background:rgba(59,130,246,.18);border-color:rgba(59,130,246,.5);color:#8ec5ff}

/* Tall enough that a race reads as a shape rather than a strip. A race
   card is wide, so a fixed height turns the map into a letterbox on a
   desktop — the height follows the width until it hits the cap, which is
   what keeps a full course and its finishing circuit in one view without
   pushing the profile under it off the screen. */
.rm-canvas{position:relative;height:clamp(280px, 34vw, 520px);border-radius:10px;
  overflow:hidden;border:1px solid var(--border);background:var(--bg3)}
.rm-canvas-in{position:absolute;inset:0}
@media (max-width:640px){ .rm-canvas{height:300px} }

/* The wind read-out under the map rather than floating over it: on a card
   this narrow an overlay covers the course it is describing. */
.rm-wind-panel{margin-top:8px;padding:8px 10px;border-radius:9px;
  background:var(--bg3);border:1px solid var(--border);font-size:11px;color:var(--text2)}
.rm-wp-hd{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:6px}
.rm-wp-hd strong{font-size:11px;letter-spacing:.04em;color:#8ec5ff}
.rm-wp-legend{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:6px}
.rm-wp-legend span{display:flex;align-items:center;gap:5px}
.rm-wp-legend i{width:10px;height:10px;border-radius:2px;display:inline-block;flex-shrink:0}
.rm-wp-sim{display:flex;align-items:center;gap:8px}
.rm-wp-sim input{flex:1;min-width:80px;accent-color:#38bdf8;height:4px}
.rm-wp-note{margin:6px 0 0;color:#fbbf24}


/* ══════════════════════════════════════════════════════════
   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.
   ══════════════════════════════════════════════════════════ */
/* ── ADD WAYPOINT ACTIVE MODE & POI LIST ───────────────────── */
/* The toolbar's add button: a circle with a bare plus. Sized to the
/* The plate is dark in BOTH themes, so the chip on it cannot borrow the
   page's text tokens: in light mode "WBGT" painted itself dark-on-dark
   and disappeared. On this plate the text is always white. */
.rm-wbgt .wbgt-chip{background:transparent;border-color:rgba(255,255,255,.18);color:#cfe2e0}
.rm-wbgt .wbgt-chip strong,.rm-wbgt .wbgt-chip .wbgt-zone{color:#fff}
   map-tool buttons beside it so the row reads as one family. */
.btn-round-add{width:40px;height:40px;min-height:40px;padding:0;border-radius:50%;
  display:inline-flex;align-items:center;justify-content:center;font-size:17px;line-height:1;flex-shrink:0}
.btn-round-add svg{width:19px;height:19px}
.btn-round-add span{display:none}
#cacMap{position:absolute;inset:0;width:100%;height:100%}
@media (max-width:640px){
  /* Five icons and the add-waypoint button have to share one row here, so
     the icons tighten rather than wrap onto the course. */
  .map-tool-btn{width:32px;height:32px;border-radius:8px}
}
/* ── THE COURSE LEGEND, TOP RIGHT ──────────────────────────────
   Opened with ten courses in it, a legend anchored to the bottom edge
   grows upwards through the middle of the map — over the course itself,
   which is the one thing it is describing. In the corner it grows down
   the side instead, under the tools, and the map stays readable behind
   it. Scoped to the course map: the dashboard's mini-map has its own
   corner rules, and Mapbox's zoom controls sit top-left on this one. */
.map-shell .map-legend{top:58px;right:12px;bottom:auto;left:auto;transform:none;
  max-width:min(272px,calc(100% - 24px))}
.map-shell .map-legend .ml-body{max-height:min(46vh,340px)}
@media (max-width:640px){
  /* The tools wrap to two rows on a narrow screen, so the legend starts lower. */
  .map-shell .map-legend{top:auto;bottom:10px;right:10px;max-width:calc(100% - 20px)}
  .map-shell .map-legend .ml-body{max-height:30vh}
}
/* The controls live ON the canvas now, dressed as .map-tools like every
   other map in the app — the bar above the frame made this one map read
   differently from the two beside it. Four square icon buttons, and the
   basemap behind the map icon in a .map-pop, exactly as on the course-map
   screen: the native <select> that used to sit here was the only control
   in the app the operating system got to paint. */
.rm-canvas .rm-pop{top:56px;right:12px;width:min(220px,calc(100% - 24px))}
.map-tool-btn.is-on{background:linear-gradient(135deg,var(--accent-fill),var(--accent-fill2));
  color:var(--on-accent);border-color:transparent}
/* The course name as a pill at the foot of its own map. */
.rm-canvas .rm-name{position:absolute;left:10px;bottom:10px;z-index:5;display:flex;align-items:center;gap:6px;
  max-width:min(62%,360px);padding:5px 10px;border-radius:8px;min-width:0;
  background:rgba(3,37,42,.82);backdrop-filter:blur(8px);border:1px solid rgba(125,190,188,.25);
  font-size:10.5px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;color:#cfe2e0}
.rm-canvas .rm-name svg{width:13px;height:13px;flex-shrink:0}
.rm-canvas .rm-name span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* The heat verdict in the top-left corner, on a dark plate so its zone
   tint stays readable over any basemap. */
.rm-wbgt{position:absolute;top:12px;left:12px;z-index:6;margin:0;border-radius:11px;
  background:rgba(3,37,42,.78);backdrop-filter:blur(8px)}
@media (max-width:640px){
  .rm-canvas .map-tools{gap:5px}
  .rm-canvas .map-tool-btn{width:31px;height:31px;border-radius:8px;font-size:14px}
  .rm-canvas .map-tool-btn svg{width:14px;height:14px}
  .rm-canvas .rm-pop{top:48px;right:10px}
  .rm-wbgt .wbgt-chip{padding:5px 8px;font-size:11px;gap:5px}
  .rm-wbgt .wbgt-chip strong,.rm-wbgt .wbgt-zone{display:none}
}
/* ── THE PROFILE, UNDER THE MAP ────────────────────────────────
   Once the phone treatment, now the only one: the card is emitted after
   the layout on every width, and this class dresses it as the ordinary
   themed card that position deserves. The !importants date from when it
   had to beat the old floating panel's inline styles; harmless now. */
.elev-card.elev-below{
  position:static!important;
  inset:auto!important;
  z-index:auto!important;
  /* A sibling of the layout now, not a grid row — it brings its own gap. */
  margin:14px 0 0!important;
  background:var(--bg2)!important;
  backdrop-filter:none!important;
  border:1px solid var(--border)!important;
  box-shadow:var(--shadow)!important;
  padding:12px 14px!important;
}
@media (max-width:900px){
  .map-shell .map-legend{bottom:10px}
}
/* ── THE WIND READ-OUT, UNDER THE MAP ──────────────────────────
   It used to float at the top-left of the canvas, where on a phone it
   covered the course it describes — and the course is the whole point of
   colouring it by wind. Below the map it gets the full width, so the four
   blocks read as a row on a desktop and stack on a phone. */
/* Floats over the foot of the canvas — the strip the elevation profile
   held before it moved under the frame. Capped and scrollable so on a
   phone it never swallows the whole map. */
/* Mapbox's own stack sits at the bottom left of this map now, so the
   elevation panel — which spans the foot of the canvas when it is open —
   would land on top of it. Lifted by the same measured height the wind
   read-out is lifted by. */
.map-shell .mapboxgl-ctrl-bottom-left{transition:bottom .18s ease}
.map-shell .mapboxgl-ctrl-bottom-left{bottom:var(--elev-over-left-h,0px)}
.wind-card{position:absolute;bottom:calc(12px + var(--elev-over-h,0px));left:12px;right:12px;
  z-index:5;margin:0;
  max-height:58%;overflow-y:auto;box-shadow:0 8px 24px rgba(0,0,0,.5)}
.wind-card[hidden]{display:none}

/* ── THE PROFILE, OVER THE FOOT OF THE CANVAS ──────────────────
   Back where it started, and this time it folds. The argument for
   putting it under the map frame was that it covered the roads; the
   argument against was stronger — under the frame it is below the fold
   on a laptop, so the picture you want WHILE reading the coloured
   course is the one you have to go looking for.

   It is glass rather than a solid card, so the course under it is still
   legible, and it publishes its own height to the shell (--elev-over-h,
   set by elevOverHeight() in js/map.js) so the wind read-out sits on top
   of it instead of underneath it. */
.elev-card.elev-over{position:absolute;left:12px;right:12px;bottom:12px;z-index:6;margin:0;
  padding:9px 12px 10px;max-height:56%;overflow:hidden;
  background:rgba(6,20,28,.86);backdrop-filter:blur(9px);
  border:1px solid rgba(255,255,255,.12);box-shadow:0 8px 24px rgba(0,0,0,.5)}
.elev-card.elev-over .elev-hd{display:flex;align-items:center;gap:10px;margin-bottom:4px}
.elev-card.elev-over .elev-hd h3{margin:0;font-size:11px;font-weight:800;color:#38bdf8;
  text-transform:uppercase;letter-spacing:.05em;white-space:nowrap}
/* The course name and the scrub hint share what is left, and are cut off
   rather than wrapping the bar onto a second line over the map. */
.elev-card.elev-over .c-sub{flex:1;min-width:0;margin:0;font-size:10px;color:#cbd5e1;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.elev-fold-btn{flex-shrink:0;width:26px;height:26px;color:#cbd5e1}
.elev-fold-btn svg{width:16px;height:16px;transition:transform .18s ease}
/* SHUT, IT IS NOT A BAR. A strip the width of the canvas carrying a
   heading and a course name, whose only job while shut is to be
   reopened, was covering the foot of every course for the sake of one
   button. Shut it collapses to that button: a square in the corner
   wearing a profile line. Opening it brings the bar back with the
   picture it belongs to. */
.elev-card.elev-over.folded{left:auto;right:12px;width:42px;height:42px;padding:0;
  border-radius:11px;display:flex;align-items:center;justify-content:center;max-height:none}
.elev-card.elev-over.folded .elev-body{display:none}
.elev-card.elev-over.folded .elev-hd{margin:0;gap:0}
.elev-card.elev-over.folded .elev-hd h3,
.elev-card.elev-over.folded .elev-hd .c-sub{display:none}
.elev-card.elev-over.folded .elev-fold-btn{width:42px;height:42px}
.elev-card.elev-over.folded .elev-fold-btn svg{width:19px;height:19px;transform:none}
/* THE GLASS FOLLOWS THE THEME. The panel above is dark glass because it
   sits over a dark map; on the light theme the same rectangle is a black
   hole in the middle of a pale screen, and the profile inside it — drawn
   in var(--text3) and the course's own colour — is read against the
   wrong ground. Same glass, poured the other way: white over the map,
   the ordinary card border, and the heading in the theme's accent rather
   than the dark theme's cyan. */
body.light .elev-card.elev-over{
  background:rgba(255,255,255,.90);
  border:1px solid var(--border);
  box-shadow:0 8px 24px rgba(3,37,42,.18)}
body.light .elev-card.elev-over .elev-hd h3{color:var(--accent)}
body.light .elev-card.elev-over .c-sub{color:var(--text2)}
body.light .elev-fold-btn{color:var(--text2)}

/* On a phone the map is 60vh and the profile must not eat half of it. */
@media (max-width:900px){
  .elev-card.elev-over{left:8px;right:8px;bottom:8px;max-height:48%}
  .elev-card.elev-over .elev-wrap{height:74px!important}
}

.wc-hd{display:flex;align-items:center;justify-content:space-between;
  gap:10px;flex-wrap:wrap;margin-bottom:10px}
.wc-hd h3{margin:0;font-size:12px;font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;color:var(--accent)}
.wc-risk{font-size:10px;font-weight:800;letter-spacing:.04em;padding:3px 9px;
  border-radius:6px;background:var(--ok);color:#fff;white-space:nowrap}
.wc-risk.is-high{background:#ef4444}
.wc-grid{display:grid;gap:10px;
  grid-template-columns:repeat(auto-fit, minmax(min(230px,100%), 1fr));align-items:start}
.wc-box{padding:9px 11px;border-radius:9px;background:var(--bg3);
  border:1px solid var(--border);font-size:11px;line-height:1.45}
/* Where it blows from. The dial turns with the wind. */
.wc-origin{display:flex;align-items:center;gap:9px}
.wc-dial{width:32px;height:32px;border-radius:50%;flex-shrink:0;
  display:flex;align-items:center;justify-content:center;
  background:color-mix(in srgb, var(--accent) 14%, transparent);
  border:1.5px solid var(--accent)}
.wc-dial-arrow{display:inline-block;font-size:16px;line-height:1;color:var(--accent)}
.wc-origin-name{font-size:11px;font-weight:800;color:var(--accent)}
.wc-origin-sub{font-size:10.5px;color:var(--text2);margin-top:2px}
/* How many kilometres fall on each wind angle. */
.wc-split-row{display:flex;align-items:center;gap:7px;color:var(--text2)}
.wc-split-row + .wc-split-row{margin-top:3px}
.wc-split-row strong{color:var(--text)}
.wc-dot{width:9px;height:9px;border-radius:50%;flex-shrink:0}
.wc-dot.is-cross{background:#ff1744}
.wc-dot.is-head{background:#ffea00}
.wc-dot.is-tail{background:#00e676}
/* The UCI heat reading beside the wind blocks. */
.wc-wbgt-hd{font-size:11px;font-weight:800;letter-spacing:.04em;color:var(--accent);margin-bottom:7px}
.wc-wbgt-sub{font-size:10.5px;color:var(--text2);margin-top:6px}
/* What the colours along the course mean. */
.wc-legend div{display:flex;align-items:flex-start;gap:7px;color:var(--text2)}
.wc-legend div + div{margin-top:4px}
.wc-legend strong{color:var(--text)}
.wc-key{width:10px;height:10px;border-radius:2px;flex-shrink:0;margin-top:4px}
/* Turn the wind up and watch the course recolour under it. */
.wc-sim-hd{display:flex;align-items:center;justify-content:space-between;
  gap:8px;font-size:11px;font-weight:800;color:var(--accent);margin-bottom:6px}
.wc-sim-hd span:last-child{color:var(--ok)}
.wc-sim-slider{display:flex;align-items:center;gap:7px;margin-bottom:8px}
.wc-sim-slider span{font-size:9.5px;font-weight:700;color:var(--text2)}
.wc-sim-slider input{flex:1;min-width:0;height:4px;cursor:pointer;accent-color:var(--accent)}
.wc-sim-presets{display:flex;gap:5px}
.wc-sim-presets .btn{flex:1;min-width:0;font-size:10px;padding:5px 0;
  text-align:center;justify-content:center}
.wc-sim-presets .wc-storm{background:#ef4444;border-color:#ef4444;color:#fff}
@media (max-width:640px){
  .wc-grid{grid-template-columns:1fr}
  .wc-hd h3{font-size:11px}
}
/* Three risk levels, not two: the badge earned by measured kilometres. */
.wc-risk.is-mid{background:#d97706}
/* Which wind the panel is quoting: the forecast at the start gun, or the
   live reading. Small, but it changes what the numbers mean. */
.wc-origin-when{font-size:10px;color:var(--text2);margin-top:3px;font-style:italic}

/* ═══════════ ROUTE PLANNER ═══════════
   The screen wears the course map's own layout classes; below is only
   what the planner adds — the mode bar, the anchor pins, the popup
   bodies, the surface bars and the live profile. */
#plMap{position:absolute;inset:0;width:100%;height:100%}

/* Anchor pins. In-between anchors are plain white dots, RWGPS-style —
   small enough that the road stays readable under them; the dark ring
   is what keeps them visible on satellite imagery. Start and finish
   are bigger and lettered, because those two you look for. */
.pl-wp{width:20px;height:20px;border-radius:50%;border:2px solid #fff;background:#0ea5e9;
  color:#fff;display:flex;align-items:center;justify-content:center;
  font-size:10px;font-weight:800;cursor:grab;box-shadow:0 1px 5px rgba(0,0,0,.5);
  font-family:inherit;user-select:none}
.pl-wp.mid{width:13px;height:13px;background:#fff;border:2px solid #1e293b}
.pl-wp.mid:hover{transform:scale(1.25)}
.pl-wp.start{background:#34d399}
.pl-wp.finish{background:#f87171}
.pl-ghost{width:14px;height:14px;border-radius:50%;border:2px solid #fff;
  background:#eab308;box-shadow:0 1px 5px rgba(0,0,0,.5)}
.pl-hover-dot{width:12px;height:12px;border-radius:50%;border:2px solid #fff;
  background:#eab308;box-shadow:0 1px 4px rgba(0,0,0,.5)}

/* The shared popup body: a heading, then buttons in a column. */
.pl-pop-bd{display:flex;flex-direction:column;gap:5px;min-width:180px}
.pl-pop-hd{font-weight:800;font-size:12px;color:var(--text)}
.pl-pop-sub{font-size:10px;font-weight:700;color:var(--text2);margin-top:2px}
.pl-pop-bd .btn{justify-content:flex-start}
.pl-pop-mode.on{outline:2px solid var(--accent)}

/* Panel bodies. The course-map panel keeps its content inside padded
   lists; the planner's sits directly in the panel, so every block steps
   14 px in from the frame itself — nothing touches an edge. The section
   headings (.mp-hd) deliberately keep their full-width rule lines. */
.pl-panel > .field{margin:14px 14px 0}
.pl-panel > .field label{font-size:10.5px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;color:var(--text2);display:block;margin-bottom:5px}
.pl-panel .pl-stats{margin:12px 14px;padding:11px 13px;display:flex;flex-direction:column;
  gap:7px;background:var(--bg3);border:1px solid var(--border);border-radius:10px}
.pl-stat{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:12px}
.pl-stat span{color:var(--text2);display:flex;align-items:center;gap:7px;min-width:0}
.pl-stat b{color:var(--text);white-space:nowrap}
.pl-stat-mode i{width:10px;height:10px;border-radius:3px;flex-shrink:0;display:inline-block}
.pl-actions{display:grid;grid-template-columns:1fr 1fr;gap:7px;margin:12px 14px}
.pl-actions .btn{justify-content:flex-start;font-size:11px;padding:8px 10px}
/* air under a standalone panel button — it sat 2 px off the next rule */
.pl-panel > .btn{margin:12px 14px 18px;align-self:flex-start}
.pl-bars{margin:10px 14px;display:flex;flex-direction:column;gap:6px}
.pl-bar-row{display:flex;align-items:center;gap:8px;font-size:11.5px;color:var(--text2);
  min-height:18px}
.pl-bar-row b{margin-left:auto;color:var(--text)}
.pl-bar-dot{width:10px;height:10px;border-radius:3px;flex-shrink:0}
.pl-ways{border-top:1px solid var(--border);padding-top:8px;margin-top:2px}
.pl-note{font-size:10.5px;color:var(--text2);font-style:italic;margin:2px 14px 10px}
.pl-help{margin:6px 14px 14px;font-size:11px;color:var(--text2)}
.pl-help summary{cursor:pointer;font-weight:700;padding:4px 0}
.pl-help p{margin-top:4px;line-height:1.5}
.pl-pick-list{display:flex;flex-direction:column;gap:6px;max-height:50vh;overflow:auto}
.pl-pick{justify-content:flex-start;gap:8px}
.pl-pick i{margin-left:auto;font-style:normal;color:var(--text2)}
.pl-pick-dot{width:11px;height:11px;border-radius:50%;flex-shrink:0}

/* The base-map picker, anchored under the toolbar like #map-pop. */
.pl-style-pop{display:flex;flex-direction:column;gap:5px;position:absolute;top:56px;right:12px;
  z-index:7;background:var(--bg2);border:1px solid var(--border);border-radius:var(--radius);
  padding:8px;box-shadow:0 8px 22px rgba(0,0,0,.35)}
.pl-style-pop[hidden]{display:none}
.pl-style-pop .btn.on{outline:2px solid var(--accent)}

/* The live profile under the map. */
.pl-elev-hd{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px}
.pl-elev-hd h3{font-size:12px;margin:0}
#pl-elev-read{font-size:11px;color:var(--gold2,#eab308);font-weight:700;min-height:1em}
#pl-elev-plot{height:150px}
.pl-elev-svg{width:100%;height:100%;display:block}

/* ── Planner v2: the RWGPS layout ─────────────────────────────
   Info left, canvas centre, tools right; the profile strip below.
   The right column is narrower than the left — it is buttons, not
   sentences. */
.pl-layout{grid-template-columns:280px minmax(0,1fr) 232px}
/* A grid child's default min-width is its CONTENT, so the map column
   refused to shrink and shouldered the tools panel off the right edge
   of a narrower window. */
.pl-layout > *{min-width:0}
.pl-layout > .pl-tools{grid-column:3;grid-row:1}
.pl-tools{display:flex;flex-direction:column;padding-bottom:12px}
.pl-tools > .pl-actions{margin:10px 14px 2px}
.pl-undo-pair{margin:12px 14px 2px}
@media (max-width:1100px){
  .pl-layout{grid-template-columns:250px 1fr 200px}
}
@media (max-width:900px){
  /* phones stack: info, map, tools — same flow as the course map */
  .pl-layout{grid-template-columns:1fr}
  .pl-layout > .pl-tools{grid-column:1;grid-row:auto}
}

/* ── EITHER SIDE PANEL, FOLDED AWAY ─────────────────────────────
   Same idea as the course map's own single #map-panel-toggle (see
   setPanel() in js/map.js), doubled: the drawing panel on the left
   and the tools panel on the right fold independently, each down to
   nothing, and each keeps a tab sitting on whichever edge currently
   opens it. See setPlPanel() in js/planner.js. */
.pl-layout.pl-left-off{grid-template-columns:0px minmax(0,1fr) 232px}
.pl-layout.pl-right-off{grid-template-columns:280px minmax(0,1fr) 0px}
.pl-layout.pl-left-off.pl-right-off{grid-template-columns:0px minmax(0,1fr) 0px}
.pl-layout.pl-left-off > .pl-panel,.pl-layout.pl-right-off > .pl-tools{overflow:hidden;padding:0;border-width:0}
.pl-panel-toggle{position:absolute;top:50%;transform:translateY(-50%);z-index:8;
  width:22px;height:52px;padding:0;display:flex;align-items:center;justify-content:center;
  background:var(--bg2);border:1px solid var(--border2);color:var(--green);cursor:pointer;
  font-family:inherit;transition:left .22s,right .22s,background .16s,color .16s}
.pl-panel-toggle:hover{background:var(--green);color:var(--on-accent)}
body.light .pl-panel-toggle{background:#fff}
.pl-panel-toggle svg{width:14px;height:14px;flex-shrink:0}
.pl-panel-toggle-l{left:280px;margin-left:-10px;border-radius:0 8px 8px 0;border-left:0}
.pl-layout.pl-left-off .pl-panel-toggle-l{left:0;margin-left:0}
.pl-panel-toggle-r{right:232px;margin-right:-10px;border-radius:8px 0 0 8px;border-right:0}
.pl-layout.pl-right-off .pl-panel-toggle-r{right:0;margin-right:0}
@media (max-width:1100px){
  .pl-layout.pl-left-off{grid-template-columns:0px minmax(0,1fr) 200px}
  .pl-layout.pl-right-off{grid-template-columns:250px minmax(0,1fr) 0px}
  .pl-layout.pl-left-off.pl-right-off{grid-template-columns:0px minmax(0,1fr) 0px}
  .pl-panel-toggle-l{left:250px}
  .pl-panel-toggle-r{right:200px}
}
@media (max-width:900px){
  /* The stacked phone layout has no seam for a tab to sit on. */
  .pl-panel-toggle{display:none}
}

/* ── THE MODE PICKER ────────────────────────────────────────
   A row of green squares with a white drawing on each, and the caption
   under them says which one is chosen — so the buttons never have to
   carry a word. They used to be emoji on a grey chip: five different
   drawing styles from five different type foundries, sitting in an app
   that draws everything else in one stroke family.

   THE MODE'S OWN COLOUR IS STILL HERE, as the ring on the chosen one:
   that colour is the colour the leg is drawn in on the map and the
   colour of its row in the panel's breakdown, and cutting the thread
   between the button and the line would cost more than the tidiness of
   five identical squares. The ones not chosen stand back rather than
   compete — same square, same white drawing, less of it. */
.pl-mode-seg{display:flex;gap:6px;margin:12px 14px 6px}
.pl-mode-seg .pl-mode-btn{flex:1;aspect-ratio:1;display:flex;align-items:center;
  justify-content:center;border:2px solid transparent;border-radius:9px;padding:0;
  cursor:pointer;font:inherit;opacity:.45;
  /* The app's own green-with-a-contrasting-mark pair, the same one the
     primary button wears — white on deep green in the light theme, dark
     ink on mint in the dark one. A hard-coded white would be invisible
     on the dark theme's mint. */
  background:linear-gradient(135deg,var(--accent-fill),var(--accent-fill2));
  transition:opacity .16s,border-color .16s,transform .16s}
.pl-mode-seg .pl-mode-btn:hover{opacity:.75;transform:translateY(-1px)}
.pl-mode-seg .pl-mode-btn.on{opacity:1;border-color:var(--mc)}
.pl-mode-seg .pl-mode-glyph{display:flex;line-height:1;color:var(--on-accent)}
.pl-mode-seg .pl-mode-glyph svg{width:19px;height:19px;stroke-width:2.1}
.pl-mode-cur{font-size:11px;font-weight:700;color:var(--text2);margin:0 14px 4px;text-align:center}

/* Colour swatches for the saved course. */
.pl-colors{display:grid;grid-template-columns:repeat(10,1fr);gap:5px;margin:12px 14px 4px}
.pl-color{aspect-ratio:1;border-radius:4px;border:2px solid transparent;cursor:pointer;padding:0}
.pl-color.on{border-color:var(--text);box-shadow:0 0 0 2px var(--bg2)}

/* The right-click menu: dark rows, a hint column, colour dots. */
.pl-ctx{position:absolute;z-index:20;min-width:230px;max-width:300px;
  background:#101724;color:#f8fafc;border:1px solid #2b3546;border-radius:8px;
  padding:5px;box-shadow:0 10px 30px rgba(0,0,0,.5);display:flex;flex-direction:column}
.pl-ctx-row{display:flex;align-items:center;gap:8px;width:100%;text-align:left;
  background:transparent;border:0;color:inherit;font:inherit;font-size:12px;
  padding:6px 8px;border-radius:5px;cursor:pointer}
.pl-ctx-row:hover:not(:disabled){background:#1d2838}
.pl-ctx-row:disabled{opacity:.4;cursor:default}
.pl-ctx-row i{margin-left:auto;font-style:normal;font-size:10.5px;color:#8b98ab}
.pl-ctx-row.on{background:#1d2838}
.pl-ctx-row.danger{color:#fca5a5}
.pl-ctx-row span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pl-ctx-dot{width:10px;height:10px;border-radius:2px;flex-shrink:0}
.pl-ctx-hr{height:1px;background:#2b3546;margin:4px 2px}
.pl-ctx-label{font-size:10px;font-weight:800;color:#8b98ab;padding:4px 8px 2px;
  text-transform:uppercase;letter-spacing:.04em}

/* Surface rows carry kilometres AND percent. */
.pl-bar-row em{margin-left:auto;font-style:normal;color:var(--text2);font-size:11px}
.pl-bar-row b{margin-left:8px;min-width:34px;text-align:right}

/* Profile tabs, RWGPS-style chips in the strip's header. */
.pl-elev-tabs{display:flex;gap:4px}
.pl-elev-tabs button{font:inherit;font-size:10.5px;font-weight:800;border:1px solid var(--border);
  background:var(--bg3);color:var(--text2);border-radius:999px;padding:3px 10px;cursor:pointer}
.pl-elev-tabs button.on{background:var(--text);color:var(--bg2);border-color:var(--text)}
.pl-elev-tabs button:disabled{opacity:.4;cursor:default}
#pl-elev-total{font-size:11px;font-weight:700;color:var(--text2);margin-left:auto}
.pl-speed{font:inherit;font-size:10.5px;background:var(--bg3);color:var(--text);
  border:1px solid var(--border);border-radius:5px;padding:1px 3px;margin-left:5px}

/* ── TWO TO A ROW, BOTH PANELS ──────────────────────────────
   These stood one under the other because a label beside an icon runs
   out of room at half a column's width. So the label came out from
   BESIDE the icon and went UNDER it, centred and wrapped — the shape
   the four scan tiles already had, and the reason they fit two-up in a
   232 px column. One shape for every button on the screen, and half
   the scrolling. */
.pl-tools .pl-actions{grid-template-columns:1fr 1fr}
.pl-panel .pl-actions{grid-template-columns:1fr 1fr}
.pl-tools .pl-undo-pair{grid-template-columns:1fr 1fr}

/* The location search: a small box hanging under the toolbar's
   magnifier, wearing the app's own dropdown styles. */
.pl-search{position:absolute;top:56px;right:12px;z-index:8;width:min(300px,calc(100% - 24px))}
.pl-search[hidden]{display:none}
.pl-search .input{width:100%;box-shadow:0 8px 22px rgba(0,0,0,.35)}
.pl-search .search-dropdown{position:static;margin-top:4px;max-height:260px;overflow-y:auto}
/* The found-place pin is a viewfinder: visible, never clickable, so the
   click that starts drawing lands on the map underneath it. */
.pl-search-pin{font-size:26px;line-height:1;pointer-events:none;
  filter:drop-shadow(0 2px 3px rgba(0,0,0,.5))}

/* ── Planner v3: the session route list, the profile's selection and
   axes, the pinned save button. ── */

/* The save button rides the panel's foot whatever sits above it. */
.pl-panel .mp-foot{margin-top:auto}

/* Session routes: one row each — dot, name, kilometres, weld, bin. */
.pl-routes{display:flex;flex-direction:column;gap:5px;margin:10px 14px}
.pl-route-row{display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:8px;
  background:var(--bg3);border:1px solid var(--border);cursor:pointer;font-size:11.5px}
.pl-route-row:hover{border-color:var(--gold2)}
.pl-route-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  color:var(--text);font-weight:700}
.pl-route-row em{margin-left:auto;font-style:normal;color:var(--text2);white-space:nowrap}
.pl-route-weld,.pl-route-del{border:0;background:transparent;color:var(--text2);cursor:pointer;
  padding:3px;border-radius:5px;display:flex;flex-shrink:0}
.pl-route-weld:hover{color:var(--gold2)}
.pl-route-del:hover{color:#f87171}
.pl-route-weld svg,.pl-route-del svg{width:13px;height:13px}

/* The profile: taller strip, crosshair, the selection bar underneath. */
#pl-elev-plot{height:186px}
.pl-plot-wrap{position:relative;height:100%}
.pl-elev-svg{cursor:crosshair;user-select:none}
.pl-elev-selrect{fill:#eab308;fill-opacity:.16;stroke:#eab308;stroke-opacity:.55}
.pl-ax{position:absolute;font-size:9.5px;font-weight:700;color:var(--text2);
  pointer-events:none;line-height:1}
.pl-ax-y{left:6px;transform:translateY(-50%)}
.pl-ax-x{top:calc(100% - 22px);transform:translateX(-50%)}
.pl-ax-unit{top:calc(100% - 22px);right:4px;color:var(--text2)}
.pl-elev-sel{display:flex;align-items:center;flex-wrap:wrap;gap:6px 14px;margin-top:10px;
  font-size:11.5px;color:var(--text2);background:var(--bg3);border:1px solid var(--border);
  border-radius:8px;padding:7px 12px}
.pl-elev-sel b{color:var(--gold2,#eab308)}
.pl-sel-x{margin-left:auto;border:0;background:transparent;color:var(--text2);cursor:pointer;
  font-size:15px;line-height:1;padding:2px 6px;border-radius:5px}
.pl-sel-x:hover{color:var(--text);background:var(--bg4)}

/* The dot that rides the line — white, ringed, never clickable. */
.pl-hover-dot{width:13px;height:13px;border-radius:50%;background:#fff;
  border:2px solid #1e293b;box-shadow:0 1px 4px rgba(0,0,0,.5);pointer-events:none}

/* Waypoints drawn in the session: the emoji, on a small card. */
.pl-poi{font-size:15px;line-height:1;background:var(--bg2,#101724);border:1px solid var(--border);
  border-radius:7px;padding:3px 4px;cursor:pointer;box-shadow:0 1px 5px rgba(0,0,0,.4)}
/* A waypoint carrying a roadbook sign is the sign — the drawing has its
   own ring and white ground, so the little dark chip comes off. */
.pl-poi.pl-poi-img{background:none;border:0;padding:0;box-shadow:none;
  filter:drop-shadow(0 1px 3px rgba(0,0,0,.45))}
.pl-poi.pl-poi-img img{display:block;width:28px;height:28px}

/* Box / lasso select overlay, and the selection bar's action row. */
.pl-boxsel{position:absolute;inset:0;width:100%;height:100%;z-index:15;pointer-events:none}
.pl-boxsel polygon{fill:rgba(234,179,8,.10);stroke:#eab308;stroke-width:1.5;stroke-dasharray:5 4}
.pl-sel-actions{display:flex;align-items:center;flex-wrap:wrap;gap:6px;width:100%;
  padding-top:7px;margin-top:2px;border-top:1px solid var(--border)}
.pl-sel-actions .btn{font-size:10.5px;padding:5px 9px}
.pl-sel-modes{display:flex;align-items:center;gap:4px;font-size:10.5px;color:var(--text2)}
.pl-sel-mode{border:2px solid var(--mc);background:var(--bg3);border-radius:6px;
  padding:3px 6px;cursor:pointer;font-size:12px;line-height:1;display:inline-flex;
  align-items:center;color:var(--mc)}
.pl-sel-mode svg{width:15px;height:15px;display:block}
.pl-sel-mode:hover{background:var(--bg2)}
/* A mark that is ON says so on its own button — one button per mark,
   wearing the state rather than a second button beside it. */
.pl-sel-actions .btn.on{background:var(--bg2);border-color:var(--gold2);color:var(--text)}

/* ── THE SELECTION'S TWO EDGES ──────────────────────────────
   Grab either one and pull. Elements over the plot rather than shapes
   inside it: the strip is drawn preserveAspectRatio="none" and squeezed
   to whatever width the map leaves it, so anything drawn in the picture
   comes out a different width on every screen. The grab area is 18 px
   against a 2 px line, because a target the width of the line it draws
   is a target nobody hits, and the knob is what says it can be moved. */
.pl-grip{position:absolute;top:3.5%;bottom:15.5%;width:18px;margin-left:-9px;
  cursor:ew-resize;z-index:3;touch-action:none}
.pl-grip::before{content:'';position:absolute;left:8px;top:0;bottom:0;width:2px;
  background:#eab308}
.pl-grip i{position:absolute;left:50%;top:50%;width:11px;height:24px;
  margin:-12px 0 0 -5.5px;border-radius:5px;background:#eab308;
  border:1px solid #02060f;box-shadow:0 1px 4px rgba(0,0,0,.5)}
.pl-grip:hover i{background:#facc15}

/* ── Planner v4: buttons wear the card style, sections fold ──
   The bare ghost rows read like a debug menu next to the app's cards;
   these are the same card ingredients — bg2, border, radius, a lift on
   hover — at button size. Labels wrap instead of clipping: a Dutch
   label is half again as long as its English twin. */
.pl-panel .pl-actions .btn,
.pl-tools .pl-actions .btn,
.pl-panel > .btn{
  background:var(--bg2);border:1px solid var(--border);border-radius:10px;
  padding:11px 9px;flex-direction:column;justify-content:center;align-items:center;gap:7px;
  font-size:11px;font-weight:700;color:var(--text);
  box-shadow:0 1px 2px rgba(0,0,0,.12);
  min-height:70px;white-space:normal;text-align:center;line-height:1.25}
.pl-panel .pl-actions .btn span,
.pl-tools .pl-actions .btn span,
.pl-panel > .btn span{white-space:normal;line-height:1.25;min-width:0;max-width:100%;
  display:block;text-align:center;text-wrap:balance}
/* Undo and redo stay a plain pair: they are pressed on their way past,
   not read, and a 70 px tile each puts the whole tools column a screen
   further down. */
.pl-tools .pl-undo-pair .btn{flex-direction:row;justify-content:flex-start;gap:8px;
  min-height:38px;padding:8px 10px;text-align:left}
.pl-tools .pl-undo-pair .btn span{text-align:left}
.pl-panel .pl-actions .btn svg,
.pl-tools .pl-actions .btn svg,
.pl-panel > .btn svg{flex-shrink:0;color:var(--text2)}
.pl-panel .pl-actions .btn:hover,
.pl-tools .pl-actions .btn:hover,
.pl-panel > .btn:hover{border-color:var(--gold2);transform:translateY(-1px);
  box-shadow:0 3px 8px rgba(0,0,0,.18)}
.pl-panel .pl-actions .btn:hover svg,
.pl-tools .pl-actions .btn:hover svg{color:var(--gold2)}
.pl-panel > .btn{align-self:stretch;margin-right:14px}
body.light .pl-panel .pl-actions .btn,
body.light .pl-tools .pl-actions .btn,
body.light .pl-panel > .btn{background:#fff}

/* The tools panel's folding sections: the summary wears the same
   heading dress as .mp-hd-sub, with a chevron that tells the state. */
.pl-sec{border-top:1px solid var(--border)}
.pl-sec summary{list-style:none;cursor:pointer;padding:13px 16px;
  display:flex;align-items:center;justify-content:space-between;
  font-size:12px;font-weight:800;text-transform:uppercase;
  letter-spacing:.07em;color:var(--text)}
.pl-sec summary::-webkit-details-marker{display:none}
.pl-sec summary::after{content:'▸';color:var(--text2);font-size:11px;
  transition:transform .15s}
.pl-sec[open] summary::after{transform:rotate(90deg)}
.pl-sec summary:hover::after{color:var(--gold2)}

/* The four scans, two to a row. The tools column is too narrow for a
   pair of left-aligned rows, so these stand their label under their
   icon and centre it — same card dress as the tool buttons, a shape
   that fills the foot of the column instead of leaving it empty. */
.pl-scan-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin:10px 14px 6px}
/* The label sat hard against the tile's own edge — 7 px of side padding
   on a 98 px tile, with "Climbs & descents" wrapping into every pixel of
   it, read as text pushed up against the panel. Wider sides, a balanced
   wrap so the two lines come out the same length, and the pair centred
   in the tile rather than filling it. */
.pl-scan-grid .btn{flex-direction:column;justify-content:center;align-items:center;gap:7px;
  background:var(--bg2);border:1px solid var(--border);border-radius:10px;
  padding:12px 10px;font-size:11px;font-weight:700;color:var(--text);
  box-shadow:0 1px 2px rgba(0,0,0,.12);min-height:74px;
  white-space:normal;text-align:center;line-height:1.25}
.pl-scan-grid .btn span{white-space:normal;min-width:0;max-width:100%;
  display:block;text-align:center;text-wrap:balance}
.pl-scan-grid .btn svg{flex-shrink:0;color:var(--text2);width:18px;height:18px}
.pl-scan-grid .btn:hover{border-color:var(--gold2);transform:translateY(-1px);
  box-shadow:0 3px 8px rgba(0,0,0,.18)}
.pl-scan-grid .btn:hover svg{color:var(--gold2)}
body.light .pl-scan-grid .btn{background:#fff}

/* ── Planner v5: the profile rides the foot of the map ──
   Absolutely placed inside .map-shell, so full screen carries it and
   the canvas keeps its full height. FOLDS rather than vanishing — the
   same contract the course map's own #elev-card keeps (see .elev-over
   .folded above): shut, it is a 42 px square parked bottom-right
   rather than a bar spanning the map, and the one button on it is
   what both opens and closes it. There is no separate toolbar button
   any more — a card that folds to a corner square needs nothing else
   to bring it back. */
.pl-elev-over{position:absolute;left:12px;right:12px;bottom:12px;z-index:7;
  margin:0;padding:10px 12px 8px;backdrop-filter:blur(6px);
  background:color-mix(in srgb, var(--bg2) 88%, transparent);
  transition:left .2s,right .2s,width .2s,height .2s,padding .2s}
body.light .pl-elev-over{background:color-mix(in srgb, #fff 90%, transparent)}
.pl-elev-over.pl-elev-off{left:auto;right:12px;width:42px;height:42px;padding:0;
  border-radius:11px;display:flex;align-items:center;justify-content:center;max-height:none}
.pl-elev-over.pl-elev-off .pl-elev-tabs,.pl-elev-over.pl-elev-off #pl-elev-total,
.pl-elev-over.pl-elev-off #pl-elev-read,.pl-elev-over.pl-elev-off #pl-elev-plot,
.pl-elev-over.pl-elev-off #pl-elev-sel{display:none}
.pl-elev-over.pl-elev-off .pl-elev-hd{margin:0;gap:0}
.pl-elev-over.pl-elev-off .pl-elev-hide{width:42px;height:42px;border-radius:11px;
  background:linear-gradient(135deg,var(--accent-fill),var(--accent-fill2));color:var(--on-accent)}
.pl-elev-over.pl-elev-off .pl-elev-hide:hover{background:linear-gradient(135deg,var(--accent-fill),var(--accent-fill2));filter:brightness(1.08)}
.pl-elev-over.pl-elev-off .pl-elev-hide svg{width:19px;height:19px}
.pl-elev-over #pl-elev-plot{height:132px}
.pl-elev-hide{border:0;background:transparent;color:var(--text2);cursor:pointer;
  padding:2px 4px;border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.pl-elev-hide:hover{color:var(--text);background:var(--bg4)}
.pl-elev-hide svg{width:15px;height:15px;flex-shrink:0}
@media (max-width:900px){
  .pl-elev-over{left:8px;right:8px;bottom:8px;padding:8px 9px 6px}
  .pl-elev-over #pl-elev-plot{height:104px}
  .pl-elev-over.pl-elev-off{right:8px}
}

/* The strip while the heights are still landing. */
.pl-elev-wait{display:flex;align-items:center;justify-content:center;height:100%;
  margin:0;font-size:11.5px;font-style:italic;color:var(--text2)}

/* The distance, riding the gold selection line on the map itself —
   see plRenderSel() in js/planner.js. A plain label, not a speech
   -bubble popup: it has one number to say and nothing to point a tail
   at that the gold line underneath does not already show. */
.pl-sel-marker{transform:translateY(-10px);padding:3px 9px;border-radius:20px;
  background:#101724;color:#f8fafc;font-size:11.5px;font-weight:800;
  white-space:nowrap;box-shadow:0 2px 8px rgba(0,0,0,.4);pointer-events:none}
body.light .pl-sel-marker{background:#fff;color:#0f172a;border:1px solid var(--border)}

/* ── the map popovers' own form controls ──
   A select styled by the browser is the one thing that gave this panel
   away as unfinished: white on a teal glass card. Same fill, border and
   radius as the toggles beside it, with the app's chevron drawn in. */
.map-pop .mo-select{width:100%;appearance:none;-webkit-appearance:none;
  background:rgba(125,190,188,.12);color:#e8eefc;
  border:1px solid rgba(125,190,188,.24);border-radius:8px;
  padding:8px 28px 8px 10px;font-family:inherit;font-size:11.5px;font-weight:600;
  cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,rgba(232,238,252,.6) 50%),
    linear-gradient(135deg,rgba(232,238,252,.6) 50%,transparent 50%);
  background-position:calc(100% - 15px) 50%,calc(100% - 10px) 50%;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat}
.map-pop .mo-select:hover{background-color:rgba(125,190,188,.2);border-color:var(--gold2)}
.map-pop .mo-select:focus{outline:none;border-color:var(--gold2)}
.map-pop .mo-select option{background:#03252a;color:#e8eefc}

/* Labels wrap instead of being clipped — "Parcours scannen op
   beklimmingen" is half again as long as its English twin. */
.map-pop .mo-btn{height:auto;min-height:36px;white-space:normal;text-align:left;
  line-height:1.3;padding:8px 10px;align-items:center}
.map-pop .mo-btn span{white-space:normal;min-width:0}
.map-pop .mo-btn svg{flex-shrink:0}

/* ═══════════ THE COURSE ON A SHEET OF A4 ═══════════
   Everything below dresses js/course-print.js: the dialogue with the
   switches down one side and the sheet itself beside them, and the
   print rules that put that sheet — and nothing else on the page — on
   the paper. The sheet is drawn at its true size in page pixels and
   scaled to fit the dialogue, so what is on screen IS the sheet. */
/* ── A SCREEN OF ITS OWN ────────────────────────────────────
   Laid out like the route planner: the settings down one side, the
   sheet filling everything else. It outgrew a dialogue in a week — an
   A4 in a 560 px box is a stamp. */
/* One compact row: back, title and course name side by side, the two
   buttons on the right. Everything below it is the work. */
body.print-view #content{padding:10px 12px 10px;overflow:hidden}
/* Clear of the sidebar's tab (#nav-collapse-toggle, 22 px on the seam):
   at 12 px the tab sat over the start of the bar (Janny, 25 Sep 2026). */
@media (min-width:861px){body.print-view #content{padding-left:34px}}
.cp-hd{margin-bottom:0!important;align-items:center}
.cp-hd .page-hd-text{display:flex;flex-direction:row;align-items:baseline;gap:12px;flex-wrap:wrap}
.cp-hd .page-hd-text h2{margin:0;font-size:17px}
.cp-hd-name{font-size:12.5px;font-weight:700;color:var(--text3)}
.cp-hd .page-hd-actions{display:flex;gap:8px}
/* Settings either side, the sheet in the middle: on a wide screen the
   options fall into two readable columns instead of one long scroll,
   and the thing being made gets the centre of the screen. */
.cp-wrap{display:grid;grid-template-columns:230px minmax(0,1fr) 230px;gap:12px;
  align-items:start;margin-top:8px}
.cp-wrap > .ce-note,.cp-wrap > p.cp-note{grid-column:1/-1}
@media (max-width:1180px){
  .cp-wrap{grid-template-columns:236px minmax(0,1fr)}
  .cp-side-r{grid-column:1;grid-row:2}
  .cp-view{grid-column:2;grid-row:1/3}
}
@media (max-width:880px){
  .cp-wrap{grid-template-columns:1fr}
  .cp-side,.cp-side-r,.cp-view{grid-column:1;grid-row:auto}
  .cp-side{position:static;max-height:none}
}
.cp-view{position:relative;display:flex;flex-direction:column;min-width:0}
/* THE ZOOM RIDES OVER THE SHEET. As a row above the preview it pushed
   the whole middle column down, so the map started a centimetre lower
   than the two panels beside it and the three columns never lined up
   along the top. Floated over the preview instead, it costs nothing:
   there is white margin under it on every sheet. */
.cp-viewbar{position:absolute;top:9px;left:9px;right:9px;z-index:6;
  display:flex;align-items:center;gap:6px;padding:0;pointer-events:none}
.cp-viewbar > *{pointer-events:auto}
.cp-vb{font:inherit;font-size:11.5px;font-weight:700;background:var(--bg2);
  border:1px solid var(--border);border-radius:7px;padding:4px 10px;color:var(--text2);
  cursor:pointer;box-shadow:0 1px 4px rgba(0,0,0,.18)}
.cp-vb:hover{border-color:var(--gold-border);color:var(--text)}
.cp-vb-pct{margin-left:auto;font-size:11px;font-weight:800;color:var(--text2);
  font-variant-numeric:tabular-nums;background:var(--bg2);border:1px solid var(--border);
  border-radius:7px;padding:4px 8px;box-shadow:0 1px 4px rgba(0,0,0,.18)}
.cp-range{width:100%;accent-color:var(--accent2);margin:-2px 0 2px}
/* ── THE BAR ACROSS THE TOP (cpTopLayoutHtml) ──
   The sheet and one panel on the right; the bar spans both. The site
   plan's own button look (.vp-top-btn in css/venue-plan.css). */
.cp-wrap.cp-wrap-top{grid-template-columns:minmax(0,1fr) 256px;grid-template-rows:auto 1fr;gap:8px 12px;margin-top:6px}
.cp-wrap-top .cp-top{grid-column:1/-1;position:relative;border:1px solid var(--border);border-radius:10px;
  background:var(--bg2);display:flex;align-items:center;flex-wrap:wrap;gap:2px 4px;padding:4px 8px}
.cp-wrap-top .cp-view{grid-column:1;grid-row:2}
.cp-wrap-top .cp-side-r{grid-column:2;grid-row:2}
.cp-wrap-top .cp-preview,.cp-wrap-top .cp-side{height:calc(100vh - 176px)}
.cp-top-sw{cursor:pointer;color:var(--text3)}
.cp-top-sw:has(input:checked){background:var(--gold-bg);border-color:var(--gold-border);color:var(--gold2)}
.cp-top-zoom{margin-left:auto}
.cp-top-zoom .cp-vb-pct{box-shadow:none;margin-left:4px}
.cp-pop{position:absolute;z-index:40;width:300px;max-height:calc(100vh - 190px);overflow:auto;padding:10px 12px;
  background:var(--bg2);border:1px solid var(--border2);border-radius:10px;box-shadow:0 10px 30px rgba(0,0,0,.35)}
.cp-pop[hidden]{display:none}
.cp-pop .cp-sub{white-space:normal;overflow:visible;text-overflow:clip}
.cp-pop-h{margin:0 0 6px;font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--text3)}
.cp-hd .page-hd-actions .btn.sm{gap:5px}
@media (max-width:1180px){
  .cp-wrap.cp-wrap-top{grid-template-columns:minmax(0,1fr) 220px}
  .cp-wrap-top .cp-side-r{grid-column:2;grid-row:2}
  .cp-wrap-top .cp-view{grid-column:1;grid-row:2}
}
@media (max-width:880px){
  .cp-wrap.cp-wrap-top{grid-template-columns:1fr}
  .cp-wrap-top .cp-view,.cp-wrap-top .cp-side-r{grid-column:1;grid-row:auto}
  .cp-wrap-top .cp-preview,.cp-wrap-top .cp-side{height:auto}
  .cp-pop{width:min(300px,calc(100vw - 40px))}
}
.cp-side{padding:12px;background:var(--bg2);border:1px solid var(--border);border-radius:12px;
  display:flex;flex-direction:column;gap:7px;overflow-y:auto;
  height:calc(100vh - 132px);position:sticky;top:0}
.cp-lbl{display:flex;align-items:baseline;justify-content:space-between;gap:8px;
  font-size:10.5px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;
  color:var(--text3);margin-top:4px}
.cp-lbl b{font-size:11px;color:var(--text2);letter-spacing:0}
/* TWO, THREE OR FOUR ACROSS, NOT A COLUMN. A choice of three is read in
   one glance when it is three tiles side by side and scanned line by
   line when it is a stack — and a stack of three costs three times the
   height in a panel where height is the scarce thing. They wrap on
   their own, so a pair sits as a pair and a long label gets two lines
   rather than an ellipsis. */
.cp-seg{display:flex;flex-wrap:wrap;gap:4px}
.cp-seg-b{flex:1 1 56px;min-width:min-content;min-height:42px;font:inherit;font-size:11.5px;
  font-weight:700;text-align:center;display:flex;align-items:center;justify-content:center;
  background:var(--bg3);border:1px solid var(--border);border-radius:8px;
  padding:6px 7px;color:var(--text2);cursor:pointer;line-height:1.2}
.cp-seg-b:hover{border-color:var(--gold-border);color:var(--text)}
.cp-seg-b.on{background:linear-gradient(135deg,var(--accent-fill),var(--accent-fill2));
  border-color:transparent;color:var(--on-accent)}
.cp-switches{display:flex;flex-direction:column;gap:1px}
.cp-sw{display:flex;align-items:center;gap:8px;font-size:11.5px;font-weight:600;
  color:var(--text2);padding:5px 4px;border-radius:6px;cursor:pointer}
.cp-sw:hover{background:var(--bg3);color:var(--text)}
.cp-sw input{width:15px;height:15px;flex-shrink:0;accent-color:var(--accent2)}

/* The preview. The sheet inside it is transform-scaled from its top
   left, so the box is told how tall the result actually is. */
/* ZOOMED IN, THE LEFT EDGE HAD TO STAY REACHABLE. `justify-content:
   center` on a scrolling flex box centres what fits and CLIPS what does
   not — the overflow goes off the leading edge, where no scrollbar can
   ever reach it, so a sheet zoomed past the width of the box lost its
   left-hand side for good. `margin:auto` on a single child centres the
   same way and overflows in BOTH directions, which is the whole
   difference. Hence the wrapper: one child to centre, however many
   pages are inside it. */
.cp-preview{position:relative;padding:13px;overflow:auto;background:var(--bg3);
  border:1px solid var(--border);border-radius:12px;display:flex;
  height:calc(100vh - 132px);min-height:320px}
.cp-pages{margin:auto;display:flex;flex-direction:column;align-items:center;gap:14px}
/* The sheet is transform-scaled, which leaves its FULL size in the
   layout — so it sits in a stage sized to the scaled result, and the
   ordinary centring above works on that. */
.cp-stage{position:relative;flex:0 0 auto;margin:auto}
.cp-stage > .cp-sheet{position:absolute;top:0;left:0;transform-origin:top left}
/* THE MARGIN GUIDES. Magenta, the colour every layout programme uses,
   one per side over the sheet at the line the cards keep to; in
   fractions of the stage so the preview's zoom never moves them. The
   line is one pixel, the grab is nine; a side that has been given a
   margin says how much on a small tag. See cpWireGuides(). */
.cp-guides{position:absolute;inset:0;z-index:6;pointer-events:none;overflow:visible}
.cp-guide{position:absolute;pointer-events:auto;touch-action:none}
.cp-guide::before{content:'';position:absolute;background:#e11dbb;opacity:.55}
.cp-guide:hover::before,.cp-guide.set::before{opacity:.95}
.cp-guide-t,.cp-guide-b{left:0;right:0;height:9px;margin-top:-4px;cursor:row-resize}
.cp-guide-l,.cp-guide-r{top:0;bottom:0;width:9px;margin-left:-4px;cursor:col-resize}
.cp-guide-t::before,.cp-guide-b::before{left:0;right:0;top:4px;height:1px}
.cp-guide-l::before,.cp-guide-r::before{top:0;bottom:0;left:4px;width:1px}
.cp-guide i{position:absolute;font:700 9.5px/1 system-ui,sans-serif;font-style:normal;color:#fff;background:#e11dbb;
  padding:2px 4px;border-radius:3px;white-space:nowrap;pointer-events:none}
.cp-guide i:empty{display:none}
.cp-guide-t i{left:50%;top:6px;transform:translateX(-50%)}
.cp-guide-b i{left:50%;bottom:6px;transform:translateX(-50%)}
.cp-guide-l i{top:50%;left:6px;transform:translateY(-50%)}
.cp-guide-r i{top:50%;right:6px;transform:translateY(-50%)}
.cp-busy{margin:auto;font-size:12px;font-weight:700;color:var(--text3);padding:40px 0}

/* ── THE SHEET ── */
/* WHERE THE CARDS STAND. --cp-edge is the printer's strip outside the
   trim (0 unless bleed and crop marks are on) and --cp-safe the safe
   distance inside it, both set on the sheet by cpBuildSheet(): the
   heading, the key, the closures box, the insets and the profile band
   all stand at --cp-off from the paper's edge, and the sheet grown for
   a printer moves none of them against the trim. */
.cp-sheet{--cp-off:calc(var(--cp-edge,0px) + var(--cp-safe,14px));
  /* and per side, with the extra room a bound page keeps on its inner
     edge (cpExtra()): the four fall back to the plain distance */
  --cp-off-t:var(--cp-off);--cp-off-r:var(--cp-off);--cp-off-b:var(--cp-off);--cp-off-l:var(--cp-off);
  position:relative;background:#fff;color:#1f2937;overflow:hidden;
  /* The edition's merkset sets --cp-font-body / --cp-font-head on the
     sheet (cpBrandVars()); without one the sheet is in the system face. */
  font-family:var(--cp-font-body,system-ui,-apple-system,'Segoe UI',sans-serif);
  box-shadow:0 6px 24px rgba(0,0,0,.35)}
/* The map is the sheet; the title and the profile are bands laid on it,
   on a white ground so they stay readable over a street plan. */
.cp-sheet .cp-map{position:absolute;inset:0;display:block}
/* THE CORNER CARD, AND WHICH SIDE THE MARKS SIT ON. The logos and the
   stage stand SIDE BY SIDE, with the logos always on the inward side —
   heading in the right corner, marks to its left; heading in the left
   corner, marks to its right. Stacked above the words they hung off the
   outer edge with a hole under them, because the two boxes are never
   the same width; beside them they read as one card, and the pair grows
   into the middle of the sheet instead of into the margin. */
/* THE TWO BOXES ARE THE SAME HEIGHT. `flex-start` let each one be as
   tall as it happened to need, so the marks sat in a short card beside
   a tall one and the pair read as two things that had drifted together
   rather than as one heading. `stretch` makes the shorter one match,
   and the logo inside it is centred in whatever height that turns out
   to be. */
/* ── THE HEADING CARD HAS TWO DIALS ───────────────────────────
   --cp-head multiplies every measurement in this block — type, padding
   and the two elevation marks alike — so the card grows as one thing
   instead of as bigger words in the same box.

   --cp-head-ts then multiplies THE LETTERING ONLY, on top of it. The
   two are not the same want. How big the card is, is a question about
   the sheet: how much of the map it may stand on. How big the words in
   it are, is a question about the words: a race whose name runs to
   forty characters wants smaller type in the same card, and a sheet
   pinned on a wall wants larger type without the box growing to eat the
   start town. One dial could only ever answer one of them.

   Both are written into the computed style rather than applied as a
   transform: cpSheetSvg() writes this band out as SVG by reading the
   boxes off the DOM and the type off the computed style, and a
   transform moves only the first of those.

   The QR square is deliberately NOT in it. It is a target for a camera
   rather than something read, and a code shrunk with the card is a code
   that stops scanning. */
.cp-sheet .cp-head{position:absolute;left:var(--cp-off-l);top:var(--cp-off-t);z-index:2;
  display:flex;flex-direction:row-reverse;align-items:stretch;
  gap:calc(8px * var(--cp-head,1));max-width:62%}
.cp-sheet .cp-head.right{left:auto;right:var(--cp-off-r);flex-direction:row;text-align:right}
.cp-sheet .cp-head-logos,.cp-sheet .cp-head-txt{background:#fff;border-radius:3px;
  box-shadow:0 1px 6px rgba(15,23,42,.18)}
.cp-sheet .cp-head-logos{padding:calc(9px * var(--cp-head,1)) calc(12px * var(--cp-head,1));flex:0 0 auto;
  display:flex;align-items:center;justify-content:center}
.cp-sheet .cp-head-txt{flex:0 1 auto;min-width:0}
/* The padding moved INSIDE, onto the plate and the body separately: the
   title band has to run to the edges of the card, and overflow clips it
   to the card's own rounded corners. */
.cp-sheet .cp-head-txt{padding:0;overflow:hidden}
.cp-sheet .cp-head-bar{padding:calc(8px * var(--cp-head,1)) calc(14px * var(--cp-head,1)) calc(9px * var(--cp-head,1))}
/* Three columns need a floor under the card that two did not: below
   about 250 px "20.5 km" stops fitting on one line in its own box and
   the third figure is clipped. A short race name therefore makes a
   slightly wider card than it used to, which is the price of the row. */
.cp-sheet .cp-head-body{padding:calc(9px * var(--cp-head,1)) calc(14px * var(--cp-head,1)) calc(11px * var(--cp-head,1));
  min-width:calc(250px * var(--cp-head,1))}
.cp-sheet .cp-head h1{margin:0;font-size:calc(18px * var(--cp-head,1) * var(--cp-head-ts,1));font-weight:800;letter-spacing:-.01em;
  color:#0f172a;line-height:1.15;font-family:var(--cp-font-head,inherit)}
/* On the plate the lettering is whatever reads on that colour, which the
   sheet works out and writes on the element — see cpOnInk(). */
.cp-sheet .cp-head-bar h1{color:inherit}
.cp-sheet .cp-head p{margin:calc(3px * var(--cp-head,1)) 0 0;font-size:calc(11px * var(--cp-head,1) * var(--cp-head-ts,1));
  font-weight:600;color:#6b7280}
.cp-sheet .cp-head-sub{margin-top:0!important}
/* WHAT THE DISTANCE IS MADE OF, UNDER THE FIGURES. How many times round
   and how much of it is neutralised are not figures of the same kind as
   the three in the boxes — they are the sentence explaining one of them.
   Quiet, italic, and free to wrap, which is what a long lap note needs
   and what it could never do while it rode on the distance's own line. */
.cp-sheet .cp-head-note{margin:calc(6px * var(--cp-head,1)) 0 0!important;
  font-size:calc(9.5px * var(--cp-head,1) * var(--cp-head-ts,1))!important;
  font-weight:600;font-style:italic;color:#94a3b8;line-height:1.3}

/* ── HOW FAR, HOW MUCH UP, HOW MUCH DOWN — A BOX EACH ──
   Equal columns, so no one of the three reads as the important one. How
   many boxes there are is on the row: three where the course carries
   both elevations, two where it carries one, one where it carries
   neither and the distance stands alone. */
.cp-sheet .cp-head-stats{display:grid;gap:calc(6px * var(--cp-head,1));
  margin-top:calc(8px * var(--cp-head,1))}
.cp-sheet .cp-head-stats.three{grid-template-columns:1fr 1fr 1fr}
.cp-sheet .cp-head-stats.two{grid-template-columns:1fr 1fr}
.cp-sheet .cp-head-stats.one{grid-template-columns:1fr;max-width:50%}
/* THE MARK OVER THE FIGURE. It stood beside it while the distance was a
   line above: three figures on one line each made a block wider than it
   was tall, all of it air to the right of the numbers. With the distance
   down here as the third box the row can afford the second line — and
   stacked, each box is nearer square, the figure can carry more weight,
   and the three read as one row of three rather than as a strip. */
.cp-sheet .cp-head-stat{display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:calc(3px * var(--cp-head,1));
  padding:calc(7px * var(--cp-head,1)) calc(6px * var(--cp-head,1)) calc(8px * var(--cp-head,1));
  border:1px solid #e2e8f0;border-radius:5px;background:#f8fafc}
.cp-sheet .cp-head-stat b{font-size:calc(13.5px * var(--cp-head,1) * var(--cp-head-ts,1));font-weight:800;color:#0f172a;line-height:1;
  white-space:nowrap}
/* Their size is a width attribute on the SVG the sheet writes; CSS
   overrides it, which is what carries them along with the card. */
.cp-sheet .cp-elev-line{display:block;flex:0 0 auto}
.cp-sheet .cp-elev-badge{display:block;flex:0 0 auto}
/* The marks follow the lettering as well as the box: they stand beside
   the figures, and a mark left behind at full size while the figure
   shrank is the box looking broken rather than smaller. */
.cp-sheet .cp-head .cp-elev-line{width:calc(20px * var(--cp-head,1) * var(--cp-head-ts,1));
  height:calc(20px * var(--cp-head,1) * var(--cp-head-ts,1))}
.cp-sheet .cp-head .cp-elev-badge{width:calc(14px * var(--cp-head,1) * var(--cp-head-ts,1));
  height:calc(14px * var(--cp-head,1) * var(--cp-head-ts,1))}

/* The key, boxed, in the bottom-left corner. */
.cp-sheet .cp-key{position:absolute;left:var(--cp-off-l);bottom:calc(var(--cp-foot-h,0px) + var(--cp-edge,0px) + 12px);z-index:3;background:#fff;border-radius:3px;
  box-shadow:0 1px 6px rgba(15,23,42,.18);overflow:hidden;min-width:150px;max-width:34%}
.cp-sheet .cp-key-hd{background:var(--cp-brand,#0f172a);color:var(--cp-brand-on,#fff);font-family:var(--cp-font-head,inherit);font-size:8.5px;font-weight:800;
  text-transform:uppercase;letter-spacing:.1em;text-align:center;padding:4px 10px}
.cp-sheet .cp-key-rows{display:flex;flex-direction:column;gap:5px;padding:8px 11px 9px;
  font-size:8.5px;font-weight:700;color:#374151}
.cp-sheet .cp-key-rows span{display:flex;align-items:center;gap:7px}
/* Every swatch is drawn rather than styled — see the key block in
   js/course-print.js. All this has to do is keep them the same size
   and stop them shrinking when a label is long. */
.cp-sheet .cp-key-sw{width:22px;height:12px;flex-shrink:0;display:block;object-fit:contain}
.cp-sheet img.cp-key-sw{height:14px}
/* ── AND THE KEY HAS ITS OWN ───────────────────────────────────
   Scoped to .cp-key rather than written into the rules above, because
   the closure table for the police sheet borrows those same rules and
   is a different block with a different question. It keeps its size. */
.cp-sheet .cp-key{min-width:calc(150px * var(--cp-key,1))}
.cp-sheet .cp-key .cp-key-hd{font-size:calc(8.5px * var(--cp-key,1));
  padding:calc(4px * var(--cp-key,1)) calc(10px * var(--cp-key,1))}
.cp-sheet .cp-key .cp-key-rows{gap:calc(5px * var(--cp-key,1));
  padding:calc(8px * var(--cp-key,1)) calc(11px * var(--cp-key,1)) calc(9px * var(--cp-key,1));
  font-size:calc(8.5px * var(--cp-key,1))}
.cp-sheet .cp-key .cp-key-rows span{gap:calc(7px * var(--cp-key,1))}
.cp-sheet .cp-key .cp-key-sw{width:calc(22px * var(--cp-key,1));height:calc(12px * var(--cp-key,1))}
.cp-sheet .cp-key img.cp-key-sw{height:calc(14px * var(--cp-key,1))}
/* A layer that carries several signs is a heading with the signs
   under it, stepped in — see the key block in js/course-print.js. */
.cp-sheet .cp-key-rows .cp-key-grp{font-weight:800;color:#0f172a;margin-top:calc(2px * var(--cp-key,1))}
.cp-sheet .cp-key-rows .cp-key-in{padding-left:calc(9px * var(--cp-key,1))}
/* A hand-placed sign on its coloured plate, the way it stands on the sheet. */
.cp-sheet .cp-key-rows .cp-key-plate{width:calc(18px * var(--cp-key,1));height:calc(18px * var(--cp-key,1));
  border-radius:50%;justify-content:center;flex-shrink:0;border:1px solid #fff;gap:0}
.cp-sheet .cp-key-rows .cp-key-plate img.cp-key-sw{width:calc(13px * var(--cp-key,1));height:calc(13px * var(--cp-key,1))}
/* The closure table for the police sheet: the key's twin in the top
   corner the title card is not in, one line per section, hours first. */
.cp-sheet .cp-clos{background:#fff;border-radius:3px;
  box-shadow:0 1px 6px rgba(15,23,42,.18);overflow:hidden;min-width:170px;max-width:34%}
/* The passage times: the same card, a table inside. */
.cp-sheet .cp-times{background:#fff;border-radius:3px;box-shadow:0 1px 6px rgba(15,23,42,.18);overflow:hidden;min-width:190px;max-width:38%}
.cp-sheet .cp-times-tbl{border-collapse:collapse;width:100%;font-size:7.6px;line-height:1.25}
.cp-sheet .cp-times-tbl th{font-size:6.6px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:#64748b;text-align:left;padding:5px 6px 3px;border-bottom:1px solid #e2e8f0;white-space:nowrap}
.cp-sheet .cp-times-tbl td{padding:2px 6px;border-bottom:1px solid #f1f5f9;color:#1f2937;white-space:nowrap;max-width:120px;overflow:hidden;text-overflow:ellipsis}
.cp-sheet .cp-times-tbl .n,.cp-sheet .cp-times-tbl th:not(:first-child){text-align:right;font-variant-numeric:tabular-nums}
.cp-sheet .cp-times-tbl tbody tr:first-child td,.cp-sheet .cp-times-tbl tbody tr:last-child td{font-weight:800}
.cp-sheet .cp-times-more{margin:2px 6px 4px;font-size:7px;color:#64748b}
.cp-sheet .cp-clos-rows{gap:3px}
.cp-sheet .cp-clos-rows b{font-variant-numeric:tabular-nums;color:#0f172a;flex-shrink:0}
.cp-sheet .cp-clos-day{font-size:8px;text-transform:uppercase;letter-spacing:.08em;color:#64748b;margin-top:3px}

/* ── ONE DRAWER PER QUESTION ──
   Each group of settings is a <details>, so a sheet that never needs
   distance boards is a sheet whose panel does not carry them. The
   summary is the only thing left when a drawer is shut, so it reads as
   a heading rather than as a control: same size and weight as the
   labels inside it, with a chevron that turns.

   The marker is removed on both spellings — Safari still wants
   ::-webkit-details-marker and would otherwise print a second
   triangle beside this one. */
.cp-sec{border-top:1px solid var(--border);padding-top:7px;margin-top:1px}
.cp-sec:first-of-type{border-top:0;padding-top:0;margin-top:0}
.cp-sec > summary{display:flex;align-items:center;gap:6px;cursor:pointer;
  list-style:none;font-size:10.5px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;color:var(--text2);padding:3px 0;user-select:none}
.cp-sec > summary::-webkit-details-marker{display:none}
.cp-sec > summary::marker{content:''}
.cp-sec > summary::before{content:'';flex:0 0 auto;width:0;height:0;
  border-left:4px solid currentColor;border-top:3.5px solid transparent;
  border-bottom:3.5px solid transparent;transition:transform .12s ease}
.cp-sec[open] > summary::before{transform:rotate(90deg)}
.cp-sec > summary:hover{color:var(--text)}
.cp-sec-b{display:flex;flex-direction:column;gap:7px;padding:2px 0 6px}
/* The first label in a drawer needs no air above it — the summary is
   already the heading. */
.cp-sec-b > .cp-lbl:first-child{margin-top:0}
.cp-tpl-wrap{display:flex;flex-direction:column;gap:7px;padding-bottom:8px}

/* ── THINGS DRAWN ON BY HAND ──
   The overlay sits over the whole sheet and lets every click through
   EXCEPT on the marks themselves — otherwise a full-page transparent
   layer would swallow the scroll and every other click on the preview.
   The marks take the pointer back so they can be dragged. */
.cp-sheet .cp-notes{position:absolute;inset:0;z-index:4;pointer-events:none}
.cp-sheet .cp-notes .cp-note{pointer-events:auto;cursor:move}
.cp-sheet .cp-notes .cp-note-h{cursor:nwse-resize}
/* On paper there is nothing to drag, and a grip printed in the corner
   of every box would be a mark nobody drew. */
body.cprint-on .cp-notes .cp-note-h{display:none}

/* ── A FLOATING PALETTE ───────────────────────────────────────
   CONTROLS THAT ARE USED WHILE LOOKING AT SOMETHING BELONG BESIDE IT,
   not in a column beside it or a menu over it. Two places need that and
   they need exactly the same furniture, so the furniture is here once:
   the print sheet's drawing tools, and the map's waypoint layers.

   Both were the wrong shape before. The drawing tools sat 230 pixels
   wide in the settings column with the sheet off to the right, so a
   caption's own toolbar ran off the edge of it. The layers were a menu
   that shut itself the moment another menu opened — and picking layers
   is the one thing on that map you do WHILE panning around, so it shut
   every time it was being used.

   So they float, the way every drawing program has done it since the
   first palette: a small panel over the work, dragged by its bar to
   wherever it is not in the way, left open for as long as it is wanted.
   Where it was put is remembered, because a palette that jumps back to
   the middle of the screen every time is a palette nobody moves. */
.pal{position:fixed;z-index:60;width:300px;max-width:calc(100vw - 20px);
  background:var(--bg2);border:1px solid var(--border);border-radius:10px;
  box-shadow:0 16px 44px rgba(0,0,0,.45);display:flex;flex-direction:column;
  max-height:min(72vh,660px)}
.pal[hidden]{display:none!important}
/* The bar is the handle. touch-action:none so a drag on a phone moves
   the palette instead of scrolling the page behind it. */
.pal-hd{display:flex;align-items:center;gap:6px;padding:8px 8px 8px 12px;
  border-bottom:1px solid var(--border);cursor:grab;touch-action:none;
  user-select:none;-webkit-user-select:none}
.pal-hd:active{cursor:grabbing}
.pal-hd > b{flex:1 1 auto;min-width:0;font-size:9.5px;font-weight:800;
  text-transform:uppercase;letter-spacing:.07em;color:var(--text2);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pal-bd{padding:11px 12px 13px;overflow:auto;display:flex;
  flex-direction:column;gap:9px}
/* ── THE LAYERS PALETTE WEARS THE MENU'S OWN SURFACE ──────────
   IT CAME OUT WHITE ON WHITE. Everything inside it — the group label,
   the All/None pair, the layer rows, the manage button — was written
   for .map-pop above: a dark translucent plate over the map, with text
   colours to match. Dropped onto a panel painted var(--bg2), which is
   white in the light theme, every one of those colours became invisible
   and the palette read as an empty card.

   The content is not restyled; the SURFACE is. Same plate, same blur,
   same border as the menu these controls have always lived in — so
   nothing inside has to know it moved, and the two cannot drift apart
   the next time either is touched. */
.pal.map-pal{width:272px;background:rgba(3,37,42,.94);backdrop-filter:blur(14px);
  border-color:rgba(125,190,188,.28)}
.pal.map-pal .pal-hd{border-bottom-color:rgba(125,190,188,.22)}
.pal.map-pal .pal-hd > b{color:rgba(232,238,252,.72)}
/* The close button wore the light theme's white plate — a bright square
   on a dark bar with an invisible cross in it. On this surface it is a
   small, borderless mark like the menu's own. */
.pal.map-pal .pal-hd .icon-btn{width:28px;height:28px;padding:0;border-radius:7px;
  background:transparent;border:1px solid rgba(125,190,188,.22);color:rgba(232,238,252,.78);
  box-shadow:none}
.pal.map-pal .pal-hd .icon-btn svg{width:14px;height:14px}
.pal.map-pal .pal-hd .icon-btn:hover{color:#fff;background:rgba(255,255,255,.10);
  border-color:rgba(125,190,188,.45)}
.pal.map-pal .pal-bd{padding:0 0 4px}
.pal.map-pal .mo-group{padding:11px 12px 12px;margin:0}
/* A layer badge that is a drawing rather than a glyph. A file that will
   not load draws nothing at all rather than the browser's broken-image
   glyph, which reads as a layer that is somehow damaged. */
.poi-lay-img{display:block;width:18px;height:18px;object-fit:contain}
.poi-lay-img:not([src]),.poi-lay-img[src=""]{display:none}
/* The door back in, where the tools used to stand. */
.cp-pal-open{width:100%;justify-content:center}

/* The panel's own verb, under the import box and over the list. */
.mp-add-layer{width:calc(100% - 24px);margin:0 12px 10px;justify-content:center}

/* Naming a layer from inside the waypoint that wants it. */
.poi-lay-new{display:flex;gap:6px;margin-top:6px}
.poi-lay-new .input{flex:1 1 auto;min-width:0}
.poi-lay-new .btn{flex:0 0 auto}

.cp-note-add{display:flex;gap:6px;flex-wrap:wrap}
.cp-note-add .btn{flex:1 1 0;min-width:0;padding:6px 8px}
/* The image mark is a label round a file input, so it needs told to
   stand like the three buttons it stands next to. */
.cp-note-add .cp-note-img{justify-content:center;cursor:pointer}
.cp-note-list{display:flex;flex-direction:column;gap:6px}
.cp-note-list:empty{display:none}
.cp-note-row{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
/* A box's fill drops to a line of its own: four controls will not fit
   across a 230-pixel column, and the fill is the one usually left
   alone. */
.cp-note-sub{flex:1 1 100%;display:flex;align-items:center;gap:6px;flex-wrap:wrap;
  padding-left:46px;font-size:10px;font-weight:700;color:var(--text3);
  text-transform:uppercase;letter-spacing:.05em}
.cp-note-none{font-size:10px;font-weight:700;color:var(--text3)}
/* Bold, italic, underline: three little buttons that look like what
   they do, so the row needs no labels. */
.cp-note-b{flex:0 0 auto;width:24px;height:26px;font-size:12px;background:var(--bg3);
  border:1px solid var(--border);border-radius:5px;color:var(--text2);cursor:pointer;
  text-transform:none;letter-spacing:0;line-height:1}
.cp-note-b.f-bold{font-weight:800}
.cp-note-b.f-italic{font-style:italic;font-family:Georgia,serif}
.cp-note-b.f-underline{text-decoration:underline}
.cp-note-b:hover{border-color:var(--gold-border);color:var(--text)}
.cp-note-b.on{background:linear-gradient(135deg,var(--accent-fill),var(--accent-fill2));
  border-color:transparent;color:var(--on-accent)}
.cp-note-sub select{flex:1 1 60px;min-width:0;padding:4px 5px;font-size:11px}
/* The key's line under a sign, an arrow or a box: the plate colour
   (signs), the tick that lists it, and the name it is listed as. */
.cp-note-key{text-transform:none;letter-spacing:0}
.cp-note-key .input[type=text]{flex:1 1 80px;min-width:0;padding:4px 6px;font-size:11px}
.cp-note-tick{display:inline-flex;align-items:center;gap:4px;flex:0 0 auto;cursor:pointer;
  font-size:10px;font-weight:700;color:var(--text2)}
.cp-note-tick input{margin:0;accent-color:var(--gold,#f59e0b)}
/* The chosen sign, next to the list of their file names — which on
   their own say nothing about what the sign looks like. */
.cp-note-ico{flex:0 0 auto;width:26px;height:26px;object-fit:contain;
  background:#fff;border:1px solid var(--border);border-radius:5px;padding:2px}
.cp-note-ico.empty{display:block}
/* The profile downloads: a name and two formats, per stretch. */
.cp-dl{display:flex;flex-direction:column;gap:4px}
.cp-dl-row{display:flex;align-items:center;gap:5px}
.cp-dl-row > span{flex:1 1 auto;min-width:0;font-size:11.5px;font-weight:700;
  color:var(--text2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cp-dl-row .btn{flex:0 0 auto;padding:4px 8px;font-size:10.5px}
/* A swatch with no fill behind it says so with a stroke through it,
   which is the one thing a native colour input cannot show. */
.cp-note-col.off{position:relative;opacity:.5}
.cp-note-col.off::after{content:'';position:absolute;inset:-1px;border-radius:5px;
  background:linear-gradient(to top right,transparent 44%,var(--text3) 44%,
    var(--text3) 56%,transparent 56%);pointer-events:none}
.cp-note-row .input{min-width:0;flex:1 1 auto;padding:5px 7px;font-size:12px}
.cp-note-k{flex:0 0 auto;font-size:9.5px;font-weight:800;text-transform:uppercase;
  letter-spacing:.06em;color:var(--text2);width:46px}
.cp-note-sp{flex:1 1 auto}
.cp-note-col{flex:0 0 auto;width:26px;height:26px;padding:0;border:1px solid var(--border);
  border-radius:5px;background:none;cursor:pointer}
.cp-note-sz{flex:0 0 52px!important;text-align:center}
/* The four margins, one row: a word over a number, top-right-bottom-left
   the way a stylesheet reads them. */
.cp-margins{display:grid;grid-template-columns:repeat(4,1fr);gap:6px}
.cp-margins label{display:flex;flex-direction:column;gap:2px;min-width:0}
.cp-margins span{font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--text2)}
.cp-margins .input{min-width:0;padding:5px 6px;font-size:12px;text-align:center}

/* The template row: the picker takes the room, the two buttons take
   what they need. */
.cp-tpl{display:flex;align-items:center;gap:6px}
.cp-tpl select{flex:1 1 auto;min-width:0}
.cp-tpl .btn{flex:0 0 auto;padding:6px 8px}

/* THE BLOWN-UP STRETCHES, IN THE CORNER OPPOSITE THE HEADING. It is the
   only corner of the sheet that is reliably free: the key holds the
   bottom left and the scale bar and north arrow the bottom right, and
   the heading holds whichever top corner it was sent to. They stack
   downwards from there, so a finish map and a lap map can stand
   together without either being told about the other. */
.cp-sheet .cp-insets{position:absolute;top:var(--cp-off-t);right:var(--cp-off-r);z-index:3;
  display:flex;flex-direction:column;gap:8px;align-items:flex-end;max-width:40%}
.cp-sheet .cp-insets.left{right:auto;left:var(--cp-off-l);align-items:flex-start}
.cp-sheet .cp-inset{background:#fff;border-radius:3px;overflow:hidden;
  box-shadow:0 1px 6px rgba(15,23,42,.18)}
.cp-sheet .cp-inset-t{background:var(--cp-brand,#0f172a);color:var(--cp-brand-on,#fff);font-family:var(--cp-font-head,inherit);font-size:8.5px;font-weight:800;
  text-transform:uppercase;letter-spacing:.1em;padding:4px 10px;
  display:flex;align-items:center;justify-content:center;gap:8px}
/* "4 ×" — how many times round, which is the whole point of a lap map
   and the one thing a finish map has nothing to say about. */
.cp-sheet .cp-inset-t b{background:#fff;color:#0f172a;border-radius:2px;
  padding:0 4px;font-size:8.5px;letter-spacing:0}
.cp-sheet .cp-inset-map{display:block}
.cp-sheet .cp-inset-prof{padding:3px 6px 5px}
.cp-sheet .cp-inset-prof .rp-stats{display:none}

/* The QR square, on the outer edge of the head card. */
.cp-sheet .cp-head-qr{background:#fff;border-radius:3px;padding:6px;flex:0 0 auto;
  box-shadow:0 1px 6px rgba(15,23,42,.18);line-height:0}
.cp-sheet .cp-head-qr svg{display:block}
.cp-sheet .cp-head-qr-txt{display:block;max-width:110px;font-size:7px;font-weight:700;
  line-height:1.3;color:#6b7280;word-break:break-all}

/* The profile band, with the blown-up finish beside it rather than
   under it — the shape of every printed stage map's foot. */
/* The partners' strip: a white band along the foot, above the
   maker's mark, the profile band standing on it. */
.cp-sheet .cp-partners{position:absolute;left:0;right:0;bottom:calc(var(--cp-credit-h,17px) + var(--cp-edge,0px));z-index:2;
  display:flex;align-items:center;justify-content:center;gap:calc(22px * var(--cp-partner,1));flex-wrap:wrap;
  padding:6px var(--cp-off-r) 6px var(--cp-off-l);background:#fff}
.cp-sheet .cp-partners img{height:calc(26px * var(--cp-partner,1));width:auto;max-width:calc(120px * var(--cp-partner,1));object-fit:contain}
.cp-sheet .cp-foot{position:absolute;left:0;right:0;bottom:calc(var(--cp-credit-h,17px) + var(--cp-partners-h,0px) + var(--cp-edge,0px));z-index:2;
  display:flex;align-items:flex-end;gap:12px;padding:8px var(--cp-off-r) 10px var(--cp-off-l);
  background:linear-gradient(0deg,#fff 0%,#fff 86%,rgba(255,255,255,0) 100%)}
.cp-sheet .cp-profile{flex:1 1 auto;min-width:0;padding:0}
.cp-sheet .cp-zooms{flex:0 0 auto;width:31%;display:flex;flex-direction:column;gap:3px;margin:0}
.cp-sheet .cp-place circle{fill:#374151}
.cp-sheet .cp-place text{fill:#1f2937;paint-order:stroke;stroke:#fff;stroke-width:2.4px;
  stroke-linejoin:round}
.cp-sheet .cp-km text,.cp-sheet .cp-chip text{paint-order:normal}
.cp-sheet .cp-profile .rp-yax,.cp-sheet .cp-profile .rp-xax{color:#6b7280}
.cp-sheet .cp-profile .elev-grid{stroke:#e2e8f0}
.cp-sheet .cp-profile .rp-stats{display:none}
.cp-sheet .cp-fail{position:absolute;left:0;right:0;top:50%;text-align:center;
  font-size:11px;color:#9ca3af;z-index:1}
/* The road names are drawn into the map layer with their own halo — all
   this does is keep them from being selected with a stray drag. */
.cp-sheet .cp-road-name{pointer-events:none}

/* ── ON PAPER ──
   The sheet is moved to a container of its own on the body and
   everything else on the page is taken out of the flow for the
   duration; @page is written by cpPrint() because the size depends on
   which way round the course runs. */
#cprint-sheet{display:none}
body.cprint-on > *:not(#cprint-sheet){display:none!important}
body.cprint-on #cprint-sheet{display:block}
body.cprint-on #cprint-sheet .cp-sheet{box-shadow:none;transform:none}
/* A SHEET ON ITS PAPER, WITH MARGINS (cpOnPaper): the paper is a page
   of its own, white, and the drawing — a whole .cp-sheet or a bare
   profile — sits in a frame set in from its edges and scaled to fit.
   The scale is on the FRAME, never on the sheet: the rule above
   strips every transform off a printed sheet, on purpose. */
.cp-paper{background:#fff;overflow:hidden}
.cp-paper > .cp-fit{position:absolute;transform-origin:top left}
.cp-paper > .cp-fit > .cp-sheet{box-shadow:none}
.cp-paper > .cp-fit > svg{display:block}
.cprint-hidden{position:fixed;left:-20000px;top:0;pointer-events:none;opacity:0}
/* WHAT THE PRINTER IS TOLD TO KEEP. A browser drops background colour
   by default — it treats a filled box as decoration — so the key's dark
   plate came out of the printer as white paper with white lettering on
   it, and so did the green start chip and the band under the profile.
   This is the declaration that overrules that, and because it inherits,
   putting it on the sheet puts it on everything drawn inside the sheet.
   Outside @media print as well: a browser asked to "save as PDF" is
   printing, and so is the preview. */
#cprint-sheet, .cp-sheet{-webkit-print-color-adjust:exact; print-color-adjust:exact}
@media print{
  body.cprint-on{background:#fff!important;margin:0;padding:0}
  #cprint-sheet .cp-sheet{box-shadow:none}
  /* A run of the whole edition is one job of many pages, so each sheet
     ends its own page and none of them is split across two. */
  #cprint-sheet .cp-sheet{break-after:page;page-break-after:always;
    break-inside:avoid;page-break-inside:avoid}
  #cprint-sheet .cp-sheet:last-child{break-after:auto;page-break-after:auto}
  /* The sheet set on its paper is not a page of its own: the paper is. */
  #cprint-sheet .cp-paper .cp-sheet{break-after:auto;page-break-after:auto}
}
@media (max-width:860px){
  .cp-wrap{grid-template-columns:1fr}
  .cp-side{border-right:0;border-bottom:1px solid var(--border);max-height:none}
}

/* ═══════════ A STRETCH PICKED OFF A PROFILE ═══════════
   The overlay wireProfileSelect() lays over every profile in the app —
   the course map's card, the dashboard's copy and the race cards'. HTML
   over the picture rather than shapes inside it: these drawings are
   preserveAspectRatio="none" and anything drawn in them is squeezed to
   whatever width the strip lands in. See js/elevation.js. */
.pf-sel{position:absolute;inset:0;pointer-events:none;z-index:4}
.pf-sel[hidden]{display:none}
.pf-sel-band{position:absolute;top:0;bottom:0;background:rgba(234,179,8,.16);
  border-left:1px solid rgba(234,179,8,.55);border-right:1px solid rgba(234,179,8,.55)}
.pf-grip{position:absolute;top:0;bottom:0;width:18px;margin-left:-9px;
  pointer-events:auto;cursor:ew-resize;touch-action:none}
.pf-grip::before{content:'';position:absolute;left:8px;top:0;bottom:0;width:2px;background:#eab308}
.pf-grip i{position:absolute;left:50%;top:50%;width:11px;height:22px;margin:-11px 0 0 -5.5px;
  border-radius:5px;background:#eab308;border:1px solid #02060f;box-shadow:0 1px 4px rgba(0,0,0,.5)}
.pf-grip:hover i{background:#facc15}
/* The clear cross sits at the end of the numbers row it belongs to. */
.pf-sel-x{margin-left:auto;border:0;background:transparent;color:var(--text3);cursor:pointer;
  font-size:16px;line-height:1;padding:0 4px;border-radius:5px;align-self:center}
.pf-sel-x:hover{color:var(--text);background:var(--bg4)}
/* And the same three numbers on the gold line itself, on the map. */
.pf-sel-marker{background:#eab308;color:#1a1400;font-size:10.5px;font-weight:800;
  padding:3px 8px;border-radius:999px;white-space:nowrap;pointer-events:none;
  box-shadow:0 2px 8px rgba(0,0,0,.45);border:1px solid rgba(0,0,0,.25)}

/* The print panel's later half: which waypoint layers, the finish
   blow-ups, the heading and the marks that go beside it. */
.cp-in{width:100%;font-size:11.5px;padding:6px 9px}
.cp-kind-ico{width:14px;height:14px;object-fit:contain;vertical-align:-2px}
.cp-logo-row{display:flex;flex-wrap:wrap;gap:6px}
.cp-logo-chip{position:relative;display:inline-flex;background:#fff;border:1px solid var(--border);
  border-radius:7px;padding:4px 6px}
.cp-logo-chip img{height:22px;max-width:64px;object-fit:contain;display:block}
.cp-logo-chip button{position:absolute;top:-6px;right:-6px;width:16px;height:16px;border-radius:50%;
  border:0;background:var(--red,#dc2626);color:#fff;font-size:11px;line-height:1;cursor:pointer}
.cp-logo-add{justify-content:flex-start;cursor:pointer}

/* On the sheet: the marks beside the heading, the waypoints on the
   profile, and the blown-up finish under it. */
.cp-sheet .cp-logos{display:flex;align-items:center;gap:12px;flex-shrink:0;
  height:100%;min-height:0}
/* Filling the card it sits in rather than a height picked in advance:
   the card is as tall as the words beside it, which is the whole point.
   `contain` keeps a wide lockup and a square mark both undistorted. */
/* --cp-logo is the dial in "Heading, logos and QR"; 1 is the card's own
   height, which is what this always used to be. */
.cp-sheet .cp-logos img{height:calc(100% * var(--cp-logo,1));
  max-height:calc(100% * var(--cp-logo,1));width:auto;
  max-width:calc(130px * var(--cp-logo,1));
  object-fit:contain;display:block}
/* Except where there is nothing beside them to match — a sheet with
   logos and no title has no second box, and 100% of nothing is nothing. */
.cp-sheet .cp-head-logos:only-child .cp-logos img{
  height:calc(34px * var(--cp-logo,1) * var(--cp-head,1))}
/* WHAT STANDS ON THE ROAD, STANDING OVER IT. At the foot of the picture
   these signs were read as part of the axis; in the sky that rpBand()'s
   headroom opens above the course they are read as things ON the course,
   which is what they are. A hairline drops from each one so the eye can
   carry it down to the line without a ruler. */
/* The hairline runs the WHOLE height of the picture, not fourteen
   pixels of it. A stem that stops in the sky leaves the eye to guess the
   last two thirds of the drop, and on a profile with a dozen signs over
   it the guesses cross. Anchored top and bottom so the line simply fills
   whatever is left under the sign. */
.rp-mark{position:absolute;top:1px;bottom:0;transform:translateX(-50%);pointer-events:none;
  line-height:0;display:flex;flex-direction:column;align-items:center}
.rp-mark img{display:block;width:16px;height:16px;order:1}
.rp-mark b{display:block;font-size:11px;line-height:1;order:1}
/* And its kilometre under the picture, on a row of its own so it cannot
   collide with the round numbers of the axis.

   IT MUST NAME ITS COLUMN. .rp-plot is a two-column grid — altitudes,
   then picture — and this row carried no column, so the grid auto-placed
   it in column ONE: every waypoint kilometre stacked inside the 34px
   altitude gutter, half of each hanging off the left edge, printing as a
   grey smudge beside the axis that nobody could read as a number. The
   axis row below says grid-column:2 for exactly this reason; this row
   forgot to. */
.rp-wpax{grid-column:2;position:relative;height:12px;margin-top:1px}
.rp-wpkm{position:absolute;top:0;transform:translateX(-50%);font-size:8.5px;font-weight:800;
  color:var(--text3);font-variant-numeric:tabular-nums;white-space:nowrap}
.cp-sheet .rp-wpkm{color:#6b7280}
.cp-sheet .cp-zoom{position:relative;padding-top:9px}
.cp-sheet .cp-zoom-t{position:absolute;top:0;left:0;font-size:8px;font-weight:800;
  text-transform:uppercase;letter-spacing:.06em;color:#6b7280}
.cp-sheet .cp-zoom .rp-stats{display:none}

/* ═══════════ THE COURSE AS A FILE ═══════════
   One row per format in js/course-export.js: a heading that opens it,
   the sentence that says what it is for, its own settings, and its own
   download button. Only one open at a time, so the dialogue is a list
   to read rather than six blocks to scroll past. */
.ce-wrap{display:flex;flex-direction:column;gap:12px}
.ce-note{margin:0;font-size:11.5px;color:var(--text3);line-height:1.45}
.ce-rows{display:flex;flex-direction:column}
.ce-row{border-top:1px solid var(--border)}
.ce-row:last-child{border-bottom:1px solid var(--border)}
.ce-row-hd{width:100%;display:flex;align-items:center;justify-content:space-between;gap:10px;
  background:none;border:0;padding:13px 2px;cursor:pointer;font:inherit;font-size:13px;
  font-weight:700;color:var(--text);text-align:left}
.ce-row-hd:hover{color:var(--gold2)}
.ce-row-hd svg{width:15px;height:15px;color:var(--text3);flex-shrink:0}
.ce-row.on .ce-row-hd{color:var(--gold2)}
.ce-row-bd{padding:0 2px 14px;display:flex;flex-direction:column;gap:10px}
.ce-row-bd p{margin:0;font-size:12px;line-height:1.5;color:var(--text2)}
.ce-sw{display:flex;align-items:center;gap:9px;font-size:12px;font-weight:600;
  color:var(--text2);cursor:pointer}
.ce-sw input{width:16px;height:16px;accent-color:var(--accent2);flex-shrink:0}
.ce-speed{display:flex;flex-direction:column;gap:5px;font-size:11.5px;font-weight:600;color:var(--text2)}
.ce-speed span{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.ce-speed b{color:var(--text);font-size:13px;font-weight:800}
.ce-speed input[type=range]{width:100%;accent-color:var(--accent2)}
.ce-dl{align-self:stretch;justify-content:center}
/* The course file, straight off the race card on the schedule. */
.rc-export{padding:5px 10px;min-height:34px;gap:6px;white-space:nowrap}

/* The sheet's ink: the course's own colour first, then the app's own
   palette. See cpInk() in js/course-print.js. */
.cp-inks{display:grid;grid-template-columns:repeat(7,1fr);gap:4px}
.cp-ink{aspect-ratio:1;border-radius:5px;border:2px solid transparent;background:var(--i);
  cursor:pointer;padding:0}
.cp-ink.on{border-color:var(--text);box-shadow:0 0 0 2px var(--bg2)}
/* The gravel sectors' line: each button draws its own line above its
   name, three to a row. */
.cp-gravel-styles .cp-seg-b{flex:1 1 30%;flex-direction:column;gap:4px;min-height:48px}
.cp-gravel-styles svg{width:48px;height:13px;flex-shrink:0;overflow:visible}
/* The gravel sectors' free colour, beside their swatches. */
.cp-gravel-own{display:flex;align-items:center;justify-content:space-between;gap:8px;
  margin-top:8px;font-size:11.5px;font-weight:600;color:var(--text2)}
.cp-gravel-own input{width:44px;height:28px;padding:0;border:1px solid var(--border);
  border-radius:6px;background:none;cursor:pointer}

/* The distance boards, as a grid of the signs themselves — a tick list
   of "25 km, 20 km, 10 km" says nothing about which drawing goes up. */
.cp-sub{margin:2px 0 0;font-size:10.5px;font-weight:700;color:var(--text3)}
/* The contacts list has a .cp-sub of its own (components.css) that clips to
   one line; in the print screen a hint is a sentence and wraps. */
#v-print .cp-sub{white-space:normal;overflow:visible;text-overflow:clip}
/* A word in a hint that does something — "Back to its corner". */
.cp-link{border:0;background:none;padding:0;font:inherit;color:var(--gold2,#fbbf24);cursor:pointer;text-decoration:underline}
/* The key is dragged on the preview; on paper a cursor is nothing.
   So is every sign on the map that carries a drag handle. */
#cp-preview .cp-sheet .cp-key,
#cp-preview .cp-sheet [data-cp-mark]{cursor:move}
/* The name over a row of passage chips. It says WHOSE laps these are —
   the climb's or the feed zone's — so it is the waypoint's own sign and
   its own word, in the ink the switch above uses, with air over it so
   two rows do not read as one long row of numbers. */
.cp-pass-hd{margin-top:9px;color:var(--text2)}
.cp-pass-hd:first-of-type{margin-top:2px}
/* How many times the course rides past THIS point. Two feed zones on one
   sheet are told apart by their names, and by this: fifteen on the town
   circuit, twice on the mountain. */
.cp-pass-n{font-weight:800;color:var(--text3);font-variant-numeric:tabular-nums}
/* Why a point that IS switched on has no row of laps under it. Quieter
   than the rows and set on its own line: it is an answer to a question
   somebody is already asking, not another control. */
.cp-pass-note{margin-top:8px;font-weight:600;line-height:1.45;color:var(--text3)}
/* ── A CHIP IS ONE SIGN ON THE PROFILE ────────────────────────
   Which means it is at a kilometre, and the kilometre is what a reader
   matches against the picture — so that is the figure, big. The count
   across the layer rides above it, small: it answers "the third feed of
   the race" without taking the room the kilometre needs. Wider than the
   plain chips because "110.5" is four figures and a point, and tabular
   so a row of them lines up. */
.cp-lap-km{display:flex;flex-direction:column;align-items:center;justify-content:center;
  min-width:46px;gap:1px;padding:3px 6px;line-height:1}
.cp-lap-km i{font-style:normal;font-size:8.5px;font-weight:800;opacity:.62}
.cp-lap-km b{font-size:11px;font-weight:800;font-variant-numeric:tabular-nums}
.cp-boards{display:grid;grid-template-columns:repeat(4,1fr);gap:4px}
/* ── WHICH TIME ROUND ──────────────────────────────────────────
   One chip per passage of a lap course, dressed like the distance
   markers under them because they answer the same shape of question:
   a row of small yes-or-nos, read as a pattern rather than one by one.
   "Not the first two laps" is a thing a commissaire says, and it has to
   be sayable in one glance. */
.cp-laps{display:flex;flex-wrap:wrap;gap:4px}
.cp-lap{min-width:34px;min-height:34px;padding:0 7px;font:inherit;font-size:12px;
  font-weight:800;font-variant-numeric:tabular-nums;cursor:pointer;
  border:1px solid var(--border);border-radius:8px;background:var(--bg3);color:var(--text3);
  transition:background .14s,border-color .14s,color .14s}
.cp-lap:hover{border-color:var(--gold-border);color:var(--text)}
/* ON HAS TO BE UNMISTAKABLE. A border a shade different from the border
   beside it is a state nobody can read across a row of twelve, and a
   row where the state cannot be read is a row that reads as dead —
   which is exactly how this was reported: "I can't press them." Filled,
   in the accent, the way every other chosen thing in this panel is. */
.cp-lap.on{border-color:transparent;color:var(--on-accent);
  background:linear-gradient(135deg,var(--accent-fill),var(--accent-fill2))}
.cp-lap.on:hover{color:var(--on-accent)}
.cp-lap:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.cp-board{position:relative;display:flex;flex-direction:column;align-items:center;gap:2px;
  padding:5px 2px 4px;border:1px solid var(--border);border-radius:8px;background:var(--bg3);
  cursor:pointer;font-size:8.5px;font-weight:700;color:var(--text3)}
.cp-board input{position:absolute;opacity:0;pointer-events:none}
.cp-board img{width:22px;height:22px;object-fit:contain;opacity:.45}
.cp-board.on{border-color:var(--accent2);background:var(--green-bg);color:var(--text)}
.cp-board.on img{opacity:1}
.cp-viewbar{padding:0 0 8px}

/* The railways switch, lit when the layer is on — a corner button
   rather than a row in the basemap menu. See mapAddRailButton(). */
.map-rail-btn.on{background:var(--accent-fill,#0a6b43);color:var(--on-accent,#fff);
  border-color:transparent}
@media (max-width:880px){
  /* The panels stop being columns and the screen scrolls again. */
  body.print-view #content{overflow-y:auto}
  .cp-side{height:auto;max-height:none;position:static}
  .cp-preview{height:auto;min-height:360px}
}
.cp-board-sw{display:block}

/* The courses in the layers palette — see mapPalTracksHtml(). */
.pal .pl-trk-sw{width:16px;height:4px;border-radius:2px;display:block;flex-shrink:0}

/* ── THE PROFILE FOLDS TO ITS TITLE LINE ─────────────────────── */
.elev-fold{flex-shrink:0;width:26px;height:26px;color:#cbd5e1}
.elev-fold svg{width:15px;height:15px}
.elev-card.folded #elev-wrap,.elev-card.folded #elev-stats{display:none}
.elev-card.folded > div:first-child{margin-bottom:0!important}

/* ── THE ROADBOOK'S SIGNS OVER THE PROFILE ───────────────────
   A strip of sky above the picture, one row per tier of signs — see
   elevTrackSigns() in js/map.js. The picture below keeps its height. */
.elev-canvas{display:flex;flex-direction:column}
.elev-signs{position:relative;flex:0 0 auto;pointer-events:none}
.elev-pic{position:relative;flex:1 1 auto;min-height:0}
.elev-sign{position:absolute;width:20px;height:20px;transform:translateX(-50%);line-height:0;
  pointer-events:auto}
.elev-sign img,.elev-sign .elev-sign-img{display:block;width:19px;height:19px;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.45))}

/* ── ONE COURSE, ON ITS OWN PAGE ──────────────────────────────
   body.course-view: a share link cut to one course — see courseOnly()
   in js/map.js. The header, the sidebar, the read-only strip and the
   course list all go; the map takes the window, the profile sits under
   it and the videos under that, and the page scrolls to them. */
body.course-view #header,body.course-view #sidebar,body.course-view #menuBtn,
body.course-view #sidebar-scrim,body.course-view #ro-banner{display:none!important}
/* The sidebar's own fold tab — the orange tongue at the left edge — is
   a tab for a sidebar that is not there. Off on both map-only pages. */
body.course-view #nav-collapse-toggle,body.medmap-view #nav-collapse-toggle{display:none!important}
/* THE LAYERS PALETTE WEARS THE MAP'S OWN CHROME. It is the print
   sheet's palette, which takes the app's card colour — teal in this
   house — and over the map it sat beside a navy popover and a navy
   toolbar looking like something from another screen. Over the map,
   the map's colours; the print sheet keeps its own. */
.pal.map-pal{background:rgba(8,12,24,.94);backdrop-filter:blur(14px);border-color:rgba(148,163,184,.28)}
body.course-view #main{padding:0}
body.course-view #content{padding:0;overflow-y:auto}
/* The map is one window tall on every width — the layout wraps it and
   the profile and the videos follow underneath, where the page scrolls
   to them. Set on the shell rather than on the grid, so the phone
   rules (which give the shell 60vh) are simply outranked. */
body.course-view #v-map .map-layout,body.course-view #v-map .map-layout.panel-off{
  grid-template-columns:1fr;grid-template-rows:auto;gap:0;height:auto;min-height:0}
body.course-view .map-layout > .map-panel,body.course-view .map-panel-toggle,
body.course-view .map-rail{display:none!important}
body.course-view .map-layout > .map-shell{grid-column:1;grid-row:auto;height:100vh;min-height:360px;
  border-radius:0;border:none}
@supports (height:100dvh){
  body.course-view .map-layout > .map-shell{height:100dvh}
}
body.course-view .elev-card.elev-below{margin:0!important;border-radius:0!important;
  border-width:1px 0 0!important}
/* The film is behind the toolbar's button on this page, not a card. */
body.course-view .video-card{display:none!important}
/* WHAT A READER OF ONE COURSE DOES NOT NEED. Overlapping courses (there
   is one), the climb and descent scans (a scan is the organiser's
   work), live traffic and the railways: crossed off by Janny on the
   first real page. What stays is the wind, the layers, the heat, the
   GPX, the film, the settings, the basemap and the 3D view. */
body.course-view .course-map-tools [data-pop="courses"],body.course-view .course-map-tools [data-pop="climbs"],
body.course-view .course-map-tools [data-pop="descents"],body.course-view .course-map-tools [data-pop="points"],
body.course-view .map-traffic-btn,body.course-view .map-rail-btn{display:none!important}
/* ── ON THE FIELD (js/field-map.js) ──
   One panel top-right over the full-screen map: the course, where am I,
   who rides here, the road works and the mobility plan. Folds to a
   button, which is how a phone opens it. */
.fld{position:absolute;top:10px;right:10px;z-index:7;display:flex;flex-direction:column;align-items:flex-end;gap:8px;
  max-height:calc(100% - 20px);pointer-events:none}
.fld > *{pointer-events:auto}
.fld-fab{width:42px;height:42px;border-radius:12px;border:1px solid rgba(148,163,184,.35);background:rgba(8,12,24,.92);
  color:#fff;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;flex:0 0 auto}
.fld-fab svg{width:20px;height:20px}
.fld-panel{width:300px;max-width:calc(100vw - 24px);min-height:0;overflow-y:auto;background:rgba(8,12,24,.94);backdrop-filter:blur(14px);
  color:#e2e8f0;border:1px solid rgba(148,163,184,.28);border-radius:14px;padding:12px;display:flex;flex-direction:column;gap:8px;font-size:13px}
.fld-panel[hidden]{display:none}
.fld-panel .input{width:100%;background:#0f172a;color:#fff;border-color:rgba(148,163,184,.35)}
.fld-me{width:100%;justify-content:center}
.fld-h{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;color:#94a3b8;margin-top:4px}
.fld-races{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
.fld-races li{display:flex;flex-direction:column;background:rgba(255,255,255,.06);border-radius:8px;padding:6px 8px}
.fld-when{font-size:11px;color:#94a3b8}
.fld-races b{font-size:12.5px;color:#fff}
.fld-races i{font-style:normal;font-size:11px;color:#facc15}
.fld-none{margin:0;color:#94a3b8;font-size:12px}
.fld-sw{display:flex;align-items:center;gap:8px;cursor:pointer;padding:7px 9px;border-radius:8px;background:rgba(255,255,255,.06)}
.fld-sw.on{background:rgba(250,204,21,.16)}
.fld-sw b{margin-left:auto;font-size:11px;color:#94a3b8}
.fld-mob{display:flex;flex-direction:column;gap:6px}
.fld-mob[hidden]{display:none}
.fld-chips{display:flex;flex-wrap:wrap;gap:5px}
.fld-chip{padding:4px 9px;border-radius:999px;border:1px solid rgba(148,163,184,.35);background:transparent;color:#e2e8f0;
  font:inherit;font-size:11.5px;cursor:pointer}
.fld-chip.on{background:#facc15;color:#111;border-color:#facc15}
.fld-thumb{display:block;width:100%;max-height:140px;object-fit:cover;border-radius:6px;margin-bottom:6px}
/* The printed picture in the card: its own grid, its own height. */
.elev-wrap.elev-print{display:block;height:auto!important;cursor:default;padding:4px 0 0}
/* HOW MANY TIMES PAST THE LINE. A box under the finish pin on the
   course page: "12 laps" for a circuit race, read off the race that
   rides the course. See mapLapBoxHtml() in js/map.js. */
.map-lapbox{position:absolute;left:50%;top:100%;transform:translate(-50%,6px);white-space:nowrap;
  font:800 11px/1 Inter,system-ui,sans-serif;letter-spacing:.04em;text-transform:uppercase;
  color:#fff;background:rgba(220,38,38,.92);padding:5px 8px;border-radius:7px;
  border:1.5px solid #fff;box-shadow:0 2px 8px rgba(0,0,0,.4);pointer-events:none}
/* The one line that says which course this is, over the map — on the
   RIGHT, clear of the toolbar in the left corner. */
.course-title{position:absolute;right:12px;top:12px;z-index:7;max-width:min(60%,420px);
  padding:8px 12px;border-radius:10px;background:rgba(6,20,28,.86);backdrop-filter:blur(9px);
  border:1px solid rgba(255,255,255,.12);box-shadow:0 8px 24px rgba(0,0,0,.45);
  color:#f1f5f9;pointer-events:none;text-align:right}
.course-title strong{display:block;font-size:14px;font-weight:800;line-height:1.2}
.course-title span{display:block;font-size:11px;color:#cbd5e1;margin-top:2px}
@media (max-width:700px){
  .course-title{max-width:calc(100% - 24px);top:58px;right:12px}
  .course-title strong{font-size:13px}
}
/* ── THE PROFILE OVER THE FOOT OF THE MAP ─────────────────────
   renderMap() moves #elev-card into the shell and dresses it
   .elev-over .elev-float — on the course page since it was cut, and
   on the Course map & video screen since 17 Sep 2026, where the card
   under the window-high layout was always below the fold (Janny: "valt
   altijd buiten mijn scherm"). The glass card the map screen once
   floated, with its own header row and fold. Folded, it is the small
   square in the corner the old card folded to, with only the chevron
   in it. The sky strip keeps its own measure — the phone rule that
   gives the strip 74 px was measured for a strip without signs. */
.elev-card.elev-float > div:first-child{display:flex;align-items:center;gap:10px;margin-bottom:4px}
/* Folded, the square is GOLD — the house accent, white icon on it —
   because a grey square in the corner of a satellite map is a square
   nobody sees (Janny: make it more visible, orange). !important where
   the light theme's own rule for the floating card would outrank it. */
.elev-card.elev-float.folded{left:auto;right:12px;width:46px;height:46px;padding:0;
  display:flex;align-items:center;justify-content:center;overflow:hidden;
  background:var(--gold,#f59e0b)!important;border:2px solid #fff!important;
  box-shadow:0 4px 14px rgba(0,0,0,.45)!important}
.elev-card.elev-float.folded > div:first-child{margin:0!important;gap:0}
.elev-card.elev-float.folded h3,.elev-card.elev-float.folded #elev-name{display:none}
/* The button is an .icon-btn, which the light theme paints white with a
   grey border — a white button filling a gold square is a white square,
   which is what Janny saw. Over the gold it is bare: no fill, no border,
   the white profile alone. */
.elev-card.elev-float.folded .elev-fold{width:46px;height:46px;color:#fff!important;
  background:transparent!important;border:0!important;box-shadow:none!important;border-radius:0}
.elev-card.elev-float.folded .elev-fold:hover{background:rgba(255,255,255,.14)!important}
.elev-card.elev-float.folded .elev-fold svg{width:24px;height:24px;stroke:#fff}
.elev-card.elev-float .elev-stats{margin-top:6px}
/* The film in its modal: the same frame the card drew, one per row, in
   a dialogue as wide as the window allows. */
.modal.modal-video{max-width:min(1180px,96vw)}
.vc-modal,.vc-list.vc-modal{grid-template-columns:1fr;gap:16px}
.vc-modal .vc-item{margin-bottom:0}
.vc-modal .vc-item-hd{display:flex;align-items:center;justify-content:space-between;gap:10px}
.vc-frame:fullscreen{background:#000;border-radius:0}
.vc-frame:fullscreen iframe{position:absolute;inset:0;width:100%;height:100%}
.vc-modal .vc-frame{position:relative;aspect-ratio:16/9;max-width:100%;border-radius:10px;overflow:hidden;
  background:#000}
.vc-modal .vc-frame iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
/* ═══════════════════════════════════════════════════════════
   THE COURSE IN STREET VIEW — js/streetwalk.js
   A screen over everything: our map down the left with the mark that
   walks, Google's panorama filling the rest. The map column is a
   variable the grip on its edge sets (js: svWireGrip). Below 720 px
   the map goes on top and the road underneath, the hint goes and so
   does the grip.
   ═══════════════════════════════════════════════════════════ */
.sv-screen{position:fixed;inset:0;z-index:calc(var(--z-modal) + 3);display:grid;grid-template-columns:var(--sv-side,340px) 1fr;
  background:var(--bg);color:var(--text)}
body.sv-open{overflow:hidden}
.sv-side{position:relative;display:flex;flex-direction:column;min-width:0;min-height:0;border-right:1px solid var(--border);background:var(--bg2)}
/* The grip: 12 px astride the border, a knob in the middle that says
   it moves. The panorama's iframe would swallow the pointer once the
   cursor is over it, so while a drag is on the road is told to ignore
   the mouse. */
.sv-grip{position:absolute;top:0;bottom:0;right:-6px;width:12px;z-index:5;cursor:col-resize;touch-action:none}
.sv-grip i{position:absolute;left:50%;top:50%;width:6px;height:36px;margin:-18px 0 0 -3px;border-radius:3px;
  background:var(--border2);opacity:.85;transition:background .12s,opacity .12s}
.sv-grip:hover i,.sv-dragging .sv-grip i{background:#1da1f2;opacity:1}
.sv-dragging{cursor:col-resize;user-select:none}
.sv-dragging .sv-pano-wrap{pointer-events:none}
.sv-hd{display:flex;align-items:flex-start;gap:8px;padding:12px 12px 8px}
.sv-title{flex:1;min-width:0}
.sv-eyebrow{display:block;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--text3)}
.sv-title strong{display:block;font-size:15px;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sv-map{flex:1;min-height:160px;position:relative}
.sv-read{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 10px;padding:10px 12px 4px;font-size:12.5px}
.sv-km b{font-size:20px;font-weight:800;font-variant-numeric:tabular-nums}
.sv-km i{font-style:normal;color:var(--text3)}
.sv-tag{font-size:11px;font-weight:700;color:var(--text2);background:var(--bg3);padding:2px 7px;border-radius:999px}
.sv-tag.warn{background:#fee2e2;color:#991b1b}
/* The profile strip: the hill drawn small, a line and a dot where the
   camera stands; the slider under it is the same road as a control. */
.sv-prof{position:relative;margin:6px 12px 0;height:64px;cursor:pointer;border-radius:6px;overflow:hidden;background:var(--bg3);color:var(--text3)}
.sv-prof .rp-svg{height:64px;overflow:hidden}
.sv-prof-mark{position:absolute;top:0;bottom:0;left:0;width:0;pointer-events:none}
.sv-prof-mark::before{content:"";position:absolute;left:-1px;top:0;bottom:0;border-left:2px solid #1da1f2;opacity:.9}
.sv-prof-mark i{position:absolute;left:-5px;bottom:5px;width:10px;height:10px;border-radius:50%;background:#1da1f2;border:2px solid #fff;box-sizing:border-box}
.sv-slider{width:calc(100% - 24px);margin:6px 12px;accent-color:#1da1f2}
.sv-acts .sv-play.on{background:#dc2626;border-color:#dc2626;color:#fff}
.sv-acts .sv-speed{min-width:44px;font-variant-numeric:tabular-nums;font-weight:800}
.sv-acts{display:flex;flex-wrap:wrap;gap:6px;padding:4px 12px}
.sv-acts .btn.on{border-color:#1da1f2;color:#1da1f2}
.sv-hint{margin:6px 12px 12px;font-size:11.5px;color:var(--text3);line-height:1.4}
.sv-pano-wrap{position:relative;min-width:0;min-height:0;background:#111}
.sv-pano{position:absolute;inset:0}
.sv-state{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);max-width:min(420px,90%);padding:18px 20px;
  border-radius:12px;background:var(--bg2);color:var(--text);border:1px solid var(--border2);box-shadow:var(--shadow-md);
  text-align:center;font-size:13px}
.sv-state p{margin:8px 0 12px;color:var(--text2)}
.sv-state .btn{display:inline-flex}
/* The mark: a dot where the camera stands and a cone the way it looks. */
.sv-me{width:40px;height:40px}
.sv-me svg{display:block}
.sv-me .sv-cone{fill:#1da1f2;opacity:.28}
.sv-me .sv-dot{fill:#1da1f2;stroke:#fff;stroke-width:2.5}
@media (max-width:720px){
  .sv-screen{grid-template-columns:1fr;grid-template-rows:44% 1fr}
  .sv-side{border-right:0;border-bottom:1px solid var(--border)}
  .sv-hint,.sv-grip{display:none}
}


/* ═══ 27 Sep 2026 — the print tool, eight more things ═══════════════ */

/* THE MERKSET. The accent is a rule, not a colour for words: an
   edition's yellow accent would be unreadable as type on white, and as
   a 2 px line over each figure it is the brand without the risk. */
.cp-sheet.cp-branded .cp-head-stat{border-top:2px solid var(--cp-accent,#e2e8f0)}
.cp-sheet.cp-branded .cp-key-hd{border-bottom:2px solid var(--cp-accent,transparent)}

/* A WORD ACROSS THE SHEET, over everything and in the way of nothing. */
.cp-sheet .cp-wm{position:absolute;inset:0;width:100%;height:100%;z-index:6;pointer-events:none}

/* THE CLIMBS, THE SECTORS: the number plate in a table, and the gradient
   key as one row of little swatches rather than seven lines. */
.cp-sheet .cp-sec-no{display:inline-block;min-width:13px;padding:0 3px;border-radius:3px;text-align:center;
  font-weight:800;font-size:7px;line-height:11px}
.cp-sheet .cp-sec-stars svg{display:inline-block;vertical-align:middle}
.cp-sheet .cp-times-tbl .n .cp-sec-no{font-variant-numeric:tabular-nums}
.cp-sheet .cp-key-rows .cp-key-grades{display:flex;flex-wrap:wrap;gap:calc(3px * var(--cp-key,1)) calc(7px * var(--cp-key,1));
  padding-left:calc(9px * var(--cp-key,1))}
.cp-sheet .cp-key-rows .cp-key-grades i{display:inline-flex;align-items:center;gap:3px;font-style:normal;font-weight:700;
  font-size:calc(7.5px * var(--cp-key,1))}
.cp-sheet .cp-key-rows .cp-key-grades svg{width:calc(9px * var(--cp-key,1));height:calc(9px * var(--cp-key,1));flex-shrink:0}
.cp-sheet .cp-locator{line-height:0}

/* ── THE POSTER ──
   The dark sheet: every card goes dark with the ground, the lettering
   light, the thin frames a shade above the card. The course glows in
   the map itself (CP_PALETTES.poster); this is only the furniture. */
.cp-sheet.cp-poster{background:#0b1220;color:#e5edf7}
.cp-sheet.cp-poster .cp-head-logos,.cp-sheet.cp-poster .cp-head-txt,.cp-sheet.cp-poster .cp-key,
.cp-sheet.cp-poster .cp-clos,.cp-sheet.cp-poster .cp-times,.cp-sheet.cp-poster .cp-inset,.cp-sheet.cp-poster .cp-head-qr{
  background:#111c2e;box-shadow:0 0 0 1px #26354b,0 6px 20px rgba(0,0,0,.45)}
.cp-sheet.cp-poster .cp-head h1{color:#f8fafc;letter-spacing:-.02em}
.cp-sheet.cp-poster .cp-head-bar h1{color:inherit}
.cp-sheet.cp-poster .cp-head h1{font-size:calc(24px * var(--cp-head,1) * var(--cp-head-ts,1));font-weight:900}
.cp-sheet.cp-poster .cp-head p{color:#9fb0c6}
.cp-sheet.cp-poster .cp-head-note{color:#7c8ba1!important}
.cp-sheet.cp-poster .cp-head-stat{background:#0d1726;border-color:#26354b}
.cp-sheet.cp-poster .cp-head-stat b{color:#f8fafc}
.cp-sheet.cp-poster .cp-head .cp-elev-line{stroke:#9fb0c6}
.cp-sheet.cp-poster .cp-key-hd,.cp-sheet.cp-poster .cp-inset-t{background:var(--cp-brand,#1e2b40)}
.cp-sheet.cp-poster .cp-key-rows{color:#cbd5e1}
.cp-sheet.cp-poster .cp-key-rows .cp-key-grp{color:#f1f5f9}
.cp-sheet.cp-poster .cp-times-tbl th{color:#8fa0b7;border-bottom-color:#26354b}
.cp-sheet.cp-poster .cp-times-tbl td{color:#dbe4ef;border-bottom-color:#18253a}
.cp-sheet.cp-poster .cp-clos-rows b{color:#f1f5f9}
.cp-sheet.cp-poster .cp-place circle{fill:#9fb0c6}
.cp-sheet.cp-poster .cp-place text{fill:#dbe4ef;stroke:#0b1220}
.cp-sheet.cp-poster .cp-foot{background:linear-gradient(0deg,#0b1220 0%,#0b1220 86%,rgba(11,18,32,0) 100%)}
.cp-sheet.cp-poster .cp-partners{background:#0b1220}
.cp-sheet.cp-poster .cp-profile .rp-yax,.cp-sheet.cp-poster .cp-profile .rp-xax,.cp-sheet.cp-poster .rp-wpkm{color:#8fa0b7}
.cp-sheet.cp-poster .cp-profile .elev-grid,.cp-sheet.cp-poster .cp-inset-prof .elev-grid{stroke:#1f2d44}
.cp-sheet.cp-poster .cp-fail{color:#64748b}

/* ── THE PANEL'S NEW CONTROLS ── */
.cp-custom{display:flex;align-items:center;gap:5px}
.cp-custom .input{flex:1 1 0;min-width:0;padding:5px 6px;font-size:12px;text-align:center}
.cp-custom span{color:var(--text3);font-weight:800}
.cp-custom .cp-seg-b{flex:0 0 auto;min-height:32px}
.cp-arrow-styles .cp-seg-b{flex:1 1 30%;flex-direction:column;gap:4px;min-height:48px}
.cp-arrow-styles svg{flex-shrink:0;overflow:visible}
.cp-sectors{display:flex;flex-direction:column;gap:5px}
.cp-sector-row{display:grid;grid-template-columns:auto minmax(0,1fr) auto auto;align-items:center;gap:6px}
.cp-sector-row .input{min-width:0;padding:4px 6px;font-size:12px}
.cp-sector-row > span:not(.cp-stars){font-size:11.5px;font-weight:700;color:var(--text2);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cp-sector-row small{font-size:10px;font-weight:700;color:var(--text3);font-variant-numeric:tabular-nums}
.cp-sectors .cp-sec-no{display:inline-flex;align-items:center;justify-content:center;min-width:22px;height:20px;padding:0 4px;
  border-radius:5px;font-size:11px;font-weight:800;font-style:normal}
.cp-stars{display:inline-flex;gap:1px}
.cp-star{border:0;background:none;padding:0 1px;font-size:14px;line-height:1;color:var(--border2);cursor:pointer;font-style:normal}
button.cp-star:hover{color:#f59e0b}
.cp-star.on{color:#f59e0b}
.cp-brand-row{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.cp-brand-row label{display:flex;align-items:center;justify-content:space-between;gap:6px;font-size:11.5px;font-weight:700;color:var(--text2)}
.cp-brand-row input[type=color]{width:44px;height:28px;padding:0;border:1px solid var(--border);border-radius:6px;background:none;cursor:pointer}
.cp-brand-draft{color:var(--gold2)}

/* ── THE CHECK ── a line per finding, the colour of how bad; the badge
   on its button says how many at a glance. */
.cp-pf-list{display:flex;flex-direction:column;gap:4px}
.cp-pf-row{display:flex;align-items:flex-start;gap:8px;text-align:left;font:inherit;font-size:11.5px;font-weight:600;line-height:1.35;
  color:var(--text2);background:var(--bg3);border:1px solid var(--border);border-left-width:3px;border-radius:7px;padding:6px 8px;cursor:pointer}
.cp-pf-row:hover:not(:disabled){color:var(--text);border-color:var(--gold-border)}
.cp-pf-row:disabled{cursor:default}
.cp-pf-row i{flex:0 0 auto;width:8px;height:8px;border-radius:50%;margin-top:4px;background:var(--text3)}
.cp-pf-row.err{border-left-color:#ef4444}.cp-pf-row.err i{background:#ef4444}
.cp-pf-row.warn{border-left-color:#f59e0b}.cp-pf-row.warn i{background:#f59e0b}
.cp-pf-row.info{border-left-color:#38bdf8}.cp-pf-row.info i{background:#38bdf8}
.cp-pf-ok{margin:2px 0;font-size:12px;font-weight:700;color:#22c55e}
.cp-pf-ask{margin:6px 0 0;padding-left:18px;font-size:13px;line-height:1.45}
[data-cp-pop="check"]{position:relative}
.cp-pf-badge{position:absolute;top:-4px;right:-5px;min-width:15px;height:15px;padding:0 3px;border-radius:8px;
  font-size:9.5px;font-weight:800;line-height:15px;text-align:center;color:#fff;background:#64748b;pointer-events:none}
.cp-pf-badge.err{background:#ef4444}.cp-pf-badge.warn{background:#f59e0b;color:#1f2937}.cp-pf-badge.ok{background:#22c55e}
.cp-pf-badge[hidden]{display:none}
.cp-pf-hl{position:absolute;z-index:8;pointer-events:none;border:2px solid #f59e0b;border-radius:4px;
  box-shadow:0 0 0 3px rgba(245,158,11,.25);animation:cpPfPulse .9s ease-in-out 3}
.cp-pf-hl.err{border-color:#ef4444;box-shadow:0 0 0 3px rgba(239,68,68,.25)}
.cp-pf-hl.info{border-color:#38bdf8;box-shadow:0 0 0 3px rgba(56,189,248,.25)}
@keyframes cpPfPulse{50%{opacity:.35}}
@media (prefers-reduced-motion:reduce){.cp-pf-hl{animation:none}}

/* The climb and gravel tables are as wide as their rows: the column's
   38 % clipped the stars off the gravel table. */
.cp-sheet .cp-gtable,.cp-sheet .cp-ctable{max-width:none;width:max-content}
/* A heading or corner card somebody dragged: on its own, where it was
   put (cpCardPos()); the grab shows it can be. */
.cp-sheet .cp-card-free{position:absolute;z-index:3;display:flex;flex-direction:column}
.cp-sheet .cp-card-free > *{max-width:none}
.cp-preview .cp-sheet [data-cp-card]{cursor:move}

/* The corner tables grow with their own dial, --cp-tbl (cpTableScale()):
   the type, the padding, the number plates and the stars as one. */
.cp-sheet .cp-times,.cp-sheet .cp-clos{min-width:calc(170px * var(--cp-tbl,1))}
.cp-sheet .cp-times .cp-key-hd,.cp-sheet .cp-clos .cp-key-hd{font-size:calc(8.5px * var(--cp-tbl,1));
  padding:calc(4px * var(--cp-tbl,1)) calc(10px * var(--cp-tbl,1))}
.cp-sheet .cp-times-tbl{font-size:calc(7.6px * var(--cp-tbl,1))}
.cp-sheet .cp-times-tbl th{font-size:calc(6.6px * var(--cp-tbl,1));
  padding:calc(5px * var(--cp-tbl,1)) calc(6px * var(--cp-tbl,1)) calc(3px * var(--cp-tbl,1))}
.cp-sheet .cp-times-tbl td{padding:calc(2px * var(--cp-tbl,1)) calc(6px * var(--cp-tbl,1));max-width:calc(120px * var(--cp-tbl,1))}
.cp-sheet .cp-times-more{font-size:calc(7px * var(--cp-tbl,1))}
.cp-sheet .cp-clos .cp-key-rows{font-size:calc(8.5px * var(--cp-tbl,1));gap:calc(3px * var(--cp-tbl,1));
  padding:calc(8px * var(--cp-tbl,1)) calc(11px * var(--cp-tbl,1)) calc(9px * var(--cp-tbl,1))}
.cp-sheet .cp-clos-day{font-size:calc(8px * var(--cp-tbl,1))}
.cp-sheet .cp-times-tbl .cp-sec-no{min-width:calc(13px * var(--cp-tbl,1));padding:0 calc(3px * var(--cp-tbl,1));
  font-size:calc(7px * var(--cp-tbl,1));line-height:calc(11px * var(--cp-tbl,1))}
.cp-sheet .cp-sec-stars svg{width:calc(34px * var(--cp-tbl,1));height:calc(7px * var(--cp-tbl,1))}

/* A redraw that takes a moment: the old sheet stays, this says the new
   one is coming (cpBusyChip()). */
.cp-busy-chip{position:absolute;top:10px;right:14px;z-index:7;padding:4px 10px;border-radius:999px;
  background:rgba(15,23,42,.8);color:#fff;font-size:11px;font-weight:700;pointer-events:none}
/* A section option that needs a measurement first: greyed and still until there is one. */
.cp-needs.off{opacity:.42;pointer-events:none}
.cp-needs-note{display:grid;gap:8px;margin:4px 0 10px;padding:10px 12px;border:1px dashed var(--gold-border);border-radius:8px;background:var(--bg3)}
.cp-needs-note .cp-sub{margin:0}
/* The sign's dotted leader: down through the sky (::after) and on to the line (.elev-lead). */
.elev-sign::after{content:"";position:absolute;left:50%;top:20px;height:var(--lead,0px);border-left:1px dashed var(--text3,#94a3b8);opacity:.8;pointer-events:none}
.elev-lead{stroke:var(--text3,#94a3b8);stroke-width:1;stroke-dasharray:3 3;opacity:.8;fill:none}

/* ── THE COURSE FILM — js/flyover.js ────────────────────────────
   The page in the menu is a form; the studio is full screen over the
   app: a quiet bar across the top, the film on its stage, the options
   in one block on the right, nothing that scrolls on a laptop. Dark
   like a cutting room, ochre like the event. */
body.fly-open{overflow:hidden}
/* ── THE COURSE FILM AS A PLAYER (js/fly-player.js) ──
   The studio with its workbench put away: the picture, the timeline, play,
   the time, reset view, full screen (and × on a link). */
.fly-studio.fly-player{grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr)}
.fly-player .fly-top,.fly-player .fly-side,.fly-player [data-fly="rec"],.fly-player [data-fly="setshot"],.fly-player [data-fly="setkey"],
.fly-player .fly-shotn,.fly-player [data-fly="clearshots"],.fly-player .fly-angle,.fly-player .fly-shots,.fly-player .fly-rate{display:none !important}
.fly-player .fly-bar{gap:10px;padding:8px 14px 10px}
.fly-pl-title{padding:10px 18px 0;font:800 15px/1.2 var(--font-body);letter-spacing:.02em;color:#e8eefc;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fly-pl-fs,.fly-pl-close{min-width:36px;font-size:17px}
/* undo / redo in the studio's top bar (js/fly-history.js) */
.fly-hist{display:inline-flex;gap:4px}
/* the film's size in pixels beside the shapes, and under Quality */
.fly-px{font:600 11.5px/1 var(--font-body);color:rgba(232,238,252,.7);font-variant-numeric:tabular-nums;white-space:nowrap}
.fly-px-big{font-variant-numeric:tabular-nums}
.fly-hist .fly-btn{min-width:34px;padding-left:8px;padding-right:8px}
.fly-hist .fly-btn:disabled{opacity:.35;cursor:default}
.fly-pl-open{position:fixed;right:16px;bottom:16px;z-index:3000;padding:12px 18px;border-radius:999px;border:0;cursor:pointer;
  background:#f59e0b;color:#0c0b08;font:800 14px/1 var(--font-body);box-shadow:0 8px 24px rgba(0,0,0,.35)}
/* the embed: the player alone in the frame, the app behind it never shown */
body.embed-view #app > :not(.fly-studio),body.embed-view #header,body.embed-view #sidebar{visibility:hidden}
.fly-pl-none{position:fixed;inset:0;display:grid;place-items:center;background:#060a14;color:#e8eefc;font:600 15px var(--font-body);text-align:center;padding:24px}
@media (max-width:640px){.fly-player .fly-look,.fly-player [data-fly="resetview"]{display:none}}
.fly-studio{position:fixed;inset:0;z-index:4000;display:grid;
  grid-template-columns:minmax(0,1fr) 320px;grid-template-rows:52px minmax(0,1fr);
  background:#060a14;color:#e8eefc;font-family:var(--font-body)}
.fly-top{grid-column:1 / -1;display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:0 12px 0 16px;background:rgba(232,238,252,.035);border-bottom:1px solid rgba(232,238,252,.09)}
.fly-top-l,.fly-top-r{display:flex;align-items:center;gap:8px;min-width:0}
.fly-brand{display:inline-flex;align-items:center;gap:8px;color:#f59e0b;white-space:nowrap}
.fly-brand svg{width:18px;height:18px}
.fly-brand b{font-family:var(--font-display);font-size:15px;letter-spacing:.02em;color:#e8eefc}
.fly-in{height:32px;border-radius:8px;padding:0 10px;font:inherit;font-size:13px;min-width:0;
  background:#0c1322;color:#e8eefc;border:1px solid rgba(232,238,252,.16)}
.fly-in:focus{outline:none;border-color:#f59e0b}
.fly-top .fly-in{max-width:230px}
.fly-top .fly-title-in{width:200px}
.fly-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border-radius:8px;cursor:pointer;
  font:inherit;font-size:12.5px;font-weight:800;color:#e8eefc;background:rgba(232,238,252,.08);border:1px solid rgba(232,238,252,.16)}
.fly-btn svg{width:15px;height:15px}
.fly-btn:hover{border-color:#f59e0b}
.fly-btn.primary{background:#f59e0b;border-color:#f59e0b;color:#060a14}
.fly-btn.big{height:44px;padding:0 20px;font-size:14.5px}
/* the cross: plainly a button, light on dark */
.fly-close{display:inline-grid;place-items:center;width:34px;height:34px;border-radius:9px;cursor:pointer;margin-left:4px;
  background:rgba(232,238,252,.14);border:1px solid rgba(232,238,252,.28);color:#fff}
.fly-close svg{width:18px;height:18px;stroke:#fff;stroke-width:2.4}
.fly-close:hover{background:#e23629;border-color:#e23629}
.fly-main{display:flex;flex-direction:column;min-width:0;min-height:0}
.fly-stage{flex:1;min-height:0;display:grid;place-items:center;overflow:hidden}
.fly-frame{position:relative;box-shadow:0 18px 60px rgba(0,0,0,.6);border-radius:6px;overflow:hidden;background:#000}
.fly-mapbox{position:absolute;left:0;top:0;transform-origin:0 0;opacity:0;pointer-events:none}
.fly-out{position:absolute;inset:0;width:100%;height:100%;display:block}
/* the safe areas over the preview (js/fly-tv.js): action 3.5 %, title 5 %, EBU R95 */
.fly-safe{position:absolute;inset:0;pointer-events:none;z-index:2}
.fly-safe[hidden]{display:none}
.fly-safe i{position:absolute;border:1px dashed rgba(255,255,255,.75);box-shadow:0 0 0 1px rgba(0,0,0,.35)}
.fly-safe-a{inset:3.5%}
.fly-safe-t{inset:5%;border-color:rgba(255,214,10,.9) !important}
.fly-safe b{position:absolute;left:4px;top:2px;font:700 10px/1.2 var(--font-body);letter-spacing:.06em;text-transform:uppercase;color:rgba(255,255,255,.85);text-shadow:0 1px 2px #000}
.fly-safe-t b{top:auto;bottom:2px;color:rgba(255,214,10,.95)}
.fly-safe-x{left:50%;top:50%;width:24px;height:24px;margin:-12px 0 0 -12px;border:0 !important;box-shadow:none !important;
  background:linear-gradient(rgba(255,255,255,.7),rgba(255,255,255,.7)) center/1px 100% no-repeat,linear-gradient(rgba(255,255,255,.7),rgba(255,255,255,.7)) center/100% 1px no-repeat}
.fly-bar{display:flex;align-items:center;gap:12px;padding:8px 18px 12px}
.fly-play{display:inline-grid;place-items:center;width:38px;height:38px;border-radius:50%;cursor:pointer;
  background:#f59e0b;border:0;color:#060a14}
.fly-play svg{width:16px;height:16px;fill:#060a14}
.fly-scrub{flex:1;accent-color:#f59e0b}
.fly-time{font-variant-numeric:tabular-nums;font-size:13px;color:rgba(232,238,252,.7);min-width:92px;text-align:right}
.fly-progress{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;padding:0 18px 12px}
.fly-progress>div{flex:1;height:8px;border-radius:4px;background:rgba(232,238,252,.12);overflow:hidden;min-width:120px}
.fly-progress span{display:block;height:100%;width:0;background:#f59e0b;transition:width .15s}
.fly-progress b{font-size:12px;font-variant-numeric:tabular-nums;min-width:120px}
.fly-progress em{flex-basis:100%;font-style:normal;font-size:12px;color:#f59e0b}
/* the options, one block, on the right */
.fly-side{grid-column:2;grid-row:2;overflow:auto;padding:4px 14px 12px;background:#060a14;border-left:1px solid rgba(232,238,252,.09)}
.fly-step{padding:14px 0 16px;border-bottom:1px solid rgba(232,238,252,.1);display:grid;gap:10px}
.fly-step:last-of-type{border-bottom:0}
.fly-step h4{margin:0;font-size:11px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;color:#f59e0b}
.fly-row{display:grid;grid-template-columns:58px minmax(0,1fr);align-items:center;gap:8px}
.fly-lab{font-size:11px;font-weight:700;color:rgba(232,238,252,.6)}
.fly-seg{display:flex;flex-wrap:wrap;gap:6px}
/* one option from the next: a hairline and some air */
.fly-step>.fly-row+.fly-row,.fly-step>.fly-ticks+.fly-row,.fly-step>.fly-row+.fly-ticks{border-top:1px solid rgba(232,238,252,.07);padding-top:10px}
.fly-step>.fly-ticks{gap:8px 12px}
/* a camera point or shot past the film's end */
.fly-shot.fly-late>button:first-child{background:#e23629 !important;color:#fff}
.fly-keyrow.fly-late{border-color:rgba(226,54,41,.6)}
.fly-late-hint{color:#f87171}
.fly-seg button{flex:1 1 auto;min-width:min-content;padding:5px 7px;border-radius:7px;cursor:pointer;
  font:inherit;font-size:11.5px;font-weight:700;color:rgba(232,238,252,.82);
  background:rgba(232,238,252,.06);border:1px solid rgba(232,238,252,.13)}
.fly-seg button:hover{border-color:#f59e0b;color:#fff}
.fly-seg button.on{background:#f59e0b;border-color:#f59e0b;color:#060a14}
.fly-top .fly-formats button{padding:5px 9px}
/* ROUND, ALWAYS — Janny, 30 Sep 2026: "die bollen staan wat uit de haak".
   Seven dots in a narrow panel were squeezed into ovals; they keep their
   size now and go onto a second line when there is no room. */
.fly-swatches{display:flex;flex-wrap:wrap;gap:7px;align-items:center}
.fly-swatches>button,.fly-swatches>.fly-own{flex:0 0 26px;min-width:26px}
.fly-swatches button,.fly-own{width:26px;height:26px;border-radius:50%;cursor:pointer;padding:0;
  background:var(--c);border:2px solid rgba(232,238,252,.25);box-shadow:inset 0 0 0 2px #060a14}
.fly-swatches button.on,.fly-own.on{border-color:#fff;box-shadow:inset 0 0 0 2px #060a14,0 0 0 2px #f59e0b}
/* any colour: the browser's own picker behind a rainbow swatch */
.fly-own{position:relative;overflow:hidden;background:conic-gradient(#f43f5e,#f59e0b,#eab308,#22c55e,#06b6d4,#6366f1,#d946ef,#f43f5e)}
.fly-own.on{background:var(--c)}
/* the line in its gradient's colours: a swatch of the slope colours */
.fly-swatches button.fly-grad-sw{background:linear-gradient(135deg,#22c55e 0%,#eab308 50%,#ef4444 100%)}
.fly-swatches button.fly-grad-sw:disabled{opacity:.75;cursor:default}
.fly-own input{position:absolute;inset:-6px;width:calc(100% + 12px);height:calc(100% + 12px);opacity:0;cursor:pointer}
.fly-ticks{display:grid;grid-template-columns:1fr 1fr;gap:6px 10px}
/* the sonar's "same as the line" swatch: the line's colour with a ring inside */
.fly-swatches .fly-sonar-line{background:radial-gradient(circle,transparent 38%,var(--c) 40%)}
.fly-tick{display:flex;gap:7px;align-items:center;font-size:12.5px;cursor:pointer;line-height:1.3}
.fly-tick input{accent-color:#f59e0b;margin:0}
.fly-hint{margin:6px 0 0;font-size:11.5px;color:rgba(232,238,252,.5);line-height:1.45}
/* the page: the same choices as a form, before the studio */
#v-film .page-sub{margin:4px 0 0;color:var(--text2);max-width:62ch}
.fly-setup{margin-top:14px}
.fly-setup-card{max-width:980px;background:#060a14;color:#e8eefc;border-radius:14px;
  border:1px solid rgba(232,238,252,.1);box-shadow:0 10px 40px rgba(0,0,0,.25);overflow:hidden}
.fly-setup-bd{display:grid;grid-template-columns:1fr 1fr;gap:4px 28px;padding:10px 22px 6px}
.fly-setup-col{min-width:0}
.fly-setup .fly-step{padding:12px 0}
.fly-setup .fly-in{width:100%;height:36px}
.fly-shapes{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
.fly-shapes button{display:grid;justify-items:center;align-content:end;gap:4px;padding:10px 6px 8px;border-radius:10px;cursor:pointer;
  font:inherit;color:rgba(232,238,252,.85);background:rgba(232,238,252,.05);border:1px solid rgba(232,238,252,.13);min-height:112px}
.fly-shapes i{display:block;width:auto;height:52px;max-width:88%;border-radius:4px;border:2px solid currentColor;opacity:.75}
.fly-shapes b{font-size:13px}
.fly-shapes small{font-size:10.5px;color:rgba(232,238,252,.55);text-align:center;line-height:1.25}
.fly-shapes button.on{border-color:#f59e0b;color:#f59e0b;background:rgba(245,158,11,.1)}
.fly-setup-ft{display:flex;justify-content:flex-end;padding:12px 22px 18px;border-top:1px solid rgba(232,238,252,.08)}
@media (max-width:980px){
  .fly-studio{grid-template-columns:1fr;grid-template-rows:auto minmax(0,1fr) minmax(0,40vh)}
  .fly-top{flex-wrap:wrap;padding:8px 10px}
  .fly-top .fly-title-in{width:140px}
  .fly-side{grid-column:1;grid-row:3;border-left:0;border-top:1px solid rgba(232,238,252,.09)}
  .fly-setup-bd{grid-template-columns:1fr}
}
.fly-hour{display:flex;align-items:center;gap:8px}
.fly-hour input{flex:1;accent-color:#f59e0b;min-width:0}
.fly-hour b{font-size:12px;font-variant-numeric:tabular-nums;min-width:38px;text-align:right}
.fly-stage{cursor:grab;touch-action:none}
.fly-stage.dragging{cursor:grabbing}
.fly-look{font-size:11.5px;color:rgba(232,238,252,.5);white-space:nowrap}
@media (max-width:980px){.fly-look{display:none}}
/* the film page: the form in the middle of the page, its heading over it */
#v-film .page-hd{max-width:980px;margin-left:auto;margin-right:auto}
#v-film .fly-setup-card{margin:0 auto}
/* the form's snapshot of the look */
.fly-snap{display:block;width:auto;height:auto;max-width:100%;max-height:420px;margin:0 auto;border-radius:8px;background:#04070d;box-shadow:0 6px 20px rgba(0,0,0,.35)}
.fly-row{grid-template-columns:68px minmax(0,1fr)}
.fly-angle{font-size:12px;font-variant-numeric:tabular-nums;color:#f59e0b;white-space:nowrap}
@media (max-width:980px){.fly-angle{display:none}}
.fly-btn{white-space:nowrap;flex-shrink:0}
.fly-bar .fly-scrub{min-width:80px}
/* saved films and styles — on the form's head and at the foot of the studio panel */
.fly-saved{display:grid;grid-template-columns:1fr 1fr;gap:4px 28px;padding:6px 22px 0;border-bottom:1px solid rgba(232,238,252,.08)}
.fly-films{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:8px}
.fly-film{display:flex;align-items:stretch;border-radius:10px;background:rgba(232,238,252,.06);border:1px solid rgba(232,238,252,.13);overflow:hidden}
.fly-film:hover{border-color:#f59e0b}
.fly-film-open{flex:1;min-width:0;display:grid;gap:2px;text-align:left;padding:8px 10px;cursor:pointer;background:none;border:0;color:#e8eefc;font:inherit}
.fly-film-open b{font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fly-film-open small{font-size:11px;color:rgba(232,238,252,.55);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fly-x{display:inline-grid;place-items:center;width:28px;flex-shrink:0;cursor:pointer;background:none;border:0;color:rgba(232,238,252,.5)}
.fly-x svg{width:13px;height:13px}
.fly-x:hover{color:#e23629}
.fly-styles{display:flex;flex-wrap:wrap;gap:6px}
.fly-chip{display:inline-flex;align-items:center;border-radius:999px;background:rgba(245,158,11,.12);border:1px solid rgba(245,158,11,.35)}
.fly-chip>button:first-child{padding:5px 11px;cursor:pointer;background:none;border:0;color:#f59e0b;font:inherit;font-size:12px;font-weight:800}
.fly-chip .fly-x{width:22px}
.fly-savebar{display:flex;gap:6px;align-items:center}
.fly-savebar .fly-in{flex:1;min-width:0;height:32px}
/* camera paths (js/fly-paths.js): one row each, name and what it holds, Apply, × */
.fly-paths{display:grid;gap:6px;margin-top:8px}
.fly-path{display:flex;align-items:center;gap:6px;border:1px solid rgba(232,238,252,.12);border-radius:10px;padding:7px 8px}
.fly-path-txt{flex:1;min-width:0;display:grid;gap:1px}
.fly-path-txt b{font-size:12.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fly-path-txt small{font-size:11px;color:rgba(232,238,252,.55);line-height:1.35}
.fly-path-txt .fly-path-mode{color:#f59e0b}
.fly-path .fly-btn{height:28px;padding:0 10px;flex-shrink:0}
/* a question over the studio (flyAsk): before an export, before a delete */
.fly-ask{position:fixed;inset:0;z-index:4600;display:grid;place-items:center;padding:16px;background:rgba(6,10,20,.72);backdrop-filter:blur(3px)}
.fly-ask-card{width:min(440px,100%);background:#0c1322;border:1px solid rgba(245,158,11,.35);border-radius:14px;padding:20px 20px 16px;
  box-shadow:0 24px 60px rgba(0,0,0,.5);color:#e8eefc;display:grid;gap:10px}
.fly-ask-ico{width:40px;height:40px;border-radius:10px;display:grid;place-items:center;background:rgba(245,158,11,.14);color:#f59e0b}
.fly-ask-ico svg{width:20px;height:20px}
.fly-ask-card h3{margin:0;font-size:17px;font-weight:800}
.fly-ask-card p{margin:0;font-size:13.5px;line-height:1.5;color:rgba(232,238,252,.85)}
.fly-ask-card .fly-ask-more{font-size:12px;color:rgba(232,238,252,.6)}
.fly-ask-bar{display:flex;justify-content:flex-end;gap:8px;margin-top:4px;flex-wrap:wrap}
.fly-ask-bar .fly-btn{height:36px}
.fly-btn.primary.danger{background:#e23629;border-color:#e23629;color:#fff}
.fly-side .fly-in{width:100%}
@media (max-width:980px){.fly-saved{grid-template-columns:1fr}}
/* the studio's record button, the shots on the scrub, the closing-line box */
.fly-rec{display:inline-grid;place-items:center;width:34px;height:34px;border-radius:50%;cursor:pointer;flex-shrink:0;
  background:rgba(232,238,252,.08);border:1px solid rgba(232,238,252,.22)}
.fly-rec i{display:block;width:12px;height:12px;border-radius:50%;background:#e23629}
.fly-rec.on{border-color:#e23629;background:rgba(226,54,41,.18);animation:fly-blink 1s infinite}
@keyframes fly-blink{50%{opacity:.45}}
.fly-scrubwrap{flex:1;position:relative;min-width:80px;padding-bottom:12px}
.fly-scrubwrap .fly-scrub{width:100%;display:block}
.fly-shots{position:absolute;left:8px;right:8px;bottom:0;height:12px;pointer-events:none}
.fly-shot{position:absolute;bottom:0;transform:translateX(-50%);display:flex;align-items:center;gap:2px;pointer-events:auto}
.fly-shot>button:first-child{width:10px;height:10px;transform:rotate(45deg);background:#f59e0b;border:1px solid #060a14;cursor:pointer;padding:0}
.fly-shot-x{display:none;width:14px;height:14px;line-height:12px;padding:0;border-radius:50%;font-size:11px;cursor:pointer;
  background:#e23629;color:#fff;border:0}
.fly-shot:hover .fly-shot-x{display:block}
/* a marker taken by the mouse along the time bar (js/fly-drag.js) */
.fly-shot>button:first-child{cursor:grab;touch-action:none}
.fly-shot.fly-dragging{z-index:3}
.fly-shot.fly-dragging>button:first-child{cursor:grabbing;box-shadow:0 0 0 3px rgba(255,255,255,.35)}
.fly-shot.fly-dragging .fly-shot-x{display:none !important}
.fly-drag-tip{position:absolute;bottom:18px;left:50%;transform:translateX(-50%);padding:2px 6px;border-radius:4px;background:#060a14;color:#fff;
  font:600 11px/1.3 var(--font-body);font-variant-numeric:tabular-nums;white-space:nowrap;pointer-events:none}
.fly-shotn{font-size:11.5px;color:rgba(232,238,252,.55);white-space:nowrap}
.fly-top .fly-cta-in{width:220px}
@media (max-width:980px){.fly-top .fly-cta-in{display:none}}
.fly-stretch{grid-template-columns:68px minmax(0,1fr);align-items:start}
.fly-stretch .fly-savebar{flex-wrap:wrap}
.fly-stretch select.fly-in{flex:1 1 100%}
.fly-km{width:88px;flex:0 0 88px}

/* camera points: numbered markers on the strip, a card per point */
.fly-keypt>button:first-child{width:15px;height:15px;transform:none;border-radius:50%;background:#5ec8ff;color:#0b1a24;
  font:800 9px/15px "Work Sans",system-ui,sans-serif;text-align:center}
.fly-keybtn{border-color:rgba(94,200,255,.55)}
.fly-keyrow{border:1px solid rgba(232,238,252,.12);border-radius:10px;padding:8px;margin-top:8px;display:grid;gap:6px}
.fly-keyrow.on{border-color:#5ec8ff;background:rgba(94,200,255,.07)}
.fly-keyhd{display:flex;gap:6px;align-items:center}
.fly-keyhd .fly-kn{flex:1}
.fly-keygo{width:24px;height:24px;flex:0 0 24px;border-radius:50%;border:0;background:#5ec8ff;color:#0b1a24;font-weight:800;font-size:12px;cursor:pointer;padding:0}
.fly-keyx{display:block;flex:0 0 18px;width:18px;height:18px;line-height:16px}
.fly-keygrid{display:grid;grid-template-columns:1.25fr 1fr 1fr;gap:6px}
.fly-keyfoot{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap;row-gap:6px}
.fly-keyfoot .fly-btn{flex:0 0 auto}
.fly-keyacts{display:flex;gap:6px;margin-left:auto}
.fly-kn{display:grid;gap:3px;min-width:0}
.fly-kn small{font-size:10.5px;color:rgba(232,238,252,.55);letter-spacing:.02em}
.fly-kn span{position:relative;display:block;min-width:0}
.fly-kn .fly-in{width:100%;padding:0 18px 0 8px;font-variant-numeric:tabular-nums}
.fly-kn i{position:absolute;right:6px;top:50%;transform:translateY(-50%);font-style:normal;font-size:10.5px;color:rgba(232,238,252,.5);pointer-events:none;white-space:nowrap}
@media (max-width:1500px){.fly-look{display:none}}
.fly-kn input::-webkit-inner-spin-button,.fly-kn input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}
.fly-kn input{-moz-appearance:textfield}
/* music: the file picked, and the button that picks it */
.fly-musicpick{display:inline-flex;align-items:center;justify-content:center;cursor:pointer;margin-top:6px}
.fly-musicname{display:flex;align-items:center;gap:8px;font-size:12.5px;margin-bottom:6px}
.fly-musicname span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* the tool's own tracks, and the notice under a file of one's own — FLY_MUSIC_LIB */
.fly-musiclib-h{margin:12px 0 6px;font-size:10.5px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:rgba(232,238,252,.6)}
.fly-musiclib{display:grid;gap:6px}
.fly-musiclib .fly-btn{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;text-align:left}
.fly-musiclib .fly-btn b{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fly-musiclib .fly-btn small{flex:none;opacity:.7;font-weight:600}
.fly-musiclib .fly-btn.on{background:rgba(245,158,11,.18);box-shadow:inset 0 0 0 1px #f59e0b;color:#fff}
.fly-musicwarn{margin-top:8px;padding:8px 10px;border-left:3px solid #f59e0b;border-radius:4px;background:rgba(245,158,11,.08);color:rgba(255,248,236,.9)}

/* ── STREET NAMES IN THE FILM (js/fly-streets.js) ──
   The list off OpenStreetMap: a tick, the km, the road number, the
   name as the film will write it. Scrolls on its own; a city stage
   has a hundred streets. */
.fly-st-quick{margin:6px 0}
.fly-st-list{max-height:260px;overflow-y:auto;margin-top:6px;border-top:1px solid var(--border)}
.fly-st-row{display:flex;align-items:center;gap:6px;padding:3px 0;border-bottom:1px solid var(--border)}
.fly-st-row small{width:38px;flex:none;color:var(--text3);font-size:10.5px;text-align:right}
.fly-st-row b{flex:none;background:var(--gold,#f5c542);color:#0c0b08;border-radius:4px;padding:1px 5px;font-size:10px}
.fly-st-row .fly-in{flex:1;min-width:0;padding:3px 6px;font-size:12px}

/* The toast over the film studio: the studio stands at z-index 4000 and
   the toast at 1000, so every "Film saved." was said under it (Janny,
   29 Sep 2026: "ik zie niet echt een bevestiging"). */
body:has(.fly-studio) #toast{z-index:4100}
.fly-saved{color:var(--green,#16a34a);font-weight:700;margin:6px 0 0}
.fly-saved.err{color:var(--red,#dc2626)}

/* ── LAPS & SPEED IN THE FILM (js/fly-laps.js) ── */
.fly-lap-list{display:grid;gap:4px;margin:6px 0 10px}
.fly-lap-row{display:flex;align-items:center;gap:8px;justify-content:space-between;padding:4px 0;border-bottom:1px solid var(--border)}
.fly-lap-row span{display:grid;gap:1px;font-size:12px}
.fly-lap-row small{color:var(--text3);font-size:10.5px}
.fly-lap-row select{width:auto;flex:none}
/* the speed of one block: the km on the left, the choice beside it, inside the panel */
.fly-side .fly-lap-row span{flex:1 1 auto;min-width:0;white-space:nowrap}
.fly-side .fly-lap-row select.fly-in{width:auto;flex:0 1 auto;min-width:0;max-width:58%}
.fly-lap-sub{display:block;margin:10px 0 4px}
.fly-lap-zone{display:flex;align-items:center;gap:6px;margin-bottom:6px}
/* the relay: a colour dot before each part's name */
.fly-relay-names .fly-relay-dot{flex:0 0 24px;width:24px;height:24px}
.fly-relay-names .fly-in{flex:1 1 0;min-width:0}
/* a hand-set stretch: km from → to on one line, its speed under it */
.fly-zone-card{border:1px solid var(--border,rgba(255,255,255,.12));border-radius:8px;padding:6px;margin-bottom:6px}
.fly-zone-card .fly-lap-zone{margin-bottom:4px}
.fly-zone-card .fly-zone-x{width:100%}
.fly-zone-card .fly-zone-x + .fly-zone-x{margin-top:4px}
/* "here": take the km where the film stands — a quiet ring, not the red × */
.fly-here{flex:0 0 22px;width:22px;height:22px;padding:0;border-radius:50%;border:1px solid rgba(230,247,238,.3);background:transparent;
  color:rgba(230,247,238,.8);display:inline-grid;place-items:center;cursor:pointer}
.fly-here:hover{border-color:currentColor;color:#fff}
/* a sponsor spot (js/fly-sponsors.js): the logo, its name, where it stands */
.fly-sp-card{display:grid;gap:6px}
.fly-sp-card .fly-lap-zone{margin-bottom:0}
.fly-sp-card .fly-lap-zone select.fly-in{flex:1 1 0;min-width:0}
.fly-sp-thumb{flex:0 0 40px;width:40px;height:26px;object-fit:contain;background:#fff;border-radius:5px;padding:2px}
.fly-sp-card.fly-sp-off{border-color:rgba(226,54,41,.5)}
.fly-sp-show{justify-self:start;display:inline-flex;align-items:center;gap:6px}
.fly-lap-zone .fly-kn{flex:1;min-width:0}
.fly-lap-zone select{width:auto;flex:none}
/* ── LOGOS IN THE FILM (js/fly-logos.js) ── */
.fly-logo-lib{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0}
.fly-logo-chip{display:flex;align-items:center;gap:4px;border:1px solid var(--border);border-radius:8px;padding:4px 6px;background:#fff}
.fly-logo-chip.on{border-color:var(--gold-border,#f59e0b);box-shadow:0 0 0 1px var(--gold-border,#f59e0b)}
.fly-logo-chip label{display:flex;align-items:center;gap:4px;cursor:pointer}
.fly-logo-chip img{height:26px;max-width:90px;object-fit:contain}
.fly-logo-chip button{border:0;background:none;color:#555;cursor:pointer;font-size:14px;line-height:1;padding:0 2px}
.fly-logo-chip button.sure{color:#dc2626;font-size:11px;font-weight:700}

/* ── THE STUDIO PANEL IN TABS (flyTabsApply in js/flyover.js) ──
   One row of icons at the top, sticky while the section scrolls; the
   panel never wider than its column, so it never scrolls sideways. */
.fly-side{overflow-x:hidden}
.fly-side .fly-step[hidden]{display:none}
.fly-side .fly-row > *,.fly-side .fly-step > *{min-width:0}
.fly-side .fly-seg button{white-space:normal}
.fly-tabs{position:sticky;top:-4px;z-index:2;display:flex;flex-wrap:wrap;align-items:center;gap:4px;
  margin:0 -14px 4px;padding:10px 14px 8px;background:#060a14;border-bottom:1px solid rgba(232,238,252,.09)}
.fly-tabs button{width:34px;height:34px;display:flex;align-items:center;justify-content:center;border-radius:9px;
  border:1px solid rgba(232,238,252,.12);background:rgba(232,238,252,.04);color:rgba(232,238,252,.72);cursor:pointer;padding:0}
.fly-tabs button:hover{color:#fff;border-color:rgba(245,158,11,.6)}
.fly-tabs button.on{background:#f59e0b;border-color:#f59e0b;color:#0c0b08}
.fly-tabs button svg{width:17px;height:17px}
/* the search over every option (js/fly-search.js), a line of its own under the icons */
.fly-search{flex-basis:100%;display:flex;align-items:center;gap:6px;margin-top:6px}
/* ── THE STUDIO, EASIER (js/fly-ui.js) ── */
/* tabs with their names, five to a row */
.fly-side .fly-tabs{display:grid;grid-template-columns:repeat(5,minmax(0,1fr))}
.fly-side .fly-tabs .fly-search{grid-column:1 / -1}
.fly-side .fly-tabs button{width:auto;height:46px;flex-direction:column;gap:3px;padding:4px 2px}
.fly-side .fly-tabs button span{font-size:10px;font-weight:700;line-height:1.1;letter-spacing:.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.fly-side .fly-tabs button.on{background:#f59e0b;border-color:#f59e0b;color:#0c0b08}
/* a section folds at its heading */
.fly-side .fly-step>h4[data-fly="uifold"]{cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:8px;user-select:none}
.fly-side .fly-step>h4[data-fly="uifold"]::after{content:"";width:7px;height:7px;flex:none;border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(45deg);margin:0 4px 3px 0;opacity:.75;transition:transform .15s}
.fly-side .fly-step.fly-shut>h4::after{transform:rotate(-45deg);margin-bottom:0}
.fly-side .fly-step.fly-shut{padding-bottom:12px}
.fly-side .fly-step.fly-shut>:not(h4){display:none !important}
.fly-side .fly-step>h4[data-fly="uifold"]:focus-visible{outline:2px solid #f59e0b;outline-offset:3px;border-radius:3px}
/* save and share in the top bar */
.fly-ui-save .fly-ui-dot{display:none;width:7px;height:7px;border-radius:50%;background:#f59e0b;margin-left:2px}
.fly-ui-save.dirty .fly-ui-dot{display:inline-block}
.fly-ui-saved{font-size:11px;color:rgba(232,238,252,.6);white-space:nowrap}
@media (max-width:1500px){.fly-ui-saved{display:none}}
@media (max-width:1280px){.fly-top-r .fly-ui-save span,.fly-top-r [data-fly="uishare"] span{display:none}}
/* a dialogue opened from the studio stands over it */
body:has(.fly-studio) #modal-bg{z-index:4050}
/* Google Earth's steps */
.fly-es-steps{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:4px}
.fly-es-steps li{display:flex;flex-direction:column;align-items:center;gap:4px;padding:7px 2px;border-radius:8px;background:rgba(232,238,252,.05);font-size:10.5px;text-align:center;line-height:1.2;color:rgba(232,238,252,.7)}
.fly-es-steps b{display:inline-flex;width:20px;height:20px;border-radius:50%;align-items:center;justify-content:center;background:rgba(232,238,252,.12);font-size:11px}
.fly-es-steps li.done b{background:#22c55e;color:#06140a}
.fly-es-steps li.next{box-shadow:inset 0 0 0 1px #f59e0b;color:#fff}
.fly-es-steps li.next b{background:#f59e0b;color:#060a14}
.fly-es-steps li.skip{opacity:.4}
.fly-es-next{margin:0;font-size:12px;line-height:1.4;color:#fff}
/* the time bar the whole width, the controls under it; its marks */
.fly-studio:not(.fly-player) .fly-bar{flex-wrap:wrap;row-gap:8px}
.fly-studio:not(.fly-player) .fly-scrubwrap{order:-1;flex:1 1 100%;padding-top:10px}
/* the music under the time bar, dragged sideways — flyMusicLane() */
.fly-musiclane{order:-1;flex:1 1 100%;position:relative;height:26px;margin:-4px 8px 0;border-radius:6px;
  background:rgba(232,238,252,.05);box-shadow:inset 0 0 0 1px rgba(232,238,252,.1);cursor:grab;touch-action:none;overflow:hidden}
.fly-musiclane:hover{box-shadow:inset 0 0 0 1px rgba(245,158,11,.5)}
.fly-musiclane.drag{cursor:grabbing;box-shadow:inset 0 0 0 1px #f59e0b}
.fly-musiclane canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
.fly-musiclane-t{position:absolute;top:50%;transform:translateY(-50%);font-size:11px;font-weight:700;color:#fff;
  text-shadow:0 1px 3px rgba(0,0,0,.9);pointer-events:none;white-space:nowrap;max-width:60%;overflow:hidden;text-overflow:ellipsis}
.fly-player .fly-musiclane{display:none}
.fly-marks{position:absolute;left:8px;right:8px;top:0;height:8px;pointer-events:none}
.fly-mark{position:absolute;top:0;width:8px;height:8px;margin-left:-4px;padding:0;border:0;border-radius:50%;background:rgba(232,238,252,.6);cursor:pointer;pointer-events:auto}
.fly-mark:hover{background:#fff;box-shadow:0 0 0 3px rgba(255,255,255,.25)}
.fly-mark-climb{background:#e23629;border-radius:1px;width:7px;height:7px;margin-left:-3.5px;transform:rotate(45deg)}
.fly-mark-sf{background:#34d399}
/* the ? and its list */
.fly-ui-help{display:inline-flex}
.fly-ui-help .fly-btn{padding:0 10px}
.fly-ui-keys{position:fixed;right:340px;bottom:84px;z-index:6;width:320px;max-height:70vh;overflow:auto;padding:12px 14px;border-radius:10px;
  background:#0c1322;border:1px solid rgba(232,238,252,.16);box-shadow:0 14px 44px rgba(0,0,0,.55);font-size:12px;color:#e8eefc}
.fly-ui-keys[hidden]{display:none}
.fly-ui-keys h5{margin:0 0 6px;font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:#f59e0b}
.fly-ui-keys dl{display:grid;grid-template-columns:auto 1fr;gap:5px 12px;margin:0 0 12px}
.fly-ui-keys dl:last-child{margin-bottom:0}
.fly-ui-keys dt{color:rgba(232,238,252,.8);white-space:nowrap}
.fly-ui-keys dd{margin:0;color:rgba(232,238,252,.7)}
.fly-ui-keys kbd{font:600 11px/1 var(--font-body);padding:3px 6px;border-radius:5px;background:rgba(232,238,252,.1);border:1px solid rgba(232,238,252,.18)}
.fly-search .fly-in{flex:1;min-width:0}
.fly-search-none{margin:10px 0}
/* the camera templates (js/fly-templates.js): five buttons with their path drawn */
.fly-tpl-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(86px,1fr));gap:6px}
.fly-side .fly-tpl{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;height:auto;min-height:62px;padding:8px 4px;font-size:11.5px;text-align:center;line-height:1.2;white-space:normal}
.fly-side .fly-tpl svg{color:#f59e0b;width:22px;height:22px;flex:none}

/* ── THE FILM'S FIRST PAGE IN THREE STEPS (flySetupHtml) ── */
.fly-su .fly-setup-bd{grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);gap:4px 32px;padding:6px 24px 18px}
.fly-su-films{padding:16px 24px 4px;border-bottom:1px solid rgba(232,238,252,.08)}
.fly-su-films h4{margin:0 0 8px;font-size:11px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;color:#f59e0b}
.fly-su-or{margin:10px 0 0;font-size:12px;color:rgba(232,238,252,.55)}
.fly-su-step h4{display:flex;align-items:center;gap:8px}
.fly-su-n{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;
  background:#f59e0b;color:#0c0b08;font-size:11px;font-weight:900;letter-spacing:0}
.fly-su-right{display:grid;align-content:start;gap:10px;padding-top:14px}
.fly-su-right .fly-snap{width:100%;height:auto;border-radius:12px;background:#0b1220}
.fly-su-go{justify-self:stretch;justify-content:center;padding:14px 18px;font-size:15px}
@media (max-width:820px){.fly-su .fly-setup-bd{grid-template-columns:1fr}}

/* ── A FINGER, NOT A MOUSE ─────────────────────────────────────
   On a touch screen the small controls grow to a size a thumb can hit
   standing at a junction: the − / + beside a headcount (28px wide), the
   eye on a key row (22px), the layer chips of the field map (24px), the
   small buttons everywhere (36px). Desktop keeps its compact sizes
   (impeccable audit, 5 Oct 2026). */
@media (pointer:coarse){
  .btn.sm{min-height:40px}
  .mob-step-b{flex-basis:40px}
  .mobm-eye{width:34px;height:34px}
  .fld-chip{min-height:36px;padding:7px 12px}
}
/* The print sheet's signs, notes and grips move under a finger: without
   this the browser read the drag as a scroll of the page and cancelled
   it, and the sign never moved. The sheet itself still scrolls. */
.cp-sheet [data-note],.cp-sheet [data-note-h],.cp-sheet [data-cp-mark]{touch-action:none}
/* 3D objects in the course film — js/fly-objects.js */
.fly-oblib{display:grid;grid-template-columns:1fr 1fr;gap:6px}
.fly-oblib .fly-btn{height:auto;min-height:34px;padding:6px 8px;justify-content:flex-start;white-space:normal;text-align:left;line-height:1.2}
.fly-oblib .fly-btn span{font-size:16px;flex:none}
.fly-oblib .fly-btn b{font-size:11.5px;font-weight:700;min-width:0}
.fly-musicpick.disabled{opacity:.5;pointer-events:none}
.fly-obup{width:100%;height:auto;min-height:34px;padding:7px 10px;white-space:normal;line-height:1.25;text-align:left}
.fly-obbusy{color:#f59e0b;font-weight:700}
.fly-oblist{display:grid;gap:6px;margin-bottom:10px}
.fly-obrow{display:flex;align-items:center;gap:7px;padding:6px 8px;border-radius:8px;background:rgba(232,238,252,.05);border:1px solid rgba(232,238,252,.1)}
.fly-obrow.off{opacity:.55}
.fly-obico{font-size:17px;flex:none}
.fly-obname{flex:1;min-width:0;display:grid;line-height:1.25}
.fly-obname b{font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fly-obname i{font-style:normal;font-size:11px;color:rgba(232,238,252,.6)}
.fly-obname em{font-style:normal;font-size:11px;color:#f59e0b}
.fly-btn.sm{height:28px;padding:0 8px;font-size:11.5px}
.fly-btn.sm svg{width:13px;height:13px}
.fly-btn.on{background:rgba(245,158,11,.18);border-color:#f59e0b;color:#fff}
.fly-btn.danger:not(.primary){color:#ff8a80;border-color:rgba(226,54,41,.5)}
.fly-btn.wide{width:100%;justify-content:center;height:38px}
.fly-btn:disabled{opacity:.45;cursor:default}
/* the placing map, over the studio */
.fly-obwin{position:fixed;inset:0;z-index:4500;display:grid;grid-template-columns:minmax(0,1fr) 340px;background:#060a14;color:#e8eefc}
.fly-obwin-map{position:relative;min-height:0}
.fly-obwin-side{overflow:auto;padding:14px 14px 70px;border-left:1px solid rgba(232,238,252,.09);display:grid;align-content:start;gap:8px}
.fly-obwin-side h3{margin:2px 0 4px;font-family:var(--font-display);font-size:17px}
.fly-obwin-x{position:absolute;right:14px;bottom:14px;z-index:2;height:38px;background:#f59e0b;border-color:#f59e0b;color:#060a14}
.fly-obsearch,.fly-obcoord{display:flex;gap:6px}
.fly-obsearch .fly-in,.fly-obcoord .fly-in{flex:1}
.fly-obhits{display:grid;gap:4px}
.fly-obhit,.fly-obpick{display:flex;align-items:center;gap:8px;width:100%;padding:6px 8px;border-radius:8px;cursor:pointer;text-align:left;
  font:inherit;font-size:12px;color:#e8eefc;background:rgba(232,238,252,.05);border:1px solid rgba(232,238,252,.1)}
.fly-obhit{display:grid;gap:1px}
.fly-obhit i{font-style:normal;font-size:11px;color:rgba(232,238,252,.6)}
.fly-obpick b{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fly-obpick svg{width:13px;height:13px;color:#f59e0b}
.fly-obpick.on{border-color:#f59e0b;background:rgba(245,158,11,.14)}
.fly-obpick.off{opacity:.55}
.fly-obedit{display:grid;gap:8px;padding-top:10px;border-top:1px solid rgba(232,238,252,.09)}
.fly-obhead{display:flex;align-items:center;gap:8px}
.fly-obhead span{font-size:20px}
.fly-obhead .fly-in{flex:1;font-weight:700}
.fly-obedit input[type=color]{width:44px;height:30px;padding:0;border:1px solid rgba(232,238,252,.16);border-radius:6px;background:none;cursor:pointer}
.fly-obbar{display:flex;flex-wrap:wrap;gap:6px}
.fly-obpin{width:26px;height:34px;cursor:grab;background:no-repeat center/contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 34'%3E%3Cpath d='M13 33C13 33 2 20 2 12.5A11 11 0 0 1 24 12.5C24 20 13 33 13 33Z' fill='%23f59e0b' stroke='%23060a14' stroke-width='2'/%3E%3Ccircle cx='13' cy='12.5' r='4.5' fill='%23060a14'/%3E%3C/svg%3E")}
.fly-obpin.pinned{cursor:default;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 34'%3E%3Cpath d='M13 33C13 33 2 20 2 12.5A11 11 0 0 1 24 12.5C24 20 13 33 13 33Z' fill='%2338bdf8' stroke='%23060a14' stroke-width='2'/%3E%3Crect x='8.5' y='11' width='9' height='7' rx='1.5' fill='%23060a14'/%3E%3Cpath d='M10.5 11V9a2.5 2.5 0 0 1 5 0v2' fill='none' stroke='%23060a14' stroke-width='1.8'/%3E%3C/svg%3E")}
@media (max-width:760px){
  .fly-obwin{grid-template-columns:1fr;grid-template-rows:55vh minmax(0,1fr)}
  .fly-obwin-side{border-left:0;border-top:1px solid rgba(232,238,252,.09)}
  .fly-obwin-x{top:12px;bottom:auto}
}
/* the caption text under its km — js/fly-extras.js (9 Oct 2026) */
.fly-cap-text{width:100%;box-sizing:border-box;margin-top:6px}
/* automatic fast-forward — js/fly-extras.js (9 Oct 2026) */
.fly-ff{border:1px solid rgba(245,158,11,.35);background:rgba(245,158,11,.06);border-radius:10px;padding:10px;margin:8px 0 12px}
.fly-ff-hd b{font-size:12.5px;color:#fbbf24}
.fly-ff-row{display:flex;gap:6px;margin:8px 0}
.fly-ff-row select{flex:1;min-width:0}
.fly-ff .fly-btn{width:100%;margin-top:4px;justify-content:center}
.fly-ff .fly-ff-sum{margin:8px 0 2px}
/* the real race, afterwards — js/fly-extras.js (9 Oct 2026) */
.fly-real-card .fly-real-col{width:34px;height:32px;padding:2px;border-radius:8px;border:1px solid rgba(232,238,252,.18);background:transparent;flex:none;cursor:pointer}
.fly-real-card .fly-real-name{flex:1;min-width:0}
.fly-real-ref{display:flex;align-items:center;gap:6px;margin-top:6px;font-size:12px;color:rgba(232,238,252,.78)}
.fly-real-add{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.fly-real-cars{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.fly-real-cars small{opacity:.65;font-weight:600;margin-left:4px}
/* live on the big screen — js/fly-extras.js (10 Oct 2026) */
.fly-stage:fullscreen{background:#000}
.fly-btn.fly-live-go{background:#dc2626;border-color:#dc2626;color:#fff}
