/* /vendor/leaflet/leaflet.css */
/* required styles */

.leaflet-pane,
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-tile-container,
.leaflet-pane > svg,
.leaflet-pane > canvas,
.leaflet-zoom-box,
.leaflet-image-layer,
.leaflet-layer {
	position: absolute;
	left: 0;
	top: 0;
	}
.leaflet-container {
	overflow: hidden;
	}
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow {
	-webkit-user-select: none;
	   -moz-user-select: none;
	        user-select: none;
	  -webkit-user-drag: none;
	}
/* Prevents IE11 from highlighting tiles in blue */
.leaflet-tile::selection {
	background: transparent;
}
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
.leaflet-safari .leaflet-tile {
	image-rendering: -webkit-optimize-contrast;
	}
/* hack that prevents hw layers "stretching" when loading new tiles */
.leaflet-safari .leaflet-tile-container {
	width: 1600px;
	height: 1600px;
	-webkit-transform-origin: 0 0;
	}
.leaflet-marker-icon,
.leaflet-marker-shadow {
	display: block;
	}
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
.leaflet-container .leaflet-overlay-pane svg {
	max-width: none !important;
	max-height: none !important;
	}
.leaflet-container .leaflet-marker-pane img,
.leaflet-container .leaflet-shadow-pane img,
.leaflet-container .leaflet-tile-pane img,
.leaflet-container img.leaflet-image-layer,
.leaflet-container .leaflet-tile {
	max-width: none !important;
	max-height: none !important;
	width: auto;
	padding: 0;
	}

.leaflet-container img.leaflet-tile {
	/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
	mix-blend-mode: plus-lighter;
}

.leaflet-container.leaflet-touch-zoom {
	-ms-touch-action: pan-x pan-y;
	touch-action: pan-x pan-y;
	}
.leaflet-container.leaflet-touch-drag {
	-ms-touch-action: pinch-zoom;
	/* Fallback for FF which doesn't support pinch-zoom */
	touch-action: none;
	touch-action: pinch-zoom;
}
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
	-ms-touch-action: none;
	touch-action: none;
}
.leaflet-container {
	-webkit-tap-highlight-color: transparent;
}
.leaflet-container a {
	-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
}
.leaflet-tile {
	filter: inherit;
	visibility: hidden;
	}
.leaflet-tile-loaded {
	visibility: inherit;
	}
.leaflet-zoom-box {
	width: 0;
	height: 0;
	-moz-box-sizing: border-box;
	     box-sizing: border-box;
	z-index: 800;
	}
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
.leaflet-overlay-pane svg {
	-moz-user-select: none;
	}

.leaflet-pane         { z-index: 400; }

.leaflet-tile-pane    { z-index: 200; }
.leaflet-overlay-pane { z-index: 400; }
.leaflet-shadow-pane  { z-index: 500; }
.leaflet-marker-pane  { z-index: 600; }
.leaflet-tooltip-pane   { z-index: 650; }
.leaflet-popup-pane   { z-index: 700; }

.leaflet-map-pane canvas { z-index: 100; }
.leaflet-map-pane svg    { z-index: 200; }

.leaflet-vml-shape {
	width: 1px;
	height: 1px;
	}
.lvml {
	behavior: url(#default#VML);
	display: inline-block;
	position: absolute;
	}


/* control positioning */

.leaflet-control {
	position: relative;
	z-index: 800;
	pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
	pointer-events: auto;
	}
.leaflet-top,
.leaflet-bottom {
	position: absolute;
	z-index: 1000;
	pointer-events: none;
	}
.leaflet-top {
	top: 0;
	}
.leaflet-right {
	right: 0;
	}
.leaflet-bottom {
	bottom: 0;
	}
.leaflet-left {
	left: 0;
	}
.leaflet-control {
	float: left;
	clear: both;
	}
.leaflet-right .leaflet-control {
	float: right;
	}
.leaflet-top .leaflet-control {
	margin-top: 10px;
	}
.leaflet-bottom .leaflet-control {
	margin-bottom: 10px;
	}
.leaflet-left .leaflet-control {
	margin-left: 10px;
	}
.leaflet-right .leaflet-control {
	margin-right: 10px;
	}


/* zoom and fade animations */

.leaflet-fade-anim .leaflet-popup {
	opacity: 0;
	-webkit-transition: opacity 0.2s linear;
	   -moz-transition: opacity 0.2s linear;
	        transition: opacity 0.2s linear;
	}
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
	opacity: 1;
	}
.leaflet-zoom-animated {
	-webkit-transform-origin: 0 0;
	    -ms-transform-origin: 0 0;
	        transform-origin: 0 0;
	}
svg.leaflet-zoom-animated {
	will-change: transform;
}

.leaflet-zoom-anim .leaflet-zoom-animated {
	-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
	   -moz-transition:    -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
	        transition:         transform 0.25s cubic-bezier(0,0,0.25,1);
	}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile {
	-webkit-transition: none;
	   -moz-transition: none;
	        transition: none;
	}

.leaflet-zoom-anim .leaflet-zoom-hide {
	visibility: hidden;
	}


/* cursors */

.leaflet-interactive {
	cursor: pointer;
	}
.leaflet-grab {
	cursor: -webkit-grab;
	cursor:    -moz-grab;
	cursor:         grab;
	}
.leaflet-crosshair,
.leaflet-crosshair .leaflet-interactive {
	cursor: crosshair;
	}
.leaflet-popup-pane,
.leaflet-control {
	cursor: auto;
	}
.leaflet-dragging .leaflet-grab,
.leaflet-dragging .leaflet-grab .leaflet-interactive,
.leaflet-dragging .leaflet-marker-draggable {
	cursor: move;
	cursor: -webkit-grabbing;
	cursor:    -moz-grabbing;
	cursor:         grabbing;
	}

/* marker & overlays interactivity */
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-image-layer,
.leaflet-pane > svg path,
.leaflet-tile-container {
	pointer-events: none;
	}

.leaflet-marker-icon.leaflet-interactive,
.leaflet-image-layer.leaflet-interactive,
.leaflet-pane > svg path.leaflet-interactive,
svg.leaflet-image-layer.leaflet-interactive path {
	pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
	pointer-events: auto;
	}

/* visual tweaks */

.leaflet-container {
	background: #ddd;
	outline-offset: 1px;
	}
.leaflet-container a {
	color: #0078A8;
	}
.leaflet-zoom-box {
	border: 2px dotted #38f;
	background: rgba(255,255,255,0.5);
	}


/* general typography */
.leaflet-container {
	font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
	font-size: 12px;
	font-size: 0.75rem;
	line-height: 1.5;
	}


/* general toolbar styles */

.leaflet-bar {
	box-shadow: 0 1px 5px rgba(0,0,0,0.65);
	border-radius: 4px;
	}
.leaflet-bar a {
	background-color: #fff;
	border-bottom: 1px solid #ccc;
	width: 26px;
	height: 26px;
	line-height: 26px;
	display: block;
	text-align: center;
	text-decoration: none;
	color: black;
	}
.leaflet-bar a,
.leaflet-control-layers-toggle {
	background-position: 50% 50%;
	background-repeat: no-repeat;
	display: block;
	}
.leaflet-bar a:hover,
.leaflet-bar a:focus {
	background-color: #f4f4f4;
	}
.leaflet-bar a:first-child {
	border-top-left-radius: 4px;
	border-top-right-radius: 4px;
	}
.leaflet-bar a:last-child {
	border-bottom-left-radius: 4px;
	border-bottom-right-radius: 4px;
	border-bottom: none;
	}
.leaflet-bar a.leaflet-disabled {
	cursor: default;
	background-color: #f4f4f4;
	color: #bbb;
	}

.leaflet-touch .leaflet-bar a {
	width: 30px;
	height: 30px;
	line-height: 30px;
	}
.leaflet-touch .leaflet-bar a:first-child {
	border-top-left-radius: 2px;
	border-top-right-radius: 2px;
	}
.leaflet-touch .leaflet-bar a:last-child {
	border-bottom-left-radius: 2px;
	border-bottom-right-radius: 2px;
	}

/* zoom control */

.leaflet-control-zoom-in,
.leaflet-control-zoom-out {
	font: bold 18px 'Lucida Console', Monaco, monospace;
	text-indent: 1px;
	}

.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out  {
	font-size: 22px;
	}


/* layers control */

.leaflet-control-layers {
	box-shadow: 0 1px 5px rgba(0,0,0,0.4);
	background: #fff;
	border-radius: 5px;
	}
.leaflet-control-layers-toggle {
	background-image: url(/vendor/leaflet/images/layers.png);
	width: 36px;
	height: 36px;
	}
.leaflet-retina .leaflet-control-layers-toggle {
	background-image: url(/vendor/leaflet/images/layers-2x.png);
	background-size: 26px 26px;
	}
.leaflet-touch .leaflet-control-layers-toggle {
	width: 44px;
	height: 44px;
	}
.leaflet-control-layers .leaflet-control-layers-list,
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
	display: none;
	}
.leaflet-control-layers-expanded .leaflet-control-layers-list {
	display: block;
	position: relative;
	}
.leaflet-control-layers-expanded {
	padding: 6px 10px 6px 6px;
	color: #333;
	background: #fff;
	}
.leaflet-control-layers-scrollbar {
	overflow-y: scroll;
	overflow-x: hidden;
	padding-right: 5px;
	}
.leaflet-control-layers-selector {
	margin-top: 2px;
	position: relative;
	top: 1px;
	}
.leaflet-control-layers label {
	display: block;
	font-size: 13px;
	font-size: 1.08333em;
	}
.leaflet-control-layers-separator {
	height: 0;
	border-top: 1px solid #ddd;
	margin: 5px -10px 5px -6px;
	}

/* Default icon URLs */
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
	background-image: url(/vendor/leaflet/images/marker-icon.png);
	}


/* attribution and scale controls */

.leaflet-container .leaflet-control-attribution {
	background: #fff;
	background: rgba(255, 255, 255, 0.8);
	margin: 0;
	}
.leaflet-control-attribution,
.leaflet-control-scale-line {
	padding: 0 5px;
	color: #333;
	line-height: 1.4;
	}
.leaflet-control-attribution a {
	text-decoration: none;
	}
.leaflet-control-attribution a:hover,
.leaflet-control-attribution a:focus {
	text-decoration: underline;
	}
.leaflet-attribution-flag {
	display: inline !important;
	vertical-align: baseline !important;
	width: 1em;
	height: 0.6669em;
	}
.leaflet-left .leaflet-control-scale {
	margin-left: 5px;
	}
.leaflet-bottom .leaflet-control-scale {
	margin-bottom: 5px;
	}
.leaflet-control-scale-line {
	border: 2px solid #777;
	border-top: none;
	line-height: 1.1;
	padding: 2px 5px 1px;
	white-space: nowrap;
	-moz-box-sizing: border-box;
	     box-sizing: border-box;
	background: rgba(255, 255, 255, 0.8);
	text-shadow: 1px 1px #fff;
	}
.leaflet-control-scale-line:not(:first-child) {
	border-top: 2px solid #777;
	border-bottom: none;
	margin-top: -2px;
	}
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
	border-bottom: 2px solid #777;
	}

.leaflet-touch .leaflet-control-attribution,
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
	box-shadow: none;
	}
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
	border: 2px solid rgba(0,0,0,0.2);
	background-clip: padding-box;
	}


/* popup */

.leaflet-popup {
	position: absolute;
	text-align: center;
	margin-bottom: 20px;
	}
.leaflet-popup-content-wrapper {
	padding: 1px;
	text-align: left;
	border-radius: 12px;
	}
.leaflet-popup-content {
	margin: 13px 24px 13px 20px;
	line-height: 1.3;
	font-size: 13px;
	font-size: 1.08333em;
	min-height: 1px;
	}
.leaflet-popup-content p {
	margin: 17px 0;
	margin: 1.3em 0;
	}
.leaflet-popup-tip-container {
	width: 40px;
	height: 20px;
	position: absolute;
	left: 50%;
	margin-top: -1px;
	margin-left: -20px;
	overflow: hidden;
	pointer-events: none;
	}
.leaflet-popup-tip {
	width: 17px;
	height: 17px;
	padding: 1px;

	margin: -10px auto 0;
	pointer-events: auto;

	-webkit-transform: rotate(45deg);
	   -moz-transform: rotate(45deg);
	    -ms-transform: rotate(45deg);
	        transform: rotate(45deg);
	}
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
	background: white;
	color: #333;
	box-shadow: 0 3px 14px rgba(0,0,0,0.4);
	}
.leaflet-container a.leaflet-popup-close-button {
	position: absolute;
	top: 0;
	right: 0;
	border: none;
	text-align: center;
	width: 24px;
	height: 24px;
	font: 16px/24px Tahoma, Verdana, sans-serif;
	color: #757575;
	text-decoration: none;
	background: transparent;
	}
.leaflet-container a.leaflet-popup-close-button:hover,
.leaflet-container a.leaflet-popup-close-button:focus {
	color: #585858;
	}
.leaflet-popup-scrolled {
	overflow: auto;
	}

.leaflet-oldie .leaflet-popup-content-wrapper {
	-ms-zoom: 1;
	}
.leaflet-oldie .leaflet-popup-tip {
	width: 24px;
	margin: 0 auto;

	-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
	filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
	}

.leaflet-oldie .leaflet-control-zoom,
.leaflet-oldie .leaflet-control-layers,
.leaflet-oldie .leaflet-popup-content-wrapper,
.leaflet-oldie .leaflet-popup-tip {
	border: 1px solid #999;
	}


/* div icon */

.leaflet-div-icon {
	background: #fff;
	border: 1px solid #666;
	}


/* Tooltip */
/* Base styles for the element that has a tooltip */
.leaflet-tooltip {
	position: absolute;
	padding: 6px;
	background-color: #fff;
	border: 1px solid #fff;
	border-radius: 3px;
	color: #222;
	white-space: nowrap;
	-webkit-user-select: none;
	-moz-user-select: none;
	-ms-user-select: none;
	user-select: none;
	pointer-events: none;
	box-shadow: 0 1px 3px rgba(0,0,0,0.4);
	}
.leaflet-tooltip.leaflet-interactive {
	cursor: pointer;
	pointer-events: auto;
	}
.leaflet-tooltip-top:before,
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
	position: absolute;
	pointer-events: none;
	border: 6px solid transparent;
	background: transparent;
	content: "";
	}

/* Directions */

.leaflet-tooltip-bottom {
	margin-top: 6px;
}
.leaflet-tooltip-top {
	margin-top: -6px;
}
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-top:before {
	left: 50%;
	margin-left: -6px;
	}
.leaflet-tooltip-top:before {
	bottom: 0;
	margin-bottom: -12px;
	border-top-color: #fff;
	}
.leaflet-tooltip-bottom:before {
	top: 0;
	margin-top: -12px;
	margin-left: -6px;
	border-bottom-color: #fff;
	}
.leaflet-tooltip-left {
	margin-left: -6px;
}
.leaflet-tooltip-right {
	margin-left: 6px;
}
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
	top: 50%;
	margin-top: -6px;
	}
.leaflet-tooltip-left:before {
	right: 0;
	margin-right: -12px;
	border-left-color: #fff;
	}
.leaflet-tooltip-right:before {
	left: 0;
	margin-left: -12px;
	border-right-color: #fff;
	}

/* Printing */

@media print {
	/* Prevent printers from removing background-images of controls. */
	.leaflet-control {
		-webkit-print-color-adjust: exact;
		print-color-adjust: exact;
		}
	}

/* /tokens.css */
/* TrailGoat — design tokens: the one palette vocabulary (TG-281).
 *
 * Loaded FIRST on every page, before the page's own stylesheet, so every
 * colour on the site traces back here. Page stylesheets (fuel.css, home.css,
 * site_performance.css) no longer carry their own :root palette; the theme
 * files (emerald / alpenglow / aurora / firstlight) override exactly these
 * names under their html.theme-* class, values unchanged.
 *
 * "Forest" — the default dark "trail at dusk" palette — is the plain :root
 * block below. Every token here is either today's value under a new name, or
 * a new step nothing consumes yet: this file is a visual no-op by contract. */

:root {
    /* ---- Ground: four steps, well → page → panel → raised ---- */
    --bg-0: #07120f;          /* deepest pine — the page */
    --bg-1: #0a1a1c;          /* forest navy — panels */
    --bg-well: color-mix(in srgb, var(--bg-0) 80%, #000);   /* inset tracks & wells, below the page */
    --bg-2:    color-mix(in srgb, var(--bg-1) 93%, #fff);   /* raised — --glass-2 flattened over --bg-1 */

    /* ---- Ink: four steps, bright → text → muted → faint ---- */
    --ink: #eaf4ee;           /* near-white text */
    --muted: #8ea7a0;         /* muted sage */
    --ink-bright: color-mix(in srgb, var(--ink) 60%, #fff);          /* headline emphasis */
    --faint:      color-mix(in srgb, var(--muted) 70%, var(--bg-0)); /* hints, placeholders, disabled */

    /* ---- Accent: the one hue on duty for actions and "current" ---- */
    /* Moss (TG-282). Orange is retired from chrome — it survives only as the
       Fueling data tint below. Each theme sets its own green-family accent;
       --accent-ink is the text colour on a solid accent fill (dark ink here,
       ≥12:1 on the forest ground; First Light flips it to paper). */
    --accent: #9ae600;
    --accent-ink: var(--bg-well);
    --selection: color-mix(in srgb, var(--accent) 28%, transparent);

    /* ---- The neutral ladder: every interactive state that is not the accent ----
       Chrome (buttons, toggles, nav links, hovers, menus, toasts, inputs) uses
       ONLY --accent plus these steps of the ink. Fills: idle 4% → hover 8% →
       selected 18%. Edges: a defined border sits at 40%; hover/focus edges and
       focus rings at 25%. Never a feature tint, never a coloured glow. */
    --fill-idle: color-mix(in srgb, var(--ink) 4%, transparent);
    --fill-hover: color-mix(in srgb, var(--ink) 8%, transparent);
    --fill-selected: color-mix(in srgb, var(--ink) 18%, transparent);
    --edge: color-mix(in srgb, var(--ink) 40%, transparent);
    --edge-soft: color-mix(in srgb, var(--ink) 25%, transparent);
    --ring: color-mix(in srgb, var(--ink) 25%, transparent);

    /* ---- Lines & glass ---- */
    --line: rgba(255, 255, 255, 0.09);
    /* Half a hairline, for edges that should be felt rather than seen — the
       code chip below. Derived from --line on purpose: a theme that re-lights
       the line gets a matching faint for free (TG-299). */
    --line-faint: color-mix(in srgb, var(--line) 55%, transparent);
    --glass: rgba(255, 255, 255, 0.045);
    --glass-2: rgba(255, 255, 255, 0.07);

    /* ---- Feature palette: one hue per Run Planner section ----
       Nine sections, nine hues, spread around the wheel so no two cards read
       as the same colour (KRI-119). Every theme overrides all of them; add a
       token here and there. These belong to data-viz and section iconography
       — charts, elevation, map layers, section icons — never to chrome (TG-282):
       not buttons, not hovers, not active/selected states. */
    --c-fuel: #ff7a1a;        /* Fueling */
    --c-pace: #9ae600;        /* Pacing */
    --c-crew: #3ad17f;        /* Crew — meadow */
    --c-course: #19c3b1;      /* Course */
    --c-gear: #8b6cff;        /* Gear */
    --c-weather: #e070ee;     /* Weather — dusk sky */
    --c-climb: #ff5d73;       /* Climbs */
    --c-aid: #36c5f0;         /* Aid stations + descents */
    --gold: #ffd23f;          /* AI coach — matches Capra's wordmark gradient; brand hue, outside the feature set */

    /* ---- Status: the three semantic colours (one status vocabulary) ----
       "Saved", "needs a look", "failed" — the words every status chip, error
       line and toast dot mean. They were five different reds and a handful of
       greens across the stylesheets; now they are three names, set per theme
       like the feature hues. Semantic, not accent: --ok is never the button
       colour and --accent is never "success" (TG-282). Each theme overrides
       all three, and only the state's colour changes — the chip's shape, its
       mono caps and its 1px currentColor edge stay the same everywhere. */
    --ok: #3ad17f;            /* ready, saved, synced */
    --warn: #ffb020;          /* draft, stale, needs a look */
    --bad: #ff5d73;           /* failed, invalid, destructive */

    /* ---- Legacy names: aliases of the feature palette during transition ----
       Every existing stylesheet reads these. They resolve through the theme's
       override of the --c-* token, so a theme only sets the new names. */
    --orange: var(--c-fuel);
    --moss: var(--c-pace);
    --fern: var(--c-crew);
    --teal: var(--c-course);
    --violet: var(--c-gear);
    --plum: var(--c-weather);
    --coral: var(--c-climb);
    --aqua: var(--c-aid);

    /* ---- Corners: two radii for the whole chrome (TG-283) ----
       Depth comes from thin borders and ground steps, not from blur, so the
       corners come down to two steps: --r-ctl for anything you press (nav
       links, buttons, chips, unit toggles, inputs, menu rows) and --r-card for
       the surfaces they sit on (panels, cards, menus, modals, toasts, the
       command palette). Avatars and the theme swatch dots stay round — they
       are pictures, not controls — and so do meters, progress bars and slider
       tracks, which are data. */
    --r-ctl: 6px;
    --r-card: 10px;

    /* ---- Type: three cuts of one family (TG-288) ---- */
    /* The Red Hat superfamily, in three roles: Display for headlines and the
       wordmark, Text for body copy and the chrome, Mono for the topbar, the
       small-caps labels and every figure. TrailGoat is secretly a numbers
       product, so its figures stay set like instrument readings — tabular,
       units tracked out in caps (TG-284) — but the mono now visibly belongs to
       the same family as the prose beside it instead of being a fourth rented
       font. The system fallbacks are deliberate: block fonts.googleapis and the
       page still reads and the columns still line up. */
    --display: 'Red Hat Display', -apple-system, BlinkMacSystemFont, sans-serif;
    --body: 'Red Hat Text', -apple-system, BlinkMacSystemFont, sans-serif;
    --mono: 'Red Hat Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

    /* ---- The floor under a mono-caps label (TG-301) ----
       Mono caps with letter-spacing is the product's label voice, and it is
       the voice that shrinks first: several of these had drifted to 0.6rem —
       9.6px of tracked-out uppercase, which is under what a label can be read
       at. This is a floor, not a size. A label already above it keeps its own
       size via max(); one below it comes up to meet this. It steps UP on a
       phone, where the screen is closer but smaller and the same type is
       harder, not easier. Decorative marks (the goat's bib, the `i` glyph)
       are not labels and are exempt. */
    --mono-cap: 0.6875rem;                 /* 11px */

    /* ---- Motion: announce the change, then stop (TG-285) ---- */
    /* One easing curve and two durations for the whole product. Motion here
       exists to say something arrived — a menu, a toast, the palette — and
       then it is over. Nothing in the chrome loops forever under a planning
       tool the runner is trying to read. */
    --ease-snap: cubic-bezier(0.23, 1, 0.32, 1);   /* easeOutQuint */
    --dur-ctl: 150ms;                              /* controls */
    --dur-layer: 250ms;                            /* layers that arrive */

    /* ---- You are here: the one two-colour mark (TG-287) ----
       Omarchy's single indulgence, ported: the active window's gradient border.
       Exactly ONE element per view wears it — the section chip in view on the
       planner and Training, the active view tab on /courses. The pair is the
       wordmark's (teal→moss), so each theme's own --teal/--accent makes it
       theirs. The fill is the raised ground: the padding-box layer must be
       opaque, or the ring would bleed through the middle. Never on cards,
       buttons, menus or the topbar — that keeps its flat underline. */
    --here-ring: linear-gradient(45deg, var(--teal), var(--accent));
    --here-fill: var(--bg-2);
    --here-bg: linear-gradient(var(--here-fill), var(--here-fill)) padding-box,
               var(--here-ring) border-box;

    /* ---- Shadow: one modest pop, for floating layers only ---- */
    /* Anything that leaves the page plane — dropdown menus, the command
       palette, toasts, tooltips, popovers — shares this one token. Resting
       surfaces get a 1px --line edge and a step up the ground instead of a
       shadow (TG-283), so nothing on the page floats.
       The rest of the depth system (--raise-*, --well, --ledge-orange) stays in
       fuel.css on purpose: home.css never defined it, and nav.css reads it
       without fallbacks, so hoisting it here would grow shadows on the home
       page's chrome — a visual change that refactor could not make. */
    --shadow-pop: 0 8px 24px rgba(0, 0, 0, 0.45);
}

/* The phone step-up for --mono-cap (TG-301). Overriding the token once beats
   restating a size in every consumer's own media query. */
@media (max-width: 860px) {
    :root { --mono-cap: 0.75rem; }         /* 12px */
}

/* ===== The body face (TG-288) =====
   The default for every page, declared once here because tokens.css loads
   before any page stylesheet. A page sheet that still sets its own body face
   (fuel.css, site_performance.css) loads later and keeps winning — which is
   exactly what holds the unswept tool pages on their old families until the
   sweep issue lands. */
body { font-family: var(--body); }

/* ===== The code voice (TG-299) =====
   `code`, `kbd` and `pre` are the third cut too. Without this rule they fall
   through to the UA's own monospace — a fourth family the type system never
   chose, and the one the `<iframe>` mention on /for-race-directors was still
   set in. The chip treatment is what three page stylesheets were each drawing
   for themselves; declared once here, a `<code>` reads the same wherever it
   appears. `.85em` rather than a fixed size, so it tracks the copy around it. */
code, kbd, pre {
    font-family: var(--mono);
    font-size: 0.85em;
    background: var(--bg-well);
    border: 1px solid var(--line-faint);
    border-radius: 4px;
    padding: 1px 5px;
}

/* ===== Body links (TG-299) =====
   info.css has carried the base `a` rule since TG-220 — but only the info
   pages load info.css, which is why the one prose link on the signed-out
   Creator still rendered in the UA's blue. The rule belongs here, where every
   page already loads it, and it carries the underline a body link should have.

   Scoped to classless anchors on purpose. Every anchor the chrome draws — the
   topbar, the footer, the tool cards, the anchor buttons below — wears a class
   and paints itself; a bare `a` rule would repaint all of them and drag an
   underline through the nav. `a:not([class])` is exactly the prose link this
   is for, and it is why the button classes need no exclusion list of their
   own to stay out of it. */
a:not([class]) {
    color: var(--accent);
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* An anchor that is a button never wears one. `.export-btn` (fuel.css) and
   `.btn` / `.btn-ghost` (home.css) are drawn for `<button>` first, and only
   `.btn` ever reset the UA underline — so the `<a>` form of the others showed
   one on /courses, /discover, /pricing, /404, /about, /crew-sheet and
   /dashboard, wherever a page loaded fuel.css without the local patch
   dashboard.css had been carrying. Reset here, in every state, for every
   page. */
a.export-btn, a.btn, a.btn-ghost,
a.export-btn:hover, a.btn:hover, a.btn-ghost:hover,
a.export-btn:focus, a.btn:focus, a.btn-ghost:focus,
a.export-btn:active, a.btn:active, a.btn-ghost:active {
    text-decoration: none;
}

/* ===== The instrument voice (TG-284) =====
   Two utilities, used site-wide. `.data` is any figure the product computes —
   a pace, a distance, a vert total, a cutoff, a fuel target, an ETA — and the
   tabular figures are what make a column of them line up digit for digit.
   `.data-label` is the small-caps voice that names one: eyebrows, section
   labels, table headers.

   Page stylesheets apply the same two declarations directly to their own value
   classes (`.metric-num`, `.cs-val`, `.plan-table td`, …) rather than every
   emitter growing a class — they read `var(--mono)` at the point of use, which
   is what the token is for. These utilities are for markup that has no class of
   its own to carry it. */
.data {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}
/* The unit rides with the figure but never competes with it: smaller, tracked
   out, in caps, and one weight down (TG-284 AC-5 — hierarchy by weight, not by
   another colour). */
.data-u,
.data .unit,
.data .u {
    font-size: 0.8em;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}
.data-label {
    font-family: var(--mono);
    font-weight: 500;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

/* ===== You are here (TG-287) =====
   The double-background technique: a flat fill on the padding box over the
   gradient on the border box, with the border itself transparent so the
   gradient shows through a 1px ring. Static by design — no transition, and
   nothing here for prefers-reduced-motion to suppress. Components whose own
   base rule loads later (`.section-chip`, `.cp-chip`) restate these four
   declarations at the point of use, reading the same tokens. */
.tg-here {
    color: var(--accent);
    border: 1px solid transparent;
    background: var(--here-bg);
    transition: none;
}

/* ===== The one entrance (TG-285) =====
   Every floating layer arrives the same way: a fast fade up from 96%, on
   --ease-snap. Defined here rather than in nav.css so the pages that skip nav
   (the crew sheet, the embed) can use it too. Each consumer sets its own
   transform-origin so the layer grows out of the control that opened it. */
@keyframes tg-pop-in {
    from { opacity: 0; transform: scale(0.96); }
    to   { opacity: 1; transform: none; }
}

/* ===== Touch (2026-09-04) =====
   Two properties, applied once here because tokens.css loads first on every
   page, so every control on the site inherits the behaviour rather than each
   stylesheet remembering it.

   `touch-action: manipulation` tells the browser a tap on a control can never
   be the first half of a double-tap-to-zoom, so it dispatches the click
   immediately instead of waiting to find out. That wait is the "not very
   responsive" feeling on a phone: the control is fine, the browser is just
   holding the event. Only interactive elements are named — the page body keeps
   pinch-zoom, which is an accessibility affordance, not a bug.

   The tap highlight is turned off in favour of each control's own :active
   state: the default is a grey rectangle that ignores border-radius and paints
   over the themed press feedback the components already define. */
a, button, summary, label, select, input, textarea,
[role="button"], [role="tab"], [role="switch"], .tg-tab {
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
}

/* ===== Focus: one ring, every page (2026-09-24) =====
   A keyboard visitor needs to see where they are, and until now that depended
   on which stylesheet a control happened to live in — the topbar drew a ring,
   the Creator, the info pages and most of the dashboard drew nothing but the
   browser default, which is a blue that belongs to no theme. This is the site
   default: a 2px ring in the accent, 2px off the control. `outline` follows
   `border-radius` in every current engine, so a pill gets a pill-shaped ring
   and a card gets a card-shaped one without naming either.

   Wrapped in :where() so it carries ZERO specificity: any control that already
   draws its own focus treatment (an inset ring on a tab, a border-colour swap
   on a text field) keeps it, because any class selector outranks this. It only
   fills the gaps. The main landmark is the skip link's target and takes focus
   programmatically; a ring round the whole page body says nothing. */
:where(a[href], button, input, select, textarea, summary,
       [tabindex]:not([tabindex="-1"]), [contenteditable="true"]):focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
:where(main, [tabindex="-1"]):focus { outline: none; }

/* ===== Tokyo Night — the default palette, and why it lives HERE =====
   Every other theme is a scoped-override stylesheet that tg-store.js loads on
   demand, which is right for a palette most visitors never see. It is wrong
   for the DEFAULT one: tokens.css is parsed before anything paints, so the
   page comes up in the :root palette below (Forest) and only turns Tokyo Night
   when a second file arrives — a visible flash on every first visit, reported
   2026-09-05.

   A default that costs a request is a default that flashes. So Tokyo Night's
   palette and its handful of literal-colour spots ride in this file, which is
   already on the critical path, and tg-store.js loads no stylesheet for it.
   The class is still applied the same way, so nothing else changes; if Tokyo
   Night ever stops being the default, this block moves back out to its own
   file and the roster gets its `file` back. */
html.theme-tokyonight {
    --bg-0: #1a1b26;          /* tokyo midnight */
    --bg-1: #24283b;          /* storm panels */
    --ink: #c0caf5;           /* neon-sign periwinkle white */
    --muted: #9aa5ce;         /* streetlight slate */
    --accent: #7aa2f7;        /* signal blue — the one accent on duty (TG-282) */
    --c-fuel: #ff9e64;        /* Fueling — lantern orange */
    --gold: #e0af68;          /* AI coach — Capra gradient, brass */
    --c-pace: #7aa2f7;        /* Pacing — signal blue */
    --c-crew: #9ece6a;        /* Crew — vending-machine green */
    --c-course: #0db9d7;      /* Course — neon cyan */
    --c-gear: #bb9af7;        /* Gear — arcade violet */
    /* The scheme's two purples sit 1° apart (KRI-119 would call them the same
       card twice), so Weather takes a pink-shifted dusk neon instead — the
       same separation move Emerald made for --c-aid. */
    --c-weather: #d98ae0;     /* Weather — dusk neon */
    --c-climb: #f7768e;       /* Climbs — vermilion sign */
    --c-aid: #7dcfff;         /* Aid stations + descents — pale sky glass */
    --ok: #9ece6a;            /* Status — vending-machine green */
    --warn: #e0af68;          /* Status — brass */
    --bad: #f7768e;           /* Status — vermilion sign */
}

/* --- Literal-colour spots that don't read the tokens (home.css) --- */
/* .grad / .eyebrow / .btn-primary already read the tokens — signal-blue hero for free. */
/* Backdrop tints → neon cyan + arcade violet over the indigo ground */
html.theme-tokyonight .backdrop {
    background:
        radial-gradient(1200px 600px at 70% -10%, rgba(13, 185, 215, 0.10), transparent 60%),
        radial-gradient(900px 500px at 10% 10%, rgba(187, 154, 247, 0.08), transparent 55%),
        linear-gradient(180deg, var(--bg-0), var(--bg-1));
}
html.theme-tokyonight .aurora {
    background: conic-gradient(from 180deg at 50% 50%, transparent, rgba(122, 162, 247, 0.07), transparent 40%);
}
/* Goat glow → signal blue, and stop the LED colour-cycle (it hardcodes old brand hues) */
html.theme-tokyonight .goat {
    filter: drop-shadow(0 24px 36px rgba(0, 0, 0, 0.55)) drop-shadow(0 0 10px rgba(122, 162, 247, 0.45));
    animation: bob 3.2s ease-in-out infinite;
}
/* Closing CTA band glow → violet neon */
html.theme-tokyonight .cta-band {
    background-image: radial-gradient(600px 200px at 50% -20%, rgba(187, 154, 247, 0.12), transparent 70%);
}
/* Hero route SVG gradient stops → cyan → signal blue → arcade violet */
html.theme-tokyonight #hr-grad stop:nth-of-type(1) { stop-color: #0db9d7; }
html.theme-tokyonight #hr-grad stop:nth-of-type(2) { stop-color: #7aa2f7; }
html.theme-tokyonight #hr-grad stop:nth-of-type(3) { stop-color: #bb9af7; }

/* /fuel.css */
/* TrailGoat Fuel Planner — shares the palette + type of the main dashboard.
   The palette and feature accents live in tokens.css (TG-281), which every
   page loads first; this block keeps the radius and the depth system. */
:root {
    /* Legacy card corner — now an alias of the shared --r-card (TG-283). */
    --radius: var(--r-card);

    /* Depth system — one light source for the whole site.
       raise-1: resting surfaces · raise-2: interactive/raised controls ·
       raise-primary: legacy solid-CTA depth, unused since buttons went flat ·
       well: inset tracks & inputs */
    --raise-1: inset 0 1px 0 rgba(255,255,255,0.07), 0 2px 6px rgba(0,0,0,0.35);
    --raise-2: inset 0 1px 0 rgba(255,255,255,0.09), 0 2px 5px rgba(0,0,0,0.45),
               0 10px 22px -8px rgba(0,0,0,0.55);
    --raise-primary: inset 0 1px 0 rgba(255,255,255,0.38), inset 0 -2px 4px rgba(120,45,0,0.3),
               0 2px 5px rgba(0,0,0,0.45), 0 10px 22px -8px rgba(255,122,26,0.5);
    --well: inset 0 2px 6px rgba(0,0,0,0.5), inset 0 -1px 0 rgba(255,255,255,0.05);
    --ledge-orange: 0 4px 0 #a34d03;
}

/* Inline stroke icons — inherit the button's text color so they always match. */
.ico { width: 15px; height: 15px; flex: 0 0 auto; }
.ico path, .ico circle, .ico rect, .ico line, .ico polyline { fill: none; stroke: currentColor; stroke-width: 1.75;
    stroke-linecap: round; stroke-linejoin: round; }

* { box-sizing: border-box; margin: 0; padding: 0; }

@media (prefers-reduced-motion: no-preference) {
    /* Smooth only for in-page anchor jumps (the target receives focus);
       programmatic scrolls and scroll restoration stay instant. */
    html:focus-within { scroll-behavior: smooth; }
}

body {
    font-family: var(--body);
    background: var(--bg-0);
    color: var(--ink);
    min-height: 100vh;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    overflow-x: clip;   /* not `hidden`: hidden makes body a scroll container, which eats smooth scrolls */
}

/* --- Backdrop --- */
.backdrop { position: fixed; inset: 0; z-index: -1; overflow: hidden; background:
    radial-gradient(1200px 600px at 70% -10%, rgba(25, 195, 177, 0.10), transparent 60%),
    radial-gradient(900px 500px at 10% 10%, rgba(255, 122, 26, 0.08), transparent 55%),
    linear-gradient(180deg, var(--bg-0), var(--bg-1)); }
.aurora { position: absolute; inset: -20% -20% auto -20%; height: 60%;
    background: conic-gradient(from 180deg at 50% 50%, transparent, rgba(154,230,0,0.06), transparent 40%);
    filter: blur(40px); }
.ridge { position: absolute; bottom: 0; left: 0; width: 100%; height: 38vh; opacity: 0.5; }
.ridge-back { fill: #0c2220; } .ridge-mid { fill: #0a1c1a; } .ridge-front { fill: #07140f; }

/* --- Top bar --- */
.topbar { display: flex; align-items: center; justify-content: space-between; gap: 10px;
    flex-wrap: wrap; padding: 18px clamp(16px, 2vw, 30px); max-width: none; margin: 0; }
.wordmark { font-family: var(--display); font-weight: 800; font-size: 1.4rem;
    letter-spacing: 0.02em; color: var(--ink); text-decoration: none; }
.grad { background: linear-gradient(100deg, var(--teal), var(--accent));
    -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
/* Inline brand lockup for AI-coach headings — "TRAILGOAT AI" in the wordmark's
   display cut, GOAT + AI in the brand gradient (.grad). "Ask" keeps the heading's
   own font, so on the all-caps cards it stays in the mono. */
.coach-brand { font-family: var(--display); font-weight: 800; letter-spacing: 0.02em;
    color: var(--ink); text-transform: none; }

.toggles { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
/* Unit toggles — an inset track with a raised "key" for the active side, so the
   switch reads as physical and orange stays reserved for primary actions. */
.unit-toggle { display: inline-flex; gap: 4px; background: rgba(0,0,0,0.35);
    border: 1px solid rgba(255,255,255,0.09); border-radius: var(--r-ctl); padding: 4px;
    box-shadow: var(--well); }
.unit-toggle button { background: transparent; color: var(--muted); border: none; cursor: pointer;
    font-family: inherit; font-weight: 700; font-size: 0.78rem; letter-spacing: 0.04em;
    padding: 7px 16px; border-radius: calc(var(--r-ctl) - 2px); transition: all 0.15s; }
.unit-toggle button.active { color: var(--ink);
    background: linear-gradient(180deg, rgba(255,255,255,0.16), rgba(255,255,255,0.08));
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), 0 3px 8px rgba(0,0,0,0.45); }

/* --- Layout --- */
.wrap { max-width: 1180px; margin: 0 auto; padding: 10px clamp(16px, 4vw, 40px) 80px; }

.hero { margin: 18px 0 30px; }
.eyebrow { color: var(--accent); font-family: var(--mono); font-weight: 500; letter-spacing: 0.1em;
    text-transform: uppercase; font-size: 0.8rem; margin-bottom: 12px; }
.hero h1 { font-family: var(--display); font-weight: 800;
    font-size: clamp(2rem, 5vw, 3.2rem); line-height: 1.05; letter-spacing: -0.02em; }
.hero-sub { color: var(--muted); font-size: 1.05rem; max-width: 40rem; margin-top: 16px; }

/* --- Panels --- */
.panel { background: var(--bg-2);
    border: 1px solid var(--line); border-top-color: rgba(255,255,255,0.16);
    border-radius: var(--radius);
    padding: 24px; box-shadow: var(--raise-1); }
.inputs, .fueling-plan { margin-bottom: 22px; }
.panel-title { font-family: var(--display); font-weight: 700; font-size: 1.15rem; }
.panel-head-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
/* Buttons — one solid primary per view; everything else is tonal or quiet.
   All three share the same geometry so they line up in a toolbar. */
/* Secondary verbs are the ladder's bordered neutral (TG-282): ink label, a
   defined edge, the fill steps on hover. Never a solid accent: the tool
   pages have no solid CTA since the topbar's went (TG-290). */
.export-btn { display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    background: var(--fill-idle);
    color: var(--ink); border: 1px solid var(--edge); border-radius: var(--r-ctl);
    padding: 9px 18px; font-family: inherit; font-weight: 700; font-size: 0.85rem; cursor: pointer;
    transition: transform 0.13s ease, background 0.13s ease, border-color 0.13s ease; }
.export-btn:hover { transform: translateY(-1px);
    background: var(--fill-hover); }
.export-btn:active { transform: translateY(1px); background: var(--fill-selected); }
.export-btn:disabled { opacity: 0.6; cursor: default; transform: none; }
/* Tonal — tinted glass for secondary verbs (open, reverse, undo). */
.export-btn.tonal { color: var(--ink); border: 1px solid rgba(255,255,255,0.12);
    background: linear-gradient(180deg, rgba(255,255,255,0.085), rgba(255,255,255,0.04));
    box-shadow: var(--raise-1); }
.export-btn.tonal:hover { border-color: rgba(255,255,255,0.24); filter: none; }
.export-btn.tonal:active { box-shadow: inset 0 2px 6px rgba(0,0,0,0.45); }
.export-btn.tonal .ico { color: var(--accent); }

/* The effort — three intuitive groups side by side (stack on mobile) */
.effort-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 26px; margin-top: 18px; }
.effort-col { display: flex; flex-direction: column; }
.effort-col > * + * { margin-top: 16px; }
.col-head { font-family: var(--display); font-weight: 600; font-size: 0.98rem; color: var(--ink);
    padding-bottom: 8px; border-bottom: 1px solid var(--line); }

/* Fueling plan — each section is its own card under a shared header.
   The food pack is a full-width card on top; per-hour + total sit side-by-side below it. */
.fuel-head { margin-bottom: 16px; }
.fuel-cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
.fuel-card-full { grid-column: 1 / -1; }
@media (max-width: 600px) { .fuel-cards { grid-template-columns: 1fr; } }
.fuel-card { background: var(--bg-2);
    border: 1px solid var(--line); border-top-color: rgba(255,255,255,0.16);
    border-radius: var(--radius);
    padding: 22px; box-shadow: var(--raise-1); }
.result-group { display: flex; flex-direction: column; }
.methodology { margin-top: 22px; }

/* --- Form fields --- */
.field-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 14px; }
.adv-grid { max-width: 460px; margin-top: 14px; }
.field { display: flex; flex-direction: column; gap: 6px; }
.field-block { display: flex; flex-direction: column; gap: 10px; }
.field-label { color: var(--muted); font-size: 0.85rem; font-weight: 500; }
.field-label em { color: var(--teal); font-style: normal; font-weight: 600; }
.field-label small { color: var(--muted); opacity: 0.7; font-weight: 400; }
.field-label strong { color: var(--ink); font-family: var(--display); }
.slider-hint { color: var(--gold); font-weight: 600; margin-left: 4px; }

input[type="number"], input[type="text"], input[type="search"], input[type="datetime-local"], input[type="date"], select {
    background: var(--glass-2); color: var(--ink); border: 1px solid var(--line);
    border-radius: var(--r-ctl); padding: 11px 14px; font-family: inherit; font-size: 1rem; width: 100%;
    transition: border-color 0.15s; color-scheme: dark; -webkit-appearance: none; appearance: none; }
input[type="number"]:focus, input[type="text"]:focus, input[type="search"]:focus, input[type="datetime-local"]:focus, input[type="date"]:focus, select:focus {
    outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--ring); }
input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; }
select { cursor: pointer; }
select option { background: var(--bg-1); color: var(--ink); }

/* Segmented control */
.segmented { display: inline-flex; gap: 4px; background: var(--glass-2);
    border: 1px solid var(--line); border-radius: var(--r-ctl); padding: 4px; }
.segmented button { flex: 1; background: transparent; color: var(--muted); border: none;
    cursor: pointer; font-family: inherit; font-weight: 600; font-size: 0.9rem;
    padding: 9px 12px; border-radius: calc(var(--r-ctl) - 2px); transition: all 0.15s; white-space: nowrap; }
.segmented button.active { background: var(--fill-selected); color: var(--accent); }
/* Phones: a segmented group must never widen the page (pace-split-modes hit
   500px and dragged the whole planner into horizontal scroll at 375px, KRI-109).
   The group scrolls in place instead, scrollbar hidden. */
@media (max-width: 600px) {
    .segmented { display: flex; max-width: 100%; overflow-x: auto;
        -webkit-overflow-scrolling: touch; scrollbar-width: none; }
    .segmented::-webkit-scrollbar { display: none; }
    .segmented button { flex: 0 0 auto; }
}

/* Sliders */
.slider { -webkit-appearance: none; appearance: none; width: 100%; height: 6px; border-radius: 999px;
    background: linear-gradient(90deg, var(--teal), var(--gold), var(--orange)); outline: none; }
/* outline:none above outranks the site's :where() ring, so every range input
   had no keyboard focus mark at all. Restore it, clear of the 22px thumb. */
.slider:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 22px; height: 22px;
    border-radius: 50%; background: var(--ink); border: 3px solid var(--accent); cursor: pointer;
    box-shadow: 0 2px 8px rgba(0,0,0,0.4); }
.slider::-moz-range-thumb { width: 22px; height: 22px; border-radius: 50%; background: var(--ink);
    border: 3px solid var(--accent); cursor: pointer; }

/* Flat pace + duration estimate */
.pace-row { display: flex; gap: 10px; }
.pace-row input { flex: 0 0 96px; text-align: center; }
.estimate-btn { flex: 1; color: var(--ink);
    background: linear-gradient(180deg, rgba(255,255,255,0.085), rgba(255,255,255,0.04));
    border: 1px solid var(--line); border-radius: var(--r-ctl); padding: 0 14px;
    font-family: inherit; font-weight: 600; font-size: 0.9rem; cursor: pointer;
    box-shadow: var(--raise-1);
    transition: all 0.15s; }
.estimate-btn:hover { border-color: var(--edge-soft); background: var(--fill-hover); }
.estimate-btn:active { box-shadow: inset 0 2px 6px rgba(0,0,0,0.45); }
.estimate-out { color: var(--muted); font-size: 0.85rem; margin-top: 4px; min-height: 1.1em; }
.estimate-out strong { color: var(--gold); font-family: var(--mono);
    font-weight: 700; }
.estimate-out small { opacity: 0.85; }
.estimate-out.warn { color: var(--warn); }
.estimate-out.warn strong { color: var(--warn); }

/* Weather row (date/time + button) */
.weather-row { display: flex; gap: 10px; flex-wrap: wrap; }
.weather-row input { flex: 1 1 170px; }
.weather-row .estimate-btn { flex: 0 0 auto; }

.advanced { margin-top: 20px; border-top: 1px solid var(--line); padding-top: 14px; }
.advanced summary, .methodology summary { cursor: pointer; color: var(--muted); font-weight: 600;
    font-size: 0.9rem; list-style: none; }
.advanced summary::-webkit-details-marker, .methodology summary::-webkit-details-marker { display: none; }
.advanced summary::before, .methodology summary::before { content: '＋ '; color: var(--accent); }
.advanced[open] summary::before, .methodology[open] summary::before { content: '－ '; }

/* --- Result metrics --- */
/* Gut training on the Per-hour card (TG-340) — the same segmented control the settings
   menu uses, so the two places this one value can be set look like one control. It sits
   above the grid because it is the reason the carbs number reads what it reads. */
.gut-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; margin-top: 14px; }
.gut-row-label { font-size: 0.78rem; font-weight: 700; letter-spacing: 0.04em;
    text-transform: uppercase; color: var(--muted); }
.gut-chips { flex: 1 1 auto; }
.gut-chips button { flex: 1 1 0; padding-left: 10px; padding-right: 10px; }
@media (max-width: 480px) { .gut-row-label { flex: 1 0 100%; } }

.metric-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 16px; }
.metric { position: relative; background: var(--glass-2); border: 1px solid var(--line);
    border-radius: var(--radius); padding: 15px 16px; overflow: hidden; }
