// phone-mock.jsx — iPhone frame + faithful screen recreations, synced to the // CURRENT project_blackdevil source (July 2026): // Today/Desk/Ledger + nav → "Shift Board" (design_handoff_shift_board_v2): // 0-radius, corner-cut CTAs, flush near-black/paper surfaces, mono // uppercase instrument labels, safety-orange (#FF5C00 dark / #C4502A // light terracotta) — from src/components/v2/TodaySurface.tsx, // CommandBarV2.tsx, src/components/desk/{DeskView,DecisionCard}.tsx, // src/components/v2/LedgerView.tsx, src/app/globals.css (--sb-* tokens). // Composer / Job record / Customers → still the warm "Rams" rounded-card // system (not yet Shift-Board-converted) but repainted to the SAME new // brand hex, since --brand-rams was repointed as part of the July 2 brand // unification — from src/components/v2/ComposerView.tsx, // src/components/v2/JobWorksurface.tsx, src/components/v2/CustomerWorksurface.tsx. const { useEffect, useRef } = React; // EKG waveform path — same as the actual product's logo (CommandBarV2's // WerkdPulse / HomeUI HEART_PATH). const EKG_PATH = 'M2 20L10 20L17 36L28 4L36 36L47 4L54 20L62 20'; // Inline lucide-style icon component (no external library needed at runtime — // these stroke paths come from lucide.dev). function Icon({ name, size = 18, color = 'currentColor', strokeWidth = 1.75, style }) { const paths = { 'map-pin': <>, 'navigation': <>, 'phone': <>, 'clock': <>, 'alert-circle': <>, 'bell': <>, 'chevron-right': <>, 'chevron-left': <>, 'edit': <>, 'trash': <>, 'mail': <>, 'share-2': <>, 'star': <>, 'more-vertical': <>, 'send': <>, 'plus': <>, 'check-circle': <>, 'dollar': <>, 'file-text': <>, 'calendar': <>, 'trending-up': <>, 'alert-triangle': <>, 'home': <>, 'briefcase': <>, 'camera': <>, 'mic': <>, 'message-circle': <>, 'wrench': <>, 'x': <>, 'user': <>, 'signal': <>, 'wifi': <>, 'battery': <>, 'battery-full': <>, 'pause': <>, 'play': <>, 'chevron-down': <>, 'dollar-sign': <>, 'message-square': <>, 'sparkles': <>, 'search': <>, 'bookmark': <>, 'receipt': <>, 'settings': <>, 'zap': <>, 'package': <>, 'clipboard-list': <>, 'credit-card': <>, 'user-plus': <>, 'bar-chart': <>, 'tag': <>, 'check': <>, 'users': <>, 'moon': <>, 'book-open': <>, 'route': <>, 'shield-check': <>, 'calendar-clock': <>, 'inbox': <>, }; return ( {paths[name]} ); } // Werkd EKG logo mark (waveform, no badge/background or glow — bare mark only). function WerkdMark({ size = 40, color = '#FF5C00' }) { // No container box: the mark is just the waveform glyph. Sized ~20% larger // (relative to the old badge-relative sizing) since there's no padding to // eat into anymore. Aspect ratio matches the viewBox (64:40 = 1.6:1). const h = size * 0.5; const w = h * 1.6; return ( ); } // Werkd wordmark — official spec. // Inter 800, letter-spacing -0.05em. // "werk" in main color, "d" + "." in brand orange. function WerkdWordmark({ size = 32, color = '#171717', dotColor = '#FF5C00' }) { return ( werkd. ); } // Phone frame — iPhone-ish with screen content as children. Glove-friendly: matches the product's // safe-area + bottom-nav presence. function PhoneFrame({ children, width = 340, scale = 1, theme = 'dark', tilt = 0, glow = false }) { const h = width * 2.16; // ~ iPhone 15 Pro aspect return (
{/* Outer titanium bezel */}
{/* Inner black bezel */}
{/* Screen */}
{/* Dynamic Island */}
{children}
); } // ── Shift Board (design_handoff_shift_board_v2) token set ────────────────── // Today / Desk / Ledger + the nav are fully converted to this system: // 0-radius everywhere (circles + the 8px nav badge are the only exceptions), // corner-cut CTAs (clip-path notch), flush near-black (dark) / warm paper // (light) surfaces, mono uppercase tracked instrument labels. Values lifted // verbatim from src/app/globals.css --sb-* custom properties. function SBC(isDark) { return isDark ? { bg: '#0c0d0f', bgNav: '#101114', panel: '#14161a', hairline: '#1b1e22', border: '#26292e', borderStrong: '#33373d', text: '#f2f2f0', textHigh: '#e7e8e9', text2: '#c9cbce', muted: '#9a9ca0', faint: '#6e7176', ghost: '#43474d', brand: '#ff5c00', brandText: '#ff9257', danger: '#ff4747', dangerText: '#ff6b6b', warn: '#e8a344', money: '#4ade80', hazardBg: 'repeating-linear-gradient(-45deg, #2a1206 0 6px, #1a0c04 6px 12px)', onBrand: '#0c0d0f', } : { bg: '#f6f2ea', bgNav: '#f1ece1', panel: '#fdfcf8', hairline: '#e4ddce', border: '#dad3c4', borderStrong: '#c9c1b0', text: '#201d18', textHigh: '#2a2620', text2: '#4a453c', muted: '#6b655b', faint: '#8a8478', ghost: '#b5ac99', brand: '#c4502a', brandText: '#b04724', danger: '#d03b2f', dangerText: '#b0342a', warn: '#9a6b1f', money: '#2e6b44', hazardBg: 'repeating-linear-gradient(-45deg, #f5ded6 0 6px, #efd2c8 6px 12px)', onBrand: '#f6f2ea', }; } const SB_CUT_HERO = 'polygon(0 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%)'; const SB_CUT_CARD = 'polygon(0 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%)'; // SB mono section label — 0.22em tracked uppercase, orange when accent. function SBLabel({ C, children, right, accent }) { return (
{children} {right && {right}}
); } // 38px→31px SB header circle (Map / Calendar / Settings). function SBCircle({ C, icon, size = 31 }) { return (
); } // SB header — wordmark ("d." orange) + mono meta line, 3 circles right. function SBHeader({ C, meta, icons }) { return (
Werkd.
{meta && (
{meta}
)}
{icons.map((ic, i) => )}
); } // SB stat strip — 3 cells, 1px rules, mono values over tracked mono labels. function SBStatRow({ C, cols }) { return (
{cols.map((c, i) => (
0 ? '1px solid ' + C.border : 'none' }}>
{c.value}
{c.label}
))}
); } // SB hairline notice row — 3px square rail, body title + faint sub, money/action right. function SBNoticeRow({ C, tone, label, sub, right, action, first }) { const rail = tone === 'danger' ? C.danger : tone === 'warning' ? C.warn : C.brand; return (
{label} {sub && {sub}} {right && {right}} {action ? ( {action} ) : ( )}
); } // v2 bottom nav — Today · Desk · Ledger + far-right ⊕ FAB (CommandBarV2.tsx). // Flush bg-nav bar, 1px top border. Active = safety orange, mono 9px tracked // caps, NO underline/notch (spec explicitly drops it). FAB is a dominant // orange circle carrying the Werkd pulse mark, ringed by the bar's own bg so // it "cuts" out of the top border. function CommandBar({ theme = 'dark', active = 'today', deskCount = 2 }) { const C = SBC(theme === 'dark'); const tabs = [ { id: 'today', label: 'Today', icon: 'home' }, { id: 'desk', label: 'Desk', icon: 'inbox', badge: deskCount }, { id: 'ledger', label: 'Ledger', icon: 'search' }, ]; return (
{tabs.map((tab) => { const on = active === tab.id; return (
{tab.badge > 0 && ( {tab.badge} )} {tab.label}
); })} {/* ⊕ Composer FAB — far-right, dominant, rides above the bar */}
); } function V2HomeIndicator({ isDark }) { return (
); } // TODAY — "The Line" (TodaySurface.tsx, Shift Board). Header → NEXT JOB label // + big instrument clock + leave/late chip → hero panel (name/address/desc + // Navigate & start + Call/AI job prep) → stat row → Needs review → Queue. function TodayScreen({ theme = 'dark', state = 'default', spotlight = false }) { const isDark = theme === 'dark'; const C = SBC(isDark); return (
Next job {/* Instrument clock — big bold hour, stacked mins + AM/PM, mono chip */}
10 30 AM
LEAVE IN 12 MIN
THU, JUL 2
{/* Hero instrument panel — fill + border, 4px tone rail */}
Aria Russell
30 min drive
2847 Birch Lane
Remove old thermostat, install smart, verify zone wiring.
Navigate & start
Call
AI job prep →
Needs review Queue
{[ { t: '11:00A', n: 'Dave Wilson', d: 'Outlet repair', a: '$140', done: false }, { t: '8:00A', n: 'Mike — Drain clear', d: null, a: '$185', done: true }, ].map((j, i) => (
{j.t} {j.n} {j.d ? {j.d} : DONE · {j.a}} {!j.done && {j.a}}
))}
); } function V2StatusBar({ C }) { return (
9:41
); } // ── Rams (not yet Shift-Board-converted) token set — Composer, Job record, // Customers still use these rounded warm surfaces. Brand hex updated to the // July 2 unification (--brand-rams now resolves to the same new orange). function V2C(isDark) { return isDark ? { bg: '#181714', card: '#22201c', control: '#302c26', border: '#38322b', strong: '#453e34', text: '#f5f5f7', text2: '#a8a8b0', text3: '#8a8a92', muted: '#6c6c74', brand: '#ff5c00', ink: '#0c0d0f', danger: '#ee5555', warn: '#e8a344', success: '#3cc26d', brandMuted: 'rgba(255,92,0,0.12)', dangerMuted: 'rgba(238,85,85,0.12)', dim: 'rgba(0,0,0,0.5)', } : { bg: '#f8f4ed', card: '#fffdfa', control: '#f0ece6', border: '#e3d8c9', strong: '#d3c6b3', text: '#171717', text2: '#6f7177', text3: '#9a9ca3', muted: '#9a9ca3', brand: '#c4502a', ink: '#f6f2ea', danger: '#dc2626', warn: '#d97706', success: '#16a34a', brandMuted: 'rgba(196,80,42,0.10)', dangerMuted: 'rgba(220,38,38,0.10)', dim: 'rgba(0,0,0,0.32)', }; } function V2Label({ C, children, right, dot, dotColor }) { return (
{dot && } {children} {right && {right}}
); } // DESK — "Decisions, not documents" (DeskView.tsx + DecisionCard.tsx, Shift // Board). 76px instrument count hero, mono kind labels + 4px tone rail cards, // corner-cut CTAs, "Werkd did" journal. function DeskScreen({ theme = 'dark' }) { const isDark = theme === 'dark'; const C = SBC(isDark); const cards = [ { rail: C.danger, kind: 'COLLECT · $1,847', kc: C.dangerText, title: 'Mike Chen — invoice 14 days late', receipt: 'Friendly-but-firm reminder drafted · 3rd nudge', amt: '$1,847', cta: 'Send reminder', adjust: true }, { rail: C.warn, kind: 'REVENUE', kc: C.warn, title: 'Aria Russell — job done, uninvoiced', receipt: 'Invoice drafted from today’s job', amt: '$420', cta: 'Review & send →', adjust: true }, { rail: C.borderStrong, kind: 'CLOSE', kc: C.muted, title: 'Close out today', receipt: '1 job left to invoice · books tidy', amt: null, cta: 'Close the day', adjust: false }, ]; return (
On your desk
3 Decisions
{cards.map((card, i) => (
{card.kind}
{card.title} {card.amt && {card.amt}}
{card.receipt}
{card.cta} {card.adjust && Adjust} skip
))}
Werkd did {[ { t: '4:51', l: 'Invoice sent to Mike Chen — $185' }, { t: '3:12', l: 'Quote follow-up sent to Dave Wilson' }, ].map((j, i) => (
0 ? '1px solid ' + C.hairline : 'none' }}> {j.t} {j.l}
))}
); } // LEDGER — "Look it up, then leave" (LedgerView.tsx, Shift Board). Collected // hero (money-green instrument numeral), pulse strip, AI brief ladder, // omnibox, tools row, recents. function LedgerScreen({ theme = 'dark' }) { const isDark = theme === 'dark'; const C = SBC(isDark); return (
Collected · June
$12,400 +18% vs May
3 invoices are overdue, $1,847 at risk. Chase
{[['tag', 'Price book'], ['bar-chart', 'Reports'], ['users', 'Customers']].map(([ic, l], i) => (
{l}
))}
Recent {[ { ic: 'receipt', l: 'Invoice #1041 — Tom Parker', s: 'Paid · $1,240', sc: SBC(isDark).money }, { ic: 'file-text', l: 'Quote #318 — Dave Wilson', s: 'Sent · expires in 6 days', sc: C.faint }, { ic: 'user', l: 'Aria Russell', s: '3 jobs · $1,260 lifetime', sc: C.faint }, ].map((r, i) => (
0 ? '1px solid ' + C.hairline : 'none' }}> {r.l} {r.s}
))}
); } const MoneyScreen = LedgerScreen; // v1 Money tab folded into Ledger // ⊕ COMPOSER — capture-first create (ComposerView.tsx, still Rams-style): // voice bar → "or pick one" create rows → sharp CTA. function ComposerScreen({ theme = 'dark' }) { const isDark = theme === 'dark'; const C = V2C(isDark); const rows = [ { icon: 'briefcase', t: 'New job', s: 'Book a customer and time', sel: true }, { icon: 'file-text', t: 'New quote', s: 'Price up work to send' }, { icon: 'receipt', t: 'New invoice', s: 'Bill a completed job' }, { icon: 'credit-card', t: 'Log expense', s: 'Snap a receipt or cost' }, { icon: 'camera', t: 'Photo diagnosis', s: 'Snap a photo, get a fix' }, ]; return (
{/* dimmed Today behind the sheet */}
Saturday, May 23
{/* the sheet */}
Just say what happened
{/* voice bar */}
Hold to talk
Hold to talk · tap to type
{/* OR PICK ONE */}
Or pick one
{rows.map((r, i) => (
{r.t} {r.s} {r.sel ? : }
))} {/* sharp CTA (radius-cta 4) */}
Start New job
); } const AIHubScreen = ComposerScreen; // retired v1 hub — kept as an alias // JOB WORKSURFACE — the record-surface recipe (JobWorksurface.tsx, still // Rams-style): ⌄ top bar, one card per concern, sticky one-CTA footer. function JobRecordScreen({ theme = 'dark' }) { const isDark = theme === 'dark'; const C = V2C(isDark); const card = { border: '1px solid ' + C.strong, background: C.card, borderRadius: 12, padding: '9px 11px', marginTop: 9, boxShadow: isDark ? '0 1px 3px rgba(0,0,0,0.2)' : '0 1px 3px rgba(29,24,18,0.06)' }; const label = { fontSize: 8, fontWeight: 700, letterSpacing: '0.12em', textTransform: 'uppercase', color: C.text3, marginBottom: 2 }; const chip = (ic) => ( ); const link = (t) => {t} ; const row = { display: 'flex', alignItems: 'center', gap: 9, padding: '7px 0' }; return (
{/* top bar: ⌄ minimize + status + kind pill */}
Job · scheduled
Schedule
Aria Russell
2847 Birch Lane · Smart thermostat swap
Schedule
{chip('calendar')} Sat, May 23 · 10:30 AM Est. 1.5 hours {link('Reschedule')}
Customer
{chip('phone')} (555) 014-2288 CallText
{chip('map-pin')} 2847 Birch Lane {link('Route')}
Job
{chip('clock')} Remove old thermostat, install smart, verify zone wiring. $420
Materials
{chip('package')} Smart thermostat $185
Photos
{chip('camera')} 2 photos added {link('Manage')}
{/* sticky footer — ONE primary CTA + Adjust; the rest are text links */}
Start job Adjust
Reschedule Cancel job
); } // Customer record — CustomerWorksurface.tsx (still Rams-style): identity + // contact + history cards, "Full profile →" CTA. (The legacy fuller detail // panel this used to recreate has been superseded by this leaner worksurface.) function CustomersScreen({ theme = 'dark' }) { const isDark = theme === 'dark'; const C = isDark ? { bg: '#181714', surface: '#22201c', surface2: '#302c26', text: '#f5f5f7', text2: '#a8a8b0', text3: '#8a8a92', hairline: '#38322b', hairlineStrong: '#453e34', brand: '#ff5c00', onBrand: '#0c0d0f', success: '#3cc26d', warn: '#e8a344', successMuted: 'rgba(60,194,109,0.14)', brandMuted: 'rgba(255,92,0,0.14)', } : { bg: '#f8f4ed', surface: '#fffdfa', surface2: '#f0ece6', text: '#171717', text2: '#6f7177', text3: '#9a9ca3', hairline: '#e3d8c9', hairlineStrong: '#d3c6b3', brand: '#c4502a', onBrand: '#f6f2ea', success: '#16a34a', warn: '#d97706', successMuted: 'rgba(22,163,74,0.10)', brandMuted: 'rgba(196,80,42,0.10)', }; return (
9:41
Customer
Aria Russell
2847 Birch Ln, Lakewood
{/* Contact card */}
Contact
{[ { icon: 'phone', value: '(312) 555-0142', action: 'Call' }, { icon: 'mail', value: 'aria.russell@email.com', action: 'Email' }, { icon: 'map-pin', value: '2847 Birch Ln, Lakewood', action: 'Route', accent: true }, ].map((r, i, arr) => (
0 ? '1px solid ' + C.hairline : 'none', }}> {r.value} {r.action} →
))}
{/* History card */}
History
Last job Mar 8 $4,820 lifetime
{/* Notes card */}
Notes
Gate code 4417 · dog in yard. Prefers text over calls.
{/* Full profile CTA — footer, mirrors RecordWorksurface's single-CTA recipe */}
Full profile
); } Object.assign(window, { Icon, WerkdMark, WerkdWordmark, PhoneFrame, TodayScreen, CommandBar, ComposerScreen, AIHubScreen, DeskScreen, LedgerScreen, MoneyScreen, JobRecordScreen, CustomersScreen, EKG_PATH, });