/**
 * Sprint Entries — shared front-end design-system foundation.
 *
 * Enqueued (see includes/class-frontend-assets.php) only on pages that
 * actually contain one of this plugin's front-end shortcodes
 * (sse_driver_portal, sse_officials_portal, sse_driver_registration,
 * sse_login, sse_entry_list, sse_drivers_list, and TEMPORARILY
 * sse_holding_home — see class-holding-home.php) — never wp-admin,
 * which is explicitly out of scope for this design system.
 *
 * This file REPLACES every scattered inline <style> echo that used to
 * live in individual PHP files (class-driver-portal.php's print_styles()
 * and class-officials-portal.php's print_styles() — both removed; their
 * rules were carried over here, not run alongside a duplicate copy).
 * Field markup already used identical `.sse-field`/`.sse-field-full`/
 * `.sse-conditional-minor` class names across the whole driver portal
 * (Profile/Vehicles/Registration/My-Registrations) before this pass —
 * keeping those exact names here means those NOT-yet-individually-
 * converted sections automatically pick up the new responsive rules
 * (min 44px controls, label-always-above, spacing scale) without their
 * own PHP/markup needing to change in this pass. Only class-driver-
 * profile.php's markup has actually been converted to the newer
 * .sse-form-panel/.sse-section/.sse-field-row/.sse-btn vocabulary below
 * — every other front-end file still renders its pre-existing markup,
 * which this stylesheet keeps looking correct via the shared class
 * names, not via a second parallel stylesheet.
 *
 * NOTE on the breakpoint: CSS custom properties cannot be referenced
 * inside an @media condition (a CSS spec limitation, not an oversight
 * here) — so 640px below is a literal in every @media rule, kept in
 * sync by hand. It is NOT expressed as --sse-breakpoint because that
 * property would be inert; treat 640px as the single source of truth
 * across this file.
 *
 * NOTE on device target: this file's tokens/rules are still phone-first
 * by default (--sse-control-min-height: 44px, the 640px stacking
 * breakpoint, --sse-input-font-size: 16px against iOS auto-zoom) — that
 * default still applies to Driver Profile, Vehicles, Registration,
 * Login/My Account, and the public Entry List/Drivers List, all of
 * which are genuinely used from a phone. Officials-only screens
 * (everything under sse_officials_portal — My Events, the Meeting
 * editor, Manage Entrants, the paddock screens, Refunds, compose-email)
 * are the one deliberate exception, decided when the selected-to-top
 * Invited Clubs/Classes picker was built: officials predominantly work
 * from a PC or tablet, so full phone-width optimization (44px targets
 * everywhere, .sse-table-responsive stacking) is no longer a hard
 * requirement specifically for that subtree — see README.md for the
 * full scope of this. This is forward-looking only; nothing already
 * converted for phone width there was stripped because of it.
 */

:root {
	/* ---- Sizing ---- */
	--sse-panel-width: 600px;
	--sse-control-min-height: 44px;
	--sse-input-font-size: 16px; /* Never smaller — prevents iOS Safari auto-zoom on focus. */

	/* ---- Spacing scale — used instead of ad hoc per-form padding/margins ---- */
	--sse-space-1: 8px;
	--sse-space-2: 16px;
	--sse-space-3: 24px;
	--sse-space-4: 32px;

	/* ---- Colors — neutral / theme-inheriting today, NOT a branded
	   palette (that is separate, explicitly future work — see README).
	   Every rule in this file references these tokens; none hardcodes a
	   literal color, so a future single-brand palette swap only ever
	   touches this block. ---- */
	--sse-color-text: inherit;
	--sse-color-bg: transparent;
	--sse-color-border: rgba(0, 0, 0, 0.15);
	--sse-color-accent: #333333;
	--sse-color-accent-contrast: #ffffff;
	--sse-color-error: #cc0000;
	--sse-color-error-rgb: 204, 0, 0; /* same color as --sse-color-error, as an r,g,b triplet — plain CSS has no way to derive this from the hex token above, so it's kept as a second property in sync by hand. Exists only so rgba(var(--sse-color-error-rgb), <alpha>) can tint a background with this color (e.g. .sse-btn-danger) without hardcoding a second, unrelated color. */
	--sse-color-success: #2e7d32;
	--sse-color-success-rgb: 46, 125, 50; /* same color as --sse-color-success, as an r,g,b triplet — same reasoning as --sse-color-error-rgb above. */
	--sse-color-warning: #856404; /* NEW (CC restoration task): a genuine third state alongside error(red)/success(green) — a proven, accessible amber-brown warning color, not a repurposed --sse-color-error. .sse-notice-warning (below) is NOT this — it deliberately uses --sse-color-error for a "needs review" banner that reads as seriously as an error; this token is for something genuinely softer: a live, non-blocking "did you mean to type this?" sanity check (see .sse-warning-text below), first used by the CC-too-low check on the Add Vehicle form. */
	--sse-color-stripe: rgba(0, 0, 0, 0.035); /* very light neutral wash for .sse-table-responsive's desktop row striping — same black-wash family as --sse-color-border, at a lower opacity suited to a large-area fill rather than a hairline. */
	--sse-color-notice-border: #cccccc; /* .sse-notice-box's border — deliberately its OWN token, not --sse-color-border: confirmed by direct pixel measurement (canvas getImageData, not assumed) that rgba(0,0,0,0.15) composites to rgb(217,217,217) over a white page background, visibly lighter than this literal #cccccc (204,204,204) — reusing --sse-color-border here would be a real, measurable color change, not the like-for-like migration this token exists to be. */
}

/* =====================================================================
   Form panel — centered 600px on desktop, near-full-width on mobile
   ===================================================================== */

.sse-form-panel {
	max-width: var(--sse-panel-width);
	margin: 0 auto;
	color: var(--sse-color-text);
	background: var(--sse-color-bg);
}

@media (max-width: 639px) {
	.sse-form-panel {
		max-width: 100%;
		padding: 0 var(--sse-space-2);
	}
}

/* =====================================================================
   Sections — visually/semantically grouped form sections
   ===================================================================== */