.metric::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 3px;
    background: var(--stat-acc); opacity: 0.9; }
.metric::after { content: ''; position: absolute; top: -40px; right: -40px; width: 110px; height: 110px;
    border-radius: 50%; background: var(--stat-acc); opacity: 0.12; filter: blur(8px); }
/* Scoped as --stat-acc (a data tint), never the global --accent (TG-282). */
.metric-water  { --stat-acc: var(--teal); }
.metric-sodium { --stat-acc: var(--violet); }
.metric-carbs  { --stat-acc: var(--gold); }
.metric-cals   { --stat-acc: var(--orange); }
.metric-label { color: var(--muted); font-family: var(--mono); font-size: max(0.74rem, var(--mono-cap)); font-weight: 500;
    letter-spacing: 0.1em; text-transform: uppercase; margin-bottom: 8px; }
.metric-num { font-family: var(--mono); font-weight: 700;
    font-size: 1.5rem; line-height: 1.05; color: var(--stat-acc); }
/* Keep a range (e.g. "998–1,831") together; let the unit wrap below if tight.
   inline-block so JS can measure its width and auto-shrink to fit the card. */
.metric-num > span:first-child { white-space: nowrap; display: inline-block; }
.metric-unit { font-size: 0.8rem; font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--muted); margin-left: 3px; }

/* Kit list */
.kit-list { list-style: none; margin-top: 14px; display: flex; flex-direction: column; gap: 12px; }
.kit-list li { display: flex; align-items: baseline; gap: 10px; font-size: 1rem; }
.kit-list small { color: var(--muted); }
.kit-num { font-family: var(--mono); font-weight: 700;
    font-size: 1.4rem; color: var(--moss);
    min-width: 1.6em; text-align: right; white-space: nowrap; }
.kit-note { color: var(--muted); font-size: 0.85rem; margin-top: 14px; }

/* --- Course / GPX --- */
.course { margin-bottom: 22px; }
.course-head { margin-bottom: 16px; }
.course-name-field { margin-bottom: 16px; max-width: 420px; position: relative; }
/* z-index must clear the mini map below the field: Leaflet panes/controls run
   z 400–1000 in this same stacking context, so 50 hid the dropdown behind it. */
.course-suggest { position: absolute; top: 100%; left: 0; right: 0; z-index: 1100; margin-top: 6px;
    background: rgba(7, 18, 15, 0.98); border: 1px solid var(--line); border-radius: var(--r-card);
    box-shadow: var(--shadow-pop); max-height: 300px; overflow-y: auto; }
.suggest-item { display: flex; flex-direction: column; gap: 2px; width: 100%; text-align: left;
    background: none; border: none; border-bottom: 1px solid var(--line); padding: 10px 14px;
    cursor: pointer; color: var(--ink); font-family: inherit; }
.suggest-item:last-child { border-bottom: none; }
.suggest-item:hover { background: var(--glass-2); }
.suggest-name { font-weight: 600; font-size: 0.92rem; }
.suggest-meta { color: var(--muted); font-size: 0.8rem; }
/* "Still looking" while the search reaches past the local index (TG-326) —
   deliberately not a .suggest-item: there is nothing here to click yet. */
.suggest-wait { color: var(--muted); font-size: 0.86rem; padding: 10px 14px; }
.panel-sub { color: var(--muted); font-size: 0.88rem; margin-top: 4px; }
.panel-sub.rd-sec-lead { margin-top: 0; }   /* a section's first line, straight under its title */
/* "Community" on a course search result (TG-228): official matches rank first. */
.tg-community-badge { border: 1px solid currentColor; border-radius: var(--r-ctl);
    padding: 0 6px; font-size: 10px; opacity: 0.85; }
.inline-link { color: var(--accent); text-decoration: none; font-weight: 600; white-space: nowrap; }
.inline-link:hover { text-decoration: underline; }

.dropzone { display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 8px; text-align: center; padding: 32px 20px; border: 1.5px dashed var(--line);
    border-radius: var(--radius); background: var(--glass-2); cursor: pointer;
    transition: border-color 0.15s, background 0.15s; }
.dropzone:hover, .dropzone.dragover { border-color: var(--accent); background: var(--fill-hover); }
.dz-icon { font-size: 2rem; }
.dz-icon .ico { width: 30px; height: 30px; color: var(--muted); }
.base-map-cap .ico { color: var(--teal); vertical-align: -2px; }
.tg-browse-btn .ico { color: var(--accent); }
.dz-text { color: var(--ink); font-size: 0.98rem; }
.dz-text strong { font-weight: 600; }
.dz-status { color: var(--muted); font-size: 0.85rem; min-height: 1em; }
.dz-status.error { color: var(--bad); }
/* As a rail row of its own (TG-320) it must not hold a blank line open — the
   rail's gap would space an empty box like a real one. */
.rd-status:empty { display: none; }

.course-title { font-family: var(--display); font-weight: 800; font-size: 1.4rem; color: var(--ink);
    margin: 0 2px 12px; line-height: 1.2; }
.course-stats { display: flex; flex-wrap: wrap; gap: 10px; margin: 22px 0 16px; align-items: stretch; }
/* One line per label, one baseline per row (TG-301). The tiles are a flex row
   of equal-ish boxes, so a label that wraps makes its own tile taller and
   drops its figure below the others' — the row stops reading as a set of
   readings and starts reading as six unrelated boxes. The label gets its own
   line and is not allowed to take a second; the tiles stretch to a common
   height and the figure is pushed to the bottom of each, so every figure sits
   on one baseline whether or not its label needed the room. */
.course-stat { background: var(--glass-2); border: 1px solid var(--line); border-radius: var(--r-card);
    padding: 10px 14px; flex: 1 1 110px;
    display: flex; flex-direction: column; }
.course-stat .cs-label { color: var(--muted); font-family: var(--mono); font-weight: 500;
    font-size: max(0.72rem, var(--mono-cap)); text-transform: uppercase; letter-spacing: 0.1em;
    white-space: nowrap; }
/* The qualifier that used to ride in the unit slot after the figure. Muted,
   un-tracked and sentence case: it is a footnote to the label, not a label. */
.course-stat .cs-sub { display: block; font-family: var(--body); font-weight: 400;
    font-size: 0.7rem; letter-spacing: normal; text-transform: none;
    color: var(--muted); opacity: 0.85; white-space: nowrap; }
.course-stat .cs-val { font-family: var(--mono); font-weight: 700;
    font-size: 1.2rem; margin-top: auto; padding-top: 3px; }
.course-stat .cs-val .unit { font-size: 0.72rem; font-weight: 500; letter-spacing: 0.08em;
    text-transform: uppercase; color: var(--muted); margin-left: 4px; }
.cs-gain .cs-val { color: var(--orange); }
.cs-loss .cs-val { color: var(--aqua); }
.cs-dist .cs-val { color: var(--moss); }
.cs-high .cs-val { color: var(--gold); }
.cs-low  .cs-val { color: var(--teal); }
.cs-oxy  .cs-val { color: var(--plum); }

/* Surface mix (KRI-54). Deliberately the SAME tokens the map route, the profile
   ribbon and the pace-table chips already use — grey paved · gold gravel · moss
   trail · faded unknown — so the colour language is learned once and a theme
   restyles all of it together. The tile's value takes the dominant surface's
   colour, so the number and the strip below it agree at a glance. */
.cs-surface .cs-val { color: var(--moss); }          /* d-trail (default) */
.cs-surface.d-gravel .cs-val { color: var(--gold); }
.cs-surface.d-paved  .cs-val { color: var(--muted); }
.cs-mix { display: flex; height: 5px; border-radius: 3px; overflow: hidden; margin-top: 8px; }
.cs-mix i { display: block; min-width: 1px; }
.sfx-trail   { background: var(--moss); }
.sfx-gravel  { background: var(--gold); }
.sfx-paved   { background: var(--muted); }
/* Unknown is an ABSENCE of data, not a surface — same hue, dialled back so it
   reads as "nothing here" rather than as a fourth category. */
.sfx-unknown { background: var(--muted); opacity: 0.3; }

/* Event attribution under the course title (KRI-40) */
/* Event byline ("Jun 27, 2026 · by Western States Endurance Run"): a second
   line INSIDE the course card's header band, under the title (TG-318). It is
   a summary child, so that band wraps; body face, no caps, and the chevron
   stays on the title row (its order 0 beats the byline's 11). Links inside a
   <summary> follow without toggling the card — the anchor's activation wins. */
#course-view-panel > summary { flex-wrap: wrap; row-gap: 2px; }
.rd-section > summary .course-event-line {
    flex: 1 1 100%; order: 11; margin: 0 0 0 35px;
    font-family: var(--body); font-weight: 400; font-size: 0.82rem; color: var(--muted);
    text-transform: none; letter-spacing: normal;
}
.course-event-line a { color: var(--accent); text-decoration: none; }
.course-event-line a:hover { text-decoration: underline; }
/* "Train for this race →" (KRI-82) — a CTA, so it gets the site's orange. */
.course-event-line a.rd-train-link { color: var(--accent); font-weight: 600; }
.course-event-line[hidden] { display: none; }

/* Aid-station markers (map) + matching badges (plan table) */
.leaflet-div-icon.aid-marker-wrap { background: transparent; border: 0; }
.aid-marker { display: flex; align-items: center; justify-content: center; width: 26px; height: 26px;
    border-radius: 50%; color: #06140f; font-family: var(--display); font-weight: 800;
    font-size: 0.92rem; border: 2px solid rgba(255,255,255,0.92); box-shadow: 0 1px 5px rgba(0,0,0,0.5); }
.aid-badge { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px;
    border-radius: 50%; color: #06140f; font-family: var(--display); font-weight: 800; font-size: 0.72rem;
    margin-right: 8px; vertical-align: middle; }

/* isolation: Leaflet's panes (z 400) and controls (z 1000) otherwise escape into
   the page's stacking order and paint over anything sticky above the map — on
   the Run Planner the pane's section-chip row (z 7) vanished under the tiles as
   the plan scrolled. One stacking context per map keeps Leaflet's z-indexes
   internal; .map-expanded still lifts the whole wrap with its own z-index. */
.map-wrap { position: relative; isolation: isolate; border-radius: var(--radius); overflow: hidden; border: 1px solid var(--line); }
/* One frame around the map (TG-300). The Course panel drew three: the section
   card's border, then 24px of padding, then the map wrap's own 1px. The card's
   edge is the frame — the map loses its border and sits 12px inside, which is
   also 24px of width the profile and the stat tiles get back on a phone.
   Scoped to the panel rather than to .map-wrap: below 861px the pane merge
   moves this content into the rail, where .rd-merged has already stripped the
   card and the map's border becomes the only one there is. */
#course-view-panel { padding: 12px; }
#course-view-panel > summary { margin: -12px; padding: 10px 12px; }
/* The id selector above rewrites the shared band's whole margin shorthand, so
   the open/collapsed bottom margins from `.rd-section[open] > summary` lose on
   specificity and have to be restated at 12px here — without them the band
   keeps its -12px bottom and the map rides up over the header (and over its
   bottom rule). This card's band is the only two-row one on the page (the
   event byline sits under the title), so it also takes 10px of vertical
   padding rather than the shared 13px: two rows at 13px read as a slab. */
#course-view-panel:not([open]) > summary { margin-bottom: -12px; }
#course-view-panel[open] > summary { margin-bottom: 12px; }
#course-view-panel .map-wrap { border: none; }
#course-map { height: 425px; width: 100%; background: var(--bg-1); }

/* 3D terrain view (MapLibre) — overlays the 2D map within the same wrap.
   position:absolute !important beats MapLibre's own .maplibregl-map{position:relative}
   (its stylesheet loads later); z-index sits above Leaflet's panes/controls. */
.tg-3d { position: absolute !important; inset: 0; z-index: 1200; background: var(--bg-1); }
.tg-3d-badge { position: absolute; top: 10px; left: 50%; transform: translateX(-50%); z-index: 1300;
    font-family: var(--mono); font-weight: 700; font-size: 0.66rem; letter-spacing: 0.06em;
    text-transform: uppercase; color: var(--gold); background: rgba(7,18,15,0.85);
    border: 1px solid rgba(255,210,63,0.45); border-radius: var(--r-ctl); padding: 4px 10px; }
.tg-3d-exit { position: absolute; top: 10px; right: 10px; z-index: 1300; cursor: pointer;
    background: rgba(7,18,15,0.92); color: var(--ink); border: 1px solid var(--line); border-radius: 8px;
    padding: 7px 12px; font-family: var(--body); font-weight: 700; font-size: 0.82rem;
    box-shadow: 0 2px 8px rgba(0,0,0,0.45); }
.tg-3d-exit:hover { border-color: var(--edge-soft); color: var(--accent); }
.map-3d-btn { display: flex !important; align-items: center; justify-content: center; width: 32px; height: 32px;
    background: rgba(7,18,15,0.92); color: var(--ink); border: 1px solid var(--line); border-radius: 8px;
    font-family: var(--body); font-weight: 800; font-size: 0.72rem; line-height: 1; text-decoration: none;
    box-shadow: 0 2px 8px rgba(0,0,0,0.45); }
.map-3d-btn:hover { border-color: var(--edge-soft); color: var(--accent); }
/* Hide the 2D Leaflet controls while the 3D overlay is up (they drive the hidden map) */
.map-wrap.tg-3d-active .leaflet-control-container { display: none; }
/* 3D flythrough control (play/pause + speed), bottom-left of the 3D view */
.tg-3d-fly { position: absolute; left: 10px; bottom: 10px; z-index: 1300; display: flex; gap: 6px; }
.tg-3d-fly-btn, .tg-3d-fly-speed { cursor: pointer; background: rgba(7,18,15,0.92); color: var(--ink);
    border: 1px solid var(--line); border-radius: 8px; font-family: var(--body); font-weight: 700;
    box-shadow: 0 2px 8px rgba(0,0,0,0.45); line-height: 1; }
.tg-3d-fly-btn { padding: 9px 14px; font-size: 0.85rem; }
.tg-3d-fly-speed { padding: 9px 11px; font-size: 0.8rem; color: var(--muted); min-width: 36px; }
.tg-3d-fly-btn:hover { border-color: var(--edge-soft); color: var(--accent); }
.tg-3d-fly-speed:hover { border-color: var(--edge-soft); color: var(--ink); }

/* Locate-me button — same glass block as the 3D/expand controls beside it.
   No resting `color`: Leaflet's `.leaflet-container a` blue wins the cascade on
   those neighbours too, so omitting it here matches them by the same mechanism. */
.map-locate-btn { display: flex !important; align-items: center; justify-content: center;
    width: 32px; height: 32px; background: rgba(7,18,15,0.92);
    border: 1px solid var(--line); border-radius: 8px; line-height: 1;
    text-decoration: none; box-shadow: 0 2px 8px rgba(0,0,0,0.45); }
.map-locate-btn svg { width: 16px; height: 16px; display: block; }
.map-locate-btn:hover { border-color: var(--edge-soft); color: var(--accent); }

/* Expand-to-fullscreen button + state */
.map-expand-btn { display: flex !important; align-items: center; justify-content: center;
    width: 32px; height: 32px; background: rgba(7,18,15,0.92); color: var(--ink);
    border: 1px solid var(--line); border-radius: 8px; font-size: 1.05rem; line-height: 1;
    text-decoration: none; box-shadow: 0 2px 8px rgba(0,0,0,0.45); }
.map-expand-btn:hover { border-color: var(--edge-soft); color: var(--accent); }
/* Course playback control (play / pause + speed) */
.map-play { display: flex; gap: 6px; }
.map-play-btn, .map-speed-btn { display: flex !important; align-items: center; justify-content: center;
    height: 32px; background: rgba(7,18,15,0.92); color: var(--ink); border: 1px solid var(--line);
    border-radius: 8px; font-size: 0.95rem; line-height: 1; text-decoration: none;
    box-shadow: 0 2px 8px rgba(0,0,0,0.45); font-family: var(--body); font-weight: 700; }
.map-play-btn { width: 32px; }
.map-speed-btn { min-width: 34px; padding: 0 8px; font-size: 0.82rem; color: var(--muted); }
.map-play-btn:hover { border-color: var(--edge-soft); color: var(--accent); }
.map-speed-btn:hover { border-color: var(--edge-soft); color: var(--ink); }
.map-wrap.map-expanded { position: fixed; inset: 0; z-index: 9999; margin: 0;
    border: none; border-radius: 0; }
.map-wrap.map-expanded #course-map,
.map-wrap.map-expanded #lib-map,
.map-wrap.map-expanded #base-map { height: 100vh; height: 100dvh; }
body.map-modal-open { overflow: hidden; }
.leaflet-container { background: var(--bg-1); font-family: inherit; }

.elev-wrap { margin-top: 16px; }
.elev-head { color: var(--muted); font-size: 0.85rem; font-weight: 600; margin-bottom: 8px; }
.elev-head small { font-weight: 400; opacity: 0.8; }
/* Elevation-profile overlay toggles (Aid stations / Climbs / Descents) */
.tg-elev-toggles { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.tg-tog { display: inline-flex; align-items: center; gap: 7px; font-family: var(--body);
    font-weight: 600; font-size: 0.8rem; color: var(--muted); background: var(--glass-2);
    border: 1px solid var(--line); border-radius: var(--r-ctl); padding: 6px 12px; cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease; }
.tg-tog:hover { color: var(--ink); }
/* An explicit display beats the UA [hidden] rule — restate it (same trap as
   nav.css). Without this the Night/Altitude pills "hidden" for irrelevant
   courses still rendered, lit, on every low flat race. */
.tg-tog[hidden] { display: none; }
.tg-tog .tg-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--tg, #888);
    opacity: 0.3; transition: opacity 0.15s ease; }
