diff --git a/.planning/phase-3-dogfood-readiness/README.md b/.planning/phase-3-dogfood-readiness/README.md index aa3b379..9a233f8 100644 --- a/.planning/phase-3-dogfood-readiness/README.md +++ b/.planning/phase-3-dogfood-readiness/README.md @@ -30,7 +30,7 @@ Phase 2 produces a working live map. Phase 3 makes that map _fielded_ — usable | 3.5 | Empty / loading state polish | "Connecting…", "Waiting for first positions…", "No devices in this event yet" | | 3.6 | Vitest + React Testing Library setup + targeted tests | Auth store, coalescer, position-store reducer. Not exhaustive | | 3.7 | Production logging discipline | Console-error captures + optional remote-shipper for stage | -| 3.8 | Visual brand pass | Apply the actual TRM brand if one exists by then. Logo + colour palette | +| 3.8 | Visual brand pass — adopt TRM design system | Apply the design handoff bundle. Bundle path + scope + recommended approach below. | ## Acceptance for the phase as a whole @@ -40,3 +40,25 @@ Phase 2 produces a working live map. Phase 3 makes that map _fielded_ — usable - [ ] Clicking a device opens the detail panel; the panel shows the device's current vehicle/crew (joined from Directus) and recent positions (from the store). - [ ] Vitest runs in CI; existing tests are green; coverage is documented but not gated on a percentage threshold. - [ ] The dogfood-day operator sign-off: a marshal can use the SPA on race day without us standing over them. (This is the real acceptance gate; the rest is observable proxy.) + +## Task 3.8 — TRM design system adoption (deferred from earlier) + +A design handoff bundle was generated by Claude Design (claude.ai/design) on 2026-05-02 and lives at `TRM_Design_System-handoff/trm-design-system/` in this repo. It defines a **Bloomberg / F1-pit-wall** aesthetic — high data density, ink-on-paper base with one race-flag red accent (`#E8412B`), mono numerics for any changing value, square-edged everything, sharp printed offset shadows (no blur), Goldplay (real licensed font with three weights in the bundle's `fonts/`) + JetBrains Mono + Inter. Four surfaces designed: web dashboard, live leaderboard, mobile app, marketing site — only the first two are in this SPA's scope. + +The bundle's READMEs (top-level + `trm-design-system/README.md` + `project/README.md`) and `chats/chat1.md` are the source of truth. `colors_and_type.css` ships the full token set as CSS custom properties. + +**Recommended approach when Phase 3 picks this up — retheme shadcn, don't replace.** Tailwind 4's `@theme` directive maps cleanly to the design's tokens; shadcn's CSS-variable-driven theming lets us keep all the existing primitives (Button / Input / Form / Card / Alert) and only swap the cosmetics. Concrete steps: + +1. Translate `colors_and_type.css` into a Tailwind `@theme` block — the paper / ink / night / race-accent / viz palettes all become Tailwind utilities. +2. Override shadcn's `--background`, `--foreground`, `--primary`, `--destructive`, `--ring`, `--radius` to point at the TRM tokens. +3. Add Goldplay as a webfont via the bundle's woff2 / ttf files (drop into `public/fonts/`); register JetBrains Mono via Google Fonts. +4. Set the global radius to `0` (square-edged) and replace shadcn's soft shadows with the printed offset utility (`box-shadow: 2px 2px 0 0 var(--ink)`). +5. Reskin shadcn primitives where defaults conflict — mainly: button radius, card border (full-ink 1 px not hairline), focus ring colour (race-flag red, 2 px outline + offset). +6. Adopt night mode for the Phase 2 live-map page only (the design says night is the default for trackside / kiosk views, not a toggle); paper/ink everywhere else. +7. Replace the home-page placeholder + login page with the design's chrome (56 px top bar, 240/64 px collapsible sidebar — the dashboard layout). + +**Out of scope for 3.8:** mobile app and marketing site. Those are separate products in the design system; the SPA only adopts dashboard + leaderboard surfaces. + +**Open question for when 3.8 starts:** the design notes the brand may have a custom icon set (cube / pixel-grid / map glyphs from the logo) — Lucide is the documented substitute. Stick with Lucide unless the custom set surfaces by then. + +**Why deferred:** the design's foundational tokens are non-blocking for Phase 1 (login + placeholder home) and Phase 2 (live map without chrome). Adopting them now would either delay the dogfood-blocking work or land partial styling that gets reworked in 3.8 anyway. The bundle is committed alongside this plan so it's findable when Phase 3 runs. diff --git a/TRM_Design_System-handoff/trm-design-system/README.md b/TRM_Design_System-handoff/trm-design-system/README.md new file mode 100644 index 0000000..bd13d97 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/README.md @@ -0,0 +1,25 @@ +# CODING AGENTS: READ THIS FIRST + +This is a **handoff bundle** from Claude Design (claude.ai/design). + +A user mocked up designs in HTML/CSS/JS using an AI design tool, then exported this bundle so a coding agent can implement the designs for real. + +## What you should do — IMPORTANT + +**Read the chat transcripts first.** There are 1 chat transcript(s) in `trm-design-system/chats/`. The transcripts show the full back-and-forth between the user and the design assistant — they tell you **what the user actually wants** and **where they landed** after iterating. Don't skip them. The final HTML files are the output, but the chat is where the intent lives. + +**Find the primary design file under `trm-design-system/project/` and read it top to bottom.** The chat transcripts will tell you which file the user was last iterating on. Then **follow its imports**: open every file it pulls in (shared components, CSS, scripts) so you understand how the pieces fit together before you start implementing. + +**If anything is ambiguous, ask the user to confirm before you start implementing.** It's much cheaper to clarify scope up front than to build the wrong thing. + +## About the design files + +The design medium is **HTML/CSS/JS** — these are prototypes, not production code. Your job is to **recreate them pixel-perfectly** in whatever technology makes sense for the target codebase (React, Vue, native, whatever fits). Match the visual output; don't copy the prototype's internal structure unless it happens to fit. + +**Don't render these files in a browser or take screenshots unless the user asks you to.** Everything you need — dimensions, colors, layout rules — is spelled out in the source. Read the HTML and CSS directly; a screenshot won't tell you anything they don't. + +## Bundle contents + +- `trm-design-system/README.md` — this file +- `trm-design-system/chats/` — conversation transcripts (read these!) +- `trm-design-system/project/` — the `TRM Design System` project files (HTML prototypes, assets, components) diff --git a/TRM_Design_System-handoff/trm-design-system/chats/chat1.md b/TRM_Design_System-handoff/trm-design-system/chats/chat1.md new file mode 100644 index 0000000..6a24d70 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/chats/chat1.md @@ -0,0 +1,393 @@ +# Event Timing Dashboard + +_Started 2026-04-30 19:47 UTC_ + +--- + +## User + + + +## Assistant + +I'll start by exploring what's been provided for TRM - Tracking & Race Management. + +_[tool: list_files]_ + +The project is empty — no codebase, Figma links, or design assets have been provided. Before I build a design system from scratch (which the guidance specifically warns against), I need some materials to work from. + +Could you provide any of the following for TRM - Tracking & Race Management? + +1. **Codebase** — via the Import menu (local repo, GitHub link, or another project) +2. **Figma file** — a link to the design system, components, or product screens +3. **Screenshots** — of the existing product UI, marketing site, or any branded materials +4. **Brand assets** — logos, color palette, fonts, brand guidelines doc, or a slide template +5. **Product context** — even a brief description of what TRM does (race timing? GPS tracking? event management? motorsport? running? sailing?), who uses it, and what surfaces exist (mobile app, web dashboard, race-day kiosk, marketing site, etc.) + +A few quick questions to point me in the right direction even before assets arrive: + +_[tool: questions_v2]_ + +## User + +Questions answered: +- domain: Multi-sport / generic event timing +- surfaces: Web dashboard (organizers / officials), Marketing website, Live tracking / leaderboard view, Mobile app (athletes / spectators) +- assets: Nothing — please mock from scratch +- vibe: Technical / data-dense (think Bloomberg, F1 pit wall) +- logo: uploads/logo-1777578841639.png + +## Assistant + +I'll build a TRM design system from scratch with a technical/data-dense aesthetic. Let me start by examining the logo and laying out the plan. + +_[tool: view_image]_ + +_[tool: image_metadata]_ + +Good — bold geometric wordmark with a 3D cube (T), a pixel-grid (R), and a folded map (M) as inset glyphs. That's a great starting visual vocabulary: blocky, technical, geometric, ink-on-white. I'll build the system around it. + +_[tool: update_todos]_ + +_[tool: set_project_title]_ + +_[tool: copy_files]_ + +Now I'll define the system. Visual direction: **Bloomberg/F1-pit-wall** technical density on a clean white-and-ink base. Mono numerics for all data, sharp small-radius corners, fine 1px borders, a single high-energy accent color (race-flag amber/red), and semantic data-viz colors that read clearly on dense leaderboards. + +Let me set up fonts and core tokens. + +_[tool: write_file]_ + +Now the README with brand context, content fundamentals, and visual foundations. + +_[tool: write_file]_ + +Now let's build the preview cards. I'll create a shared frame helper, then crank through them in batches. + +_[tool: write_file]_ + +## Type cards + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: snip]_ + +## Color cards + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: snip]_ + +## Spacing, radii, shadows + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: snip]_ + +## Component cards + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: snip]_ + +## Brand cards + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: snip]_ + +Now register all preview cards. + +_[tool: register_assets]_ + +_[tool: snip]_ + +## UI Kits — let me build a shared kit-frame helper, then each kit. + +_[tool: write_file]_ + +_[tool: snip]_ + +## UI Kit 1: Web Dashboard + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: snip]_ + +_[tool: write_file]_ + +_[tool: show_html]_ + +_[tool: show_html]_ + +_[tool: snip]_ + +_[tool: get_webview_logs]_ + +_[tool: save_screenshot]_ + +_[tool: view_image]_ + +_[tool: snip]_ + +Dashboard looks great. Let me move to the leaderboard kit. + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: snip]_ + +_[tool: show_html]_ + +_[tool: get_webview_logs]_ + +_[tool: save_screenshot]_ + +_[tool: view_image]_ + +_[tool: snip]_ + +Now the mobile UI kit. + +_[tool: write_file]_ + +_[tool: copy_starter_component]_ + +_[tool: snip]_ + +_[tool: grep]_ + +_[tool: grep]_ + +_[tool: snip]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: snip]_ + +_[tool: show_html]_ + +_[tool: snip]_ + +_[tool: get_webview_logs]_ + +_[tool: save_screenshot]_ + +_[tool: snip]_ + +_[tool: view_image]_ + +_[tool: snip]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: write_file]_ + +_[tool: snip]_ + +_[tool: show_html]_ + +_[tool: snip]_ + +_[tool: get_webview_logs]_ + +_[tool: save_screenshot]_ + +_[tool: snip]_ + +_[tool: view_image]_ + +_[tool: snip]_ + +_[tool: register_assets]_ + +_[tool: write_file]_ + +_[tool: done]_ + +_[tool: snip]_ + +_[tool: fork_verifier_agent]_ + +The TRM Design System is built. Open the **Design System** tab to see all 27 cards (Type, Colors, Spacing, Components, Brand) plus the four UI kits. + +### Caveats — please help me iterate + +- **Source material was a logo only**, so the brand voice, content tone, sport vocabulary, vibe, and pricing copy are all *plausible-but-invented*. Treat as a starting hypothesis. +- **Font substitutions flagged:** Space Grotesk (display/UI), JetBrains Mono (data), Inter (prose) — all best-fit Google Fonts. If TRM has licensed faces, please share `.woff2`. +- **Iconography substituted:** Lucide via CDN. The logo's three inset glyphs (cube · pixel-grid · folded map) hint at a custom set — if it exists, swap in. +- **No real product imagery.** I avoided fabricating photos. Hero/social slots are clean ink layouts only. +- **Race-specific iconography** (checkered flag, timing chip, podium, sailing buoy, transition area) is currently rendered with Lucide approximations — a small bespoke SVG set would lift everything. +- **Sport coverage is generic.** I leaned on running for examples. If TRM is heavier in cycling, sailing, or motorsport, sample data and wave terminology should shift. + +### **What I need from you to make this perfect** + +1. **A handful of real product screenshots** (any surface — dashboard, kiosk, mobile) so I can replace the invented layouts with the real visual vocabulary. +2. **Confirm or correct** the brand accent (`#E8412B` race-flag red) and the square-edged, hairline-bordered, mono-numeric direction. +3. **Sport mix** — which 3 sports does TRM most need to look great in? +4. Any existing **Figma file, codebase, or marketing site URL** — even a pasted hero screenshot — would replace the biggest assumptions in one move. + +Pick any one of those four and I'll iterate. + +## User + + + +## Assistant + +_[tool: snip]_ + +_[tool: list_files]_ + +_[tool: read_file]_ + +Goldplay is a humanist sans — best fit as the **display/UI** family (replacing Space Grotesk). Only Semibold weight provided, so I'll register it at 600 and let other weights synthesize. + +_[tool: str_replace_edit]_ + +_[tool: snip]_ + +_[tool: grep]_ + +_[tool: str_replace_edit]_ + +_[tool: snip]_ + +_[tool: grep]_ + +_[tool: str_replace_edit]_ + +_[tool: str_replace_edit]_ + +_[tool: snip]_ + +Now update the README font reference and re-register the typography cards so the system picks up the new versions. + +_[tool: grep]_ + +_[tool: snip]_ + +_[tool: str_replace_edit]_ + +_[tool: str_replace_edit]_ + +_[tool: grep]_ + +_[tool: snip]_ + +_[tool: str_replace_edit]_ + +_[tool: register_assets]_ + +_[tool: snip]_ + +_[tool: done]_ + +Goldplay is wired in — installed at `fonts/goldplay-semibold.woff2`, mapped to `--font-display` / `--font-ui`, and now driving every heading, button, label, and overline across the previews and all four UI kits. README and the type preview cards are updated to reflect the new family. + +**Caveats:** +- Only the Semibold cut was provided. 400 and 700 weights synthesize from the same file, which is fine on screen but a real Regular and Bold cut would tighten things up — share them if you have them. +- Mono (JetBrains Mono) and body (Inter) are still Google Font substitutes; let me know if TRM uses licensed faces there too. + +## User + +What about these regular and bold goldplay? + +## Assistant + +_[tool: snip]_ + +_[tool: copy_files]_ + +_[tool: read_file]_ + +_[tool: str_replace_edit]_ + +_[tool: snip]_ + +_[tool: str_replace_edit]_ + +_[tool: done]_ + +_[tool: snip]_ + +Goldplay Regular and Bold are now wired in as real font files — no more synthesis. All three weights (400 / 600 / 700) load from their own files, and the README's font note has been updated to reflect the full installed set. + diff --git a/TRM_Design_System-handoff/trm-design-system/project/README.md b/TRM_Design_System-handoff/trm-design-system/project/README.md new file mode 100644 index 0000000..8ecf0df --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/README.md @@ -0,0 +1,246 @@ +# TRM — Tracking & Race Management + +**Design System v1.0** + +TRM (Tracking & Race Management) is a multi-sport, generic event-timing platform — race directors, timing officials, athletes, and spectators all live in one product family. Think of the way an F1 pit-wall display, a marathon results board, a triathlon transition mat, and a sailing nav screen all need to coexist visually: high-density numerical data, instant readability under any light, and absolute trust in the numbers on screen. + +The system covers four surfaces: + +| Surface | Audience | Density | +|---|---|---| +| **Web dashboard** | Race directors, timing officials, race control | Very high | +| **Live tracking / leaderboard** | Spectators, broadcast, kiosk | Very high, glanceable | +| **Mobile app** | Athletes, spectators following a friend | Medium | +| **Marketing website** | Race organizers evaluating the product | Editorial | + +--- + +## Sources & provenance + +This system was built **from scratch** — no existing codebase, Figma file, or brand guide was provided. The only input was a **logo PNG** (`uploads/logo-1777578841639.png` → `assets/logo-trm.png`): a bold geometric wordmark with three inset glyphs — a 3D **cube** in the T, a **pixel grid** in the R, and a **folded map** in the M. That triad — *object · data · place* — is the conceptual core of the brand and runs through the rest of the system. + +If you receive updated source material (real product screenshots, Figma, fonts, a brand book), treat this document as a starting hypothesis to be replaced — not as canon. + +--- + +## CONTENT FUNDAMENTALS + +TRM copy reads like a **race-control radio call**: short, factual, present tense, no hype. The product is responsible for numbers people care about (a podium finish, a qualifying time), so the voice is calm and exact. Drama lives in the data, not in the prose. + +### Voice attributes + +- **Precise over expressive.** "Lap 14 / 22" not "Almost there!" +- **Active, present tense.** "Smith passes Jones" not "Smith has just managed to pass Jones." +- **Short.** Most UI strings are ≤ 4 words. Sentences in marketing rarely exceed 16. +- **No exclamation marks** in product UI. Marketing may use one per page, max. +- **Second person ("you") in marketing.** First person plural ("we") only when explicitly speaking as the company. Product UI prefers no pronoun at all ("Add bib" not "Add a bib to your event"). +- **Numerals beat words.** "3 laps left," not "three laps remaining." +- **Time is sacred.** Always render times in mono with tabular figures: `01:23:45.678`. Leading zeros on minutes/seconds. Milliseconds when relevant. + +### Casing + +| Context | Style | +|---|---| +| Buttons, links, menu items | **Sentence case** ("Start race", "Export results") | +| Labels above fields | **UPPERCASE** with letter-spacing (overline class) | +| Section headings | **Sentence case** | +| Table column headers | **UPPERCASE** mono, e.g. `POS BIB NAME GAP` | +| Status flags | **UPPERCASE** ("LIVE", "DNF", "DSQ", "DNS") | +| Brand wordmark | **TRM** — always uppercase, never "Trm" | + +### Vocabulary — preferred terms + +| Use | Not | +|---|---| +| Event | Race (use "race" only for a single heat within an event) | +| Participant | User, racer, runner (sport-specific only when the event is single-sport) | +| Bib | Number, ID | +| Wave | Group, batch | +| Split | Checkpoint *(use "checkpoint" only when split is geographic)* | +| Leaderboard | Ranking, scoreboard | +| DNF / DSQ / DNS | Did not finish / Disqualified / Did not start *(spell out only on first use)* | +| Live | Real-time *(reserve "real-time" for technical copy)* | + +### Emoji & symbols + +- **No decorative emoji** anywhere in product UI. None. +- Marketing may use **🏁** or **▲ ▼** as standalone graphic elements but never inline in sentences. +- Race-flag glyphs are part of the design system as **CSS-drawn flags or SVG**, not emoji. +- Mathematical / typographic symbols *are* used freely: `+`, `−`, `±`, `→`, `·`, `°`, `Δ`. + +### Sample copy + +> **Marketing hero:** +> *Run any event. Time any sport. TRM is the race-day operating system used by 4,000+ event organizers — from 5K fun runs to 24-hour endurance races.* + +> **Empty state in dashboard:** +> *No events yet. Create your first event to start timing.* + +> **Toast on save:** +> *Saved · 14:02:11* *(timestamped, mono)* + +> **Race-control alert:** +> *Bib 247 — missed split 3 — flagging for review* + +> **Push notification, athlete app:** +> *Maya passed split 2 — 00:42:18 — pace 4:13/km* + +--- + +## VISUAL FOUNDATIONS + +The system is **ink on paper, with one race-flag accent**. Square-edged. Hairline-bordered. Mono-numeric. The visual mood sits between a Bloomberg terminal and a printed race program. + +### Colors + +- **Paper / Ink palette** drives 90% of screens. Off-white `#FAFAF7` ground, deep ink `#0E0E0C` strokes and type. No true black, no true white — both are exhausting on data screens. +- **Night mode** (`#0B0D10`) is the default for live tracking, kiosk, and trackside displays. It is not a "dark theme toggle" — it's a separate context. +- **Race-flag red `#E8412B`** is the only brand accent. Reserved for: primary CTAs, "live" pulse, danger states, the leading position in a leaderboard. Used sparingly. If everything is red, nothing is. +- **Amber `#F2A516`** = caution / yellow flag / warnings. +- **Green `#2E8C4A`** = go / improvement / personal best / passed checkpoint. +- **Blue `#2563C8`** = informational, link, "tracking" pulse. +- **Categorical viz palette** is 8 hues, ordered by frequency of use; never assign meaning to a viz hue beyond chart legend. + +### Typography + +- **Display & UI:** *Goldplay* (Semibold supplied; 400 / 700 synthesized). The brand face — humanist sans with confident curves and a slightly editorial register. Used for headings, buttons, navigation, labels. +- **Mono / data:** *JetBrains Mono* (400 / 500 / 600). Tabular figures are non-negotiable for any time, gap, distance, or ranking. Every number that could change is mono. +- **Body / long-form prose:** *Inter* (400 / 600). Used only in marketing long-form and documentation. The dashboard does not have body prose. +- **Letter-spacing:** display is tight (`-0.02em`). Overlines / table headers are open (`+0.10em`) and uppercase. + +> ✅ **Goldplay (display/UI)** — brand face installed with three weights: Regular `400` (`fonts/goldplay-regular.ttf`), Semibold `600` (`fonts/goldplay-semibold.woff2`), Bold `700` (`fonts/goldplay-bold.ttf`). No synthesis. **Mono / body** are still Google Font substitutes — share licensed faces if available.e *Berkeley Mono* or *GT America Mono*), please provide the `.woff2` / `.ttf` files and we'll swap them in. + +### Spacing & grid + +- **4-px base** unit. Standard scale: 4 · 8 · 12 · 16 · 20 · 24 · 32 · 40 · 48 · 64 · 80 · 96. +- **12-column grid** at 1280 px container, 24 px gutters, 16 px column gap. +- **Table density** is the system's defining choice. Default row height is **36 px**, "dense" is **28 px**, and dense is the dashboard default — race directors look at hundreds of rows. + +### Corners & borders + +- **Square by default.** `--r-0: 0`. Cards, inputs, buttons, modals: all square. +- **2 px radius** for chips and small inputs only. +- **4–10 px radius** reserved for marketing cards and the mobile app surface. +- **Hairline 1 px borders** — `var(--hairline)` for division within a card; full ink `1px solid var(--ink)` for the outer edge of any "first-class" container (modal, primary card, button). +- **No rounded pills**, except for status badges where pill is functionally meaningful (`LIVE`, `DNF`). + +### Shadows & elevation + +TRM uses a **printed offset shadow** as its primary elevation model — a sharp 2 px or 4 px ink-colored offset, no blur. It says "the chip is sitting on the page," not "the chip is glowing." Soft blurry shadows are allowed only on mobile sheets and marketing site. + +| Token | Use | +|---|---| +| `--shadow-2` (2 px ink offset) | Buttons at rest, primary cards | +| `--shadow-3` (4 px ink offset) | Buttons / cards on hover | +| `--shadow-soft` | Mobile bottom sheets | +| `--shadow-pop` | Marketing testimonial / floating dropdowns | + +### Backgrounds & imagery + +- **No gradients** in product UI. Marketing may use a **flat ink-to-night vertical gradient** behind a hero — never multi-color. +- **Imagery vibe:** high-contrast B&W or duotone (ink + flag) photography of race-day moments — start lines, timing mats, marshals, finish tape. Crops are **tight and asymmetric**. Color photos are allowed in marketing but should be **slightly desaturated and warm-graded** so they coexist with the ink palette. +- **Patterns:** a subtle **dot-grid** (`2 px dot, 24 px spacing`, ink at 8% opacity) and a **diagonal hatch** (used sparingly to mark "in progress" or "estimated" data). These are CSS-drawn, never image files. +- **No hand-drawn illustrations.** No abstract blobs. No gradients-as-backgrounds. The brand is photographic + typographic. + +### Animation + +- **Functional, never decorative.** Transitions are 120–320 ms, almost always `--ease-snap`. +- Hover changes use `120 ms`. Modal / sheet entrances use `180 ms`. Chart redraws use `320 ms`. +- **The "live" pulse** is the one signature motion: a 2 s loop where a red dot scales from 1.0 → 1.15 and a fading ring expands from 0 → 16 px. Used at most once per screen, next to the word LIVE. +- **No bouncy / spring easing.** No fly-ins from off-screen. No micro-interactions on every button. + +### States — hover, press, focus, disabled + +| State | Treatment | +|---|---| +| **Hover** (button) | Shadow grows from `--shadow-2` → `--shadow-3`, button translates `1px ↑ 1px ←` | +| **Hover** (link) | Color shifts `--ink` → `--flag` | +| **Hover** (table row) | Background shifts to `--paper-2`, no elevation change | +| **Press** | Shadow collapses to `0 0 0 0`, button translates back to `0,0` | +| **Focus** | 2 px outline in `--flag`, 2 px offset, *never* removed. Keyboard users matter on race day. | +| **Disabled** | Opacity 40%, cursor `not-allowed`, no shadow | + +### Transparency & blur + +- **Backdrop blur** used only on mobile bottom sheets and the kiosk overlay (`backdrop-filter: blur(12px)` over a `rgba(11,13,16,0.7)` scrim). +- Tints (`--flag-tint`, `--amber-tint`, `--green-tint`, `--blue-tint`) are flat 10–15% mixes, never alpha layers, so they composite predictably over `--paper-2`. + +### Layout rules — fixed elements + +- **Top bar** is `56 px`, full-width, ink border on the bottom, sticky. +- **Side nav** is `240 px` collapsed to `64 px`, ink border on the right, sticky. +- **Live tracking pages** use a **3-column** layout: leaderboard (40%) · map (40%) · selected-athlete detail (20%). +- **Tables fill remaining space**, scroll independently of the page. +- **Time/clock** is always pinned top-right of any "race in progress" view, mono, jumbo size. + +### Iconography + +See the **ICONOGRAPHY** section below. + +--- + +## ICONOGRAPHY + +TRM uses **Lucide** as its icon system — a clean, square-cornered, 2 px stroke library that pairs with Goldplay's humanist sans and the square-edged component language. Lucide is loaded via CDN (`unpkg.com/lucide@latest`) in HTML examples and via the `lucide-react` package in production code. + +> ⚠ **Substitution flag:** Lucide is a substitute. The TRM logo's three inset glyphs (cube, pixel-grid, map) suggest the brand may have a custom-drawn icon set in the same blocky style. If that set exists, swap it in — Lucide is the closest CDN-available match (clean strokes, square caps, geometric). + +### Icon rules + +- **Stroke weight:** 2 px (Lucide default). Never 1.5 / 1 — strokes get lost on dark mode. +- **Sizes:** 14 / 16 / 20 / 24 / 32 px. Never in between. +- **Color:** inherits `currentColor`. Default `--ink-3`; hover state inherits whatever the parent's hover color is. +- **Alignment:** icons are **box-aligned**, not optically aligned. The tabular feel beats the typographic feel here. +- **Race-specific iconography** that Lucide doesn't cover (checkered flag, timing chip, transition area, podium, finish-line tape, sailing buoy, lap split) is rendered as **inline SVG** in the same 2 px stroke style. A small set lives in `assets/icons/` as we encounter the need. + +### Emoji + +**Not used** in product UI. Only race-flag glyphs (🏁) are tolerated in marketing, and even then only as standalone graphic elements at large size — never inline in sentences. + +### Unicode glyphs + +Used freely for compact mathematical / directional indicators: + +- `↑ ↓ → ←` for trend arrows in leaderboards +- `▲ ▼` for sort direction +- `±` for tolerance ("split window ±5s") +- `·` as a compact bullet between meta items ("Wave 3 · 4.2 km · 47 starters") +- `°` for temperature ("18°C, dry") +- `Δ` for delta ("Δ +1.4s") + +### Logo + +- `assets/logo-trm.png` — primary wordmark, ink on transparent, 286×158. +- Minimum width: 80 px. +- Clear space: half the cap-height of the wordmark, all sides. +- **Never** stretch, recolor (except inversion to paper-on-ink), or place on a busy photograph without a 1 px ink-bordered paper plate behind it. + +--- + +## INDEX — what's in this folder + +| Path | Purpose | +|---|---| +| `README.md` | This file. Read first. | +| `SKILL.md` | Agent-Skill manifest for Claude Code / portable use. | +| `colors_and_type.css` | All design tokens as CSS custom properties + base type styles. **Import this first** in any HTML mock. | +| `assets/` | Logos, icons, brand imagery. | +| `assets/logo-trm.png` | Primary wordmark. | +| `preview/` | Per-token / per-component preview cards rendered into the Design System tab. Useful as visual reference. | +| `ui_kits/dashboard/` | Web dashboard for organizers — sidebar, tables, race control. | +| `ui_kits/leaderboard/` | Live tracking / spectator leaderboard view. | +| `ui_kits/mobile/` | Athlete & spectator mobile app inside an iOS frame. | +| `ui_kits/marketing/` | Marketing site — homepage hero, features, pricing strip. | + +Each `ui_kits//` folder contains its own `README.md` describing the screens, an `index.html` you can open directly, and JSX components for the major UI pieces. + +--- + +## Quick start for designers + +```html + + +``` + +Then build with the tokens. The preview cards in `preview/` are good copy-paste starting points for any new screen. diff --git a/TRM_Design_System-handoff/trm-design-system/project/SKILL.md b/TRM_Design_System-handoff/trm-design-system/project/SKILL.md new file mode 100644 index 0000000..f183cf4 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/SKILL.md @@ -0,0 +1,32 @@ +--- +name: trm-design +description: Use this skill to generate well-branded interfaces and assets for TRM (Tracking & Race Management), either for production or throwaway prototypes/mocks/etc. Contains essential design guidelines, colors, type, fonts, assets, and UI kit components for prototyping. +user-invocable: true +--- + +Read the README.md file within this skill, and explore the other available files. + +If creating visual artifacts (slides, mocks, throwaway prototypes, etc), copy assets out and create static HTML files for the user to view. If working on production code, you can copy assets and read the rules here to become an expert in designing with this brand. + +If the user invokes this skill without any other guidance, ask them what they want to build or design, ask some questions, and act as an expert designer who outputs HTML artifacts _or_ production code, depending on the need. + +## Quick orientation + +- `README.md` — brand context, content tone, visual foundations, iconography +- `colors_and_type.css` — all design tokens; **import first** in any HTML +- `assets/logo-trm.png` — primary wordmark +- `preview/*.html` — token & component reference cards +- `ui_kits/dashboard/` — organizer web dashboard +- `ui_kits/leaderboard/` — spectator/kiosk live tracking (night mode) +- `ui_kits/mobile/` — athlete & spectator iOS app +- `ui_kits/marketing/` — marketing homepage + +## Defining traits + +- **Ink on paper, one race-flag accent** (`#E8412B`) +- **Square corners**, hairline borders, printed-offset shadows (`2px 2px 0 0 ink`) +- **Mono numerics** (JetBrains Mono, tabular figures) for every time/gap/distance +- **Display:** Space Grotesk, tight tracking, sentence case +- **Tables are dense** — 28px rows in dashboard +- **Night mode** for trackside/kiosk surfaces +- **No gradients, no decorative emoji, no rounded pills** (except status badges) diff --git a/TRM_Design_System-handoff/trm-design-system/project/assets/logo-trm.png b/TRM_Design_System-handoff/trm-design-system/project/assets/logo-trm.png new file mode 100644 index 0000000..18063dc Binary files /dev/null and b/TRM_Design_System-handoff/trm-design-system/project/assets/logo-trm.png differ diff --git a/TRM_Design_System-handoff/trm-design-system/project/colors_and_type.css b/TRM_Design_System-handoff/trm-design-system/project/colors_and_type.css new file mode 100644 index 0000000..0b7b448 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/colors_and_type.css @@ -0,0 +1,257 @@ +/* ============================================================ + TRM — Tracking & Race Management + Foundational tokens: colors, type, spacing, radii, shadows + ============================================================ */ + +/* ---- Webfonts ---- + Display + UI: "Goldplay" (brand face — Regular / Semibold / Bold) + Mono / data: "JetBrains Mono" + Body: "Inter" +*/ +@font-face { + font-family: "Goldplay"; + font-weight: 400; + font-style: normal; + font-display: swap; + src: url("fonts/goldplay-regular.ttf") format("truetype"); +} +@font-face { + font-family: "Goldplay"; + font-weight: 600; + font-style: normal; + font-display: swap; + src: url("fonts/goldplay-semibold.woff2") format("woff2"), + url("fonts/goldplay-semibold.woff") format("woff"); +} +@font-face { + font-family: "Goldplay"; + font-weight: 700; + font-style: normal; + font-display: swap; + src: url("fonts/goldplay-bold.ttf") format("truetype"); +} +@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Inter:wght@400;500;600;700&display=swap"); + +:root { + /* ---------- COLOR — INK & PAPER ---------- */ + --paper: #FAFAF7; /* off-white page */ + --paper-2: #F2F2EE; /* card sunk a level */ + --paper-3: #E8E8E2; /* deeper sunk / table stripe */ + --ink: #0E0E0C; /* primary text & strokes */ + --ink-2: #2A2A26; /* strong secondary */ + --ink-3: #5A5A53; /* body secondary */ + --ink-4: #8A8A82; /* meta / placeholder */ + --ink-5: #B8B8B0; /* hairlines on light */ + --ink-6: #DCDCD4; /* dividers */ + --line: #0E0E0C; /* default border = ink */ + --hairline: rgba(14,14,12,0.12); + + /* ---------- COLOR — DARK MODE / TIMING SCREEN ---------- */ + --night: #0B0D10; /* trackside dark bg */ + --night-2: #14171C; + --night-3: #1E222A; + --night-line: #2A2F38; + --night-fg: #F2F2EE; + --night-fg-2: #B8B8B0; + --night-fg-3: #8A8A82; + + /* ---------- COLOR — RACE ACCENTS ---------- */ + --flag: #E8412B; /* primary accent — race-flag red */ + --flag-2: #C8331F; + --flag-tint: #FBE3DE; + --amber: #F2A516; /* yellow-flag / caution */ + --amber-2: #C88500; + --amber-tint: #FBEFD0; + --green: #2E8C4A; /* go / personal best / pass */ + --green-2: #1F6A36; + --green-tint: #DDEFE2; + --blue: #2563C8; /* link / info / "live" pulse */ + --blue-2: #1A4FA8; + --blue-tint: #DCE6F8; + --violet: #6B46C1; /* secondary categorical */ + --magenta: #C9296F; + --teal: #188C8A; + + /* Semantic shortcuts (status, alerts) */ + --ok: var(--green); + --warn: var(--amber); + --danger: var(--flag); + --info: var(--blue); + + /* ---------- COLOR — DATA VIZ (categorical, 8) ---------- */ + --viz-1: #E8412B; /* flag red */ + --viz-2: #2563C8; /* blue */ + --viz-3: #2E8C4A; /* green */ + --viz-4: #F2A516; /* amber */ + --viz-5: #6B46C1; /* violet */ + --viz-6: #188C8A; /* teal */ + --viz-7: #C9296F; /* magenta */ + --viz-8: #5A5A53; /* graphite */ + + /* ---------- TYPE — FAMILIES ---------- */ + --font-display: "Goldplay", "Helvetica Neue", Arial, sans-serif; + --font-ui: "Goldplay", "Helvetica Neue", Arial, sans-serif; + --font-body: "Inter", "Helvetica Neue", Arial, sans-serif; + --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace; + + /* ---------- TYPE — SCALE ---------- + Modular but not strict. Optimized for data density. + */ + --fs-overline: 11px; /* uppercase labels */ + --fs-micro: 12px; /* table meta */ + --fs-small: 13px; /* body small */ + --fs-body: 15px; /* body */ + --fs-lead: 17px; /* lead paragraph */ + --fs-h6: 14px; + --fs-h5: 16px; + --fs-h4: 20px; + --fs-h3: 26px; + --fs-h2: 34px; + --fs-h1: 48px; + --fs-display: 72px; /* hero / kiosk timing */ + --fs-jumbo: 120px; /* leaderboard primary clock */ + + --lh-tight: 1.05; + --lh-snug: 1.2; + --lh-normal: 1.35; + --lh-loose: 1.55; + + --ls-tight: -0.02em; + --ls-normal: 0; + --ls-wide: 0.04em; + --ls-caps: 0.10em; /* overline / small caps */ + + /* ---------- SPACING (4px base) ---------- */ + --s-0: 0; + --s-1: 2px; + --s-2: 4px; + --s-3: 8px; + --s-4: 12px; + --s-5: 16px; + --s-6: 20px; + --s-7: 24px; + --s-8: 32px; + --s-9: 40px; + --s-10: 48px; + --s-11: 64px; + --s-12: 80px; + --s-13: 96px; + + /* ---------- RADIUS ---------- */ + --r-0: 0; /* default — TRM is square-edged */ + --r-1: 2px; + --r-2: 4px; /* chips / inputs */ + --r-3: 6px; /* small cards */ + --r-4: 10px; /* large cards */ + --r-pill: 999px; /* pills only when truly needed */ + + /* ---------- BORDERS ---------- */ + --bw-1: 1px; + --bw-2: 2px; + --bw-3: 3px; + --b-default: 1px solid var(--ink); + --b-hair: 1px solid var(--hairline); + --b-night: 1px solid var(--night-line); + + /* ---------- ELEVATION ---------- */ + /* TRM uses sharp 1-2px offset shadows ("printed" feel), not soft blooms. */ + --shadow-0: none; + --shadow-1: 0 1px 0 0 var(--ink); /* underline */ + --shadow-2: 2px 2px 0 0 var(--ink); /* button rest */ + --shadow-3: 4px 4px 0 0 var(--ink); /* card hover */ + --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 ---------- */ + --ease-snap: cubic-bezier(0.2, 0.8, 0.2, 1); + --ease-out: cubic-bezier(0.16, 1, 0.3, 1); + --ease-linear: linear; + --t-quick: 120ms; + --t-base: 180ms; + --t-slow: 320ms; + + /* ---------- LAYOUT ---------- */ + --container: 1280px; + --gutter: 24px; + --col-gap: 16px; + --grid-cols: 12; + + /* ---------- COMPONENT TOKENS ---------- */ + --control-h-sm: 28px; + --control-h-md: 36px; + --control-h-lg: 44px; + --table-row-h: 36px; + --table-row-h-dense: 28px; +} + +/* ============================================================ + SEMANTIC TYPOGRAPHY — apply directly or via classes + ============================================================ */ +html, body { + background: var(--paper); + color: var(--ink); + font-family: var(--font-body); + font-size: var(--fs-body); + line-height: var(--lh-normal); + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; +} + +h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6 { + font-family: var(--font-display); + color: var(--ink); + letter-spacing: var(--ls-tight); + line-height: var(--lh-tight); + font-weight: 600; + margin: 0; +} +h1, .h1 { font-size: var(--fs-h1); font-weight: 700; } +h2, .h2 { font-size: var(--fs-h2); font-weight: 700; } +h3, .h3 { font-size: var(--fs-h3); } +h4, .h4 { font-size: var(--fs-h4); } +h5, .h5 { font-size: var(--fs-h5); line-height: var(--lh-snug); } +h6, .h6 { font-size: var(--fs-h6); line-height: var(--lh-snug); } + +.display { font-family: var(--font-display); font-size: var(--fs-display); font-weight: 700; line-height: var(--lh-tight); letter-spacing: var(--ls-tight); } +.jumbo { font-family: var(--font-mono); font-size: var(--fs-jumbo); font-weight: 600; line-height: 1; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; } + +p, .body { font-size: var(--fs-body); line-height: var(--lh-loose); color: var(--ink-2); } +.lead { font-size: var(--fs-lead); line-height: var(--lh-loose); color: var(--ink-2); } +.small { font-size: var(--fs-small); } +.micro { font-size: var(--fs-micro); color: var(--ink-3); } + +.overline { + font-family: var(--font-ui); + font-size: var(--fs-overline); + font-weight: 600; + letter-spacing: var(--ls-caps); + text-transform: uppercase; + color: var(--ink-3); +} + +.mono, code, kbd, samp, pre { + font-family: var(--font-mono); + font-variant-numeric: tabular-nums; +} +.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: -0.01em; } + +a { + color: var(--ink); + text-decoration: underline; + text-decoration-thickness: 1px; + text-underline-offset: 2px; +} +a:hover { color: var(--flag); } + +hr { border: 0; border-top: 1px solid var(--ink); margin: var(--s-7) 0; } + +/* Foreground/background tokens (semantic aliases) */ +:root { + --fg-1: var(--ink); + --fg-2: var(--ink-2); + --fg-3: var(--ink-3); + --fg-4: var(--ink-4); + --bg-1: var(--paper); + --bg-2: var(--paper-2); + --bg-3: var(--paper-3); +} diff --git a/TRM_Design_System-handoff/trm-design-system/project/fonts/goldplay-bold.ttf b/TRM_Design_System-handoff/trm-design-system/project/fonts/goldplay-bold.ttf new file mode 100644 index 0000000..9baf3d9 Binary files /dev/null and b/TRM_Design_System-handoff/trm-design-system/project/fonts/goldplay-bold.ttf differ diff --git a/TRM_Design_System-handoff/trm-design-system/project/fonts/goldplay-regular.ttf b/TRM_Design_System-handoff/trm-design-system/project/fonts/goldplay-regular.ttf new file mode 100644 index 0000000..174d58f Binary files /dev/null and b/TRM_Design_System-handoff/trm-design-system/project/fonts/goldplay-regular.ttf differ diff --git a/TRM_Design_System-handoff/trm-design-system/project/fonts/goldplay-semibold.woff b/TRM_Design_System-handoff/trm-design-system/project/fonts/goldplay-semibold.woff new file mode 100644 index 0000000..13d1014 Binary files /dev/null and b/TRM_Design_System-handoff/trm-design-system/project/fonts/goldplay-semibold.woff differ diff --git a/TRM_Design_System-handoff/trm-design-system/project/fonts/goldplay-semibold.woff2 b/TRM_Design_System-handoff/trm-design-system/project/fonts/goldplay-semibold.woff2 new file mode 100644 index 0000000..4097b17 Binary files /dev/null and b/TRM_Design_System-handoff/trm-design-system/project/fonts/goldplay-semibold.woff2 differ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/_card.css b/TRM_Design_System-handoff/trm-design-system/project/preview/_card.css new file mode 100644 index 0000000..aabf443 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/_card.css @@ -0,0 +1,17 @@ +/* Shared base for preview cards. Each card = 700x, no titles + (the asset name renders outside). Just show the thing. */ +*,*::before,*::after { box-sizing: border-box; } +html, body { margin: 0; padding: 0; } +body { + width: 700px; + background: var(--paper); + color: var(--ink); + font-family: var(--font-body); + padding: 20px; +} +.card-pad { padding: 20px; } +.row { display: flex; gap: 12px; align-items: center; } +.col { display: flex; flex-direction: column; gap: 8px; } +.fill { flex: 1; } +.dot { width: 8px; height: 8px; border-radius: 999px; display: inline-block; } +.hairline { border-top: 1px solid var(--hairline); } diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/brand-icons.html b/TRM_Design_System-handoff/trm-design-system/project/preview/brand-icons.html new file mode 100644 index 0000000..36aa017 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/brand-icons.html @@ -0,0 +1,35 @@ + + + + + + +
Iconography · Lucide 2px stroke
+
+
flag
+
timer
+
pin
+
trophy
+
users
+
chart
+
settings
+
bell
+
play
+
pause
+
stop
+
radio
+
route
+
watch
+
wifi
+
export
+
+
Sizes 14 / 16 / 20 / 24 / 32 · color inherits currentColor
+ + diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/brand-logo.html b/TRM_Design_System-handoff/trm-design-system/project/preview/brand-logo.html new file mode 100644 index 0000000..14d9471 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/brand-logo.html @@ -0,0 +1,25 @@ + + + + + +
Logo · primary wordmark
+
+
+
TRM
+
Ink on paper · default
+
+
+
TRM
+
Paper on ink · night surfaces
+
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/brand-patterns.html b/TRM_Design_System-handoff/trm-design-system/project/preview/brand-patterns.html new file mode 100644 index 0000000..45d52a3 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/brand-patterns.html @@ -0,0 +1,41 @@ + + + + + +
+
+
8% ink · 16px
+
Dot grid
+
+
+
45° · 12px
+
Diagonal hatch · "estimated"
+
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/brand-pulse.html b/TRM_Design_System-handoff/trm-design-system/project/preview/brand-pulse.html new file mode 100644 index 0000000..6cf01d6 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/brand-pulse.html @@ -0,0 +1,23 @@ + + + + + +
Live pulse · signature motion
+
+
LIVE
+
01:23:45.6
+
+
2s loop · scale 1→1.15 · ring 0→2.6× · used at most once per screen
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/colors-accents.html b/TRM_Design_System-handoff/trm-design-system/project/preview/colors-accents.html new file mode 100644 index 0000000..e5610f4 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/colors-accents.html @@ -0,0 +1,34 @@ + + + + + +
Brand · accents
+
+
+
Flag
+
#E8412B
Primary CTA · Live · #1 pos
+
+
+
Amber
+
#F2A516
Caution · Yellow flag · Warn
+
+
+
Green
+
#2E8C4A
Go · PB · Pass
+
+
+
Blue
+
#2563C8
Info · Link · Tracking
+
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/colors-neutrals.html b/TRM_Design_System-handoff/trm-design-system/project/preview/colors-neutrals.html new file mode 100644 index 0000000..cf8c40a --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/colors-neutrals.html @@ -0,0 +1,36 @@ + + + + + +
Paper / Ink scale — light surface
+
+
white
#FFFFFF
+
paper
#FAFAF7
+
paper-2
#F2F2EE
+
paper-3
#E8E8E2
+
ink-6
#DCDCD4
+
ink-5
#B8B8B0
+
ink-4
#8A8A82
+
ink-3
#5A5A53
+
+
Ink scale — type & strokes
+
+
ink-3
#5A5A53
+
ink-2
#2A2A26
+
ink
#0E0E0C
+
night-3
#1E222A
+
night-2
#14171C
+
night
#0B0D10
+
black
#000000
+
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/colors-night.html b/TRM_Design_System-handoff/trm-design-system/project/preview/colors-night.html new file mode 100644 index 0000000..75079fc --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/colors-night.html @@ -0,0 +1,34 @@ + + + + + +
+
Night mode · trackside / kiosk
+
+
night
#0B0D10
+
night-2
#14171C
+
night-3
#1E222A
+
line
#2A2F38
+
fg-3
#8A8A82
+
fg
#F2F2EE
+
+
Status pills on night
+
+ LIVE + FINISHED + FLAG + DNS +
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/colors-semantic.html b/TRM_Design_System-handoff/trm-design-system/project/preview/colors-semantic.html new file mode 100644 index 0000000..caf50c0 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/colors-semantic.html @@ -0,0 +1,34 @@ + + + + + +
Semantic · status
+
+
+
OK
+
green / ok
Started · finished · pass · personal best
+
+
+
WARN
+
amber / warn
Yellow flag · slow split · review
+
+
+
DANGER
+
flag / danger
DSQ · DNF · red flag · error
+
+
+
INFO
+
blue / info
Live · tracking · link
+
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/colors-viz.html b/TRM_Design_System-handoff/trm-design-system/project/preview/colors-viz.html new file mode 100644 index 0000000..2b8f2ba --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/colors-viz.html @@ -0,0 +1,35 @@ + + + + + +
Categorical · data viz (8)
+
+
viz-1
E8412B
+
viz-2
2563C8
+
viz-3
2E8C4A
+
viz-4
F2A516
+
viz-5
6B46C1
+
viz-6
188C8A
+
viz-7
C9296F
+
viz-8
5A5A53
+
+
+
+
+
+
+
+
+
+
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/comp-alerts.html b/TRM_Design_System-handoff/trm-design-system/project/preview/comp-alerts.html new file mode 100644 index 0000000..14231f5 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/comp-alerts.html @@ -0,0 +1,40 @@ + + + + + +
Inline alerts · race control
+
+
+
+
Bib 247 — missed split 3   flagging for review
+
14:02:11
+
+
+
+
Yellow flag — sector 2   debris cleared in 90s
+
14:00:42
+
+
+
+
Wave 3 cleared start mat   412 / 412 starters
+
13:45:00
+
+
+
+
Tracking active   14 of 14 mats online
+
13:30:00
+
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/comp-badges.html b/TRM_Design_System-handoff/trm-design-system/project/preview/comp-badges.html new file mode 100644 index 0000000..670bae0 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/comp-badges.html @@ -0,0 +1,33 @@ + + + + + +
Status badges
+
+ LIVE + FINISHED + FLAG + STARTED + DNS + DNF + DSQ +
+
Filter chips
+
+ Wave 1 + Wave 2 + Wave 3 ✕ + M40–49 + Elite +
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/comp-buttons.html b/TRM_Design_System-handoff/trm-design-system/project/preview/comp-buttons.html new file mode 100644 index 0000000..94826b8 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/comp-buttons.html @@ -0,0 +1,39 @@ + + + + + +
Buttons
+
+ + + + + +
+
Default · primary (ink) · flag (live) · ghost · disabled
+
+ + + +
+
Sizes — sm 28 · md 36 · lg 44
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/comp-inputs.html b/TRM_Design_System-handoff/trm-design-system/project/preview/comp-inputs.html new file mode 100644 index 0000000..6d3131f --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/comp-inputs.html @@ -0,0 +1,42 @@ + + + + + +
Inputs
+
+
+ + +
Tabular figures — leading zeros optional
+
+
+ + +
+
+ + +
+
+ + +
Bib already in use by Wave 2
+
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/comp-kpi.html b/TRM_Design_System-handoff/trm-design-system/project/preview/comp-kpi.html new file mode 100644 index 0000000..61eadbe --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/comp-kpi.html @@ -0,0 +1,34 @@ + + + + + +
Stat / KPI cards
+
+
+
Active bibs
+
1,247
+
↑ 12 in last 5 min
+
+
+
Lead time
+
42:18.4
+
Bib 247 · split 3
+
+
+
Leader gap
+
+0:04.2
+
↓ closing 0.3s/km
+
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/comp-table.html b/TRM_Design_System-handoff/trm-design-system/project/preview/comp-table.html new file mode 100644 index 0000000..103599e --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/comp-table.html @@ -0,0 +1,32 @@ + + + + + +
+
Leaderboard table · dense 28px
+ + + + + + + + + +
POSBIBNAMEWAVESPLIT 3GAPPACE
1247Maya ChenElite00:42:18.404:13
2188Ravi ParkElite00:42:22.6+0:04.204:14
3044Noemi VegaElite00:42:30.1+0:11.704:15
4302Tomás RieraElite00:42:55.0+0:36.604:18
5119Anika JoshiElite00:43:01.2+0:42.804:19
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/layout-grid.html b/TRM_Design_System-handoff/trm-design-system/project/preview/layout-grid.html new file mode 100644 index 0000000..d575bab --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/layout-grid.html @@ -0,0 +1,43 @@ + + + + + +
+
+ + +
14:02:11
+
+
+
+
+
+
+
+
+
+
+
+
Leaderboard 40%POS BIB NAME GAP
1 247 M.Chen —
2 188 R.Park +0:04.2
3 044 N.Vega +0:11.7
+
Map 40%Track view · checkpoints · live dots
+
Detail 20%Selected athlete
+
+
+
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/spacing-radius.html b/TRM_Design_System-handoff/trm-design-system/project/preview/spacing-radius.html new file mode 100644 index 0000000..9bf7759 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/spacing-radius.html @@ -0,0 +1,22 @@ + + + + + +
Corner radius · square by default
+
+
0
r-0 default
+
2
r-1
+
4
r-2 chip
+
6
r-3 sm card
+
10
r-4 lg card
+
r-pill status
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/spacing-scale.html b/TRM_Design_System-handoff/trm-design-system/project/preview/spacing-scale.html new file mode 100644 index 0000000..27d246b --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/spacing-scale.html @@ -0,0 +1,27 @@ + + + + + +
Spacing scale · 4-px base
+
+
4
s-2
+
8
s-3
+
12
s-4
+
16
s-5
+
20
s-6
+
24
s-7
+
32
s-8
+
40
s-9
+
48
s-10
+
64
s-11
+
80
s-12
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/spacing-shadow.html b/TRM_Design_System-handoff/trm-design-system/project/preview/spacing-shadow.html new file mode 100644 index 0000000..16f5331 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/spacing-shadow.html @@ -0,0 +1,20 @@ + + + + + +
Elevation · printed offset shadow
+
+
flat
shadow-0
surface · no shadow
+
2px
shadow-2
button rest
+
4px
shadow-3
button hover · card
+
soft
shadow-pop
menu · marketing
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/type-body.html b/TRM_Design_System-handoff/trm-design-system/project/preview/type-body.html new file mode 100644 index 0000000..8b35d74 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/type-body.html @@ -0,0 +1,34 @@ + + + + + +
+
+
Race directors trust TRM to time everything from a 60-runner park 5K to a 24-hour endurance event with 4,000 starters across six waves.
+
Lead · 17/24 · Inter 400
+
+
+
Body. Used in marketing copy and long-form documentation. The dashboard itself rarely contains body prose — it's all tables and tokens.
+
Body · 15/22 · Inter 400
+
+
+
Small. Field hints, table footnotes, secondary detail beneath a headline number.
+
Small · 13/18 · Inter 400
+
+
+
Micro. Reserved for table meta and timestamp pills. Use sparingly — must remain legible at glance.
+
Micro · 12/16 · Inter 400
+
+
+
Wave 3 · 4.2 km · 47 starters
+
Overline · 11/14 · Goldplay 600 · +0.10em
+
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/type-display.html b/TRM_Design_System-handoff/trm-design-system/project/preview/type-display.html new file mode 100644 index 0000000..d5474a5 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/type-display.html @@ -0,0 +1,34 @@ + + + + + +
+
+
Lap 14 / 22
+
Display · 56/56 · Goldplay 700
+
+
+
Run any event.
+
H1 · 48/52 · Goldplay 700
+
+
+
Time any sport.
+
H2 · 34/38 · Goldplay 700
+
+
+
Wave 3 starts at 09:15
+
H3 · 26/30 · Goldplay 600
+
+
+
Live race control
+
H4 · 20/24 · Goldplay 600
+
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/type-mono.html b/TRM_Design_System-handoff/trm-design-system/project/preview/type-mono.html new file mode 100644 index 0000000..af5d565 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/type-mono.html @@ -0,0 +1,41 @@ + + + + + +
+
+
01:23:45.6
+
Jumbo · JetBrains Mono 600 · 80px
+
+
+
+00:04.218
+
Mono lg · 40px · gap value
+
+
+
+
04:13/km
+
Mono md · 22px · pace
+
+
+
247
+
Mono md · bib
+
+
+
POS BIB NAME GAP
+
Table header · 14px · uppercase
+
+
+
1 247 M. CHEN —
+
Table row · 14px · tabular figs
+
+
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/preview/type-scale.html b/TRM_Design_System-handoff/trm-design-system/project/preview/type-scale.html new file mode 100644 index 0000000..56112cb --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/preview/type-scale.html @@ -0,0 +1,25 @@ + + + + + +
Type scale
+
+
display
72px
1.05
Aa Race
+
h1
48px
1.05
Aa Race
+
h2
34px
1.20
Aa Race
+
h3
26px
1.20
Aa Race
+
h4
20px
1.35
Aa Race
+
body
15px
1.55
The race begins at noon.
+
small
13px
1.55
The race begins at noon.
+
over
11px
+0.10em
Wave 3 · 47 starters
+
+ diff --git a/TRM_Design_System-handoff/trm-design-system/project/screenshots/dashboard.png b/TRM_Design_System-handoff/trm-design-system/project/screenshots/dashboard.png new file mode 100644 index 0000000..249e69b Binary files /dev/null and b/TRM_Design_System-handoff/trm-design-system/project/screenshots/dashboard.png differ diff --git a/TRM_Design_System-handoff/trm-design-system/project/screenshots/leaderboard.png b/TRM_Design_System-handoff/trm-design-system/project/screenshots/leaderboard.png new file mode 100644 index 0000000..34712cf Binary files /dev/null and b/TRM_Design_System-handoff/trm-design-system/project/screenshots/leaderboard.png differ diff --git a/TRM_Design_System-handoff/trm-design-system/project/screenshots/marketing.png b/TRM_Design_System-handoff/trm-design-system/project/screenshots/marketing.png new file mode 100644 index 0000000..e16523c Binary files /dev/null and b/TRM_Design_System-handoff/trm-design-system/project/screenshots/marketing.png differ diff --git a/TRM_Design_System-handoff/trm-design-system/project/screenshots/mobile.png b/TRM_Design_System-handoff/trm-design-system/project/screenshots/mobile.png new file mode 100644 index 0000000..845e288 Binary files /dev/null and b/TRM_Design_System-handoff/trm-design-system/project/screenshots/mobile.png differ diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/AlertFeed.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/AlertFeed.jsx new file mode 100644 index 0000000..ee22623 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/AlertFeed.jsx @@ -0,0 +1,23 @@ +function AlertFeed({ alerts }) { + return ( +
+
+

Race control feed

+ LIVE +
+
+ {alerts.map((a, i) => ( +
+
+
+
{a.msg}
+
{a.detail}
+
+
{a.time}
+
+ ))} +
+
+ ); +} +window.AlertFeed = AlertFeed; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/EventsTable.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/EventsTable.jsx new file mode 100644 index 0000000..a731ff7 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/EventsTable.jsx @@ -0,0 +1,42 @@ +function EventsTable({ events, onSelect }) { + return ( +
+
+

Events

+
+ + +
+
+ + + + + + + + + + + + + + + {events.map(e => ( + onSelect && onSelect(e)} style={{ cursor: 'pointer' }}> + + + + + + + + + + ))} + +
EVENTDATESPORTSTARTERSWAVESSTATUS
{e.name}{e.date}{e.sport}{e.starters.toLocaleString()}{e.waves}{e.status}
+
+ ); +} +window.EventsTable = EventsTable; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/KpiStrip.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/KpiStrip.jsx new file mode 100644 index 0000000..a788ba4 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/KpiStrip.jsx @@ -0,0 +1,16 @@ +function KpiStrip({ items }) { + return ( +
+ {items.map((it, i) => ( +
+
{it.label}
+
{it.value}
+
+ {it.delta} +
+
+ ))} +
+ ); +} +window.KpiStrip = KpiStrip; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/README.md b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/README.md new file mode 100644 index 0000000..b09cc76 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/README.md @@ -0,0 +1,17 @@ +# Dashboard UI Kit — TRM + +Race director / timing official dashboard. Primary surface for organizing events, managing waves and bibs, and running race control on race day. + +## Screens covered +- **Events overview** — list of upcoming/live/past events with KPI strip +- **Race control** — live event view with leaderboard, mat status, and alert feed + +## Components +- `TopBar.jsx` — sticky header with brand, search, clock, user +- `SideNav.jsx` — primary navigation +- `EventsTable.jsx` — events list with status pills +- `KpiStrip.jsx` — 4-up KPI cards +- `RaceControl.jsx` — leaderboard + alert feed + mat status +- `AlertFeed.jsx` — race-control alerts + +Open `index.html` to interact (click between screens). diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/RaceControl.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/RaceControl.jsx new file mode 100644 index 0000000..031a43d --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/RaceControl.jsx @@ -0,0 +1,58 @@ +function RaceControl({ leaders, alerts, mats }) { + return ( +
+
+
+