.sse-section {
	border: 1px solid var(--sse-color-border);
	border-radius: 4px;
	margin: 0 0 var(--sse-space-3) 0;
	padding: var(--sse-space-3);
}

.sse-section > legend {
	font-weight: 600;
	padding: 0 var(--sse-space-1);
}

/* 0.1.67: the warning triangle beside a section legend (driver profile). Shape plus "!" plus hidden text, never
   colour alone (§4). The SVG is aria-hidden; screen readers get .sse-visually-hidden's text. */
.sse-section-flag {
	display: inline-block;
	margin-left: var(--sse-space-1);
	color: var(--sse-color-error);
	vertical-align: -0.2em;
	line-height: 1;
}
.sse-section-flag svg {
	display: block;
}
/* 0.1.69: sse-driver-profile.js hides a triangle once nothing in its section is still flagged. The display above would
   beat the browser's own [hidden] rule (§3), so it needs this exception on the same selector. */
.sse-section-flag[hidden] {
	display: none;
}

/* Text for screen readers only: out of sight, still read aloud. */
.sse-visually-hidden {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* =====================================================================
   Field units — .sse-field is one label+control; label is ALWAYS above
   the control at every width (never beside it, even on desktop — a
   deliberate change from this plugin's earlier side-by-side-label
   layout). .sse-field-row groups two or more .sse-field units to sit
   side-by-side on desktop and stack on mobile.
   ===================================================================== */

.sse-field {
	display: flex;
	flex-direction: column;
	gap: var(--sse-space-1);
	margin-bottom: var(--sse-space-2);
}

/* .sse-field fieldset > legend added 2026-09-16 — Licence type/Licence
   grade's group headings moved from a plain <span> (which matched
   nothing here, and visibly rendered lighter than every other field
   label) to a real <fieldset>/<legend>. Reuses this exact rule rather
   than a second declaration with the same weight copied in, so the two
   forms of "field heading" can never silently drift apart. */
.sse-field > label,
.sse-field fieldset > legend {
	font-weight: 600;
}

/* Resets a nested <fieldset>'s own browser UA-stylesheet defaults
   (border, padding, margin, and — the one that actually causes layout
   shift — min-inline-size: min-content in Chromium, confirmed by real
   measurement to add ~20px of otherwise-invisible overhead) so wrapping
   Licence type/Licence grade's radios in a <fieldset> for a real,
   accessible group name changes nothing about how they're laid out. */
.sse-option-group-fieldset {
	border: 0;
	padding: 0;
	margin: 0;
	min-inline-size: 0;
}

/* 0.1.74: "Who drives first?" on the Register for an event form became a <legend> (it was a <label> linked to nothing).
   A legend keeps the browser's own 2px inline padding, which moved the heading 2px right of where the label drew it;
   this puts it back exactly (the form is measured pixel-for-pixel against the previous release). Scoped to this form:
   the driver profile's licence legends keep that padding, as they always have. */
#sse-registration-form .sse-option-group-fieldset > legend {
	padding: 0;
}

.sse-field-full {
	margin-bottom: var(--sse-space-2);
}

/* 0.1.171: the "I don't have a mobile number" tick (SSE_Driver_Profile::landline_tick_html()). The checkbox is the first
   column; its label and the two hint lines are each a line of their own in the second, so the hints line up with the
   label's text, not under the box. */
.sse-phone-tick {
	display: grid;
	grid-template-columns: auto 1fr;
	column-gap: var(--sse-space-1);
	align-items: center;
}

.sse-phone-tick > input[type="checkbox"] {
	margin: 0;
}

.sse-phone-tick > label,
.sse-phone-tick > .sse-field-hint {
	grid-column: 2;
}

.sse-field input[type="text"],
.sse-field input[type="email"],
.sse-field input[type="tel"],
.sse-field input[type="date"],
.sse-field input[type="number"],
.sse-field input[type="password"],
.sse-field input[type="file"],
.sse-field select,
.sse-field textarea {
	min-height: var(--sse-control-min-height);
	font-size: var(--sse-input-font-size);
	padding: var(--sse-space-1);
	border: 1px solid var(--sse-color-border);
	border-radius: 4px;
	width: 100%;
	box-sizing: border-box;
	color: var(--sse-color-text);
	background: var(--sse-color-bg);
}

.sse-field textarea {
	min-height: calc(var(--sse-control-min-height) * 2);
}

.sse-field-row {
	display: flex;
	flex-direction: column;
	gap: 0 var(--sse-space-2);
}

@media (min-width: 640px) {
	.sse-field-row {
		flex-direction: row;
	}
	.sse-field-row > .sse-field {
		flex: 1;
	}
}

/* The Meeting Editor's Invited Clubs/Classes filter box — deliberately
   NOT wrapped in .sse-field (a <label> beside it, not around it): the
   existing filter script (class-officials-meeting-editor.php) walks
   e.target.parentElement.querySelector(".sse-club-filter"/".sse-class-
   filter") to find the checkbox list to show/hide, so the input's
   parentElement must stay .sse-portal-filter-wrap, the same element
   that directly contains that checkbox-list div — an .sse-field
   wrapper around just the input would break that traversal. This rule
   gives it the same 44px/16px sizing as a real .sse-field text input
   without changing its position in the DOM. */
.sse-portal-filter-input {
	display: block;
	width: 100%;
	box-sizing: border-box;
	min-height: var(--sse-control-min-height);
	font-size: var(--sse-input-font-size);
	padding: var(--sse-space-1);
	margin-bottom: var(--sse-space-2);
	border: 1px solid var(--sse-color-border);
	border-radius: 4px;
	color: var(--sse-color-text);
	background: var(--sse-color-bg);
}

/* 0.1.176: the display: block above would beat [hidden] (§3), and Manage Entrants' "Filter drivers" box is rendered
   hidden until sse-portal-filter.js reveals it -- so with JavaScript off it must really be gone. */
.sse-portal-filter-input[hidden] {
	display: none;
}

/* Radio/checkbox option groups used in place of a <select> for a small
   (3-5 option) fixed choice set — large, thumb-sized targets, label
   always to the right of its own control, options stacked. */
