/* stepfox-moto-stats — front-end CSS.
 *
 * THE LAW (SPEC-V2 §1): every visual decision — layout, spacing, typography,
 * colour, border, radius, shadow, hover — is a BLOCK ATTRIBUTE on a core block,
 * rendered by stepfox-looks. Nothing in this file may express one.
 *
 * What is allowed here, and nothing else:
 *   1. state classes our own JS toggles (fx.js / filters.js / fantasy.js)
 *   2. ::before / ::after and @keyframes
 *   3. SVG presentation properties (stroke-width, vector-effect)
 *   4. overflow scroll containers, and the scrollbar the UA draws in them
 *   5. aspect-ratio, where no block attribute reaches the element
 *   6. the :root scheme-class token remap — a runtime palette swap on <html>
 *      that no per-block attribute can perform
 *   7. UA form-control resets (appearance, font:inherit) — a <button> ignores
 *      inherited font, so without these the same block renders two sizes
 *
 * Hard ceiling 250 lines. If you are adding a type size, a typeface, spacing,
 * a gap, a colour, a surface fill, a corner radius, a shadow or a layout
 * display — stop. That is an attribute, and it belongs in the theme.
 */

/* ============================================================ 1. scheme swap
 * moto/scheme-toggle + fx.js put `sfmoto-light` on <html> (pre-painted by
 * stepfox_moto_scheme_preboot() so a light reader never sees a dark flash).
 * Only the PRESET TOKENS are redefined: no element is styled here, so every
 * block keeps rendering from its own attributes and simply resolves them
 * against a light palette. A block attribute cannot do this — it would have to
 * exist twice on every block on the site. */