Live leaderboard · Coastline 10K

+ LIVE + 00:42:18.4 +
+ + + + + + + + + + + + + + {leaders.map(l => ( + + + + + + + + + + ))} + +
POSBIBNAMEWAVESPLIT 3GAPPACE
{l.pos}{l.bib}{l.name}{l.wave}{l.split}{l.gap}{l.pace}
+
+
+
+

Timing mats

+
+ {mats.map(m => ( +
+ +
+
{m.name}
+
{m.id} · {m.km} km
+
+ {m.reads} +
+ ))} +
+
+ +
+
+ ); +} +window.RaceControl = RaceControl; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/SideNav.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/SideNav.jsx new file mode 100644 index 0000000..6dd1828 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/SideNav.jsx @@ -0,0 +1,39 @@ +function SideNav({ active, onNav }) { + const items = [ + { id: 'events', icon: 'calendar', label: 'Events', badge: '12' }, + { id: 'live', icon: 'radio', label: 'Race control', badge: '1' }, + { id: 'results', icon: 'trophy', label: 'Results' }, + { id: 'participants', icon: 'users', label: 'Participants' }, + { id: 'mats', icon: 'route', label: 'Timing mats' }, + { id: 'reports', icon: 'bar-chart-3', label: 'Reports' }, + ]; + const settings = [ + { id: 'team', icon: 'user-cog', label: 'Team' }, + { id: 'billing', icon: 'credit-card', label: 'Billing' }, + { id: 'settings', icon: 'settings', label: 'Settings' }, + ]; + return ( + + ); +} +window.SideNav = SideNav; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/TopBar.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/TopBar.jsx new file mode 100644 index 0000000..cff7e8d --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/TopBar.jsx @@ -0,0 +1,22 @@ +// TopBar — sticky header for the dashboard. +function TopBar({ clock }) { + return ( +
+
+ TRM + Dashboard +
+
+ + +
+
+ LIVE · 1 EVENT + {clock} + +
JR
+
+
+ ); +} +window.TopBar = TopBar; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/index.html b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/index.html new file mode 100644 index 0000000..782d913 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/dashboard/index.html @@ -0,0 +1,128 @@ + + +TRM Dashboard · UI Kit + + + + + + + + +
+ + + + + + + + diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/kit.css b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/kit.css new file mode 100644 index 0000000..358cef7 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/kit.css @@ -0,0 +1,67 @@ +/* Shared chrome for all UI kits — top bar / sidebar / table tokens */ +:root { --top-h: 56px; --side-w: 240px; } + +* { box-sizing: border-box; } +html, body { margin: 0; padding: 0; min-height: 100vh; background: var(--paper); color: var(--ink); font-family: var(--font-body); } + +.kit-app { display: grid; grid-template-rows: var(--top-h) 1fr; min-height: 100vh; } +.kit-top { + display: grid; grid-template-columns: var(--side-w) 1fr auto; align-items: center; + border-bottom: 1px solid var(--ink); background: var(--paper); + position: sticky; top: 0; z-index: 5; +} +.kit-brand { display: flex; align-items: center; gap: 10px; padding: 0 18px; height: 100%; border-right: 1px solid var(--ink); } +.kit-brand img { height: 22px; width: auto; } +.kit-brand .b-meta { font-family: var(--font-mono); font-size: 10px; color: var(--ink-3); letter-spacing: 0.08em; text-transform: uppercase; } +.kit-search { display: flex; align-items: center; gap: 10px; padding: 0 18px; height: 100%; } +.kit-search input { border: 1px solid var(--ink); height: 32px; width: 320px; padding: 0 10px; font-family: var(--font-mono); font-size: 13px; background: var(--paper-2); border-radius: 2px; } +.kit-top-actions { display: flex; align-items: center; gap: 14px; padding: 0 18px; height: 100%; border-left: 1px solid var(--hairline); } +.kit-clk { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 14px; font-weight: 600; } + +.kit-main { display: grid; grid-template-columns: var(--side-w) 1fr; min-height: 0; } +.kit-side { border-right: 1px solid var(--ink); background: var(--paper); display: flex; flex-direction: column; } +.kit-side-section { padding: 16px 14px 6px; font-family: var(--font-display); font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.10em; color: var(--ink-4); } +.kit-nav-item { display: flex; align-items: center; gap: 10px; padding: 0 14px; height: 36px; font-family: var(--font-display); font-size: 13px; color: var(--ink-2); cursor: pointer; border-left: 2px solid transparent; } +.kit-nav-item:hover { background: var(--paper-2); } +.kit-nav-item.active { background: var(--paper-2); border-left-color: var(--flag); color: var(--ink); font-weight: 600; } +.kit-nav-item [data-lucide] { width: 16px; height: 16px; stroke-width: 2; } +.kit-nav-item .badge { margin-left: auto; font-family: var(--font-mono); font-size: 10px; color: var(--ink-3); } + +.kit-content { padding: 22px 28px; min-width: 0; overflow: hidden; } + +.btn { font-family: var(--font-display); font-weight: 600; font-size: 13px; border: 1px solid var(--ink); background: var(--paper); color: var(--ink); padding: 0 14px; height: 32px; cursor: pointer; display: inline-flex; align-items: center; gap: 8px; box-shadow: 2px 2px 0 0 var(--ink); border-radius: 0; transition: all 120ms var(--ease-snap); } +.btn:hover { box-shadow: 3px 3px 0 0 var(--ink); transform: translate(-1px,-1px); } +.btn:active { box-shadow: 0 0 0 0 var(--ink); transform: translate(2px,2px); } +.btn.primary { background: var(--ink); color: var(--paper); } +.btn.flag { background: var(--flag); color: #fff; } +.btn.ghost { box-shadow: none; } +.btn [data-lucide] { width: 14px; height: 14px; } + +.pill { display:inline-flex; align-items:center; gap:6px; padding: 3px 10px; font-family: var(--font-mono); font-size: 10px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; border-radius: 999px; border: 1px solid currentColor; } +.pill .dot { width:6px; height:6px; border-radius:999px; background: currentColor; } +.pill.live { color: var(--flag); } +.pill.live .dot { animation: pulse 2s infinite ease-out; } +.pill.ok { color: var(--green); } +.pill.warn { color: var(--amber-2); } +.pill.danger { color: var(--flag-2); } +.pill.info { color: var(--blue-2); } +.pill.neutral { color: var(--ink-3); } +@keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(232,65,43,0.6); } 100% { box-shadow: 0 0 0 8px rgba(232,65,43,0); } } + +table.lb { width: 100%; border-collapse: collapse; border: 1px solid var(--ink); } +table.lb th, table.lb td { text-align: left; padding: 0 10px; height: 28px; font-family: var(--font-mono); font-size: 12px; border-bottom: 1px solid var(--hairline); } +table.lb th { background: var(--paper-2); font-weight: 600; font-size: 10px; letter-spacing: 0.10em; text-transform: uppercase; color: var(--ink-3); border-bottom: 1px solid var(--ink); } +table.lb tr:hover td { background: var(--paper-2); } +table.lb td.num { text-align: right; font-variant-numeric: tabular-nums; } +table.lb td.name { font-family: var(--font-display); font-weight: 500; font-size: 13px; } +.gain { color: var(--green); } +.loss { color: var(--flag); } + +.card { border: 1px solid var(--ink); background: var(--paper); } +.card-head { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-bottom: 1px solid var(--ink); background: var(--paper-2); } +.card-head h3 { font-family: var(--font-display); font-size: 13px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; margin: 0; } +.card-body { padding: 14px; } +.kpi { padding: 14px; } +.kpi .lbl { font-family: var(--font-display); font-size: 10px; font-weight: 600; letter-spacing: 0.10em; text-transform: uppercase; color: var(--ink-3); } +.kpi .val { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 32px; font-weight: 600; letter-spacing: -0.02em; line-height: 1; margin-top: 8px; } +.kpi .delta { font-family: var(--font-mono); font-size: 11px; margin-top: 6px; } diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/HeroClock.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/HeroClock.jsx new file mode 100644 index 0000000..b210660 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/HeroClock.jsx @@ -0,0 +1,22 @@ +function HeroClock({ time, eventName, sport, distance, weather }) { + return ( +
+
+
+ TRM + Live tracking + LIVE +
+
{eventName}
+
+ {sport} · {distance} · {weather} +
+
+
+
Race clock
+
{time}
+
+
+ ); +} +window.HeroClock = HeroClock; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/LiveTable.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/LiveTable.jsx new file mode 100644 index 0000000..d311d2c --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/LiveTable.jsx @@ -0,0 +1,33 @@ +function LiveTable({ rows }) { + return ( + + + + + + + + + + + + + + + {rows.map(r => ( + + + + + + + + + + + ))} + +
POSBIBNAMEWAVESPLIT 3GAP TO LEADPACELAST
{r.pos}{r.bib}{r.name}{r.wave}{r.split}{r.gap}{r.pace}{r.last}
+ ); +} +window.LiveTable = LiveTable; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/MiniMap.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/MiniMap.jsx new file mode 100644 index 0000000..5026bc2 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/MiniMap.jsx @@ -0,0 +1,24 @@ +function MiniMap({ checkpoints }) { + return ( +
+
+

Course schematic

+ 10.0 km · 6 mats +
+
+ + + + {checkpoints.map((cp, i) => ( + + + {cp.label} + {cp.km} km + + ))} + +
+
+ ); +} +window.MiniMap = MiniMap; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/README.md b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/README.md new file mode 100644 index 0000000..1af7cac --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/README.md @@ -0,0 +1,12 @@ +# Leaderboard UI Kit — TRM + +Live spectator/broadcast leaderboard view. Optimized for night-mode kiosk and trackside displays. High-density, high-contrast, glanceable. + +## Screens +- **Live leaderboard** with hero clock, race meta, full table, mini-map, last-passings ticker. + +## Components +- `HeroClock.jsx` — jumbo race clock + meta strip +- `LiveTable.jsx` — full-width leaderboard +- `MiniMap.jsx` — schematic course with checkpoint dots +- `Ticker.jsx` — last passings strip across the bottom diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/Ticker.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/Ticker.jsx new file mode 100644 index 0000000..bd712af --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/Ticker.jsx @@ -0,0 +1,20 @@ +function Ticker({ items }) { + return ( +
+
+ {[...items, ...items].map((it, i) => ( + + + {it.cp} + BIB {it.bib} + {it.name} + {it.time} + {it.delta} + + ))} +
+ +
+ ); +} +window.Ticker = Ticker; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/index.html b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/index.html new file mode 100644 index 0000000..88e0376 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/leaderboard/index.html @@ -0,0 +1,96 @@ + + +TRM Live Leaderboard + + + + + + + + +
+ + + + + + diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/FeatureGrid.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/FeatureGrid.jsx new file mode 100644 index 0000000..70acb92 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/FeatureGrid.jsx @@ -0,0 +1,28 @@ +function FeatureGrid() { + const features = [ + { title: 'Chip-time accuracy', body: 'Sub-100ms read precision across UHF and BLE timing mats. One mat, one truth.', stat: '<100ms' }, + { title: 'Any sport', body: 'Run, ride, swim, paddle, sail, ski, drive. Configure laps, splits, transitions per discipline.', stat: '14 sports' }, + { title: 'Live everywhere', body: 'Embed leaderboards anywhere. Push splits to athletes and spectators in real time.', stat: 'Real-time' }, + { title: 'Race control', body: 'Yellow flag, red flag, manual overrides, DSQ workflows. Race directors stay in command.', stat: 'In-app' }, + { title: 'Results in minutes', body: 'Auto-generated category results, exportable to USATF / UCI / FFC formats.', stat: '<2 min' }, + { title: 'Athlete companion', body: 'Free mobile app for participants and supporters. Branded for your event, no extra cost.', stat: 'iOS · Android' }, + ]; + return ( +
+
+
What's in TRM
+

The whole stack — from start mat to certificate.

+
+
+ {features.map((f, i) => ( +
+
{f.stat}
+

{f.title}

+

{f.body}

+
+ ))} +
+
+ ); +} +window.FeatureGrid = FeatureGrid; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/LogoWall.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/LogoWall.jsx new file mode 100644 index 0000000..e2376b7 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/LogoWall.jsx @@ -0,0 +1,14 @@ +function LogoWall() { + const orgs = ['NORTHSHORE MARATHON', 'IRON SANDS ULTRA', 'GRANITE CRIT', 'TWIN PEAKS TRI', 'HARBOR REGATTA', 'SUMMIT VERTICAL', 'MIDNIGHT 24', 'COASTLINE 10K']; + return ( +
+
Trusted by event organizers in 38 countries
+
+ {orgs.map((o, i) => ( +
{o}
+ ))} +
+
+ ); +} +window.LogoWall = LogoWall; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/MktFooter.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/MktFooter.jsx new file mode 100644 index 0000000..0a32ef3 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/MktFooter.jsx @@ -0,0 +1,33 @@ +function MktFooter() { + const cols = [ + { h: 'Product', l: ['Features', 'Sports', 'Hardware', 'Pricing', 'Changelog'] }, + { h: 'Solutions', l: ['Running', 'Cycling', 'Triathlon', 'Sailing', 'Federation'] }, + { h: 'Resources', l: ['Docs', 'API', 'Support', 'Status', 'Help center'] }, + { h: 'Company', l: ['About', 'Customers', 'Careers', 'Press', 'Contact'] }, + ]; + return ( +
+
+
+ TRM +

+ The race-day operating system. Built by timing officials, for timing officials. +

+
+ {cols.map(c => ( +
+
{c.h}
+
+ {c.l.map(x => {x})} +
+
+ ))} +
+
+
© 2026 TRM Tracking & Race Management
+
v3.18.0 · 99.99% uptime · 14:02:11 UTC
+
+
+ ); +} +window.MktFooter = MktFooter; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/MktHero.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/MktHero.jsx new file mode 100644 index 0000000..a506c47 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/MktHero.jsx @@ -0,0 +1,70 @@ +function MktHero() { + return ( +
+
+
+ LIVE NOW · 47 EVENTS +
+

+ Run any event.
+ Time any sport. +

+

+ TRM is the race-day operating system used by 4,000+ event organizers — from 5K fun runs to 24-hour endurance races. One platform for timing, tracking, and results. +

+
+ + +
+
+
+
4,000+
+
Organizers
+
+
+
2.1M
+
Athletes timed
+
+
+
14
+
Sports supported
+
+
+
+
+
+ LIVE + Coastline 10K · Spring 2026 +
+
01:23:45.6
+
+ + + + + + + + + + {[ + { p: 1, n: 'Maya Chen', g: '—' }, + { p: 2, n: 'Ravi Park', g: '+0:04.2' }, + { p: 3, n: 'Noemi Vega', g: '+0:11.7' }, + { p: 4, n: 'Tomás Riera', g: '+0:36.6' }, + ].map((r, i) => ( + + + + + + ))} + +
POSNAMEGAP
{r.p}{r.n}{r.g}
+
+
Embed any leaderboard on your event site
+
+
+ ); +} +window.MktHero = MktHero; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/MktNav.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/MktNav.jsx new file mode 100644 index 0000000..703d2e5 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/MktNav.jsx @@ -0,0 +1,20 @@ +function MktNav() { + const items = ['Product', 'Sports', 'Pricing', 'Customers', 'Docs']; + return ( + + ); +} +window.MktNav = MktNav; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/PricingStrip.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/PricingStrip.jsx new file mode 100644 index 0000000..8a1cf69 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/PricingStrip.jsx @@ -0,0 +1,29 @@ +function PricingStrip() { + const tiers = [ + { name: 'Club', price: '$0', per: 'per event', desc: 'Up to 200 starters · self-service timing.', cta: 'Start free', primary: false }, + { name: 'Organizer', price: '$2', per: 'per starter', desc: 'Unlimited events · race control · live leaderboards.', cta: 'Start trial', primary: true }, + { name: 'Federation', price: 'Custom', per: 'annual', desc: 'White-label · API · SLA · dedicated support.', cta: 'Contact sales', primary: false }, + ]; + return ( +
+
+
Pricing
+

Pay per starter. No setup fees.

+
+
+ {tiers.map((t, i) => ( +
+
{t.name}
+
+ {t.price} + {t.per} +
+

{t.desc}

+ +
+ ))} +
+
+ ); +} +window.PricingStrip = PricingStrip; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/README.md b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/README.md new file mode 100644 index 0000000..7309082 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/README.md @@ -0,0 +1,19 @@ +# Marketing Site UI Kit — TRM + +Single-page marketing site for race organizers evaluating the platform. + +## Sections +- Top nav with brand +- Hero with split layout — bold headline + live data peek +- Logo wall (event organizers using TRM) +- Feature grid +- Pricing strip +- Footer + +## Components +- `MktNav.jsx` +- `MktHero.jsx` +- `LogoWall.jsx` +- `FeatureGrid.jsx` +- `PricingStrip.jsx` +- `MktFooter.jsx` diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/index.html b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/index.html new file mode 100644 index 0000000..857fb2c --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/marketing/index.html @@ -0,0 +1,38 @@ + + +TRM Marketing + + + + + + + + +
+ + + + + + + + diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/BibCard.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/BibCard.jsx new file mode 100644 index 0000000..3f946ed --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/BibCard.jsx @@ -0,0 +1,26 @@ +function BibCard({ bib, name, event, projected, status }) { + return ( +
+
+ LIVE + {event} +
+
+ BIB + {bib} +
+
{name}
+
+
+
Projected finish
+
{projected}
+
+
+
Status
+
{status}
+
+
+
+ ); +} +window.BibCard = BibCard; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/BottomNav.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/BottomNav.jsx new file mode 100644 index 0000000..75e1284 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/BottomNav.jsx @@ -0,0 +1,21 @@ +function BottomNav({ active, onNav }) { + const items = [ + { id: 'race', label: 'My race', icon: 'M12 2v4 M12 18v4 M2 12h4 M18 12h4' }, + { id: 'follow',label: 'Following', icon: 'M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2 M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8 M23 21v-2a4 4 0 0 0-3-3.87 M16 3.13a4 4 0 0 1 0 7.75' }, + { id: 'find', label: 'Find', icon: 'M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16 M21 21l-4.35-4.35' }, + { id: 'me', label: 'Profile', icon: 'M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2 M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8' }, + ]; + return ( +
+ {items.map(it => ( +
onNav(it.id)} style={{ padding: '10px 0 6px', textAlign: 'center', cursor: 'pointer', borderTop: active === it.id ? '2px solid var(--flag)' : '2px solid transparent', marginTop: -1 }}> + + {it.icon.split(' M').map((d, i) => )} + +
{it.label}
+
+ ))} +
+ ); +} +window.BottomNav = BottomNav; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/FollowList.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/FollowList.jsx new file mode 100644 index 0000000..a2094a8 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/FollowList.jsx @@ -0,0 +1,24 @@ +function FollowList({ people, onSelect }) { + return ( +
+
+ Following + {people.length} +
+ {people.map((p, i) => ( +
onSelect && onSelect(p)} style={{ display: 'grid', gridTemplateColumns: '40px 1fr auto', gap: 12, padding: '12px 14px', borderBottom: i < people.length - 1 ? '1px solid var(--hairline)' : 'none', alignItems: 'center', cursor: 'pointer' }}> +
{p.bib}
+
+
{p.name}
+
{p.event} · {p.lastSplit}
+
+
+
{p.time}
+
{p.delta}
+
+
+ ))} +
+ ); +} +window.FollowList = FollowList; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/README.md b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/README.md new file mode 100644 index 0000000..b9c7869 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/README.md @@ -0,0 +1,13 @@ +# Mobile UI Kit — TRM + +Athlete & spectator mobile companion. Inside an iOS frame for context. + +## Screens +- **My race** — athlete view: bib, current split, projected finish, course progress +- **Following** — spectator view: list of tracked athletes with live status + +## Components +- `BibCard.jsx` — hero bib + projected finish +- `SplitList.jsx` — vertical timeline of splits +- `FollowList.jsx` — list of followed athletes +- `BottomNav.jsx` — tab bar diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/SplitList.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/SplitList.jsx new file mode 100644 index 0000000..2ab503d --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/SplitList.jsx @@ -0,0 +1,22 @@ +function SplitList({ splits }) { + return ( +
+
+ Splits + 4 of 6 +
+ {splits.map((s, i) => ( +
+ +
+
{s.name}
+
{s.km} km
+
+
{s.time}
+
{s.delta}
+
+ ))} +
+ ); +} +window.SplitList = SplitList; diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/index.html b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/index.html new file mode 100644 index 0000000..81789fe --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/index.html @@ -0,0 +1,84 @@ + + +TRM Mobile · UI Kit + + + + + + + + +
+ + + + + + + diff --git a/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/ios-frame.jsx b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/ios-frame.jsx new file mode 100644 index 0000000..1a15e27 --- /dev/null +++ b/TRM_Design_System-handoff/trm-design-system/project/ui_kits/mobile/ios-frame.jsx @@ -0,0 +1,338 @@ + +// iOS.jsx — Simplified iOS 26 (Liquid Glass) device frame +// Based on the iOS 26 UI Kit + Figma status bar spec. No assets, no deps. +// Exports: IOSDevice, IOSStatusBar, IOSNavBar, IOSGlassPill, IOSList, IOSListRow, IOSKeyboard + +// ───────────────────────────────────────────────────────────── +// Status bar +// ───────────────────────────────────────────────────────────── +function IOSStatusBar({ dark = false, time = '9:41' }) { + const c = dark ? '#fff' : '#000'; + return ( +
+
+ {time} +
+
+ + + + + + + + + + + + + + + + +
+
+ ); +} + +// ───────────────────────────────────────────────────────────── +// Liquid glass pill — blur + tint + shine +// ───────────────────────────────────────────────────────────── +function IOSGlassPill({ children, dark = false, style = {} }) { + return ( +
+ {/* blur + tint */} +
+ {/* shine */} +
+
+ {children} +
+
+ ); +} + +// ───────────────────────────────────────────────────────────── +// Navigation bar — glass pills + large title +// ───────────────────────────────────────────────────────────── +function IOSNavBar({ title = 'Title', dark = false, trailingIcon = true }) { + const muted = dark ? 'rgba(255,255,255,0.6)' : '#404040'; + const text = dark ? '#fff' : '#000'; + const pillIcon = (content) => ( + +
+ {content} +
+
+ ); + return ( +
+
+ {/* back chevron */} + {pillIcon( + + + + )} + {/* trailing ellipsis */} + {trailingIcon && pillIcon( + + + + + + )} +
+ {/* large title */} +
{title}
+
+ ); +} + +// ───────────────────────────────────────────────────────────── +// Grouped list (inset card, r:26) + row (52px) +// ───────────────────────────────────────────────────────────── +function IOSListRow({ title, detail, icon, chevron = true, isLast = false, dark = false }) { + const text = dark ? '#fff' : '#000'; + const sec = dark ? 'rgba(235,235,245,0.6)' : 'rgba(60,60,67,0.6)'; + const ter = dark ? 'rgba(235,235,245,0.3)' : 'rgba(60,60,67,0.3)'; + const sep = dark ? 'rgba(84,84,88,0.65)' : 'rgba(60,60,67,0.12)'; + return ( +
+ {icon && ( +
+ )} +
{title}
+ {detail && {detail}} + {chevron && ( + + + + )} + {!isLast && ( +
+ )} +
+ ); +} + +function IOSList({ header, children, dark = false }) { + const hc = dark ? 'rgba(235,235,245,0.6)' : 'rgba(60,60,67,0.6)'; + const bg = dark ? '#1C1C1E' : '#fff'; + return ( +
+ {header && ( +
{header}
+ )} +
{children}
+
+ ); +} + +// ───────────────────────────────────────────────────────────── +// Device frame +// ───────────────────────────────────────────────────────────── +function IOSDevice({ + children, width = 402, height = 874, dark = false, + title, keyboard = false, +}) { + return ( +
+ {/* dynamic island */} +
+ {/* status bar (absolute) */} +
+ +
+ {/* nav + content */} +
+ {title !== undefined && } +
{children}
+ {keyboard && } +
+ {/* home indicator — always on top */} +
+
+
+
+ ); +} + +// ───────────────────────────────────────────────────────────── +// Keyboard — iOS 26 liquid glass +// ───────────────────────────────────────────────────────────── +function IOSKeyboard({ dark = false }) { + const glyph = dark ? 'rgba(255,255,255,0.7)' : '#595959'; + const sugg = dark ? 'rgba(255,255,255,0.6)' : '#333'; + const keyBg = dark ? 'rgba(255,255,255,0.22)' : 'rgba(255,255,255,0.85)'; + + // special-key icons + const icons = { + shift: , + del: , + ret: , + }; + + const key = (content, { w, flex, ret, fs = 25, k } = {}) => ( +
{content}
+ ); + + const row = (keys, pad = 0) => ( +
+ {keys.map(l => key(l, { flex: true, k: l }))} +
+ ); + + return ( +
+ {/* liquid glass bg — same recipe as nav pills */} +
+
+ + {/* autocorrect bar */} +
+ {['"The"', 'the', 'to'].map((w, i) => ( + + {i > 0 &&
} +
{w}
+ + ))} +
+ + {/* key layout */} +
+ {row(['q','w','e','r','t','y','u','i','o','p'])} + {row(['a','s','d','f','g','h','j','k','l'], 20)} +
+ {key(icons.shift, { w: 45, k: 'shift' })} +
+ {['z','x','c','v','b','n','m'].map(l => key(l, { flex: true, k: l }))} +
+ {key(icons.del, { w: 45, k: 'del' })} +
+
+ {key('ABC', { w: 92.25, fs: 18, k: 'abc' })} + {key('', { flex: true, k: 'space' })} + {key(icons.ret, { w: 92.25, ret: true, k: 'ret' })} +
+
+ + {/* bottom spacer (emoji+mic area, icons omitted) */} +
+
+ ); +} + +Object.assign(window, { + IOSDevice, IOSStatusBar, IOSNavBar, IOSGlassPill, IOSList, IOSListRow, IOSKeyboard, +}); diff --git a/TRM_Design_System-handoff/trm-design-system/project/uploads/goldplay-bold.ttf b/TRM_Design_System-handoff/trm-design-system/project/uploads/goldplay-bold.ttf new file mode 100644 index 0000000..9baf3d9 Binary files /dev/null and b/TRM_Design_System-handoff/trm-design-system/project/uploads/goldplay-bold.ttf differ diff --git a/TRM_Design_System-handoff/trm-design-system/project/uploads/goldplay-regular.ttf b/TRM_Design_System-handoff/trm-design-system/project/uploads/goldplay-regular.ttf new file mode 100644 index 0000000..174d58f Binary files /dev/null and b/TRM_Design_System-handoff/trm-design-system/project/uploads/goldplay-regular.ttf differ diff --git a/TRM_Design_System-handoff/trm-design-system/project/uploads/logo-1777578841639.png b/TRM_Design_System-handoff/trm-design-system/project/uploads/logo-1777578841639.png new file mode 100644 index 0000000..18063dc Binary files /dev/null and b/TRM_Design_System-handoff/trm-design-system/project/uploads/logo-1777578841639.png differ