.sse-option-group {
	display: flex;
	flex-direction: column;
	gap: var(--sse-space-1);
}

/* The club/class picker's Selected/Unpicked lists are real <ul>/<li>
   markup (not <div>s, like every other .sse-option-group usage) — a
   real element to move between the two zones is what the picker
   script's DOM-move actually needs. Un-does the browser default <ul>
   indent/margin/bullet so it reads identically to the <div> case. */
ul.sse-option-group {
	margin: 0;
	padding: 0;
	list-style: none;
}

.sse-option-group label {
	display: flex;
	align-items: center;
	gap: var(--sse-space-1);
	min-height: var(--sse-control-min-height);
	padding: 0 var(--sse-space-1);
	border: 1px solid var(--sse-color-border);
	border-radius: 4px;
}

/* Without this, assets/js/sse-portal-filter.js's/sse-meeting-editor-
   picker.js's `label.hidden = true` has no visual effect at all: any
   author-set `display` value (the `display: flex` immediately above)
   always wins over the UA stylesheet's own `[hidden] { display: none }`
   default, regardless of selector specificity -- confirmed live, a real
   Manager typing into the driver filter saw every row stay visible
   despite the JS correctly setting the hidden property/attribute on
   non-matches. This selector's specificity doesn't need to beat the
   rule above on its own merits; author `[hidden]` rules simply need to
   exist for the browser to ever consider hiding an element this way. */
.sse-option-group label[hidden] {
	display: none;
}

/* The rule above correctly zeroes a hidden label's own box, but its
   parent <li> is still a flex ITEM of the .sse-option-group container
   above (flex-direction: column; gap: ...) -- an item's own collapsed
   size doesn't remove it from the flex layout, so `gap` still inserts
   a full gap on both sides of it, one extra blank gap per hidden row.
   Confirmed live: typing a filter that hid several rows left visible
   rows separated by multiples of the normal gap instead of sitting
   flush together. Hiding the <li> itself (not just its label) removes
   it from the flex layout entirely, so `gap` only ever applies between
   rows that are still actually visible. `:has()` is supported by every
   browser this plugin otherwise targets (baseline since ~2023). */
.sse-option-group li:has(> label[hidden]) {
	display: none;
}

.sse-option-group input[type="radio"],
.sse-option-group input[type="checkbox"] {
	width: 20px;
	height: 20px;
	flex-shrink: 0;
}

/* Pure-CSS conditional reveal (e.g. under-18 fields tied to an
   #is_minor checkbox) — the input itself is display:none, not just its
   wrapping element; ancestor-only display:none was found NOT to
   reliably exempt a required descendant from HTML5 constraint
   validation (see class-driver-profile.php's docblock for the full
   incident) — kept here as defense-in-depth, not the sole guarantee:
   this plugin's conditionally-required fields are also always enforced
   server-side. */
.sse-conditional-minor,
.sse-conditional-minor input {
	display: none;
}

.sse-form-panel:has(#is_minor:checked) .sse-conditional-minor {
	display: flex;
}

.sse-form-panel:has(#is_minor:checked) .sse-conditional-minor input {
	display: revert;
}

/* Same pure-CSS conditional reveal as .sse-conditional-minor above (see
   that rule's own comment for the input-level display:none reasoning),
   but reacting to a <select>'s chosen <option> instead of a checked
   checkbox (Vehicles' "NCR Tyre Category" -> "Please specify" detail
   field, class-driver-vehicles.php) — confirmed empirically with a real
   headless-Chromium test that :has(select option[value="X"]:checked)
   reacts correctly and reactively before this was relied on here. */
.sse-conditional-tyres-other,
.sse-conditional-tyres-other input {
	display: none;
}

.sse-form-panel:has(#tyres_blue_book_category option[value="Other"]:checked) .sse-conditional-tyres-other {
	display: flex;
}

.sse-form-panel:has(#tyres_blue_book_category option[value="Other"]:checked) .sse-conditional-tyres-other input {
	display: revert;
}

/* Vehicle Registration type (0.1.51) -- the hint under "Registration number"
   (0.1.155: the plate only; the passport number has its own field and its own
   always-shown hint, .sse-passport-hint) that matches the checked type radio (SSE_Vehicle_Registration::
   render_fields(), shared by the driver Add/Edit Vehicle form and the officials'
   Edit Entry form). Pure CSS, the same :has() mechanism as the NCR Tyre Category
   "Other" reveal above -- NO JavaScript. The hints are plain text, not form
   controls, so hiding them cannot affect constraint validation. With no radio
   checked (never the case: UK is preselected, and a stored type always is) no hint
   shows and nothing is lost. */
.sse-reg-hint {
	display: none;
}

.sse-reg-fields:has(#registration_type_uk:checked) .sse-reg-hint-uk,
.sse-reg-fields:has(#registration_type_foreign:checked) .sse-reg-hint-foreign,
.sse-passport-hint {
	display: block;
}

/* The price line under the registration form's Event dropdown (0.1.55, #sse-price-line, filled by
   assets/js/sse-driver-registration-class-picker.js). Its space is RESERVED from the start, one line of its own
   text tall (0.1.56), so the controls below it no longer jump down when an Event is first chosen. No placeholder text. */
#sse-price-line {
	min-height: 1.5em; /* fallback for a browser without the lh unit */
	min-height: 1lh;
}

/* =====================================================================
   Card grid — two cards side-by-side on wide screens, stacks on phone
   ===================================================================== */

.sse-card-grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--sse-space-2);
}

@media (min-width: 640px) {
	.sse-card-grid {
		grid-template-columns: 1fr 1fr;
	}
}

.sse-card {
	border: 1px solid var(--sse-color-border);
	border-radius: 4px;
	padding: var(--sse-space-2);
}

