docs: import TRM design handoff + defer adoption to phase 3.8

A design handoff bundle generated by Claude Design (claude.ai/design)
on 2026-05-02. Defines the Bloomberg/F1-pit-wall aesthetic for TRM:
- ink-on-paper base + race-flag red accent (#E8412B)
- square-edged everything, sharp printed offset shadows
- mono numerics (JetBrains Mono) for any changing value
- Goldplay (real licensed font, three weights in bundle fonts/)
- four surfaces designed: dashboard / leaderboard / mobile / marketing
  (SPA scope is the first two)

The bundle is committed in-tree at TRM_Design_System-handoff/ so 3.8
has the full source material when it picks the work up. Includes:
- Top-level + project READMEs (the design spec)
- chats/chat1.md (intent + iteration history)
- colors_and_type.css (token set, drop-in for Tailwind 4 @theme)
- fonts/ (Goldplay regular/semibold/bold)
- ui_kits/ (HTML prototypes per surface)
- preview/ (per-token visual reference cards)

Updated phase-3-dogfood-readiness/README.md task 3.8 row to point at
the bundle and document the recommended approach (retheme shadcn via
CSS variable overrides + Tailwind 4 @theme, not replace).

Why deferred: foundational tokens are non-blocking for Phase 1 (login
+ placeholder home) and Phase 2 (live map without chrome). Applying
them now would either delay dogfood-blocking work or land partial
styling that gets reworked when 3.8 lands the full pass.
This commit is contained in:
2026-05-02 19:10:11 +02:00
parent 0467a4b7ef
commit 8223a566e4
72 changed files with 3154 additions and 1 deletions
@@ -0,0 +1,84 @@
<!doctype html>
<html><head><meta charset="utf-8">
<title>TRM Mobile · UI Kit</title>
<link rel="stylesheet" href="../../colors_and_type.css">
<link rel="stylesheet" href="../kit.css">
<style>
body { background: var(--paper-3); display: flex; align-items: center; justify-content: center; padding: 32px; min-height: 100vh; }
.stage { display: flex; gap: 32px; align-items: flex-start; }
</style>
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel" src="ios-frame.jsx"></script>
<script type="text/babel" src="BibCard.jsx"></script>
<script type="text/babel" src="SplitList.jsx"></script>
<script type="text/babel" src="FollowList.jsx"></script>
<script type="text/babel" src="BottomNav.jsx"></script>
<script type="text/babel">
const { useState } = React;
const SPLITS = [
{ name: 'Start', km: 0, time: '09:00:00.0', delta: '—', passed: true },
{ name: 'Split 1', km: 2.5, time: '00:10:38.4', delta: '-0:01.2', passed: true },
{ name: 'Split 2', km: 5.0, time: '00:21:14.7', delta: '-0:02.0', passed: true },
{ name: 'Split 3', km: 7.5, time: '00:31:55.1', delta: '+0:00.4', passed: true },
{ name: 'Split 4', km: 9.0, time: '—', delta: '—', passed: false },
{ name: 'Finish', km: 10, time: '—', delta: '—', passed: false },
];
const PEOPLE = [
{ bib: 247, name: 'Maya Chen', event: 'Coastline 10K', lastSplit: 'Split 3', time: '31:55.1', delta: '+0:00.4' },
{ bib: 188, name: 'Ravi Park', event: 'Coastline 10K', lastSplit: 'Split 3', time: '32:01.6', delta: '-0:01.8' },
{ bib: 44, name: 'Noemi Vega', event: 'Coastline 10K', lastSplit: 'Split 3', time: '32:08.4', delta: '+0:02.1' },
{ bib: 612, name: 'Diego Acosta', event: 'Twin Peaks Tri', lastSplit: 'Bike', time: '1:12:04', delta: '-0:18.0' },
];
function MyRace() {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 14, padding: 14 }}>
<BibCard bib="247" name="Maya Chen" event="Coastline 10K · Spring 2026" projected="00:42:12" status="ON PACE · PB" />
<SplitList splits={SPLITS} />
</div>
);
}
function Following({ onSelect }) {
return (
<div style={{ padding: 14 }}>
<FollowList people={PEOPLE} onSelect={onSelect} />
</div>
);
}
function App() {
const [tab, setTab] = useState('race');
return (
<div className="stage">
<IOSDevice title="My race" width={390} height={780}>
<div style={{ background: 'var(--paper-2)', minHeight: '100%', display: 'flex', flexDirection: 'column' }}>
<div style={{ flex: 1, overflow: 'auto' }}>
{tab === 'race' && <MyRace />}
{tab === 'follow' && <Following onSelect={() => setTab('race')} />}
{tab === 'find' && <div style={{ padding: 24, textAlign: 'center', color: 'var(--ink-4)', fontFamily: 'var(--font-mono)', fontSize: 12 }}>Search any event by name or bib.</div>}
{tab === 'me' && <div style={{ padding: 24, textAlign: 'center', color: 'var(--ink-4)', fontFamily: 'var(--font-mono)', fontSize: 12 }}>Profile · history · personal bests</div>}
</div>
<BottomNav active={tab} onNav={setTab} />
</div>
</IOSDevice>
<IOSDevice title="Following" width={390} height={780}>
<div style={{ background: 'var(--paper-2)', minHeight: '100%', display: 'flex', flexDirection: 'column' }}>
<div style={{ flex: 1, overflow: 'auto' }}><Following /></div>
<BottomNav active="follow" onNav={() => {}} />
</div>
</IOSDevice>
</div>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>
</body></html>