@import "tailwindcss"; /* Bloomberg-terminal aesthetic: dense, dark, monospace, keyboard-first. Tailwind v4 — design tokens live here in @theme (no tailwind.config.js). The booth runs on a fixed appliance display; we optimise for a dark room, glanceable status colour, and high information density over whitespace. Token vocabulary adopted from the "TRM" design system (Tracking & Race Management) — TOKENS ONLY: colours, type scale, spacing, radii, shadows. None of TRM's race-timing components are used. The existing `term-*` accents are aligned onto TRM's exact values so the whole booth UI inherits the TRM palette without renaming a single class. TRM's full vocabulary is also exposed as utilities (night-*, ink-*, paper-*, flag/amber/green/blue, the spacing/type/shadow scales) for new work. Offline appliance: NO webfont @import (no network at runtime). Goldplay (the TRM display face) is not self-hosted yet — display/heading text falls back to a clean sans stack; wire local Goldplay @font-face here if it's wanted. */ @theme { /* ============================================================ TERMINAL ACCENTS — aligned onto TRM's exact values. These keep their `term-*` names (used across every screen), but now resolve to TRM colours so the palette is unified. ============================================================ */ /* Surfaces — TRM "night" (trackside dark) scale. */ --color-term-bg: #0b0d10; /* TRM --night */ --color-term-panel: #14171c; /* TRM --night-2 */ --color-term-panel-2: #1e222a; /* TRM --night-3 */ --color-term-border: #2a2f38; /* TRM --night-line */ --color-term-muted: #8a8a82; /* TRM --night-fg-3 / --ink-4 */ --color-term-text: #f2f2ee; /* TRM --night-fg */ /* Status accents — TRM semantic colours. */ --color-term-amber: #f2a516; /* TRM --amber (caution / accent / focus) */ --color-term-green: #2e8c4a; /* TRM --green (entry / ok / free) */ --color-term-red: #e8412b; /* TRM --flag (exit / fault / full) */ --color-term-cyan: #2563c8; /* TRM --blue (payment / info / live) */ /* ============================================================ TRM FULL VOCABULARY — exposed as Tailwind utilities for new work. ============================================================ */ /* Ink & paper (light surfaces — for any light-on-dark inversions). */ --color-paper: #fafaf7; --color-paper-2: #f2f2ee; --color-paper-3: #e8e8e2; --color-ink: #0e0e0c; --color-ink-2: #2a2a26; --color-ink-3: #5a5a53; --color-ink-4: #8a8a82; --color-ink-5: #b8b8b0; --color-ink-6: #dcdcd4; /* Night scale (the booth's working surfaces). */ --color-night: #0b0d10; --color-night-2: #14171c; --color-night-3: #1e222a; --color-night-line: #2a2f38; --color-night-fg: #f2f2ee; --color-night-fg-2: #b8b8b0; --color-night-fg-3: #8a8a82; /* Race accents + semantic. */ --color-flag: #e8412b; --color-flag-2: #c8331f; --color-flag-tint: #fbe3de; --color-amber: #f2a516; --color-amber-2: #c88500; --color-amber-tint: #fbefd0; --color-green: #2e8c4a; --color-green-2: #1f6a36; --color-green-tint: #ddefe2; --color-blue: #2563c8; --color-blue-2: #1a4fa8; --color-blue-tint: #dce6f8; --color-violet: #6b46c1; --color-magenta: #c9296f; --color-teal: #188c8a; --color-ok: #2e8c4a; --color-warn: #f2a516; --color-danger: #e8412b; --color-info: #2563c8; /* Data-viz categorical (8). */ --color-viz-1: #e8412b; --color-viz-2: #2563c8; --color-viz-3: #2e8c4a; --color-viz-4: #f2a516; --color-viz-5: #6b46c1; --color-viz-6: #188c8a; --color-viz-7: #c9296f; --color-viz-8: #5a5a53; /* ---------- TYPE — families ---------- */ /* Mono is the booth's primary face (data-dense, tabular). Display/UI fall back to a clean sans (Goldplay not self-hosted — see header note). */ --font-mono: "JetBrains Mono", "IBM Plex Mono", ui-monospace, "SFMono-Regular", "Menlo", "Consolas", monospace; --font-display: "Goldplay", "Helvetica Neue", Arial, sans-serif; --font-ui: "Goldplay", "Helvetica Neue", Arial, sans-serif; --font-body: "Inter", "Helvetica Neue", Arial, sans-serif; /* ---------- TYPE — scale (TRM, optimised for data density) ---------- */ --text-overline: 11px; --text-micro: 12px; --text-small: 13px; --text-body: 15px; --text-lead: 17px; --text-h6: 14px; --text-h5: 16px; --text-h4: 20px; --text-h3: 26px; --text-h2: 34px; --text-h1: 48px; --text-display: 72px; --text-jumbo: 120px; /* ---------- SPACING (TRM 4px base) ---------- */ --spacing-s0: 0; --spacing-s1: 2px; --spacing-s2: 4px; --spacing-s3: 8px; --spacing-s4: 12px; --spacing-s5: 16px; --spacing-s6: 20px; --spacing-s7: 24px; --spacing-s8: 32px; --spacing-s9: 40px; --spacing-s10: 48px; --spacing-s11: 64px; --spacing-s12: 80px; --spacing-s13: 96px; /* ---------- RADIUS — TRM is square-edged ---------- */ --radius-term: 2px; /* existing alias, kept */ --radius-r0: 0; --radius-r1: 2px; --radius-r2: 4px; --radius-r3: 6px; --radius-r4: 10px; /* ---------- ELEVATION — TRM sharp "printed" offset shadows ---------- */ --shadow-term-1: 0 1px 0 0 #0e0e0c; --shadow-term-2: 2px 2px 0 0 #0e0e0c; --shadow-term-3: 4px 4px 0 0 #0e0e0c; --shadow-soft: 0 1px 2px rgba(14, 14, 12, 0.06), 0 4px 12px rgba(14, 14, 12, 0.04); --shadow-pop: 0 8px 24px rgba(14, 14, 12, 0.12); /* ---------- MOTION (TRM) ---------- */ --ease-snap: cubic-bezier(0.2, 0.8, 0.2, 1); --ease-out: cubic-bezier(0.16, 1, 0.3, 1); /* ---------- COMPONENT TOKENS (TRM control heights, table rows) ---------- */ --control-h-sm: 28px; --control-h-md: 36px; --control-h-lg: 44px; --table-row-h: 36px; --table-row-h-dense: 28px; } html, body, #root { height: 100%; } body { margin: 0; background: var(--color-term-bg); color: var(--color-term-text); font-family: var(--font-mono); font-size: 13px; line-height: 1.4; -webkit-font-smoothing: antialiased; /* Crisp text and no rubber-banding on the fixed appliance display. */ overscroll-behavior: none; } /* Tabular numerics everywhere — counts, money, clocks must not jitter. */ .num, .tabular { font-variant-numeric: tabular-nums; letter-spacing: -0.01em; } /* Terminal scrollbars — thin, dark, unobtrusive. */ * { scrollbar-width: thin; scrollbar-color: var(--color-term-border) transparent; } /* A visible keyboard-focus ring in the amber accent (keyboard-first UI). */ :focus-visible { outline: 1px solid var(--color-term-amber); outline-offset: 1px; } /* ============================================================ COMPONENT LAYER The TRM tokens are good, but every screen hand-rolled inputs and buttons as bare outlines on near-black panels, so a field, a card, and a button were visually indistinguishable. These classes give each control a real identity: - inputs read as RECESSED slots (lighter fill + inset shadow) - the primary button is FILLED (accent body, dark text) — the one obvious action; neutrals are filled grey, not bare outlines - explicit hover / active / focus / disabled states everywhere Use @apply so the classes compose with Tailwind utilities. ============================================================ */ @layer components { /* ---- Form fields: a recessed slot, clearly an input ---- */ .input, .select, .textarea { @apply w-full rounded-term border bg-term-bg px-2.5 text-term-text placeholder:text-term-muted; border-color: #3a414c; /* lighter than panel borders */ height: var(--control-h-md); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.45); transition: border-color 120ms var(--ease-snap), box-shadow 120ms var(--ease-snap); } .textarea { height: auto; @apply py-2 leading-snug; } .input::placeholder, .textarea::placeholder { @apply text-term-muted; } .input:hover, .select:hover, .textarea:hover { border-color: #4a525f; } .input:focus, .select:focus, .textarea:focus { outline: none; border-color: var(--color-term-amber); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.45), 0 0 0 1px var(--color-term-amber); } .input:disabled, .select:disabled, .textarea:disabled { @apply cursor-not-allowed opacity-50; } /* Small / dense variant for inline table cells */ .input-sm { height: var(--control-h-sm); @apply px-2 text-[12px]; } .field { @apply flex flex-col gap-1; } .label { @apply text-[11px] uppercase tracking-wider text-term-muted; } .hint { @apply text-[11px] leading-snug text-term-muted; } /* ---- Buttons: a button must look pressable, never like a field ---- */ .btn { @apply inline-flex items-center justify-center gap-1.5 rounded-term border px-3 text-[12px] font-semibold uppercase tracking-wider transition-colors select-none; height: var(--control-h-md); /* Neutral default: a filled grey body, not a bare outline. */ background: var(--color-term-panel-2); border-color: #3a414c; color: var(--color-term-text); } .btn:hover:not(:disabled) { background: #2a313b; border-color: #4a525f; } .btn:active:not(:disabled) { transform: translateY(1px); } .btn:disabled { @apply cursor-not-allowed opacity-40; } .btn-sm { height: var(--control-h-sm); @apply px-2.5 text-[11px]; } .btn-lg { height: var(--control-h-lg); @apply px-5 text-[13px]; } /* Primary: FILLED amber, dark text — the unmistakable main action. */ .btn-primary { background: var(--color-term-amber); border-color: var(--color-term-amber); color: #0b0d10; } .btn-primary:hover:not(:disabled) { background: #ffb733; border-color: #ffb733; } /* Semantic filled variants (entry / payment / destructive). */ .btn-go { background: var(--color-term-green); border-color: var(--color-term-green); color: #f2f2ee; } .btn-go:hover:not(:disabled) { background: #38a85a; border-color: #38a85a; } .btn-pay { background: var(--color-term-cyan); border-color: var(--color-term-cyan); color: #f2f2ee; } .btn-pay:hover:not(:disabled) { background: #2f74e0; border-color: #2f74e0; } .btn-danger { background: transparent; border-color: var(--color-term-red); color: var(--color-term-red); } .btn-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--color-term-red) 14%, transparent); } /* Ghost: lowest-emphasis (cancel, secondary nav) — text + hover only. */ .btn-ghost { background: transparent; border-color: transparent; color: var(--color-term-muted); } .btn-ghost:hover:not(:disabled) { background: var(--color-term-panel-2); color: var(--color-term-text); border-color: transparent; } /* ---- Card: a panel that is clearly a container, not a field ---- */ .card { @apply rounded-term border border-term-border bg-term-panel; } .card-head { @apply flex items-center justify-between border-b border-term-border bg-term-panel-2 px-4 py-2 text-[12px] uppercase tracking-wider text-term-muted; } .card-body { @apply p-4; } } /* ============================================================ LIGHT THEME The booth defaults to dark (dark room), but a user may prefer light; the choice is saved to their profile (users.theme) and applied on as `.theme-light`. Every screen reads colour through the --color-term-* tokens, so re-pointing them here re-skins the whole app. The TRM "paper/ink" scale supplies the surfaces; accents are tuned a shade darker for contrast on white. A few component-layer values are literal hex (input borders, the inset "recessed" shadow, primary-button text) — those are overridden too so fields and buttons keep their affordance on a light background. ============================================================ */ html.theme-light { /* Surfaces — TRM paper scale (light → slightly darker for layering). */ --color-term-bg: #fafaf7; /* paper */ --color-term-panel: #f2f2ee; /* paper-2 */ --color-term-panel-2: #e8e8e2; /* paper-3 */ --color-term-border: #d2d2c8; --color-term-muted: #5a5a53; /* ink-3 — readable secondary text */ --color-term-text: #14171c; /* near-black ink */ /* Accents — a step darker than the dark-theme values for white-bg contrast. */ --color-term-amber: #b8740a; --color-term-green: #1f6a36; --color-term-red: #c8331f; --color-term-cyan: #1a4fa8; } /* Component-layer literals that must flip for light (the rest read tokens). */ html.theme-light .input, html.theme-light .select, html.theme-light .textarea { border-color: #c2c2b8; box-shadow: inset 0 1px 2px rgba(20, 23, 28, 0.08); } html.theme-light .input:hover, html.theme-light .select:hover, html.theme-light .textarea:hover { border-color: #a8a89e; } html.theme-light .input:focus, html.theme-light .select:focus, html.theme-light .textarea:focus { box-shadow: inset 0 1px 2px rgba(20, 23, 28, 0.08), 0 0 0 1px var(--color-term-amber); } html.theme-light .btn { border-color: #c2c2b8; } html.theme-light .btn:hover:not(:disabled) { background: #dcdcd4; border-color: #a8a89e; } /* Filled buttons keep light text; primary uses dark-on-amber, kept legible. */ html.theme-light .btn-primary { color: #fafaf7; }