@@ -176,6 +402,600 @@ function Demo() {
);
}
+type StateMode = MascotState | 'auto';
+
+/** Cycles through the states every few seconds until one is picked. */
+function useAutoState() {
+ const [mode, setMode] = useState
('auto');
+ const [tick, setTick] = useState(0);
+ useEffect(() => {
+ if (mode !== 'auto') return;
+ const timer = window.setInterval(() => setTick((n) => n + 1), 5200);
+ return () => window.clearInterval(timer);
+ }, [mode]);
+ const state = mode === 'auto' ? LIVE_STATES[tick % LIVE_STATES.length] : mode;
+ return { mode, setMode, state };
+}
+
+function StateSwitch({ mode, state, onChange }: { mode: StateMode; state: MascotState; onChange: (mode: StateMode) => void }) {
+ return (
+
+ {(['auto', ...LIVE_STATES] as const).map((option) => (
+ onChange(option)}>
+ {option === 'auto' ? `auto · ${STATE_LABEL[state]}` : STATE_LABEL[option]}
+
+ ))}
+
+ );
+}
+
+const PI_SHAPES: { id: PiShape; caption: string }[] = [
+ { id: 'pip', caption: 'Pip · Pi is a circle' },
+ { id: 'brackets', caption: 'Brackets · the frame' },
+ { id: 'caret', caption: 'Caret · the cursor' },
+ { id: 'glyph', caption: 'Glyph · the mark, stood up' },
+ { id: 'stamp', caption: 'Stamp · the seal' },
+];
+
+const PI_LOOKS: { id: PiLook; label: string }[] = [
+ { id: 'ink', label: 'ink' },
+ { id: 'blueprint', label: 'blueprint' },
+ { id: 'paper', label: 'paper' },
+ { id: 'warm', label: 'warm' },
+];
+
+const PI_ICONS: PiIconName[] = ['pi', 'session', 'terminal', 'branch', 'diff', 'file', 'check', 'stop', 'loop', 'spark'];
+const PI_RULES: { kind: RuleKind; label: string }[] = [
+ { kind: 'ruler', label: 'Ruler · 4px and 20px ticks' },
+ { kind: 'mark', label: 'Mark · the Pi between two hairlines' },
+ { kind: 'dotted', label: 'Dotted · 8px step' },
+ { kind: 'thread', label: 'Thread · tidal fading out' },
+];
+
+function LookSwitch({ look, onChange }: { look: PiLook; onChange: (look: PiLook) => void }) {
+ return (
+
+ {PI_LOOKS.map((option) => (
+ onChange(option.id)}>
+ {option.label}
+
+ ))}
+
+ );
+}
+
+const GLYPH_POSES = [
+ { id: 'glyph', caption: 'Glyph · the original', node: },
+ { id: 'peek', caption: 'Peek · eyes in the counter', node: },
+ { id: 'carry', caption: 'Carry · the dot rides up top', node: },
+ { id: 'walk', caption: 'Walk · on the road while it runs', node: },
+ { id: 'assemble', caption: 'Assemble · built from its grid', node: },
+];
+
+const GLYPH_SIZES = [16, 24, 32, 48, 72, 112];
+
+function GlyphFamilyDemo() {
+ const { mode, setMode, state } = useAutoState();
+ const [look, setLook] = useState('ink');
+ return (
+
+
+
+
Glyph family
+
The mark, stood up, and everything it can do.
+
+
+
+
+
+
+
+
+ {GLYPH_POSES.map((pose) => (
+
+
+ {pose.node}
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+ pidex
+ ~/projects/pidex · main
+
+ ● {STATE_LABEL[state]}
+
+
+
+
+
+
+ {GLYPH_SIZES.map((size) => (
+
+ = 24} />
+ {size}
+
+ ))}
+
+
+
+
+ );
+}
+
+const PASSPORT: { node: ReactNode; left: string; top: string }[] = [
+ { node: , left: '3%', top: '16%' },
+ { node: , left: '24%', top: '6%' },
+ { node: , left: '62%', top: '12%' },
+ { node: , left: '76%', top: '34%' },
+ { node: , left: '26%', top: '52%' },
+ { node: your turn, left: '6%', top: '74%' },
+ { node: , left: '58%', top: '68%' },
+];
+
+function StampsDemo() {
+ const { mode, setMode, state } = useAutoState();
+ const [look, setLook] = useState('ink');
+ const [inked, setInked] = useState(true);
+ return (
+
+
+
+
Stamps
+
Seals, tickets, postmarks, and stickers.
+
+ Each stamp is pressed again whenever the state changes. Worn ink speckles the ink and
+ roughens its edge, like a real rubber stamp.
+
+
+
+
+
+
+ setInked((v) => !v)}>
+ worn ink · {inked ? 'on' : 'off'}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Inks
+
One ink per state.
+
+
+ {LIVE_STATES.map((tone, i) => (
+
+
+ {STATE_LABEL[tone]}
+
+ ))}
+
+
+
+
+
+
Passport
+
A page of collected stamps.
+
+
+
+
+ Passport
+ pidex · sessions this week
+
+ {PASSPORT.map((item, i) => (
+
+ {item.node}
+
+ ))}
+
+
+
+
+
+
+
Stickers
+
Die-cut, for laptops and READMEs.
+
+
+
+
+
+
+
+
+
+ );
+}
+
+const SHEET_LOOKS: { id: PiLook; label: string }[] = [
+ { id: 'blueprint', label: 'blueprint' },
+ { id: 'paper', label: 'whiteprint' },
+ { id: 'ink', label: 'ink' },
+];
+
+function SchematicDemo() {
+ const { mode, setMode, state } = useAutoState();
+ const [look, setLook] = useState('blueprint');
+ return (
+
+
+
+
Schematic
+
The Glyph, drawn up as a blueprint.
+
+ A dimensioned elevation, an exploded view with a parts list, and the session state
+ schema. The current state lights its box and flows out along its arrows, and the
+ seal is pressed onto the title block.
+
+
+
+
+ {SHEET_LOOKS.map((option) => (
+ setLook(option.id)}>
+ {option.label}
+
+ ))}
+
+
+
+
+
+
+ );
+}
+
+function PiSetDemo() {
+ const { mode, setMode, state } = useAutoState();
+ const [look, setLook] = useState('ink');
+ return (
+
+
+
+
Shapes
+
Five shapes, four looks, one set of inks.
+
+
+
+ {PI_LOOKS.map((option) => (
+ setLook(option.id)}>
+ {option.label}
+
+ ))}
+
+
+
+
+
+
+ {PI_SHAPES.map((shape) => (
+
+
+
+
+
+ ))}
+
+
+
+
+
Every look
+
Four looks for every shape.
+
+
+ {PI_LOOKS.map((row) => (
+
+
{row.label}
+ {PI_SHAPES.map((shape) => (
+
+
+
+ ))}
+
+ ))}
+
+
+
+
+
+
Assets
+
Stamps, rules, icons, and an empty state.
+
+
+
+
draft
+
running
+
your turn
+
blocked
+
shipped
+
+
+ {PI_RULES.map((rule) => (
+
+ ))}
+
+
+ {PI_ICONS.map((name) => (
+
+ ))}
+
+
+
+
+
+
+
Nothing running yet.
+
Start a session and it will show up here.
+
› pidex new "fix the flaky test"
+
+
+
+
+
+ );
+}
+
+const LIVE_STATES: MascotState[] = ['idle', 'thinking', 'input', 'blocked', 'done'];
+
+const STATE_LABEL: Record = {
+ idle: 'idle',
+ thinking: 'running',
+ input: 'needs input',
+ blocked: 'blocked',
+ done: 'ready',
+};
+
+type RosterRow = {
+ name: string;
+ meta: string;
+ status: string;
+ state: MascotState;
+ tone: MascotTone;
+ gear: MascotGear;
+ badge?: BadgeTone;
+};
+
+const ROSTER: RosterRow[] = [
+ { name: 'fix-auth-redirect', meta: 'pidex · turn 14', status: 'Running the auth tests', state: 'thinking', tone: 'accent', gear: 'antenna', badge: 'active' },
+ { name: 'migrate-sqlite', meta: 'pidex · turn 6', status: 'Wants to drop the sessions table', state: 'input', tone: 'warm', gear: 'bead', badge: 'stale' },
+ { name: 'flaky-e2e', meta: 'pidex · turn 22', status: 'Chrome would not start in CI', state: 'blocked', tone: 'rust', gear: 'none', badge: 'blocked' },
+ { name: 'readme-stills', meta: 'pidex · turn 9', status: 'Four stills are ready to review', state: 'done', tone: 'sage', gear: 'halo', badge: 'done' },
+ { name: 'scratch', meta: 'pidex · turn 0', status: 'Waiting for a prompt', state: 'idle', tone: 'blue', gear: 'none' },
+];
+
+const VARIANTS: { tone: MascotTone; gear: MascotGear; caption: string }[] = [
+ { tone: 'accent', gear: 'antenna', caption: 'Accent · antenna' },
+ { tone: 'warm', gear: 'bead', caption: 'Warm · bead' },
+ { tone: 'sage', gear: 'halo', caption: 'Sage · halo' },
+ { tone: 'rust', gear: 'none', caption: 'Rust · bare' },
+];
+
+function MascotRoster() {
+ return (
+
+
+
Roster
+
One Blink per session.
+
+ Each session gets a top face and a piece of gear, so you can tell them apart. The face
+ and the signal above the head show what the session is doing, and hold for as long as
+ that state lasts.
+
+
+
+
+ );
+}
+
+function MascotVariants({ state }: { state: MascotState }) {
+ return (
+
+
+
Variants
+
Tone and gear.
+
+
+ {VARIANTS.map((v) => (
+
+
+
+
+
+ ))}
+
+
+ );
+}
+
+const PIXEL_SKINS: { id: PixelSkin; caption: string; note: string }[] = [
+ { id: 'mono', caption: 'Mono', note: 'The whole body takes the state colour' },
+ { id: 'terminal', caption: 'Terminal', note: 'pi.dev terminal: #142433 and #f8f8f2' },
+ { id: 'cube', caption: 'Cube', note: 'Parchment lid, lit right face, tidal left' },
+ { id: 'crest', caption: 'Crest', note: 'The Pi mark worn on the head' },
+ { id: 'blueprint', caption: 'Blueprint', note: 'Accent linework on the page grid' },
+ { id: 'paper', caption: 'Paper', note: 'Light theme: evening blue on moonstone' },
+];
+
+function MascotTerminal({ state }: { state: MascotState }) {
+ return (
+
+
+
Terminal
+
Blink in block characters, in pi.dev colours.
+
+ For the CLI and for anywhere without SVG. Seven columns wide, in the same five states.
+ Each skin takes its colours from pi.dev, and the signal above the head always takes the
+ state colour.
+
+
+
+
+
+
+ pidex
+ ~/projects/pidex · main
+
+ ● {STATE_LABEL[state]}
+
+
+
+
+
+ {PIXEL_SKINS.map((skin) => (
+
+
+
+ {skin.id === 'terminal' ? (
+
+ › pidex
+
+ ) : null}
+
{skin.note}
+
+
+ ))}
+
+
+ {LIVE_STATES.map((s) => (
+
+ ))}
+
+
+ );
+}
+
+function LiveMascots() {
+ const { mode, setMode, state } = useAutoState();
+ return (
+
+
+
+
Alive
+
Three takes on the pair, moving.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
const root = document.getElementById('root');
if (root) {
createRoot(root).render(
diff --git a/src/renderer/design-system/components.css b/src/renderer/design-system/components.css
index 7ad11b1..318d2cc 100644
--- a/src/renderer/design-system/components.css
+++ b/src/renderer/design-system/components.css
@@ -341,3 +341,2278 @@
border-top: 1px solid var(--line-soft);
margin: 0;
}
+
+/* Patterns -------------------------------------------------------------- */
+
+/* pi.dev page grid: 4px fine lines, 20px heavy lines. */
+.ds-blueprint {
+ background-color: var(--bg-canvas);
+ background-image:
+ repeating-linear-gradient(90deg, hsl(218 60% 80% / 0.16) 0 1px, transparent 1px 20px),
+ repeating-linear-gradient(0deg, hsl(218 60% 80% / 0.16) 0 1px, transparent 1px 20px),
+ repeating-linear-gradient(90deg, hsl(218 60% 80% / 0.05) 0 1px, transparent 1px 4px),
+ repeating-linear-gradient(0deg, hsl(218 60% 80% / 0.05) 0 1px, transparent 1px 4px);
+}
+
+.ds-hatch {
+ background-color: var(--bg-deep);
+ background-image: repeating-linear-gradient(
+ -45deg,
+ transparent 0 7px,
+ var(--line-soft) 7px 8px
+ );
+}
+
+/* Loading --------------------------------------------------------------- */
+
+.ds-loader {
+ display: inline-flex;
+ width: fit-content;
+ align-items: center;
+ justify-content: flex-start;
+ gap: 0.7rem;
+ color: var(--muted-strong);
+ font-family: var(--accent-mono);
+ font-size: 0.66rem;
+ letter-spacing: 0.14em;
+ line-height: 1;
+ text-transform: uppercase;
+}
+
+.ds-loader-ticks {
+ display: inline-flex;
+ gap: 0.28rem;
+}
+
+.ds-loader-ticks span {
+ width: 0.42rem;
+ height: 0.42rem;
+ background: var(--line);
+ animation: ds-tick 1.2s steps(1, end) infinite;
+}
+
+.ds-loader-ticks span:nth-child(2) { animation-delay: 0.15s; }
+.ds-loader-ticks span:nth-child(3) { animation-delay: 0.3s; }
+.ds-loader-ticks span:nth-child(4) { animation-delay: 0.45s; }
+
+@keyframes ds-tick {
+ 0%,
+ 22% { background: var(--accent); }
+ 23%,
+ 100% { background: var(--line); }
+}
+
+.ds-scan {
+ position: relative;
+ display: block;
+ width: 8.5rem;
+ height: 2px;
+ overflow: hidden;
+ background: var(--line);
+}
+
+.ds-scan::after {
+ content: "";
+ position: absolute;
+ inset: 0 auto 0 0;
+ width: 42%;
+ background: linear-gradient(90deg, transparent, var(--accent), transparent);
+ animation: ds-scan 1.2s steps(7, end) infinite;
+}
+
+@keyframes ds-scan {
+ from { transform: translateX(-120%); }
+ to { transform: translateX(280%); }
+}
+
+.ds-skeleton {
+ display: grid;
+ gap: 0.9rem;
+}
+
+.ds-skeleton-row {
+ display: grid;
+ gap: 0.38rem;
+}
+
+.ds-skeleton-row span {
+ display: block;
+ height: 0.55rem;
+ background: var(--panel-soft);
+ animation: ds-blink 1.6s steps(1, end) infinite;
+}
+
+.ds-skeleton-row span:first-child { width: 78%; }
+.ds-skeleton-row span:last-child { width: 34%; }
+
+.ds-skeleton-row:nth-child(2) span { animation-delay: 0.15s; }
+.ds-skeleton-row:nth-child(3) span { animation-delay: 0.3s; }
+.ds-skeleton-row:nth-child(4) span { animation-delay: 0.45s; }
+
+.ds-caret {
+ display: inline-block;
+ width: 0.5ch;
+ height: 0.95em;
+ background: var(--accent);
+ vertical-align: text-bottom;
+ animation: ds-blink 1.05s steps(1, end) infinite;
+}
+
+/* 3D frame loader. Corner brackets, not a cube. */
+
+.ds-frame-loader {
+ display: grid;
+ justify-items: center;
+ gap: 0.9rem;
+}
+
+.ds-frame-loader-scene {
+ width: 96px;
+ height: 96px;
+ perspective: 340px;
+}
+
+.ds-frame-loader-spin {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ transform-style: preserve-3d;
+ animation: ds-frame-turn 7.5s linear infinite;
+}
+
+@keyframes ds-frame-turn {
+ from { transform: rotateX(-24deg) rotateY(0deg); }
+ to { transform: rotateX(-24deg) rotateY(360deg); }
+}
+
+.ds-frame-loader-plane {
+ position: absolute;
+ inset: 10px;
+ border: 1px solid var(--line-strong);
+ transform-style: preserve-3d;
+}
+
+.ds-frame-loader-plane--front { transform: translateZ(28px); }
+.ds-frame-loader-plane--back {
+ transform: translateZ(-28px);
+ border-color: var(--accent-border-strong);
+}
+
+.ds-frame-loader-corner {
+ position: absolute;
+ width: 16px;
+ height: 16px;
+ color: var(--moonstone);
+}
+
+.ds-frame-loader-plane--back .ds-frame-loader-corner { color: var(--accent); }
+
+.ds-frame-loader-corner--tl { top: -1px; left: -1px; border-top: 2px solid; border-left: 2px solid; }
+.ds-frame-loader-corner--tr { top: -1px; right: -1px; border-top: 2px solid; border-right: 2px solid; }
+.ds-frame-loader-corner--bl { bottom: -1px; left: -1px; border-bottom: 2px solid; border-left: 2px solid; }
+.ds-frame-loader-corner--br { bottom: -1px; right: -1px; border-bottom: 2px solid; border-right: 2px solid; }
+
+/* Agent loop ------------------------------------------------------------ */
+
+.ds-loop {
+ padding: 1.15rem 1.5rem 1.35rem;
+}
+
+.ds-loop-stage {
+ position: relative;
+ width: min(100%, 240px);
+ margin: 0 auto;
+}
+
+.ds-loop-svg {
+ display: block;
+ width: 100%;
+ height: auto;
+ color: var(--line-strong);
+}
+
+.ds-loop-track {
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 1;
+}
+
+.ds-loop-head {
+ fill: none;
+ stroke: var(--accent);
+ stroke-width: 2;
+ stroke-dasharray: 48 720;
+ animation: ds-loop-run 4.8s linear infinite;
+}
+
+@keyframes ds-loop-run {
+ to { stroke-dashoffset: -768; }
+}
+
+.ds-loop-node {
+ position: absolute;
+ padding: 0.28rem 0.46rem 0.34rem;
+ border: 1px solid var(--line-soft);
+ background: var(--panel);
+ color: var(--muted);
+ font-family: var(--accent-mono);
+ font-size: 0.62rem;
+ letter-spacing: 0.14em;
+ line-height: 1;
+ text-transform: uppercase;
+ animation: ds-loop-on 4.8s steps(1, end) infinite;
+}
+
+.ds-loop-node:nth-child(3) { animation-delay: 1.2s; }
+.ds-loop-node:nth-child(4) { animation-delay: 2.4s; }
+.ds-loop-node:nth-child(5) { animation-delay: 3.6s; }
+
+.ds-loop-node--think { top: 0; left: 0; transform: translate(-18%, -42%); }
+.ds-loop-node--reply { top: 0; right: 0; transform: translate(18%, -42%); }
+.ds-loop-node--tool { bottom: 0; right: 0; transform: translate(18%, 42%); }
+.ds-loop-node--result { bottom: 0; left: 0; transform: translate(-18%, 42%); }
+
+@keyframes ds-loop-on {
+ 0%,
+ 24% {
+ color: var(--text);
+ border-color: var(--accent);
+ background: var(--accent-surface-soft);
+ }
+ 25%,
+ 100% {
+ color: var(--muted);
+ border-color: var(--line-soft);
+ background: var(--panel);
+ }
+}
+
+/* 3D objects. Sheets and a token, not cubes. */
+
+.ds-object {
+ display: grid;
+ justify-items: center;
+ gap: 0.85rem;
+}
+
+.ds-object-scene {
+ width: 140px;
+ height: 140px;
+ display: grid;
+ place-items: center;
+ perspective: 460px;
+}
+
+.ds-sheet-spin,
+.ds-stack-spin,
+.ds-token-spin {
+ position: relative;
+ transform-style: preserve-3d;
+ animation: ds-object-turn 9s linear infinite;
+}
+
+@keyframes ds-object-turn {
+ from { transform: rotateX(-20deg) rotateY(0deg); }
+ to { transform: rotateX(-20deg) rotateY(360deg); }
+}
+
+.ds-sheet-spin { width: 74px; height: 100px; }
+
+.ds-sheet {
+ position: absolute;
+ inset: 0;
+ display: grid;
+ align-content: center;
+ justify-items: center;
+ gap: 7px;
+ background: #2a3b50;
+ border: 1px solid #6e849c;
+ color: var(--moonstone);
+ backface-visibility: hidden;
+ transform: translateZ(4px);
+}
+
+.ds-sheet i {
+ display: block;
+ width: 34px;
+ height: 2px;
+ background: #6e849c;
+}
+
+.ds-sheet--back {
+ background: #1c2838;
+ transform: rotateY(180deg) translateZ(4px);
+}
+
+.ds-stack-spin { width: 108px; height: 86px; }
+
+.ds-panel3 {
+ position: absolute;
+ inset: 0;
+ background: #2a3b50;
+ border: 1px solid #6e849c;
+ transform: translateZ(var(--z)) rotateY(-6deg);
+}
+
+.ds-panel3::before {
+ content: "";
+ position: absolute;
+ left: 16px;
+ right: 28px;
+ top: 22px;
+ height: 2px;
+ background: #6e849c;
+}
+
+.ds-panel3:nth-child(1) { --z: 20px; border-color: var(--accent); }
+.ds-panel3:nth-child(2) { --z: 0px; background: #24384c; }
+.ds-panel3:nth-child(3) { --z: -20px; background: #1c2838; }
+
+.ds-token-spin {
+ width: 78px;
+ height: 78px;
+ animation-name: ds-token-turn;
+}
+
+@keyframes ds-token-turn {
+ from { transform: rotateX(-12deg) rotateY(0deg); }
+ to { transform: rotateX(-12deg) rotateY(360deg); }
+}
+
+.ds-token {
+ position: absolute;
+ inset: 0;
+ display: grid;
+ place-items: center;
+ background: #2a3b50;
+ border: 1px solid var(--moonstone);
+ color: var(--moonstone);
+ backface-visibility: hidden;
+ transform: translateZ(5px);
+}
+
+.ds-token--back {
+ background: var(--moonstone);
+ color: #0d1116;
+ transform: rotateY(180deg) translateZ(5px);
+}
+
+.ds-orb-spin,
+.ds-hoop-spin {
+ position: relative;
+ width: 92px;
+ height: 92px;
+ transform-style: preserve-3d;
+ animation: ds-token-turn 8s linear infinite;
+}
+
+.ds-hoop-spin { animation-name: ds-hoop-turn; }
+.ds-orb-spin { animation-name: ds-orb-turn; }
+
+@keyframes ds-orb-turn {
+ from { transform: rotateX(18deg) rotateZ(0deg); }
+ to { transform: rotateX(18deg) rotateZ(-360deg); }
+}
+
+@keyframes ds-hoop-turn {
+ from { transform: rotateX(66deg) rotateZ(0deg); }
+ to { transform: rotateX(66deg) rotateZ(360deg); }
+}
+
+.ds-orb {
+ position: absolute;
+ inset: 0;
+ display: grid;
+ place-items: center;
+ border-radius: 50%;
+ background: radial-gradient(circle at 32% 28%, #4d6d8f, #1c2838 68%);
+ border: 1.5px solid var(--moonstone);
+ color: var(--moonstone);
+ backface-visibility: hidden;
+ transform: translateZ(5px);
+}
+
+.ds-hoop {
+ width: 92px;
+ height: 92px;
+ border-radius: 50%;
+ border: 3px solid var(--moonstone);
+ border-top-color: var(--accent);
+ box-shadow: inset 0 0 0 1px #1c2838;
+}
+
+.ds-ring {
+ width: 1.15rem;
+ height: 1.15rem;
+ display: block;
+}
+
+.ds-ring-track,
+.ds-ring-head {
+ fill: none;
+ stroke-width: 2.4;
+}
+
+.ds-ring-track { stroke: var(--line); }
+
+.ds-ring-head {
+ stroke: var(--accent);
+ stroke-linecap: round;
+ stroke-dasharray: 24 46;
+ transform-origin: center;
+ animation: ds-ring-turn 1.15s linear infinite;
+}
+
+@keyframes ds-ring-turn {
+ to { transform: rotate(360deg); }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .ds-loader-ticks span,
+ .ds-scan::after,
+ .ds-skeleton-row span,
+ .ds-caret,
+ .ds-frame-loader-spin,
+ .ds-loop-head,
+ .ds-loop-node,
+ .ds-sheet-spin,
+ .ds-stack-spin,
+ .ds-token-spin,
+ .ds-orb-spin,
+ .ds-hoop-spin,
+ .ds-ring-head {
+ animation: none;
+ }
+
+ .ds-frame-loader-spin,
+ .ds-sheet-spin,
+ .ds-stack-spin { transform: rotateX(-24deg) rotateY(-32deg); }
+ .ds-token-spin { transform: rotateX(-12deg) rotateY(-28deg); }
+ .ds-orb-spin { transform: rotateX(18deg) rotateZ(-24deg); }
+ .ds-hoop-spin { transform: rotateX(62deg) rotateZ(-20deg); }
+ .ds-loop-node--think {
+ color: var(--text);
+ border-color: var(--accent);
+ background: var(--accent-surface-soft);
+ }
+}
+
+/* ── Live mascots ───────────────────────────────────────────────
+ Three takes on the cube and the dot. Each reads data-state:
+ idle, thinking, or done. --look-x / --look-y (-1..1) come from the pointer. */
+
+@property --open {
+ syntax: '';
+ inherits: false;
+ initial-value: 0deg;
+}
+
+@property --lid {
+ syntax: '';
+ inherits: false;
+ initial-value: 90deg;
+}
+
+.ds-live {
+ --look-x: 0;
+ --look-y: 0;
+ position: relative;
+ display: grid;
+ place-items: center;
+ width: 100%;
+ min-height: 300px;
+}
+
+.ds-live svg {
+ width: 100%;
+ max-width: 300px;
+ height: auto;
+ overflow: visible;
+}
+
+.ds-live-face {
+ stroke: #6e849c;
+ stroke-width: 1.6;
+ stroke-linejoin: round;
+}
+
+.ds-live-face--top { fill: #2a3b50; }
+.ds-live-face--right { fill: #3d536b; }
+.ds-live-face--left { fill: #1c2838; }
+.ds-live-ink { fill: var(--moonstone); }
+
+.ds-live-shadow {
+ fill: #000;
+ opacity: 0.34;
+ transform-box: fill-box;
+ transform-origin: center;
+}
+
+.ds-live-body,
+.ds-live-dot {
+ transform-box: fill-box;
+ transform-origin: 50% 100%;
+}
+
+/* Blink: a face that watches the pointer */
+
+.ds-live--blink .ds-live-body {
+ animation: ds-live-breathe 3.4s ease-in-out infinite;
+}
+
+.ds-live--blink .ds-live-dot {
+ animation: ds-live-bob 2.6s ease-in-out infinite;
+}
+
+.ds-live-eye {
+ fill: var(--moonstone);
+ transform-box: fill-box;
+ transform-origin: center;
+ animation: ds-live-blink 4.6s infinite;
+}
+
+.ds-live-look--small .ds-live-eye { animation-delay: 0.14s; }
+
+.ds-live-look {
+ transform: translate(calc(var(--look-x) * 7px), calc(var(--look-y) * 5px));
+ transition: transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
+}
+
+.ds-live-look--small {
+ transform: translate(calc(var(--look-x) * 3px), calc(var(--look-y) * 2px));
+}
+
+.ds-live-mouth {
+ fill: none;
+ stroke: var(--moonstone);
+ stroke-width: 3;
+ stroke-linecap: square;
+ stroke-linejoin: miter;
+ transition: opacity 160ms ease;
+}
+
+.ds-live-mouth--smile { opacity: 0; }
+
+.ds-live-ticks rect {
+ fill: var(--moonstone);
+ opacity: 0;
+}
+
+.ds-live--blink[data-state='thinking'] .ds-live-look {
+ transform: translate(8px, -7px);
+}
+
+.ds-live--blink[data-state='thinking'] .ds-live-look--small {
+ transform: translate(3px, -3px);
+}
+
+.ds-live--blink[data-state='thinking'] .ds-live-ticks rect {
+ animation: ds-live-tick 1.2s steps(1, end) infinite;
+}
+
+.ds-live--blink[data-state='thinking'] .ds-live-ticks rect:nth-child(2) { animation-delay: 0.2s; }
+.ds-live--blink[data-state='thinking'] .ds-live-ticks rect:nth-child(3) { animation-delay: 0.4s; }
+
+.ds-live--blink[data-state='done'] .ds-live-mouth--flat { opacity: 0; }
+.ds-live--blink[data-state='done'] .ds-live-mouth--smile { opacity: 1; }
+
+.ds-live--blink[data-state='done'] .ds-live-body {
+ --hop: 44px;
+ animation: ds-live-hop 1.7s cubic-bezier(0.3, 0, 0.3, 1) infinite;
+}
+
+.ds-live--blink[data-state='done'] .ds-live-dot {
+ --hop: 30px;
+ animation: ds-live-hop 1.7s cubic-bezier(0.3, 0, 0.3, 1) 0.2s infinite;
+}
+
+.ds-live--blink[data-state='done'] .ds-live-shadow {
+ animation: ds-live-shadow 1.7s cubic-bezier(0.3, 0, 0.3, 1) infinite;
+}
+
+.ds-live--blink[data-state='done'] .ds-live-shadow--dot { animation-delay: 0.2s; }
+
+@keyframes ds-live-breathe {
+ 0%, 100% { transform: scale(1, 1); }
+ 50% { transform: scale(1.012, 0.985); }
+}
+
+@keyframes ds-live-bob {
+ 0%, 100% { transform: translateY(0); }
+ 50% { transform: translateY(-4px); }
+}
+
+@keyframes ds-live-blink {
+ 0%, 91%, 100% { transform: scaleY(1); }
+ 94% { transform: scaleY(0.08); }
+}
+
+@keyframes ds-live-tick {
+ 0% { opacity: 0; transform: translateY(0); }
+ 30% { opacity: 1; transform: translateY(-6px); }
+ 70% { opacity: 0.35; transform: translateY(-10px); }
+ 100% { opacity: 0; }
+}
+
+@keyframes ds-live-hop {
+ 0%, 92%, 100% { transform: translateY(0) scale(1, 1); }
+ 12% { transform: translateY(0) scale(1.08, 0.88); }
+ 32% { transform: translateY(calc(var(--hop) * -0.85)) scale(0.94, 1.08); }
+ 48% { transform: translateY(calc(var(--hop) * -1)) scale(1, 1); }
+ 66% { transform: translateY(0) scale(1.1, 0.86); }
+ 78% { transform: translateY(0) scale(0.97, 1.03); }
+}
+
+@keyframes ds-live-shadow {
+ 0%, 12%, 66%, 100% { transform: scale(1); opacity: 0.34; }
+ 48% { transform: scale(0.62); opacity: 0.16; }
+}
+
+/* Prompt: the code mascot */
+
+.ds-live--prompt .ds-live-body {
+ translate: calc(var(--look-x) * 5px) 0;
+ transition: translate 240ms ease-out;
+ animation: ds-live-float 4.2s ease-in-out infinite;
+}
+
+.ds-live-screen {
+ fill: #0d1116;
+ stroke: color-mix(in srgb, var(--accent) 45%, transparent);
+ stroke-width: 1;
+}
+
+.ds-live-prompt {
+ fill: var(--accent);
+ font-family: var(--accent-mono);
+ font-size: 13px;
+}
+
+.ds-live-code rect {
+ fill: var(--moonstone);
+ opacity: 0.72;
+ transform-box: fill-box;
+ transform-origin: 0 50%;
+ animation: ds-live-type 7.2s steps(7, end) infinite;
+ animation-delay: calc(var(--i) * 0.9s);
+ transition: opacity 200ms ease;
+}
+
+.ds-live-code rect:nth-child(3n + 2) { fill: var(--accent); }
+.ds-live-code rect:nth-child(3n) { fill: var(--sunkissed); opacity: 0.6; }
+
+.ds-live-caret {
+ fill: var(--accent);
+ animation: ds-live-caret 1s steps(1, end) infinite;
+}
+
+.ds-live-status {
+ fill: var(--signal);
+ font-family: var(--accent-mono);
+ font-size: 13px;
+ opacity: 0;
+ transition: opacity 200ms ease;
+}
+
+.ds-live-vents rect {
+ fill: #6e849c;
+ opacity: 0.45;
+}
+
+.ds-live-stem {
+ stroke: #6e849c;
+ stroke-width: 2;
+}
+
+.ds-live-bead {
+ color: #6e849c;
+ stroke: #0d1116;
+ stroke-width: 1;
+ transform-box: fill-box;
+ transform-origin: center;
+ transition: color 240ms ease;
+}
+
+.ds-live-steam text {
+ fill: var(--moonstone);
+ font-family: var(--accent-mono);
+ font-size: 14px;
+ opacity: 0;
+ text-anchor: middle;
+}
+
+.ds-live--prompt[data-state='thinking'] .ds-live-code rect {
+ animation-duration: 2.4s;
+ animation-delay: calc(var(--i) * 0.3s);
+}
+
+.ds-live--prompt[data-state='thinking'] .ds-live-bead {
+ animation: ds-live-pulse 0.9s ease-in-out infinite;
+}
+
+.ds-live--prompt[data-state='thinking'] .ds-live-steam text {
+ animation: ds-live-steam 2.6s ease-out infinite;
+ animation-delay: calc(var(--i) * 0.42s);
+}
+
+.ds-live--prompt[data-state='input'] .ds-live-code rect,
+.ds-live--prompt[data-state='blocked'] .ds-live-code rect,
+.ds-live--prompt[data-state='done'] .ds-live-code rect {
+ animation: none;
+ opacity: 0.18;
+}
+
+.ds-live--prompt:is([data-state='done'], [data-state='blocked']) .ds-live-caret { visibility: hidden; }
+.ds-live--prompt[data-state='done'] .ds-live-status--done,
+.ds-live--prompt[data-state='input'] .ds-live-status--input,
+.ds-live--prompt[data-state='blocked'] .ds-live-status--blocked { opacity: 1; }
+
+
+.ds-live--prompt[data-state='done'] .ds-live-body {
+ animation: ds-live-nod 2s cubic-bezier(0.3, 0, 0.3, 1) infinite;
+}
+
+@keyframes ds-live-float {
+ 0%, 100% { transform: translateY(0); }
+ 50% { transform: translateY(-6px); }
+}
+
+@keyframes ds-live-type {
+ 0% { transform: scaleX(0); }
+ 14%, 82% { transform: scaleX(1); }
+ 90%, 100% { transform: scaleX(0); }
+}
+
+@keyframes ds-live-caret {
+ 0% { opacity: 1; }
+ 50% { opacity: 0; }
+}
+
+@keyframes ds-live-pulse {
+ 0%, 100% { transform: scale(1); }
+ 50% { transform: scale(1.28); }
+}
+
+@keyframes ds-live-steam {
+ 0% { opacity: 0; transform: translateY(0); }
+ 18% { opacity: 0.9; }
+ 100% { opacity: 0; transform: translateY(-46px); }
+}
+
+@keyframes ds-live-nod {
+ 0%, 40%, 100% { transform: scale(1, 1); }
+ 10% { transform: scale(1.05, 0.92); }
+ 22% { transform: translateY(-10px) scale(0.98, 1.03); }
+}
+
+/* Fold: a real cube that opens into its net */
+
+.ds-live--fold {
+ --s: 104px;
+ min-height: 340px;
+ perspective: 900px;
+}
+
+.ds-fold-scene,
+.ds-fold-tilt,
+.ds-fold-hop,
+.ds-fold-spin {
+ width: var(--s);
+ height: var(--s);
+ transform-style: preserve-3d;
+}
+
+.ds-fold-scene { position: relative; z-index: 1; }
+
+.ds-fold-tilt {
+ transform: rotateX(calc(-34deg - var(--look-y) * 14deg)) rotateY(calc(var(--look-x) * 30deg));
+ transition: transform 500ms cubic-bezier(0.2, 0.8, 0.2, 1);
+}
+
+.ds-fold-spin {
+ position: relative;
+ animation: ds-fold-spin 16s linear infinite;
+}
+
+.ds-fold-face {
+ position: absolute;
+ inset: 0;
+ box-sizing: border-box;
+ border: 1.5px solid #6e849c;
+ background: #2a3b50;
+ transform-style: preserve-3d;
+}
+
+.ds-fold-bottom {
+ display: grid;
+ place-items: center;
+ background: #1a2432;
+ transform: translateY(calc(var(--s) / 2)) rotateX(90deg);
+}
+
+.ds-fold-dot {
+ width: 26%;
+ height: 26%;
+ background: var(--accent);
+ box-shadow: 0 0 18px color-mix(in srgb, var(--accent) 70%, transparent);
+}
+
+.ds-fold-side {
+ transform-origin: 50% 100%;
+ transform: rotateY(calc(var(--k) * 90deg)) translateZ(calc(var(--s) / 2)) rotateX(var(--open));
+}
+
+.ds-fold-side--front { background: #3d536b; }
+.ds-fold-side--right { background: #2f4259; }
+.ds-fold-side--back { background: #24344a; }
+.ds-fold-side--left { background: #1c2838; }
+
+.ds-fold-top {
+ inset: auto 0 100% 0;
+ height: var(--s);
+ display: grid;
+ place-items: center;
+ color: var(--moonstone);
+ background: #2a3b50;
+ transform-origin: 50% 100%;
+ transform: rotateX(var(--lid));
+}
+
+.ds-fold-top svg { transform: scaleX(-1); }
+
+.ds-fold-ground,
+.ds-fold-pulse {
+ position: absolute;
+ left: 50%;
+ top: calc(50% + var(--s) * 0.95);
+ width: calc(var(--s) * 1.7);
+ height: calc(var(--s) * 0.34);
+ border-radius: 50%;
+ translate: -50% -50%;
+ pointer-events: none;
+}
+
+.ds-fold-ground {
+ background: radial-gradient(closest-side, rgb(0 0 0 / 0.5), transparent);
+}
+
+.ds-fold-pulse {
+ border: 2px solid var(--signal);
+ opacity: 0;
+}
+
+.ds-live--fold[data-state='thinking'] .ds-fold-tilt {
+ transform: rotateX(calc(-58deg - var(--look-y) * 10deg)) rotateY(calc(var(--look-x) * 30deg));
+}
+
+.ds-live--fold[data-state='thinking'] .ds-fold-spin { animation-duration: 28s; }
+
+.ds-live--fold[data-state='thinking'] .ds-fold-side {
+ animation: ds-fold-open 4.2s cubic-bezier(0.6, 0, 0.2, 1) infinite;
+}
+
+.ds-live--fold[data-state='thinking'] .ds-fold-side--right { animation-delay: 0.08s; }
+.ds-live--fold[data-state='thinking'] .ds-fold-side--back { animation-delay: 0.16s; }
+.ds-live--fold[data-state='thinking'] .ds-fold-side--left { animation-delay: 0.24s; }
+
+.ds-live--fold[data-state='thinking'] .ds-fold-top {
+ animation: ds-fold-lid 4.2s cubic-bezier(0.6, 0, 0.2, 1) 0.16s infinite;
+}
+
+.ds-live--fold[data-state='done'] .ds-fold-hop {
+ animation: ds-fold-hop 1.8s cubic-bezier(0.3, 0, 0.3, 1) infinite;
+}
+
+.ds-live--fold[data-state='done'] .ds-fold-face { border-color: color-mix(in srgb, var(--signal) 70%, #6e849c); }
+
+.ds-live--fold[data-state='done'] .ds-fold-pulse {
+ animation: ds-fold-pulse 1.8s ease-out infinite;
+}
+
+@keyframes ds-fold-spin {
+ from { transform: rotateY(-38deg); }
+ to { transform: rotateY(322deg); }
+}
+
+@keyframes ds-fold-open {
+ 0%, 96%, 100% { --open: 0deg; }
+ 30%, 66% { --open: -90deg; }
+}
+
+@keyframes ds-fold-lid {
+ 0%, 96%, 100% { --lid: 90deg; }
+ 30%, 66% { --lid: 0deg; }
+}
+
+@keyframes ds-fold-hop {
+ 0%, 90%, 100% { transform: translateY(0) rotateY(0); }
+ 10% { transform: translateY(0) scale3d(1.06, 0.9, 1.06); }
+ 40% { transform: translateY(-46px) rotateY(90deg); }
+ 64% { transform: translateY(0) rotateY(90deg) scale3d(1.08, 0.88, 1.08); }
+ 76% { transform: translateY(0) rotateY(90deg); }
+}
+
+@keyframes ds-fold-pulse {
+ 0%, 62% { opacity: 0; scale: 0.5; }
+ 66% { opacity: 0.9; scale: 0.6; }
+ 100% { opacity: 0; scale: 1.5; }
+}
+
+/* State colour. Signals, beads, and status text all read it. */
+
+.ds-live { --signal: var(--moonstone); }
+.ds-live[data-state='thinking'] { --signal: var(--success); }
+.ds-live[data-state='input'] { --signal: var(--sunkissed); }
+.ds-live[data-state='blocked'] { --signal: var(--terracotta-light); }
+.ds-live[data-state='done'] { --signal: var(--accent); }
+
+.ds-live--prompt[data-state='idle'] .ds-live-bead { color: #6e849c; }
+.ds-live--prompt:not([data-state='idle']) .ds-live-bead {
+ color: var(--signal);
+ filter: drop-shadow(0 0 6px var(--signal));
+}
+
+.ds-live--prompt[data-state='input'] .ds-live-bead {
+ animation: ds-live-pulse 0.6s ease-in-out infinite;
+}
+
+.ds-live--prompt[data-state='blocked'] .ds-live-body,
+.ds-live--blink[data-state='blocked'] .ds-live-body {
+ animation: ds-live-shake 2.2s ease-in-out infinite;
+}
+
+/* Blink tones: the top face changes, the sides stay */
+
+.ds-live[data-tone='accent'] .ds-live-face--top { fill: #4b7aa3; }
+.ds-live[data-tone='warm'] .ds-live-face--top { fill: #9c7040; }
+.ds-live[data-tone='sage'] .ds-live-face--top { fill: #6f7048; }
+.ds-live[data-tone='rust'] .ds-live-face--top { fill: #844f3b; }
+
+/* Blink signals */
+
+.ds-live-bang rect,
+.ds-live-sparks rect { fill: var(--signal); }
+
+.ds-live-bang,
+.ds-live-cross,
+.ds-live-sparks rect {
+ opacity: 0;
+ transform-box: fill-box;
+ transform-origin: 50% 100%;
+}
+
+.ds-live-cross path {
+ fill: none;
+ stroke: var(--signal);
+ stroke-width: 5;
+ stroke-linecap: square;
+}
+
+.ds-live--blink[data-state='input'] .ds-live-bang {
+ opacity: 1;
+ animation: ds-live-call 1.4s cubic-bezier(0.3, 0, 0.3, 1) infinite;
+}
+
+.ds-live--blink[data-state='blocked'] .ds-live-cross { opacity: 1; }
+
+.ds-live--blink[data-state='done'] .ds-live-sparks rect {
+ animation: ds-live-spark 1.7s ease-out infinite;
+}
+
+.ds-live-mouth--frown,
+.ds-live-mouth--open { opacity: 0; }
+
+.ds-live--blink:is([data-state='input'], [data-state='blocked']) .ds-live-mouth--flat { opacity: 0; }
+.ds-live--blink[data-state='input'] .ds-live-mouth--open { opacity: 1; }
+.ds-live--blink[data-state='blocked'] .ds-live-mouth--frown { opacity: 1; }
+
+.ds-live-eyes {
+ transform-box: fill-box;
+ transform-origin: center;
+ transition: transform 200ms cubic-bezier(0.2, 0.8, 0.2, 1);
+}
+
+.ds-live--blink[data-state='input'] .ds-live-look { transform: translate(-2px, 1px); }
+.ds-live--blink[data-state='input'] .ds-live-look .ds-live-eyes { transform: scale(1.22); }
+.ds-live--blink[data-state='blocked'] .ds-live-look { transform: translate(-3px, 5px); }
+.ds-live--blink[data-state='blocked'] .ds-live-look .ds-live-eyes { transform: scaleY(0.3); }
+
+.ds-live--blink[data-state='input'] .ds-live-body {
+ --hop: 16px;
+ animation: ds-live-hop 1.4s cubic-bezier(0.3, 0, 0.3, 1) infinite;
+}
+
+.ds-live--blink[data-state='input'] .ds-live-dot .ds-live-look { transform: translate(-4px, -2px); }
+.ds-live--blink[data-state='blocked'] .ds-live-dot { animation: ds-live-shake 2.2s ease-in-out 0.12s infinite; }
+
+/* Blink gear */
+
+.ds-live-gear line {
+ stroke: #6e849c;
+ stroke-width: 2.5;
+}
+
+.ds-live-gear--antenna circle,
+.ds-live-gear--bead circle {
+ fill: var(--signal);
+ stroke: #0d1116;
+ stroke-width: 1.5;
+ transition: fill 240ms ease;
+}
+
+.ds-live-gear--halo ellipse {
+ fill: none;
+ stroke: var(--signal);
+ stroke-width: 2.5;
+ opacity: 0.85;
+}
+
+.ds-live-halo-bead {
+ fill: var(--moonstone);
+ animation: ds-live-orbit 3.6s linear infinite;
+}
+
+.ds-live[data-state='thinking'] .ds-live-halo-bead { animation-duration: 1.2s; }
+.ds-live[data-state='blocked'] .ds-live-halo-bead { animation-play-state: paused; }
+
+.ds-live-gear--bead circle {
+ transform-box: fill-box;
+ transform-origin: center;
+ animation: ds-live-bob 2.2s ease-in-out infinite;
+}
+
+.ds-live[data-state='thinking'] .ds-live-gear--antenna circle,
+.ds-live[data-state='input'] .ds-live-gear--antenna circle {
+ animation: ds-live-pulse 0.8s ease-in-out infinite;
+ transform-box: fill-box;
+ transform-origin: center;
+}
+
+/* Compact Blink for lists */
+
+.ds-live--compact {
+ min-height: 0;
+ width: auto;
+}
+
+.ds-live--compact svg {
+ width: var(--avatar, 44px);
+ max-width: none;
+}
+
+.ds-live--compact .ds-live-look { transition: none; }
+
+/* Fold, input and blocked */
+
+.ds-live--fold[data-state='input'] .ds-fold-hop {
+ animation: ds-fold-call 1.4s cubic-bezier(0.3, 0, 0.3, 1) infinite;
+}
+
+.ds-live--fold[data-state='input'] .ds-fold-face { border-color: var(--sunkissed); }
+
+.ds-live--fold[data-state='blocked'] .ds-fold-spin { animation-play-state: paused; }
+.ds-live--fold[data-state='blocked'] .ds-fold-hop { animation: ds-live-shake 2.2s ease-in-out infinite; }
+.ds-live--fold[data-state='blocked'] .ds-fold-face {
+ border-color: var(--terracotta-light);
+ filter: saturate(0.5) brightness(0.85);
+}
+
+/* Pixel Blink */
+
+.ds-pixel {
+ margin: 0;
+ /* Menlo and SF Mono draw block elements edge to edge; the brand monos leave seams. */
+ font-family: Menlo, "SF Mono", "DejaVu Sans Mono", monospace;
+ font-size: 22px;
+ line-height: 1;
+ letter-spacing: 0;
+ color: var(--moonstone);
+ white-space: pre;
+}
+
+.ds-pixel[data-state='thinking'] { color: var(--success); }
+.ds-pixel[data-state='input'] { color: var(--sunkissed); }
+.ds-pixel[data-state='blocked'] { color: var(--terracotta-light); }
+.ds-pixel[data-state='done'] { color: var(--accent); }
+
+/* Pixel skins. Body colour comes from the skin, the signal row from the state. */
+
+.ds-pixel { --pixel-body: var(--moonstone); --pixel-signal: var(--moonstone); }
+.ds-pixel[data-state='thinking'] { --pixel-signal: var(--success); }
+.ds-pixel[data-state='input'] { --pixel-signal: var(--sunkissed); }
+.ds-pixel[data-state='blocked'] { --pixel-signal: var(--terracotta-light); }
+.ds-pixel[data-state='done'] { --pixel-signal: var(--accent); }
+
+.ds-pixel:not([data-skin='mono']) { color: var(--pixel-body); }
+.ds-pixel-row--signal { color: var(--pixel-signal); }
+
+/* Terminal: pi.dev's terminal card, #142433 ground and #f8f8f2 type */
+.ds-pixel[data-skin='terminal'] { --pixel-body: #f8f8f2; }
+
+/* Cube: parchment lid, lit right face, tidal left face */
+.ds-pixel[data-skin='cube'] .ds-pixel-row--lid { color: var(--parchment); }
+.ds-pixel[data-skin='cube'] .ds-pixel-c--l { color: var(--tidal-blue); }
+.ds-pixel[data-skin='cube'] .ds-pixel-c--m { color: #5b7a9e; }
+.ds-pixel[data-skin='cube'] .ds-pixel-c--r { color: var(--accent); }
+.ds-pixel[data-skin='cube'] .ds-pixel-row--feet { color: var(--tidal-blue); }
+
+/* Crest: the Pi mark worn on the head */
+.ds-pixel[data-skin='crest'] { --pixel-body: var(--accent); }
+.ds-pixel[data-skin='crest'] .ds-pixel-row--pi { color: #ffffff; }
+
+/* Blueprint: accent linework on the page grid */
+.ds-pixel[data-skin='blueprint'] { --pixel-body: color-mix(in srgb, var(--accent) 88%, white); }
+.ds-pixel[data-skin='blueprint'] .ds-pixel-row--feet { color: var(--tidal-blue); }
+
+/* Paper: pi.dev light theme, evening blue on moonstone */
+.ds-pixel[data-skin='paper'] { --pixel-body: #252f3d; }
+.ds-pixel[data-skin='paper'][data-state='idle'] { --pixel-signal: #252f3d; }
+.ds-pixel[data-skin='paper'][data-state='thinking'] { --pixel-signal: #3f8a58; }
+.ds-pixel[data-skin='paper'][data-state='input'] { --pixel-signal: #b0712a; }
+.ds-pixel[data-skin='paper'][data-state='blocked'] { --pixel-signal: var(--terracotta); }
+.ds-pixel[data-skin='paper'][data-state='done'] { --pixel-signal: var(--tidal-blue); }
+.ds-pixel[data-skin='paper'] .ds-pixel-row--pi { color: #09090b; }
+
+@keyframes ds-live-shake {
+ 0%, 22%, 100% { translate: 0 0; }
+ 4%, 12% { translate: -4px 0; }
+ 8%, 16% { translate: 4px 0; }
+}
+
+@keyframes ds-live-call {
+ 0%, 60%, 100% { transform: translateY(0) scale(1); }
+ 14% { transform: translateY(-8px) scale(1.05, 1.1); }
+ 28% { transform: translateY(0) scale(1.1, 0.9); }
+ 40% { transform: translateY(-4px) scale(1); }
+}
+
+@keyframes ds-live-spark {
+ 0%, 38% { opacity: 0; transform: translate(0, 0) scale(0.4); }
+ 48% { opacity: 1; transform: translate(calc(var(--sx) * 6px), calc(var(--sy) * 6px)) scale(1); }
+ 80%, 100% { opacity: 0; transform: translate(calc(var(--sx) * 16px), calc(var(--sy) * 14px)) scale(0.6); }
+}
+
+@keyframes ds-live-orbit {
+ from { offset-distance: 0%; }
+ to { offset-distance: 100%; }
+}
+
+@keyframes ds-fold-call {
+ 0%, 60%, 100% { transform: translateY(0) rotateZ(0); }
+ 15% { transform: translateY(-14px) rotateZ(-6deg); }
+ 30% { transform: translateY(0) rotateZ(4deg); }
+ 42% { transform: translateY(-5px) rotateZ(0); }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .ds-live *,
+ .ds-live-body,
+ .ds-live-dot {
+ animation: none !important;
+ }
+
+ .ds-live-code rect { transform: none; }
+}
+
+/* ── pi.dev set ─────────────────────────────────────────────────
+ Mascots that are not cubes, plus stamps, rules, and icons.
+ A look sets four inks. A state sets --pm-signal, which lands on one part. */
+
+.ds-pm {
+ --pm-ground: #0d1116;
+ --pm-body: var(--parchment);
+ --pm-line: var(--moonstone);
+ --pm-eye: #13110f;
+ --pm-signal: var(--pm-line);
+ color: var(--pm-line);
+ background: var(--pm-ground);
+}
+
+.ds-pm[data-look='blueprint'] {
+ --pm-ground: var(--bg-canvas);
+ --pm-body: hsl(208 50% 60% / 0.14);
+ --pm-line: var(--accent);
+ --pm-eye: var(--accent);
+ background-image:
+ repeating-linear-gradient(90deg, hsl(218 60% 80% / 0.14) 0 1px, transparent 1px 20px),
+ repeating-linear-gradient(0deg, hsl(218 60% 80% / 0.14) 0 1px, transparent 1px 20px),
+ repeating-linear-gradient(90deg, hsl(218 60% 80% / 0.045) 0 1px, transparent 1px 4px),
+ repeating-linear-gradient(0deg, hsl(218 60% 80% / 0.045) 0 1px, transparent 1px 4px);
+}
+
+.ds-pm[data-look='paper'] {
+ --pm-ground: #ebe7e4;
+ --pm-body: #252f3d;
+ --pm-line: #252f3d;
+ --pm-eye: #ebe7e4;
+}
+
+.ds-pm[data-look='warm'] {
+ --pm-ground: #13110f;
+ --pm-body: var(--sunkissed);
+ --pm-line: var(--terracotta-light);
+ --pm-eye: #13110f;
+}
+
+.ds-pm[data-state='thinking'] { --pm-signal: var(--success); }
+.ds-pm[data-state='input'] { --pm-signal: var(--warning); }
+.ds-pm[data-state='blocked'] { --pm-signal: var(--error); }
+.ds-pm[data-state='done'] { --pm-signal: var(--accent); }
+.ds-pm[data-look='paper'][data-state='thinking'] { --pm-signal: #3f8a58; }
+.ds-pm[data-look='paper'][data-state='input'] { --pm-signal: #b0712a; }
+.ds-pm[data-look='paper'][data-state='blocked'] { --pm-signal: var(--terracotta); }
+.ds-pm[data-look='paper'][data-state='done'] { --pm-signal: var(--tidal-blue); }
+.ds-pm[data-look='blueprint'][data-state='done'] { --pm-signal: var(--moonstone); }
+
+.ds-pm-svg {
+ display: block;
+ width: 100%;
+ max-width: 200px;
+ height: auto;
+ overflow: visible;
+}
+
+.ds-pm-fill {
+ fill: var(--pm-body);
+ stroke: var(--pm-line);
+ stroke-width: 2.5;
+ stroke-linejoin: miter;
+ transition: fill 240ms ease, stroke 240ms ease;
+}
+
+.ds-pm-shadow { fill: #000; opacity: 0.3; }
+.ds-pm[data-look='paper'] .ds-pm-shadow { opacity: 0.12; }
+
+.ds-pm-signal { fill: var(--pm-signal); transition: fill 240ms ease; }
+
+.ds-pm-body,
+.ds-pm-glyph-dot,
+.ds-pm-corners,
+.ds-pm-stamp-type,
+.ds-pm-eyes,
+.ds-pm-eye,
+.ds-pm-trail rect {
+ transform-box: fill-box;
+ transform-origin: 50% 100%;
+}
+
+.ds-pm-eyes,
+.ds-pm-eye,
+.ds-pm-corners,
+.ds-pm-stamp-type { transform-origin: center; }
+
+.ds-pm-eye {
+ fill: var(--pm-eye);
+ animation: ds-pm-blink 4.8s infinite;
+}
+
+.ds-pm-eyes { transition: transform 200ms cubic-bezier(0.2, 0.8, 0.2, 1); }
+
+.ds-pm-mouth {
+ fill: none;
+ stroke: var(--pm-eye);
+ stroke-width: 3;
+ stroke-linecap: square;
+ opacity: 0;
+ transition: opacity 160ms ease;
+}
+
+.ds-pm[data-state='idle'] .ds-pm-mouth--flat,
+.ds-pm[data-state='thinking'] .ds-pm-mouth--flat,
+.ds-pm[data-state='input'] .ds-pm-mouth--open,
+.ds-pm[data-state='blocked'] .ds-pm-mouth--frown,
+.ds-pm[data-state='done'] .ds-pm-mouth--smile { opacity: 1; }
+
+.ds-pm[data-state='thinking'] .ds-pm-eyes { transform: translate(4px, -3px); }
+.ds-pm[data-state='input'] .ds-pm-eyes { transform: scale(1.25); }
+.ds-pm[data-state='blocked'] .ds-pm-eyes { transform: translateY(4px) scaleY(0.3); }
+
+/* Pip */
+
+.ds-pm-shine {
+ fill: none;
+ stroke: var(--pm-ground);
+ stroke-width: 4;
+ stroke-linecap: square;
+ opacity: 0.35;
+}
+
+.ds-pm[data-look='paper'] .ds-pm-shine,
+.ds-pm[data-look='blueprint'] .ds-pm-shine { stroke: var(--pm-line); }
+
+.ds-pm-pip { animation: ds-pm-rock 3.2s ease-in-out infinite; }
+.ds-pm-pip-bead { animation: ds-pm-orbit 9s linear infinite; }
+.ds-pm[data-state='thinking'] .ds-pm-pip-bead { animation-duration: 1.4s; }
+.ds-pm[data-state='input'] .ds-pm-pip-bead { animation: ds-pm-orbit 0.7s cubic-bezier(0.6, 0, 0.4, 1) infinite alternate; }
+.ds-pm[data-state='blocked'] .ds-pm-pip-bead { animation-play-state: paused; }
+.ds-pm[data-state='input'] .ds-pm-pip { animation: ds-pm-call 1.3s cubic-bezier(0.3, 0, 0.3, 1) infinite; }
+.ds-pm[data-state='blocked'] .ds-pm-pip { animation: ds-pm-shake 2.2s ease-in-out infinite; }
+.ds-pm[data-state='done'] .ds-pm-pip { animation: ds-pm-roll 2s cubic-bezier(0.5, 0, 0.3, 1) infinite; transform-origin: 50% 58%; }
+
+/* Brackets */
+
+.ds-pm-brackets-fill { stroke: none; opacity: 0.1; }
+
+/* The body is see-through, so the face takes the line ink. */
+.ds-pm-brackets .ds-pm-eye { fill: var(--pm-line); }
+.ds-pm-brackets .ds-pm-mouth { stroke: var(--pm-line); }
+
+.ds-pm-corner {
+ fill: none;
+ stroke: var(--pm-line);
+ stroke-width: 6;
+ stroke-linecap: square;
+ stroke-linejoin: miter;
+ animation: ds-pm-breathe 2.6s ease-in-out infinite alternate;
+ transition: stroke 240ms ease;
+}
+
+.ds-pm:not([data-state='idle']) .ds-pm-corner { stroke: var(--pm-signal); }
+.ds-pm[data-state='thinking'] .ds-pm-corners { animation: ds-pm-quarter 2.4s cubic-bezier(0.7, 0, 0.2, 1) infinite; }
+.ds-pm[data-state='input'] .ds-pm-corner { animation: ds-pm-hug 0.9s ease-in-out infinite alternate; }
+.ds-pm[data-state='blocked'] .ds-pm-corners { rotate: -8deg; }
+.ds-pm[data-state='blocked'] .ds-pm-corner { animation: none; stroke-dasharray: 6 5; }
+.ds-pm[data-state='done'] .ds-pm-corner { animation: ds-pm-burst 1.8s cubic-bezier(0.3, 0, 0.2, 1) infinite; }
+
+/* Caret */
+
+.ds-pm-caret-block { animation: ds-pm-caret 1.1s steps(1, end) infinite; }
+.ds-pm-trail rect { opacity: 0; }
+.ds-pm[data-state='thinking'] .ds-pm-caret-block { animation: none; }
+.ds-pm[data-state='thinking'] .ds-pm-caret { animation: ds-pm-type 0.5s steps(1, end) infinite; }
+.ds-pm[data-state='thinking'] .ds-pm-trail rect {
+ animation: ds-pm-trail 2s steps(1, end) infinite;
+ animation-delay: calc(var(--i) * 0.25s);
+}
+.ds-pm[data-state='input'] .ds-pm-caret { rotate: 8deg; transition: rotate 300ms cubic-bezier(0.3, 1.6, 0.4, 1); }
+.ds-pm[data-state='input'] .ds-pm-caret-block { fill: var(--pm-signal); animation-duration: 0.5s; }
+.ds-pm[data-state='blocked'] .ds-pm-caret-block { animation: none; fill: none; stroke: var(--pm-signal); stroke-dasharray: 8 6; }
+.ds-pm[data-state='blocked'] .ds-pm-caret .ds-pm-eye { fill: var(--pm-signal); }
+.ds-pm[data-state='done'] .ds-pm-caret-block { animation: none; fill: var(--pm-signal); }
+.ds-pm[data-state='done'] .ds-pm-caret { animation: ds-pm-hop 1.7s cubic-bezier(0.3, 0, 0.3, 1) infinite; }
+
+/* Glyph */
+
+.ds-pm-glyph-dot { animation: ds-pm-bob 2.4s ease-in-out infinite; }
+.ds-pm:not([data-state='idle']) .ds-pm-dot { fill: var(--pm-signal); }
+.ds-pm[data-state='thinking'] .ds-pm-glyph-dot { animation: ds-pm-circuit 1.8s linear infinite; }
+.ds-pm[data-state='input'] .ds-pm-glyph-dot { animation: ds-pm-jump 0.9s cubic-bezier(0.3, 0, 0.3, 1) infinite; }
+.ds-pm[data-state='blocked'] .ds-pm-glyph-dot { animation: none; translate: 10px 20px; rotate: 24deg; }
+.ds-pm[data-state='blocked'] .ds-pm-glyph { animation: ds-pm-shake 2.2s ease-in-out infinite; }
+.ds-pm[data-state='done'] .ds-pm-glyph-dot { animation: ds-pm-hop 1.7s cubic-bezier(0.3, 0, 0.3, 1) infinite; }
+.ds-pm[data-state='done'] .ds-pm-glyph { animation: ds-pm-hop 1.7s cubic-bezier(0.3, 0, 0.3, 1) 0.15s infinite; --hop: 10px; }
+
+/* Stamp */
+
+.ds-pm-ring {
+ fill: none;
+ stroke: var(--pm-eye);
+ stroke-width: 1.5;
+ stroke-dasharray: 2 4;
+ opacity: 0.6;
+}
+
+.ds-pm-ring-text {
+ fill: var(--pm-eye);
+ font-family: var(--accent-mono);
+ font-size: 10px;
+ letter-spacing: 2.2px;
+}
+
+.ds-pm:not([data-state='idle']) .ds-pm-ring-text { fill: var(--pm-signal); }
+.ds-pm[data-look='ink']:not([data-state='idle']) .ds-pm-ring-text,
+.ds-pm[data-look='warm']:not([data-state='idle']) .ds-pm-ring-text { fill: var(--pm-eye); }
+.ds-pm[data-look='ink']:not([data-state='idle']) .ds-pm-stamp .ds-pm-fill,
+.ds-pm[data-look='warm']:not([data-state='idle']) .ds-pm-stamp .ds-pm-fill { stroke: var(--pm-signal); stroke-width: 5; }
+.ds-pm-stamp-type { animation: ds-pm-spin 24s linear infinite; }
+.ds-pm[data-state='thinking'] .ds-pm-stamp-type { animation-duration: 4s; }
+.ds-pm[data-state='input'] .ds-pm-stamp-type { animation-play-state: paused; }
+.ds-pm[data-state='input'] .ds-pm-stamp { animation: ds-pm-wobble 1.2s ease-in-out infinite; transform-origin: center; }
+.ds-pm[data-state='blocked'] .ds-pm-stamp-type { animation-play-state: paused; }
+.ds-pm[data-state='blocked'] .ds-pm-stamp { rotate: -12deg; transform-origin: center; }
+.ds-pm[data-state='done'] .ds-pm-stamp { animation: ds-pm-press 1.8s cubic-bezier(0.3, 0, 0.2, 1) infinite; transform-origin: center; }
+
+@keyframes ds-pm-blink {
+ 0%, 92%, 100% { transform: scaleY(1); }
+ 95% { transform: scaleY(0.1); }
+}
+
+@keyframes ds-pm-rock {
+ 0%, 100% { rotate: -4deg; }
+ 50% { rotate: 4deg; }
+}
+
+@keyframes ds-pm-orbit {
+ from { offset-distance: 0%; }
+ to { offset-distance: 100%; }
+}
+
+@keyframes ds-pm-call {
+ 0%, 60%, 100% { transform: translateY(0) scale(1); }
+ 15% { transform: translateY(-12px) scale(0.96, 1.06); }
+ 30% { transform: translateY(0) scale(1.08, 0.92); }
+ 42% { transform: translateY(-4px); }
+}
+
+@keyframes ds-pm-shake {
+ 0%, 22%, 100% { translate: 0 0; }
+ 5%, 14% { translate: -4px 0; }
+ 9%, 18% { translate: 4px 0; }
+}
+
+@keyframes ds-pm-roll {
+ 0%, 12% { transform: translateY(0) rotate(0); }
+ 45% { transform: translateY(-18px) rotate(200deg); }
+ 70% { transform: translateY(0) rotate(360deg) scale(1.06, 0.94); }
+ 82%, 100% { transform: translateY(0) rotate(360deg); }
+}
+
+@keyframes ds-pm-breathe {
+ from { translate: 0 0; }
+ to { translate: calc(var(--dx) * 3px) calc(var(--dy) * 3px); }
+}
+
+@keyframes ds-pm-quarter {
+ 0% { rotate: 0deg; }
+ 25% { rotate: 90deg; }
+ 50% { rotate: 180deg; }
+ 75% { rotate: 270deg; }
+ 100% { rotate: 360deg; }
+}
+
+@keyframes ds-pm-hug {
+ from { translate: 0 0; }
+ to { translate: calc(var(--dx) * -7px) calc(var(--dy) * -7px); }
+}
+
+@keyframes ds-pm-burst {
+ 0%, 20% { translate: 0 0; }
+ 38% { translate: calc(var(--dx) * 12px) calc(var(--dy) * 12px); }
+ 60%, 100% { translate: 0 0; }
+}
+
+@keyframes ds-pm-caret {
+ 0% { opacity: 1; }
+ 50% { opacity: 0.18; }
+}
+
+@keyframes ds-pm-type {
+ 0% { translate: 0 0; }
+ 50% { translate: 2px 0; }
+}
+
+@keyframes ds-pm-trail {
+ 0% { opacity: 0; }
+ 12%, 80% { opacity: 1; }
+ 90% { opacity: 0; }
+}
+
+@keyframes ds-pm-hop {
+ 0%, 92%, 100% { transform: translateY(0) scale(1); }
+ 12% { transform: translateY(0) scale(1.08, 0.88); }
+ 34% { transform: translateY(calc(var(--hop, 26px) * -1)) scale(0.95, 1.06); }
+ 52% { transform: translateY(calc(var(--hop, 26px) * -1)); }
+ 68% { transform: translateY(0) scale(1.08, 0.9); }
+ 80% { transform: translateY(0) scale(0.98, 1.02); }
+}
+
+@keyframes ds-pm-bob {
+ 0%, 100% { translate: 0 0; }
+ 50% { translate: 0 -5px; }
+}
+
+@keyframes ds-pm-circuit {
+ 0% { translate: 0 0; }
+ 25% { translate: 0 -66px; }
+ 50% { translate: -92px -66px; }
+ 60% { translate: -92px -66px; opacity: 0.4; }
+ 75% { translate: -92px 0; opacity: 1; }
+ 100% { translate: 0 0; }
+}
+
+@keyframes ds-pm-jump {
+ 0%, 100% { transform: translateY(0) scale(1.1, 0.9); }
+ 40% { transform: translateY(-34px) scale(0.94, 1.06); }
+ 55% { transform: translateY(-36px); }
+}
+
+@keyframes ds-pm-spin {
+ to { rotate: 360deg; }
+}
+
+@keyframes ds-pm-wobble {
+ 0%, 100% { rotate: -4deg; }
+ 50% { rotate: 4deg; }
+}
+
+@keyframes ds-pm-press {
+ 0%, 30% { scale: 1; }
+ 40% { scale: 0.86; }
+ 52% { scale: 1.06; }
+ 64%, 100% { scale: 1; }
+}
+
+/* Assets */
+
+.ds-pa-stamp {
+ display: inline-block;
+ padding: 0.35rem 0.7rem 0.3rem;
+ border: 3px double currentColor;
+ font-family: var(--accent-mono);
+ font-size: 0.8rem;
+ letter-spacing: 0.14em;
+ text-transform: uppercase;
+ color: var(--pm-line);
+ mix-blend-mode: normal;
+}
+
+.ds-pa-stamp[data-tone='thinking'] { color: var(--success); }
+.ds-pa-stamp[data-tone='input'] { color: var(--warning); }
+.ds-pa-stamp[data-tone='blocked'] { color: var(--error); }
+.ds-pa-stamp[data-tone='done'] { color: var(--accent); }
+.ds-pm[data-look='paper'] .ds-pa-stamp[data-tone='thinking'] { color: #3f8a58; }
+.ds-pm[data-look='paper'] .ds-pa-stamp[data-tone='input'] { color: #b0712a; }
+.ds-pm[data-look='paper'] .ds-pa-stamp[data-tone='blocked'] { color: var(--terracotta); }
+.ds-pm[data-look='paper'] .ds-pa-stamp[data-tone='done'] { color: var(--tidal-blue); }
+
+.ds-pa-rule {
+ width: 100%;
+ height: 12px;
+ color: var(--pm-line);
+}
+
+.ds-pa-rule--ruler {
+ background:
+ repeating-linear-gradient(90deg, currentColor 0 1px, transparent 1px 20px) bottom / 100% 12px no-repeat,
+ repeating-linear-gradient(90deg, currentColor 0 1px, transparent 1px 4px) bottom / 100% 5px no-repeat,
+ linear-gradient(currentColor, currentColor) bottom / 100% 1px no-repeat;
+ opacity: 0.7;
+}
+
+.ds-pa-rule--dotted {
+ background: radial-gradient(circle, currentColor 1.2px, transparent 1.6px) center / 8px 8px repeat-x;
+ opacity: 0.6;
+}
+
+.ds-pa-rule--thread {
+ background: linear-gradient(90deg, transparent, var(--tidal-blue) 12%, var(--pm-line) 50%, var(--tidal-blue) 88%, transparent) center / 100% 2px no-repeat;
+}
+
+.ds-pa-rule--mark {
+ display: flex;
+ align-items: center;
+ gap: 0.8rem;
+ height: auto;
+}
+
+.ds-pa-rule--mark span {
+ flex: 1;
+ height: 1px;
+ background: currentColor;
+ opacity: 0.45;
+}
+
+.ds-pa-icon {
+ display: block;
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 1.75;
+ stroke-linecap: square;
+ stroke-linejoin: miter;
+}
+
+.ds-pa-icon--pi { fill: currentColor; stroke: none; }
+
+@media (prefers-reduced-motion: reduce) {
+ .ds-pm *,
+ .ds-pm *::before {
+ animation: none !important;
+ transition: none !important;
+ }
+}
+
+/* ── Glyph family ───────────────────────────────────────────────
+ The Pi mark stood up. Inks and state come from the surrounding .ds-pm. */
+
+.ds-gl-mark { display: block; overflow: visible; }
+.ds-gl-mark .ds-pm-eye { animation-delay: 0.4s; }
+
+.ds-gl-svg .ds-pm-eyes,
+.ds-gl-rider,
+.ds-gl-walker,
+.ds-gl-follower,
+.ds-gl-cell,
+.ds-gl-cells,
+.ds-gl-peek-eyes {
+ transform-box: fill-box;
+ transform-origin: 50% 100%;
+}
+
+.ds-gl-peek-eyes,
+.ds-gl-cell { transform-origin: center; }
+
+/* Peek */
+
+.ds-gl-peek-room { fill: var(--pm-line); opacity: 0.08; }
+.ds-gl-peek-eye { fill: var(--pm-line); }
+.ds-gl-peek-eyes { animation: ds-gl-look 6s ease-in-out infinite; }
+.ds-pm[data-state='thinking'] .ds-gl-peek-eyes { animation: ds-gl-scan 1.2s steps(4, end) infinite; }
+.ds-pm[data-state='input'] .ds-gl-peek-eyes { animation: none; transform: scale(1.35); }
+.ds-pm[data-state='input'] .ds-gl-peek-body { animation: ds-pm-call 1.3s cubic-bezier(0.3, 0, 0.3, 1) infinite; }
+.ds-pm[data-state='blocked'] .ds-gl-peek-eyes { animation: none; transform: translateY(6px) scaleY(0.4); }
+.ds-pm[data-state='done'] .ds-gl-peek-eyes { animation: none; transform: scaleY(0.35); }
+.ds-pm[data-state='done'] .ds-gl-peek-body { animation: ds-pm-hop 1.7s cubic-bezier(0.3, 0, 0.3, 1) 0.12s infinite; --hop: 14px; }
+
+/* Carry */
+
+.ds-gl-rider { animation: ds-gl-sway 3s ease-in-out infinite; }
+.ds-pm[data-state='thinking'] .ds-gl-rider { animation: ds-gl-juggle 0.9s cubic-bezier(0.3, 0, 0.3, 1) infinite; transform-origin: center; }
+.ds-pm[data-state='input'] .ds-gl-rider { animation: ds-gl-wave 0.5s ease-in-out infinite alternate; }
+.ds-pm[data-state='blocked'] .ds-gl-rider { animation: none; transform-origin: center; transform: translate(59px, 99px) rotate(90deg); }
+.ds-pm[data-state='blocked'] .ds-gl-carry-body { animation: ds-pm-shake 2.2s ease-in-out infinite; }
+.ds-pm[data-state='blocked'] .ds-gl-carry-body > .ds-pm-eyes { transform: translate(6px, 4px) scaleY(0.4); }
+.ds-pm[data-state='done'] .ds-gl-carry-body { animation: ds-pm-hop 1.7s cubic-bezier(0.3, 0, 0.3, 1) infinite; --hop: 18px; }
+.ds-pm[data-state='done'] .ds-gl-rider { animation: ds-gl-lift 1.7s cubic-bezier(0.3, 0, 0.3, 1) infinite; }
+.ds-pm[data-state='thinking'] .ds-gl-carry-body > .ds-pm-eyes { transform: translateY(-3px); }
+
+/* Walk */
+
+.ds-gl-walk { overflow: hidden; }
+.ds-gl-road rect { fill: var(--pm-line); opacity: 0.5; }
+.ds-gl-walker { animation: ds-pm-bob 3s ease-in-out infinite; }
+.ds-gl-follower { animation: ds-pm-bob 3s ease-in-out 0.3s infinite; }
+.ds-pm[data-state='thinking'] .ds-gl-road { animation: ds-gl-road 0.42s linear infinite; }
+.ds-pm[data-state='thinking'] .ds-gl-walker { animation: ds-gl-step 0.84s ease-in-out infinite; }
+.ds-pm[data-state='thinking'] .ds-gl-follower { animation: ds-gl-skip 0.42s cubic-bezier(0.3, 0, 0.3, 1) infinite; }
+.ds-pm[data-state='thinking'] .ds-gl-walker .ds-pm-eyes { transform: translateX(3px); }
+.ds-pm[data-state='input'] .ds-gl-follower { animation: ds-pm-jump 0.9s cubic-bezier(0.3, 0, 0.3, 1) infinite; }
+.ds-pm[data-state='input'] .ds-gl-walker .ds-pm-eyes { transform: translateX(-4px) scale(1.2); }
+.ds-pm[data-state='blocked'] .ds-gl-walker { animation: ds-gl-strain 1.6s ease-in-out infinite; }
+.ds-pm[data-state='blocked'] .ds-gl-walker .ds-pm-eyes { transform: translateX(3px) scaleY(0.35); }
+.ds-pm[data-state='blocked'] .ds-gl-follower { animation: none; translate: 10px 0; }
+.ds-pm[data-state='done'] .ds-gl-walker { animation: ds-pm-hop 1.7s cubic-bezier(0.3, 0, 0.3, 1) infinite; --hop: 20px; }
+.ds-pm[data-state='done'] .ds-gl-follower { animation: ds-pm-hop 1.7s cubic-bezier(0.3, 0, 0.3, 1) 0.18s infinite; --hop: 28px; }
+
+/* Assemble */
+
+.ds-gl-slot {
+ fill: none;
+ stroke: var(--pm-signal);
+ stroke-width: 2;
+ stroke-dasharray: 4 4;
+ opacity: 0;
+}
+
+.ds-gl-cells { transform-origin: 50% 100%; }
+.ds-gl-assemble-eyes { transition: opacity 200ms ease; }
+.ds-pm[data-state='thinking'] .ds-gl-cell {
+ animation: ds-gl-scatter 3s cubic-bezier(0.6, 0, 0.3, 1) infinite;
+ animation-delay: calc(var(--i) * 0.04s);
+}
+.ds-pm[data-state='thinking'] .ds-gl-assemble-eyes { animation: ds-gl-eyes-away 3s ease infinite; }
+.ds-pm[data-state='input'] .ds-gl-slot { opacity: 0.9; }
+.ds-pm[data-state='input'] .ds-gl-cell--dot { animation: ds-gl-hover 1s ease-in-out infinite alternate; }
+.ds-pm[data-state='blocked'] .ds-gl-cell {
+ transform: translate(var(--px), var(--py)) rotate(var(--pr));
+ transition: transform 700ms cubic-bezier(0.5, 0, 0.8, 0.4);
+ transition-delay: calc(var(--i) * 0.03s);
+}
+.ds-pm[data-state='blocked'] .ds-gl-assemble-eyes { opacity: 0; }
+.ds-pm[data-state='done'] .ds-gl-cells { animation: ds-pm-hop 1.7s cubic-bezier(0.3, 0, 0.3, 1) infinite; --hop: 16px; }
+.ds-pm[data-state='done'] .ds-gl-assemble-eyes { animation: ds-pm-hop 1.7s cubic-bezier(0.3, 0, 0.3, 1) infinite; --hop: 16px; }
+.ds-pm[data-state='done'] .ds-gl-cell { animation: ds-gl-flash 1.7s ease-out infinite; }
+
+/* Extrude */
+
+.ds-gl-extrude {
+ position: relative;
+ display: grid;
+ place-items: center;
+ width: 100%;
+ min-height: 300px;
+ perspective: 800px;
+}
+
+.ds-gl-extrude-spin {
+ position: relative;
+ width: 150px;
+ height: 141px;
+ transform-style: preserve-3d;
+ animation: ds-gl-turn 4.5s ease-in-out infinite alternate;
+}
+
+.ds-gl-layer {
+ position: absolute;
+ inset: 0;
+ width: 100%;
+ height: 100%;
+ overflow: visible;
+ transform: translateZ(calc(var(--z) * -3px));
+}
+
+.ds-gl-side { fill: color-mix(in srgb, var(--pm-body) 42%, #05070a); }
+.ds-gl-layer--back .ds-gl-side { stroke: var(--pm-line); stroke-width: 1.5; }
+.ds-pm[data-look='paper'] .ds-gl-side { fill: color-mix(in srgb, var(--pm-body) 70%, #ebe7e4); }
+.ds-pm[data-look='blueprint'] .ds-gl-side { fill: hsl(208 50% 60% / 0.1); stroke: hsl(208 50% 60% / 0.35); stroke-width: 1; }
+
+.ds-gl-extrude-floor {
+ position: absolute;
+ bottom: 30px;
+ width: 190px;
+ height: 18px;
+ border-radius: 50%;
+ background: radial-gradient(closest-side, rgb(0 0 0 / 0.45), transparent);
+}
+
+.ds-pm[data-look='paper'] .ds-gl-extrude-floor { background: radial-gradient(closest-side, rgb(37 47 61 / 0.18), transparent); }
+.ds-pm[data-state='thinking'] .ds-gl-extrude-spin { animation: ds-gl-spin 3s linear infinite; }
+.ds-pm[data-state='input'] .ds-gl-extrude-spin { animation: ds-gl-nudge 0.8s ease-in-out infinite alternate; }
+.ds-pm[data-state='blocked'] .ds-gl-extrude-spin { animation: none; transform: rotateX(24deg) rotateY(-52deg) rotateZ(-8deg); }
+.ds-pm[data-state='done'] .ds-gl-extrude-spin { animation: ds-gl-flip 2s cubic-bezier(0.6, 0, 0.2, 1) infinite; }
+
+/* Wordmark */
+
+.ds-gl-word {
+ display: flex;
+ align-items: flex-end;
+ gap: 18px;
+}
+
+.ds-gl-word-text {
+ font-family: var(--serif);
+ font-size: 92px;
+ font-weight: 400;
+ line-height: 0.8;
+ letter-spacing: -0.02em;
+ color: var(--pm-line);
+}
+
+.ds-gl-i {
+ position: relative;
+ display: inline-block;
+}
+
+.ds-gl-tittle {
+ position: absolute;
+ left: 50%;
+ top: -0.05em;
+ width: 0.14em;
+ height: 0.14em;
+ margin-left: -0.07em;
+ background: var(--pm-signal);
+ animation: ds-pm-bob 2.8s ease-in-out infinite;
+}
+
+.ds-pm[data-state='thinking'] .ds-gl-tittle { animation: ds-gl-tittle-bounce 0.6s cubic-bezier(0.3, 0, 0.3, 1) infinite; }
+.ds-pm[data-state='input'] .ds-gl-tittle { animation: ds-gl-tittle-wait 1.4s cubic-bezier(0.3, 0, 0.3, 1) infinite; }
+.ds-pm[data-state='blocked'] .ds-gl-tittle { animation: none; translate: 0.26em 0.62em; rotate: 90deg; }
+.ds-pm[data-state='done'] .ds-gl-tittle { animation: ds-gl-tittle-flip 1.7s cubic-bezier(0.3, 0, 0.3, 1) infinite; }
+
+/* Pixel */
+
+.ds-gl-pixel {
+ margin: 0;
+ font-family: Menlo, "SF Mono", "DejaVu Sans Mono", monospace;
+ font-size: 22px;
+ line-height: 1;
+ white-space: pre;
+ color: var(--pm-line);
+}
+
+.ds-gl-pixel-dot { color: var(--pm-signal); }
+
+@keyframes ds-gl-look {
+ 0%, 20%, 100% { transform: translateX(0); }
+ 30%, 45% { transform: translateX(-5px); }
+ 55%, 70% { transform: translateX(5px); }
+ 80% { transform: translate(0, -3px); }
+}
+
+@keyframes ds-gl-scan {
+ 0% { transform: translate(-5px, -3px); }
+ 25% { transform: translate(0, -4px); }
+ 50% { transform: translate(5px, -3px); }
+ 75% { transform: translate(0, 2px); }
+}
+
+@keyframes ds-gl-sway {
+ 0%, 100% { rotate: -3deg; }
+ 50% { rotate: 3deg; }
+}
+
+@keyframes ds-gl-juggle {
+ 0%, 100% { transform: translateY(0) rotate(0); }
+ 45% { transform: translateY(-34px) rotate(90deg); }
+ 55% { transform: translateY(-34px) rotate(90deg); }
+ 90% { transform: translateY(0) rotate(180deg); }
+}
+
+@keyframes ds-gl-wave {
+ from { rotate: -14deg; }
+ to { rotate: 14deg; }
+}
+
+@keyframes ds-gl-lift {
+ 0%, 50%, 100% { translate: 0 0; }
+ 62% { translate: 0 -16px; }
+ 76% { translate: 0 0; }
+}
+
+@keyframes ds-gl-road {
+ from { transform: translateX(0); }
+ to { transform: translateX(-12px); }
+}
+
+@keyframes ds-gl-step {
+ 0%, 100% { transform: rotate(-4deg) translateY(0); }
+ 25% { transform: rotate(0) translateY(-4px); }
+ 50% { transform: rotate(4deg) translateY(0); }
+ 75% { transform: rotate(0) translateY(-4px); }
+}
+
+@keyframes ds-gl-skip {
+ 0%, 100% { transform: translateY(0) scale(1.06, 0.94); }
+ 50% { transform: translateY(-10px) scale(0.96, 1.04); }
+}
+
+@keyframes ds-gl-strain {
+ 0%, 100% { transform: rotate(10deg) translateX(0); }
+ 50% { transform: rotate(13deg) translateX(3px); }
+}
+
+@keyframes ds-gl-scatter {
+ 0%, 12%, 84%, 100% { transform: translate(0, 0) rotate(0); }
+ 34%, 60% { transform: translate(var(--sx), var(--sy)) rotate(var(--sr)); }
+}
+
+@keyframes ds-gl-eyes-away {
+ 0%, 12%, 88%, 100% { opacity: 1; }
+ 24%, 76% { opacity: 0; }
+}
+
+@keyframes ds-gl-hover {
+ from { transform: translateY(-10px); }
+ to { transform: translateY(-20px); }
+}
+
+@keyframes ds-gl-flash {
+ 0%, 60%, 100% { fill: var(--pm-body); }
+ 68% { fill: var(--pm-signal); }
+}
+
+@keyframes ds-gl-turn {
+ from { transform: rotateX(-10deg) rotateY(-38deg); }
+ to { transform: rotateX(-10deg) rotateY(38deg); }
+}
+
+@keyframes ds-gl-spin {
+ from { transform: rotateX(-10deg) rotateY(0deg); }
+ to { transform: rotateX(-10deg) rotateY(360deg); }
+}
+
+@keyframes ds-gl-nudge {
+ from { transform: rotateX(-6deg) rotateY(-14deg) translateY(0); }
+ to { transform: rotateX(-14deg) rotateY(14deg) translateY(-10px); }
+}
+
+@keyframes ds-gl-flip {
+ 0%, 15% { transform: rotateX(-10deg) rotateY(0) translateY(0); }
+ 45% { transform: rotateX(-10deg) rotateY(180deg) translateY(-26px); }
+ 75%, 100% { transform: rotateX(-10deg) rotateY(360deg) translateY(0); }
+}
+
+@keyframes ds-gl-tittle-bounce {
+ 0%, 100% { translate: 0 0; scale: 1.15 0.85; }
+ 50% { translate: 0 -0.18em; scale: 0.92 1.08; }
+}
+
+@keyframes ds-gl-tittle-wait {
+ 0%, 100% { translate: 0 0; }
+ 20%, 70% { translate: 0 -0.34em; }
+}
+
+@keyframes ds-gl-tittle-flip {
+ 0%, 20% { translate: 0 0; rotate: 0deg; }
+ 50% { translate: 0 -0.4em; rotate: 180deg; }
+ 75%, 100% { translate: 0 0; rotate: 360deg; }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .ds-gl-extrude-spin,
+ .ds-gl-tittle,
+ .ds-gl-cell { animation: none !important; transition: none !important; }
+}
+
+/* ── Stamps ─────────────────────────────────────────────────────
+ One ink per tone. Paper darkens each ink so it holds on moonstone. */
+
+.ds-st-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
+
+.ds-st { --st-ink: var(--pm-line, var(--moonstone)); --st-ground: var(--pm-ground, #0d1116); color: var(--st-ink); }
+.ds-st[data-tone='thinking'] { --st-ink: var(--success); }
+.ds-st[data-tone='input'] { --st-ink: var(--warning); }
+.ds-st[data-tone='blocked'] { --st-ink: var(--error); }
+.ds-st[data-tone='done'] { --st-ink: var(--accent); }
+.ds-pm[data-look='paper'] .ds-st[data-tone='thinking'] { --st-ink: #3f8a58; }
+.ds-pm[data-look='paper'] .ds-st[data-tone='input'] { --st-ink: #b0712a; }
+.ds-pm[data-look='paper'] .ds-st[data-tone='blocked'] { --st-ink: var(--terracotta); }
+.ds-pm[data-look='paper'] .ds-st[data-tone='done'] { --st-ink: var(--tidal-blue); }
+.ds-pm[data-look='warm'] .ds-st[data-tone='done'] { --st-ink: var(--sunkissed); }
+
+.ds-st[data-inked='true'] { filter: url(#ds-ink); }
+
+.ds-st-line { fill: none; stroke: var(--st-ink); }
+.ds-st-ink-fill { fill: var(--st-ink); }
+
+.ds-st-type {
+ fill: var(--st-ink);
+ font-family: var(--accent-mono);
+ letter-spacing: 0.14em;
+}
+
+.ds-st-ring { font-size: 12.5px; letter-spacing: 0.2em; }
+.ds-st-band { fill: var(--st-ground); font-size: 13px; letter-spacing: 0.16em; }
+.ds-st-small { font-size: 10px; letter-spacing: 0.18em; }
+.ds-st-date { font-size: 10px; letter-spacing: 0; }
+
+/* Label */
+
+.ds-st-label {
+ display: inline-block;
+ padding: 0.4rem 0.8rem 0.35rem;
+ border: 4px double var(--st-ink);
+ font-family: var(--accent-mono);
+ font-size: 0.95rem;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ white-space: nowrap;
+}
+
+/* Seal */
+
+.ds-st-seal { display: block; width: 180px; height: 180px; overflow: visible; }
+
+/* Ticket */
+
+.ds-st-ticket {
+ --notch: 11px;
+ display: grid;
+ grid-template-columns: auto 1fr;
+ width: 340px;
+ max-width: 100%;
+ color: var(--st-ground);
+ background: var(--st-ink);
+ mask:
+ radial-gradient(circle var(--notch) at 0 50%, transparent 98%, #000) left / 51% 100% no-repeat,
+ radial-gradient(circle var(--notch) at 100% 50%, transparent 98%, #000) right / 51% 100% no-repeat;
+}
+
+.ds-st-ticket-stub {
+ display: grid;
+ justify-items: center;
+ align-content: center;
+ gap: 8px;
+ padding: 16px 18px 14px 22px;
+ border-right: 2px dashed var(--st-ground);
+ font-family: var(--accent-mono);
+ font-size: 0.72rem;
+ letter-spacing: 0.1em;
+}
+
+.ds-st-ticket-stub svg { width: 52px; height: auto; }
+.ds-st-ticket-stub .ds-st-ink-fill { fill: var(--st-ground); }
+
+.ds-st-ticket-body {
+ display: grid;
+ gap: 4px;
+ align-content: center;
+ padding: 14px 24px 14px 18px;
+ min-width: 0;
+}
+
+.ds-st-ticket-kicker,
+.ds-st-ticket-word {
+ font-family: var(--accent-mono);
+ font-size: 0.66rem;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+}
+
+.ds-st-ticket-title {
+ overflow: hidden;
+ font-family: var(--serif);
+ font-size: 1.35rem;
+ font-style: italic;
+ line-height: 1.1;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.ds-st-ticket-word {
+ justify-self: start;
+ margin-top: 4px;
+ padding: 2px 6px;
+ border: 1.5px solid var(--st-ground);
+}
+
+/* Postmark */
+
+.ds-st-postmark { display: block; width: 300px; max-width: 100%; height: auto; overflow: visible; }
+
+/* Review */
+
+.ds-st-review {
+ width: 260px;
+ border: 3px solid var(--st-ink);
+ font-family: var(--accent-mono);
+ font-size: 0.7rem;
+ letter-spacing: 0.1em;
+ text-transform: uppercase;
+}
+
+.ds-st-review-head {
+ padding: 6px 10px;
+ color: var(--st-ground);
+ background: var(--st-ink);
+ letter-spacing: 0.2em;
+}
+
+.ds-st-review dl {
+ display: grid;
+ grid-template-columns: auto 1fr;
+ gap: 8px 14px;
+ margin: 0;
+ padding: 12px 12px 14px;
+}
+
+.ds-st-review dt { opacity: 0.7; }
+.ds-st-review dd { margin: 0; border-bottom: 1px dotted currentColor; padding-bottom: 2px; text-transform: none; font-family: var(--mono); letter-spacing: 0; }
+
+.ds-st-review-result {
+ position: relative;
+ justify-self: start;
+ padding: 0 6px;
+ border-bottom: 0 !important;
+ font-family: var(--accent-mono) !important;
+ letter-spacing: 0.14em !important;
+ text-transform: uppercase !important;
+}
+
+.ds-st-review-result svg {
+ position: absolute;
+ inset: -9px -12px;
+ width: calc(100% + 24px);
+ height: calc(100% + 18px);
+ overflow: visible;
+}
+
+/* Stickers */
+
+.ds-st-sticker {
+ display: block;
+ width: 120px;
+ height: auto;
+ overflow: visible;
+ filter: drop-shadow(0 6px 8px rgb(0 0 0 / 0.35));
+ transition: rotate 300ms cubic-bezier(0.3, 1.6, 0.4, 1), translate 300ms cubic-bezier(0.3, 1.6, 0.4, 1);
+}
+
+.ds-st-sticker:hover { rotate: 0deg !important; translate: 0 -4px; }
+.ds-st-sticker[aria-label='Built with pi sticker'],
+.ds-st-sticker[aria-label='Ship it sticker'] { width: 190px; }
+.ds-st-sticker-edge { fill: #ebe7e4; }
+
+.ds-st-sticker-ring {
+ fill: #13110f;
+ font-family: var(--accent-mono);
+ font-size: 9.5px;
+ letter-spacing: 0.12em;
+}
+
+.ds-st-sticker-pi {
+ fill: #13110f;
+ font-family: var(--serif);
+ font-size: 46px;
+ font-style: italic;
+}
+
+.ds-st-sticker-word {
+ fill: #ebe7e4;
+ font-family: var(--serif);
+ font-size: 25px;
+ font-style: italic;
+}
+
+.ds-st-sticker-word--ink {
+ fill: #13110f;
+ font-family: var(--accent-mono);
+ font-size: 17px;
+ font-style: normal;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+}
+
+/* Press */
+
+.ds-st-press {
+ position: relative;
+ display: grid;
+ place-items: center;
+ animation: ds-st-press 520ms cubic-bezier(0.5, 0, 0.2, 1) both;
+}
+
+.ds-st-splash {
+ position: absolute;
+ inset: 12%;
+ border: 2px solid var(--pm-signal, var(--accent));
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ animation: ds-st-splash 700ms ease-out 180ms both;
+}
+
+@keyframes ds-st-press {
+ 0% { opacity: 0; transform: scale(1.7) rotate(8deg); filter: blur(2px); }
+ 55% { opacity: 1; transform: scale(0.94) rotate(-1deg); filter: blur(0); }
+ 75% { transform: scale(1.02) rotate(0); }
+ 100% { opacity: 1; transform: scale(1) rotate(0); }
+}
+
+@keyframes ds-st-splash {
+ 0% { opacity: 0.8; transform: scale(0.7); }
+ 100% { opacity: 0; transform: scale(1.5); }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .ds-st-press,
+ .ds-st-splash { animation: none; }
+ .ds-st-splash { display: none; }
+}
+
+/* ── Schematic ──────────────────────────────────────────────────
+ A drawing sheet. Linework in the look's line ink, the live state in the signal ink. */
+
+@property --bp-spread {
+ syntax: '';
+ inherits: true;
+ initial-value: 0px;
+}
+
+.ds-bp-sheet {
+ display: block;
+ width: 100%;
+ height: auto;
+ overflow: visible;
+}
+
+.ds-bp-frame { fill: none; stroke: var(--pm-line); stroke-width: 1.5; }
+.ds-bp-frame--inner { stroke-width: 2.5; }
+.ds-bp-ext { fill: none; stroke: var(--pm-line); stroke-width: 1; opacity: 0.6; }
+.ds-bp-construct { fill: none; stroke: var(--pm-line); stroke-width: 1; stroke-dasharray: 2 4; opacity: 0.35; }
+.ds-bp-center { fill: none; stroke: var(--pm-line); stroke-width: 1; stroke-dasharray: 14 4 3 4; opacity: 0.55; }
+.ds-bp-arrow { fill: var(--pm-line); }
+.ds-bp-arrow--hot { fill: var(--pm-signal); }
+
+.ds-bp-dimline {
+ fill: none;
+ stroke: var(--pm-line);
+ stroke-width: 1.25;
+ stroke-dasharray: 1;
+ animation: ds-bp-draw 1.1s cubic-bezier(0.6, 0, 0.2, 1) 0.2s both;
+}
+
+.ds-bp-label {
+ fill: var(--pm-line);
+ font-family: var(--accent-mono);
+ font-size: 12px;
+ letter-spacing: 0.1em;
+}
+
+.ds-bp-small { font-size: 10.5px; }
+.ds-bp-tiny { font-size: 9px; opacity: 0.65; }
+.ds-bp-note { font-size: 9.5px; letter-spacing: 0.04em; opacity: 0.85; }
+.ds-bp-zone { font-size: 10px; opacity: 0.7; }
+.ds-bp-view-title { font-size: 12.5px; letter-spacing: 0.16em; }
+
+.ds-bp-title {
+ fill: var(--pm-line);
+ font-family: var(--serif);
+ font-size: 26px;
+ font-style: italic;
+}
+
+.ds-bp-part { stroke-width: 2; }
+.ds-pm[data-look='blueprint'] .ds-bp-part { fill: hsl(208 50% 60% / 0.16); }
+.ds-pm[data-look='blueprint'] .ds-bp-eye { fill: var(--pm-line); }
+
+.ds-bp-depth { fill: color-mix(in srgb, var(--pm-line) 10%, transparent); stroke: var(--pm-line); stroke-width: 1; }
+
+.ds-bp-pin { fill: var(--pm-line); }
+.ds-bp-leader { fill: none; stroke: var(--pm-line); stroke-width: 1; }
+.ds-bp-balloon { fill: var(--pm-ground); stroke: var(--pm-line); stroke-width: 1.25; }
+.ds-bp-balloon-n { font-size: 11px; letter-spacing: 0; }
+
+.ds-bp-callout {
+ animation: ds-bp-fade 500ms ease both;
+ animation-delay: calc(0.5s + var(--n) * 0.18s);
+}
+
+.ds-bp-callout:nth-child(n) .ds-bp-pin { fill: var(--pm-line); }
+.ds-bp-view > .ds-bp-callout:last-of-type .ds-bp-pin { fill: var(--pm-signal); }
+
+/* Exploded view breathes: the cells part and close along their own grid offsets */
+.ds-bp-explode { animation: ds-bp-explode 6s cubic-bezier(0.6, 0, 0.3, 1) infinite; }
+.ds-bp-cell { transform: translate(calc(var(--cx) * var(--bp-spread)), calc(var(--cy) * var(--bp-spread))); }
+
+.ds-bp-hot-row .ds-bp-label,
+.ds-bp-hot-text .ds-bp-label:last-child { fill: var(--pm-signal); }
+
+/* State schema */
+
+.ds-bp-edge-line { fill: none; stroke: var(--pm-line); stroke-width: 1.25; opacity: 0.7; }
+
+.ds-bp-edge--hot .ds-bp-edge-line {
+ stroke: var(--pm-signal);
+ stroke-width: 2;
+ stroke-dasharray: 6 5;
+ opacity: 1;
+ animation: ds-bp-flow 0.8s linear infinite;
+}
+
+.ds-bp-node rect { fill: var(--pm-ground); stroke: var(--pm-line); stroke-width: 1.5; }
+
+.ds-bp-node--hot rect {
+ fill: color-mix(in srgb, var(--pm-signal) 16%, var(--pm-ground));
+ stroke: var(--pm-signal);
+ stroke-width: 2.5;
+ animation: ds-bp-pulse 1.6s ease-in-out infinite;
+}
+
+.ds-bp-node--hot .ds-bp-label { fill: var(--pm-signal); }
+
+.ds-bp-seal { opacity: 0.9; }
+.ds-bp-seal .ds-st-seal { animation: ds-st-press 520ms cubic-bezier(0.5, 0, 0.2, 1) 0.9s both; transform-box: fill-box; transform-origin: center; }
+
+@keyframes ds-bp-draw {
+ from { stroke-dashoffset: 1; }
+ to { stroke-dashoffset: 0; }
+}
+
+@keyframes ds-bp-fade {
+ from { opacity: 0; translate: -6px 0; }
+ to { opacity: 1; translate: 0 0; }
+}
+
+@keyframes ds-bp-explode {
+ 0%, 18%, 100% { --bp-spread: 0px; }
+ 42%, 76% { --bp-spread: 16px; }
+}
+
+@keyframes ds-bp-flow {
+ to { stroke-dashoffset: -11; }
+}
+
+@keyframes ds-bp-pulse {
+ 0%, 100% { stroke-opacity: 1; }
+ 50% { stroke-opacity: 0.45; }
+}