.tg-tog.on { color: var(--ink); border-color: var(--tg, #888);
    background: color-mix(in srgb, var(--tg, #888) 13%, transparent); }
.tg-tog.on .tg-dot { opacity: 1; }
/* Distance-marker pill: the dot mimics the numbered puck on the map. */
.tg-tog-mile .tg-dot { width: 11px; height: 11px; background: rgba(7, 18, 15, 0.88);
    border: 1.5px solid var(--gold); }
.elev-canvas-wrap { position: relative; height: 260px; }
.elev-empty { color: var(--muted); font-size: 0.9rem; line-height: 1.5; padding: 28px 22px;
    text-align: center; border: 1px dashed var(--line); border-radius: var(--radius);
    background: var(--glass-2); }

/* Leaflet layer switcher — match the dark UI */
.leaflet-control-layers { background: rgba(7,18,15,0.92) !important; color: var(--ink);
    border: 1px solid var(--line) !important; border-radius: var(--r-card) !important;
    box-shadow: 0 8px 24px rgba(0,0,0,0.5) !important; }
.leaflet-control-layers-expanded { padding: 8px 12px !important; }
.leaflet-control-layers label { color: var(--ink); font-size: 0.85rem; font-weight: 500; margin: 2px 0; }
.leaflet-control-layers-selector { accent-color: var(--accent); margin-right: 6px; }
.leaflet-bar a { background: rgba(7,18,15,0.92); color: var(--ink); border-color: var(--line); }
.leaflet-bar a:hover { background: var(--fill-hover); }

/* Fueling-plan per-section summary — its own card below the metric cards */
.plan-summary { margin-top: 18px; }
.plan-summary .col-head { border-bottom: none; padding-bottom: 0; margin-bottom: 10px; }
.summary-text { color: var(--muted); font-size: 0.95rem; line-height: 1.55; margin-bottom: 14px; max-width: 64ch; }
.summary-text strong { color: var(--gold); font-weight: 700; }
/* Biggest-carries strip — replaces the old duplicate per-leg table. */
.carry-head { font-family: var(--mono); font-size: 0.75rem; font-weight: 500; letter-spacing: 0.1em;
    text-transform: uppercase; color: var(--muted); margin: 0 0 8px; }
.carry-strip { list-style: none; margin: 0; padding: 0; display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 10px; }
.carry-strip li { display: flex; flex-direction: column; gap: 2px; padding: 12px 14px;
    background: rgba(255, 255, 255, 0.03); border: 1px solid var(--line); border-radius: var(--r-card); }
.carry-name { font-weight: 700; font-size: 0.92rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.carry-dist { color: var(--muted); font-family: var(--mono); font-size: 0.78rem; }
.carry-load { font-family: var(--mono); font-size: 0.92rem; font-weight: 700; margin-top: 4px; }

/* Race plan table */
.plan-wrap { margin-top: 20px; }
.plan-scroll { overflow-x: auto; margin-top: 10px; }
.plan-table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.plan-table th { text-align: left; color: var(--muted); font-family: var(--mono); font-weight: 500;
    font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.1em;
    padding: 6px 10px; border-bottom: 1px solid var(--line); }
/* Every column but the first holds a figure. The mono face here, plus the shared
   tabular-figures rule at the foot of this file, is what makes a split table read
   down a column instead of across a ragged edge (AC-4). */
.plan-table th:not(:first-child), .plan-table td:not(:first-child) { text-align: right; white-space: nowrap; }
.plan-table td:not(:first-child), .cmp-table td:not(:first-child) { font-family: var(--mono); }
/* td inherits --ink by default — don't set color here, or it would out-specify the
   .t-* value classes when they're applied directly to a <td> (they'd stay white). */
.plan-table td { padding: 9px 10px; border-bottom: 1px solid var(--line); }
/* Zebra striping + a warm hover so it's easy to track a single row across the table. */
.plan-table tbody tr:nth-child(even) { background: color-mix(in srgb, var(--ink) 3%, transparent); }   /* ink-based: a stripe on white too */
.plan-table tbody tr:hover { background: var(--fill-hover); }
.plan-table tbody tr:hover td { border-bottom-color: var(--edge-soft); }
.plan-table .aid-name { color: var(--ink); font-weight: 500; }
/* Semantic value colours (match the elevation profile: climbs orange, descents blue).
   Scoped under .plan-table so they reliably win on a <td> as well as a <span>. */
.plan-table .t-up { color: var(--orange); font-weight: 600; }
.plan-table .t-down { color: var(--aqua); font-weight: 600; }
/* OSM surface rows + aid-leg badges (KRI-35) — tokens, so themes restyle free */
.plan-table .srf-trail { color: var(--moss); font-weight: 600; }
.plan-table .srf-gravel { color: var(--gold); font-weight: 600; }
.plan-table .srf-paved { color: var(--muted); font-weight: 600; }
.srf-chip { display: inline-block; margin-left: 6px; padding: 1px 8px; border-radius: var(--r-ctl);
    font-size: 0.68rem; font-weight: 700; letter-spacing: 0.04em;
    border: 1px solid currentColor; opacity: 0.9; vertical-align: 1px; }
.plan-table .t-pace { color: var(--gold); font-weight: 700; }
.plan-table .t-water { color: var(--teal); font-weight: 600; }
.plan-table .t-carb { color: var(--gold); font-weight: 600; }
.plan-table .t-sep { color: var(--muted); font-weight: 400; }
.plan-table .t-flat { color: var(--muted); }
/* Aid table at a glance (gpx.js): the Temp cell's cool→hot wash and the
   Water cell's volume bar (--w, the leg's share of the biggest carry). Data
   hues, so each theme tints them its own way. */
.plan-table td.t-tint { border-radius: 6px; }
.plan-table td.t-hot  { background: color-mix(in srgb, var(--c-climb) 20%, transparent); }
.plan-table td.t-warm { background: color-mix(in srgb, var(--c-fuel) 17%, transparent); }
.plan-table td.t-mild { background: color-mix(in srgb, var(--gold) 12%, transparent); }
.plan-table td.t-cool { background: color-mix(in srgb, var(--c-aid) 14%, transparent); }
.plan-table td.w-carry { border-radius: 6px;
    background: linear-gradient(90deg, color-mix(in srgb, var(--c-course) 13%, transparent) var(--w, 0%), transparent var(--w, 0%)); }
/* Climb steepness scale — gentle gold → moderate orange → steep coral. */
.plan-table .grade-soft { color: var(--gold); font-weight: 600; }
.plan-table .grade-mid { color: var(--orange); font-weight: 600; }
.plan-table .grade-hard { color: var(--coral); font-weight: 700; }
.aid-actions { display: inline-flex; gap: 4px; margin-left: 8px; vertical-align: middle; }
/* Post-race plan vs actual (2026-08). */
.cmp-drop { margin: 4px 0 10px; }
.cmp-drop.over { border-color: var(--plum); }
.cmp-headline { font-size: 0.98rem; margin: 10px 0; }
.cmp-early { color: var(--ok); font-weight: 700; }
.cmp-late { color: var(--bad); font-weight: 700; }
.cmp-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
.cmp-table th { text-align: left; color: var(--muted); font-family: var(--mono); font-weight: 500;
    font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.1em;
    padding: 6px 10px 6px 0; border-bottom: 1px solid var(--line); }
.cmp-table td { padding: 6px 10px 6px 0; border-bottom: 1px solid var(--line); }
.cmp-table .cmp-miss td { color: var(--muted); opacity: 0.7; }
.cmp-fade { color: var(--muted); font-size: 0.88rem; margin: 12px 0 2px; }
.cmp-fade b { color: var(--plum); }
.cmp-fade a { color: var(--fern); }

/* RD verification chip on the course event line — flat outline, fern check. */
.tg-verified { display: inline-flex; align-items: center; gap: 4px; padding: 1px 8px;
    font-size: 0.78rem; font-weight: 600; color: var(--fern);
    border: 1px solid color-mix(in srgb, var(--fern) 50%, transparent); border-radius: var(--r-ctl); }
.tg-verified svg { width: 11px; height: 11px; fill: none; stroke: currentColor; stroke-width: 2.5;
    stroke-linecap: round; stroke-linejoin: round; }

/* Night marker: a stop reached in darkness (and the headlamp note's glyph). */
.aid-night { display: inline-block; margin-left: 6px; vertical-align: -1px; color: var(--violet); }
.aid-night svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; }
#night-note { color: var(--muted); }
#night-note .aid-night { margin-left: 0; }

/* Cutoff badge under a stop's arrival — flat outline pill, buffer-colored.
   ok ≥ 1h of margin · tight < 1h · missed = planned arrival is past it.
   Status tokens, the split table's margin column's thresholds and hues
   (raceday.css .pace-cut-m): a state, not a data series. */
.aid-cutoff { display: block; width: fit-content; margin-top: 3px; padding: 1px 7px;
    font-size: 0.72rem; font-family: var(--body); white-space: nowrap;
    border: 1px solid var(--line); border-radius: var(--r-ctl); color: var(--muted); cursor: pointer; }
.aid-cutoff.cut-ok { border-color: color-mix(in srgb, var(--ok) 45%, transparent); color: var(--ok); }
/* Time at this stop (TG-309) — the cutoff pill's quieter sibling: same outline,
   no grading, because a dwell is a choice rather than a threat. */
.aid-dwell { display: block; width: fit-content; margin-top: 3px; padding: 1px 7px;
    font: 500 .7rem/1.5 var(--mono); font-variant-numeric: tabular-nums; white-space: nowrap;
    border: 1px solid var(--line); border-radius: var(--r-ctl); color: var(--muted); cursor: pointer; }
.aid-dwell:hover, .aid-dwell:focus-visible { border-color: color-mix(in srgb, var(--accent) 55%, transparent); color: var(--ink); }
/* A stop too close to the start or finish to carry time (TG-314). Not
   editable, so it must not look or behave editable — the cursor and the hover
   response are what the row uses to say "this one is telling you something,
   not offering you something". */
.aid-dwell-off { cursor: default; border-style: dashed; opacity: 0.75; }
.aid-dwell-off:hover, .aid-dwell-off:focus-visible { border-color: var(--line); color: var(--muted); }
/* The 95% guard is binding: the number shown is scaled, not what was set. */
.aid-dwell-scaled { border-color: color-mix(in srgb, var(--gold) 55%, transparent); color: var(--gold); }
.aid-cutoff.cut-tight { border-color: color-mix(in srgb, var(--warn) 55%, transparent); color: var(--warn); }
.aid-cutoff.cut-missed { border-color: color-mix(in srgb, var(--bad) 60%, transparent); color: var(--bad); }
/* A pill that has something to say (TG-310): the demand goes on its own line
   inside the pill, so the buffer stays scannable and the required pace reads
   as the answer to it. nowrap comes off — the sentence is longer than the
   column, and clipping a number a runner needs is worse than a second line. */
.aid-cutoff.cut-warn { white-space: normal; max-width: 36ch; line-height: 1.35; }
.aid-cutoff .cut-need { display: block; font-weight: 600; }
.aid-rm, .aid-edit, .aid-cut { background: none; border: none; color: var(--muted); cursor: pointer;
    line-height: 1; padding: 2px 4px; border-radius: 6px; }
.aid-rm { font-size: 1.1rem; }
.aid-edit { font-size: 0.95rem; }
.aid-rm:hover { color: var(--ink); background: var(--fill-hover); }
.aid-edit:hover, .aid-cut:hover { color: var(--accent); background: var(--fill-hover); }
.aid-cut svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2; }
.aid-fixed { color: var(--muted); font-weight: 600; }
.plan-empty { color: var(--muted); font-size: 0.85rem; padding: 12px 2px; }
.plan-note { color: var(--muted); font-size: 0.8rem; margin-top: 8px; }
.plan-note strong { color: var(--ink); font-weight: 600; }

.aid-add { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.aid-add #aid-dist { flex: 0 0 80px; }
.aid-add #aid-name { flex: 1 1 140px; }
.aid-add .estimate-btn { flex: 0 0 auto; }

.course-actions { margin-top: 18px; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.course-actions .course-clear { margin-top: 0; }
.save-status { font-size: 0.85rem; color: var(--muted); }
.save-status.ok { color: var(--ok); }
.save-status.warn { color: var(--warn); }

.course-clear { margin-top: 16px; background: transparent; color: var(--muted);
    border: 1px solid var(--line); border-radius: var(--r-ctl); padding: 8px 16px; cursor: pointer;
    font-family: inherit; font-weight: 600; font-size: 0.85rem; transition: all 0.15s; }
.course-clear:hover { color: var(--ink); border-color: var(--edge-soft); background: var(--fill-hover); }

/* --- Course library page --- */
.topnav { display: flex; gap: 8px; flex-wrap: wrap; }
.back-link { color: var(--muted); text-decoration: none; font-weight: 600; font-size: 0.9rem;
    padding: 8px 16px; border: 1px solid var(--line); border-radius: var(--r-ctl); }
.back-link:hover { color: var(--ink); border-color: var(--edge-soft); background: var(--fill-hover); }
/* Primary in-app nav — mirrors the landing page (.nav from home.css). */
.nav { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.nav a { color: var(--muted); text-decoration: none; font-weight: 600; font-size: 0.92rem;
    padding: 8px 14px; border-radius: var(--r-ctl); transition: color 0.2s ease, background 0.2s ease; }
.nav a:hover { color: var(--ink); background: var(--glass); }
.nav .beta-tag { font-size: 0.62rem; font-weight: 700; color: var(--gold); margin-left: 4px;
    letter-spacing: 0.05em; vertical-align: super; }
.lib-toolbar { display: flex; gap: 10px; align-items: center; margin-bottom: 20px; flex-wrap: wrap; }
.lib-search { flex: 1 1 280px; max-width: 480px; }
.lib-manage { background: var(--glass-2); color: var(--muted); border: 1px solid var(--line);
    border-radius: var(--r-ctl); padding: 9px 16px; font-family: inherit; font-weight: 600; font-size: 0.85rem;
    cursor: pointer; white-space: nowrap; }
.lib-manage:hover { color: var(--ink); border-color: var(--edge-soft); background: var(--fill-hover); }
.lib-manage.active { color: var(--accent); border-color: var(--accent); background: var(--fill-selected); }
.lib-card { position: relative; }
.lib-del { position: absolute; top: 8px; right: 8px; width: 24px; height: 24px; border-radius: 50%;
    border: 1px solid var(--line); background: rgba(7,18,15,0.85); color: var(--muted); cursor: pointer;
    font-size: 1.1rem; line-height: 1; display: flex; align-items: center; justify-content: center; }
.lib-del:hover { color: var(--ink); border-color: var(--edge-soft); background: var(--fill-hover); }
.lib-count { color: var(--muted); font-size: 0.85rem; margin: 2px 2px 16px; }
.lib-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 16px; }

.lib-card { position: relative; display: flex; flex-direction: column; gap: 8px; text-decoration: none;
    text-align: left; width: 100%; font-family: inherit; color: var(--ink); cursor: pointer;
    background: var(--glass-2); border: 1px solid var(--line); border-radius: var(--radius);
    padding: 18px; transition: border-color 0.15s, transform 0.15s, background 0.15s; }
.lib-card:hover { border-color: var(--edge-soft); transform: translateY(-2px);
    background: var(--fill-hover); }
.lib-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lib-card-cta { color: var(--accent); font-weight: 600; }
.lib-card-name { font-family: var(--display); font-weight: 700; font-size: 1.02rem; color: var(--ink); }
.lib-card-stats { display: flex; flex-wrap: wrap; gap: 14px; color: var(--muted); font-size: 0.9rem; }
.lib-card-stats strong { color: var(--ink); font-family: var(--display); }
.lib-card-date { color: var(--teal); font-size: 0.85rem; }
.lib-card-foot { color: var(--muted); font-size: 0.78rem; margin-top: auto; opacity: 0.8; }
.lib-tag { color: var(--gold); font-size: 0.78rem; }
.lib-empty { color: var(--muted); font-size: 0.95rem; padding: 24px 4px; }

/* Course preview window (modal) */
.pv-modal-backdrop { position: fixed; inset: 0; z-index: 9000; display: flex; align-items: flex-start;
    justify-content: center; padding: 4vh 16px; overflow-y: auto;
    background: rgba(3, 9, 7, 0.82); }
.pv-modal-backdrop[hidden] { display: none; }
.pv-modal { position: relative; width: 100%; max-width: 800px; margin: auto; background: var(--bg-1);
    border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-pop); padding: 26px; }
.pv-close { position: absolute; top: 16px; right: 16px; width: 34px; height: 34px; border-radius: 50%;
    border: 1px solid var(--line); background: var(--glass-2); color: var(--muted); cursor: pointer;
    font-size: 1rem; line-height: 1; display: flex; align-items: center; justify-content: center; z-index: 2; }
.pv-close:hover { color: var(--ink); border-color: var(--edge-soft); background: var(--fill-hover); }
.lib-preview-head { margin-bottom: 16px; padding-right: 40px; }
.pv-meta { color: var(--muted); font-size: 0.88rem; margin-top: 6px; }
#pv-map { height: 450px; width: 100%; background: var(--bg-1); }
.pv-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 20px;
    padding-top: 18px; border-top: 1px solid var(--line); }
.pv-actions-label { color: var(--muted); font-size: 0.9rem; margin-right: 2px; }
body.pv-open { overflow: hidden; }

/* "Open in…" chooser modal (library page) */
.tg-modal-backdrop { position: fixed; inset: 0; z-index: 10000; display: flex; align-items: center;
    justify-content: center; padding: 20px; background: rgba(3, 9, 7, 0.8); }
.tg-modal { width: 100%; max-width: 440px; background: var(--bg-1); border: 1px solid var(--line);
    border-radius: var(--radius); box-shadow: var(--shadow-pop); padding: 24px; }
.tg-modal-eyebrow { color: var(--accent); font-family: var(--mono); font-weight: 500;
    letter-spacing: 0.1em; text-transform: uppercase; font-size: 0.72rem; }
.tg-modal-title { font-family: var(--display); font-weight: 700; font-size: 1.2rem; margin-top: 6px; }
.tg-modal-sub { color: var(--muted); font-size: 0.9rem; margin-top: 4px; }
.tg-modal-choices { display: flex; flex-direction: column; gap: 10px; margin: 18px 0 14px; }
.tg-modal-choice { display: flex; flex-direction: column; gap: 3px; text-align: left; cursor: pointer;
    background: var(--glass-2); border: 1px solid var(--line); border-radius: var(--r-card); padding: 14px 16px;
    color: var(--ink); font-family: inherit; transition: border-color 0.15s, background 0.15s; }
.tg-modal-choice:hover { border-color: var(--edge-soft); background: var(--fill-hover); }
.tg-choice-title { font-family: var(--display); font-weight: 600; font-size: 1rem; }
.tg-choice-sub { color: var(--muted); font-size: 0.83rem; }
.tg-modal-cancel { background: transparent; color: var(--muted); border: 1px solid var(--line);
    border-radius: var(--r-ctl); padding: 8px 16px; cursor: pointer; font-family: inherit; font-weight: 600;
    font-size: 0.85rem; }
.tg-modal-cancel:hover { color: var(--ink); border-color: var(--muted); }

/* --- TrailGoat AI coach --- */
.coach { margin-bottom: 22px; }
.coach-messages { display: flex; flex-direction: column; gap: 10px; margin: 16px 0; }
/* Assistant bubbles render minimal markdown (bold + bullets) — see fuel-coach.js. */
.coach-msg ul { margin: 4px 0; padding-left: 18px; }
.coach-msg li { margin: 2px 0; }
.coach-msg strong { color: var(--gold); font-weight: 700; }
.coach-msg { max-width: 85%; padding: 10px 14px; border-radius: var(--r-card); font-size: 0.92rem; line-height: 1.5;
    white-space: pre-wrap; }
.coach-user { align-self: flex-end; background: var(--fill-selected); color: var(--ink); border-bottom-right-radius: 4px; }
.coach-assistant { align-self: flex-start; background: rgba(25,195,177,0.08); border: 1px solid rgba(25,195,177,0.28);
    border-left: 3px solid var(--teal); color: var(--ink); border-bottom-left-radius: 4px; }
.coach-assistant strong { color: var(--teal); }
.coach-thinking { color: var(--teal); font-style: italic; }
.coach-suggestions { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.coach-suggestions[hidden] { display: none; }   /* the flex above was beating [hidden] */
.coach-chip { background: var(--fill-idle); color: var(--ink); border: 1px solid var(--edge-soft);
    border-radius: var(--r-ctl); padding: 7px 14px; font-family: inherit; font-size: 0.85rem; cursor: pointer;
    transition: all 0.15s; }
.coach-chip:hover { border-color: var(--edge); background: var(--fill-hover); color: var(--ink); }
.coach-input { display: flex; gap: 10px; }
/* The runner's answer to "may we keep your questions?", with a way to change it. */
.coach-consent { margin: 8px 2px 0; font-size: .8rem; color: var(--muted); line-height: 1.45; }
.coach-consent[hidden] { display: none; }
.coach-consent-change { font: inherit; font-weight: 600; color: var(--accent); background: none; border: 0;
    padding: 0; cursor: pointer; text-decoration: underline; text-underline-offset: 3px; }
.coach-consent-change:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
.coach-input input { flex: 1; }
/* Locked Capra (KRI-199): the panel stays fully readable — hiding it would make
   the feature look absent rather than paid — but the controls go inert and the
   whole row becomes one click target for the upgrade cards. */
.coach-chip:disabled { opacity: .55; pointer-events: none; }
.coach-suggestions.coach-locked { cursor: pointer; }
.coach-chip:disabled:hover { border-color: var(--edge-soft); background: var(--fill-idle); color: var(--ink); }
.coach-input.coach-locked { cursor: pointer; }
.coach-input.coach-locked input { opacity: .55; pointer-events: none; }
.coach-input.coach-locked .export-btn { opacity: .55; pointer-events: none; }
.coach-input .export-btn { flex: 0 0 auto; }

/* Streaming (the Capra idea): stage copy until the first token, then a caret
   while tokens arrive. The caret is the bubble's own ink, not a new hue. */
.coach-streaming::after { content: ''; display: inline-block; width: 0.5em; height: 1em; margin-left: 2px;
    vertical-align: -0.15em; background: currentColor; opacity: .55; border-radius: 1px;
    animation: capra-caret 1s steps(2, start) infinite; }
@keyframes capra-caret { to { visibility: hidden; } }
.coach-thinking::before { content: ''; display: inline-block; width: 7px; height: 7px; margin-right: 8px;
    border-radius: 50%; background: var(--gold); vertical-align: 0.05em; animation: capra-pulse 1.2s var(--ease-snap) infinite; }
@keyframes capra-pulse { 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) {
    .coach-streaming::after, .coach-thinking::before { animation: none; }
}
/* Where the reply's suggestions went — one line under the answer. */
.capra-note { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line); white-space: normal; }
.capra-note .inline-link, .capra-pop .inline-link { background: none; border: 0; padding: 0; font: inherit;
    font-size: 0.85rem; font-weight: 600; cursor: pointer; }
.capra-note .inline-link:focus-visible, .capra-pop .inline-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

/* Capra's chip on an aid-table row: small, gold (Capra's brand hue — the one
   thing on the table that is an opinion rather than a number), and a button,
   so the printout's table clone drops it with the other controls. */
.capra-sug { display: inline-flex; align-items: center; gap: 5px; margin: 2px 0 2px 8px; padding: 2px 8px;
    min-height: 24px; max-width: 100%; border-radius: var(--r-ctl); font: inherit; font-size: 0.78rem; line-height: 1.2;
    color: var(--ink); background: color-mix(in srgb, var(--gold) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--gold) 45%, transparent); cursor: pointer; vertical-align: middle;
    text-align: left; transition: background var(--dur-ctl) var(--ease-snap), border-color var(--dur-ctl) var(--ease-snap); }
.capra-sug:hover, .capra-sug[aria-expanded="true"] { background: color-mix(in srgb, var(--gold) 18%, transparent);
    border-color: var(--gold); }
.capra-sug:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.capra-sug-by { font-family: var(--mono); font-size: 0.64rem; font-weight: 700; letter-spacing: 0.08em;
    text-transform: uppercase; color: var(--gold); }
.capra-pop { position: fixed; z-index: 60; padding: 12px 14px; background: var(--bg-2); color: var(--ink);
    border: 1px solid color-mix(in srgb, var(--gold) 45%, transparent); border-left: 3px solid var(--gold);
    border-radius: var(--r-card); box-shadow: var(--shadow-pop); font-size: 0.88rem;
    animation: capra-pop-in var(--dur-layer) var(--ease-snap); }
@keyframes capra-pop-in { from { opacity: 0; transform: translateY(-4px); } }
.capra-pop-head { font-weight: 700; line-height: 1.35; }
.capra-pop-at { font-weight: 400; color: var(--muted); }
.capra-pop-why { margin: 6px 0 0; color: var(--ink); line-height: 1.45; }
.capra-pop-actions { display: flex; align-items: center; gap: 12px; margin-top: 10px; }
@media (prefers-reduced-motion: reduce) { .capra-pop { animation: none; } }
@media (max-width: 860px) {
    .capra-sug { min-height: 32px; margin-left: 0; }
    .capra-pop-actions .export-btn, .capra-pop-actions .inline-link { min-height: 44px; }
}

/* Footer */
.foot { text-align: center; color: var(--muted); font-size: 0.85rem; padding: 30px 24px 50px; }
.foot a { color: var(--accent); text-decoration: none; }
.foot a:hover { text-decoration: underline; }

/* Methodology */
.methodology p { color: var(--muted); font-size: 0.9rem; margin-top: 12px; }
.methodology .disclaimer { color: var(--muted); }
.methodology .disclaimer strong { color: var(--gold); }

/* =========================================================================
   Two-pane app shell (Planner + Fuel) — body.split-page only.
   Mobile keeps the natural stacked, page-scroll flow (the grid/scroll panes
   only kick in at >=861px). Left = setup/inputs, right = map + outputs.
   ========================================================================= */
/* Empty-state placeholder in a result pane — shown until a course loads.
   (Global so it works on mobile too; the sibling toggle hides it once the
   course view is un-hidden by the page JS.) */
.split-empty {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 12px; min-height: 280px; text-align: center; color: var(--muted); padding: 20px;
}
.split-empty-icon { font-size: 2.6rem; opacity: 0.7; }
.split-empty p { max-width: 26rem; }
.course-view:not([hidden]) ~ .split-empty { display: none; }   /* loaded → hide placeholder */

/* Empty state = a navigable base map of the user's area (before a course loads). */
.split-empty.has-basemap { display: block; min-height: 0; padding: 0; text-align: left; }
#base-map { height: clamp(450px, 72vh, 775px); width: 100%; background: var(--bg-1); }
#base-map[hidden] { display: none; }   /* explicit height above would beat [hidden] */
/* Waiting / "open a course" cards shown in the map slot (base-map.js states 1 & 3). */
.base-map-note {
    height: clamp(450px, 72vh, 775px);
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 8px; text-align: center; padding: 24px;
    border: 1px dashed var(--line); border-radius: var(--radius);
    background: var(--glass); color: var(--ink); font-size: 0.95rem;
}
.base-map-note strong { color: var(--ink); font-size: 1.1rem; font-family: var(--display); }
.base-map-note span { max-width: 46ch; }
.base-map-note .bm-goat { display: block; width: 49px; height: 64px; margin: 0 auto;
    filter: drop-shadow(0 2px 3px rgba(0,0,0,0.55)); }
.base-map-note .bm-retry {
    margin-top: 10px; font: inherit; font-size: 0.86rem; font-weight: 600;
    color: var(--ink); background: none; border: 1px solid var(--edge);
    border-radius: var(--r-ctl); padding: 6px 14px; cursor: pointer;
}
.base-map-note .bm-retry:hover { background: var(--fill-hover); }
/* Featured-course cards (KRI-56) — the one-click wow moment. */
.bm-featured { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center;
    margin-top: 14px; width: 100%; max-width: 640px; }
.bm-card { flex: 1 1 170px; max-width: 210px; display: grid; gap: 3px; text-align: left;
    text-decoration: none; border: 1px solid var(--line); border-radius: var(--r-card);
    padding: 12px 14px; background: var(--glass-2, rgba(255,255,255,0.03));
    transition: border-color 0.15s, background 0.15s, transform 0.15s; }
.bm-card:hover { border-color: var(--edge-soft); background: var(--fill-hover);
    transform: translateY(-1px); }
.bm-card-name { font-weight: 700; color: var(--ink); font-family: var(--display);
    font-size: 0.95rem; }
.bm-card-meta { color: var(--muted); font-size: 0.78rem; }
.bm-card-go { color: var(--accent); font-size: 0.78rem; font-weight: 600; margin-top: 4px; }
.bm-fail { color: var(--bad); font-size: 0.82rem; margin-top: 6px; }
@media (max-width: 560px) {
    .bm-featured { flex-direction: column; }
    .bm-card { max-width: none; }
}
.base-map-cap { color: var(--muted); font-size: 0.86rem; margin: 12px 2px 0; max-width: none;
    display: flex; align-items: center; gap: 6px 10px; flex-wrap: wrap; }
.base-map-cap strong { color: var(--ink); }
.base-map-sub { opacity: 0.8; }
/* "You are here" mascot marker on the base map (neutralise Leaflet's default div-icon box). */
.tg-you-goat { background: none; border: 0; text-align: center;
    filter: drop-shadow(0 2px 3px rgba(0,0,0,0.55)); }
.tg-you-goat img { display: block; width: 33px; height: 44px; }

@media (min-width: 861px) {
    /* Scoped to the split-page layout ON PURPOSE. An unscoped `html {height:100%}`
       clamps the background POSITIONING AREA to one viewport on every page that
       loads this sheet, so a body gradient tiles once per screen down a long
       page (the crew sheet showed a seam every ~900px). The planner hides that
       behind its fixed .backdrop; pages without one don't.
       Two rules, not one list: an unsupported :has() would invalidate the whole
       list and take the split-page rule down with it. */
    html:has(body.split-page) { height: 100%; }
    body.split-page { height: 100%; }
    body.split-page {
        display: flex; flex-direction: column;
        height: 100vh; height: 100dvh;
        overflow: hidden;                         /* the page itself never scrolls */
    }
    body.split-page .topbar { flex: 0 0 auto; }

    body.split-page .wrap {
        max-width: none; width: 100%;
        margin: 0; padding: 0 clamp(16px, 2vw, 30px);
        flex: 1 1 auto; min-height: 0;
        display: flex; flex-direction: column;
    }
    body.split-page .foot { display: none; }      /* reclaim vertical space */

    /* Hero now lives inside .split-left so the right-pane map rises to the top, inline
       with the hero text (reclaims the wasted top-right space). */
    body.split-page .hero { flex: 0 0 auto; margin: 0; }
    body.split-page .hero h1 { font-size: clamp(1.35rem, 2.2vw, 1.85rem); }
    body.split-page .hero-sub { display: none; }

    /* Two columns fill the remaining height; each scrolls on its own. */
    body.split-page .app-split {
        flex: 1 1 auto; min-height: 0;
        display: grid; grid-template-columns: minmax(320px, 400px) 1fr; gap: 18px;
        align-items: stretch; padding-bottom: 14px;
    }
    body.split-page .split-left,
    body.split-page .split-right {
        min-height: 0; overflow-y: auto; overscroll-behavior: contain;
        display: flex; flex-direction: column; gap: 16px; padding-right: 4px;
    }
    body.split-page .split-left::-webkit-scrollbar,
    body.split-page .split-right::-webkit-scrollbar { width: 9px; }
    body.split-page .split-left::-webkit-scrollbar-thumb,
    body.split-page .split-right::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--ink) 14%, transparent); border-radius: 8px; }

    /* Panels inside the panes shouldn't add their own outer margins. */
    body.split-page .split-left > .panel,
    body.split-page .split-right > .panel { margin: 0; }
}

/* ===== Build your pack (food database) ===== */
.fp { margin-top: 6px; }
.fp-empty { color: var(--muted); font-size: 0.9rem; line-height: 1.5; margin: 4px 0 0; }

/* Coverage bars: pack total vs the engine's race targets. Full-width card → lay the
   bars out in a responsive grid; glossy 3D pills with a moving sheen. */
.fp-cov-sub-head { font-family: var(--body); font-weight: 400; font-size: 0.78rem; color: var(--muted); }
.fp-coverage { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 16px 26px; margin-top: 12px; }
.fp-coverage[hidden] { display: none; }
.fp-cov-row { display: flex; flex-direction: column; gap: 7px; }
.fp-cov-caf { --acc: var(--c-climb); }   /* caffeine: an informational total */
.fp-cov-top { display: flex; align-items: baseline; justify-content: space-between; }
.fp-cov-label { font-family: var(--display); font-weight: 600; font-size: 0.95rem; color: var(--ink); }
.fp-pct { font-family: var(--mono); font-weight: 700;
    font-size: 1.02rem; color: var(--acc, var(--teal));
    text-shadow: 0 0 12px color-mix(in srgb, var(--acc, var(--teal)) 55%, transparent); }
.fp-pct.over { color: var(--ok); text-shadow: 0 0 12px color-mix(in srgb, var(--ok) 55%, transparent); }

/* Track = a recessed channel (inset shadow reads as carved-in depth). */
.fp-cov-track {
    position: relative; height: 16px; border-radius: 999px; overflow: hidden;
    background: linear-gradient(180deg, rgba(0,0,0,0.45), rgba(255,255,255,0.03));
    border: 1px solid rgba(255,255,255,0.07);
    box-shadow: inset 0 2px 5px rgba(0,0,0,0.55), inset 0 -1px 0 rgba(255,255,255,0.04);
}
/* Fill = a glossy raised pill: vertical light→dark gradient + top highlight + glow. */
.fp-cov-fill {
    position: relative; height: 100%; border-radius: 999px; min-width: 6px;
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--acc, var(--teal)) 58%, #fff) 0%,
        var(--acc, var(--teal)) 45%,
        color-mix(in srgb, var(--acc, var(--teal)) 70%, #000) 100%);
    box-shadow: 0 0 14px -2px var(--acc, var(--teal)),
        inset 0 1px 0 rgba(255,255,255,0.6),
        inset 0 -3px 6px rgba(0,0,0,0.28);
    transition: width 0.5s cubic-bezier(.2,.8,.3,1);
}
/* A fixed highlight across the fill — the gloss stays, the perpetual sweep is
   gone (TG-285). */
.fp-cov-fill::after {
    content: ""; position: absolute; inset: 0; border-radius: inherit;
    background: linear-gradient(115deg, transparent 30%, rgba(255,255,255,0.28) 48%, transparent 66%);
}
@media (prefers-reduced-motion: reduce) {
    .fp-cov-fill { transition: none; }
}
.fp-cov-sub { font-size: 0.84rem; color: var(--muted); }
.fp-cov-sub small { opacity: 0.8; }
.fp-cov-info { justify-content: flex-end; }
.fp-cov-info .fp-cov-sub { color: var(--ink); }

/* Your pack */
.fp-pack-head { display: flex; align-items: baseline; justify-content: space-between; margin: 18px 0 8px; }
.fp-pack-head h4 { font-family: var(--display); font-weight: 600; font-size: 0.95rem; color: var(--ink); margin: 0; }
.fp-count { color: var(--muted); font-weight: 500; font-size: 0.82rem; margin-left: 6px; }
.fp-clear { background: none; border: 1px solid var(--line); color: var(--muted); border-radius: var(--r-ctl);
    font: inherit; font-size: 0.78rem; padding: 3px 11px; cursor: pointer; transition: all 0.15s; }
.fp-clear:hover { color: var(--ink); border-color: var(--edge-soft); background: var(--fill-hover); }

/* Fixed-height scroll region, NOT free-growing: every added pill used to push
   the food grid down mid-tap, so the second tap landed on the wrong product
   (2026-08 review, worst on phones). The pack scrolls inside itself instead —
   nothing below it ever moves. */
.fp-pack { display: flex; flex-wrap: wrap; gap: 8px; align-content: flex-start;
    height: 84px; overflow-y: auto; padding-right: 6px;
    scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--ink) 20%, transparent) transparent; }
.fp-pack::-webkit-scrollbar { width: 8px; }
.fp-pack::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--ink) 14%, transparent); border-radius: 8px; }
/* Slots (2026-09): the pack laid out as a vest — front L, front R, back —
   plus a card per drop bag. Still one fixed-height scroller, taller now it
   holds cards, for the same reason as above. */
.fp-pack { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 8px;
    height: 176px; flex-wrap: nowrap; }
.fp-slot { border: 1px solid var(--line); border-radius: var(--r-card); padding: 7px 8px 8px;
    background: var(--glass); min-width: 0; align-self: start; }
.fp-slot.is-bag { border-style: dashed; }
.fp-slot-h { display: flex; justify-content: space-between; align-items: baseline; gap: 6px; margin-bottom: 6px; }
.fp-slot-t { font-weight: 600; font-size: 0.8rem; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fp-slot-s { font-size: 0.72rem; color: var(--muted); white-space: nowrap; }
.fp-slot-pills { display: flex; flex-wrap: wrap; gap: 6px; }
.fp-slot-pills:empty::before { content: "—"; color: var(--muted); font-size: 0.8rem; }

/* Carbs per hour: what the pack can feed each hour against the target. */
.fp-meter { margin: 2px 0 16px; }
.fp-meter[hidden] { display: none; }
.fp-meter-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px;
    font-size: 0.72rem; color: var(--muted); margin-bottom: 6px; }
.fp-meter-tgt { color: var(--ink); font-size: 0.8rem; white-space: nowrap; }
.fp-meter-chart { position: relative; display: flex; align-items: flex-end; gap: 2px; height: 72px;
    padding-top: 2px; border-bottom: 1px solid var(--line); }
.fp-meter-goal { position: absolute; left: 0; right: 0; top: 2px; border-top: 1px dashed var(--edge-soft, var(--line)); pointer-events: none; }
.fp-meter-bar { flex: 1 1 0; min-width: 2px; border-radius: 2px 2px 0 0; background: var(--ok); }
.fp-meter-bar.warn { background: var(--warn); }
.fp-meter-bar.bad { background: var(--bad); }
.fp-meter-ticks { display: flex; justify-content: space-between; font-size: 0.68rem; color: var(--muted); margin-top: 3px; }
.fp-short { margin: 10px 0 0; padding: 8px 10px; border-radius: var(--r-ctl); font-size: 0.85rem;
    border: 1px solid color-mix(in srgb, var(--ok) 40%, transparent); color: var(--ink); }
.fp-short p { margin: 0; }
.fp-short.bad { border-color: color-mix(in srgb, var(--bad) 45%, transparent); }
.fp-short.bad b { color: var(--bad); }
.fp-short.ok b { color: var(--ok); }
.fp-short-sub { color: var(--muted); }
.fp-short-fix { margin-top: 8px; min-height: 36px; text-align: left; }
@media (max-width: 860px) {
    .fp-pack { height: 220px; grid-template-columns: 1fr 1fr; }
    .fp-short-fix { min-height: 44px; width: 100%; justify-content: center; }
}
@media (max-width: 420px) {
    .fp-pack { grid-template-columns: 1fr; }
}
.fp-pack-empty { grid-column: 1 / -1; color: var(--muted); font-size: 0.88rem; font-style: italic; padding: 4px 2px; }
.fp-pill { display: inline-flex; align-items: center; gap: 4px; padding: 3px 4px 3px 4px;
    border: 1px solid color-mix(in srgb, var(--cat, var(--teal)) 55%, transparent);
    background: color-mix(in srgb, var(--cat, var(--teal)) 14%, transparent);
    border-radius: var(--r-ctl); font-family: var(--body); font-size: 0.85rem; color: var(--ink); }
.fp-pill .fp-name { padding: 0 2px; }
.fp-qty { font-family: var(--mono); font-weight: 700;
    min-width: 1.1em; text-align: center;
    color: var(--cat, var(--teal)); }
.fp-step { width: 22px; height: 22px; border-radius: 50%; border: none; cursor: pointer;
    background: var(--fill-hover); color: var(--ink); font-size: 1rem; line-height: 1;
    display: inline-flex; align-items: center; justify-content: center; transition: background 0.15s; }
.fp-step:hover { background: color-mix(in srgb, var(--cat, var(--teal)) 35%, transparent); }
.fp-rm { width: 20px; height: 20px; margin-left: 2px; border: none; cursor: pointer; background: none;
    color: var(--muted); font-size: 1.05rem; line-height: 1; border-radius: 50%; transition: all 0.15s; }
.fp-rm:hover { color: var(--ink); background: var(--fill-hover); }

/* Search + food bin */
.fp-search-wrap { display: block; margin: 16px 0 10px; }
.fp-search-wrap input { width: 100%; }
/* overscroll-behavior:auto so reaching the bin's scroll limit chains back to the
   page/pane scroll instead of dead-stopping. */
.fp-bin { display: flex; flex-direction: column; gap: 14px; max-height: 360px; overflow-y: auto;
    padding-right: 4px; overscroll-behavior: auto; }
.fp-bin::-webkit-scrollbar { width: 8px; }
.fp-bin::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--ink) 14%, transparent); border-radius: 8px; }
.fp-bin-cat { display: flex; align-items: baseline; gap: 8px; margin: 0 0 8px; flex-wrap: wrap;
    font-family: var(--mono); font-weight: 700; font-size: 0.78rem; letter-spacing: 0.1em;
    text-transform: uppercase; color: var(--cat, var(--muted)); }
.fp-bin-cat small { text-transform: none; letter-spacing: 0; font-weight: 400; color: var(--muted); opacity: 0.85; }
.fp-bin-pills { display: flex; flex-wrap: wrap; gap: 8px; }
.fp-bin-none { color: var(--muted); font-size: 0.88rem; font-style: italic; }
.fp-add-pill { display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px 5px 9px;
    border: 1px solid var(--line); border-radius: var(--r-ctl); background: var(--glass); cursor: pointer;
    font-family: var(--body); font-size: 0.85rem; color: var(--muted); transition: all 0.15s; }
.fp-add-pill:hover { color: var(--ink); transform: translateY(-1px);
    border-color: var(--cat, var(--teal)); background: color-mix(in srgb, var(--cat, var(--teal)) 12%, transparent); }
.fp-add-pill:active { transform: translateY(0) scale(0.97); }
.fp-add-pill.added { color: var(--ink); border-color: color-mix(in srgb, var(--cat, var(--teal)) 55%, transparent);
    background: color-mix(in srgb, var(--cat, var(--teal)) 10%, transparent); }
.fp-add-ic { color: var(--cat, var(--teal)); font-weight: 700; line-height: 1; }
.fp-add-name { color: inherit; }
.fp-add-macros { color: var(--muted); font-size: 0.74rem; white-space: nowrap; }
.fp-add-macros small { opacity: 0.7; }

/* ===== Hour-by-hour weather strip (shared by /fuel and /raceday; logic in raceday-weather.js) ===== */
.rd-weather { margin-top: 18px; }
.rd-weather[hidden] { display: none; }
.rd-wx-strip { display: flex; align-items: stretch; gap: 8px; margin-top: 8px; }
.rd-wx-cells { flex: 1 1 auto; display: grid; grid-template-columns: repeat(12, 1fr); gap: 5px; min-width: 0; }
.rd-wx-cell {
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    padding: 9px 2px; border-radius: var(--r-ctl); background: var(--glass); border: 1px solid var(--line);
    min-width: 0;
}
.rd-wx-cell.rd-wx-race { border-color: rgba(255,122,26,0.6); background: rgba(255,122,26,0.08); }
.rd-wx-cell.rd-wx-empty { opacity: 0.4; }
.rd-wx-cell.rd-wx-newday { box-shadow: inset 2px 0 0 rgba(255,210,63,0.55); }
.rd-wx-day { font-size: 0.58rem; font-weight: 700; color: var(--gold); min-height: 0.85em; white-space: nowrap; line-height: 1; }
.rd-wx-time { font-family: var(--mono); font-size: 0.64rem; color: var(--muted); white-space: nowrap; }
.rd-wx-ico { line-height: 1; color: var(--ink); display: flex; justify-content: center; }
/* Weather art is line-icon SVG (icons.js) — sized here, coloured by context. */
.rd-wx-ico .wx-ico { width: 22px; height: 22px; }
.rd-wx-race .rd-wx-ico { color: var(--orange); }
/* Small inline glyphs beside a stat (droplet, wind, sunrise, thermometer…). */
.wx-gl { width: 13px; height: 13px; vertical-align: -0.16em; opacity: .9; }
.wx-gl.aqua { color: var(--aqua); } .wx-gl.gold { color: var(--gold); } .wx-gl.orange { color: var(--orange); }
.rd-wx-temp { font-family: var(--mono); font-weight: 700; font-size: 0.9rem; }
/* Temperature steps, cool → hot (weather-explorer.js tempCls; its chart
   resolves the same tokens). Data hues: a temperature is data, not a state. */
.wx-tn { color: var(--muted); }
.wx-t0 { color: var(--c-aid); }
.wx-t1 { color: var(--c-course); }
.wx-t2 { color: var(--c-crew); }
.wx-t3 { color: var(--gold); }
.wx-t4 { color: var(--c-fuel); }
.wx-t5 { color: var(--c-climb); }
.rd-wx-pp { font-size: 0.6rem; color: var(--teal); min-height: 0.8em; white-space: nowrap; }
.rd-wx-arrow {
    flex: 0 0 auto; width: 34px; border-radius: var(--r-ctl); cursor: pointer;
    background: var(--glass-2); color: var(--ink); border: 1px solid var(--line);
    font-size: 1.2rem; line-height: 1; transition: all 0.15s ease;
}
.rd-wx-arrow:hover:not(:disabled) { border-color: var(--edge-soft); background: var(--fill-hover); }
.rd-wx-arrow:disabled { opacity: 0.3; cursor: default; }
.rd-wx-status { color: var(--muted); font-size: 0.8rem; margin-top: 8px; min-height: 1em; }
.rd-wx-status.warn { color: var(--warn); }

/* ===================== Weather explorer card (weather-explorer.js) ===================== */
.rd-wx-bar { display: flex; align-items: center; gap: 12px 18px; flex-wrap: wrap; margin-bottom: 12px; }
.rd-wx-datefield { display: inline-flex; align-items: center; gap: 8px; color: var(--muted); font-size: 0.86rem; }
.rd-wx-datefield input { background: var(--glass-2); color: var(--ink); border: 1px solid var(--line); border-radius: 10px; padding: 7px 10px; font: inherit; color-scheme: dark; }
.rd-wx-datefield input:focus { outline: none; border-color: var(--accent); }
.rd-wx-datefield input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.rd-wx-summary { display: flex; flex-wrap: wrap; gap: 7px 16px; align-items: center; color: var(--muted); font-size: 0.86rem; }
.rd-wx-summary b:not([class]) { color: var(--ink); }   /* a .wx-t* high keeps its hue */
.rd-wx-sum-note { font-style: italic; opacity: 0.85; }

.rd-wx-days { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(60px, 1fr); gap: 6px;
    overflow-x: auto; padding-bottom: 6px; margin-bottom: 14px; overscroll-behavior-x: contain; }
.rd-wx-day-chip { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 8px 4px;
    border-radius: var(--r-ctl); background: var(--glass); border: 1px solid var(--line); cursor: pointer; color: var(--ink); transition: all 0.15s ease; }
.rd-wx-day-chip:hover { border-color: var(--edge-soft); background: var(--fill-hover); }
.rd-wx-day-chip.active { border-color: var(--accent); background: var(--fill-selected); }
.rd-wx-dc-day { font-size: 0.7rem; font-weight: 700; color: var(--muted); }
.rd-wx-dc-ico { font-size: 1.1rem; line-height: 1; }
.rd-wx-dc-hl { font-family: var(--mono); font-size: 0.72rem; }