/* =====================================================================
   Notice boxes — migrated from scattered inline style="..." attributes
   in class-officials-paddock.php/class-officials-refunds.php (flagged
   as outstanding in the README, resolved here). Padding/margin kept as
   literal em values matching exactly what was there before, not
   remapped onto --sse-space-*'s px scale — that scale wasn't what these
   were built against, and forcing them onto it risks a real (if small)
   visual change under a base font-size this file doesn't control,
   which isn't what was asked for here.

   .sse-notice-warning — "needs review" banner, e.g. the second-driver-
   mismatch and same-car/dual-drive warnings. Border color is
   --sse-color-error (#c00 expands to the exact same #cc0000 already
   used there), not a new token — this genuinely is that color, not a
   near-miss.

   .sse-notice-box — plain neutral info card, e.g. each pending-
   withdrawal/closed-reserve entry on the Refunds screen. Uses the
   dedicated --sse-color-notice-border token (see its own :root
   comment for why this ISN'T --sse-color-border).
   ===================================================================== */

.sse-notice-warning {
	border: 2px solid var(--sse-color-error);
	padding: 0.75em 1em;
	margin-bottom: 1em;
}

.sse-notice-box {
	border: 1px solid var(--sse-color-notice-border);
	padding: 0.75em 1em;
	margin-bottom: 1em;
}

/* Two adjacent <form>s meant to sit side by side (e.g. the paddock
   screens' "Import from exchange directory" / "Upload and import"
   pair) rather than stack full-width — also migrated from inline
   style="display:inline-block[; margin-right:2em]". .sse-inline-form-gap
   is applied alongside .sse-inline-form on the FIRST of a pair only,
   to open a gap before its sibling; the last one in a group carries
   just .sse-inline-form. */

.sse-inline-form {
	display: inline-block;
}

.sse-inline-form-gap {
	margin-right: 2em;
}

/* One condensed, single-line-per-zone row on the Officials Portal's Zone
   Overrides section (SSE_Officials_Meeting_Editor::render_zone_overrides_section())
   — deliberately NOT .sse-field (label-always-above, full-width): PC/
   tablet-only screen (see the device-target note at the top of this
   file), Capacity/Fill Order/Start Number are realistically 1-3 digit
   values, so a narrow input with its label immediately before it reads
   as one dense row instead of three stacked full-width fields. Also
   migrated from inline style, same as .sse-inline-form above. */
.sse-zone-override-row {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 0.4em 1em;
	margin-bottom: 0.75em;
}

.sse-zone-override-input {
	width: 3.5em;
}

/* =====================================================================
   Selected-to-top club/class picker — Invited Clubs/Classes, rendered
   by admin/class-admin-associations.php, kept live by
   class-officials-meeting-editor.php's own picker script. Always
   Selected-above-Unpicked, at every width — this isn't a responsive
   two-column layout, the zones are genuinely ordered top-to-bottom by
   design (Selected must stay unbounded/always-visible, Unpicked is the
   one that scrolls). One of the officials-only screens covered by the
   PC/tablet-primary convention (see the note at the top of this file's
   :root block) — .sse-option-group's existing 44px/bordered item
   styling is reused as-is rather than shrunk for density, so this still
   works fine with touch input; just not obligated to go further and
   collapse into a phone-first card layout.
   ===================================================================== */

.sse-picker-selected h4,
.sse-picker-unpicked h4 {
	margin: 0 0 var(--sse-space-1) 0;
	font-size: 0.95em;
	font-weight: 600;
}

.sse-picker-selected-list {
	margin-bottom: var(--sse-space-2);
}

.sse-picker-empty-note {
	margin: 0 0 var(--sse-space-2) 0;
	color: var(--sse-color-text);
	opacity: 0.7;
	font-style: italic;
}

.sse-picker-scroll {
	max-height: 280px;
	overflow-y: auto;
	border: 1px solid var(--sse-color-border);
	border-radius: 4px;
	padding: var(--sse-space-1);
}

/* =====================================================================
   Buttons — large, thumb-sized
   ===================================================================== */

.sse-btn {
	/* inline-flex + align-items/justify-content, not the old
	   inline-block + line-height trick — that trick only centers text
	   correctly when line-height alone is what sets the box's height.
	   Here min-height (44px) is taller than a single line of text wants
	   to be, so min-height won, the content box grew to fill it, and the
	   text stayed top-anchored inside that taller box instead of
	   centering — exactly the reported bug. Flex centering is correct
	   regardless of which of min-height/line-height/padding ends up
	   governing the box's actual height, and box-sizing: border-box
	   means min-height already accounts for padding+border, so this
	   element's rendered height is genuinely 44px, not 44px-plus-padding. */
	display: inline-flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	min-height: var(--sse-control-min-height);
	padding: var(--sse-space-1) var(--sse-space-3);
	font-size: var(--sse-input-font-size);
	font-weight: 600;
	line-height: 1.2;
	color: var(--sse-color-accent-contrast);
	background: var(--sse-color-accent);
	border: 1px solid var(--sse-color-accent);
	/* Rounded-pill shape — a deliberately oversized radius (never
	   reachable at any realistic button size) rather than a computed
	   half-height value, so it self-scales correctly for every .sse-btn
	   variant with no separate override needed: the CSS border-radius
	   spec requires the UA to shrink an oversized radius down to
	   exactly half the box's own (shorter) dimension whenever it would
	   otherwise overlap, which is precisely the pill shape at ANY
	   height — the full-size 44px button and .sse-btn-compact's 28px
	   one both render as a true pill from this one rule, unchanged. */
	border-radius: 9999px;
	cursor: pointer;
	text-align: center;
	text-decoration: none;
}

/* 0.1.99: sse-portal-filter.js hides the officials Meeting selector's "Show" button once it submits on change; the
   inline-flex above would beat the browser's own [hidden] rule (§3), so it needs this exception on the same selector. */
.sse-btn[hidden] {
	display: none;
}

.sse-btn:hover,
.sse-btn:focus {
	opacity: 0.9;
}

.sse-btn-secondary {
	color: var(--sse-color-accent);
	background: var(--sse-color-bg);
}

/* Destructive actions (Delete, etc.) — added in Phase 2 for the
   Vehicles list, but a foreseeable need across every other file with a
   delete action, so it lives here as a foundation variant rather than
   a one-off. A subtle tinted fill (not the base .sse-btn's solid fill)
   reads as a real, clickable button rather than plain colored text,
   while staying visually distinct from a primary action — same red
   used for --sse-color-error throughout, at low opacity via
   --sse-color-error-rgb, not a second hardcoded color. */
