Files
nucleic/website/cockpit-mobile.html
T
abkslmandnucleic af875217a5 Prevent Google Fonts IP Collection
Nucleic-Session: 70972BA4-18A4-4077-AFC2-9CD7F5873D2F
Co-authored-by: Nucleic <[email protected]>
2026-06-29 21:05:49 -07:00

461 lines
25 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Nucleic — iPhone cockpit mock (faithful web port of the iOS app)</title>
<!-- Self-hosted fonts (latin subset). The woff2 binaries live in fonts/ and are
preloaded so they download in parallel with the HTML; @font-face is inlined
(no render-blocking stylesheet) and the page never contacts Google. -->
<link rel="preload" href="fonts/space-grotesk.woff2" as="font" type="font/woff2" crossorigin />
<link rel="preload" href="fonts/jetbrains-mono.woff2" as="font" type="font/woff2" crossorigin />
<style>
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:400 700;font-display:swap;src:url(fonts/space-grotesk.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400 500;font-display:swap;src:url(fonts/jetbrains-mono.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
</style>
<!--
============================================================================
NUCLEIC iPHONE COCKPIT — web-compatible port of the iOS app (NucleicRemote)
============================================================================
FOR THE WEBSITE AGENT
Self-contained, previewable port of Nucleic's *phone* interface — the iOS
app's Home tab. It is the mobile counterpart to website/cockpit.html (the Mac
cockpit): where that shows the desktop home + Control sidebar, this shows the
phone the app actually ships, so the site can swap the wide Mac window for the
app surface on small screens.
NO DEVICE FRAME. Because this renders ON a phone, drawing a phone around it
would be a phone-in-a-phone. So there is no bezel, no status bar (clock /
signal / wifi / battery), no Dynamic Island, no home indicator — only the app's
own chrome (the tab bar and the connection chip). The app content sits in a
clean, borderless surface framed like the desktop cockpit: a rounded card with a
hairline border and soft shadow. Internal scrolling is locked — the card sizes to
its content and the page scrolls.
GROUNDED IN THE iOS SOURCE (ios/NucleicRemote/NucleicRemote):
• RootView (NucleicRemoteApp.swift) — the 5-tab bar: Home · Sessions ·
Projects · To-dos · Settings, tinted with Palette.accent (teal). Sessions
carries .badge(needsYouCount).
• HomeView.swift — greeting (time-of-day) + StreakBadge, the five StatCards
(Projects / In progress / Active / Messages / Tokens), the GitHub-style
ActivityGrid in a card, the InProgressSessions card, then QuickTodos and
StartChatComposer. navigationTitle("Home"), inline.
• SessionRow (SessionsView.swift) — status symbol+color, title + project,
trailing pending-approval pill / diffstat.
• Composer.swift — QuickTodos (capture field + idea rows) and
StartChatComposer (project + Auto, model + effort, prompt + send).
• ConnectionChip.swift — the floating "Connected · LAN" capsule pinned to the
bottom safe area above the tab bar.
• Theme.swift — Palette (teal accent, blue/amber/green/purple status,
frozen blue, orchestra gold) and StatusStyle (symbol/label per status).
CONTENT mirrors the app's offline preview seed (RemoteStore.seedDemo, used for
NUCLEIC_DEMO UI previews) so every number, title, and status is real app data:
host "Andrew's Mac"; 2 projects (nucleic, website); 5 chats, 2 active, 142
messages, 1.28M tokens; the running "flaky-tests" chat; three captured ideas.
THEME: the app adapts to the system; this port is pinned to iOS LIGHT mode —
systemBackground white, secondarySystemBackground (#f2f2f7) cards with a
primary-6% hairline, the iOS semantic label tiers, and the exact Palette sRGB
values from Theme.swift. It uses the phone's TEAL accent (Palette.accent),
not the Mac cockpit's violet Control accent — this is the product on a phone.
HOW TO COPY IT IN (three regions, all scoped under `.nuc-ios`, no collisions):
1. Copy the contents of <style data-nuc-ios> … </style> into the site's <style>.
2. Drop the <div class="nuc-ios"> … </div> markup wherever the phone should show.
3. Copy the <script data-nuc-ios> … </script> block before </body> (it sizes the
activity grid to its column, like the app's GeometryReader; idempotent + guarded).
TO REPLACE THE MAC COCKPIT ON MOBILE (in website/index.html — do NOT edit it from
here; this is just the recipe). The Mac window lives at `.showcase .nuc-cockpit`.
Put the phone next to it and let one CSS breakpoint trade them:
.nuc-ios{ display:none } /* desktop: phone hidden */
@media (max-width:860px){
.showcase .nuc-cockpit{ display:none } /* mobile: hide the Mac window */
.nuc-ios{ display:flex } /* …show the phone instead */
}
860px is the same breakpoint cockpit.html already uses to drop its sidebar.
Everything is namespaced under `.nuc-ios` with its own CSS variables, so it
neither reads from nor pollutes the site's :root tokens.
============================================================================
-->
<style data-nuc-ios>
/* ===== Nucleic iPhone cockpit — scoped, iOS light mode, Home tab ============ */
.nuc-ios{
/* Surfaces — iOS light system colors (UX_IOS / Theme.swift CardBackground) */
--bg:#ffffff; /* systemBackground — the Home ScrollView */
--card:#f2f2f7; /* secondarySystemBackground — .card() surfaces */
--field:#ffffff; /* .roundedBorder text field fill */
--hair:rgba(0,0,0,.07); /* Color.primary.opacity(.06) card hairline */
--field-hair:rgba(0,0,0,.16);
--tabbar:rgba(249,249,249,.94);
/* Text — iOS semantic label tiers (light) */
--label:#000000; /* UIColor.label */
--label2:rgba(60,60,67,.6); /* secondaryLabel */
--label3:rgba(60,60,67,.3); /* tertiaryLabel */
--tab-off:#999a9f; /* unselected tab item */
/* Palette.swift — the mobile categorical palette (exact sRGB) */
--accent:#0a8580; /* deep teal — Palette.accent (.04,.52,.50) */
--active:#338cf2; /* blue — running (.20,.55,.95) */
--attention:#ffa626;/* amber — awaiting approval (1,.65,.15) */
--success:#4dcc73; /* green — finished/done (.30,.80,.45) */
--paused:#9e7ded; /* purple — interrupted (.62,.49,.93) */
--danger:#eb5757; /* red — error / badge (.92,.34,.34) */
--frozen:#42a3f5; /* iced streak-freeze blue (.26,.64,.96) */
--orchestra:#e6a829;/* orchestra gold (.90,.66,.16) */
/* ActivityGrid shades — Palette.activity(intensity): success.opacity(i),
empty = secondary.opacity(.15) */
--a0:#e3e3e8;
--a1:rgba(77,204,115,.4);
--a2:rgba(77,204,115,.65);
--a3:rgba(77,204,115,.82);
--a4:#4dcc73;
--mono:"JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
/* surface geometry — a borderless app card (no device frame); sizes to its
content with scrolling locked (the page scrolls); fits any viewport (max-width:100%) */
--w:360px;
font-family:-apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", system-ui, "Space Grotesk", Arial, sans-serif;
color:var(--label);
display:flex;justify-content:center;
/* illustrative chrome — keep its text unselectable */
-webkit-user-select:none;user-select:none;
}
.nuc-ios *{box-sizing:border-box}
.nuc-ios svg{display:block}
/* ---- borderless app surface (framed like the desktop cockpit — no device
bezel, status bar, Dynamic Island, or home indicator; this already renders
on a phone) ------------------------------------------------------------- */
.nuc-ios .ios-phone{
position:relative;
width:var(--w);max-width:100%; /* height: natural (content-sized) */
display:flex;flex-direction:column;
background:var(--bg);
border:1px solid var(--hair);
border-radius:16px;overflow:hidden;
box-shadow:0 1px 0 rgba(255,255,255,.7) inset,
0 30px 70px -40px rgba(40,30,50,.40);
}
/* ---- Home content (no title bar — content starts at the top; scrolling locked,
the surface sizes to its content and the page scrolls) --------------------- */
.nuc-ios .ios-content{
padding:22px 16px 120px; /* bottom room for the chip + tab bar */
display:flex;flex-direction:column;gap:22px;
}
/* greeting + streak (HomeView header HStack) */
.nuc-ios .ios-hi{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
.nuc-ios .ios-hi h1{margin:0;font-size:27px;font-weight:700;letter-spacing:-.02em;line-height:1.05}
.nuc-ios .ios-hi .sub{margin:5px 0 0;font-size:14px;color:var(--label2)}
.nuc-ios .ios-streak{
flex:none;display:inline-flex;align-items:center;gap:7px;
background:var(--card);border-radius:999px;padding:7px 11px;
}
.nuc-ios .ios-streak .bolt{color:var(--frozen);filter:drop-shadow(0 0 4px rgba(66,163,245,.5))}
.nuc-ios .ios-streak .col{display:flex;flex-direction:column;line-height:1}
.nuc-ios .ios-streak .n{font-size:16px;font-weight:600;font-variant-numeric:tabular-nums}
.nuc-ios .ios-streak .lbl{font-size:10px;color:var(--label2);margin-top:2px}
.nuc-ios .ios-streak .fz{display:inline-flex;align-items:center;gap:2px;color:var(--frozen);font-size:12px;font-weight:600}
.nuc-ios .ios-streak .fz svg{width:12px;height:12px}
/* StatCard row — five across, like HomeView.statCards (tight at phone width,
exactly as the app is; labels wrap like SwiftUI Text, value never wraps) */
.nuc-ios .ios-stats{display:flex;gap:7px;align-items:stretch}
.nuc-ios .ios-stat{
flex:1 1 0;min-width:0;
background:var(--card);border:1px solid var(--hair);border-radius:13px;
padding:8px 7px;display:flex;flex-direction:column;gap:3px;
}
.nuc-ios .ios-stat .ic{color:var(--accent)}
.nuc-ios .ios-stat .ic svg{width:15px;height:15px}
.nuc-ios .ios-stat .n{font-size:15px;font-weight:600;font-family:var(--mono);letter-spacing:-.03em;white-space:nowrap}
.nuc-ios .ios-stat .l{font-size:9.5px;line-height:1.12;color:var(--label2);overflow-wrap:break-word}
/* a .card() block (CardBackground modifier) */
.nuc-ios .ios-card{background:var(--card);border:1px solid var(--hair);border-radius:14px;padding:14px}
.nuc-ios .ios-card-h{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}
.nuc-ios .ios-card-h .h{font-size:16px;font-weight:600;letter-spacing:-.01em}
.nuc-ios .ios-card-h .cnt{font-size:15px;color:var(--label2);font-variant-numeric:tabular-nums}
/* ActivityGrid (no legend on iOS — just the grid) */
.nuc-ios .ios-grid{display:flex;gap:3px;flex-wrap:nowrap;overflow:hidden}
.nuc-ios .ios-grid .col{display:flex;flex-direction:column;gap:3px}
.nuc-ios .ios-grid i{width:13px;height:13px;border-radius:2px;background:var(--a0);display:block}
.nuc-ios .ios-grid i.l1{background:var(--a1)} .nuc-ios .ios-grid i.l2{background:var(--a2)}
.nuc-ios .ios-grid i.l3{background:var(--a3)} .nuc-ios .ios-grid i.l4{background:var(--a4)}
.nuc-ios .ios-grid i.fz{background:var(--frozen)}
/* SessionRow */
.nuc-ios .ios-srow{display:flex;align-items:center;gap:12px;padding:3px 0}
.nuc-ios .ios-srow .sym{width:24px;flex:none;display:flex;justify-content:center}
.nuc-ios .ios-srow .sym svg{width:21px;height:21px}
.nuc-ios .ios-srow .sc{flex:1;min-width:0}
.nuc-ios .ios-srow .st{font-size:16px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nuc-ios .ios-srow .sp{font-size:12px;color:var(--label2);margin-top:1px}
.nuc-ios .ios-srow .diff{font-size:12px;font-family:var(--mono);color:var(--label2);flex:none}
/* QuickTodos */
.nuc-ios .ios-capture{display:flex;align-items:center;gap:10px;margin-bottom:10px}
.nuc-ios .ios-input{
flex:1;min-width:0;background:var(--field);border:1px solid var(--field-hair);border-radius:8px;
padding:8px 11px;font-size:14px;color:var(--label3);
}
.nuc-ios .ios-addbtn{color:var(--accent);flex:none;display:flex}
.nuc-ios .ios-addbtn svg{width:24px;height:24px}
.nuc-ios .ios-todo{display:flex;align-items:center;gap:10px;padding:6px 0}
.nuc-ios .ios-todo .box{color:var(--label3);flex:none;display:flex}
.nuc-ios .ios-todo .box svg{width:18px;height:18px}
.nuc-ios .ios-todo .tt{flex:1;min-width:0;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nuc-ios .ios-todo .pn{font-size:11px;color:var(--label2);flex:none}
/* StartChatComposer */
.nuc-ios .ios-comp-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px}
.nuc-ios .ios-menu{display:inline-flex;align-items:center;gap:5px;font-size:14px;color:var(--label)}
.nuc-ios .ios-menu svg{width:15px;height:15px;color:var(--label2)}
.nuc-ios .ios-tint{display:inline-flex;align-items:center;gap:4px;font-size:13px;color:var(--accent);font-weight:500}
.nuc-ios .ios-tint svg{width:14px;height:14px}
.nuc-ios .ios-tint .badge{color:var(--label3);font-weight:400}
.nuc-ios .ios-auto{
display:inline-flex;align-items:center;gap:5px;font-size:13px;color:var(--label2);
border:1px solid var(--field-hair);border-radius:8px;padding:5px 9px;font-weight:500;
}
.nuc-ios .ios-auto svg{width:14px;height:14px}
.nuc-ios .ios-comp-field{display:flex;align-items:flex-end;gap:8px}
.nuc-ios .ios-comp-field .ios-input{padding:10px 12px;font-size:15px}
.nuc-ios .ios-send{color:var(--accent);flex:none;display:flex}
.nuc-ios .ios-send svg{width:30px;height:30px}
/* ConnectionChip — floating, pinned above the tab bar */
.nuc-ios .ios-chip{
position:absolute;left:50%;bottom:72px;transform:translateX(-50%);z-index:5;
display:inline-flex;align-items:center;gap:6px;
background:rgba(255,255,255,.74);
-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
border:1px solid var(--hair);border-radius:999px;padding:6px 12px;
font-size:13px;font-weight:500;color:var(--label);
box-shadow:0 6px 18px -10px rgba(0,0,0,.35);
}
.nuc-ios .ios-chip .dot{width:8px;height:8px;border-radius:50%;background:#34c759}
/* ---- tab bar (RootView TabView) ------------------------------------------- */
.nuc-ios .ios-tabbar{
position:absolute;left:0;right:0;bottom:0;z-index:4;
display:flex;align-items:center;padding:6px 6px;height:60px;
background:var(--tabbar);
-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);
border-top:1px solid var(--hair);
}
.nuc-ios .ios-tab{
flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;
color:var(--tab-off);position:relative;
}
.nuc-ios .ios-tab svg{width:25px;height:25px}
.nuc-ios .ios-tab .tl{font-size:10px;font-weight:500;letter-spacing:.01em}
.nuc-ios .ios-tab.on{color:var(--accent)}
.nuc-ios .ios-tab .tbadge{
position:absolute;top:-3px;left:calc(50% + 7px);
min-width:16px;height:16px;padding:0 4px;border-radius:999px;
background:var(--danger);color:#fff;font-size:10px;font-weight:700;
display:flex;align-items:center;justify-content:center;font-variant-numeric:tabular-nums;
}
</style>
</head>
<body style="margin:0;background:#faf7f3;background-image:radial-gradient(#e6ded4 1px,transparent 1px);background-size:26px 26px;background-position:-13px -13px;padding:48px 20px;font-family:'Space Grotesk',-apple-system,sans-serif;">
<div style="max-width:520px;margin:0 auto;">
<!-- ===== COPY FROM HERE: iPhone cockpit markup =============================== -->
<div class="nuc-ios" aria-label="The Nucleic iPhone app — Home tab">
<div class="ios-phone">
<!-- Home content (HomeView) -->
<div class="ios-content">
<!-- greeting + StreakBadge -->
<div class="ios-hi">
<div>
<h1>Good morning</h1>
<p class="sub">2 active of 5 chats · 2 projects</p>
</div>
<span class="ios-streak">
<svg class="bolt" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M13 2 4 14h6l-1 8 9-12h-6z"/></svg>
<span class="col"><span class="n">15</span><span class="lbl">day streak</span></span>
<span class="fz">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><path d="M12 2v20M3.5 7l17 10M20.5 7l-17 10"/><path d="M12 6l2.2-2.2M12 6 9.8 3.8M12 18l2.2 2.2M12 18l-2.2 2.2"/></svg>
1
</span>
</span>
</div>
<!-- five StatCards -->
<div class="ios-stats">
<div class="ios-stat">
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M3 7a2 2 0 0 1 2-2h3.5l2 2H19a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg></span>
<span class="n">2</span><span class="l">Projects</span>
</div>
<div class="ios-stat">
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 0 0 0 18z" fill="currentColor" stroke="none"/></svg></span>
<span class="n">1</span><span class="l">In progress</span>
</div>
<div class="ios-stat">
<span class="ic"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M13 2 4 14h6l-1 8 9-12h-6z"/></svg></span>
<span class="n">2</span><span class="l">Active</span>
</div>
<div class="ios-stat">
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"><path d="M21 3 10 14M21 3l-7 18-4-7-7-4z"/></svg></span>
<span class="n">142</span><span class="l">Messages</span>
</div>
<div class="ios-stat">
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"><path d="M4 8h7M4 12h11M4 16h6"/></svg></span>
<span class="n">1.3M</span><span class="l">Tokens</span>
</div>
</div>
<!-- Activity card -->
<div class="ios-card">
<div class="ios-card-h"><span class="h">Activity</span></div>
<div class="ios-grid" aria-hidden="true"><!-- cells injected by the scoped script --></div>
</div>
<!-- In progress card -->
<div class="ios-card">
<div class="ios-card-h"><span class="h">In progress</span><span class="cnt">1</span></div>
<div class="ios-srow">
<span class="sym" style="color:var(--active)">
<!-- circle.lefthalf.filled (running) -->
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 0 0 0 18z" fill="currentColor" stroke="none"/></svg>
</span>
<span class="sc"><div class="st">flaky-tests</div><div class="sp">nucleic</div></span>
<span class="diff">+88/12</span>
</div>
</div>
<!-- To-dos card (QuickTodos) -->
<div class="ios-card">
<div class="ios-card-h"><span class="h">To-dos</span><span class="cnt">3</span></div>
<div class="ios-capture">
<span class="ios-input">Capture an idea…</span>
<span class="ios-addbtn"><svg viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="12" r="10"/><path d="M12 8v8M8 12h8" fill="none" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg></span>
</div>
<div class="ios-todo">
<span class="box"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="12" cy="12" r="9"/></svg></span>
<span class="tt">Dark mode in settings</span>
<span class="pn">website</span>
</div>
<div class="ios-todo">
<span class="box"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="12" cy="12" r="9"/></svg></span>
<span class="tt">Sync server memory leak</span>
<span class="pn">nucleic</span>
</div>
<div class="ios-todo">
<span class="box"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="12" cy="12" r="9"/></svg></span>
<span class="tt">Write release notes</span>
</div>
</div>
<!-- New chat composer (StartChatComposer) -->
<div class="ios-card">
<div class="ios-card-h"><span class="h">New chat</span></div>
<div class="ios-comp-row">
<span class="ios-menu"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M3 7a2 2 0 0 1 2-2h3.5l2 2H19a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>nucleic</span>
<span class="ios-auto"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M13 2 4 14h6l-1 8 9-12h-6z"/><path d="M3 3l18 18"/></svg>Auto</span>
</div>
<div class="ios-comp-row">
<span class="ios-tint"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="8.5" y="8.5" width="7" height="7" rx="1"/><path d="M9 1.5v2.5M15 1.5v2.5M9 20v2.5M15 20v2.5M1.5 9H4M1.5 15H4M20 9h2.5M20 15h2.5"/></svg>Default model</span>
<span class="ios-tint"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M4 6h10M18 6h2M4 12h2M10 12h10M4 18h8M16 18h4"/><circle cx="16" cy="6" r="2.2" fill="#fff"/><circle cx="8" cy="12" r="2.2" fill="#fff"/><circle cx="14" cy="18" r="2.2" fill="#fff"/></svg>high</span>
</div>
<div class="ios-comp-field">
<span class="ios-input">Describe a task…</span>
<span class="ios-send"><svg viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="12" r="11"/><path d="M12 17V8M8 11l4-4 4 4" fill="none" stroke="#fff" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
</div>
</div>
</div>
<!-- ConnectionChip -->
<span class="ios-chip"><span class="dot"></span>Connected · LAN</span>
<!-- tab bar -->
<nav class="ios-tabbar">
<span class="ios-tab on">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M3 11.2 12 4l9 7.2V20a1.4 1.4 0 0 1-1.4 1.4h-4.1V15h-3v6.4H4.4A1.4 1.4 0 0 1 3 20z"/></svg>
<span class="tl">Home</span>
</span>
<span class="ios-tab">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"><path d="M4 9.5 12 6l8 3.5-8 3.5z"/><path d="M5 13l7 3 7-3M5 16.5l7 3 7-3"/></svg>
<span class="tl">Sessions</span>
<span class="tbadge">2</span>
</span>
<span class="ios-tab">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><path d="M3 7a2 2 0 0 1 2-2h3.5l2 2H19a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>
<span class="tl">Projects</span>
</span>
<span class="ios-tab">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6l1.6 1.6L8.5 4.7M11 6h9M4 12l1.6 1.6L8.5 10.7M11 12h9M4 18l1.6 1.6L8.5 16.7M11 18h9"/></svg>
<span class="tl">To-dos</span>
</span>
<span class="ios-tab">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="3.2"/><path d="M12 2.5v3M12 18.5v3M2.5 12h3M18.5 12h3M5.2 5.2l2.1 2.1M16.7 16.7l2.1 2.1M18.8 5.2l-2.1 2.1M7.3 16.7l-2.1 2.1"/></svg>
<span class="tl">Settings</span>
</span>
</nav>
</div>
</div>
<!-- ===== COPY TO HERE ======================================================= -->
<p style="text-align:center;margin:22px 0 0;font-family:'JetBrains Mono',monospace;font-size:12px;color:#8b8590">The Nucleic iPhone app — Home tab. Mobile counterpart to the Mac cockpit. Illustrative.</p>
</div>
<!-- ===== COPY: scoped script that paints the activity grid (once, fixed width) ===== -->
<script data-nuc-ios>
(function () {
// Paint the activity grid ONCE with a fixed column count sized to the 360px
// card — no live width measuring and no resize rebuild, so it never reflows or
// "jumps" on load. Deterministic (seeded); recent weeks (right) trend busier,
// with two streak-freeze cells in the iced blue. The grid's overflow:hidden
// clips the rightmost column gracefully on phones narrower than the card.
var COLS = 19, ROWS = 7;
function build(grid) {
grid.textContent = '';
var seed = 20260629;
function rnd() { seed = (seed * 1103515245 + 12345) & 0x7fffffff; return seed / 0x7fffffff; }
var frozen = {};
frozen[(COLS - 7) + ',2'] = 1;
frozen[(COLS - 3) + ',5'] = 1;
for (var c = 0; c < COLS; c++) {
var col = document.createElement('div');
col.className = 'col';
var recency = c / (COLS - 1);
for (var r = 0; r < ROWS; r++) {
var i = document.createElement('i');
if (frozen[c + ',' + r]) {
i.className = 'fz';
} else {
var p = rnd() * 0.55 + recency * 0.6;
var lvl = p < 0.3 ? 0 : p < 0.52 ? 1 : p < 0.73 ? 2 : p < 0.9 ? 3 : 4;
if (lvl) i.className = 'l' + lvl;
}
col.appendChild(i);
}
grid.appendChild(col);
}
}
function fill() { document.querySelectorAll('.nuc-ios .ios-grid').forEach(build); }
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fill);
else fill();
})();
</script>
</body>
</html>