/* Two hourly views, switchable via a pill toggle: an Apple-style temperature curve
   (Chart.js, mirrors the elevation profile's hover/drag scrubber) and the classic
   hour-by-hour cells. */
.rd-wx-chart-head { display: flex; align-items: center; justify-content: space-between; gap: 10px;
    flex-wrap: wrap; margin: 16px 0 8px; }
.rd-wx-chart-title { color: var(--muted); font-size: 0.85rem; font-weight: 600; }
.rd-wx-view-toggle { display: inline-flex; gap: 4px; background: var(--glass-2);
    border: 1px solid var(--line); border-radius: var(--r-ctl); padding: 3px; }
.rd-wx-view-toggle button { background: transparent; color: var(--muted); border: none; cursor: pointer;
    border-radius: var(--r-ctl); padding: 5px 13px; font-family: var(--body); font-weight: 600; font-size: 0.78rem; }
.rd-wx-view-toggle button.active { background: var(--fill-selected); color: var(--accent); }
.rd-wx-chart-wrap { position: relative; height: 210px; }
/* City label in the Weather header band (reverse-geocoded from the course start). */
.rd-wx-place { color: var(--ink); font-weight: 600; }
/* .rd-wx-strip sets display:flex (fuel.css), which beats the UA [hidden] rule — re-assert it
   so toggling back to the graph actually hides the hour-by-hour cells. */
.rd-wx-strip[hidden], .rd-wx-chart-wrap[hidden] { display: none; }

/* Classic hour-by-hour cells (base .rd-wx-* come from fuel.css). */
#rd-weather-card .rd-wx-cells { grid-template-columns: repeat(12, minmax(72px, 1fr)); overflow-x: auto; overscroll-behavior-x: contain; }
.rd-wx-feels { font-size: 0.6rem; color: var(--muted); min-height: 0.8em; white-space: nowrap; }
.rd-wx-wind { font-size: 0.6rem; color: var(--muted); white-space: nowrap; }
.rd-wx-cell.rd-wx-night { background: rgba(60, 80, 140, 0.16); }
.rd-wx-none { color: var(--muted); font-style: italic; padding: 8px 2px; }

@media (max-width: 560px) {
    .rd-wx-cells { grid-template-columns: repeat(12, minmax(46px, 1fr)); overflow-x: auto; }
}

/* ===== Collapsible coloured left-pane sections (shared by /raceday, /fuel, /planner) =====
   A .panel that is a <details>; the <summary> is the header. Each section carries an accent
   colour via --acc (set inline) for a coloured left edge + icon chip + chevron, so the left
   pane reads as distinct, lively cards. */
/* The collapsible card look — ONE source of truth, shared by /fuel, /planner and
   /raceday (every `.panel.rd-section`). Treatment: a mono all-caps title, a
   filled accent header band, and an accent glow outline, all keyed off the card's
   per-card `--acc` colour. Panel content padding is 14px (top/bottom) × 24px
   (left/right), so the band uses matching negative margins to bleed to the edges.
   Change the card aesthetic HERE and all three pages stay in sync. */
.rd-section { padding-top: 14px; padding-bottom: 14px; }
/* When a card is collapsed, force-hide its body even where an author rule (the base map,
   the fuel-cards grid, etc.) would otherwise display:block/grid it. Shared so the result
   cards collapse correctly on /fuel and /planner, not just /raceday. */
.rd-section:not([open]) > :not(summary) { display: none !important; }

/* The section's identity stays in its 1px accent-tinted edge (iconography);
   the coloured glow it used to carry is gone (TG-282). */
.rd-section.panel {
    border: 1px solid color-mix(in srgb, var(--acc, var(--line)) 55%, var(--line));
    box-shadow: none;
}

.rd-section > summary {
    list-style: none; cursor: pointer; user-select: none;
    display: flex; align-items: center; gap: 9px;
    font-family: var(--mono); font-weight: 700; font-size: 1.02rem; color: var(--ink);
    text-transform: uppercase; letter-spacing: 0.02em;
    /* Filled header band — bleeds to the card edges. */
    margin: -14px -24px; padding: 13px 24px;
    background: linear-gradient(100deg, color-mix(in srgb, var(--acc, var(--muted)) 26%, transparent), transparent 92%);
    border-radius: calc(var(--radius) - 1px);
}
.rd-section > summary::-webkit-details-marker { display: none; }
/* The section title is a real <h2> (one outline for screen readers) that
   looks exactly like the summary text it wraps. */
.rd-sec-h { margin: 0; font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit; }
.rd-sec-ico {
    flex: 0 0 auto; width: 26px; height: 26px; border-radius: 8px; display: grid; place-items: center;
    font-size: 0.95rem; background: var(--acc, var(--muted));
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.28), 0 2px 5px rgba(0,0,0,0.35);
}
/* Dark stroke on the accent tile — same raised-tile treatment as the landing cards. */
.rd-sec-ico .ico { width: 15px; height: 15px; color: #081410; }
.rd-section > summary::after {
    content: '⌄'; margin-left: auto; color: var(--acc, var(--muted)); font-size: 1.1rem; line-height: 1;
    transition: transform 0.18s ease;
}

/* The AI coach card wears its gold section tint like every other section.
   The three-hue gradient ring / band / tile it used to carry is retired: the
   wordmark and the goat are the only multicolour brand marks (TG-282). Its
   "TRAILGOAT AI" title still carries the wordmark gradient via .grad. */
#coach-panel { --acc: var(--gold); position: relative; }
.rd-section[open] > summary::after { transform: rotate(180deg); }
.rd-section > summary .rd-sec-sub {
    font-family: var(--body); font-weight: 400; font-size: 0.78rem; color: var(--muted);
    text-transform: none; letter-spacing: normal;
}
/* Collapsed: the band fills the whole card. Open: band caps the top, body sits below. */
.rd-section:not([open]) > summary { margin-bottom: -14px; }
.rd-section[open] > summary {
    margin-bottom: 14px; border-bottom: 1px solid var(--line);
    border-radius: calc(var(--radius) - 1px) calc(var(--radius) - 1px) 0 0;
}

/* The fuel form must stay one element (fuel.js delegates its 'input' listener on it),
   but it shouldn't draw its own box — let its <details> children be the panes. */
.rd-form { display: contents; }

/* Space the sections' controls a touch tighter in the narrow left pane. */
.rd-section .field-block + .field-block { margin-top: 14px; }
.rd-section .effort-col > * + * { margin-top: 14px; }

/* A small note under a section heading. */
.rd-note { color: var(--muted); font-size: 0.84rem; margin: 0 0 12px; }
.rd-note:last-child { margin-bottom: 0; }
/* Clear-course control inside the Course card (left pane). */
.course-card-actions { margin-top: 12px; display: flex; flex-wrap: wrap; gap: 8px; }
/* GPX download only means something once a course is loaded (KRI-112). */
#download-gpx { display: none; }
body.has-course #download-gpx { display: inline-flex; }

/* ===== Mobile ergonomics (shared by every tool page; fuel.css is the common sheet) ===== */
@media (max-width: 860px) {
    /* iOS Safari zooms the whole page when a focused field computes under 16px.
       Guard every text-entry control — the typed selector matches the specificity
       of the themed input rules above, and this block loads later, so it wins. */
    input[type], input:not([type]), select, textarea { font-size: max(1rem, 16px); }

    /* Touch targets: grow hit areas toward the 44px minimum without inflating
       the glyphs. Isolated map-corner controls and pill controls that sit in
       tight clusters get as close as their context allows. */
    .map-3d-btn, .map-expand-btn, .map-play-btn, .map-locate-btn { width: 42px; height: 42px; }
    .map-locate-btn svg { width: 20px; height: 20px; }
    .map-speed-btn { min-width: 42px; height: 42px; }

    /* Food-pack pills: bigger steppers, comfortable pill height. */
    .fp-pill { padding: 5px 6px; }
    .fp-step { width: 34px; height: 34px; }
    .fp-rm { width: 30px; height: 30px; }
    .fp-add-pill { min-height: 44px; padding: 8px 14px 8px 11px; }
    .fp-clear { min-height: 36px; padding: 5px 14px; }

    /* Aid-station row actions (✎ / ×): full-size touch targets. */
    .aid-actions { gap: 0; margin-left: 4px; }
    .aid-rm, .aid-edit {
        min-width: 42px; min-height: 42px;
        display: inline-flex; align-items: center; justify-content: center;
    }
}

/* ===== Mobile plan tables: stacked two-line rows =====
   Under 600px the 5–6 column tables don't fit; instead of clipping the payload
   columns (pace, splits, water, carbs) off-screen, each <tr> reflows into a
   card-like row: line 1 = the label + the answer, line 2 = muted supporting
   detail. Pure CSS — the row templates in JS are untouched. Line breaks are
   deterministic: a flex-grow:1 cell fills the rest of its line, so the next
   cell always wraps. */
@media (max-width: 600px) {
    /* Stat cards: distance is the headline (full width), the rest pair up 2×2 —
       no more lone orphan card stretched across the last row. */
    .course-stats { display: grid; grid-template-columns: 1fr 1fr; }
    .course-stats .cs-dist { grid-column: 1 / -1; }

    #pace-table thead, #climbs-table thead, #plan-summary .plan-table thead,
    #raceplan-table thead, #aid-table thead, #lib-aid-table thead { display: none; }

    #pace-table, #climbs-table, #plan-summary .plan-table,
    #raceplan-table, #aid-table, #lib-aid-table { display: block; }
    #pace-table tbody, #climbs-table tbody, #plan-summary .plan-table tbody,
    #raceplan-table tbody, #aid-table tbody, #lib-aid-table tbody { display: block; }

    #pace-table tr, #climbs-table tr, #plan-summary .plan-table tr,
    #raceplan-table tr, #aid-table tr, #lib-aid-table tr {
        display: flex; flex-wrap: wrap; align-items: baseline;
        column-gap: 14px; row-gap: 3px;
        padding: 11px 4px; border-bottom: 1px solid var(--line);
    }
    #pace-table td, #climbs-table td, #plan-summary .plan-table td,
    #raceplan-table td, #aid-table td, #lib-aid-table td {
        display: block; padding: 0; border: 0; text-align: left;
    }

    /* Pacing plan — line 1: segment + target pace; line 2: gain/loss · grade · elapsed.
       The rows' ::before is an invisible full-width flex item — a deterministic
       line break between the headline cells and the detail cells. */
    #pace-table tr::before { content: ""; flex: 1 1 100%; order: 3; }
    #pace-table td:nth-child(1) { flex: 1 1 auto; order: 1; font-weight: 600; }
    #pace-table td:nth-child(4) { order: 2; }
    #pace-table td:nth-child(2) { order: 4; font-size: 0.82rem; }
    #pace-table td:nth-child(3) { order: 5; font-size: 0.82rem; }
    #pace-table td:nth-child(5) { order: 6; margin-left: auto; font-size: 0.82rem; color: var(--muted); }
    #pace-table td:nth-child(5)::before { content: "elapsed "; }

    /* Major climbs — line 1: climb + gain; line 2: from–to · length · grade */
    #climbs-table tr::before { content: ""; flex: 1 1 100%; order: 3; }
    #climbs-table td:nth-child(1) { flex: 1 1 auto; order: 1; font-weight: 600; }
    #climbs-table td:nth-child(4) { order: 2; }
    #climbs-table td:nth-child(2) { order: 4; font-size: 0.82rem; color: var(--muted); }
    #climbs-table td:nth-child(3) { order: 5; font-size: 0.82rem; color: var(--muted); }
    #climbs-table td:nth-child(5) { order: 6; margin-left: auto; font-size: 0.82rem; }

    /* Fuel plan summary — line 1: section + water + carbs; line 2: distance · arrival */
    #plan-summary .plan-table tr::before { content: ""; flex: 1 1 100%; order: 4; }
    #plan-summary .plan-table td:nth-child(1) { flex: 1 1 auto; order: 1; font-weight: 600; }
    #plan-summary .plan-table td:nth-child(4) { order: 2; }
    #plan-summary .plan-table td:nth-child(5) { order: 3; }
    #plan-summary .plan-table td:nth-child(2) { order: 5; font-size: 0.82rem; color: var(--muted); }
    #plan-summary .plan-table td:nth-child(3) { order: 6; margin-left: auto; font-size: 0.82rem; color: var(--muted); }
    #plan-summary .plan-table td:nth-child(3)::before { content: "arrive "; }

    /* Race Day plan — a card per stop, one concern per line:
         1  name (wraps as it must) · drop bag           edit / cutoff / remove
         2  crew marks — only when someone meets or hands off here
         3  dist · arrive ETA · temp
         4  cutoff pill — only when the stop has one
         5  water + carbs to carry
       The name cell wraps so a long stop name never crushes the crew pills
       and the controls never run off the right edge (a three-pill Leadville
       row used to push the cutoff clock past the screen). The arrival cell
       is display:contents so its cutoff can leave the ETA's line and take
       its own — inside a block it sat indented under the ETA, mid-row. Two
       invisible full-width items (::before/::after) are the line breaks; they
       are zero-height lines, so the space between lines rides on the items'
       own top margins rather than a row-gap the breaks would double. */
    #raceplan-table tr { row-gap: 0; }
    #raceplan-table tr::before { content: ""; flex: 1 1 100%; order: 5; }
    #raceplan-table tr::after { content: ""; flex: 1 1 100%; order: 7; }
    #raceplan-table td:nth-child(2), #raceplan-table .aid-eta, #raceplan-table td:nth-child(4),
    #raceplan-table .aid-cutoff, #raceplan-table .aid-dwell, #raceplan-table td:nth-child(5), #raceplan-table td:nth-child(6) { margin-top: 6px; }
    #raceplan-table td:nth-child(1) { flex: 1 1 100%; order: 1; display: flex; flex-wrap: wrap;
        align-items: center; column-gap: 6px; row-gap: 6px; font-weight: 600; }
    #raceplan-table td:nth-child(1) .aid-nm { flex: 1 1 0; min-width: 0; }
    #raceplan-table td:nth-child(1) .aid-bag { margin-left: 0; }
    #raceplan-table td:nth-child(1) .aid-actions { flex: 0 0 auto; margin-left: auto; }
    /* Renaming and removing stops is desk work — on a phone the two buttons
       cost a third of the name line. The cutoff clock stays: it is the one
       control a runner reaches for on race week, and the only way to set a
       cutoff on a stop that has none. */
    #raceplan-table .aid-edit, #raceplan-table .aid-rm { display: none; }
    #raceplan-table td:nth-child(1) .aid-crewline { flex: 1 1 100%; order: 9;
        display: flex; flex-wrap: wrap; align-items: center; column-gap: 6px; row-gap: 6px; }
    #raceplan-table .aid-crewline .aid-crew, #raceplan-table .aid-crewline .crew-io { margin-left: 0; }
    #raceplan-table td:nth-child(2) { order: 2; font-size: 0.82rem; color: var(--muted); }
    #raceplan-table td:nth-child(3) { display: contents; }
    #raceplan-table .aid-eta { order: 3; font-size: 0.82rem; color: var(--muted); }
    #raceplan-table .aid-eta::before { content: "arrive "; }
    #raceplan-table td:nth-child(4) { order: 4; font-size: 0.82rem; color: var(--muted); }
    #raceplan-table .aid-cutoff { order: 6; margin-top: 0; }
    /* The card is the full width on a phone, so the demand can take it. */
    #raceplan-table .aid-cutoff.cut-warn { max-width: 100%; }
    #raceplan-table .aid-dwell { order: 7; margin-top: 0; }
    #raceplan-table td:nth-child(5) { order: 8; }
    #raceplan-table td:nth-child(6) { order: 9; }
    /* Nothing to say, nothing shown: the "—" cells (Start's carry, a stop
       with no forecast) are noise once the column header is gone. */
    #raceplan-table td.plan-none { display: none; }
    /* The pacer's bar runs the full card, not just the name line. */
    #raceplan-table tr.leg-paced { box-shadow: inset 3px 0 0 var(--pc, var(--teal)); padding-left: 10px; }
    #raceplan-table tr.leg-paced td:first-child { box-shadow: none; }

    /* Pacing aid stations — line 1: checkpoint (edit controls right); line 2: distance · elapsed */
    #aid-table td:nth-child(1) { flex: 1 1 100%; order: 1; display: flex; align-items: center; }
    #aid-table td:nth-child(1) .aid-actions { margin-left: auto; }
    #aid-table td:nth-child(2) { order: 2; font-size: 0.85rem; color: var(--muted); }
    #aid-table td:nth-child(3) { order: 3; margin-left: auto; font-size: 0.85rem; color: var(--muted); }
    #aid-table td:nth-child(3)::before { content: "elapsed "; }

    /* Course Creator aid list — line 1: name + edit controls; line 2: distance */
    #lib-aid-table td:nth-child(1) { flex: 1 1 auto; order: 1; display: flex; align-items: center; }
    #lib-aid-table td:nth-child(3) { order: 2; margin-left: auto; }
    #lib-aid-table td:nth-child(2) { order: 3; flex: 1 1 100%; font-size: 0.85rem; color: var(--muted); }
}

/* ===== Mobile header compaction =====
   The desktop app-shell (≥861px) already trades the tall hero for a compact
   heading; phones — the least screen — were still getting the full-size one.
   Mirror it: small h1, no lead paragraph, tighter margins, so the first tool
   card lands inside the first viewport. (Action buttons like Race Day's
   "Plan a race" stay.) */
@media (max-width: 560px) {
    .hero { margin: 10px 0 16px; }
    .hero h1 { font-size: 1.5rem; line-height: 1.15; }
    .eyebrow { font-size: 0.72rem; margin-bottom: 6px; }
    .hero-sub { display: none; }
    .hero-cta { margin-top: 12px; }

    /* Panels: a touch less padding buys real column width at 375px. The
       .rd-section header band bleeds edge-to-edge via negative margins that
       must mirror the panel padding — keep them in lockstep. */
    .panel { padding: 18px; }
    .rd-section { padding-top: 14px; padding-bottom: 14px; }
    .rd-section > summary { margin: -14px -18px; padding: 13px 18px; }
    .rd-section:not([open]) > summary { margin-bottom: -14px; }
    .rd-section[open] > summary { margin-bottom: 14px; }

    /* Card headers: let the subtitle take its own line under the title instead
       of squeezing beside it ("HOW THE PACING WORKS grade-adjusted splits"). */
    .rd-section > summary { flex-wrap: wrap; row-gap: 2px; }
    .rd-section > summary .rd-sec-sub { flex: 1 1 100%; order: 10; margin-left: 35px; }
}

/* ===== Food bin: collapsible categories (details/summary, all widths) ===== */
.fp-bin-group > summary::-webkit-details-marker { display: none; }
.fp-bin-cat { list-style: none; cursor: pointer; user-select: none; }
.fp-bin-cat::after {
    content: '⌄'; margin-left: auto; color: var(--muted);
    font-size: 1rem; line-height: 1; transition: transform 0.18s ease;
}
.fp-bin-group[open] > .fp-bin-cat::after { transform: rotate(180deg); }
.fp-bin-count {
    font-size: 0.7rem; font-weight: 600; color: var(--muted);
    background: var(--glass-2); border: 1px solid var(--line);
    border-radius: var(--r-ctl); padding: 1px 8px; margin-left: 2px;
}
@media (max-width: 860px) {
    /* No scroll region inside the page scroll — the categories collapse instead. */
    .fp-bin { max-height: none; overflow: visible; padding-right: 0; }
    .fp-bin-cat { align-items: center; min-height: 44px; }
}

/* ===== Mobile pane merge (pairs with the nav.js module) ===== */
.merged-away { display: none !important; }

@media (max-width: 860px) {
    /* Stacked cards need breathing room — desktop's app-split grid gap only
       exists ≥861px, so phones were rendering the cards edge-to-edge. */
    body.split-page .app-split,
    body.split-page .split-left,
    body.split-page .split-right { display: flex; flex-direction: column; gap: 14px; }
    /* The column's own gap is the only spacing between cards. Two panels carry
       a legacy margin-bottom from the standalone fuel page (.fueling-plan and
       .coach, fuel.css above), which lands ON TOP of that gap: Fueling sat 36px
       from Gear where every other pair sat 14px. Desktop already zeroes these
       the same way a few blocks up; this is the phone half of that rule. */
    body.split-page .split-left > .panel,
    body.split-page .split-right > .panel { margin: 0; }

    /* A display-card body merged into its input card: divider between the
       inputs above and the map / plan / table below. */
    .rd-merged { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); }

    /* The weather explorer card adopted into Conditions: flatten from a
       full panel to a sub-section of its host card. */
    .rd-merged .rd-section.panel {
        border: none; box-shadow: none; background: transparent;
        padding: 0; border-radius: 0;
    }
    .rd-merged .rd-section > summary {
        margin: 0; padding: 2px 0 10px; background: none; border-radius: 0;
    }
    .rd-merged .rd-section:not([open]) > summary { margin-bottom: 0; }
    .rd-merged .rd-section[open] > summary { margin-bottom: 8px; border-bottom: none; }
}

/* ===== Fullscreen elevation profile (trail-map.js createProfile expand) ===== */
.tg-elev-expand { margin-left: auto; }   /* right end of the overlay toggle bar */
.elev-canvas-wrap.elev-expanded {
    position: fixed; inset: 0; z-index: 9999;
    height: auto; max-height: none;
    background: var(--bg-1, #0a1a1c);
    padding: 58px 16px 22px;
}
body.elev-modal-open { overflow: hidden; }
.tg-elev-close {
    position: absolute; top: 10px; right: 10px; z-index: 2;
    width: 44px; height: 44px; border-radius: 50%;
    background: var(--glass-2); color: var(--ink); border: 1px solid var(--line);
    font-size: 1.1rem; line-height: 1; cursor: pointer;
    display: flex; align-items: center; justify-content: center;
}
.tg-elev-close:hover { border-color: var(--edge-soft); background: var(--fill-hover); }
.tg-elev-hint {
    position: absolute; top: 22px; left: 16px; right: 70px;
    color: var(--muted); font-size: 0.82rem; display: none;
}
/* The hint only matters on a phone held upright. */
@media (orientation: portrait) and (max-width: 860px) {
    .elev-canvas-wrap.elev-expanded .tg-elev-hint { display: block; }
}

/* ===== Map feel pass: new shared controls (trail-map.js) ===== */
/* In-map toast — gesture hint, locate status. */
.tg-map-toast {
    position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
    z-index: 900; pointer-events: none;
    background: rgba(4, 12, 10, 0.82); color: var(--ink);
    border: 1px solid var(--line); border-radius: var(--r-ctl);
    padding: 10px 18px; font-size: 0.88rem; font-weight: 600; white-space: nowrap;
    opacity: 0; transition: opacity 0.25s ease;
}
.tg-map-toast.show { opacity: 1; }

/* Distance markers along the route. */
.tg-mile-wrap { background: none; border: 0; }
.tg-mile {
    display: flex; align-items: center; justify-content: center;
    width: 22px; height: 22px; border-radius: 50%;
    background: rgba(7, 18, 15, 0.88); color: var(--gold);
    border: 1.5px solid var(--gold);
    font-family: var(--mono); font-weight: 700; font-size: 0.62rem;
}
/* Touch screens: at least 24×24 (WCAG 2.2 target size); trail-map.js gives
   the Leaflet icon the same box so the badge stays centred on its mile. */
@media (pointer: coarse) {
    .tg-mile { width: 24px; height: 24px; font-size: 0.66rem; }
}

/* Tap-to-inspect popup + scale bar: dark-theme the Leaflet chrome. */
.tg-inspect .leaflet-popup-content-wrapper {
    background: rgba(7, 18, 15, 0.94); color: var(--ink);
    border: 1px solid var(--line); border-radius: var(--r-card); box-shadow: var(--shadow-pop);
}
.tg-inspect .leaflet-popup-content { margin: 9px 14px; font: 600 0.88rem/1.45 var(--body); }
.tg-inspect .leaflet-popup-content b { color: var(--gold); }
.tg-inspect .leaflet-popup-tip { background: rgba(7, 18, 15, 0.94); border: 1px solid var(--line); }
.leaflet-control-scale-line {
    background: rgba(7, 18, 15, 0.75); color: var(--muted);
    border-color: var(--line); font-size: 0.66rem;
}

/* ===== Interaction grammar (audit PR 4, re-cut by TG-282) =====
   One hover language for the whole product: interactive surfaces lift a touch
   and step the neutral ladder — never a coloured glow. Hover-capable pointers
   only; reduced motion keeps color changes but drops movement. */
@media (hover: hover) {
    details.rd-section {
        transition: border-color 0.18s ease, box-shadow 0.18s ease;
    }
    /* Sections no longer lift or glow in their tint on hover (TG-282): the
       coloured glow is gone and hover never wears a feature tint. */
    .export-btn, .estimate-btn, .rd-plan-btn, .fp-clear, .course-clear, .lib-manage, .lib-create-route {
        transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease,
            background 0.15s ease, color 0.15s ease;
    }
    /* Flat buttons lift, they don't glow — .export-btn/.rd-plan-btn keep their
       own outline hover (see the base rules). */
    .lib-create-route:hover { transform: translateY(-1px); }
    .export-btn.tonal:hover, .estimate-btn:hover, .lib-create-route:hover {
        box-shadow: var(--raise-2);
    }
    .export-btn:hover, .rd-plan-btn:hover { transform: translateY(-1px); }
}
@media (prefers-reduced-motion: reduce) {
    .export-btn:hover, .estimate-btn:hover, .rd-plan-btn:hover, .lib-create-route:hover { transform: none; }
}

/* Keyboard focus wears the one accent (TG-282). */
:where(a, button, summary, [role="button"], .fp-pill):focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Digits line up in every data surface (arrival times stop wobbling on rerender).
   One declaration site for the whole file — the mono pass (TG-284) sets the face
   on each value class and adds its selector here rather than repeating the
   property a dozen times. */
.plan-table td, .plan-table th, .cmp-table td, .cmp-table th,
.cs-val, .metric-num, .kit-num, .fp-cov-sub, .fp-pill, .fp-pct, .fp-qty,
.rd-wx-cell, .rd-wx-day-chip, .summary-text, .carry-dist, .carry-load,
.lib-item-meta, .estimate-out {
    font-variant-numeric: tabular-nums;
}

/* ===== Cross-highlighting (audit PR 5) =====
   Hovering a table row answers on the map and elevation profile — and tapping
   a map marker flashes its row. */
.aid-marker { transition: transform 0.15s ease, box-shadow 0.15s ease; }
.aid-marker-wrap { z-index: 600; }
.aid-marker-wrap.aid-hover { z-index: 900 !important; }
.aid-marker-wrap.aid-hover .aid-marker {
    transform: scale(1.45);
    /* Ink, not white: the glow has to read on First Light's light topo too. */
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--ink) 25%, transparent), 0 0 18px 2px color-mix(in srgb, var(--ink) 35%, transparent);
}
@media (hover: hover) {
    .plan-table tbody tr { cursor: default; }
}
.plan-table tbody tr.row-flash {
    animation: tg-row-flash 1.6s ease;
}
@keyframes tg-row-flash {
    0%, 60% { background: rgba(255, 210, 63, 0.18); }
    100% { background: transparent; }
}
@media (prefers-reduced-motion: reduce) {
    .aid-marker { transition: none; }
    .plan-table tbody tr.row-flash { animation: none; background: rgba(255, 210, 63, 0.14); }
}

/* ===== Depth & page transitions (audit second wave) ===== */
/* A whisper of film grain keeps the big dark fields from reading flat.
   Inline SVG turbulence — no request, ~2% opacity. */
.backdrop::after {
    content: ""; position: absolute; inset: 0; pointer-events: none;
    opacity: 0.025;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(/%23n)'/%3E%3C/svg%3E");
}

/* Cross-fade between tool pages (same-origin MPA). Free in Chromium/Safari,
   gracefully nothing elsewhere. */
@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.18s; }
@media (prefers-reduced-motion: reduce) {
    @view-transition { navigation: none; }
}

/* ===== Mini map in the left rail (course loaded, desktop) =====
   The right pane scrolls independently, so once you're down at the race plan
   the big map is gone — the mini map keeps every hover/tap answer in view.
   It lives behind the rail's "Show map" disclosure (#rd-sum-map, raceday.html)
   now that the rail's main job is the plan summary; gpx.js builds it only while
   the disclosure is open. Mobile keeps the merged full map instead (pane
   merge), so it's ≥861px only. */
.mini-map-wrap { display: none; margin-top: 4px; }

/* ===== The rail's three ways to start (TG-300, TG-320) =====
   Each way in gets a label and one line of hint, so the rail itself is the
   explanation the welcome popover used to give from on top of it. With a
   course loaded the whole block goes (TG-320): the rail is the pinned map
   then, the topbar search switches courses, and Clear course brings the
   three ways back. The head swaps from "Run setup" to the course name in the
   same stroke. display: contents keeps the rows as the rail's own flex items,
   so its gap spaces them exactly as before the wrapper existed. */
.rd-start { display: contents; }
.rd-start-row { display: flex; flex-direction: column; gap: 6px; }
.rd-start-hint { color: var(--muted); font-size: 0.82rem; line-height: 1.45; margin: 0; }
/* The browse link moved inside the search row, so it is spaced by that row's
   gap rather than by the rail's old negative-margin pull. */
.rd-start-row > .creator-note { margin: 0; }
.rd-start-wiz #rd-start-wizard { width: 100%; }
body.has-course .rd-start { display: none; }
.rd-rail-course { display: none; }
body.has-course .rd-rail-setup { display: none; }
body.has-course .rd-rail-course { display: flex; }
/* The browse button stays visible with a course loaded — switching is the point. */
.tg-browse-btn { background: none; border: none; padding: 0; font: inherit; cursor: pointer; }
@media (min-width: 861px) {
    body.has-course .mini-map-wrap { display: block; }
    /* Sized for a glance under the summary, not for the whole rail. */
    #mini-map { height: clamp(200px, 28vh, 360px); }
}
.map-wrap.map-expanded #mini-map { height: 100vh; height: 100dvh; }

/* ===== Mini-map aid dots =====
   Full 26px "A" badges bury the route at mini-map size — render them as small
   colored dots that grow into the badge when their row is hovered (.aid-hover
   comes from the cross-highlighting fan-out). */
.aid-marker-wrap.aid-mini { display: flex; align-items: center; justify-content: center; }
.aid-mini .aid-marker {
    width: 11px; height: 11px; font-size: 0; border-width: 1.5px;
    transition: width 0.15s ease, height 0.15s ease, font-size 0.1s ease 0.05s,
        transform 0.15s ease, box-shadow 0.15s ease;
}
.aid-mini.aid-hover .aid-marker {
    width: 26px; height: 26px; font-size: 0.92rem;
    transform: scale(1.1);   /* the base .aid-hover scale(1.45) is too much on top of the grow */
}
@media (prefers-reduced-motion: reduce) {
    .aid-mini .aid-marker { transition: none; }
}


/* ===== Full-height Course card (Race Day) =====
   The Course card is the ONLY left card, so the pane doesn't scroll — the
   card scales to the screen instead. With no course loaded the dropzone grows
   to fill it; with one loaded the plan summary (raceday.css) sits at natural
   height and the optional mini map below it is clamp-sized. overflow-y:auto
   on the pane remains as a safety net for very short windows only. */
@media (min-width: 861px) {
    body.split-page .split-left > #rd-course[open] {
        flex: 1 1 auto; min-height: 0;
        display: flex; flex-direction: column;
    }
    /* Chrome wraps a details' children in an internal ::details-content box —
       the flex above only splits [summary | content box], so the content box
       itself must flex-fill and lay its children out as a column too. Kept as
       its own rule: browsers without the pseudo drop just this block. */
    body.split-page .split-left > #rd-course[open]::details-content {
        display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;
    }
    body.has-course .mini-elev-wrap { display: block; }
    body.split-page:not(.has-course) .split-left #rd-course .dropzone { flex: 1 1 auto; }
}
/* Mini elevation profile under the mini map. */
.mini-elev-wrap { display: none; margin-top: 10px; }
.mini-elev-wrap[hidden] { display: none; }
.mini-elev-wrap .elev-canvas-wrap { height: 140px; }

/* Goal inputs at the top of the Pacing plan panel (the left card is retired). */
.pace-goal-row { display: flex; flex-wrap: wrap; gap: 12px 28px; align-items: flex-end;
    margin: 2px 0 10px; }
.pace-goal-row .field-block { margin: 0; }

/* ===== The rail slides away (TG-320, desktop) =====
   The drag handle that used to sit between the panes is gone: a runner who
   wants the plan full-width hides the rail instead. html.rd-rail-closed is
   set before first paint by the inline script in raceday.html's head and kept
   honest by raceday.js — never without a course loaded. The column animates
   between two minmax() tracks (the same shape at both ends is what lets the
   grid interpolate it) while the rail fades and slips left under it. The seam
   and its padding go too, or a 0px column would still show 19px of them. */
@media (min-width: 861px) {
    body.split-page .app-split { transition: grid-template-columns 0.2s ease, gap 0.2s ease; }
    html.rd-rail-closed body.split-page .app-split { grid-template-columns: minmax(0px, 0px) 1fr; gap: 0; }
    body.split-page .split-left {
        min-width: 0; overflow-x: hidden;
        transition: opacity 0.2s ease, transform 0.2s ease, padding-right 0.2s ease, border-color 0.2s ease, visibility 0s linear 0s;
    }
    html.rd-rail-closed body.split-page .split-left {
        opacity: 0; transform: translateX(-24px); visibility: hidden; pointer-events: none;
        padding-right: 0; border-right-color: transparent;
        transition-delay: 0s, 0s, 0s, 0s, 0.2s;
    }
}
@media (prefers-reduced-motion: reduce) {
    body.split-page .app-split, body.split-page .split-left { transition: none; }
}

/* ===== Compact conditions controls (Weather card) =====
   The adopted inputs read as one toolbar row, not a stacked form — start
   time + fetch, temp, humidity and acclimation wrap side by side. */
#wx-conditions .effort-col { flex-direction: row; flex-wrap: wrap; align-items: flex-end; gap: 12px 22px; }
#wx-conditions .effort-col > * + * { margin-top: 0; }
#wx-conditions .field-block { display: flex; flex-direction: column; gap: 6px; margin: 0; }
#wx-conditions .weather-row { flex-wrap: nowrap; gap: 8px; }
#wx-conditions .weather-row input { flex: 0 1 auto; width: 205px; padding: 8px 10px; }
#wx-conditions .estimate-btn { padding: 8px 12px; font-size: 0.84rem; }
#wx-conditions .field-grid { display: flex; gap: 12px; }
#wx-conditions .field-grid .field { gap: 6px; }
#wx-conditions .field-grid .field input { width: 88px; padding: 8px 10px; }
#wx-conditions .segmented button { flex: 0 0 auto; padding: 7px 14px; font-size: 0.8rem; }
/* The estimate line only earns space when it has something to say. */
#wx-conditions .weather-out { margin: 0; min-height: 0; }
#wx-conditions .weather-out:empty { display: none; }

/* Aid-station rename icon (icons.js). */
.aid-ico { width: 13px; height: 13px; vertical-align: -0.1em; }

/* ===== Upgrade dialog (billing) — flat outline cards, brand rules ===== */
.tg-upg-opts { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 14px 0 4px; }
.tg-upg-opt { display: flex; flex-direction: column; gap: 4px; align-items: flex-start; text-align: left;
    padding: 14px; background: transparent; color: var(--ink); font: inherit; cursor: pointer;
    border: 1px solid var(--line); border-radius: var(--r-card); transition: border-color .15s, box-shadow .15s; }
.tg-upg-opt:hover { border-color: var(--edge); background: var(--fill-hover); }
.tg-upg-opt b { font-family: var(--mono); letter-spacing: .02em; }
.tg-upg-price { color: var(--accent); font-weight: 700; font-size: 1.15rem; }
.tg-upg-opt small { color: var(--muted); line-height: 1.4; }
.tg-upg-note { color: var(--muted); font-size: .84rem; margin: 10px 2px 0; }
.tg-upg-note a { color: var(--accent); }
@media (max-width: 520px) { .tg-upg-opts { grid-template-columns: 1fr; } }

/* ===== Aid stations edited in place (planner-5) =====
   gpx.js: a grip to drag (or Alt+↑/↓), the name and the mile as click
   targets that open an inline field, and a type chip set per stop. The
   chips draw their word from data-t so the cell's text stays the name.
   One accent on duty: a chip that is on, the field that is open, the
   line a dragged row will land on. */
#raceplan-table .aid-grip {
    display: inline-flex; align-items: center; justify-content: center; vertical-align: middle;
    width: 20px; height: 28px; margin: 0 4px 0 -4px; border-radius: var(--r-ctl);
    color: var(--muted); cursor: grab; touch-action: none; opacity: 0.55;
    transition: opacity var(--dur-ctl) var(--ease-snap), background var(--dur-ctl) var(--ease-snap);
}
#raceplan-table .aid-grip svg { width: 16px; height: 16px; fill: currentColor; }
#raceplan-table tr:hover .aid-grip, #raceplan-table .aid-grip:focus-visible { opacity: 1; }
#raceplan-table .aid-grip:hover { background: var(--fill-hover); color: var(--ink); }
#raceplan-table .aid-grip:focus-visible,
#raceplan-table .aid-nm[role="button"]:focus-visible,
#raceplan-table .aid-mi:focus-visible,
#raceplan-table .aid-type:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#raceplan-table .aid-nm[role="button"], #raceplan-table .aid-mi { cursor: text; border-radius: 4px; }
#raceplan-table .aid-nm[role="button"]:hover, #raceplan-table .aid-mi:hover {
    background: var(--fill-hover); box-shadow: 0 0 0 3px var(--fill-hover); }