.sse-btn-danger {
	color: var(--sse-color-error);
	background: rgba(var(--sse-color-error-rgb), 0.12);
	border-color: var(--sse-color-error);
}

/* Same .sse-btn colors/spacing/shape, sized down for a dense row of
   several buttons together (e.g. Manage Entrants' per-Event withdraw
   links) — only reachable on the officials-only screens covered by
   this file's PC/tablet-primary convention (see the device-target
   note at the top of this file), where the 44px touch-target minimum
   is no longer a hard requirement. Never apply this on a phone-first
   screen (Driver Profile/Vehicles/Registration, Login/My Account, the
   public Entry/Drivers List) — .sse-btn on its own, unmodified, is
   still correct there. */
.sse-btn-compact {
	min-height: 28px;
	padding: 2px var(--sse-space-2);
	font-size: 0.9em;
}

/* A tight inline row of same-sized action buttons sharing one table
   cell (e.g. Manage Entrants' Sat/Sun/Both withdraw choices) — never
   wraps onto a second line, however narrow the cell gets; relies on
   .sse-table-scroll below as the fallback (the table's own container
   scrolls sideways), not on these buttons wrapping. min-width is sized
   to comfortably fit this group's own longest label so every button
   reads as the same size — a short label like "Sat" doesn't look
   cramped next to "Both" a few buttons along. */
.sse-btn-group {
	display: flex;
	flex-wrap: nowrap;
	gap: var(--sse-space-1);
}

.sse-btn-group .sse-btn {
	min-width: 3.5em;
}

/* Plain horizontal-scroll wrapper for a STANDARD (non-.sse-table-
   responsive) table on an officials-only screen — the phone-width
   card-collapse behavior .sse-table-responsive gives other tables
   isn't needed here at all (see the device-target note at the top of
   this file): the table stays a real table at every width, and if it
   ends up wider than the viewport, this wrapper scrolls sideways
   instead of any cell wrapping or collapsing.

   overflow-x: auto alone genuinely works here — confirmed with a real
   headless-Chromium render (not just computed styles): the table
   correctly grows past the wrapper, and scrollLeft is programmatically
   movable. The bug this was investigated for turned out to be neither
   of table-layout:fixed, an errant overflow:hidden, nor the wrapper
   being the wrong element — all three checked directly and ruled out.
   The real fault: scrollbar-width/::-webkit-scrollbar styling (tried
   first) has NO effect on "overlay" scrollbars — confirmed by
   measuring the wrapper's clientHeight/offsetHeight, identical either
   way, meaning no scrollbar space was ever actually being reserved —
   and overlay scrollbars are the DEFAULT in headless Chromium, and
   common on real browsers too (macOS trackpad users, mobile Chrome/
   Safari). On those, an overflowing row has NO visible affordance at
   all: it just looks cut off, indistinguishable from genuinely being
   clipped, with nothing on screen hinting there's more to the right.
   Native scrollbar styling can't be relied on to fix that, so instead:
   an inset shadow on the right edge, independent of whichever
   scrollbar rendering mode the browser/OS is using.

   Originally always-on (a "deliberate simplification": assumed
   harmless on a row that already fits the viewport). Found to be a
   real bug, not harmless, once the officials-portal alignwide/
   alignfull widening (see class-officials-portal.php's own docblock)
   made Manage Entrants' table fit without scrolling at normal desktop
   widths — the shadow kept rendering regardless, a stray vertical bar
   down the right edge of a table that no longer needed it at all,
   confirmed with a real render: scrollWidth === clientWidth (no
   overflow) yet box-shadow computed as fully present either way. CSS
   alone has no way to express "only when this element's content is
   actually wider than its box" (no :has-overflow pseudo-class exists),
   so the shadow itself now lives on this separate,
   NOT-applied-by-default modifier class instead, toggled by this
   plugin's fourth deliberate bit of JS — see
   print_scroll_shadow_script_once() in class-officials-portal.php. */
.sse-table-scroll {
	overflow-x: auto;
}

.sse-table-scroll-overflowing {
	box-shadow: inset -8px 0 6px -6px rgba(0, 0, 0, 0.3);
}

/* Utility: keep one cell's content on a single line regardless of
   column width (e.g. Manage Entrants' Driver name, so "Miss Stacey
   Campbell" never breaks across two lines) — a plain white-space
   override, not tied to any specific table. */
.sse-nowrap {
	white-space: nowrap;
}

/* =====================================================================
   Status badges — a short, colored label for a value that has a small
   fixed set of meaningfully-different states (e.g. Payment status:
   Paid/Pending/Refunded). Same tinted-fill approach as .sse-btn-danger,
   reusing the same tokens, not a one-off for wherever it's first used.
   ===================================================================== */

.sse-badge {
	display: inline-block;
	padding: 2px 8px;
	border-radius: 3px;
	font-size: 0.85em;
	font-weight: 600;
	white-space: nowrap;
}

.sse-badge-success {
	color: var(--sse-color-success);
	background: rgba(var(--sse-color-success-rgb), 0.12);
}

.sse-badge-error {
	color: var(--sse-color-error);
	background: rgba(var(--sse-color-error-rgb), 0.12);
}

.sse-badge-neutral {
	color: var(--sse-color-text);
	background: var(--sse-color-stripe);
}

/* =====================================================================
   Inline validation state — never color alone: an icon/symbol +
   descriptive text always accompanies the color.
   ===================================================================== */

.sse-field-error {
	border-color: var(--sse-color-error) !important;
}

.sse-error-text {
	display: block;
	margin-top: var(--sse-space-1);
	color: var(--sse-color-error);
	font-size: 0.9em;
}

.sse-error-text::before {
	content: "\26A0 "; /* ⚠ — a symbol, not color alone, carries the meaning */
}

/* 0.1.69: the driver profile's script hides an error with [hidden] once the field is completed; display: block above
   would otherwise beat the browser's [hidden] rule (§3). */
.sse-error-text[hidden] {
	display: none;
}

/* 0.1.70: the vehicle lookup's status line (sse-driver-vehicles.js). Empty = no height and no gap; with text it reads
   like the field hints, and takes .sse-success-text / .sse-warning-text for found / not found. */