:root.sfmoto-light {
	--wp--preset--color--base: #f6f5f2;
	--wp--preset--color--panel: #ffffff;
	--wp--preset--color--panel-2: #eeece7;
	--wp--preset--color--line: rgba(10,10,12,0.12);
	--wp--preset--color--ink: #14141a;
	--wp--preset--color--muted: #5c5c68;
	--wp--preset--color--glass: rgba(246,245,242,0.86);
	--wp--preset--color--glass-2: rgba(255,255,255,0.78);
	/* Gold as TEXT only (~2:1 on a near-white panel). `gold` is NOT remapped: it
	   is the medal/ring surface and must stay metallic. */
	--wp--preset--color--gold-ink: #8a6f1c;
	--wp--preset--gradient--scrim: linear-gradient(180deg, rgba(246,245,242,0) 18%, rgba(246,245,242,0.62) 58%, rgba(246,245,242,0.96) 100%);

	/* EVERY gradient that paints a SURFACE flips too. Only `scrim` was listed,
	 * and the design restoration then gave most surfaces a gradient — each with
	 * a dark value baked in (#131317, #1c1c22, rgba(10,10,12,…)). Light mode
	 * left them dark while `ink` went near-black, so the hero, the facts row and
	 * the race-weekend panel rendered black-on-black. The BRAND gradients are
	 * deliberately not redefined: brand, brand-soft, hairline, kerb, accent-wash,
	 * accent-bar, gold-wash and gold-fade are red or gold over transparency and
	 * read on either ground. */
	--wp--preset--gradient--panel-sheen: linear-gradient(163deg, #ffffff 0%, #f7f6f3 46%, #f7f6f3 100%);
	--wp--preset--gradient--panel-sheen-2: linear-gradient(163deg, #ffffff 0%, #eeece7 46%, #eeece7 100%);
	--wp--preset--gradient--gold-crown: linear-gradient(180deg, #f7edd2 0%, #ffffff 62%, #ffffff 100%);
	--wp--preset--gradient--hero-glow: radial-gradient(620px 260px at 8% -20%, rgba(225,6,0,0.10) 0%, rgba(225,6,0,0) 70%), radial-gradient(520px 240px at 100% 120%, rgba(255,59,47,0.07) 0%, rgba(255,59,47,0) 70%), #ffffff;
	--wp--preset--gradient--card-glow: radial-gradient(300px 160px at 50% -30%, rgba(225,6,0,0.12) 0%, rgba(225,6,0,0) 70%), radial-gradient(240px 150px at 100% 4%, rgba(255,59,47,0.09) 0%, rgba(255,59,47,0) 74%), #ffffff;
	--wp--preset--gradient--carbon: repeating-linear-gradient(135deg, rgba(10,10,12,0.05) 0px, rgba(10,10,12,0.05) 7px, rgba(10,10,12,0) 7px, rgba(10,10,12,0) 16px), #eeece7;
	/* The two photo veils invert as well, because the light scheme puts DARK
	   text over photography — the same reason `scrim` above is already flipped. */
	--wp--preset--gradient--hero-scrim: linear-gradient(90deg, rgba(246,245,242,0.95) 0%, rgba(246,245,242,0.78) 42%, rgba(246,245,242,0.15) 100%);
	--wp--preset--gradient--dark-veil: linear-gradient(180deg, rgba(246,245,242,0.25) 0%, rgba(246,245,242,0.72) 60%, rgba(246,245,242,0.94) 100%);

	color-scheme: light;
}

/* =============================================================== 2. motion
 * fx.js adds `sfmoto-fx` to <body> only when it is safe to animate, so a
 * no-JS or reduced-motion render is complete and visible rather than a page of
 * elements waiting for a class. --fxd is the per-item stagger fx.js writes. */
@keyframes sfmoto-in {
	from { opacity: 0; transform: translate3d(0, 14px, 0); }
	to   { opacity: 1; transform: none; }
}

body.sfmoto-fx .sfmoto-reveal {
	opacity: 0;
	will-change: opacity, transform;
}

body.sfmoto-fx .sfmoto-reveal.is-in {
	animation: sfmoto-in 0.52s cubic-bezier(0.2, 0.7, 0.3, 1) both;
	animation-delay: var(--fxd, 0ms);
}

/* Pointer tilt. --rx/--ry are degrees fx.js writes per pointermove. */
body.sfmoto-fx .sfmoto-tilt {
	transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
	transition: transform 0.18s ease-out;
}

@keyframes sfmoto-pulse {
	0%, 100% { opacity: 1; }
	50%      { opacity: 0.45; }
}

.sfmoto-pulse {
	animation: sfmoto-pulse 1.6s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
	body.sfmoto-fx .sfmoto-reveal,
	body.sfmoto-fx .sfmoto-reveal.is-in {
		opacity: 1;
		animation: none;
	}
	body.sfmoto-fx .sfmoto-tilt { transform: none; }
	.sfmoto-pulse { animation: none; }
}

/* ================================================== 3. sortable table state
 * filters.js toggles these on `th.sfmoto-sortable` and on the cells of the
 * active column, and writes the ▲/▼ glyph into .sfmoto-sort-arrow itself. */
.sfmoto-sortable { cursor: pointer; user-select: none; }
.sfmoto-sortable .sfmoto-sort-arrow { opacity: 0.55; }
.sfmoto-sortable.is-sorted .sfmoto-sort-arrow { opacity: 1; }
.is-sorted-col { opacity: 1; }
.sfmoto-sortable:not(.is-sorted) .sfmoto-sort-arrow:empty::after { content: "\2195"; opacity: 0.35; }

/* ==================================================== 4. filtered card grids
 * filters.js hides non-matching cards with the `hidden` attribute; a block
 * that sets `display` in an attribute would otherwise out-specify it. */
.sfmoto-card[hidden],
.sfmoto-noresults[hidden] { display: none !important; }

/* ================================================== 5. scroll containers
 * A wide results table cannot be reflowed by an attribute — it has to scroll
 * inside its own box or it pushes the page sideways on a phone. */
[data-scroll-x] {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
}

[data-scroll-y] {
	overflow-y: auto;
	-webkit-overflow-scrolling: touch;
}

/* Scrollbars. A scroll container must show one and the UA default is a bright
 * grey slab — a hard white seam across the ticker and down the fantasy rail.
 * Scrollbars are painted by the UA, not the box: `color-scheme`,
 * `scrollbar-width` and `::-webkit-scrollbar` are the only handles, and none is
 * a block attribute. `color-scheme: dark` does most of it — the missing half of
 * the `.sfmoto-light` swap in section 1, which set `light` with no counterpart. */
:root {
	color-scheme: dark;
}

/* `.sfmoto-scroll` — a panel the reader is meant to scroll. Slim and quiet,
   resolved against the preset tokens so the light scheme swaps it too. */
.sfmoto-scroll { scrollbar-width: thin; scrollbar-color: var(--wp--preset--color--line) transparent; }
.sfmoto-scroll::-webkit-scrollbar { width: 6px; height: 6px; }
.sfmoto-scroll::-webkit-scrollbar-track { background: transparent; }
.sfmoto-scroll::-webkit-scrollbar-thumb { background-color: var(--wp--preset--color--line); border-radius: 3px; }
.sfmoto-scroll::-webkit-scrollbar-thumb:hover { background-color: var(--wp--preset--color--muted); }

/* There is deliberately NO hide-the-bar class. The ticker had one, and it made
   the strip unusable: a vertical wheel does not scroll a horizontal box, so with
   no bar to drag the chips off the right edge were unreachable with a mouse. */

/* ============================================================ 6. moto/track-svg
 * Presentation attributes on an <svg>. vector-effect is what keeps a 1000-unit
 * viewBox outline the same visual weight at any rendered size, and there is no
 * block attribute that reaches inside the SVG to the <path>. */
.sfmoto-track {
	aspect-ratio: 1 / 1;
	max-width: 100%;
	height: auto;
	color: inherit;
}

.sfmoto-track__path {
	fill: none;
	stroke: currentColor;
	stroke-width: 15;
	vector-effect: non-scaling-stroke;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/* ================================================= 7. moto/countdown state
 * The digits are rewritten every second by the inline ES5 ticker, which finds
 * them by `[data-cd]`. `is-over` / `is-live` are set by the server and by that
 * ticker; everything else about the clock is the theme's attributes. */
.sfmoto-countdown.is-over [data-cd] { opacity: 0.4; }

/* A finished race has no countdown: moto/countdown marks itself `is-over`
   server-side and the clock wrapper collapses off it, because one template
   serves both states. `!important` for the .sfmoto-card[hidden] reason above. */
.sfmoto-clock:has(.sfmoto-cd.is-over) { display: none !important; }

/* ============================================== 8. moto/session-list state
 * Session rows carry server-computed weekend state. Only the state differs —
 * the row itself is styled by the block's attributes. */
.sfmoto-session.is-past { opacity: 0.45; }
.sfmoto-session.is-live { font-weight: 700; }

/* ==================================================== 9. moto/pick (fantasy)
 * ONE rider's control — a <form> wrapping a <button> wrapping the theme's own
 * blocks, repeated by a core/post-template. Appearance is entirely attributes;
 * these rules are pure STATE, which changes after load and so cannot be one.
 *
 * The <form> is a transport wrapper the theme never sees, so it is taken out of
 * the grid's flow: without this each control would be a block-level form box
 * around the chip and the picker would lay out one per row instead of as a grid. */
.sfmoto-pick { display: contents; }
/* A <button> does NOT inherit font. Logged in the control is a <button> and
   logged out an <a>, so the same chip rendered with the UA's 13.333px Arial as
   its inherited base: names wrapped differently and every row sat ~2px taller.
   Neither `appearance` nor `font: inherit` is a block attribute. */
.sfmoto-pick-opt { appearance: none; -webkit-appearance: none; font: inherit; }

.sfmoto-pick.is-saving { opacity: 0.55; pointer-events: none; }
.sfmoto-pick-opt[disabled] { cursor: not-allowed; opacity: 0.5; }
/* The chosen rider: accent outline + a very low-opacity accent fill, so the pick
   reads as FILLED and hover only as ringed — they were near-identical before.
   ACCENT not currentColor (which is the ink, and painted a hard white ring).
   Outline and ::after, never background: the chip's own background and shadow are
   emitted on `#block_<id>`, which out-specifies anything a class can say. */
.sfmoto-pick-opt[aria-pressed="true"] { outline: 2px solid var(--wp--preset--color--accent); outline-offset: -1px; }
.sfmoto-pick-opt[aria-pressed="true"]::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background: rgba(225,6,0,0.10); pointer-events: none; }

/* ================================================= 10. moto/scheme-toggle
 * One button holds both icons; aria-pressed — which fx.js owns — decides which
 * one is on screen. There is no attribute that can reach inside the button. */
.sfmoto-toggle-btn[aria-pressed="false"] .sfmoto-toggle-moon,
.sfmoto-toggle-btn[aria-pressed="true"] .sfmoto-toggle-sun { display: none; }

/* ========================================================= 11. a11y utility
 * Deliberately padding/margin free so it cannot read as styling: the clip-path
 * form takes the element out of flow on its own. */
.screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* Session row — the block's OWN internals, which no theme attribute can reach:
   the <li>'s two spans are emitted inside moto/session-list. Without this the
   label and the time render adjacent and read as "Fri · FP110:45". */
.sfmoto-session {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: 12px;
}
.sfmoto-session__time { white-space: nowrap; }