#raceplan-table .aid-inline {
    font: inherit; color: var(--ink); background: var(--bg-well);
    border: 1px solid var(--accent); border-radius: var(--r-ctl); padding: 3px 7px; min-height: 32px;
    width: min(220px, 100%);
}
#raceplan-table .aid-inline-mile { width: 7ch; font-family: var(--mono); font-variant-numeric: tabular-nums; }
#raceplan-table .aid-inline:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
#raceplan-table tr.aid-dragging { opacity: 0.55; }
body.aid-drag-on { user-select: none; -webkit-user-select: none; cursor: grabbing; }
#raceplan-table tr.aid-drop-before td { box-shadow: inset 0 2px 0 var(--accent); }
#raceplan-table tr.aid-drop-after td { box-shadow: inset 0 -2px 0 var(--accent); }
#raceplan-table .aid-types { display: inline-flex; flex-wrap: wrap; gap: 3px; margin-left: 8px; vertical-align: middle; }
#raceplan-table .aid-type {
    min-height: 22px; padding: 0 7px; border-radius: var(--r-ctl);
    border: 1px dashed var(--line); background: none; color: var(--muted); cursor: pointer;
    font: 600 0.68rem/1 var(--body); letter-spacing: 0.02em;
    transition: background var(--dur-ctl) var(--ease-snap), color var(--dur-ctl) var(--ease-snap), border-color var(--dur-ctl) var(--ease-snap);
}
#raceplan-table .aid-type::before { content: attr(data-t); }
#raceplan-table .aid-type:hover { color: var(--ink); border-color: var(--edge-soft); }
#raceplan-table .aid-type.on {
    border-style: solid; border-color: color-mix(in srgb, var(--accent) 45%, transparent);
    color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent);
}
/* Quiet until wanted: the chips that are off show on the row's hover, while
   it is being edited or keyboard-focused, and always where there is no hover. */
@media (hover: hover) {
    #raceplan-table .aid-type:not(.on) { display: none; }
    #raceplan-table tr:hover .aid-type, #raceplan-table tr:focus-within .aid-type,
    #raceplan-table tr.aid-editing .aid-type { display: inline-block; }
}
.aid-paste-link { margin: 10px 0 0; font-size: 0.85rem; color: var(--muted); }
.aid-paste-link a { color: var(--accent); }
@media (max-width: 600px) {
    #raceplan-table td:nth-child(1) .aid-types { flex: 1 1 100%; order: 10; margin: 6px 0 0; }
    #raceplan-table .aid-type { min-height: 44px; min-width: 44px; padding: 0 10px; }
    #raceplan-table .aid-grip { width: 32px; height: 44px; opacity: 0.8; }
}
@media (prefers-reduced-motion: reduce) {
    #raceplan-table .aid-grip, #raceplan-table .aid-type { transition: none; }
}

/* /course.css */
/* Course pages (/courses + /course/{slug}) — the SEO landing pages (KRI-61).
   Rides on fuel.css tokens; only page-shape rules live here. */

.cp-wrap { max-width: 1040px; margin: 0 auto; padding: 24px 18px 64px; }

.cp-crumbs { display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
    font-size: .82rem; color: var(--muted); margin: 6px 0 18px; }
.cp-crumbs a { color: var(--muted); text-decoration: none; }
.cp-crumbs a:hover { color: var(--ink); }

.cp-hero { position: relative; }
.cp-hero-inner { max-width: 1040px; margin: 0 auto; padding: 24px 18px 0; }
.cp-hero h1 { font-family: var(--display); font-weight: 800; font-size: clamp(1.6rem, 4vw, 2.4rem);
    line-height: 1.15; margin: 0 0 8px; }
/* ---- With a flythrough on file: a full-bleed band under the topbar ---- */
.cp-hero-fly { overflow: hidden; display: grid; align-items: end;
    min-height: max(480px, 68svh); background: var(--bg-0); border-bottom: 1px solid var(--line); }
.cp-hero-fly.hero-still { background: var(--bg-0) var(--cp-poster) center / cover no-repeat; }
.cp-hero-fly .hero-video { position: absolute; inset: -1px; width: calc(100% + 2px); height: calc(100% + 2px); object-fit: cover; }
.cp-hero-fly.hero-still .hero-video { display: none; }
.cp-hero-fly .hero-scrim { position: absolute; inset: 0; pointer-events: none;
    background: linear-gradient(180deg, color-mix(in srgb, var(--bg-0) 30%, transparent) 0%, transparent 30%,
        color-mix(in srgb, var(--bg-0) 55%, transparent) 65%, color-mix(in srgb, var(--bg-0) 92%, transparent) 100%); }
.cp-hero-fly .cp-hero-inner { position: relative; z-index: 1; width: 100%; padding: 120px 18px 28px; box-sizing: border-box; }
.cp-hero-fly h1 { font-size: clamp(1.9rem, 5vw, 3.2rem); letter-spacing: -0.015em; text-wrap: balance; }
.cp-hero-fly .cp-loc { color: var(--ink); opacity: .85; }
.cp-hero-fly .cp-ctas { margin-bottom: 0; }
.cp-hero-cap { position: absolute; right: 18px; top: 14px; z-index: 1; font-family: var(--mono); font-size: .7rem;
    letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
@media (max-width: 640px) {
    .cp-hero-fly { min-height: max(440px, 62svh); }
    .cp-hero-fly .cp-hero-inner { padding-top: 90px; }
}
.cp-loc { color: var(--muted); margin: 0 0 16px; max-width: 720px; }
.cp-ctas { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 22px; }

.cp-panel { padding: 18px; margin-bottom: 22px; }
.cp-panel h2 { font-family: var(--display); font-size: 1.1rem; margin: 0 0 10px; }

/* rd-section cards (the Run Planner's accent cards, from fuel.css) on this page:
   space them out, give their bodies breathing room, and keep the elevation
   toggle bar from crowding the map's bottom edge. */
.cp-wrap .rd-section { margin-bottom: 22px; }
.cp-body { padding-top: 18px; }
.cp-body .course-stats { margin-top: 0; }
.cp-body .map-wrap { margin-bottom: 18px; }
.cp-body .tg-elev-toggles { margin: 0 0 14px; }
/* Rotation insurance: the chart resizes on its own observer; until it does,
   its canvas must never widen the page. */
.cp-body .elev-canvas-wrap { max-width: 100%; overflow-x: hidden; }
.cp-about-text { color: var(--ink); line-height: 1.55; margin: 0 0 10px; max-width: 75ch; }

.cp-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 10px; margin-bottom: 14px; }
.cp-stat { border: 1px solid var(--line); border-radius: var(--r-card); padding: 10px 12px; }
.cp-stat b { display: block; font-family: var(--mono); font-variant-numeric: tabular-nums;
    font-weight: 700; font-size: 1.12rem; }
.cp-stat span { color: var(--muted); font-family: var(--mono); font-weight: 500; font-size: .72rem;
    letter-spacing: .1em; text-transform: uppercase; }
.cp-stat small { display: block; color: var(--muted); font-family: var(--mono);
    font-variant-numeric: tabular-nums; font-size: .72rem; }

/* Both server-rendered map pages: the race course page and, since TG-241, a
   community route's own page. Height has to be set here — Leaflet renders into
   a 0px box otherwise, and the map simply doesn't appear. */
#course-map, #route-map { height: 380px; border-radius: var(--r-card); }

/* Map states: a map-shaped skeleton while the course JSON loads (or the route
   draws) and a one-line error with Retry when it can't, in place of the blank
   the map area used to be. The page script sets data-map-state on .cp-map
   (loading → ready | error); the overlays sit above Leaflet's controls
   (z-index 1000) so nothing half-drawn shows through. Tokens only: the
   shimmer is the well with a pass of the hover fill. */
.cp-map-state { position: absolute; inset: 0; z-index: 1100; display: none; place-items: center;
    text-align: center; padding: 16px; background: var(--bg-well); color: var(--ink);
    border-radius: var(--r-card); }
.cp-map[data-map-state="loading"] .cp-map-loading,
.cp-map[data-map-state="error"] .cp-map-error { display: grid; }
.cp-map-loading { pointer-events: none; }
.cp-map-skel { position: absolute; inset: 0; opacity: .7;
    background: linear-gradient(90deg, transparent 25%, var(--fill-hover) 50%, transparent 75%);
    background-size: 200% 100%; animation: cp-map-shimmer 1.3s ease-in-out infinite; }
.cp-map-msg { position: relative; font-family: var(--mono); font-size: var(--mono-cap);
    letter-spacing: .06em; color: var(--muted); }
.cp-map-error { gap: 4px; align-content: center; font-size: .9rem; }
.cp-map-error b { display: block; font-weight: 700; }
/* Status, not decoration: the failure dot is the --bad token (#541). */
.cp-map-error b::before { content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 8px;
    border-radius: 50%; background: var(--bad); vertical-align: .08em; }
.cp-map-error span { display: block; color: var(--muted); font-size: .86rem; }
.cp-map-error .export-btn { margin-top: 8px; min-height: 44px; }
.cp-map-error .export-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The profile canvas only draws once the course has; until then (and when
   it never does) the empty 190px strip under the map is just more blank. */
.cp-map:not([data-map-state="ready"]) ~ .cp-elev { display: none; }
@keyframes cp-map-shimmer { 0% { background-position: 180% 0; } 100% { background-position: -80% 0; } }
@media (prefers-reduced-motion: reduce) { .cp-map-skel { animation: none; } }
/* The dot loader (tg-field.js): the course's profile gathering out of dust, in
   place of the shimmer. The message stays underneath as the live status. */
.tg-field-loader { position: absolute; inset: 0; width: 100%; height: 100%; display: block; transition: opacity .4s ease; }
.tg-field-loader.out { opacity: 0; }
.cp-map-loading.has-field .cp-map-skel { display: none; }
.cp-map-loading.has-field .cp-map-msg { align-self: end; margin-bottom: 14px; }
.cp-elev { margin-top: 12px; }

.cp-aid-table { width: 100%; border-collapse: collapse; font-size: .88rem; }
.cp-aid-table th, .cp-aid-table td { text-align: left; padding: 7px 10px;
    border-bottom: 1px solid var(--line); }
.cp-aid-table th { color: var(--muted); font-family: var(--mono); font-weight: 500; font-size: .72rem;
    text-transform: uppercase; letter-spacing: .1em; }
.cp-aid-table td:nth-child(2), .cp-aid-table td:nth-child(3),
.cp-aid-table th:nth-child(2), .cp-aid-table th:nth-child(3) { text-align: right; }
.cp-aid-table td:nth-child(2), .cp-aid-table td:nth-child(3) {
    font-family: var(--mono); font-variant-numeric: tabular-nums; }

.cp-about p { color: var(--ink); line-height: 1.55; margin: 0 0 10px; }
.cp-note { color: var(--muted); font-size: .86rem; }
.cp-note a { color: var(--accent); }
/* The embed action appears twice on a course page — an <a> in the aid section
   and a <button> in the about section — and must read as ONE treatment
   (KRI-220). fuel.css's .inline-link supplies it; this only outranks the
   .cp-note a gold above, which would otherwise win on specificity. */
.cp-note a.inline-link { color: var(--accent); text-decoration: none; }
.cp-note a.inline-link:hover { text-decoration: underline; }

/* Send-to-RD (runner-as-outreach): bordered-neutral buttons (TG-282). */
.cp-rd-send { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 14px; }
.cp-rd-send-label { color: var(--muted); font-size: .86rem; }
.cp-btn { display: inline-flex; align-items: center; gap: 7px; padding: 8px 14px;
    background: var(--fill-idle); color: var(--ink); font: inherit; font-size: .88rem; font-weight: 600;
    border: 1px solid var(--edge); border-radius: var(--r-ctl); cursor: pointer;
    text-decoration: none; transition: border-color .15s, background .15s; }
.cp-btn:hover { background: var(--fill-hover); }
.cp-btn .ico { width: 15px; height: 15px; }


.cp-more ul { list-style: none; margin: 0; padding: 0; display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 8px; }
.cp-more a { display: block; border: 1px solid var(--line); border-radius: var(--r-card);
    padding: 10px 12px; color: var(--ink); text-decoration: none; font-size: .9rem; }
.cp-more a:hover { border-color: var(--edge-soft); background: var(--fill-hover); }
.cp-more a small { display: block; color: var(--muted); margin-top: 2px; }

/* /courses hub — country groups of course links */
.cp-group { margin-bottom: 26px; }
.cp-group h2 { font-family: var(--display); font-size: 1.05rem; margin: 0 0 10px;
    color: var(--gold); }
.cp-group ul { list-style: none; margin: 0; padding: 0; display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 8px; }
/* Each tile carries an --acc from its DISTANCE BAND (server-set), so the wall
   of 220 courses reads as a legend at a glance instead of a page of white
   boxes. Flat accent edge + a whisper of tint — never a filled card. */
.cp-group li { --acc: var(--teal); }
.cp-group a { display: block; border: 1px solid var(--line);
    border-left: 3px solid color-mix(in srgb, var(--acc) 62%, transparent);
    border-radius: var(--r-card); padding: 10px 12px 10px 11px;
    background: color-mix(in srgb, var(--acc) 5%, var(--glass, transparent));
    color: var(--ink); text-decoration: none; font-size: .9rem;
    transition: border-color .16s ease, transform .16s ease, background .16s ease; }
.cp-group a:hover { border-color: var(--acc); transform: translateY(-2px);
    background: color-mix(in srgb, var(--acc) 11%, var(--glass, transparent)); }
.cp-group a small { display: flex; flex-wrap: wrap; align-items: center; gap: 0 6px;
    color: var(--muted); margin-top: 3px; }
/* The band label doubles as the colour's key on every tile. */
.cp-band { margin-left: auto; padding: 1px 7px; border-radius: var(--r-ctl);
    font-size: .72rem; font-weight: 600; color: var(--acc);
    border: 1px solid color-mix(in srgb, var(--acc) 40%, transparent); }

/* Surface mix on a community tile (TG-238) — the Surface stat card's bar and
   palette (fuel.css .cs-mix/.sfx-*, loaded on this page) shrunk to fit a meta
   line. Same colours and same ordering, so a route reads identically here and
   on its course page. */
.cp-surf { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
    margin-left: 2px; }
.cp-surf-bar { display: inline-flex; width: 34px; height: 4px;
    border-radius: 3px; overflow: hidden; }
.cp-surf-bar i { display: block; min-width: 1px; }

/* A community tile carries two destinations (TG-241): the card opens the
   route's own page, and a footer strip opens it in the Run Planner. Anchors
   can't nest, so they are siblings in a flex column — the card grows to fill
   the grid cell and the strip sits under it, so neither can overlap the other
   however the meta line wraps. Both selectors are qualified with .cp-group
   because the plain `.cp-group a` card rule above out-specifies a bare class.
   Flat orange text, no fill: brand rule. */
.cp-group li.cp-comm { display: flex; flex-direction: column; }
.cp-group li.cp-comm > a.cp-comm-card { flex: 1 1 auto; border-radius: var(--r-card) var(--r-card) 0 0; }
/* TG-70 put a second link in the strip, so the STRIP carries the card styling
   and the two links inside it are plain text. Left as two bordered anchors
   they read as two chips with a gap, which breaks the one-tile-one-card look
   the accent edge exists to create. The planner link keeps the weight it had;
   Report rides at the far end, muted until hovered — a rare action that has to
   be findable without competing with the primary one. */
.cp-group li.cp-comm > .cp-tile-foot { display: flex; align-items: center;
    justify-content: space-between; gap: 8px; margin-top: -1px;
    border: 1px solid var(--line);
    border-left: 3px solid color-mix(in srgb, var(--acc) 62%, transparent);
    border-radius: 0 0 12px 12px;
    background: color-mix(in srgb, var(--acc) 5%, var(--glass, transparent)); }
.cp-group li.cp-comm .cp-tile-plan,
.cp-group li.cp-comm .cp-tile-report { border: 0; background: none; border-radius: 0; }
.cp-group li.cp-comm .cp-tile-plan { padding: 7px 0 8px 11px;
    font-size: .78rem; font-weight: 600; color: var(--accent); }
.cp-group li.cp-comm .cp-tile-report { padding: 7px 12px 8px 0;
    font-size: .72rem; color: var(--muted); }
.cp-group li.cp-comm .cp-tile-report:hover { color: var(--accent); }
/* The card's lift would peel the two halves apart — they move together or not
   at all, and the border/background hover still marks the target. */
.cp-group li.cp-comm > a:hover { transform: none; }

/* --- Filter toolbar (search + distance chips) --- */
.cp-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 0 0 20px; }
.cp-search-wrap { position: relative; display: flex; align-items: center; flex: 1 1 260px; }
.cp-search-wrap .ico { position: absolute; left: 12px; width: 15px; height: 15px;
    color: var(--muted); pointer-events: none; }
.cp-search-wrap input { width: 100%; padding: 10px 12px 10px 34px;
    background: var(--glass); border: 1px solid var(--line); border-radius: var(--r-card);
    color: var(--ink); font: 500 .95rem/1.2 var(--body); }
.cp-search-wrap input:focus { outline: none; border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--ring); }
.cp-search-wrap input::-webkit-search-cancel-button { filter: invert(0.6); }
.cp-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.cp-chip { display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
    padding: 7px 11px; border-radius: var(--r-ctl); background: transparent;
    border: 1px solid var(--line); color: var(--muted);
    font: 600 .8rem/1 var(--body); transition: border-color .16s ease, color .16s ease; }
.cp-chip i { width: 8px; height: 8px; border-radius: 50%; background: var(--acc); }
.cp-chip:hover { color: var(--ink); border-color: color-mix(in srgb, var(--acc) 45%, transparent); }
.cp-chip.on { color: var(--acc); border-color: color-mix(in srgb, var(--acc) 60%, transparent);
    background: color-mix(in srgb, var(--acc) 10%, transparent); }
/* The source switch (Official · Community · All) is fuel.css's .segmented,
   the same control /discover's layer switch wears: one question, one control,
   on the neutral ladder (fill-selected + --accent text for the one that's on).
   It used to wear the "you are here" ring, which is the nav's — a page's own
   filter is not a place you are. Distance chips keep .on above — several can
   be on at once. */
.cp-seg { gap: 2px; }
.cp-seg button { display: inline-flex; align-items: center; gap: 5px;
    font: 600 .8rem/1 var(--body); padding: 8px 12px; color: var(--muted);
    transition: color var(--dur-ctl) var(--ease-snap), background var(--dur-ctl) var(--ease-snap); }
.cp-seg button:hover { color: var(--ink); }
.cp-seg button.active { background: var(--fill-selected); color: var(--accent); }
.cp-seg button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.cp-seg-n { font: 500 .72rem/1 var(--mono); font-variant-numeric: tabular-nums;
    color: var(--muted); opacity: .85; }
.cp-seg-n::before { content: '· '; }
.cp-seg-n:empty { display: none; }
.cp-seg button.active .cp-seg-n { color: inherit; }
.cp-shield { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2;
    stroke-linecap: round; stroke-linejoin: round; }
.cp-chip-n { color: var(--muted); font-weight: 500; font-size: .75rem; }
/* Official / Community is the switch that decides what the whole page shows,
   and at ~29px it was under a thumb's reach for the entire touch range — not
   just the 640px one the sizing block below covers. Height by padding; the
   label size is untouched (TG-301). */
@media (max-width: 860px) {
    .cp-chip { min-height: 40px; }
    .cp-seg button { min-height: 40px; }
}
.cp-chip.on .cp-chip-n { color: inherit; opacity: .8; }
.cp-count { flex-basis: 100%; margin: 0; color: var(--muted); font-size: .84rem; }
.cp-count-on { color: var(--accent); }
.cp-empty { color: var(--muted); text-align: center; padding: 28px 0; }

@media (max-width: 640px) {
    .cp-tools { gap: 8px; }
    .cp-chips { gap: 5px; }
    .cp-chip { padding: 6px 9px; font-size: .76rem; }
}

/* What "official" earns, on every catalog tile: a small shield after the
   name, with the reason on hover (data-tip, via tg-tips.js). The server still
   renders the ✓ for an RD-verified course (seo.py); courses-filter.js turns
   that glyph into the shield and adds a plain one to the rest, so a JS-less
   crawl keeps the check and a runner sees one consistent mark. Accent on the
   verified shield only — that is the one that carries a claim. */
.cp-verified { color: var(--fern, #3ad17f); font-weight: 700; }
.cp-official { display: inline-flex; align-items: center; vertical-align: -2px;
    margin-left: 6px; color: var(--muted); font-weight: 400; cursor: help; }
.cp-official.cp-verified { color: var(--accent); }
.cp-official .cp-shield { width: 14px; height: 14px; }
.cp-official:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }

/* ---- Reviews (TG-276) ------------------------------------------------
   Server-rendered on /course/{slug} and /route/{id}/{slug}. The panel is an
   rd-section like every other block on these pages and owns the plum accent
   (KRI-119: one hue per section; --aqua/--gold are taken here and orange is
   the runner card's). Stars, meters and chips are SVG and CSS — no emoji. */

.rv-rollup { display: grid; gap: 16px; padding-bottom: 16px;
    border-bottom: 1px solid var(--line); margin-bottom: 16px; }
.rv-score { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.rv-score > b { font: 700 1.9rem/1 var(--mono); font-variant-numeric: tabular-nums; color: var(--ink); }
.rv-count { color: var(--muted); font-size: .84rem; }

.rv-stars { display: inline-flex; gap: 2px; }
.rv-star { width: 17px; height: 17px; }
/* Filled from the accent, empty from the rule colour — the same star outline
   either way, so a 3.5 reads as three and a half of the SAME shape. */
.rv-star path { fill: var(--line); stroke: none; }
.rv-full path { fill: var(--acc); }
/* A half star is one star at half weight, not half a star drawn — the shape
   stays whole so a row of five always reads as five. */
.rv-half path { fill: color-mix(in srgb, var(--acc) 55%, var(--line)); }

.rv-meters { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; }
.rv-meter-top { display: flex; justify-content: space-between; align-items: baseline;
    font-size: .82rem; color: var(--muted); }
.rv-meter-top b { color: var(--ink); font-size: .95rem; }
.rv-meter-bar { height: 6px; border-radius: 999px; background: var(--line); margin: 5px 0 4px; }
.rv-meter-bar i { display: block; height: 100%; border-radius: 999px; background: var(--acc); }
.rv-meter-ends { display: flex; justify-content: space-between; gap: 10px;
    font-size: .7rem; color: var(--muted); line-height: 1.25; }
.rv-meter-ends span:last-child { text-align: right; }

.rv-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.rv-chip { display: inline-flex; align-items: center; gap: 5px; padding: 5px 10px;
    border-radius: var(--r-ctl); border: 1px solid var(--line); color: var(--muted);
    font: 600 .76rem/1 var(--body); }
.rv-chip b { color: var(--acc); font-weight: 700; }

.rv-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 18px; }
.rv-item { padding-bottom: 18px; border-bottom: 1px solid var(--line); }
.rv-item:last-child { padding-bottom: 0; border-bottom: 0; }
.rv-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.rv-who { font-weight: 700; color: var(--ink); }
.rv-meta { display: flex; flex-wrap: wrap; gap: 6px 12px; margin: 4px 0 8px;
    font-size: .8rem; color: var(--muted); }
.rv-outcome { color: var(--acc); font-weight: 600; }
.rv-body { margin: 8px 0 0; white-space: pre-wrap; }
.rv-aid { margin: 8px 0 0; font-size: .9rem; }
.rv-aid-label { color: var(--muted); font-family: var(--mono); font-weight: 500; font-size: .72rem;
    text-transform: uppercase; letter-spacing: .1em; margin-right: 6px; }
.rv-sliders { margin-top: 8px; font-size: .76rem; color: var(--muted); }
.rv-empty { text-align: center; padding: 20px 0; }

@media (max-width: 640px) {
    .rv-meters { grid-template-columns: 1fr; }
    .rv-score > b { font-size: 1.6rem; }
}

/* ---- Rating badge on browse surfaces (TG-277) ------------------------
   The stars glyph is TG-276's (.rv-stars/.rv-star), reused so a course reads
   the same on a tile as on its page. The FILL is pinned here rather than
   inherited: on these tiles --acc is the distance band, which carries
   information, so a 100-miler's stars would come out coral and a 50K's teal.
   One neutral gold everywhere instead. */
.cp-rating { display: inline-flex; align-items: center; gap: 5px; margin-left: 7px;
    vertical-align: 1px; }
.cp-rating .rv-star { width: 13px; height: 13px; }
.cp-rating .rv-star path { fill: var(--line); }
.cp-rating .rv-full path { fill: var(--gold); }
.cp-rating .rv-half path { fill: color-mix(in srgb, var(--gold) 55%, var(--line)); }
.cp-rating-n { color: var(--muted); font-size: .74rem; font-weight: 600; }

/* ---- The review form (TG-280) ---------------------------------------
   Mobile-first: every control is a tap target at 375px, and the only typing
   is the write-up. Buttons are flat orange text+outline per the brand rules;
   stars are the same SVG the rendered reviews use. */

.rv-form-mount { margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--line); }
.rv-form { display: grid; gap: 16px; }
.rv-f-head { font: 700 1rem/1.2 var(--display); color: var(--ink); }
.rv-signedout { gap: 10px; justify-items: start; }

.rv-f-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.rv-f-stack { display: grid; gap: 8px; }
.rv-f-label { color: var(--muted); font-size: .82rem; font-weight: 600; }
.rv-f-label i { font-style: normal; font-weight: 400; opacity: .8; }

/* Stars: 40px targets, which is the smallest a thumb reliably hits. */
.rv-stars-pick { display: inline-flex; gap: 2px; }
.rv-star-btn { background: none; border: 0; padding: 6px; cursor: pointer; line-height: 0; }
.rv-star-btn .rv-star { width: 26px; height: 26px; }
.rv-star-btn .rv-star path { fill: var(--line); transition: fill .12s ease; }
.rv-star-btn.on .rv-star path { fill: var(--gold); }
.rv-star-btn[disabled] { cursor: default; }

.rv-f-sliders { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 18px; }
.rv-f-slider label { display: flex; justify-content: space-between; align-items: baseline;
    color: var(--muted); font-size: .82rem; font-weight: 600; }
.rv-f-slider label b { color: var(--ink); font-size: .95rem; }
.rv-f-slider input[type="range"] { width: 100%; margin: 6px 0 4px; accent-color: var(--acc);
    height: 28px; }
.rv-f-anchors { display: flex; justify-content: space-between; gap: 8px;
    font-size: .68rem; color: var(--muted); line-height: 1.25; }
.rv-f-anchors span { flex: 1; }
.rv-f-anchors span:nth-child(2) { text-align: center; }
.rv-f-anchors span:last-child { text-align: right; }

.rv-f-bucket { display: grid; gap: 6px; }
.rv-f-bucket-name { color: var(--muted); font-family: var(--mono); font-size: .7rem; font-weight: 500;
    text-transform: uppercase; letter-spacing: .1em; }
.rv-f-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.rv-f-chip { background: none; cursor: pointer; padding: 9px 13px; border-radius: var(--r-ctl);
    border: 1px solid var(--line); color: var(--muted);
    font: 600 .78rem/1 var(--body); transition: border-color .16s ease, color .16s ease; }
.rv-f-chip:hover { color: var(--ink); }
.rv-f-chip.on { color: var(--acc); border-color: color-mix(in srgb, var(--acc) 60%, transparent);
    background: color-mix(in srgb, var(--acc) 10%, transparent); }

.rv-form select, .rv-form input[type="text"], .rv-form textarea {
    background: var(--glass-2); border: 1px solid var(--line); border-radius: 10px;
    color: var(--ink); font-family: inherit; font-size: .92rem; padding: 9px 12px; }
.rv-form select { min-height: 40px; }
.rv-form input[type="text"] { flex: 1 1 220px; min-width: 0; }
.rv-f-field { display: grid; gap: 6px; }
.rv-f-field label { color: var(--muted); font-size: .82rem; font-weight: 600; }
.rv-f-field textarea { width: 100%; resize: vertical; }
.rv-f-count { color: var(--muted); font-size: .72rem; justify-self: end; }
.rv-f-count.short { color: var(--gold); }

.rv-f-error { margin: 0; color: var(--coral, #ff5d73); font-size: .84rem; }
.rv-f-error[hidden] { display: none; }
.rv-f-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.rv-f-actions .export-btn[disabled] { opacity: .45; cursor: not-allowed; }

@media (max-width: 640px) {
    .rv-f-sliders { grid-template-columns: 1fr; }
    .rv-f-row { align-items: flex-start; }
    .rv-form input[type="text"] { flex-basis: 100%; }
}

/* The review footer: the compact slider line, and the Report control pushed
   to the far end (TG-278). Quiet by design — a report is a rare action, and a
   loud button beside every review would invite one. */
.rv-foot { display: flex; align-items: baseline; justify-content: space-between;
    gap: 12px; margin-top: 8px; }
.rv-foot .rv-sliders { margin-top: 0; }
.rv-report { flex: none; background: none; border: 0; padding: 0; cursor: pointer;
    color: var(--muted); font: 500 .74rem/1 var(--body);
    text-decoration: underline; text-underline-offset: 3px;
    transition: color .16s ease; }
.rv-report:hover { color: var(--ink); }
.rv-report[disabled] { cursor: default; text-decoration: none; opacity: .7; }

/* Review photos (TG-279). Thumbnails under a review: a fixed-height strip so
   four portrait and landscape shots read as one row rather than a staircase;
   each is a real link to the full image, and reviews.js upgrades the tap to a
   lightbox. Neutral chrome only — the picture is the colour. */
.rv-photos { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.rv-photo { display: block; flex: 0 0 auto; width: 96px; height: 96px; border-radius: 10px;
    overflow: hidden; border: 1px solid var(--line); background: var(--glass-2); }
.rv-photo img { width: 100%; height: 100%; object-fit: cover; display: block;
    transition: transform .2s ease; }
.rv-photo:hover img, .rv-photo:focus-visible img { transform: scale(1.04); }
.rv-photo:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; }

.rv-lightbox { border: 0; padding: 0; margin: auto; background: transparent; max-width: min(96vw, 1600px);
    max-height: 96vh; }
.rv-lightbox::backdrop { background: rgba(0, 0, 0, .82); }
.rv-lightbox img { display: block; max-width: 96vw; max-height: 92vh; border-radius: 12px; }
.rv-lightbox-x { position: fixed; top: 14px; right: 14px; width: 40px; height: 40px;
    border-radius: 50%; border: 1px solid rgba(255, 255, 255, .35); background: rgba(0, 0, 0, .5);
    color: #fff; cursor: pointer; display: grid; place-items: center; }
.rv-lightbox-x .ico { width: 18px; height: 18px; stroke: currentColor; stroke-width: 2; fill: none; }

/* The picker: four slots, each carrying its prompt so the four photos a
   runner reaches for are four different ones (AC-3). A slot is a <label>
   wrapping a hidden file input until it holds something, then a card with a
   Remove control. Sized for a thumb at 375px. */
.rv-f-hint { margin: 0; color: var(--muted); font-size: .78rem; }
.rv-f-slots { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
.rv-f-slot { position: relative; display: grid; gap: 4px; align-content: start; min-height: 132px;
    padding: 10px; border-radius: var(--r-ctl); border: 1px dashed var(--line);
    background: var(--glass-2); color: var(--muted); cursor: pointer;
    transition: border-color .16s ease, color .16s ease; }
.rv-f-slot:hover { color: var(--ink); border-color: color-mix(in srgb, var(--ink) 35%, var(--line)); }
.rv-f-slot.has { border-style: solid; cursor: default; }
.rv-f-slot-n { font-family: var(--mono); font-size: .68rem; font-weight: 500;
    text-transform: uppercase; letter-spacing: .1em; }
.rv-f-slot-prompt { font-size: .76rem; line-height: 1.3; color: var(--muted); }
.rv-f-slot-add { display: inline-flex; align-items: center; gap: 6px; margin-top: auto;
    font: 600 .8rem/1 var(--body); color: var(--ink); }
.rv-f-slot-add .ico { width: 16px; height: 16px; fill: currentColor; }
.rv-f-slot-input { position: absolute; inset: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; }
.rv-f-slot-img { width: 100%; height: 72px; object-fit: cover; border-radius: 8px; margin-top: 2px; }
.rv-f-slot-name { font-size: .74rem; color: var(--ink); overflow-wrap: anywhere; }
.rv-f-slot-state { font-size: .7rem; color: var(--acc); }
.rv-f-slot-x { justify-self: start; margin-top: 2px; background: none; border: 0; padding: 0;
    cursor: pointer; color: var(--muted); font: 500 .74rem/1 var(--body);
    text-decoration: underline; text-underline-offset: 3px; }
.rv-f-slot-x:hover { color: var(--ink); }

@media (max-width: 420px) {
    .rv-f-slots { grid-template-columns: 1fr 1fr; }
    .rv-photo { width: 76px; height: 76px; }
}

/* "Typical finish" (TG-352) — how the race usually goes, under the stat tiles.
   Reuses .course-stat/.cs-* wholesale so it reads as part of the Course
   section; the only new rules are the sub-heading and the spacing that
   separates it from the tiles above. Neutral chrome, one accent, per the
   brand rule: the numbers are facts about a past race, not a call to act. */
.cp-tf { margin-top: 18px; }
.cp-tf-h { font: 700 .82rem/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
    color: var(--muted); margin: 0 0 9px; }
.cp-tf-cards { margin-top: 0; }
.cp-tf-note { margin: 9px 0 0; }

/* ---- Profile 2.0 (trail-map.js opts.profile2) ------------------------
   The readout that follows the pointer, the Elevation | Grade | Surface
   switch, the legend for the active mode and the selected-stretch card.
   Figures are mono tabular; the switch is fuel.css's .segmented; the only
   colours here are chrome tokens — the grade and surface swatches are data
   hues set inline from the same tokens the line is drawn with. */
.tg-p2-head { display: flex; align-items: center; justify-content: space-between; gap: 10px 16px;
    flex-wrap: wrap; margin: 0 0 8px; }
.tg-p2-modes { gap: 2px; padding: 3px; }
.tg-p2-modes button { min-height: 36px; padding: 6px 12px; font-size: .82rem; }
.tg-p2-modes button[hidden] { display: none; }
.tg-p2-modes button:hover { color: var(--ink); }
.tg-p2-modes button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.tg-p2-readout { font-size: .82rem; color: var(--muted); min-width: 0; text-align: right;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tg-p2-readout.on { color: var(--ink); }
.cp-elev canvas:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: var(--r-ctl); }
.tg-p2-foot { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 14px; margin-top: 8px;
    font-size: .76rem; color: var(--muted); }
.tg-p2-legend { display: inline-flex; flex-wrap: wrap; gap: 4px 12px; }
.tg-p2-legend[hidden] { display: none; }
.tg-p2-key { display: inline-flex; align-items: center; gap: 5px; font-family: var(--mono); font-size: .72rem; }
.tg-p2-key i { width: 14px; height: 4px; border-radius: 2px; }
.tg-p2-how { margin-left: auto; }
.tg-p2-sel { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 4px 12px;
    margin-top: 10px; padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--r-card);
    background: var(--fill-idle); }
.tg-p2-sel[hidden] { display: none; }
.tg-p2-sel-label { grid-column: 1; font-size: max(.7rem, var(--mono-cap)); color: var(--muted); }
.tg-p2-sel-figs { grid-column: 1; display: flex; flex-wrap: wrap; gap: 4px 16px; font-weight: 700; font-size: .95rem; color: var(--ink); }
.tg-p2-sel-figs .u { margin-left: 4px; color: var(--muted); }
.tg-p2-clear { grid-column: 2; grid-row: 1 / span 2; min-height: 44px; padding: 8px 12px; border: 0;
    border-radius: var(--r-ctl); background: none; color: var(--muted); font: 600 .82rem/1 var(--body); cursor: pointer;
    transition: color var(--dur-ctl) var(--ease-snap), background var(--dur-ctl) var(--ease-snap); }
.tg-p2-clear:hover { color: var(--ink); background: var(--fill-hover); }
.tg-p2-clear:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 860px) {
    .tg-p2-head { flex-direction: column; align-items: stretch; }
    .tg-p2-modes { align-self: flex-start; }
    .tg-p2-modes button { min-height: 44px; }
    .tg-p2-readout { text-align: left; }
    .tg-p2-how { margin-left: 0; }
}

/* ---- Race-day light: the Typical finish block's shape, four tiles ----
   Night's violet is the profile's night band and the Night pill (--c-gear);
   sunrise gold, sunset dusk — data hues on the figures only. */
.cp-light .cs-dark .cs-val, .cp-light .cs-lamp .cs-val { color: var(--c-gear); }
.cp-light .cs-rise .cs-val { color: var(--gold); }
.cp-light .cs-set .cs-val { color: var(--c-weather); }
.cp-light[hidden] { display: none; }

/* ---- Cutoffs with a goal ------------------------------------------------
   The aid table's own shape (.cp-aid-table) with three computed columns. The
   chips are bordered neutral with the accent for the chosen one; the margins
   are status, so --ok / --warn / --bad and nothing else. */
.cut-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 12px 20px; margin-bottom: 14px; }
.cut-label { font-size: max(.72rem, var(--mono-cap)); color: var(--muted); }
.cut-lede { margin: 4px 0 0; }
.cut-goal { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; }
.cut-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.cut-chip { display: inline-flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 1px;
    min-height: 44px; padding: 5px 11px; border: 1px solid var(--edge-soft); border-radius: var(--r-ctl);
    background: var(--fill-idle); color: var(--ink); font: 700 .86rem/1.2 var(--body); cursor: pointer;
    transition: background var(--dur-ctl) var(--ease-snap), border-color var(--dur-ctl) var(--ease-snap); }
.cut-chip small { font: 500 .68rem/1.1 var(--body); color: var(--muted); }
.cut-chip:hover { background: var(--fill-hover); border-color: var(--edge); }
.cut-chip.on { border-color: var(--accent); background: var(--fill-selected); box-shadow: inset 0 -2px 0 var(--accent); }
.cut-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cut-slider { display: inline-flex; align-items: center; gap: 10px; }
.cut-slider input { width: 150px; min-height: 44px; accent-color: var(--accent); cursor: pointer; }
.cut-slider input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-ctl); }
.cut-goal-val { min-width: 64px; font-weight: 700; color: var(--ink); }
.cut-scroll { overflow-x: auto; }
.cut-table th.num, .cut-table td.num { text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; white-space: nowrap; }
.cut-table td.num { color: var(--ink); }
.cut-table td.cut-margin { font-weight: 700; }
.cut-table .cut-mi { display: none; margin-top: 1px; font-size: .72rem; color: var(--muted); }
.cut-table td.cut-ok { color: var(--ok); }
.cut-table td.cut-warn { color: var(--warn); }
.cut-table td.cut-bad { color: var(--bad); }
.cut-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 16px; margin-top: 12px; }
.cut-foot .cp-note { margin: 0; }
.cut-foot .export-btn { min-height: 44px; }
.cut-foot .export-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cut-fine { margin: 10px 0 0; font-size: .78rem; }
@media (max-width: 860px) {
    .cut-goal { width: 100%; }
    .cut-slider { width: 100%; }
    .cut-slider input { flex: 1; width: auto; }
    /* Four columns fit a phone: the distance rides under the name and the
       clock column goes, so the margin — the answer — is never scrolled off. */
    .cut-chips { display: grid; grid-template-columns: 1fr 1fr; width: 100%; }
    .cut-table th, .cut-table td { padding: 7px 5px; font-size: .82rem; }
    .cut-table th:nth-child(2), .cut-table td:nth-child(2),
    .cut-table th:nth-child(5), .cut-table td:nth-child(5) { display: none; }
    .cut-table .cut-mi { display: block; }
    .cut-table th { letter-spacing: .04em; }
    .cut-table .cut-your { display: none; }
    .cut-table td:nth-child(3) { white-space: normal; }
    .cut-foot .export-btn { width: 100%; }
}