.sse-vehicle-lookup-status:not(:empty) {
	margin: 0 0 var(--sse-space-3) 0;
	font-size: 0.9em;
}

.sse-success-text {
	display: block;
	margin-top: var(--sse-space-1);
	color: var(--sse-color-success);
	font-size: 0.9em;
}

.sse-success-text::before {
	content: "\2713\00a0"; /* ✓ and a gap -- 0.1.173: the space in "\2713 " only ended the escape, so the text touched the tick */
}

/* The page notice (SSE_Notices::render_page_notice(), 2026-09-19, 0.1.41): one per screen,
   directly under the heading. A redirect lands on #sse-notice; scroll-margin keeps the
   screen's heading visible above it instead of scrolled off the top. */
#sse-notice {
	scroll-margin-top: 6rem;
}

/* NEW (CC restoration task): a genuine third inline state, distinct
   from both of the above — a live, non-blocking sanity-check message
   ("did you mean to type this?"), never a rejection. Same block/
   margin/font-size shape as .sse-error-text/.sse-success-text
   (consistent rhythm when they appear in the same place at different
   times), but its own --sse-color-warning token and its own icon, so
   it can never be mistaken for either a real error or a real success —
   first used by assets/js/sse-driver-vehicles.js's low-CC check. NOT
   the same thing as .sse-notice-warning above, which is a block-level
   "needs review" banner that deliberately uses the SAME red as a real
   error — this is the genuinely softer, inline, per-field state that
   didn't exist anywhere in this stylesheet before. */
.sse-warning-text {
	display: block;
	margin-top: var(--sse-space-1);
	color: var(--sse-color-warning);
	font-size: 0.9em;
}

.sse-warning-text::before {
	content: "\26A0 "; /* ⚠ — same symbol as .sse-error-text, different color, same "never color alone" posture */
}

/* Field-level save-failure redirect targets (My Details / driver profile
   — includes/class-driver-profile.php handle_save()) — a fragment lands
   the driver directly on the field that failed instead of the top of the
   page. --wp-admin--admin-bar--height is WordPress core's own custom
   property (wp-includes/css/admin-bar.css), only ever set on <html> when
   the admin bar is genuinely showing (32px desktop, 46px at core's own
   782px breakpoint) — the 0px fallback here is what applies whenever it
   isn't. Core also sets its own scroll-padding-top tied to the same
   variable, but that's a page-wide fallback with no breathing room of its
   own — this per-target scroll-margin-top is what actually supplies the
   gap below the admin bar (--sse-space-2, the same token used for this
   form's own field spacing elsewhere, not a new magic number) and keeps
   working even on a page where that core stylesheet isn't loaded. */
#field-is_minor,
#field-telephone,
#field-next_of_kin_number,
#field-licence_type_id,
#field-licence_grade_id,
#field-licence_front,
#field-licence_back,
#field-contact_email,
#field-current_password,
#field-name,
#field-address_line_1,
#field-town_city,
#field-postcode,
#field-competition_licence_no,
#field-date_of_birth,
#field-parent_guardian,
#field-parent_guardian_number,
#field-club_membership_id,
#field-club_number,
#field-next_of_kin {
	scroll-margin-top: calc(var(--wp-admin--admin-bar--height, 0px) + var(--sse-space-2));
}

/* =====================================================================
   Responsive table — below the breakpoint, each row's cells become a
   stacked label:value card instead of columns. Opt-in via
   .sse-table-responsive on the <table>; every <td> must carry a
   data-label="Column Name" attribute for the mobile view to show a
   label at all (added per-file as each table is converted).

   Action-cell modifier — data-cell-type="action" on a <td> (alongside
   its data-label, which stays present for markup clarity even though
   it's not rendered): for a cell that's a button (Delete, and future
   ones like Edit) rather than plain data, mobile should show neither a
   "Delete:"-style label prefix nor a label-left/value-right split — the
   button just sits centered on its own full-width row in the card. Only
   affects the mobile (<640px) layout; desktop is completely untouched
   by this attribute, since desktop cells never use the label/flex
   treatment in the first place.

   Desktop layout: real <table>/<tr>/<td> cells, so vertical centering
   is native vertical-align (not flex/align-items — that's the mobile
   card view's mechanism, once td becomes display:flex below 640px).
   vertical-align: middle here is what keeps a wrapped multi-line cell
   (e.g. a long Status message) aligned with its row's single-line
   siblings (Reg/Make/Model/…) and with a .sse-btn action button, whose
   own inline-flex centering (see .sse-btn above) composes cleanly with
   the cell's vertical-align rather than fighting it. The padding bump
   (space-2 vertical, space-3 horizontal) and the even-row stripe below
   are both desktop-only polish — mobile's own media query already
   overrides padding/background for the card view, so nothing here
   needs separate mobile guarding except the stripe rule itself (a
   background-color with no mobile override to naturally neutralize
   it, so it's wrapped in its own min-width query).
   ===================================================================== */

.sse-table-responsive {
	width: 100%;
	border-collapse: collapse;
}

.sse-table-responsive th,
.sse-table-responsive td {
	text-align: left;
	vertical-align: middle;
	padding: var(--sse-space-2) var(--sse-space-3);
	border-bottom: 1px solid var(--sse-color-border);
}

/* "Wide column, optional second line" pattern — for a column too long
   to sit comfortably alongside the others (e.g. a Status message next
   to Reg/Make/Model/Year/CC). Mark its <tr> with class="sse-row-secondary"
   and give it one <td colspan="N" data-label="…"> spanning every real
   column — that <tr> is a genuine sibling row in the DOM (a <tr> can't
   make one of its own cells break onto a second line while its
   siblings stay single-line under plain table layout), but the CSS
   below makes the pair read as one grouped unit: no border between
   them, a lighter/tinted background on the secondary line so it reads
   as less prominent than the primary fields, and (on the mobile card
   view further down) no separate card border/margin of its own — it
   stays inside the SAME card as the row above it. Generic — any future
   table using .sse-table-responsive can mark a wide column the same
   way; nothing here is Vehicles/Status-specific. A row with no
   .sse-row-secondary sibling (the plain, original single-line case)
   is completely unaffected — every rule below only fires in the
   presence of that class. */

