/*
 * Tee It Up design tokens — the web surface.
 *
 * The block between the two GENERATED TOKENS markers below is written
 * by `cargo run -p design-tokens --bin generate` from
 * `design/tokens.toml`, the one canonical design source, and must
 * never be hand-edited: `crates/design-tokens/tests/regeneration.rs`
 * fails on any difference, and `tests/cross_surface_audit.rs` fails
 * on any name declared here that the source does not carry. It holds
 * every tier — the palette, the semantic colours in their light forms
 * with the dark forms under `prefers-color-scheme: dark`, the type
 * roles, weights, radii, spacing, sizes, and opacities — and the
 * component contract as `--<treatment>-<part>` custom properties.
 *
 * Hand-written rules go OUTSIDE the block, below the END marker, and
 * consume the custom properties it declares (`var(--colour-accent)`,
 * `var(--primary-button-fill)`) — never a literal colour, size, or
 * radius. There are none yet: the two Leptos applications are unstyled
 * today, and this file is the surface their control rules will read
 * from. Both applications link it through Trunk (`<link data-trunk
 * rel="css" href="../web-common/design.css">` in each `index.html`),
 * so one file serves the player and the admin apps alike.
 */

/* GENERATED TOKENS BEGIN — do not hand-edit; regenerate with `cargo run -p design-tokens --bin generate` from `design/tokens.toml`. */
:root {
	/* ---- Palette (placeholder swatches, exact hex) ---- */
	--colour-white: #ffffff;
	--colour-grey-50: #f5f5f5;
	--colour-grey-100: #f2f2f2;
	--colour-grey-200: #e2e2e2;
	--colour-grey-400: #a3a3a3;
	--colour-grey-500: #6b6b6b;
	--colour-ink-700: #2e2f33;
	--colour-ink-800: #232427;
	--colour-ink-850: #17181a;
	--colour-ink-900: #111111;
	--colour-ink-950: #0b0b0c;
	--colour-blue-500: #3b82f6;
	--colour-blue-600: #2563eb;
	--colour-red-400: #f87171;
	--colour-red-600: #dc2626;
	--colour-green-400: #4ade80;
	/* Replaces the placeholder's original light success swatch,
	   #16a34a, which white text clears by only 3.30:1 — under the
	   4.5:1 text floor (SC 1.4.3). White on this one is 5.02:1. */
	--colour-green-700: #15803d;

	/* ---- Semantic tokens (light forms; the dark forms follow under
	   `prefers-color-scheme: dark`) ---- */
	/* The screen's own background, behind every card. */
	--colour-page: var(--colour-white);
	/* Body text and icons directly on `page`. */
	--colour-foreground: var(--colour-ink-900);
	/* A card, sheet, or field's fill — sits above `page`. */
	--colour-card: var(--colour-white);
	/* Text and icons on `card`. */
	--colour-card-foreground: var(--colour-ink-900);
	/* A nested well inside a card, or a disabled control's ground. */
	--colour-muted: var(--colour-grey-100);
	/* Secondary / de-emphasised text. */
	--colour-muted-foreground: var(--colour-grey-500);
	/* The brand accent — primary actions, links, selected state. */
	--colour-accent: var(--colour-blue-600);
	/* Text and icons on `accent`. */
	--colour-accent-foreground: var(--colour-white);
	/* Destructive actions and error states. */
	--colour-destructive: var(--colour-red-600);
	/* Text and icons on `destructive`. */
	--colour-destructive-foreground: var(--colour-white);
	/* Hairlines: card edges, field outlines, dividers. */
	--colour-border: var(--colour-grey-200);
	/* Focus ring / focused-field outline. */
	--colour-ring: var(--colour-blue-600);
	/* Positive / confirmation states. The light form is the one value
	   in this file that is NOT what the shells rendered before it
	   existed — see `green-700`'s own note. */
	--colour-success: var(--colour-green-700);
	/* Text and icons on `success`. */
	--colour-success-foreground: var(--colour-white);

	/* ---- Typography ---- */
	/* The platform's own face on every surface — SF on iOS, Roboto on
	   Android, the browser's `system-ui` on the web. Type SIZES below
	   are ROLES with a reference size in logical pixels: the shells map
	   each role onto their own type scale (iOS's Dynamic Type styles,
	   Material's type scale), which is platform idiom and deliberately
	   not forced to match — the rendered hierarchy must agree, the code
	   need not. The mapping each shell uses is recorded in
	   `CONTRIBUTING.md`'s "Design tokens" section. */
	--font-body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
	/* Control labels and the empty state's title (iOS `.headline`;
	   Material `titleMedium`). */
	--font-size-headline: 17px;
	/* Row titles, toggle labels, a field's own text (iOS `.body`;
	   Material `bodyLarge`). */
	--font-size-body: 17px;
	/* Row subtitles, state messages, text links, banners, the
	   stepper's caption (iOS `.subheadline`; Material `bodyMedium`). */
	--font-size-subheadline: 15px;
	/* Small print: a toggle's subtitle, a badge (iOS `.caption`;
	   Material `labelMedium`). */
	--font-size-caption: 12px;
	/* The stepper's big value (Material `displaySmall`; iOS has no
	   stepper yet — `.largeTitle` is its nearest rung). */
	--font-size-display: 36px;

	/* ---- Weights ---- */
	/* Plain text: subtitles, messages, links, a field's own text. */
	--weight-regular: 400;
	/* A row's or toggle's title, a badge. */
	--weight-medium: 500;
	/* Control labels and the empty state's title. */
	--weight-semibold: 600;
	/* The stepper's value. */
	--weight-bold: 700;

	/* ---- Radii ---- */
	--radius-field: 14px;
	--radius-panel: 20px;
	/* "Full": the capsule, whatever the control's width. Any radius
	   over half the control's height renders as the capsule, so this
	   is spelt as a number every surface clamps — CSS `border-radius`,
	   SwiftUI's corner radius, and Compose's `RoundedCornerShape(percent
	   = 50)`, which is the same shape by its own spelling. */
	--radius-pill: 999px;

	/* ---- Spacing ---- */
	/* The rungs the components actually use today, in order; a
	   placeholder scale, not a grid. Rung 4 (10) exists for the badge's
	   horizontal inset alone. */
	--space-1: 2px;
	--space-2: 4px;
	--space-3: 8px;
	--space-4: 10px;
	--space-5: 12px;
	--space-6: 16px;
	--space-7: 24px;
	--space-8: 32px;

	/* ---- Sizes ---- */
	/* Fixed dimensions that are neither spacing nor type: the tier the
	   component contract below names for a control's height, an icon's
	   square, and a page's width cap, so no shell carries the raw
	   number. The first three are the control metrics the estate's
	   cross-shell review found diverging, and are what each shell's
	   hand-written `BrandMetrics` still names until the shells read
	   the generated files. */
	/* Every button's minimum height. */
	--size-button-height: 52px;
	/* A field's height. */
	--size-field-height: 56px;
	/* The widest a page's content stretches on a regular-width
	   (tablet) window — keyed on the width the page is GIVEN, never on
	   the device class. */
	--size-page-max-content-width: 600px;
	/* The square of the empty state's icon. */
	--size-state-icon: 40px;
	/* The square of a field's leading icon. iOS frames it at 20;
	   Android today leaves Material's 24 default — the one recorded
	   disagreement on the field, resolved to iOS's explicit value. */
	--size-field-icon: 20px;
	/* The glyph square of an icon button, a banner's icon: Material's
	   own default, recorded so the web and iOS render the same square
	   when they gain the component. */
	--size-icon: 24px;
	/* The width reserved for the stepper's centred value, so the +/-
	   controls do not shift as the digits change. */
	--size-stepper-value: 64px;

	/* ---- Opacities ---- */
	/* How far a disabled control is dimmed. A filled button dims its
	   FILL alone and keeps its label; the secondary button dims as a
	   whole, because a faded fill under a full-strength border reads as
	   enabled. */
	--opacity-disabled: 0.4;
	/* How far a button dims while pressed — iOS's own press feedback;
	   Android has Material's ripple instead, the one recorded
	   platform-idiom difference on the buttons. */
	--opacity-pressed: 0.85;
	/* A state colour washed into a badge's fill behind the same colour
	   as text — the sync-state badge (Android). */
	--opacity-tint: 0.16;
	/* The fainter wash the error banner's fill takes (Android). */
	--opacity-tint-faint: 0.12;

	/* ---- Component contract ---- */

	/* The primary action: a full-width capsule filled with the accent,
	   its label in the accent's foreground. Disabled, the fill dims to
	   `--opacity-disabled` and the label stays; pressed, the whole
	   control dims to `--opacity-pressed`. */
	--primary-button-fill: var(--colour-accent);
	--primary-button-text: var(--colour-accent-foreground);
	--primary-button-radius: var(--radius-pill);
	--primary-button-height: var(--size-button-height);
	--primary-button-label-size: var(--font-size-headline);
	--primary-button-label-weight: var(--weight-semibold);

	/* The secondary action: the same capsule on the card fill with a
	   hairline border, its label in the card's foreground. Disabled,
	   the WHOLE control dims (fill, border, and label together). */
	--secondary-button-fill: var(--colour-card);
	--secondary-button-text: var(--colour-card-foreground);
	--secondary-button-border: var(--colour-border);
	--secondary-button-border-width: 1px;
	--secondary-button-radius: var(--radius-pill);
	--secondary-button-height: var(--size-button-height);
	--secondary-button-label-size: var(--font-size-headline);
	--secondary-button-label-weight: var(--weight-semibold);

	/* A destructive action: the same capsule filled with the
	   destructive colour. Its own treatment rather than a flag on the
	   primary one, so a safe default can never sit on a destructive
	   action. Disabled and pressed as the primary button. */
	--destructive-button-fill: var(--colour-destructive);
	--destructive-button-text: var(--colour-destructive-foreground);
	--destructive-button-radius: var(--radius-pill);
	--destructive-button-height: var(--size-button-height);
	--destructive-button-label-size: var(--font-size-headline);
	--destructive-button-label-weight: var(--weight-semibold);

	/* A single-line text field on the card fill: a leading icon and a
	   label in the muted foreground, the entered text in the card's
	   foreground, a hairline border that becomes the 2px ring while
	   focused — when the icon and the label take the ring colour too.
	   The label's PLACEMENT is platform idiom: an inline placeholder
	   on iOS, Material's floating label on Android. Android also
	   renders an error state (border, icon, label, and a helper line
	   in `destructive`) that iOS has no counterpart to yet. */
	--field-fill: var(--colour-card);
	--field-text: var(--colour-card-foreground);
	--field-border: var(--colour-border);
	--field-border-width: 1px;
	--field-focus: var(--colour-ring);
	--field-focus-width: 2px;
	--field-radius: var(--radius-field);
	--field-height: var(--size-field-height);
	--field-label-size: var(--font-size-body);
	--field-label-weight: var(--weight-regular);
	--field-label-colour: var(--colour-muted-foreground);
	--field-icon-size: var(--size-field-icon);
	--field-icon-colour: var(--colour-muted-foreground);
	--field-padding-horizontal: var(--space-6);

	/* The content panel every form and list section sits on: the card
	   fill with a hairline border and the panel radius, its children
	   stacked on the gap. */
	--card-fill: var(--colour-card);
	--card-text: var(--colour-card-foreground);
	--card-border: var(--colour-border);
	--card-border-width: 1px;
	--card-radius: var(--radius-panel);
	--card-padding-horizontal: var(--space-6);
	--card-padding-vertical: var(--space-6);
	--card-gap: var(--space-5);

	/* One row of a list, on the card fill around it: a medium-weight
	   title in the card's foreground over an optional subtitle in the
	   muted foreground, with a trailing slot. Two recorded
	   disagreements. The inset: Android insets the row 16 by 12; iOS
	   pads 10 vertically inside the list's own insets — Android's
	   reading is named, since the list's inset is what a person sees
	   on iOS. The gap: iOS stacks title and subtitle 2 apart; Android's
	   column stacks them with no arrangement at all (0) — iOS's reading
	   is named, as the one that separates the two lines at all, and it
	   is what rung 1 of the spacing scale exists for. */
	--row-text: var(--colour-card-foreground);
	--row-label-size: var(--font-size-body);
	--row-label-weight: var(--weight-medium);
	--row-label-colour: var(--colour-card-foreground);
	--row-message-size: var(--font-size-subheadline);
	--row-message-weight: var(--weight-regular);
	--row-message-colour: var(--colour-muted-foreground);
	--row-padding-horizontal: var(--space-6);
	--row-padding-vertical: var(--space-5);
	--row-gap: var(--space-1);

	/* The page frame every screen sits in: the page fill, the
	   foreground for text, and a CAP on the content width on a
	   regular-width window. Android's frame also pads its column (24
	   by 16, children 16 apart) where iOS's screens pad themselves —
	   a layout difference, recorded here rather than named. */
	--page-fill: var(--colour-page);
	--page-text: var(--colour-foreground);
	--page-width: var(--size-page-max-content-width);

	/* A named empty state, never a blank screen: a muted icon over a
	   semibold title in the foreground and a muted message, centred in
	   the space it is given. */
	--empty-state-text: var(--colour-muted-foreground);
	--empty-state-title-size: var(--font-size-headline);
	--empty-state-title-weight: var(--weight-semibold);
	--empty-state-title-colour: var(--colour-foreground);
	--empty-state-message-size: var(--font-size-subheadline);
	--empty-state-message-weight: var(--weight-regular);
	--empty-state-message-colour: var(--colour-muted-foreground);
	--empty-state-icon-size: var(--size-state-icon);
	--empty-state-icon-colour: var(--colour-muted-foreground);
	--empty-state-padding-horizontal: var(--space-8);
	--empty-state-padding-vertical: var(--space-8);
	--empty-state-gap: var(--space-5);

	/* A loading indicator tinted with the accent rather than the
	   platform's default. */
	--loading-text: var(--colour-accent);

	/* An inline text action — "Forgot your password?": subheadline
	   text in the accent, no fill, no frame. Its own treatment so a
	   screen never reaches for the platform's own text button and
	   inherits the system tint. */
	--text-link-text: var(--colour-accent);
	--text-link-label-size: var(--font-size-subheadline);
	--text-link-label-weight: var(--weight-regular);

	/* A labelled on/off switch. `fill`, `text`, and `border` are the
	   OFF track, knob, and outline; `selected` is the ON track and
	   knob; the label sits beside the switch on the card fill, over an
	   optional subtitle (iOS only). Android states all six colours;
	   iOS today tints the framework's own Toggle with the accent and
	   inherits the system's off track and white knob — a recorded
	   disagreement, resolved to the stated colours. The outline's
	   width is likewise Android's reading: Material draws the track
	   outline at 2 (its `TrackOutlineWidth`), and iOS draws no outline
	   at all. */
	--toggle-fill: var(--colour-muted);
	--toggle-text: var(--colour-muted-foreground);
	--toggle-selected-fill: var(--colour-accent);
	--toggle-selected-text: var(--colour-accent-foreground);
	--toggle-border: var(--colour-border);
	--toggle-border-width: 2px;
	--toggle-label-size: var(--font-size-body);
	--toggle-label-weight: var(--weight-medium);
	--toggle-label-colour: var(--colour-card-foreground);
	--toggle-message-size: var(--font-size-caption);
	--toggle-message-weight: var(--weight-regular);
	--toggle-message-colour: var(--colour-muted-foreground);

	/* An inline, non-blocking notice — the offline indicator: an icon
	   and a line of text in the muted foreground on the muted fill.
	   Android's warning and error tones swap the text for
	   `destructive` (and the error fill for `destructive` at
	   `--opacity-tint-faint`) — variants this entry does not name.
	   iOS's offline strip runs edge to edge (no radius, 16 by 8, caption
	   text); Android's is a rounded card-inset row — Android's reading is
	   named, as the more general of the two. */
	--banner-fill: var(--colour-muted);
	--banner-text: var(--colour-muted-foreground);
	--banner-radius: var(--radius-field);
	--banner-label-size: var(--font-size-subheadline);
	--banner-label-weight: var(--weight-regular);
	--banner-icon-size: var(--size-icon);
	--banner-icon-colour: var(--colour-muted-foreground);
	--banner-padding-horizontal: var(--space-6);
	--banner-padding-vertical: var(--space-5);

	/* A small capsule label — a round's sync state (Android only
	   today): caption text in the muted foreground on the muted fill.
	   The sync-state variants wash `success` or `destructive` into
	   the fill at `--opacity-tint` with the same colour as text. */
	--badge-fill: var(--colour-muted);
	--badge-text: var(--colour-muted-foreground);
	--badge-radius: var(--radius-pill);
	--badge-label-size: var(--font-size-caption);
	--badge-label-weight: var(--weight-medium);
	--badge-padding-horizontal: var(--space-4);
	--badge-padding-vertical: var(--space-2);

	/* A hairline row separator (Android only today): a border with
	   nothing inside it. */
	--divider-border: var(--colour-border);
	--divider-border-width: 1px;

	/* A bare icon control — the stepper's +/- (Android only today):
	   the glyph in the accent, or the muted foreground while disabled
	   (a tint rather than the buttons' opacity — recorded). */
	--icon-button-text: var(--colour-accent);
	--icon-button-muted: var(--colour-muted-foreground);
	--icon-button-icon-size: var(--size-icon);

	/* A big, fast numeric entry (Android only today): a muted caption
	   over a bold display-size value in the card's foreground, an
	   icon button either side. */
	--stepper-text: var(--colour-card-foreground);
	--stepper-width: var(--size-stepper-value);
	--stepper-label-size: var(--font-size-subheadline);
	--stepper-label-weight: var(--weight-regular);
	--stepper-label-colour: var(--colour-muted-foreground);
	--stepper-title-size: var(--font-size-display);
	--stepper-title-weight: var(--weight-bold);
	--stepper-title-colour: var(--colour-card-foreground);

	/* The bottom tab bar: on the card fill, the selected tab in the
	   accent and the rest in the muted foreground; the selected fill
	   equals the bar's, which hides Material's indicator pill. iOS
	   today tints the framework's TabView with the accent over the
	   system bar material — a recorded disagreement, resolved to the
	   stated colours. */
	--tab-bar-fill: var(--colour-card);
	--tab-bar-text: var(--colour-muted-foreground);
	--tab-bar-selected-fill: var(--colour-card);
	--tab-bar-selected-text: var(--colour-accent);

	/* A back arrow and a title in the foreground (Android only: iOS
	   uses the navigation bar). */
	--screen-header-text: var(--colour-foreground);
	--screen-header-label-size: var(--font-size-body);
	--screen-header-label-weight: var(--weight-regular);
	--screen-header-label-colour: var(--colour-foreground);

	/* A destructive-action confirmation (Android only): the card fill,
	   the title in the card's foreground, the message muted, its
	   buttons the destructive button and the text link. iOS presents
	   the system alert instead, which carries no tokens — the recorded
	   idiom. */
	--confirm-dialog-fill: var(--colour-card);
	--confirm-dialog-text: var(--colour-card-foreground);
	--confirm-dialog-message-size: var(--font-size-subheadline);
	--confirm-dialog-message-weight: var(--weight-regular);
	--confirm-dialog-message-colour: var(--colour-muted-foreground);

	/* A pull-to-refresh list of rows on the card fill, the system's own
	   list chrome hidden (iOS only: Android's lists sit directly on
	   the page or a card). */
	--list-fill: var(--colour-card);
}

@media (prefers-color-scheme: dark) {
	:root {
		--colour-page: var(--colour-ink-950);
		--colour-foreground: var(--colour-grey-50);
		--colour-card: var(--colour-ink-850);
		--colour-card-foreground: var(--colour-grey-50);
		--colour-muted: var(--colour-ink-800);
		--colour-muted-foreground: var(--colour-grey-400);
		--colour-accent: var(--colour-blue-500);
		--colour-accent-foreground: var(--colour-ink-950);
		--colour-destructive: var(--colour-red-400);
		--colour-destructive-foreground: var(--colour-ink-950);
		--colour-border: var(--colour-ink-700);
		--colour-ring: var(--colour-blue-500);
		--colour-success: var(--colour-green-400);
		--colour-success-foreground: var(--colour-ink-950);
	}
}
/* GENERATED TOKENS END */