/* ---- Share sheet (one dialog: card preview, Link · Embed · QR) ---------- */
.share-sheet { margin: auto; width: min(480px, calc(100% - 32px)); max-height: calc(100dvh - 32px); overflow-y: auto;
    padding: 20px; color: var(--ink); background: var(--bg-1); border: 1px solid var(--line);
    border-radius: var(--r-card); box-shadow: var(--shadow-pop); }
.share-sheet[open] { display: grid; gap: 14px; animation: share-in var(--dur-layer) var(--ease-snap); }
.share-sheet::backdrop { background: color-mix(in srgb, var(--bg-0) 75%, transparent); }
@keyframes share-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .share-sheet[open] { animation: none; } }
.share-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.share-head h2 { margin: 0; font: 700 1.1rem/1.2 var(--display); }
.share-x { display: inline-grid; place-items: center; width: 44px; height: 44px; margin: -8px -8px -8px 0;
    border: 0; border-radius: var(--r-ctl); background: none; color: var(--muted); cursor: pointer;
    transition: background var(--dur-ctl) var(--ease-snap), color var(--dur-ctl) var(--ease-snap); }
.share-x:hover { background: var(--fill-hover); color: var(--ink); }
.share-x .ico { width: 18px; height: 18px; stroke: currentColor; stroke-width: 2; fill: none; }
.share-card { margin: 0; border: 1px solid var(--line); border-radius: var(--r-card); overflow: hidden; background: var(--bg-0); }
.share-card img { display: block; width: 100%; height: auto; aspect-ratio: 1200 / 630; background: var(--bg-well); }
.share-card figcaption { padding: 6px 10px; font-size: .72rem; color: var(--muted); }
.share-tabs { justify-self: start; gap: 2px; padding: 3px; }
.share-tabs button { min-height: 40px; padding: 6px 16px; }
.share-tabs button:hover { color: var(--ink); }
.share-panel { display: grid; gap: 10px; }
.share-panel[hidden] { display: none; }
.share-panel .cp-note { margin: 0; }
.share-field { display: flex; gap: 8px; align-items: stretch; }
.share-field input, .share-field textarea { flex: 1; min-width: 0; min-height: 44px; padding: 10px 12px; font-size: .8rem;
    color: var(--ink); background: var(--bg-well); border: 1px solid var(--line); border-radius: var(--r-ctl); resize: none; }
.share-field textarea { line-height: 1.45; }
.share-field input:focus-visible, .share-field textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.share-field-tall { align-items: flex-start; }
.share-sheet .export-btn { min-height: 44px; }
.share-sheet .export-btn:focus-visible, .share-x:focus-visible, .share-tabs button:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 2px; }
.share-native { justify-self: start; }
.share-qr { justify-self: center; width: min(220px, 70vw); border-radius: var(--r-ctl); overflow: hidden; }
.share-qr svg { display: block; width: 100%; height: auto; }
/* A QR is an image for a camera, not chrome: dark modules on a white tile
   in every theme, because that is what every scanner reads. */
.share-qr .qr-paper { fill: #fff; }
.share-qr .qr-ink { fill: #000; }
.share-panel [data-share-qr-png] { justify-self: center; }
@media (max-width: 860px) {
    .share-sheet { width: calc(100% - 24px); padding: 16px; }
    .share-field-tall { flex-direction: column; align-items: stretch; }
}

/* ---- Hero: social proof and the countdown, one quiet line ---- */
.cp-proof { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin: -8px 0 16px;
    font-size: .88rem; color: var(--muted); }
.cp-proof[hidden] { display: none; }
.cp-proof-n b { color: var(--ink); font-weight: 700; }
.cp-countdown { color: var(--ink); font-size: .84rem; }
.cp-hero-fly .cp-proof { color: var(--ink); opacity: .85; }
@media (max-width: 860px) { .cp-proof { flex-direction: column; gap: 2px; } .cp-proof-sep { display: none; } }

/* ---- Climb cards (course-page idea): every climb as its own object ---- */
.climbs { margin-top: 18px; }
.climbs[hidden] { display: none; }
.climbs-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; margin-bottom: 9px; }
.climbs-h { font: 700 .82rem/1 var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--muted); margin: 0; }
.climbs-sort { margin-left: auto; color: var(--muted); font-size: .76rem; }
.climb-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.climb-list li[hidden] { display: none; }
.climb-card { width: 100%; min-height: 44px; display: grid; grid-template-columns: auto minmax(0, 1fr) 120px; align-items: center; gap: 10px;
    padding: 9px 11px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--glass-2);
    color: var(--ink); font: inherit; text-align: left; cursor: pointer;
    transition: background var(--dur-ctl) var(--ease-snap), border-color var(--dur-ctl) var(--ease-snap); }
.climb-card:hover { background: var(--fill-hover); border-color: var(--edge); }
.climb-card[aria-pressed="true"] { border-color: var(--accent); background: var(--fill-selected); box-shadow: inset 3px 0 0 var(--accent); }
.climb-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.climb-rank { display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 50%;
    background: var(--c-climb); color: var(--bg-0); font-size: .74rem; font-weight: 700; }
.climb-main { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.climb-title { display: flex; align-items: baseline; gap: 4px 8px; flex-wrap: wrap; min-width: 0; }
.climb-name { font-size: .9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.climb-where { color: var(--muted); font-size: .72rem; }
.climb-figs { display: flex; flex-wrap: wrap; gap: 2px 11px; font-size: .78rem; font-variant-numeric: tabular-nums; }
.climb-figs .u { margin-left: 2px; color: var(--muted); font-weight: 400; font-size: .9em; }
.climb-gain { color: var(--c-climb); font-weight: 700; }
.climb-spark { width: 120px; height: 40px; display: block; overflow: visible; }
.climb-area { fill: color-mix(in srgb, var(--c-climb) 18%, transparent); }
.climb-line { fill: none; stroke: var(--c-climb); stroke-width: 1.5; vector-effect: non-scaling-stroke; stroke-linejoin: round; }
.climbs-foot { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px; margin-top: 9px; }
.climbs-foot .export-btn { min-height: 44px; }
.climbs-foot .export-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.climbs-hint { margin: 0; }
@media (max-width: 860px) {
    .climb-list { grid-template-columns: minmax(0, 1fr); }
    .climb-card { grid-template-columns: auto minmax(0, 1fr) 88px; gap: 8px; padding: 8px 10px; }
    .climb-spark { width: 88px; height: 34px; }
    .climbs-sort { margin-left: 0; }
}

/* ---- Conditions (course-page idea): typical race-day weather ---- */
.wx-conds[hidden], .cond-cards[hidden], .cond-cards .course-stat[hidden] { display: none; }
.cond-cards { margin: 0 0 4px; }
.cond-cards .cs-hi .cs-val, .cond-cards .cs-last .cs-val { color: var(--c-fuel); }
.cond-cards .cs-lo .cs-val { color: var(--c-aid); }
.cond-cards .cs-wet .cs-val { color: var(--c-weather); }
.cond-note { margin: 9px 0 0; }

/* ---- Similar courses (course-page idea): the catalog card, compact ---- */
.sim-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.sim-card { display: flex; flex-direction: column; gap: 4px; min-height: 44px; padding: 10px 11px; border: 1px solid var(--line);
    border-radius: var(--r-card); background: var(--glass-2); color: var(--ink); text-decoration: none;
    transition: background var(--dur-ctl) var(--ease-snap), border-color var(--dur-ctl) var(--ease-snap); }
.sim-card:hover { background: var(--fill-hover); border-color: var(--edge); }
.sim-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.sim-spark { display: block; width: 100%; height: 34px; margin-bottom: 2px; }
.sim-spark path { fill: color-mix(in srgb, var(--c-course) 16%, transparent); stroke: var(--c-course); stroke-width: 1.5;
    vector-effect: non-scaling-stroke; stroke-linejoin: round; }
.sim-spark-none { border-bottom: 1px dashed var(--line); }
.sim-name { font-size: .9rem; line-height: 1.25; }
.sim-why { color: var(--muted); font-size: .74rem; }
@media (max-width: 860px) {
    .sim-list { grid-template-columns: minmax(0, 1fr); gap: 8px; }
    .sim-card { display: grid; grid-template-columns: 96px minmax(0, 1fr); grid-template-rows: auto auto; column-gap: 12px; align-items: center; }
    .sim-spark { grid-row: 1 / 3; height: 32px; margin: 0; }
}

/* ---- Reviews with structure (course-page idea) ---- */
.rv-sort { margin: 18px 0 12px; }
.rv-sort button { min-height: 44px; }
.rv-sort button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* "says they finished": the reviewer's own word, so it reads as a quiet tag,
   not a verified check. */
.rv-fin { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: 999px;
    border: 1px solid var(--edge-soft); color: var(--muted); font: 600 .72rem/1.3 var(--body); }
.rv-fin .ico { width: 12px; height: 12px; stroke: var(--ok); fill: none; stroke-width: 2.5; }
.rv-helpful { flex: none; display: inline-flex; align-items: center; gap: 5px; min-height: 44px; margin: -12px 0 -12px auto;
    padding: 0 10px; border: 0; border-radius: var(--r-ctl); background: none; color: var(--muted);
    font: 600 .76rem/1 var(--body); cursor: pointer; transition: color var(--dur-ctl) var(--ease-snap), background var(--dur-ctl) var(--ease-snap); }
.rv-helpful[hidden] { display: none; }
.rv-helpful .ico { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.8; }
.rv-helpful b { font-weight: 700; }
.rv-helpful:hover { color: var(--ink); background: var(--fill-hover); }
.rv-helpful[aria-pressed="true"] { color: var(--accent); }
.rv-helpful[aria-pressed="true"] .ico { fill: color-mix(in srgb, var(--accent) 25%, transparent); }
.rv-helpful:focus-visible, .rv-report:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.rv-foot { align-items: center; }
.rv-f-rating { margin-top: 6px; }
.rv-f-rating .rv-f-chips { flex-wrap: nowrap; }
.rv-f-num { min-width: 44px; min-height: 44px; font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* ---- Course history (course-page idea) ---- */
.hist { margin-top: 18px; }
.hist-h { font: 700 .82rem/1 var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--muted); margin: 0; }
.hist-list { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.hist-list li { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: 12px; align-items: baseline; font-size: .88rem; }
.hist-when { color: var(--muted); font-size: .74rem; font-variant-numeric: tabular-nums; }
.hist-what b { color: var(--ink); }
.hist-who { color: var(--muted); font-size: .78rem; }
.hist-sub { display: block; margin-top: 2px; color: var(--muted); font-size: .8rem; }
.hist-sub a { color: var(--accent); }
.hist-sub a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
@media (max-width: 860px) { .hist-list li { grid-template-columns: minmax(0, 1fr); gap: 2px; } }

/* Photos pinned to the course (course-page idea). A horizontal strip of
   review photos in course order under the profile, each labelled with where
   it was taken; camera marks on the profile and the map are the same photos.
   The picture is the colour: the chrome is neutral, and the one accent marks
   the photo that is lit (hovered, scrubbed to, or focused). */
.cp-shots { margin-top: 18px; }
.cp-shot-list { list-style: none; margin: 0; padding: 2px 2px 8px; display: flex; gap: 10px;
    overflow-x: auto; scroll-snap-type: x proximity; scrollbar-width: thin;
    overscroll-behavior-x: contain; }
.cp-shot-list > li { flex: 0 0 auto; scroll-snap-align: start; }
.cp-shot { position: relative; display: block; width: 208px; aspect-ratio: 4 / 3;
    border-radius: var(--r-card); overflow: hidden; border: 1px solid var(--line);
    background: var(--bg-well);
    transition: box-shadow var(--dur-ctl) var(--ease-snap), border-color var(--dur-ctl) var(--ease-snap); }
.cp-shot img { width: 100%; height: 100%; object-fit: cover; display: block;
    transition: transform var(--dur-layer) var(--ease-snap); }
.cp-shot:hover img, .cp-shot.on img { transform: scale(1.04); }
.cp-shot.on { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); }
.cp-shot:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The label sits on the photo, so it carries its own scrim in both themes. */
.cp-shot-tag { position: absolute; left: 6px; bottom: 6px; max-width: calc(100% - 12px);
    padding: 3px 7px; border-radius: var(--r-ctl); background: rgba(0, 0, 0, .58); color: #fff;
    font-size: .7rem; line-height: 1.25; overflow: hidden;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; }
.cp-shots-hint { margin: 4px 0 0; }

/* The marks: a camera in a small disc, on the profile (along the top of the
   plot, placed by trail-map.js) and on the map (a Leaflet divIcon). */
.tg-pin-layer { position: absolute; inset: 0; pointer-events: none; z-index: 2; }
.tg-photo-pin, .tg-photo-mk { display: grid; place-items: center; border-radius: 50%;
    background: var(--bg-2); border: 1.5px solid var(--accent); color: var(--ink);
    box-shadow: 0 1px 4px rgba(0, 0, 0, .35);
    transition: transform var(--dur-ctl) var(--ease-snap), background var(--dur-ctl) var(--ease-snap); }
.tg-photo-pin { position: absolute; width: 22px; height: 22px; padding: 0; margin: 0;
    transform: translate(-50%, -30%); pointer-events: auto; cursor: pointer; }
/* A 44px target around a 22px mark: the ring is invisible, the tap is not. */
.tg-photo-pin::before { content: ""; position: absolute; inset: -11px; border-radius: 50%; }
.tg-photo-pin svg, .tg-photo-mk svg { width: 13px; height: 13px; fill: none; stroke: currentColor;
    stroke-width: 2; stroke-linejoin: round; }
.tg-photo-pin:hover, .tg-photo-pin.on { transform: translate(-50%, -30%) scale(1.18); }
.tg-photo-pin.on, .tg-photo-mk.on { background: var(--accent); color: var(--accent-ink); }
.tg-photo-pin:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tg-photo-mk { width: 26px !important; height: 26px !important; cursor: pointer; }
.tg-photo-mk.on { transform: scale(1.18); }
.tg-photo-mk:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
    .cp-shot img, .tg-photo-pin, .tg-photo-mk { transition: none; }
}

/* The lightbox, opened from the strip: where the photo was taken, and steps
   to the photo before and after it along the course. */
.rv-lightbox-fig { margin: 0; }
.rv-lightbox-cap { margin-top: 8px; text-align: center; color: #fff; font-size: .8rem; }
.rv-lightbox-nav { position: fixed; top: 50%; width: 44px; height: 44px; margin-top: -22px;
    border-radius: 50%; border: 1px solid rgba(255, 255, 255, .35); background: rgba(0, 0, 0, .5);
    color: #fff; cursor: pointer; display: grid; place-items: center; }
.rv-lightbox-nav[hidden] { display: none; }
.rv-lightbox-nav:disabled { opacity: .35; cursor: default; }
.rv-lightbox-nav.prev { left: 14px; }
.rv-lightbox-nav.next { right: 14px; }
.rv-lightbox-nav .ico { width: 20px; height: 20px; stroke: currentColor; stroke-width: 2; fill: none; }
.rv-lightbox-nav:focus-visible, .rv-lightbox-x:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The form: where a stored photo sits, and the mini profile a reviewer taps
   to place one that came without a location. */
.rv-f-slot-pin { font-size: .72rem; color: var(--ink); }
.rv-place { margin-top: 12px; padding: 12px; border: 1px solid var(--line); border-radius: var(--r-card);
    background: var(--glass-2); display: grid; gap: 8px; }
.rv-place-prof { width: 100%; height: 64px; display: block; cursor: crosshair; }
.rv-place-area { fill: color-mix(in srgb, var(--ink) 10%, transparent); }
.rv-place-line { fill: none; stroke: var(--muted); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.rv-place-mark { stroke: var(--accent); stroke-width: 2; vector-effect: non-scaling-stroke; }
.rv-place-range { width: 100%; min-height: 44px; accent-color: var(--accent); margin: 0; }
.rv-place-range:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-ctl); }
.rv-place-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.rv-place-row .export-btn { min-height: 44px; }
.rv-pin-note { margin-top: 8px; color: var(--ink); }

/* The climb cards' "Show all" stays out of the layout until it has a job. */
.climbs-more[hidden] { display: none; }

@media (max-width: 860px) {
    .cp-shot { width: 156px; }
    .cp-shot-list { margin: 0 -2px; }
    /* A narrow plot packs the marks close: smaller discs, same 44px reach. */
    .tg-photo-pin { width: 18px; height: 18px; }
    .tg-photo-pin svg { width: 11px; height: 11px; }
}

/* A card that becomes the page: a cross-document view transition between
   /courses and a course page (both load this file). courses-field.js names the
   clicked card and its title; the course page's hero and h1 carry the same
   names, so the card grows into the header. Other same-site hops crossfade. */
@view-transition { navigation: auto; }
[data-vt-hero] { view-transition-name: tg-card; }
[data-vt-hero] h1 { view-transition-name: tg-title; }
::view-transition-group(tg-card), ::view-transition-group(tg-title) { animation-duration: 420ms; animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); }
::view-transition-old(tg-card), ::view-transition-new(tg-card) { height: 100%; object-fit: cover; }
::view-transition-group(root) { animation-duration: 260ms; }
@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}

/* ---- Contours that rise (course-topo.js): the hero's backdrop until the course
   has a flythrough. Faint lines over the page ground, faded under the title and
   toward the foot so the heading and buttons always read first. */