.sse-table-responsive tbody tr.sse-row-secondary td {
	background: var(--sse-color-stripe);
	font-size: 0.9em;
}

@media (min-width: 640px) {
	.sse-table-responsive tbody tr:not(.sse-row-secondary):nth-child(even) {
		background: var(--sse-color-stripe);
	}
	/* The primary row of a two-tier group loses its bottom border —
	   the secondary row's own border-bottom (inherited from the base
	   th/td rule above) closes the group instead, so the two rows
	   read as one continuous box rather than two separately-bordered
	   ones. */
	.sse-table-responsive tbody tr:not(.sse-row-secondary):has(+ tr.sse-row-secondary) td {
		border-bottom: none;
	}
}

@media (max-width: 639px) {
	.sse-table-responsive thead {
		display: none;
	}
	.sse-table-responsive,
	.sse-table-responsive tbody,
	.sse-table-responsive tr,
	.sse-table-responsive td {
		display: block;
		width: 100%;
		/* Without this, width:100% is CONTENT width only — tr's own
		   left/right border (1px each) and td's own padding then add on
		   top, pushing the rendered box past its container's true 100%
		   and causing a slight page-level horizontal overflow at narrow
		   viewports (confirmed via real headless-Chromium measurement:
		   ~10px past a 375px viewport). Same fix, same reasoning, as
		   .sse-btn's own box-sizing: border-box above. */
		box-sizing: border-box;
	}
	.sse-table-responsive tbody tr {
		border-left: 1px solid var(--sse-color-border);
		border-right: 1px solid var(--sse-color-border);
		border-top: 1px solid var(--sse-color-border);
		padding: var(--sse-space-1);
	}
	/* Standalone row — no .sse-row-secondary sibling — is the plain,
	   original one-box-per-row case: close the box on every side and
	   leave a gap before the next row's own box. */
	.sse-table-responsive tbody tr:not(.sse-row-secondary):not(:has(+ tr.sse-row-secondary)) {
		border-bottom: 1px solid var(--sse-color-border);
		border-radius: 4px;
		margin-bottom: var(--sse-space-2);
	}
	/* Primary row of a two-tier group — top corners only; no bottom
	   border/margin yet, so it stays visually attached to the
	   secondary row immediately beneath it rather than becoming its
	   own separate card. */
	.sse-table-responsive tbody tr:not(.sse-row-secondary):has(+ tr.sse-row-secondary) {
		border-top-left-radius: 4px;
		border-top-right-radius: 4px;
	}
	/* Secondary row — no top border (flush against the primary row
	   above, so the seam between them disappears), bottom corners +
	   border + the group's margin-bottom close the shared card. Same
	   tinted background as the desktop version, for the same "less
	   prominent, but clearly still this row's data" reasoning. */
	.sse-table-responsive tbody tr.sse-row-secondary {
		border-top: none;
		border-left: 1px solid var(--sse-color-border);
		border-right: 1px solid var(--sse-color-border);
		border-bottom: 1px solid var(--sse-color-border);
		border-bottom-left-radius: 4px;
		border-bottom-right-radius: 4px;
		margin-bottom: var(--sse-space-2);
		padding: var(--sse-space-1);
		padding-top: 0;
	}
	.sse-table-responsive td {
		display: flex;
		justify-content: space-between;
		align-items: center;
		gap: var(--sse-space-2);
		border-bottom: none;
		padding: calc(var(--sse-space-1) / 2) 0;
	}
	.sse-table-responsive td::before {
		content: attr(data-label);
		font-weight: 600;
		margin-right: var(--sse-space-2);
	}
	.sse-table-responsive td[data-cell-type="action"] {
		justify-content: center;
	}
	.sse-table-responsive td[data-cell-type="action"]::before {
		content: none;
		margin-right: 0;
	}
}

/* 0.1.159, My Entries only: on the phone card a value that wraps onto two lines (e.g. "Withdrawn — refunded £153.00")
   kept the cell's text-align: left, so it started at the label while every one-line value sat at the right edge. Right-
   aligned here so a wrapped value lines up with its single-line neighbours. Scoped to .sse-my-entries, not the shared
   rule: Your vehicles' full-width status-message row and the officials' tables wrap longer text that reads better
   left-aligned, and those tables could not all be checked. */
@media (max-width: 639px) {
	.sse-my-entries td {
		text-align: right;
	}
}

/* =====================================================================
   Carried over unchanged from class-officials-portal.php's removed
   print_styles() — same selectors/rules, moved here rather than
   duplicated, so existing officials-portal tables (not yet converted
   to .sse-table-responsive) keep exactly the same density/appearance
   they already had.
   ===================================================================== */

.sse-officials-portal table {
	border-collapse: collapse;
	width: 100%;
	font-size: 0.85em;
}

.sse-officials-portal th,
.sse-officials-portal td {
	padding: 2px 6px;
	line-height: 1.3;
	text-align: left;
}