.cp-hero-topo { overflow: hidden; }
.cp-hero-topo .cp-topo { position: absolute; inset: 0; width: 100%; height: 100%; display: block; pointer-events: none;
    -webkit-mask-image: linear-gradient(90deg, rgba(0,0,0,.35) 0%, rgba(0,0,0,.55) 40%, #000 72%), linear-gradient(180deg, #000 60%, transparent);
    -webkit-mask-composite: source-in; mask-image: linear-gradient(90deg, rgba(0,0,0,.35) 0%, rgba(0,0,0,.55) 40%, #000 72%), linear-gradient(180deg, #000 60%, transparent);
    mask-composite: intersect; }
.cp-hero-topo .cp-hero-inner { position: relative; z-index: 1; }
.cp-hero-topo.topo-ready .cp-hero-inner { padding-top: 56px; padding-bottom: 12px; }
.cp-topo-cap { top: auto; bottom: 6px; }
@media (max-width: 767px) { .cp-hero-topo.topo-ready .cp-hero-inner { padding-top: 36px; } .cp-topo-cap { display: none; } }

/* /nav.css */
/* ===== Shared site navigation (all pages) =====
   Desktop (≥861px): the existing inline pill nav, unchanged — this file only adds
   the active-page state. Mobile (≤860px): the topbar becomes a compact sticky bar
   with a hamburger; the nav links + unit toggles collapse into a dropdown panel
   (.topbar-tools) opened by nav.js. Uses the page tokens (--bg-*, --ink, --line…)
   defined by each page's own stylesheet, so it must load AFTER it. */

/* --- Inline stroke icons (shared, every page) ---
   Duplicate of the fuel.css base so pages that don't load fuel.css
   (landing, stats) still render them. Icons inherit the text color. */
.ico { width: 15px; height: 15px; flex: 0 0 auto; vertical-align: -0.18em; }
.ico path, .ico circle, .ico rect, .ico line, .ico polyline { fill: none; stroke: currentColor; stroke-width: 1.75;
    stroke-linecap: round; stroke-linejoin: round; }
.nav-ico .ico { width: 13px; height: 13px; }
.nav-search .ico, .nav-gear .ico { width: 16px; height: 16px; }

/* --- Active page (all widths) — set by nav.js via aria-current --- */
/* One accent on duty (TG-282): the current page wears --accent on a ladder
   fill. No per-tool hue, no glow. */
.nav a[aria-current="page"] {
    color: var(--accent);
    background: var(--fill-selected);
}

/* --- Dropdown groups (Option A, 2026-08): Courses ▾ / Why TrailGoat ▾ --- */
.nav-group { position: relative; display: inline-flex; }
.nav-caret { display: inline-flex; margin-left: 5px; opacity: 0.65; transition: transform 0.15s ease; }
.nav-caret svg { width: 10px; height: 10px; fill: none; stroke: currentColor;
    stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.nav-group-btn[aria-expanded="true"] .nav-caret { transform: rotate(180deg); }
/* The group wears a quiet glow when the current page lives inside it. */
.nav .nav-group-here { color: var(--ink); background: var(--glass, rgba(255,255,255,0.045)); }

@media (min-width: 861px) {
    .nav-group-menu {
        position: absolute; top: calc(100% + 6px); left: 0; z-index: 2100;
        min-width: 220px; padding: 6px;
        background: color-mix(in srgb, var(--bg-1, #0a1a1c) 96%, #ffffff 4%);
        border: 1px solid var(--line); border-radius: var(--r-card);
        box-shadow: var(--shadow-pop);
        transform-origin: top left;
        animation: tg-pop-in var(--dur-layer) var(--ease-snap);
    }
    .nav .nav-group-menu a { display: flex; align-items: center; width: 100%;
        padding: 9px 12px; border-radius: var(--r-ctl); }
    .nav .nav-group-menu a small { margin-left: 6px; color: var(--muted); font-weight: 500; }
}
@media (max-width: 860px) {
    /* In the hamburger, groups flatten into labeled sections: the trigger is a
       normal row (it navigates on mobile) and its children sit indented under
       it, always visible. display:contents beats the [hidden] UA rule, which
       is exactly what we want here. */
    .nav-group, .nav-group-menu, .nav-group-menu[hidden] { display: contents; }
    .nav-caret { display: none; }
    /* `.topbar .topbar-tools …`, not `.topbar-tools …`: the canonical
       `.topbar .nav a` block further down ties a two-class selector on
       specificity and wins by coming later, which turned these rows into
       centred pills. One more class here and the panel rows win outright. */
    .topbar .topbar-tools .nav .nav-group-menu a { padding-left: 36px; min-height: 42px; font-size: 0.95rem; }
    .topbar .topbar-tools .nav a small { margin-left: 6px; color: var(--muted); font-weight: 500; }
}

/* --- Hamburger button (hidden on desktop) --- */
.nav-burger { display: none; }


@media (max-width: 860px) {
    /* Compact sticky bar — the nav is reachable from anywhere on 4,000px+ pages. */
    .topbar {
        position: sticky; top: 0; z-index: 2000;
        flex-wrap: nowrap;
        padding-top: 10px; padding-bottom: 10px;
        background: color-mix(in srgb, var(--bg-0, #07120f) 86%, transparent);
        -webkit-backdrop-filter: blur(14px);
        backdrop-filter: blur(14px);
        border-bottom: 1px solid var(--line);
    }

    /* No blur support (old WebViews, battery savers) → solid bars, still legible. */
    @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
        .topbar, .section-chips { background: var(--bg-0, #07120f); }
    }

    .nav-burger {
        display: inline-flex; align-items: center; justify-content: center;
        order: 10;                      /* far right, after any topbar CTA */
        flex: 0 0 auto;
        width: 44px; height: 44px;      /* full-size touch target */
        margin: -4px 0;                 /* …without growing the bar */
        background: transparent; border: none; border-radius: var(--r-ctl);
        cursor: pointer; color: var(--ink);
    }
    .nav-burger:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

    /* The three lines → X morph */
    .nav-burger-box { position: relative; width: 20px; height: 14px; display: block; }
    .nav-burger-box span {
        position: absolute; left: 0; width: 20px; height: 2px; border-radius: 2px;
        background: currentColor; transition: transform 0.2s ease, opacity 0.15s ease, top 0.2s ease;
    }
    .nav-burger-box span:nth-child(1) { top: 0; }
    .nav-burger-box span:nth-child(2) { top: 6px; }
    .nav-burger-box span:nth-child(3) { top: 12px; }
    .menu-open .nav-burger-box span:nth-child(1) { top: 6px; transform: rotate(45deg); }
    .menu-open .nav-burger-box span:nth-child(2) { opacity: 0; }
    .menu-open .nav-burger-box span:nth-child(3) { top: 6px; transform: rotate(-45deg); }

    /* The mascot hugs the wordmark; the auto margin absorbs the slack so
       space-between can't center him between wordmark and burger. */
    .topbar-mascot { display: inline-flex; margin-right: auto; }

    /* Landing-page CTA stays visible in the bar, compacted. */

    /* --- Dropdown panel --- */
    .topbar-tools {
        display: none;
        position: absolute; top: calc(100% + 8px); left: 12px; right: 12px;
        flex-direction: column; align-items: stretch; gap: 4px;
        /* fuel.css's .toggles sets flex-wrap:wrap AND justify-content:flex-end.
           In a height-capped COLUMN that wrapped overflow into a clipped second
           column, and packed items to the bottom so anything that didn't fit
           spilled off the TOP where no scrollbar can reach it. One column,
           packed from the top, scrolled. */
        flex-wrap: nowrap; justify-content: flex-start;
        padding: 8px;
        background: color-mix(in srgb, var(--bg-1, #0a1a1c) 96%, #ffffff 4%);
        border: 1px solid var(--line); border-radius: var(--r-card);
        box-shadow: var(--shadow-pop);
        max-height: calc(100dvh - 90px); overflow-y: auto;
    }
    .topbar.menu-open .topbar-tools {
        display: flex; transform-origin: top center;
        animation: tg-pop-in var(--dur-layer) var(--ease-snap);
    }

    /* Links become full-width touch rows. (Three classes — see the note on the
       group rows above for why two were not enough.) */
    .topbar .topbar-tools .nav { display: flex; flex-direction: column; align-items: stretch; flex-wrap: nowrap; gap: 2px; }
    .topbar .topbar-tools .nav a {
        display: flex; align-items: center; min-height: 46px;
        padding: 10px 14px; border-radius: var(--r-ctl);
        font-size: 1rem; font-weight: 600;
    }
    .topbar .topbar-tools .nav a[aria-current="page"] { color: var(--accent); }
    .topbar .topbar-tools .nav a:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

    /* Unit toggles ride along in the panel as full-width segmented controls
       (they're inside .topbar-tools on the pages that have them). */
    .topbar-tools .unit-toggle { display: flex; width: 100%; }
    .topbar-tools .unit-toggle button { flex: 1 1 0; padding-top: 10px; padding-bottom: 10px; }
    .topbar-tools .unit-toggle:first-of-type {
        margin-top: 6px; border-radius: var(--r-ctl);
    }
    .topbar-tools .unit-toggle:first-of-type::before { display: none; }
    .topbar-tools .unit-toggle + .unit-toggle { border-radius: var(--r-ctl); }

    /* Dim + block the page behind the open menu; tapping it closes (nav.js). */
    body.nav-open::after {
        content: ""; position: fixed; inset: 0; z-index: 1900;
        background: rgba(4, 10, 8, 0.45);
    }
}

@media (prefers-reduced-motion: reduce) {
    .topbar.menu-open .topbar-tools { animation: none; }
    .nav-burger-box span { transition: none; }
}

/* ===== Section-jump chips (built by nav.js on the long tool pages) =====
   Pill styles are shared; each breakpoint defines its own ROW. Narrow: sticky
   under the topbar (the page scrolls). Desktop split pages: a quiet static row
   between topbar and panes (the RIGHT PANE scrolls — audit F5: a 6,000px pane
   had no navigation at all on desktop). */
.section-chips { display: none; }
.section-chip {
    flex: 0 0 auto; white-space: nowrap;
    min-height: 36px; padding: 6px 14px;
    background: var(--fill-idle);
    color: var(--muted);
    border: 1px solid var(--line);
    border-radius: var(--r-ctl);
    font: inherit; font-family: var(--body); font-size: 0.82rem; font-weight: 600;
    cursor: pointer;
    transition: box-shadow 0.25s ease, background 0.25s ease, border-color 0.25s ease;
}
/* Hover steps the fill. The section in view wears the one "you are here"
   mark (TG-287): the teal→moss ring from tokens.css, restated here because
   this base rule loads after tokens.css and would otherwise win the fill.
   nav.js stamps .tg-here alongside aria-current; nothing reads --chip-acc. */
.section-chip:hover { color: var(--ink); background: var(--fill-hover); border-color: var(--edge-soft); }
.section-chip[aria-current], .section-chip.tg-here {
    color: var(--accent);
    border-color: transparent;
    background: var(--here-bg);
    transition: none;
}
.section-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.section-chips::-webkit-scrollbar { display: none; }
@media (max-width: 860px) {
    /* A thumb needs 40px of height; the chips stood at 36 (TG-301). The extra
       comes out of padding — the label size is what makes the row readable
       while scrolling past it, so it does not move. */
    .section-chip { min-height: 40px; }
    .section-chips {
        position: sticky; z-index: 1890;   /* under the topbar (2000) and the menu scrim (1900) */
        top: 63px;                          /* nav.js keeps this synced to the real topbar height */
        display: flex; gap: 8px;
        padding: 8px 16px 10px;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        background: color-mix(in srgb, var(--bg-0, #07120f) 86%, transparent);
        -webkit-backdrop-filter: blur(14px);
        backdrop-filter: blur(14px);
        border-bottom: 1px solid var(--line);
    }
    .section-chips[hidden] { display: none; }
    /* Scrollability affordance (KRI-58): the clipped edge fades to nothing —
       a half-faded chip is the "more this way" signal. Mask-only, so the row's
       background and blur fade with the chips instead of leaving a hard seam.
       nav.js toggles the classes from scroll position. */
    .section-chips.chips-more-right {
        -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 44px), transparent);
        mask-image: linear-gradient(90deg, #000 calc(100% - 44px), transparent);
    }
    .section-chips.chips-more-left {
        -webkit-mask-image: linear-gradient(270deg, #000 calc(100% - 44px), transparent);
        mask-image: linear-gradient(270deg, #000 calc(100% - 44px), transparent);
    }
    .section-chips.chips-more-left.chips-more-right {
        -webkit-mask-image: linear-gradient(90deg, transparent, #000 44px, #000 calc(100% - 44px), transparent);
        mask-image: linear-gradient(90deg, transparent, #000 44px, #000 calc(100% - 44px), transparent);
    }
}
@media (min-width: 861px) {
    /* Inside the right pane (nav.js moves it there): a sticky floating toolbar
       pinned to the top of the column it controls. Centered, and it WRAPS —
       never clips — when the pane is narrow. z-index clears the scroll fade (6). */
    body.split-page .split-right > .section-chips {
        display: flex; flex-wrap: wrap; justify-content: center; gap: 7px;
        position: sticky; top: 0; z-index: 7;
        margin: 0; padding: 10px 12px;
        background: var(--bg-0, #07120f);
        border: 1px solid var(--line); border-radius: var(--r-card);
    }
    /* An explicit display beats the [hidden] UA rule — restate it (known trap). */
    body.split-page .split-right > .section-chips[hidden] { display: none; }
    body.split-page .split-right > .section-chips .section-chip { padding: 6px 10px; font-size: 0.8rem; }
    /* Auto-hide, in lockstep with the plan-action bar (one timer in raceday.js
       toggles .rd-actions-hidden on both). Opacity-only fade: the sticky slot
       stays in flow so chip-click / scrollspy offsets that use row.offsetHeight
       don't shift. Slides UP — it's a top bar (the plan bar slides down). */
    body.split-page .split-right > .section-chips {
        transition: opacity 0.28s ease, transform 0.28s ease;
    }
    body.split-page .split-right > .section-chips.rd-actions-hidden {
        opacity: 0; transform: translateY(-10px); pointer-events: none;
    }
}
@media (prefers-reduced-motion: reduce) {
    body.split-page .split-right > .section-chips.rd-actions-hidden { transform: none; }
}

/* ===== Topbar mascot — the goat mascot trotting beside the wordmark =====
   The landing hero's goat, miniaturised: same LED palette-cycle glow hugging
   his silhouette, a small bob, and the poof trailing behind him (he runs
   right, so the dust kicks off to his left — `order` puts it there without
   touching the template). */
/* Mobile-only: on desktop the wordmark stands alone. */
.topbar-mascot { display: none; align-items: center; gap: 1px; margin-left: 8px; flex: 0 0 auto; }
@media (max-width: 860px) { .topbar-mascot { display: inline-flex; } }
.topbar-goat {
    height: 32px; width: auto; display: block;
    animation: tg-mini-bob 3.2s ease-in-out infinite;
}
/* The palette cycle is a moment now, not a 22s loop (TG-285): nav.js adds
   .goat-led for one 2.2s pass through the brand hues when the page settles, a
   plan is saved, or a tour step advances. Same react() plumbing as the sprint
   and the hop; the idle bob keeps running underneath. */
.topbar-mascot.goat-led .topbar-goat {
    animation: tg-mini-bob 3.2s ease-in-out infinite, tg-mini-led 2.2s linear 1;
}
/* An SVG puff, not the emoji it used to be: the brand rule is SVG icons only,
   and the mascot <img> beside it is the single exception (KRI-200). The
   keyframes drive opacity/transform, so they work on an <svg> unchanged. */
.topbar-dust { width: 14px; height: 14px; fill: var(--muted); flex: 0 0 auto; order: -1;
    animation: tg-mini-dust 1.6s ease-in-out infinite; }
@keyframes tg-mini-bob {
    0%, 100% { transform: translateY(0) rotate(-1deg); }
    50%      { transform: translateY(-2px) rotate(1deg); }
}
@keyframes tg-mini-led {
    0%, 100% { filter: drop-shadow(0 0 2px rgba(255,122,26,0.55)) drop-shadow(0 0 7px rgba(255,122,26,0.4)); }
    16.6%    { filter: drop-shadow(0 0 2px rgba(255,210,63,0.55)) drop-shadow(0 0 7px rgba(255,210,63,0.4)); }
    33.3%    { filter: drop-shadow(0 0 2px rgba(154,230,0,0.55)) drop-shadow(0 0 7px rgba(154,230,0,0.4)); }
    50%      { filter: drop-shadow(0 0 2px rgba(25,195,177,0.55)) drop-shadow(0 0 7px rgba(25,195,177,0.4)); }
    66.6%    { filter: drop-shadow(0 0 2px rgba(139,108,255,0.55)) drop-shadow(0 0 7px rgba(139,108,255,0.4)); }
    83.3%    { filter: drop-shadow(0 0 2px rgba(255,93,115,0.55)) drop-shadow(0 0 7px rgba(255,93,115,0.4)); }
}
@keyframes tg-mini-dust {
    0%   { opacity: 0; transform: translateX(3px) scale(0.8); }
    40%  { opacity: 0.85; }
    100% { opacity: 0; transform: translateX(-10px) scale(1.1); }
}
@media (prefers-reduced-motion: reduce) {
    .topbar-goat, .topbar-dust { animation: none; }
}

/* ===== Status chips: one vocabulary, five states =====
   Draft · Ready · Shared · Live · Finished, on the three status tokens plus
   two feature hues the state already owns. The chip is the label voice —
   mono caps, tracked out — with a 1px edge in currentColor, so a state is
   one class and one colour: `<span class="tg-status is-ready">ready</span>`.
   Anything that says "saved", "draft" or "failed" should wear this rather
   than invent its own tint. Same shape in every theme; only the ink moves. */
.tg-status {
    display: inline-flex; align-items: center; gap: 5px;
    font-family: var(--mono); font-size: var(--mono-cap); font-weight: 600;
    letter-spacing: 0.08em; text-transform: uppercase; line-height: 1;
    padding: 3px 7px; border-radius: var(--r-ctl);
    border: 1px solid currentColor; color: var(--muted);
    white-space: nowrap; vertical-align: middle;
}
.tg-status.is-draft    { color: var(--muted); }
.tg-status.is-ready    { color: var(--ok); }
.tg-status.is-shared   { color: var(--c-aid); }
.tg-status.is-live     { color: var(--c-crew); }
.tg-status.is-finished { color: var(--gold); }
/* The generic three, for a chip that reports an outcome rather than a stage. */
.tg-status.is-ok       { color: var(--ok); }
.tg-status.is-warn     { color: var(--warn); }
.tg-status.is-bad      { color: var(--bad); }
/* Live carries a dot that breathes — the one status allowed to move, because
   it reports a clock that is running. Stops under reduced motion. */
.tg-status.is-live::before {
    content: ""; width: 6px; height: 6px; border-radius: 50%;
    background: currentColor; animation: tg-status-pulse 2s ease-in-out infinite;
}
@keyframes tg-status-pulse { 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .tg-status.is-live::before { animation: none; } }

/* ===== Toasts (TrailGoatToast — nav.js, and tg-toast.js on pages without nav) =====
   Bottom-centre, not the corner. On a phone the corner IS the centre, so the
   two layouts only differ on a desktop, and there the centre is where the eye
   already is after pressing a control in the page body — the corner sat
   under a scrollbar and next to nothing. Nothing else on the site pins to
   the bottom edge except the installed app's tab bar, which the stack lifts
   itself above. Newest toast at the bottom, closest to the hand. */
.tg-toast-stack {
    position: fixed; left: 50%; bottom: max(18px, env(safe-area-inset-bottom, 0px));
    transform: translateX(-50%); z-index: 4000;
    width: max-content; max-width: min(calc(100vw - 32px), 480px);
    display: flex; flex-direction: column; align-items: center; gap: 10px;
    pointer-events: none;
}
html.tg-tabs .tg-toast-stack {
    bottom: calc(var(--tg-tabbar-space, 0px) + 12px);
}
.tg-toast {
    pointer-events: auto;
    display: flex; align-items: center; gap: 10px;
    transform-origin: bottom center;
    max-width: 100%; box-sizing: border-box;
    background: var(--bg-2, #0e1f20);
    border: 1px solid var(--line, rgba(255, 255, 255, 0.1));
    border-left: 3px solid var(--tg-toast-acc, var(--accent));
    color: var(--ink, #eef5ef);
    border-radius: var(--r-card); padding: 10px 14px;
    font-size: 0.92rem; line-height: 1.45;
    box-shadow: var(--shadow-pop);
    opacity: 0; transform: translateY(8px) scale(0.96);
    transition: opacity var(--dur-layer) var(--ease-snap), transform var(--dur-layer) var(--ease-snap);
}
.tg-toast.show { opacity: 1; transform: none; }
/* kind: the bar takes the status colour unless the caller passed an accent,
   and a small dot in the same ink leads the message so the state reads even
   before the words do. */
.tg-toast.is-ok   { --tg-toast-kind: var(--ok); }
.tg-toast.is-warn { --tg-toast-kind: var(--warn); }
.tg-toast.is-bad  { --tg-toast-kind: var(--bad); }
.tg-toast.is-ok, .tg-toast.is-warn, .tg-toast.is-bad {
    border-left-color: var(--tg-toast-acc, var(--tg-toast-kind));
}
.tg-toast-dot {
    flex: none; width: 8px; height: 8px; border-radius: 50%;
    background: var(--tg-toast-kind, var(--accent));
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--tg-toast-kind, var(--accent)) 22%, transparent);
}
.tg-toast-msg { flex: 1 1 auto; min-width: 0; }
/* The action (Undo, Reload): the quiet rung of the button ladder, in the
   accent because it is the one thing here you can press. 44px tall on a
   phone — the toast is exactly the control a thumb reaches for in a hurry. */
.tg-toast-act {
    flex: none; margin: -6px -8px -6px 2px;
    padding: 6px 10px; min-height: 32px;
    border: 0; border-radius: var(--r-ctl); background: transparent;
    color: var(--accent); font: inherit; font-weight: 700; cursor: pointer;
    transition: background var(--dur-ctl) var(--ease-snap);
}
.tg-toast-act:hover { background: var(--fill-hover); }
.tg-toast-act:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
@media (max-width: 860px) {
    .tg-toast-act { min-height: 44px; padding: 6px 12px; }
}
@media (prefers-reduced-motion: reduce) {
    .tg-toast { transition: none; transform: none; }
}

/* ===== Command palette (⌘K) ===== */
.tg-pal-backdrop {
    position: fixed; inset: 0; z-index: 4500; display: none;
    background: rgba(3, 9, 7, 0.55);
    -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
    padding: 12vh 16px 0;
}
.tg-pal-backdrop.open { display: block; }
.tg-pal {
    max-width: 520px; margin: 0 auto;
    transform-origin: top center;
    animation: tg-pop-in var(--dur-layer) var(--ease-snap);
    background: var(--bg-1, #0a1a1c);
    border: 1px solid var(--line, rgba(255, 255, 255, 0.1));
    border-radius: var(--r-card); overflow: hidden;
    box-shadow: var(--shadow-pop);
}
.tg-pal-input {
    width: 100%; padding: 16px 18px;
    background: transparent; border: none; outline: none;
    color: var(--ink, #eef5ef); font: inherit; font-family: var(--body); font-size: 1.05rem;
    border-bottom: 1px solid var(--line, rgba(255, 255, 255, 0.1));
}
.tg-pal-list { max-height: 320px; overflow-y: auto; padding: 6px; }
.tg-pal-item {
    display: flex; align-items: baseline; gap: 10px; width: 100%;
    padding: 10px 12px; border: none; border-radius: var(--r-ctl);
    background: transparent; color: var(--ink, #eef5ef);
    font: inherit; font-family: var(--body); text-align: left; cursor: pointer;
}
.tg-pal-item.sel { background: var(--fill-selected); }
.tg-pal-kind {
    flex: 0 0 auto; font-size: 0.68rem; font-weight: 700; letter-spacing: 0.08em;
    text-transform: uppercase; color: var(--muted, #9ab5a8);
    border: 1px solid var(--line, rgba(255, 255, 255, 0.1));
    border-radius: var(--r-ctl); padding: 1px 6px;
}
.tg-pal-name { font-weight: 600; }
.tg-pal-meta { color: var(--muted, #9ab5a8); font-size: 0.85rem; margin-left: auto;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 45%; }
.tg-pal-none { padding: 18px; color: var(--muted, #9ab5a8); font-size: 0.92rem; }
.tg-pal-hint {
    padding: 8px 16px; border-top: 1px solid var(--line, rgba(255, 255, 255, 0.08));
    color: var(--muted, #9ab5a8); font-size: 0.75rem;
}
body.pal-open { overflow: hidden; }

/* Palette 2.0 (nav.js): a head with the field, grouped results with counts,
   skeleton rows while a search is in flight. The Planner's course browser
   (gpx.js) reuses .tg-pal / .tg-pal-item as a flat list and never gets the
   head, the groups or .tg-pal-text, so nothing below changes it. */
.tg-pal-head {
    display: flex; align-items: center; gap: 10px; padding: 0 8px 0 16px;
    border-bottom: 1px solid var(--line);
}
.tg-pal-head > .ico { width: 18px; height: 18px; flex: 0 0 auto; color: var(--muted); }
/* Page stylesheets dress bare text inputs; this field is the whole card's
   subject, so it stays bare, and the open palette is its focus indication. */
.tg-pal-head .tg-pal-input {
    flex: 1 1 auto; min-width: 0; padding: 16px 0; margin: 0;
    border: 0; border-radius: 0; background: transparent; box-shadow: none;
    font-size: max(1.05rem, 16px);
}
.tg-pal-head .tg-pal-input:focus, .tg-pal-head .tg-pal-input:focus-visible { outline: none; border: 0; box-shadow: none; }
.tg-pal-esc {
    flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
    min-width: 44px; min-height: 44px; padding: 0; cursor: pointer;
    background: none; border: 0; border-radius: var(--r-ctl);
}
.tg-pal-esc:hover { background: var(--fill-hover); }
.tg-pal kbd {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 20px; height: 20px; padding: 0 5px; box-sizing: border-box;
    font: 500 0.68rem/1 var(--mono); color: var(--muted);
    background: var(--fill-idle); border: 1px solid var(--edge-soft);
    border-bottom-width: 2px; border-radius: var(--r-ctl);
}
.tg-pal-head ~ .tg-pal-list { max-height: min(420px, 56vh); }
.tg-pal-group + .tg-pal-group { margin-top: 4px; }
.tg-pal-gh {
    display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
    padding: 8px 12px 4px;
}
.tg-pal-gh .data-label { font-size: 0.66rem; color: var(--muted); }
.tg-pal-count { font-size: 0.7rem; color: var(--faint, var(--muted)); }
div.tg-pal-item { align-items: center; min-height: 44px; box-sizing: border-box; }
.tg-pal-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
.tg-pal-text .tg-pal-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tg-pal-text .tg-pal-meta { margin-left: 0; max-width: none; font-size: 0.8rem; }
.tg-pal-side { flex: 0 0 auto; font-size: 0.76rem; color: var(--muted); }
.tg-pal-item .tg-pal-kind { min-width: 78px; text-align: center; box-sizing: border-box; }
.tg-pal-item.sel .tg-pal-kind { color: var(--ink); border-color: var(--edge); }
.tg-pal-note {
    margin: 6px 6px 2px; padding: 8px 10px; border-radius: var(--r-ctl);
    background: var(--fill-idle); color: var(--muted); font-size: 0.8rem;
}
.tg-pal-none a { color: var(--accent); font-weight: 600; }
.tg-pal-skel { display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 0 12px; }
.tg-pal-skel-k, .tg-pal-skel-l {
    height: 12px; border-radius: var(--r-ctl);
    background: linear-gradient(90deg, var(--fill-idle) 25%, var(--fill-hover) 50%, var(--fill-idle) 75%);
    background-size: 200% 100%;
    animation: tg-pal-shimmer 1.2s ease-in-out infinite;
}
.tg-pal-skel-k { width: 78px; height: 18px; flex: 0 0 auto; }
@keyframes tg-pal-shimmer { 0% { background-position: 180% 0; } 100% { background-position: -80% 0; } }
.tg-pal-hint { display: flex; flex-wrap: wrap; gap: 6px 16px; }
.tg-pal-hint span { display: inline-flex; align-items: center; gap: 3px; }
.tg-pal-hint kbd { min-width: 18px; height: 18px; }
@media (max-width: 860px) {
    .tg-pal-backdrop { padding-top: 8px; }
    .tg-pal-hint-wide { display: none !important; }
    .tg-pal-side { display: none; }
}
@media (prefers-reduced-motion: reduce) { .tg-pal-skel-k, .tg-pal-skel-l { animation: none; } }

/* ===== Goat moments ===== */
.topbar-mascot.goat-sprint .topbar-goat { animation: goat-sprint 0.35s ease-in-out 4; }
.topbar-mascot.goat-sprint .topbar-dust { animation: goat-dust 1.4s ease-out 1; }
.topbar-mascot.goat-party .topbar-goat { animation: goat-hop 0.4s cubic-bezier(.3,1.6,.5,1) 4; }
@keyframes goat-sprint {
    0%, 100% { transform: translateX(0) rotate(0); }
    50% { transform: translateX(-5px) rotate(-6deg); }
}
@keyframes goat-dust {
    0% { opacity: 0; transform: translateX(0) scale(0.8); }
    30% { opacity: 1; }
    100% { opacity: 0; transform: translateX(10px) scale(1.3); }
}
@keyframes goat-hop {
    0%, 100% { transform: translateY(0); }
    45% { transform: translateY(-7px) rotate(6deg); }
}

/* ===== Auth (Sign in with Google — auth.js) ===== */
.tg-auth { position: relative; display: inline-flex; align-items: center; }
.tg-auth-btn {
    font: inherit; font-family: var(--body); font-size: 0.88rem; font-weight: 600;
    color: var(--ink, #eef5ef);
    background: var(--glass, rgba(255, 255, 255, 0.045));
    border: 1px solid var(--line, rgba(255, 255, 255, 0.1));
    border-radius: var(--r-ctl); padding: 7px 16px; cursor: pointer;
    transition: border-color var(--dur-ctl) var(--ease-snap), background var(--dur-ctl) var(--ease-snap);
}
.tg-auth-btn:hover { border-color: var(--edge-soft); background: var(--fill-hover); }
.tg-auth-chip {
    display: inline-flex; align-items: center; gap: 8px;
    font: inherit; font-family: var(--body); font-size: 0.88rem; font-weight: 600;
    color: var(--ink, #eef5ef);
    background: var(--glass, rgba(255, 255, 255, 0.045));
    border: 1px solid var(--line, rgba(255, 255, 255, 0.1));
    border-radius: var(--r-ctl); padding: 4px 14px 4px 5px; cursor: pointer;
}
.tg-auth-avatar { width: 26px; height: 26px; border-radius: 50%; display: block; }
.tg-auth-menu {
    position: absolute; top: calc(100% + 8px); right: 0; z-index: 3000;
    min-width: 220px; transform-origin: top right;
    animation: tg-pop-in var(--dur-layer) var(--ease-snap);
    background: var(--bg-1, #0a1a1c);
    border: 1px solid var(--line, rgba(255, 255, 255, 0.1));
    border-radius: var(--r-card); padding: 10px;
    box-shadow: var(--shadow-pop);
}
.tg-auth-menu[hidden] { display: none; }
.tg-auth-who { padding: 4px 6px 10px; font-weight: 600; color: var(--ink, #eef5ef); }
.tg-auth-who small { display: block; font-weight: 400; color: var(--muted, #9ab5a8); margin-top: 2px; }
.tg-auth-out {
    width: 100%; text-align: left; font: inherit; font-family: var(--body); font-size: 0.9rem;
    color: var(--ink, #eef5ef); background: transparent;
    border: 1px solid var(--line, rgba(255, 255, 255, 0.1));
    border-radius: var(--r-ctl); padding: 9px 12px; cursor: pointer;
}
.tg-auth-out:hover { border-color: var(--edge-soft); background: var(--fill-hover); }
.tg-auth-head { font-weight: 700; padding: 4px 6px 10px; }
.tg-auth-google { display: flex; justify-content: center; padding: 4px 0 8px; min-height: 44px; }
.tg-auth-note { color: var(--muted, #9ab5a8); font-size: 0.8rem; margin: 4px 6px 2px; line-height: 1.45; }

@media (max-width: 860px) {
    /* Inside the hamburger panel the auth control becomes a full-width row,
       and its dropdown opens in flow (an absolute menu would clip).
       ORDERED FIRST: appended last it sat under nine nav links plus search
       and settings, so on a phone (browser chrome eating the height) the one
       control a signed-out visitor came for was below the fold — and with
       Dashboard off the navbar, so was the way back to their account. */
    .tg-auth {
        display: block; order: -1;
        margin: 0 0 8px; padding-bottom: 8px;
        border-bottom: 1px solid var(--line);
    }
    .tg-auth-btn, .tg-auth-chip { width: 100%; justify-content: center; display: inline-flex; min-height: 46px; }
    .tg-auth-menu { position: static; margin-top: 6px; width: 100%; box-shadow: none; animation: none; }
}

/* ===== My plans (auth.js phase 2) ===== */
.tg-plans-head {
    font-family: var(--mono); font-size: 0.72rem; font-weight: 500; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--muted, #9ab5a8); padding: 8px 6px 6px;
    border-top: 1px solid var(--line, rgba(255, 255, 255, 0.08)); margin-top: 4px;
}
.tg-plans-list { max-height: 260px; overflow-y: auto; margin-bottom: 8px; }
.tg-plans-empty { color: var(--muted, #9ab5a8); font-size: 0.85rem; padding: 6px; line-height: 1.45; }
.tg-plan-row { display: flex; align-items: stretch; gap: 4px; }
.tg-plan-open {
    flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px;
    text-align: left; font: inherit; font-family: var(--body); color: var(--ink, #eef5ef);
    background: transparent; border: 1px solid transparent; border-radius: var(--r-ctl);
    padding: 8px 10px; cursor: pointer;
}
.tg-plan-open:hover { background: var(--fill-hover); border-color: var(--edge-soft); }
.tg-plan-name { font-weight: 600; font-size: 0.92rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tg-plan-meta { color: var(--muted, #9ab5a8); font-size: 0.78rem; }
/* Crew-sheet line under a plan that has a bound share (KRI-121): the runner
   grabs the /plan/{token} link straight from the list. Flat text actions. */
.tg-plan-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.tg-plan-crew { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    padding: 2px 10px 7px; font-size: 0.76rem; color: var(--muted, #9ab5a8); }
.tg-plan-crew .ico { width: 13px; height: 13px; flex: 0 0 auto;
    fill: none; stroke: currentColor; stroke-width: 1.8;
    stroke-linecap: round; stroke-linejoin: round; }
.tg-plan-crew-copy, .tg-plan-crew-open {
    background: none; border: none; padding: 2px 0; cursor: pointer;
    font: 600 0.76rem/1.3 inherit; font-family: var(--body);
    color: var(--accent); text-decoration: underline;
    text-underline-offset: 3px; }
.tg-plan-crew-copy:hover, .tg-plan-crew-open:hover,
.tg-plan-crew-copy:focus-visible, .tg-plan-crew-open:focus-visible {
    color: var(--ink, #eef5ef); }
.tg-plan-del {
    flex: 0 0 auto; width: 34px; font: inherit; font-family: var(--body); font-size: 1rem;
    color: var(--muted, #9ab5a8); background: transparent;
    border: 1px solid transparent; border-radius: var(--r-ctl); cursor: pointer;
}
.tg-plan-del:hover { color: var(--ink); border-color: var(--edge-soft); background: var(--fill-hover); }

/* "Save plan" beside Clear course (fuel/raceday, signed-in with a course) —
   a secondary verb: the ladder's bordered neutral, no glow (TG-282). */
.tg-plan-save {
    font: inherit; font-family: var(--body); font-size: 0.88rem; font-weight: 600;
    color: var(--ink);
    background: var(--fill-idle);
    border: 1px solid var(--edge);
    border-radius: var(--r-ctl); padding: 8px 16px; cursor: pointer; margin-right: 8px;
    transition: background 0.15s ease, transform 0.15s ease;
}
.tg-plan-save:hover { background: var(--fill-hover); transform: translateY(-1px); }
.tg-plan-save[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) { .tg-plan-save:hover { transform: none; } }

/* ===== Search + settings controls ===== */
/* Settings (unit toggles, About you) collapse behind a gear; search fronts
   the ⌘K palette. The desktop bar that holds them is further down. */
.nav-ico { margin-right: 7px; }
.nav-search, .nav-gear {
    flex: 0 0 auto;
    width: 36px; height: 36px;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 0.95rem; cursor: pointer;
    color: var(--ink, #eef5ef);
    background: var(--glass, rgba(255, 255, 255, 0.045));
    border: 1px solid var(--line, rgba(255, 255, 255, 0.1));
    border-radius: var(--r-ctl);
    transition: border-color var(--dur-ctl) var(--ease-snap), background var(--dur-ctl) var(--ease-snap);
}
.nav-search:hover, .nav-gear:hover {
    border-color: var(--edge-soft);
    background: var(--fill-hover);
}
.nav-search:focus-visible, .nav-gear:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The desktop door links run the full height of the bar, so the site ring's
   2px offset (tokens.css) would be cut off by the bar's top edge — inset it. */
.topbar .nav a:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.nav-settings { position: relative; flex: 0 0 auto; }
.nav-settings-menu {
    position: absolute; top: calc(100% + 8px); right: 0; z-index: 3000;
    min-width: 260px; transform-origin: top right;
    animation: tg-pop-in var(--dur-layer) var(--ease-snap);
    background: var(--bg-1, #0a1a1c);
    border: 1px solid var(--line, rgba(255, 255, 255, 0.1));
    border-radius: var(--r-card); padding: 12px;
    box-shadow: var(--shadow-pop);
    display: flex; flex-direction: column; gap: 10px;
}
.nav-settings-menu[hidden] { display: none; }
.set-row { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.set-label { font-size: 0.88rem; font-weight: 600; }
.set-row .unit-toggle { margin: 0; }
/* Theme picker: five options — stack the row and let the pills wrap. */
.set-row-theme { flex-direction: column; align-items: stretch; gap: 8px; }
/* Five themes never fitted the 2-segment .unit-toggle pill: wrapping left a
   999px-rounded box with ragged rows and the active pill riding its curve.
   Own component — an even grid, cells of equal width, modest corners. */
/* minmax(0,1fr), not 1fr: plain 1fr floors at min-content, so the longest
   label ('Alpenglow') would widen its column and skew the grid. */
.theme-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 5px;
    background: rgba(0,0,0,0.35); border: 1px solid rgba(255,255,255,0.09);
    border-radius: var(--r-card); padding: 5px;
    box-shadow: var(--well, inset 0 2px 6px rgba(0,0,0,0.5)); }
/* An odd one out spans the row, so the block stays symmetric instead of
   lopsided — but only when the count IS odd; an even grid keeps its columns. */
.theme-grid button:last-child:nth-child(odd) { grid-column: 1 / -1; }
.theme-grid button { display: flex; align-items: center; gap: 8px; width: 100%; min-width: 0;
    white-space: nowrap;
    background: transparent; color: var(--muted, #8ea7a0); border: 1px solid transparent;
    cursor: pointer; font-family: var(--body); font-weight: 700; font-size: 0.78rem;
    letter-spacing: 0.03em; padding: 7px 10px; border-radius: var(--r-ctl);
    transition: background 0.15s, color 0.15s, border-color 0.15s; }
.theme-grid button:hover { color: var(--ink, #eaf4ee); background: rgba(255,255,255,0.05); }
.theme-grid button.active { color: var(--ink, #eaf4ee);
    background: linear-gradient(180deg, rgba(255,255,255,0.16), rgba(255,255,255,0.08));
    border-color: rgba(255,255,255,0.16);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), 0 3px 8px rgba(0,0,0,0.45); }
.theme-grid button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Palette preview: the theme's ground with its two accents sitting on it. */
.theme-swatch { position: relative; flex: 0 0 auto; width: 22px; height: 16px; border-radius: 5px;
    border: 1px solid rgba(255,255,255,0.18); overflow: hidden; display: block; }
.theme-swatch i { position: absolute; bottom: 3px; width: 6px; height: 6px; border-radius: 50%; }
.theme-swatch i:first-child { left: 3px; }
.theme-swatch i:last-child { right: 3px; }
.set-note { margin: 0; color: var(--muted, #9ab5a8); font-size: 0.76rem; }

@media (max-width: 860px) {
    /* In the hamburger panel: search becomes a full-width row; the gear hides
       and the settings rows show inline (an explicit display beats [hidden]). */
    .nav-search {
        width: 100%; height: auto; min-height: 46px;
        justify-content: flex-start; gap: 10px;
        border-radius: var(--r-ctl); padding: 10px 14px;
        font-size: 1rem; font-weight: 600;
    }
    .nav-search-label { display: inline; font-size: 1rem; font-family: var(--body); letter-spacing: 0; text-transform: none; }
    .nav-gear { display: none; }
    .nav-settings { width: 100%; }
    .nav-settings-menu, .nav-settings-menu[hidden] {
        display: flex; position: static; min-width: 0; width: 100%;
        box-shadow: none; padding: 10px 4px 2px; border: none; border-top: 1px solid var(--line);
        border-radius: 0; background: transparent; animation: none;
    }
}

/* ===== Canonical topbar look (pairs with nav-template.js) =====
   The topbar markup is injected from ONE template on every page; these rules
   (loaded after each page's own stylesheet) make it render identically
   everywhere, whatever the page CSS defines for .topbar/.nav/.unit-toggle. */
/* Full-width on EVERY page — the wordmark sits hard left regardless of window
   width or body class. (It used to be a centered 1180px container, so pages
   without the app-shell override — Dashboard, Training — floated the wordmark
   ~190px inboard on wide monitors.) */
.topbar { display: flex; align-items: center; justify-content: space-between; gap: 10px;
    flex-wrap: wrap; padding: 18px clamp(16px, 2vw, 30px); max-width: none; margin: 0; }
.topbar .wordmark { font-family: var(--display); font-weight: 800; font-size: 1.4rem;
    letter-spacing: 0.02em; color: var(--ink, #eaf4ee); text-decoration: none; }
.topbar .grad { background: linear-gradient(100deg, var(--teal), var(--accent));
    -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.topbar .nav { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.topbar .nav a { color: var(--muted, #8ea7a0); text-decoration: none; font-weight: 600; font-size: 0.92rem;
    padding: 8px 14px; border-radius: var(--r-ctl); transition: color 0.2s ease, background 0.2s ease; }
.topbar .nav a:hover { color: var(--ink, #eaf4ee); background: var(--glass, rgba(255,255,255,0.045)); }
/* No topbar CTA (retired 2026-09-02, TG-290): the doors are the way in and
   the bar's spare room belongs to the search field. The one solid accent per
   view (TG-282) is now the page's own primary verb where it has one (the home
   hero's "Plan a run"); the tool pages run on bordered neutrals. */

/* ===== The terminal topbar (TG-286) =====
   One 44px row on --bg-0 with a hairline under it, and it cannot wrap: the
   eleven items that used to fold into an off-centre second row between 861
   and ~1250px are now three doors — Plan, Courses, Why TrailGoat — plus the
   search field, the gear, the account chip and the one CTA. Small mono caps
   for the doors (the same voice as every label since TG-284); the current page
   wears the accent and a 2px inset underline, and a door whose page is open
   wears the underline on its trigger. The menus underneath keep the ladder
   look from TG-282/283. */
@media (min-width: 861px) {
    .topbar {
        flex-wrap: nowrap; height: 44px; gap: 14px;
        padding-top: 0; padding-bottom: 0;
        background: var(--bg-0); border-bottom: 1px solid var(--line);
    }
    body.split-page > .topbar, body.app-shell > .topbar { padding-top: 0; padding-bottom: 0; }
    .topbar .wordmark { flex: 0 0 auto; font-size: 1.15rem; }
    /* The cluster is also fuel.css's .toggles, which wraps and packs right —
       inside a 44px row a wrapped item would float below the bar. Nowrap
       here, packed from the left; the guard below measures this box too. */
    .topbar-tools {
        display: flex; align-items: center; justify-content: flex-start; gap: 8px;
        flex-wrap: nowrap; flex: 1 1 auto; min-width: 0; height: 44px; margin: 0;
    }
    .topbar .nav.tool-switch {
        display: inline-flex; align-items: stretch; gap: 0; flex: 0 0 auto; height: 44px;
        margin: 0; padding: 0; background: none; border: 0; border-radius: 0;
    }
    .nav-group { display: inline-flex; align-items: stretch; }
    /* The three doors. */
    .topbar .nav > .nav-group > .nav-group-btn, .topbar .nav > a {
        display: inline-flex; align-items: center; height: 44px; padding: 0 11px;
        border-radius: 0; white-space: nowrap;
        font-family: var(--mono); font-weight: 500; font-size: 0.72rem;
        letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted);
        transition: color var(--dur-ctl) var(--ease-snap), background var(--dur-ctl) var(--ease-snap);
    }
    .topbar .nav > .nav-group > .nav-group-btn:hover, .topbar .nav > a:hover,
    .topbar .nav > .nav-group > .nav-group-btn[aria-expanded="true"] {
        color: var(--ink); background: var(--fill-hover);
    }
    /* You are here: accent ink and a 2px inset underline — on the page's own
       link, or on the door it lives behind. No fill, no glow. */
    .topbar .nav > a[aria-current="page"],
    .topbar .nav > .nav-group > .nav-group-btn.nav-group-here {
        color: var(--accent); background: none;
        box-shadow: inset 0 -2px 0 var(--accent);
    }
    .topbar .nav > .nav-group > .nav-group-btn.nav-group-here:hover { background: var(--fill-hover); }
    .topbar .nav-caret { margin-left: 6px; }
    /* Menu rows stay in the body face with the ladder's selected fill. */
    .topbar .nav .nav-group-menu a {
        font-family: var(--body); font-weight: 600; font-size: 0.92rem;
        letter-spacing: 0; text-transform: none; height: auto; padding: 9px 12px;
        border-radius: var(--r-ctl); box-shadow: none; color: var(--muted);
    }
    .topbar .nav .nav-group-menu a:hover { color: var(--ink); background: var(--fill-hover); }
    .topbar .nav .nav-group-menu a[aria-current="page"] { color: var(--accent); background: var(--fill-selected); }
    /* The search field — centred in whatever room the doors and the controls
       leave, labelled with the shortcut that opens it. Wider since the topbar
       CTA went (TG-290): that room was the point of retiring it. */
    .nav-search {
        flex: 0 1 440px; min-width: 0; width: auto; height: 30px; margin: 0 auto;
        justify-content: flex-start; gap: 8px; padding: 0 12px 0 10px;
        color: var(--muted); font-family: var(--mono); font-size: 0.68rem;
        letter-spacing: 0.06em; text-transform: none;
    }
    .nav-search:hover { color: var(--ink); }
    /* The hint inherits 0.68rem from the field — 10.9px of mono, a hair under
       the label floor. It takes the floor for itself; the field's own size
       still governs the icon and the box (TG-301). */
    .nav-search-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
        font-size: max(0.68rem, var(--mono-cap)); }
    .nav-gear { width: 32px; height: 32px; }
    .tg-auth-btn, .tg-auth-chip { flex: 0 0 auto; }
    /* Below ~1080px the field is today's icon button; the same shape is what the
       measured overflow guard (nav.js) falls back to at any width where the bar
       would otherwise spill — say, 861px at 125% zoom with a long account name. */
    .topbar.topbar-tight .nav-search { flex: 0 0 auto; width: 32px; height: 32px; padding: 0; margin: 0 0 0 auto; justify-content: center; }
    .topbar.topbar-tight .nav-search-label { display: none; }
    /* The account chip shows a first name; it may not crowd the search field
       off the bar. Ellipsis past 12 characters, and at the tightest notch the
       chip is the avatar alone. */
    .tg-auth-name { display: inline-block; max-width: 12ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    /* Second notch: the door icons step back and the chip drops its name. */
    .topbar.topbar-tighter .nav > .nav-group > .nav-group-btn .nav-ico { display: none; }
    .topbar.topbar-tighter .tg-auth-chip { padding-right: 5px; }
    .topbar.topbar-tighter .tg-auth-name { display: none; }
}
@media (min-width: 861px) and (max-width: 1079px) {
    .nav-search { flex: 0 0 auto; width: 32px; height: 32px; padding: 0; margin: 0 0 0 auto; justify-content: center; }
    .nav-search-label { display: none; }
}

/* App-shell pages (Race Day's split layout, the Course Creator): the body is a
   flex column, which shrink-wraps the topbar to its content — the wordmark ends
   up bunched against the nav pills in a floating centered cluster. Stretch it
   full-width so space-between lays it out like the landing page: wordmark hard
   left, pills centered, controls right. */
body.split-page > .topbar,
body.app-shell > .topbar { align-self: stretch; width: auto; max-width: none;
    margin-left: 0; margin-right: 0;   /* the shared .topbar's `margin: 0 auto` absorbs the stretch */
    padding-left: clamp(16px, 2vw, 30px); padding-right: clamp(16px, 2vw, 30px); }
/* Unit toggles — inset track + raised neutral key (one look sitewide). */
.unit-toggle { display: inline-flex; gap: 4px; background: rgba(0,0,0,0.35);
    border: 1px solid rgba(255,255,255,0.09); border-radius: var(--r-ctl); padding: 4px;
    box-shadow: var(--well, inset 0 2px 6px rgba(0,0,0,0.5)); }
.unit-toggle button { background: transparent; color: var(--muted, #8ea7a0); border: none; cursor: pointer;
    font-family: var(--body); font-weight: 700; font-size: 0.78rem; letter-spacing: 0.04em;
    padding: 7px 16px; border-radius: calc(var(--r-ctl) - 2px); transition: all 0.15s; }
.unit-toggle button.active { color: var(--ink, #eaf4ee);
    background: linear-gradient(180deg, rgba(255,255,255,0.16), rgba(255,255,255,0.08));
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), 0 3px 8px rgba(0,0,0,0.45); }

/* ===== "About you" inside the settings menu (Race Day, data-athlete) ===== */
.nav-settings-menu { max-height: min(76vh, 640px); overflow-y: auto; }
.set-sec { margin-top: 6px; padding-top: 10px; border-top: 1px solid var(--line, rgba(255,255,255,0.1));
    font-size: 0.88rem; font-weight: 700; }
.set-sec small { display: block; font-weight: 400; font-size: 0.72rem;
    color: var(--muted, #8ea7a0); margin-top: 1px; }
.set-field { display: flex; flex-direction: column; gap: 6px; }
.set-field .field-label { font-size: 0.8rem; font-weight: 600; color: var(--muted, #8ea7a0); }
.set-field .field-label em { font-style: normal; color: var(--muted, #8ea7a0); }
.set-field select, .set-field input[type="number"] {
    width: 100%; background: rgba(0,0,0,0.3); color: var(--ink, #eaf4ee);
    border: 1px solid var(--line, rgba(255,255,255,0.1)); border-radius: var(--r-ctl);
    padding: 8px 10px; font-family: var(--body); font-size: 0.9rem;
    box-shadow: var(--well, inset 0 2px 6px rgba(0,0,0,0.5)); color-scheme: dark;
}

/* "I've measured it" (TG-341) — the escape hatch under each 1-10 slider for a
   runner who has done a sweat test. Deliberately quiet: the slider is still the
   model and this only snaps it, so it reads as a secondary affordance rather
   than a second control. The input has to out-specify the full-width rule
   above, hence `input.` rather than a bare class. */
.slider-measured { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.slider-measured-label { flex: 1 1 auto; font-size: 0.72rem; color: var(--muted, #8ea7a0); }
.set-field input.slider-measured-input { flex: 0 0 88px; width: 88px; padding: 6px 8px;
    font-size: 0.82rem; text-align: right; }
.slider-measured-unit { flex: 0 0 auto; font-style: normal; font-size: 0.72rem;
    color: var(--muted, #8ea7a0); min-width: 46px; }
.set-field select:focus, .set-field input:focus { outline: none; border-color: var(--accent); }

/* ===== Tips (pairs with tg-tips.js, injected sitewide by nav-template.js) ===== */
.tg-info { display: inline-grid; place-items: center; width: 16px; height: 16px;
    padding: 0; border-radius: 50%; border: 1px solid rgba(255,255,255,0.28);
    background: rgba(255,255,255,0.06); color: var(--muted, #8ea7a0);
    font: 700 0.62rem/1 var(--mono); cursor: help;
    vertical-align: -2px; flex: 0 0 auto;
    transition: color 0.15s, border-color 0.15s, background 0.15s; }
.tg-info:hover, .tg-info:focus-visible { color: var(--accent-ink); background: var(--accent);
    border-color: var(--accent); outline: none; }
/* Touch screens: 16px is un-tappable — grow the target (KRI-109). */
@media (pointer: coarse) {
    .tg-info { width: 24px; height: 24px; font-size: 0.72rem; }
}
/* Raised ground, so the tip is the theme's own colour (it was a Forest-green
   literal that read as a stray green box under Tokyo Night). */
#tg-tip { position: fixed; z-index: 9999; max-width: 260px; background: var(--bg-2, #10231e);
    border: 1px solid var(--edge-soft); color: var(--ink, #eaf4ee);
    font-size: 0.78rem; line-height: 1.5; padding: 9px 12px; border-radius: var(--r-card);
    box-shadow: var(--shadow-pop);
    opacity: 0; pointer-events: none; transition: opacity var(--dur-ctl) var(--ease-snap); }
#tg-tip.show { opacity: 1; }
/* Colour legend rows inside a tip (data-tip-legend): dot + label, one per line. */
#tg-tip .tg-tip-legend { list-style: none; margin: 7px 0 0; padding: 7px 0 0;
    border-top: 1px solid var(--line-faint, rgba(255, 255, 255, 0.08)); display: grid; gap: 4px; }
#tg-tip .tg-tip-legend li { display: flex; align-items: center; gap: 8px; }
#tg-tip .tg-tip-legend i { flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%; }
#tg-tip::before { content: ""; position: absolute; top: 100%; left: var(--arrow-x, 50%);
    transform: translateX(-50%); border: 6px solid transparent;
    border-top-color: var(--edge-soft); }
#tg-tip.below::before { top: auto; bottom: 100%; border-top-color: transparent;
    border-bottom-color: var(--edge-soft); }
#tg-pop { position: fixed; z-index: 9999; width: min(280px, calc(100vw - 24px));
    background: var(--bg-1, #0e211c); border: 1px solid var(--edge-soft); border-radius: var(--r-card);
    padding: 14px 32px 14px 16px; box-shadow: var(--shadow-pop);
    font-size: 0.8rem; color: var(--muted, #8ea7a0); line-height: 1.55;
    opacity: 0; pointer-events: none; transition: opacity var(--dur-ctl) var(--ease-snap); }
#tg-pop.show { opacity: 1; pointer-events: auto; }
#tg-pop b { color: var(--ink, #eaf4ee); display: block; margin-bottom: 4px; }
#tg-pop .tg-pop-more { display: block; margin-top: 8px; color: var(--accent);
    font-weight: 600; text-decoration: none; }
#tg-pop .tg-pop-more:hover { text-decoration: underline; }
#tg-pop .tg-pop-x { position: absolute; top: 8px; right: 10px; background: none; border: none;
    color: var(--muted, #8ea7a0); cursor: pointer; font-size: 0.9rem; padding: 2px; }
@media (prefers-reduced-motion: reduce) { #tg-tip, #tg-pop { transition: none; } }

/* First-visit tour styles live in tg-tour.css — tg-tour.js injects that file
   itself, so pages without nav.css (the crew sheet) render tours identically. */

/* Feedback line at the bottom of the settings menu (nav-template.js). */
.set-feedback { display: block; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line);
    font-size: 0.85rem; font-weight: 600; color: var(--accent); text-decoration: none; }
.set-feedback:hover { text-decoration: underline; }

/* ===== Dashboard link in the account chip menu (auth.js) ===== */
.tg-auth-dash { display: block; font-size: 0.9rem; font-weight: 600;
    color: var(--accent); text-decoration: none;
    border: 1px solid var(--line, rgba(255, 255, 255, 0.1));
    border-radius: var(--r-ctl); padding: 9px 12px; margin: 0 0 4px; }
.tg-auth-dash:hover { border-color: var(--edge-soft); background: var(--fill-hover); }
/* Admins get a second row under it into /admin (auth.js draws it only for an
   admin). Ink, not accent: the dashboard link stays the menu's one action. */
.tg-auth-admin { display: flex; align-items: center; gap: 8px; color: var(--ink); margin-top: 6px; }
.tg-auth-admin .ico { width: 16px; height: 16px; flex: none; color: var(--muted); }
/* Every page draws this menu, and not every page loads fuel.css's .ico. */
.tg-auth-admin .ico path { fill: none; stroke: currentColor; stroke-width: 1.75;
    stroke-linecap: round; stroke-linejoin: round; }

/* ===== Site footer (ONE template — filled by nav-template.js) =====
   The page shells only carry <footer class="foot"></footer>; content and
   styling both live with the nav template so every page matches. */
footer.foot { text-align: left; max-width: 1180px; margin: 0 auto; }
.foot-grid { display: grid; grid-template-columns: repeat(var(--foot-cols, 3), 1fr); gap: 28px;
    padding: 30px 8px 22px; border-top: 1px solid var(--line, rgba(255, 255, 255, 0.1)); }
.foot-col h4 { margin: 0 0 10px; font-family: var(--mono); font-size: 0.72rem; font-weight: 500;
    letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink, #eef5ef); }
.foot-link { display: inline-block; color: var(--accent); text-decoration: none;
    font-weight: 600; font-size: 0.92rem; }
/* Footer links are the densest tap targets on the site — a column of them at
   ~20px line boxes, on the screen where a thumb is the only pointer. Padding
   only, at the phone width only, so the desktop footer keeps its rhythm
   (TG-301). */
@media (max-width: 860px) {
    .foot-link { min-height: 40px; display: inline-flex; align-items: center; }
    .foot-legal a, .foot-nav a { min-height: 40px; display: inline-flex; align-items: center; padding: 0 4px; }
}
.foot-link:hover { text-decoration: underline; }
.foot-note { margin: 8px 0 0; font-size: 0.8rem; line-height: 1.5; color: var(--muted, #9ab5a8); }
/* A secondary verb — the ladder's bordered neutral (TG-282). */
.foot-donate { display: inline-flex; align-items: center; gap: 7px;
    font-weight: 700; font-size: 0.92rem; text-decoration: none;
    color: var(--ink);
    background: var(--fill-idle);
    border: 1px solid var(--edge);
    border-radius: var(--r-ctl); padding: 9px 18px;
    transition: background 0.13s ease, border-color 0.13s ease; }
.foot-donate:hover { background: var(--fill-hover); }
.foot-social { display: flex; gap: 10px; }
.foot-soc { display: grid; place-items: center; width: 38px; height: 38px; border-radius: 50%;
    color: var(--muted, #9ab5a8); background: var(--glass, rgba(255, 255, 255, 0.045));
    border: 1px solid var(--line, rgba(255, 255, 255, 0.1)); transition: color 0.15s, border-color 0.15s, transform 0.15s; }
.foot-soc:hover { color: var(--ink, #eef5ef); border-color: var(--edge-soft); background: var(--fill-hover); transform: translateY(-2px); }
.foot-credits { text-align: center; color: var(--muted, #9ab5a8); font-size: 0.8rem;
    padding: 14px 8px 6px; border-top: 1px solid var(--line, rgba(255, 255, 255, 0.06)); }
.foot-credits p { margin: 0; }
@media (max-width: 720px) {
    .foot-grid { grid-template-columns: 1fr; gap: 22px; }
}

/* ===== Offline plans (TG-296) =====
   The per-plan toggle on every plan row, the locked state that is the paid
   layer's clearest shop window, and the storage line. Neutral ladder for the
   control, the one accent on duty when it is on — no second hue, no glow. */
.tg-plan-offline {
    display: inline-flex; align-items: center; gap: 6px;
    margin-top: 6px; padding: 5px 11px;
    background: var(--fill-idle); border: 1px solid var(--edge); border-radius: var(--r-ctl);
    color: var(--muted); cursor: pointer;
    font-family: var(--mono); font-weight: 500; font-size: 0.64rem;
    letter-spacing: 0.1em; text-transform: uppercase;
}
.tg-plan-offline .ico { width: 13px; height: 13px; }
/* Kris requested the existing gold for an incomplete map's retry action. */
.tg-map-retry-label { color: var(--gold); }
@media (max-width: 720px) {
    .tg-plan-offline, .tg-tile-prog .export-btn { min-height: 44px; }
}
.tg-plan-offline:hover:not(:disabled) { background: var(--fill-hover); color: var(--ink); }
.tg-plan-offline:disabled { opacity: 0.55; cursor: default; }
.tg-plan-offline.on { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
/* Locked reads as "not yours yet", not as broken: the same neutral control
   with a padlock. The dialog behind it does the selling. */
.tg-plan-offline.locked::after {
    content: ""; width: 11px; height: 11px; flex: 0 0 auto;
    background: currentColor; opacity: 0.75;
    -webkit-mask: var(--tg-lock) center / contain no-repeat;
    mask: var(--tg-lock) center / contain no-repeat;
}
:root {
    /* Drawn, not an emoji — the brand rule holds in pseudo-elements too. */
    --tg-lock: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="black" d="M12 2a5 5 0 0 0-5 5v3H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8a2 2 0 0 0-2-2h-1V7a5 5 0 0 0-5-5zm-3 8V7a3 3 0 1 1 6 0v3H9z"/></svg>');
}
.tg-offline-lapsed { margin-top: 8px; }
/* The header on the offline plan list: this is a partial view, and saying so
   is the difference between "here are your plans" and "here are the ones you
   can reach right now". */
.tg-plans-offline-head { margin-bottom: 6px; }
.tg-plan-offline:disabled { opacity: 1; }   /* a state, not a dead control */

/* Tile download progress (TG-297). A flat channel and a flat fill — the meter
   treatment, no gloss, no gradient — with the size in the mono figure voice
   every other computed number wears. */
.tg-tile-prog { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.tg-tile-bar {
    flex: 1 1 auto; height: 4px; min-width: 80px;
    background: var(--fill-idle); border-radius: 999px; overflow: hidden;
}
.tg-tile-bar i {
    display: block; height: 100%; width: 0;
    background: var(--accent); transition: width 0.2s linear;
}
.tg-tile-size {
    flex: 0 0 auto; color: var(--muted);
    font-family: var(--mono); font-variant-numeric: tabular-nums;
    font-size: 0.64rem; letter-spacing: 0.06em;
}
@media (prefers-reduced-motion: reduce) { .tg-tile-bar i { transition: none; } }
.tg-offline-lapsed a { color: var(--accent); }

/* Managing a subscription is bookkeeping, not a sell (TG-345), so it reads as
   the link it sits beside rather than as a button — same size, same accent as
   the lapsed note's "See Pro". A <button>, not an <a>, because the destination
   is a single-use URL the server mints on the click. */
.tg-offline-pro { margin-top: 8px; }
.tg-portal-link {
    background: none; border: 0; padding: 0; cursor: pointer;
    font: inherit; color: var(--accent);
}
.tg-portal-link:hover { text-decoration: underline; }
.tg-portal-link:disabled { opacity: 0.6; cursor: default; text-decoration: none; }

.tg-storage-clear {
    flex: 0 0 auto; background: var(--fill-idle); border: 1px solid var(--edge);
    color: var(--ink); border-radius: var(--r-ctl); padding: 7px 15px;
    font: 600 0.82rem/1 var(--body); cursor: pointer;
}
.tg-storage-clear:hover { background: var(--fill-hover); }

/* The weather card's stale stamp: a fact, in the muted ink every other
   parenthetical uses. */
.wx-stale { color: var(--muted); }

/* ===== Offline badge (TG-295) =====
   The app shell loads with no network now, so a page can look completely
   normal while every list on it is empty. The badge is the one place that
   says why. Mono small-caps like every other label since TG-284, on the
   neutral ladder — this is a state, not an alarm, and the one accent on duty
   is spoken for. */
.tg-offline {
    flex: 0 0 auto; align-self: center;
    padding: 3px 8px; border-radius: var(--r-ctl);
    background: var(--fill-idle); border: 1px solid var(--edge); color: var(--muted);
    font-family: var(--mono); font-weight: 500; font-size: 0.62rem;
    letter-spacing: 0.12em; text-transform: uppercase; white-space: nowrap;
}
.tg-offline[hidden] { display: none; }
@media (max-width: 860px) {
    /* Beside the burger rather than in the fold — a state you cannot see is
       not a state that helps. */
    .tg-offline { order: 9; margin-left: auto; }
}

/* ===== Installed-app navigation (TG-294) + the phone tab bar (2026-09-24) =====
   The tab bar is gated on html.tg-tabs AND the phone breakpoint. nav-template.js
   sets tg-tabs on every installed page and, in a browser tab, on the four hub
   pages only (Plan, Courses, Library, Me) — so a desktop at any width, a
   tablet, and every page you arrive at rather than tab to keep the nav they
   already have. The back arrow and the More sheet stay behind
   html.tg-standalone: a browser has its own back button, and the hamburger keeps the long
   tail. Tokens only — no new colours, no glow. */
:root { --tg-tabbar-h: 56px; }

.tg-back { display: none; }
.tg-tabbar, .tg-sheet-scrim { display: none; }

@media (max-width: 860px) {
    html.tg-tabs {
        /* How much room the bar takes, published for anything that has to clear
           it from another stylesheet — tg-tour.css's docked card, today. It is
           declared HERE, inside the same two gates the bar itself is behind, so
           a page that renders no bar (an installed crew sheet, an installed
           tablet) never sees a non-zero value and keeps its own layout. */
        --tg-tabbar-space: calc(var(--tg-tabbar-h) + env(safe-area-inset-bottom, 0px));
    }
    /* Drawing in the Creator: the route toolbar owns the bottom edge, so the
       bar steps aside, and so does everything that clears it (the variable is
       re-declared on body, which every consumer sits inside). */
    html.tg-tabs body.creator-drawing { --tg-tabbar-space: 0px; }
    html.tg-tabs body.creator-drawing .tg-tabbar { display: none; }
    html.tg-tabs body {
        /* The bar is fixed, so the last thing on every page would otherwise sit
           under it. The inset keeps it off the iOS home indicator too. */
        padding-bottom: var(--tg-tabbar-space);
    }

    /* --- The bar --- */
    html.tg-tabs .tg-tabbar {
        position: fixed; left: 0; right: 0; bottom: 0; z-index: 2050;
        display: flex; align-items: stretch;
        height: calc(var(--tg-tabbar-h) + env(safe-area-inset-bottom, 0px));
        padding-bottom: env(safe-area-inset-bottom, 0px);
        background: color-mix(in srgb, var(--bg-0, #07120f) 92%, transparent);
        -webkit-backdrop-filter: blur(14px);
        backdrop-filter: blur(14px);
        border-top: 1px solid var(--line);
    }
    @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
        html.tg-tabs .tg-tabbar { background: var(--bg-0, #07120f); }
    }
    html.tg-tabs .tg-tab {
        flex: 1 1 0; min-width: 0;
        display: flex; flex-direction: column; align-items: center; justify-content: center;
        /* 44px is the floor a thumb needs (Apple HIG, and the WCAG 2.2 target
           size minimum is 24). These measured 43 — the margin was eating the
           bar. The pill still reads inset because the padding, not the margin,
           draws it. */
        min-height: 44px;
        gap: 3px; padding: 6px 2px; margin: 4px 4px;
        position: relative;                 /* anchors the lit tab's rail */
        background: none; border: 1px solid transparent; border-radius: var(--r-ctl);
        color: var(--muted); text-decoration: none; cursor: pointer;
        /* The mono small-caps voice every label has worn since TG-284. */
        font-family: var(--mono); font-weight: 500; font-size: 0.6rem;
        letter-spacing: 0.1em; text-transform: uppercase;
    }
    html.tg-tabs .tg-tab .ico { width: 20px; height: 20px; }
    html.tg-tabs .tg-tab:active { background: var(--fill-hover); }
    html.tg-tabs .tg-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
    /* Lit tab: accent ink plus a rail on the bar's top edge.
       It used to wear the TG-287 gradient ring, but a ring is a BOX, and this
       box sits 4px from the display's left edge and 6px from its bottom — a
       6px corner tucked inside a 47-62px screen corner, which reads as a
       mistake on every rounded phone. The rail carries the same "you are here"
       with no shape near the corner at all, at any radius. The ring stays the
       one-per-view mark everywhere else; the tab bar simply opts out, so
       nav.js no longer arbitrates for it. */
    html.tg-tabs .tg-tab-on { color: var(--accent); }
    html.tg-tabs .tg-tab-on::before {
        content: "";
        position: absolute; top: -6px;      /* the tab's own 6px top margin */
        left: 22%; right: 22%; height: 2px;
        background: var(--accent);
        border-radius: 0 0 2px 2px;
    }

    /* --- The More sheet --- */
    html.tg-standalone .tg-sheet-scrim {
        position: fixed; inset: 0; z-index: 2100;
        display: flex; align-items: flex-end;
        background: rgba(0, 0, 0, 0.45);
    }
    html.tg-standalone .tg-sheet-scrim[hidden] { display: none; }
    html.tg-standalone .tg-sheet {
        width: 100%; max-height: 78dvh; overflow-y: auto;
        display: flex; flex-direction: column; gap: 2px;
        /* Only the home indicator, not the tab bar: the scrim covers the bar
           while the sheet is open, so reserving its height would just be a
           strip of dead space under the last row. */
        padding: 10px 10px calc(10px + env(safe-area-inset-bottom, 0px));
        background: color-mix(in srgb, var(--bg-1, #0a1a1c) 96%, #ffffff 4%);
        border-top: 1px solid var(--line);
        border-radius: var(--r-card) var(--r-card) 0 0;
        transform-origin: bottom center;
        animation: tg-pop-in var(--dur-layer) var(--ease-snap);
    }
    html.tg-standalone .tg-sheet .nav-link {
        display: flex; align-items: center; gap: 10px;
        width: 100%; min-height: 48px; padding: 0 14px;
        background: none; border: 0; border-radius: var(--r-ctl);
        color: var(--ink); text-decoration: none; text-align: left;
        font: 600 0.95rem var(--body); cursor: pointer;
    }
    html.tg-standalone .tg-sheet .nav-link:active { background: var(--fill-hover); }
    html.tg-standalone .tg-sheet .nav-link small { margin-left: 6px; color: var(--muted); font-weight: 500; }

    /* --- The back arrow --- */
    html.tg-standalone .tg-back {
        display: inline-flex; align-items: center; justify-content: center;
        order: -1; flex: 0 0 auto;
        width: 40px; height: 40px; margin: -4px 2px -4px -8px;
        background: transparent; border: 0; border-radius: var(--r-ctl);
        color: var(--ink); cursor: pointer;
    }
    html.tg-standalone .tg-back[hidden] { display: none; }
    html.tg-standalone .tg-back .ico { width: 20px; height: 20px; }
    html.tg-standalone .tg-back:active { background: var(--fill-hover); }
    html.tg-standalone .tg-back:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

    /* The hamburger panel is height-capped against the viewport; the bar eats
       the bottom of it, and a panel that scrolls under the tabs hides its own
       last rows (AC-5 — the nav groups stay reachable). Browser hub pages too. */
    html.tg-tabs .topbar-tools {
        max-height: calc(100dvh - 90px - var(--tg-tabbar-h) - env(safe-area-inset-bottom, 0px));
    }
}

/* ===== Install offer (TG-293) =====
   A dismissible bar on the Dashboard and under a loaded course on the Run
   Planner, plus the permanent row in the settings menu. Neutral ink ladder and
   the one accent on duty — no coloured glow, and the glyphs are drawn SVG, not
   emoji. Class names are `tg-install-*` on purpose: the crew sheet's own offer
   is `.pwa-*`, styled page-locally in crew.html, and the two must not collide
   on the shared assets a sheet pulls from the root. */
.tg-install {
    display: flex; align-items: center; gap: 10px; margin: 0 0 16px;
    background: var(--glass); border: 1px solid var(--line);
    border-radius: var(--r-card); padding: 11px 13px;
}
.tg-install-ico {
    flex: 0 0 auto; width: 18px; height: 18px; fill: none; stroke: var(--accent);
    stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.tg-install-txt { flex: 1 1 auto; font-size: 0.85rem; color: var(--ink); }
.tg-install-go, .tg-install-row-btn {
    flex: 0 0 auto; background: var(--fill-idle); border: 1px solid var(--edge);
    color: var(--ink); border-radius: var(--r-ctl); padding: 7px 15px;
    font: 600 0.82rem/1 var(--body); cursor: pointer;
}
.tg-install-go:hover, .tg-install-row-btn:hover:not(:disabled) { background: var(--fill-hover); }
.tg-install-go:active, .tg-install-row-btn:active:not(:disabled) { background: var(--fill-selected); }
.tg-install-row-btn:disabled { color: var(--muted); cursor: default; }
.tg-install-x {
    flex: 0 0 auto; background: none; border: 0; color: var(--muted);
    font-size: 1.15rem; line-height: 1; cursor: pointer; padding: 2px 4px;
}
.tg-install-x:hover { color: var(--ink); }
/* Inside the installed app there is nothing left to offer. Belt and braces:
   tg-pwa.js already refuses to build the bar when html.tg-standalone is set. */
html.tg-standalone .tg-install { display: none; }

/* ===== Brand mascot as an inline icon =====
   TrailGoat never uses the generic goat emoji — it renders differently on every
   OS and reads as clip-art. This is the drawn mascot (goat-pin.png, the small
   transparent cut — goat.png is the 400 KB hero illustration, hero use only).
   Sized in em so it scales with whatever slot it sits in. */
.tg-goat {
    width: 1.35em; height: 1.35em; object-fit: contain;
    display: inline-block; vertical-align: -0.32em; flex-shrink: 0;
}

/* Footer legal links (About · Privacy) — sit between the grid and credits. */
/* .foot-nav is the crawlable link row each page ships in its served HTML;
   nav-template.js re-renders those same links as .foot-legal once it rebuilds
   the footer (at DOMContentLoaded, so .foot-nav does paint first). Both are
   styled identically so nothing shifts when the swap happens. */
.foot-legal, .foot-nav { display: flex; justify-content: center; align-items: center;
    gap: 10px; flex-wrap: wrap; margin-top: 18px; }
.foot-legal a, .foot-nav a { color: var(--muted); font-size: 12.5px; text-decoration: none; }
.foot-legal a:hover, .foot-nav a:hover { color: var(--accent); }
.foot-legal span { color: var(--muted); opacity: 0.5; font-size: 12px; }

/* ===== Keyboard shortcuts (nav.js — ? anywhere) =====
   The card, head, Esc and phone sheet are the dialog shell's (tg-dialog.css);
   this is only the list inside it. Keys are the mono voice in a
   bordered-neutral cap; group names are .data-label. */
.tg-keys-dlg .tg-dlg-body { padding: 0; }
.tg-keys-body {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 28px;
    padding: 16px 20px 20px;
}
.tg-keys-group h3 { margin: 0 0 8px; font-size: 0.66rem; color: var(--muted); }
.tg-keys-group dl {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px 12px;
    margin: 0; align-items: center;
}
.tg-keys-group dt { font-size: 0.84rem; color: var(--ink); }
.tg-keys-group dd { margin: 0; display: inline-flex; align-items: center; gap: 3px; justify-self: end; }
.tg-keys kbd {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 22px; height: 22px; padding: 0 6px; box-sizing: border-box;
    font: 500 0.7rem/1 var(--mono); color: var(--ink);
    background: var(--fill-idle); border: 1px solid var(--edge-soft);
    border-bottom-width: 2px; border-radius: var(--r-ctl);
}
.tg-keys-then { margin: 0 3px; font-size: 0.7rem; color: var(--muted); }
@media (max-width: 860px) {
    .tg-keys-body { grid-template-columns: minmax(0, 1fr); }
}

/* ===== What's new (nav.js) =====
   The dot rides the wordmark's top-right corner in a 24px hit area (WCAG 2.2
   target minimum) placed absolutely, so showing it never moves the bar. Gold
   is the brand hue outside the feature set; the popover is the palette's card
   on the one entrance. */
.tg-wm-wrap { position: relative; display: inline-flex; align-items: center; flex: 0 0 auto; }
.tg-new-dot {
    position: absolute; top: -10px; right: -16px;
    width: 24px; height: 24px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: none; border: 0; border-radius: 50%; cursor: pointer;
}
.tg-new-dot[hidden] { display: none; }
.tg-new-dot span {
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--gold);
    box-shadow: 0 0 0 2px var(--bg-0);
}
.tg-new-dot:hover span { transform: scale(1.25); }
.tg-new-dot:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; }
.tg-new {
    position: fixed; z-index: 3050;
    background: var(--bg-1); color: var(--ink);
    border: 1px solid var(--line); border-radius: var(--r-card);
    box-shadow: var(--shadow-pop);
    transform-origin: top left;
    animation: tg-pop-in var(--dur-layer) var(--ease-snap);
}
.tg-new[hidden] { display: none; }
.tg-new-head {
    display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
    padding: 12px 14px 10px; border-bottom: 1px solid var(--line);
}
.tg-new-h { font-size: 0.7rem; color: var(--gold); }
.tg-new-when { font-size: 0.72rem; color: var(--muted); }
.tg-new-list { list-style: none; margin: 0; padding: 6px 6px; }
.tg-new-list li { display: flex; align-items: baseline; gap: 10px; padding: 7px 8px; }
.tg-new-date { flex: 0 0 auto; font-size: 0.7rem; color: var(--muted); }
.tg-new-list a, .tg-new-list li > span:last-child {
    color: var(--ink); text-decoration: none; font-weight: 600; font-size: 0.86rem; line-height: 1.35;
}
.tg-new-list a:hover { color: var(--accent); }
.tg-new-foot {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 8px 14px 12px;
}
.tg-new-all { color: var(--accent); font-size: 0.82rem; font-weight: 600; text-underline-offset: 3px; }
.tg-new-ok {
    min-height: 32px; padding: 6px 14px; cursor: pointer;
    background: var(--fill-idle); color: var(--ink);
    border: 1px solid var(--edge); border-radius: var(--r-ctl);
    font: 600 0.8rem/1 var(--body);
}
.tg-new-ok:hover { background: var(--fill-hover); }
.tg-new-ok:active { background: var(--fill-selected); }
@media (pointer: coarse) { .tg-new-ok { min-height: 44px; } }
button.tg-new-all { background: none; border: 0; padding: 6px 0; cursor: pointer; font-family: var(--body); text-decoration: underline; }
/* The full list, in the dialog shell */
.tg-new-full { list-style: none; margin: -6px 0; padding: 0; }
.tg-new-full li {
    display: grid; grid-template-columns: 52px auto minmax(0, 1fr); align-items: baseline; gap: 10px;
    padding: 9px 0; border-bottom: 1px solid var(--line-faint);
}
.tg-new-full li:last-child { border-bottom: 0; }
.tg-new-full a { color: var(--ink); font-weight: 600; font-size: 0.9rem; line-height: 1.35; text-decoration: none; }
.tg-new-full a:hover { color: var(--accent); }
.tg-new-tag {
    font-size: 0.66rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--muted); border: 1px solid var(--line); border-radius: var(--r-ctl); padding: 1px 6px;
}
@media (prefers-reduced-motion: reduce) { .tg-new { animation: none; } }

/* ===== Reduced motion: the layers arrive without arriving (TG-285) =====
   This block sits at the end of the file on purpose. `.tg-pal`, `.tg-auth-menu`
   and `.nav-settings-menu` are all defined further down than the reduced-motion
   block up in the mobile section, so an override placed there loses the cascade
   to their own `animation` declarations — equal specificity, later wins. Keep
   any new arriving layer's suppression here. */
@media (prefers-reduced-motion: reduce) {
    .nav-group-menu,
    .topbar.menu-open .topbar-tools,
    .tg-auth-menu,
    .nav-settings-menu,
    .tg-pal,
    .topbar-mascot.goat-led .topbar-goat { animation: none; }
}

/* Opening a course: the tapped link goes busy until the planner paints (nav.js). */
.tg-opening { opacity: 0.6; pointer-events: none; cursor: progress; }

/* ===== Skip to content (nav-template.js) =====
   Off-screen until it takes focus, then a plain bordered-neutral pill in the
   top-left corner over the bar. Clipped rather than display:none so it stays
   in the tab order; the site-wide :focus-visible ring (tokens.css) marks it. */
.tg-skip {
    position: fixed; top: 8px; left: 8px; z-index: 12000;
    padding: 10px 14px; min-height: 44px; box-sizing: border-box;
    display: inline-flex; align-items: center;
    background: var(--bg-1); color: var(--ink);
    border: 1px solid var(--edge); border-radius: var(--r-ctl);
    font: 600 0.88rem/1 var(--body); text-decoration: none;
    box-shadow: var(--shadow-pop);
    transform: translateY(calc(-100% - 16px));
}
.tg-skip:focus, .tg-skip:focus-visible { transform: none; }

/* ===== Notification bell (nav-template.js markup, nav.js behavior) =====
   An icon button in the bar, signed in only; the dot is the unread state in
   the one accent. The popover is the What's-new card: panel colour, one
   hairline, the pop shadow. Unread rows carry the same accent dot. */
.tg-bell { position: relative; flex: 0 0 auto; display: inline-flex; }
.tg-bell[hidden] { display: none; }
.tg-bell-btn {
    position: relative; display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; padding: 0; cursor: pointer;
    background: none; border: 0; border-radius: var(--r-ctl); color: var(--muted);
    transition: background var(--dur-ctl) var(--ease-snap), color var(--dur-ctl) var(--ease-snap);
}
.tg-bell-btn .ico { width: 19px; height: 19px; }
.tg-bell-btn:hover, .tg-bell-btn[aria-expanded="true"] { background: var(--fill-hover); color: var(--ink); }
.tg-bell-dot {
    position: absolute; top: 8px; right: 9px; width: 8px; height: 8px; border-radius: 50%;
    background: var(--accent); box-shadow: 0 0 0 2px var(--bg-0);
}
.tg-bell-dot[hidden] { display: none; }
.tg-bell-pop {
    position: fixed; z-index: 3050; max-height: min(70vh, 520px); overflow-y: auto;
    background: var(--bg-1); color: var(--ink);
    border: 1px solid var(--line); border-radius: var(--r-card);
    box-shadow: var(--shadow-pop);
    transform-origin: top right;
    animation: tg-pop-in var(--dur-layer) var(--ease-snap);
}
.tg-bell-pop[hidden] { display: none; }
.tg-bell-head {
    position: sticky; top: 0; z-index: 1; background: var(--bg-1);
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 8px 8px 8px 16px; border-bottom: 1px solid var(--line);
}
.tg-bell-h { margin: 0; font-size: 0.7rem; color: var(--muted); outline: none; }
.tg-bell-all {
    min-height: 36px; padding: 6px 10px; cursor: pointer;
    background: none; border: 0; border-radius: var(--r-ctl);
    color: var(--accent); font: 600 0.8rem/1 var(--body);
}
.tg-bell-all:hover { background: var(--fill-hover); }
.tg-bell-list { list-style: none; margin: 0; padding: 6px; }
.tg-bell-list a {
    display: flex; align-items: flex-start; gap: 12px; padding: 10px;
    border-radius: var(--r-ctl); color: var(--ink); text-decoration: none;
}
.tg-bell-list a:hover { background: var(--fill-hover); }
.tg-bell-ico {
    flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px; border-radius: var(--r-ctl);
    background: var(--fill-idle); border: 1px solid var(--line); color: var(--muted);
}
.tg-bell-ico .ico { width: 15px; height: 15px; }
.tg-bell-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.tg-bell-title { font-weight: 600; font-size: 0.88rem; line-height: 1.35; }
.tg-bell-meta { font-size: 0.78rem; color: var(--muted); line-height: 1.35; }
.tg-bell-list li:not(.is-unread) .tg-bell-title { color: var(--muted); font-weight: 500; }
.tg-bell-unread { flex: 0 0 auto; width: 8px; height: 8px; margin-top: 6px; border-radius: 50%; background: var(--accent); }
.tg-bell-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.tg-bell-empty { margin: 0; padding: 16px; color: var(--muted); font-size: 0.86rem; line-height: 1.5; }
@media (max-width: 860px) {
    .tg-bell { order: 9; margin: -4px 0; }
    .tg-bell-btn { width: 44px; height: 44px; }
    .tg-bell-all { min-height: 44px; }
}
@media (prefers-reduced-motion: reduce) { .tg-bell-pop { animation: none; } }
.tg-bell-meta .data { white-space: nowrap; }
/* ===== Empty states and skeletons (shared; polish pass 2026-09-25) =====
   .tg-empty — an empty list as an invitation, the same shape everywhere: the
   goat in a ring, a headline naming what this place will hold, one line, ONE
   primary action (.export-btn.tonal, the ladder's strongest verb here) and one
   quiet alternative. `.is-compact` for dashboard tiles and side panels.
   .tg-skel — the shimmer a list shows while its fetch is pending, drawn in the
   shape of the cards that will replace it (.tg-skel-card); pages show it only
   after 150 ms so a fast answer never flashes. Static under reduced motion. */
.tg-empty { display: flex; flex-direction: column; align-items: center; text-align: center;
    max-width: 440px; margin: 0 auto; padding: 26px 16px 22px; font-style: normal; }
.tg-empty[hidden] { display: none; }
.tg-empty-art { display: grid; place-items: center; width: 60px; height: 60px; margin: 0 0 12px;
    border-radius: 50%; background: var(--fill-idle); border: 1px solid var(--line); }
.tg-empty-art img { width: 36px; height: 36px; object-fit: contain; }
.tg-empty-title { margin: 0; font-family: var(--display); font-weight: 800; font-size: 1.05rem;
    line-height: 1.25; color: var(--ink); text-wrap: balance; }
.tg-empty-line { margin: 6px 0 14px; color: var(--muted); font-size: 0.88rem; line-height: 1.5;
    text-wrap: pretty; }
.tg-empty-go { min-height: 40px; text-decoration: none; }
.tg-empty-go .ico { color: var(--accent); }
.tg-empty-alt { margin: 10px 0 0; color: var(--muted); font-size: 0.84rem; line-height: 1.4; }
.tg-empty-alt a, .tg-empty-alt button { display: inline-flex; align-items: center; min-height: 32px;
    padding: 0; border: 0; background: none; font: inherit; color: var(--accent); cursor: pointer;
    text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--accent) 40%, transparent);
    text-underline-offset: 3px; }
.tg-empty-alt a:hover, .tg-empty-alt button:hover { text-decoration-color: var(--accent); }
.tg-empty-go:focus-visible, .tg-empty-alt a:focus-visible, .tg-empty-alt button:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-ctl); }
.tg-empty.is-compact { padding: 16px 10px 14px; }
.tg-empty.is-compact .tg-empty-art { width: 46px; height: 46px; margin-bottom: 10px; }
.tg-empty.is-compact .tg-empty-art img { width: 28px; height: 28px; }
.tg-empty.is-compact .tg-empty-title { font-size: 0.96rem; }
.tg-empty.is-compact .tg-empty-line { font-size: 0.84rem; margin-bottom: 12px; }
@media (max-width: 860px) {
    .tg-empty-go { min-height: 44px; }
    .tg-empty-alt a, .tg-empty-alt button { min-height: 44px; }
}

.tg-skel { display: block; height: 12px; border-radius: var(--r-ctl);
    background: linear-gradient(90deg, var(--fill-idle) 25%, var(--fill-hover) 50%, var(--fill-idle) 75%);
    background-size: 200% 100%; animation: tg-skel 1.3s ease-in-out infinite; }
.tg-skel.is-title { height: 14px; }
.tg-skel.is-sm { height: 9px; }
.tg-skel.is-chip { height: 18px; width: 56px; flex: 0 0 auto; }
.tg-skel.is-block { height: 34px; }
.tg-skel-list { display: grid; gap: 10px; }
.tg-skel-card { display: grid; gap: 9px; padding: 13px 14px; border: 1px solid var(--line);
    border-radius: var(--r-card); background: var(--glass); }
.tg-skel-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
@keyframes tg-skel { 0% { background-position: 180% 0; } 100% { background-position: -80% 0; } }
@media (prefers-reduced-motion: reduce) {
    .tg-skel { animation: none; background: var(--fill-hover); }
}

/* /race-header.css */
/* Shared race navigation; all palettes come from tokens.css and the theme engine. */
body:has(.race-header) > .topbar { position: sticky; top: 0; z-index: 2000; }
.race-header {
    position: sticky; top: var(--race-topbar-h, 44px); z-index: 1880;
    flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between;
    gap: 16px; padding: 4px clamp(16px, 2vw, 30px);
    color: var(--ink); background: var(--bg-0); border-bottom: 1px solid var(--line);
}
.race-header[hidden] { display: none; }
.race-identity { min-width: 0; }
.race-name { display: block; font: 700 1rem/1.3 var(--display); overflow-wrap: anywhere; }
.race-meta { display: block; margin-top: 3px; font: 400 .82rem/1.5 var(--body); color: var(--muted); }
.race-meta:empty { display: none; }
.race-views {
    flex: 0 0 auto; display: flex; gap: 2px; padding: 2px;
    border: 1px solid var(--line); border-radius: var(--r-ctl); background: var(--bg-well);
}
.race-views a {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 44px; min-width: 88px; padding: 8px 14px;
    border: 1px solid transparent; border-radius: var(--r-ctl);
    font: 700 .85rem/1.3 var(--body); color: var(--muted); text-decoration: none;
    touch-action: manipulation;
}
.race-views a:hover { background: var(--fill-hover); color: var(--ink); }
.race-views a[aria-current="page"] {
    background: var(--fill-selected); color: var(--ink); border-color: var(--edge-soft);
    box-shadow: inset 0 -2px 0 var(--accent);
}
.race-views a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Second state (course page): the hero has scrolled away, so the stats line
   takes the meta line's row and the one action joins the switch. Both are
   display:none until race-header.js adds .race-header-full, so a no-JS page
   (and the Planner, which has neither element) never shows them. */
.race-stats { display: none; margin-top: 3px; gap: 12px; min-width: 0;
    font: 500 .8rem/1.5 var(--mono); font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1;
    color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.race-header-full .race-stats { display: flex; }
.race-header-full .race-meta { display: none; }
.race-stat b { font-weight: 700; color: var(--ink); }
.race-stat .u { margin-left: 3px; font-size: .8em; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; }
@media (max-width: 860px) {
    .race-header { top: var(--race-topbar-h, 73px); gap: 12px; padding: 4px 16px; }
    .race-identity { flex: 1; }
    /* Keep two readable title lines without growing a third navigation tier.
       The full name remains in the accessible text and the page body. */
    .race-name {
        font-size: .875rem; line-height: 1.25;
        display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
        overflow: hidden;
    }
    .race-views { gap: 2px; padding: 0; border: 0; background: transparent; }
    .race-meta { display: none; }
    .race-views a { min-width: 64px; padding: 8px; font-size: .8125rem; }
    /* One line of figures: distance and gain; the date and cutoff are the
       least important here and the hero (a flick up) still has them. */
    .race-stats { gap: 8px; font-size: .75rem; }
    .race-stat-date, .race-stat-cutoff { display: none; }
}
@media print { .race-header { display: none; } }

/* View transitions between Course and Planner (planner-5). The tool pages
   already cross-fade (fuel.css @view-transition); naming the elements the two
   views share — the race header, the course map and the stat tiles — lets them
   hold still (or glide to their new place) while the page underneath swaps,
   so Course | Planner reads as two tabs of one race rather than two loads.
   Both pages carry this sheet, the header, #course-map and #course-stats, so
   the names are set here once and course.html needs no edit. Only while the
   shared header is up (the pair of views exists), and never under reduced
   motion — fuel.css turns the navigation transition off there too. Browsers
   without cross-document view transitions simply navigate. */
@media (prefers-reduced-motion: no-preference) {
    body.has-race-header .race-header { view-transition-name: race-header; }
    body.has-race-header .map-wrap:has(> #course-map) { view-transition-name: race-map; }
    body.has-race-header #course-stats { view-transition-name: race-stats; }
    ::view-transition-group(race-header),
    ::view-transition-group(race-map),
    ::view-transition-group(race-stats) {
        animation-duration: var(--dur-layer, 250ms);
        animation-timing-function: var(--ease-snap, cubic-bezier(0.23, 1, 0.32, 1));
    }
    /* The header is the same bar on both sides: no cross-fade of its label
       swap, it just stays. */
    ::view-transition-old(race-header) { animation: none; opacity: 0; }
    ::view-transition-new(race-header) { animation: none; }
}

/* /launch-beta.css */
/* The launch offer extends the shared shell, palette and typography. */
.tg-launch-note { font: 400 .88rem/1.55 var(--body); color: var(--ink); background: var(--bg-1); border: 1px solid var(--line); border-radius: var(--r-card); padding: 12px 16px; margin: 12px 0; }
.tg-launch-note a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.tg-beta-label { display: none; }
html[data-launch-beta="true"] .tg-beta-label,
html[data-launch-beta="true"] .tg-plan-offline::after { display: inline-block; font: 500 var(--mono-cap)/1.3 var(--mono); text-transform: uppercase; letter-spacing: .05em; color: var(--muted); border: 1px solid var(--edge-soft); border-radius: var(--r-ctl); padding: 2px 5px; margin-left: 6px; }
html[data-launch-beta="true"] .tg-plan-offline::after { content: "Beta"; }
.tg-beta-pricing .pr-grid { margin-top: 24px; }
.tg-beta-pricing .pr-card { background: var(--bg-1); }
.tg-beta-pricing .export-btn { min-height: 44px; }
.tg-beta-pricing .info-tldr { margin: 24px 0; }
.tg-beta-pricing > .info-card { margin-top: 24px; padding: 22px; background: var(--bg-1); border: 1px solid var(--line); border-radius: var(--r-card); }
@media print { .tg-launch-note, .tg-beta-label { display: none !important; } }

html[data-launch-beta="true"] .wordmark .beta-pill { font: 500 var(--mono-cap)/1.3 var(--mono); text-transform: uppercase; letter-spacing: .04em; color: var(--muted); border: 1px solid var(--edge-soft); border-radius: var(--r-ctl); padding: 3px 5px; margin-left: 8px; }

/* Pricing during launch: every price shown, each paid card saying it's free
   until the launch window closes. The line is the accent — it is the offer —
   and sits under the price it qualifies, never in place of it. */
.tg-beta-pricing .pr-launch { font: 600 .84rem/1.4 var(--body); color: var(--accent); margin: -2px 0 12px; }
.tg-beta-pricing .pr-crew-note { color: var(--muted); font-size: .92rem; line-height: 1.5; margin: 14px 2px 0; }
.tg-beta-pricing .pr-dayblock .pr-day { margin-top: 14px; }