.sse-officials-portal .sse-class-truncate {
	max-width: 120px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* =====================================================================
   TEMPORARY — [sse_holding_home] (SSE_Holding_Home). DELETE this whole
   block alongside includes/class-holding-home.php once a real homepage
   design replaces it (see that file's own top docblock). Token-only:
   every value below reuses an existing --sse-* token or an existing
   established pattern, nothing new. The muted-note treatment matches
   .sse-picker-empty-note above exactly (color/opacity/italic); the
   small bold label matches .sse-picker-selected/.sse-picker-unpicked's
   own h4 weight/size.

   REVISED 2026-09-16 — the page's own eyebrow line ("Sprint ScimFest
   Entries") was removed (one site name everywhere now — the site
   header already carries it), so .sse-holding-eyebrow was RENAMED to
   .sse-holding-register-label rather than left as dead, unused CSS: the
   exact same rule (same small-bold-label precedent noted above) now
   labels the "New here? Register as…" group instead. .sse-holding-
   register-row is new — the two side-by-side Driver/Official choices
   that group labels, stacking below 640px — and is nothing more than
   .sse-field-row's own existing flex-column/row-at-640px idiom
   (elsewhere in this file) applied to .sse-holding-route children
   instead of .sse-field ones; no new layout mechanism.
   ===================================================================== */

.sse-holding-register-label {
	margin: 0 0 var(--sse-space-1) 0;
	font-size: 0.95em;
	font-weight: 600;
}

.sse-holding-route {
	margin: 0 0 var(--sse-space-3) 0;
}

.sse-holding-route:last-child {
	margin-bottom: 0;
}

.sse-holding-route p:first-child {
	margin: 0 0 var(--sse-space-1) 0;
}

.sse-holding-route p:last-child {
	margin: 0;
}

.sse-holding-register-row {
	display: flex;
	flex-direction: column;
	gap: 0 var(--sse-space-2);
}

@media (min-width: 640px) {
	.sse-holding-register-row {
		flex-direction: row;
	}
	.sse-holding-register-row > .sse-holding-route {
		flex: 1;
	}
}

/* 0.1.73: the driver's quick navigation (SSE_Driver_Portal::render_nav()) on My Details and the home page -- links to
   page 13's own sections, no JavaScript. Stacked full width on a phone (a column stretches its .sse-btn children), one
   wrapping row from 640px. */
.sse-driver-nav {
	display: flex;
	flex-direction: column;
	gap: var(--sse-space-2);
	margin: 0 0 var(--sse-space-3) 0;
}

@media (min-width: 640px) {
	.sse-driver-nav {
		flex-direction: row;
		flex-wrap: wrap;
	}
}

.sse-holding-footer {
	margin: var(--sse-space-3) 0 0 0;
	color: var(--sse-color-text);
	opacity: 0.7;
	font-style: italic;
	font-size: 0.9em;
}

/* =====================================================================
   Licence photo thumbnails — [sse_driver_portal]'s "My Details" page
   (class-driver-profile.php). Token-only, nothing new: the muted
   preview-caption treatment matches .sse-picker-empty-note above
   exactly (color/opacity/italic).

   The 300px width is a fixed cap, not a fluid one, deliberately —
   these are ID documents; letting one stretch to fill a wide desktop
   column would make it needlessly large without helping anyone read
   it. max-width:100% is what actually protects a narrow phone screen
   (the real requirement), 300px only ever matters as an upper bound.

   No resized/thumbnailed copy is ever generated or stored (see
   SSE_Driver_Profile::render_licence_thumb()'s own docblock) — this is
   the stored original, scaled down by these rules alone.
   ===================================================================== */

.sse-licence-thumb-wrap {
	display: block;
	margin-top: var(--sse-space-1);
}

.sse-licence-thumb {
	display: block;
	width: 300px;
	max-width: 100%;
	height: auto;
	border: 1px solid var(--sse-color-border);
	border-radius: 4px;
}

.sse-licence-thumb-caption {
	display: block;
	margin: var(--sse-space-1) 0 0 0;
	color: var(--sse-color-text);
	opacity: 0.7;
	font-style: italic;
	font-size: 0.85em;
}

/* =====================================================================
   0.1.102: the officials' Meeting editor (SSE_Officials_Meeting_Editor) -- one width for every section (a comfortable
   64rem, left-aligned under the heading, instead of a 600px centred details panel beside full-width sections), the
   setup checklist, the weekend-only group, and the collapsed Paddock block.
   ===================================================================== */
.sse-meeting-editor {
	max-width: 64rem;
}
.sse-editor-section > h3:first-child,
.sse-editor-paddock > summary h3 {
	margin-top: 0;
}
/* A save returns to its own section: the page notice is printed at the section's top and the redirect lands on it
   (#sse-notice); this keeps the section's heading in view above it. */
.sse-editor-section #sse-notice {
	scroll-margin-top: 4rem;
}
.sse-editor-checklist p {
	margin: 0 0 var(--sse-space-3) 0;
	line-height: 1.8;
}
/* Words and a warning sign, never colour alone (§4). */
.sse-checklist-missing {
	color: var(--sse-color-error);
	white-space: nowrap;
}
.sse-weekend-only {
	border-left: 3px solid var(--sse-color-border);
	padding-left: var(--sse-space-2);
	margin-bottom: var(--sse-space-2);
}
.sse-weekend-only-limit {
	margin-left: var(--sse-space-3);
}
.sse-editor-paddock > summary {
	cursor: pointer;
}
.sse-editor-paddock > summary h3 {
	display: inline;
	margin-bottom: 0;
}
.sse-editor-paddock[open] > summary {
	margin-bottom: var(--sse-space-2);
}

/* 0.1.107: the Volunteer form's Meeting / day checklist (My officiating) -- one light group per Meeting, its name and dates
   as a small heading over the site's own option list. sse-portal-filter.js hides the whole checklist with [hidden];
   nothing here gives it a display value, so the browser's [hidden] rule holds (§3). */
.sse-volunteer-meeting {
	border-top: 1px solid var(--sse-color-border);
	padding-top: var(--sse-space-2);
	margin-bottom: var(--sse-space-2);
}
.sse-volunteer-meeting h4 {
	margin: 0 0 var(--sse-space-1) 0;
	font-size: 0.95em;
	font-weight: 600;
}

/* 0.1.109: the shared Meeting selector (SSE_Meeting_Selector: the officials portal landing and My officiating) -- the
   site's own field styles (.sse-field: label above a full-width 44px select), capped to a comfortable width on a wide
   page; the "Show past Meetings" toggle a normal-weight labelled checkbox at the option lists' 20px size. */
.sse-meeting-selector {
	max-width: 36rem;
	margin-bottom: var(--sse-space-3);
}
.sse-meeting-toggle > label {
	display: flex;
	align-items: center;
	gap: var(--sse-space-1);
	min-height: var(--sse-control-min-height);
	font-weight: normal;
}
.sse-meeting-toggle input[type="checkbox"] {
	width: 20px;
	height: 20px;
	margin: 0;
	flex-shrink: 0;
}
.sse-meeting-none {
	margin: 0 0 var(--sse-space-2) 0;
}
