diff --git a/.agents/agents/design-system-keeper.md b/.agents/agents/design-system-keeper.md index 959beaa..a239273 100644 --- a/.agents/agents/design-system-keeper.md +++ b/.agents/agents/design-system-keeper.md @@ -20,11 +20,13 @@ palettes and a broken `@font-face`. **Load skills**: `design-tokens`, `--paper`, `--muted`, `--line`, `--gold` likewise. Most deltas are sub-perceptual and can be canonicalized. `--blue` (`#527f9f` vs `#215675`) is visibly different — screenshot both and get a human decision. -2. **The fonts have never rendered.** The `@font-face` in `styles.css:1` points - `src:` at a Google Fonts _stylesheet_, so Manrope and DM Mono have always - fallen back to Arial and generic monospace. Self-hosting them is a redesign, - not a refactor. Default: delete the dead rule, declare the stacks that - actually render. Escalate if someone wants the real fonts. +2. ~~**The fonts have never rendered.**~~ **Settled 2026-09-05 — do not + reopen.** The malformed `@font-face` was escalated and the human chose the + real fonts. Manrope and DM Mono are self-hosted in `public/fonts/`, wired + through `public/fonts/fonts.css`, which `BaseLayout.astro` links and the + legacy root `styles.css` `@import`s. **Do not delete these faces and do not + replace the stacks with `Arial`/`ui-monospace`** — that instruction is + obsolete. You may add `--font-sans` / `--font-mono` tokens pointing at them. ## You own diff --git a/.agents/context/design-system.md b/.agents/context/design-system.md index e7f770f..49579c8 100644 --- a/.agents/context/design-system.md +++ b/.agents/context/design-system.md @@ -8,18 +8,18 @@ files, not assumed. The same semantic names carry different values depending on which stylesheet loaded them: -| Token | `styles.css`, `rules/styles.css` | `chapters.css`, `skills-review/styles.css` | `hands-on/*/styles.css` | -| --- | --- | --- | --- | -| `--paper` | `#f5f4f1` | `#f6f3ed` | `#f4f3ef` | -| `--ink` | `#172f42` | `#122534` | `#173044` | -| `--muted` | `#697b89` | `#65717a` | `#687d8c` | -| `--line` | `#d8dee2` | `#d0d5d2` | `#d5dde1` | -| `--blue` | `#527f9f` | `#215675` | `#5683a1` | -| `--gold` | `#efc76b` | `#ebbf58` | `#efc86d` | -| `--accent` | `#7c78a8` | — | — | -| `--deep` | `#102536` | — | — | -| `--red` | — | `#a7483f` (chapters only) | — | -| `--violet` | — | `#6b668f` (review desk only) | — | +| Token | `styles.css`, `rules/styles.css` | `chapters.css`, `skills-review/styles.css` | `hands-on/*/styles.css` | +| ---------- | -------------------------------- | ------------------------------------------ | ----------------------- | +| `--paper` | `#f5f4f1` | `#f6f3ed` | `#f4f3ef` | +| `--ink` | `#172f42` | `#122534` | `#173044` | +| `--muted` | `#697b89` | `#65717a` | `#687d8c` | +| `--line` | `#d8dee2` | `#d0d5d2` | `#d5dde1` | +| `--blue` | `#527f9f` | `#215675` | `#5683a1` | +| `--gold` | `#efc76b` | `#ebbf58` | `#efc86d` | +| `--accent` | `#7c78a8` | — | — | +| `--deep` | `#102536` | — | — | +| `--red` | — | `#a7483f` (chapters only) | — | +| `--violet` | — | `#6b668f` (review desk only) | — | Most deltas are a few units per channel — drift, not intent. `--blue` is the exception: `#527f9f` vs `#215675` is a visible difference and may be deliberate. @@ -34,35 +34,36 @@ exception: `#527f9f` vs `#215675` is a visible difference and may be deliberate. Do not "just pick one" silently in the middle of another task. This is its own reviewed change with visual diffs attached. -## The typography you see is not the typography that was written +## The typography — fixed 2026-09-05 -`styles.css` line 1: +`styles.css` line 1 used to read: ```css -@font-face{font-family:Manrope;src:url('https://fonts.googleapis.com/css2?family=DM+Mono&family=Manrope:wght@400;600;700;800&display=swap')} +@font-face { + font-family: Manrope; + src: url('https://fonts.googleapis.com/css2?family=DM+Mono&family=Manrope:wght@400;600;700;800&display=swap'); +} ``` -`src:` points at a **CSS stylesheet**, not a font file. No browser can load a -font from that, so: +`src:` in an `@font-face` must point at a font binary. That URL returns a CSS +stylesheet, so no browser could load a face from it. For the whole life of the +site, every `font-family:Manrope,Arial,sans-serif` rendered as **Arial** and +every `font:… 'DM Mono',monospace` rendered as the **generic monospace** face — +`'DM Mono'` was never declared as a family at all. -- every `font-family:Manrope,Arial,sans-serif` renders as **Arial** -- every `font:… 'DM Mono',monospace` renders as the **generic monospace** face -- there are no `@font-face` blocks anywhere else and zero font files in the repo -- `scripts/audit-ui.mjs` only rejects external ``/` + + diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index 7ebe952..54d18e3 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -6,6 +6,11 @@ interface Props { } const { title, description, lang = 'en' } = Astro.props; + +// Self-hosted Manrope and DM Mono. Lives in `public/fonts/` rather than the +// bundled CSS because the legacy stylesheets @import the same file, so there +// is exactly one copy of the faces. See public/fonts/fonts.css. +const fonts = `${import.meta.env.BASE_URL}fonts/fonts.css`.replace('//', '/'); --- @@ -15,6 +20,7 @@ const { title, description, lang = 'en' } = Astro.props; {title} + diff --git a/src/pages/agents.astro b/src/pages/agents.astro new file mode 100644 index 0000000..00d207a --- /dev/null +++ b/src/pages/agents.astro @@ -0,0 +1,106 @@ +--- +// /agents/ — chapter page. Migrated from agents/index.html in task 13. +// Identical URL (/agents/), zero client JS, copy lives in +// src/content/chapters/agents.json. + +import { getEntry } from 'astro:content'; +import ChapterLayout from '../layouts/ChapterLayout.astro'; +import ChapterHero from '../components/blocks/ChapterHero.astro'; + +// Required-field guard. The chapters schema marks section eyebrow / +// panelLabel / panelCode / steps / copy as optional because the schema +// does not know which page consumes which shape. These four pages do +// consume them — fail loudly here rather than rendering a blank section. +function requireField(value: T | undefined, name: string): T { + if (value === undefined) { + throw new Error(`agents chapter: missing required field "${name}"`); + } + return value; +} + +const base = import.meta.env.BASE_URL; +const chapter = await getEntry('chapters', 'agents'); +if (!chapter) { + throw new Error('agents chapter: missing collection entry'); +} +const lede = chapter.data.lede.en; +const title = chapter.data.title.en; +const eyebrow = chapter.data.eyebrow.en; +const cards = chapter.data.cards ?? []; +const sections = chapter.data.sections ?? []; +const treeSection = sections[0]; +const handoffSection = sections[1]; +if (!treeSection) { + throw new Error('agents chapter: missing sections[0]'); +} +if (!handoffSection) { + throw new Error('agents chapter: missing sections[1]'); +} +// Narrow the section fields this page renders. Each `requireField` either +// returns a non-null value or throws — TS narrows from `T | undefined` to `T`. +const treeEyebrow = requireField(treeSection.eyebrow, 'sections[0].eyebrow'); +const treePanelLabel = requireField(treeSection.panelLabel, 'sections[0].panelLabel'); +const treePanelCode = requireField(treeSection.panelCode, 'sections[0].panelCode'); +const handoffEyebrow = requireField(handoffSection.eyebrow, 'sections[1].eyebrow'); +const handoffSteps = requireField(handoffSection.steps, 'sections[1].steps'); +--- + +]+>/g, '')}> + ← ROUTE MAP + 02 / AGENTS & TREES + field guide ↗ + + + +

{lede}

+
+ +
+
+

{treeEyebrow.en}

+

+

+
+ {treePanelLabel.en} + {treePanelCode.en} +
+
+ +
+ { + cards.map((card) => ( +
+ {card.label.en} +

{card.title.en}

+

{card.copy.en}

+
+ )) + } +
+ +
+
+

{handoffEyebrow.en}

+

+

+
+ { + handoffSteps.map((step, index) => ( +
+ {String(index + 1).padStart(2, '0')} +
+ {step.label.en} + {step.copy.en} +
+
+ )) + } +
+
+ + +
diff --git a/src/pages/models.astro b/src/pages/models.astro new file mode 100644 index 0000000..041166f --- /dev/null +++ b/src/pages/models.astro @@ -0,0 +1,105 @@ +--- +// /models/ — chapter page. Migrated from models/index.html in task 13. +// Identical URL (/models/), zero client JS, copy lives in +// src/content/chapters/models.json. The grid + panel + steps sections +// render the chapter-collections content with bilingual `en` strings. + +import { getEntry } from 'astro:content'; +import ChapterLayout from '../layouts/ChapterLayout.astro'; +import ChapterHero from '../components/blocks/ChapterHero.astro'; + +// Required-field guard. The chapters schema marks section eyebrow / +// panelLabel / panelCode / steps / copy as optional because the schema +// does not know which page consumes which shape. These four pages do +// consume them — fail loudly here rather than rendering a blank section. +function requireField(value: T | undefined, name: string): T { + if (value === undefined) { + throw new Error(`models chapter: missing required field "${name}"`); + } + return value; +} + +const base = import.meta.env.BASE_URL; +const chapter = await getEntry('chapters', 'models'); +if (!chapter) { + throw new Error('models chapter: missing collection entry'); +} +const lede = chapter.data.lede.en; +const title = chapter.data.title.en; +const eyebrow = chapter.data.eyebrow.en; +const cards = chapter.data.cards ?? []; +const sections = chapter.data.sections ?? []; +// First section carries the routing-rule panel, second carries the steps. +const ruleSection = sections[0]; +const sequenceSection = sections[1]; +if (!ruleSection) { + throw new Error('models chapter: missing sections[0]'); +} +if (!sequenceSection) { + throw new Error('models chapter: missing sections[1]'); +} +const ruleEyebrow = requireField(ruleSection.eyebrow, 'sections[0].eyebrow'); +const rulePanelLabel = requireField(ruleSection.panelLabel, 'sections[0].panelLabel'); +const rulePanelCode = requireField(ruleSection.panelCode, 'sections[0].panelCode'); +const sequenceEyebrow = requireField(sequenceSection.eyebrow, 'sections[1].eyebrow'); +const sequenceSteps = requireField(sequenceSection.steps, 'sections[1].steps'); +--- + +]+>/g, '')}> + ← ROUTE MAP + 01 / MODELS + field guide ↗ + + + +

{lede}

+
+ +
+ { + cards.map((card) => ( +
+ {card.label.en} +

{card.title.en}

+

{card.copy.en}

+
+ )) + } +
+ +
+
+

{ruleEyebrow.en}

+

+

+
+ {rulePanelLabel.en} + {rulePanelCode.en} +
+
+ +
+
+

{sequenceEyebrow.en}

+

+

+
+ { + sequenceSteps.map((step, index) => ( +
+ {String(index + 1).padStart(2, '0')} +
+ {step.label.en} + {step.copy.en} +
+
+ )) + } +
+
+ + +
diff --git a/src/pages/skills.astro b/src/pages/skills.astro new file mode 100644 index 0000000..9e9518b --- /dev/null +++ b/src/pages/skills.astro @@ -0,0 +1,93 @@ +--- +// /skills/ — chapter page. Migrated from skills/index.html in task 13. +// Identical URL (/skills/). The package-anatomy picker is an Astro island +// (SkillPackageExplorer) — the only JS the page ships. Copy lives in +// src/content/chapters/skills.json. + +import { getEntry } from 'astro:content'; +import ChapterLayout from '../layouts/ChapterLayout.astro'; +import ChapterHero from '../components/blocks/ChapterHero.astro'; +import SkillPackageExplorer from '../components/islands/SkillPackageExplorer.astro'; +import skillsStylesheet from '../../skills/styles.css?url'; + +// Required-field guard. The chapters schema marks section eyebrow / +// panelLabel / panelCode / steps / copy as optional because the schema +// does not know which page consumes which shape. These four pages do +// consume them — fail loudly here rather than rendering a blank section. +function requireField(value: T | undefined, name: string): T { + if (value === undefined) { + throw new Error(`skills chapter: missing required field "${name}"`); + } + return value; +} + +const base = import.meta.env.BASE_URL; +const chapter = await getEntry('chapters', 'skills'); +if (!chapter) { + throw new Error('skills chapter: missing collection entry'); +} +const lede = chapter.data.lede.en; +const title = chapter.data.title.en; +const eyebrow = chapter.data.eyebrow.en; +const sections = chapter.data.sections ?? []; +const anatomySection = sections[0]; +const createSection = sections[1]; +if (!anatomySection) { + throw new Error('skills chapter: missing sections[0]'); +} +if (!createSection) { + throw new Error('skills chapter: missing sections[1]'); +} +const anatomyEyebrow = requireField(anatomySection.eyebrow, 'sections[0].eyebrow'); +const anatomyCopy = requireField(anatomySection.copy, 'sections[0].copy'); +const createEyebrow = requireField(createSection.eyebrow, 'sections[1].eyebrow'); +const createSteps = requireField(createSection.steps, 'sections[1].steps'); +--- + +]+>/g, '')}> + + ← ROUTE MAP + 03 / SKILLS + review desk ↗ + + + +

+ + +

+
+

{anatomyEyebrow.en}

+

+

{anatomyCopy.en}

+

+ +
+ +
+
+

{createEyebrow.en}

+

+

+
+ { + createSteps.map((step, index) => ( +
+ {String(index + 1).padStart(2, '0')} +
+ {step.label.en} + {step.copy.en} +
+
+ )) + } +
+
+ + +
diff --git a/styles.css b/styles.css index 4009841..557ed32 100644 --- a/styles.css +++ b/styles.css @@ -1,2 +1,2 @@ -@font-face{font-family:Manrope;src:url('https://fonts.googleapis.com/css2?family=DM+Mono&family=Manrope:wght@400;600;700;800&display=swap')} :root{--paper:#f5f4f1;--ink:#172f42;--muted:#697b89;--accent:#7c78a8;--blue:#527f9f;--gold:#efc76b;--line:#d8dee2;--deep:#102536}*{box-sizing:border-box}body{margin:0;min-width:320px;background:var(--paper);color:var(--ink);font-family:Manrope,Arial,sans-serif}main{padding:28px clamp(24px,6vw,96px) 80px}.topbar,.section-label{display:flex;justify-content:space-between;align-items:center}.brand{color:var(--ink);font-size:12px;font-weight:800;text-decoration:none;text-transform:uppercase}.mark{display:inline-grid;place-items:center;width:28px;height:28px;margin-right:9px;border-radius:50%;color:var(--paper);background:var(--accent)}.edition,.eyebrow,.section-label,.thesis span,.captain span,.workers span,.route-table b,.skill-package>span,.rule span,.callout span,.sources{font:500 10px 'DM Mono',monospace;letter-spacing:.1em;text-transform:uppercase}.edition i{display:inline-block;width:6px;height:6px;margin:0 8px;border-radius:50%;background:var(--accent)}.hero{max-width:780px;padding:clamp(75px,12vh,145px) 0 85px}.eyebrow,.section-label,.thesis span{color:var(--accent)}h1{margin:16px 0 24px;font-size:clamp(56px,9vw,126px);line-height:.86;letter-spacing:-.08em}h1 em,h2 em{color:var(--blue);font-family:Georgia,serif;font-weight:400}.lede,.copy>p:last-child,.skills>div:first-child>p:last-child,.worktrees>div:first-child>p,.caption{max-width:570px;color:var(--muted);line-height:1.65}.thesis{display:grid;grid-template-columns:1fr 1fr;gap:30px;align-items:center;margin-bottom:110px;padding:28px;background:var(--gold)}.thesis div:first-child{display:grid;gap:16px}.thesis strong{font-size:clamp(24px,4vw,46px);line-height:1.05;letter-spacing:-.04em}.signal{display:flex;align-items:center;gap:10px}.signal i{width:28px;height:28px;border:1px solid var(--ink);background:var(--paper)}.signal i:nth-of-type(3){background:var(--blue)}.signal b{font:500 10px 'DM Mono',monospace}.fleet{margin-bottom:120px}.section-label{padding-bottom:14px;border-bottom:1px solid var(--line)}.section-label span:last-child{color:var(--muted)}.fleet-grid{display:grid;grid-template-columns:.8fr 50px 1.5fr;gap:24px;margin-top:30px;color:var(--paper);background:var(--deep)}.captain{display:grid;align-content:center;gap:16px;padding:32px}.captain span{color:var(--gold)}h2{margin:14px 0 20px;font-size:clamp(36px,5vw,65px);line-height:.98;letter-spacing:-.06em}.captain h2{font-size:clamp(24px,3vw,38px)}.captain code,.workers code{color:var(--gold);font:11px 'DM Mono',monospace}.arrow{display:grid;place-items:center;color:var(--gold);font-size:30px}.workers{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:#41596b}.workers article{display:grid;align-content:space-between;gap:20px;min-height:180px;padding:22px;background:var(--ink)}.workers span{color:#9eabb4}.workers strong{font-size:16px;line-height:1.2}.caption{margin:22px 0 0 auto}.workflow,.routing,.skills{display:grid;grid-template-columns:.7fr 1fr 1.3fr;gap:40px;align-items:start;margin-bottom:130px;padding-top:80px;border-top:1px solid var(--line)}.phase-tabs{display:grid;gap:8px}.phase-tabs button{display:grid;grid-template-columns:42px 1fr;gap:10px;padding:15px;border:1px solid var(--line);color:var(--ink);background:transparent;font:500 10px 'DM Mono',monospace;letter-spacing:.07em;text-align:left;cursor:pointer}.phase-tabs button b{color:var(--accent)}.phase-tabs button.active{color:var(--paper);border-color:var(--ink);background:var(--ink)}.phase-panel{min-height:260px;padding:30px;color:var(--paper);background:var(--accent)}.phase-meta{display:flex;justify-content:space-between;gap:15px;color:var(--gold);font:500 10px 'DM Mono',monospace}.phase-meta small{color:var(--paper);opacity:.7}.phase-panel h3{margin:44px 0 12px;font-size:clamp(24px,3vw,38px);line-height:1.05}.phase-panel p{line-height:1.6;opacity:.82}.phase-panel code{display:block;margin-top:26px;color:var(--gold);font:11px 'DM Mono',monospace}.handoff{margin-bottom:130px}.handoff table{width:100%;margin-top:30px;border-collapse:collapse;text-align:left}.handoff th,.handoff td{padding:17px 14px;border-bottom:1px solid var(--line)}.handoff thead{color:var(--paper);background:var(--ink);font:500 10px 'DM Mono',monospace;letter-spacing:.08em;text-transform:uppercase}.handoff tbody th{color:var(--blue);font:600 14px 'DM Mono',monospace}.handoff td{color:var(--muted);font-size:13px}.worktrees{display:grid;grid-template-columns:.8fr 1.2fr;gap:50px;align-items:center;margin-bottom:130px;padding:45px;color:var(--paper);background:var(--deep)}.worktrees .eyebrow{color:var(--gold)}.worktrees h2{color:var(--paper)}.worktrees h2 em{color:var(--gold)}.worktrees>div:first-child>p{color:#b0bac1}.worktrees pre{margin:32px 0 0;padding:20px;overflow:auto;color:var(--gold);background:var(--ink)}pre code{font:12px/1.75 'DM Mono',monospace}.map{position:relative;display:grid;grid-template-columns:1fr 1fr;gap:14px;padding-top:90px}.repo{position:absolute;top:0;left:50%;width:180px;padding:17px;transform:translateX(-50%);color:var(--ink);background:var(--gold)}.map>div:not(.repo){min-height:135px;padding:20px;border:1px solid #41596b;background:var(--ink)}.repo span,.map>div:not(.repo) span{display:block;margin-bottom:12px;color:var(--accent);font:500 9px 'DM Mono',monospace}.repo strong,.map>div:not(.repo) strong{display:block;font:14px 'DM Mono',monospace}.repo small,.map>div:not(.repo) small{display:block;margin-top:12px;color:#9eabb4;font-size:11px}.routing{grid-template-columns:.8fr 1.2fr}.route-table{border-top:1px solid var(--line);border-left:1px solid var(--line)}.route-table>div{display:grid;grid-template-columns:.8fr .9fr 1.4fr}.route-table .head{color:var(--paper);background:var(--ink);font:500 10px 'DM Mono',monospace;letter-spacing:.08em;text-transform:uppercase}.route-table>div>*{padding:15px;border-right:1px solid var(--line);border-bottom:1px solid var(--line)}.route-table strong{font-size:14px}.route-table b{color:var(--blue);letter-spacing:0;text-transform:none}.route-table small{color:var(--muted);font-size:12px}.skills{grid-template-columns:.8fr 1fr;margin-bottom:90px}.skill-package{display:grid;align-content:start;color:var(--paper);background:var(--blue)}.skill-package>span{padding:20px;color:var(--gold);border-bottom:1px solid #ffffff40}.skill-package>div{display:grid;grid-template-columns:1fr 1fr;gap:15px;padding:17px 20px;border-bottom:1px solid #ffffff40}.skill-package code{font:12px 'DM Mono',monospace}.skill-package small{opacity:.7}.skills>pre{grid-column:2;margin:0;padding:28px;overflow:auto;color:#d8dee2;background:var(--ink)}.rule{display:grid;grid-template-columns:150px 1fr;gap:30px;margin-top:55px;padding-top:22px;border-top:4px solid var(--gold)}.rule strong{max-width:850px;font-size:clamp(24px,3.3vw,42px);line-height:1.12}.callout{display:grid;grid-template-columns:150px 1fr;gap:30px;margin-top:70px;padding:27px;background:var(--gold)}.callout strong{max-width:850px;font-size:clamp(22px,3vw,36px);line-height:1.1}.sources{margin-top:90px;color:var(--muted)}.sources p{color:var(--muted);font:13px/1.6 Manrope,Arial,sans-serif;letter-spacing:0;text-transform:none}.sources a{color:var(--blue);font-weight:700}@media(max-width:800px){.thesis,.fleet-grid,.workflow,.worktrees,.routing,.skills{grid-template-columns:1fr}.arrow{transform:rotate(90deg);min-height:35px}.workers{grid-template-columns:1fr}.skills>pre{grid-column:auto}.route-table,.handoff{overflow-x:auto}.route-table>div{min-width:620px}.handoff table{min-width:650px}.rule,.callout{grid-template-columns:1fr}}@media(max-width:600px){.edition{display:none}.worktrees{padding:24px}.map{grid-template-columns:1fr;padding-top:90px}} +@import url('public/fonts/fonts.css'); :root{--paper:#f5f4f1;--ink:#172f42;--muted:#697b89;--accent:#7c78a8;--blue:#527f9f;--gold:#efc76b;--line:#d8dee2;--deep:#102536}*{box-sizing:border-box}body{margin:0;min-width:320px;background:var(--paper);color:var(--ink);font-family:Manrope,Arial,sans-serif}main{padding:28px clamp(24px,6vw,96px) 80px}.topbar,.section-label{display:flex;justify-content:space-between;align-items:center}.brand{color:var(--ink);font-size:12px;font-weight:800;text-decoration:none;text-transform:uppercase}.mark{display:inline-grid;place-items:center;width:28px;height:28px;margin-right:9px;border-radius:50%;color:var(--paper);background:var(--accent)}.edition,.eyebrow,.section-label,.thesis span,.captain span,.workers span,.route-table b,.skill-package>span,.rule span,.callout span,.sources{font:500 10px 'DM Mono',monospace;letter-spacing:.1em;text-transform:uppercase}.edition i{display:inline-block;width:6px;height:6px;margin:0 8px;border-radius:50%;background:var(--accent)}.hero{max-width:780px;padding:clamp(75px,12vh,145px) 0 85px}.eyebrow,.section-label,.thesis span{color:var(--accent)}h1{margin:16px 0 24px;font-size:clamp(56px,9vw,126px);line-height:.86;letter-spacing:-.08em}h1 em,h2 em{color:var(--blue);font-family:Georgia,serif;font-weight:400}.lede,.copy>p:last-child,.skills>div:first-child>p:last-child,.worktrees>div:first-child>p,.caption{max-width:570px;color:var(--muted);line-height:1.65}.thesis{display:grid;grid-template-columns:1fr 1fr;gap:30px;align-items:center;margin-bottom:110px;padding:28px;background:var(--gold)}.thesis div:first-child{display:grid;gap:16px}.thesis strong{font-size:clamp(24px,4vw,46px);line-height:1.05;letter-spacing:-.04em}.signal{display:flex;align-items:center;gap:10px}.signal i{width:28px;height:28px;border:1px solid var(--ink);background:var(--paper)}.signal i:nth-of-type(3){background:var(--blue)}.signal b{font:500 10px 'DM Mono',monospace}.fleet{margin-bottom:120px}.section-label{padding-bottom:14px;border-bottom:1px solid var(--line)}.section-label span:last-child{color:var(--muted)}.fleet-grid{display:grid;grid-template-columns:.8fr 50px 1.5fr;gap:24px;margin-top:30px;color:var(--paper);background:var(--deep)}.captain{display:grid;align-content:center;gap:16px;padding:32px}.captain span{color:var(--gold)}h2{margin:14px 0 20px;font-size:clamp(36px,5vw,65px);line-height:.98;letter-spacing:-.06em}.captain h2{font-size:clamp(24px,3vw,38px)}.captain code,.workers code{color:var(--gold);font:11px 'DM Mono',monospace}.arrow{display:grid;place-items:center;color:var(--gold);font-size:30px}.workers{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:#41596b}.workers article{display:grid;align-content:space-between;gap:20px;min-height:180px;padding:22px;background:var(--ink)}.workers span{color:#9eabb4}.workers strong{font-size:16px;line-height:1.2}.caption{margin:22px 0 0 auto}.workflow,.routing,.skills{display:grid;grid-template-columns:.7fr 1fr 1.3fr;gap:40px;align-items:start;margin-bottom:130px;padding-top:80px;border-top:1px solid var(--line)}.phase-tabs{display:grid;gap:8px}.phase-tabs button{display:grid;grid-template-columns:42px 1fr;gap:10px;padding:15px;border:1px solid var(--line);color:var(--ink);background:transparent;font:500 10px 'DM Mono',monospace;letter-spacing:.07em;text-align:left;cursor:pointer}.phase-tabs button b{color:var(--accent)}.phase-tabs button.active{color:var(--paper);border-color:var(--ink);background:var(--ink)}.phase-panel{min-height:260px;padding:30px;color:var(--paper);background:var(--accent)}.phase-meta{display:flex;justify-content:space-between;gap:15px;color:var(--gold);font:500 10px 'DM Mono',monospace}.phase-meta small{color:var(--paper);opacity:.7}.phase-panel h3{margin:44px 0 12px;font-size:clamp(24px,3vw,38px);line-height:1.05}.phase-panel p{line-height:1.6;opacity:.82}.phase-panel code{display:block;margin-top:26px;color:var(--gold);font:11px 'DM Mono',monospace}.handoff{margin-bottom:130px}.handoff table{width:100%;margin-top:30px;border-collapse:collapse;text-align:left}.handoff th,.handoff td{padding:17px 14px;border-bottom:1px solid var(--line)}.handoff thead{color:var(--paper);background:var(--ink);font:500 10px 'DM Mono',monospace;letter-spacing:.08em;text-transform:uppercase}.handoff tbody th{color:var(--blue);font:600 14px 'DM Mono',monospace}.handoff td{color:var(--muted);font-size:13px}.worktrees{display:grid;grid-template-columns:.8fr 1.2fr;gap:50px;align-items:center;margin-bottom:130px;padding:45px;color:var(--paper);background:var(--deep)}.worktrees .eyebrow{color:var(--gold)}.worktrees h2{color:var(--paper)}.worktrees h2 em{color:var(--gold)}.worktrees>div:first-child>p{color:#b0bac1}.worktrees pre{margin:32px 0 0;padding:20px;overflow:auto;color:var(--gold);background:var(--ink)}pre code{font:12px/1.75 'DM Mono',monospace}.map{position:relative;display:grid;grid-template-columns:1fr 1fr;gap:14px;padding-top:90px}.repo{position:absolute;top:0;left:50%;width:180px;padding:17px;transform:translateX(-50%);color:var(--ink);background:var(--gold)}.map>div:not(.repo){min-height:135px;padding:20px;border:1px solid #41596b;background:var(--ink)}.repo span,.map>div:not(.repo) span{display:block;margin-bottom:12px;color:var(--accent);font:500 9px 'DM Mono',monospace}.repo strong,.map>div:not(.repo) strong{display:block;font:14px 'DM Mono',monospace}.repo small,.map>div:not(.repo) small{display:block;margin-top:12px;color:#9eabb4;font-size:11px}.routing{grid-template-columns:.8fr 1.2fr}.route-table{border-top:1px solid var(--line);border-left:1px solid var(--line)}.route-table>div{display:grid;grid-template-columns:.8fr .9fr 1.4fr}.route-table .head{color:var(--paper);background:var(--ink);font:500 10px 'DM Mono',monospace;letter-spacing:.08em;text-transform:uppercase}.route-table>div>*{padding:15px;border-right:1px solid var(--line);border-bottom:1px solid var(--line)}.route-table strong{font-size:14px}.route-table b{color:var(--blue);letter-spacing:0;text-transform:none}.route-table small{color:var(--muted);font-size:12px}.skills{grid-template-columns:.8fr 1fr;margin-bottom:90px}.skill-package{display:grid;align-content:start;color:var(--paper);background:var(--blue)}.skill-package>span{padding:20px;color:var(--gold);border-bottom:1px solid #ffffff40}.skill-package>div{display:grid;grid-template-columns:1fr 1fr;gap:15px;padding:17px 20px;border-bottom:1px solid #ffffff40}.skill-package code{font:12px 'DM Mono',monospace}.skill-package small{opacity:.7}.skills>pre{grid-column:2;margin:0;padding:28px;overflow:auto;color:#d8dee2;background:var(--ink)}.rule{display:grid;grid-template-columns:150px 1fr;gap:30px;margin-top:55px;padding-top:22px;border-top:4px solid var(--gold)}.rule strong{max-width:850px;font-size:clamp(24px,3.3vw,42px);line-height:1.12}.callout{display:grid;grid-template-columns:150px 1fr;gap:30px;margin-top:70px;padding:27px;background:var(--gold)}.callout strong{max-width:850px;font-size:clamp(22px,3vw,36px);line-height:1.1}.sources{margin-top:90px;color:var(--muted)}.sources p{color:var(--muted);font:13px/1.6 Manrope,Arial,sans-serif;letter-spacing:0;text-transform:none}.sources a{color:var(--blue);font-weight:700}@media(max-width:800px){.thesis,.fleet-grid,.workflow,.worktrees,.routing,.skills{grid-template-columns:1fr}.arrow{transform:rotate(90deg);min-height:35px}.workers{grid-template-columns:1fr}.skills>pre{grid-column:auto}.route-table,.handoff{overflow-x:auto}.route-table>div{min-width:620px}.handoff table{min-width:650px}.rule,.callout{grid-template-columns:1fr}}@media(max-width:600px){.edition{display:none}.worktrees{padding:24px}.map{grid-template-columns:1fr;padding-top:90px}} main{max-width:1840px;margin-inline:auto}.reading-progress{position:fixed;inset:0 0 auto;z-index:20;height:3px;background:transparent}.reading-progress span{display:block;width:0;height:100%;background:var(--gold);transition:width .15s ease}.chapter-links{display:flex;gap:22px;margin-left:auto;margin-right:32px}.chapter-links a{color:var(--muted);font:500 10px 'DM Mono',monospace;letter-spacing:.08em;text-decoration:none;text-transform:uppercase}.chapter-links a:hover{color:var(--ink)}.hero{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:80px;align-items:end}.hero-index{display:grid;gap:14px;padding:20px 0;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}.hero-index span,.hero-index small{color:var(--muted);font:500 10px 'DM Mono',monospace;letter-spacing:.08em;text-transform:uppercase}.hero-index strong{font-size:clamp(27px,3vw,48px);line-height:.95;letter-spacing:-.06em}.hero-index em{color:var(--accent);font-family:Georgia,serif;font-weight:400}.hero-stats{display:grid;grid-template-columns:repeat(3,1fr) 1.6fr;gap:1px;margin:0 0 110px;background:var(--line);border-top:1px solid var(--line);border-left:1px solid var(--line)}.hero-stats div,.hero-stats p{min-height:110px;margin:0;padding:20px;border-right:1px solid var(--line);border-bottom:1px solid var(--line);background:var(--paper)}.hero-stats div{display:flex;align-items:center;gap:16px}.hero-stats strong{font:500 34px 'DM Mono',monospace;color:var(--blue)}.hero-stats span{color:var(--muted);font:500 10px/1.4 'DM Mono',monospace;letter-spacing:.06em;text-transform:uppercase}.hero-stats p{display:grid;place-items:center;color:var(--muted);font-size:13px;line-height:1.5;text-align:center}.failure-map{margin-bottom:130px;padding-top:80px;border-top:1px solid var(--line)}.failure-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;margin-top:30px;background:var(--line);border-left:1px solid var(--line)}.failure-grid article{min-height:220px;padding:24px;background:var(--paper);border-right:1px solid var(--line);border-bottom:1px solid var(--line)}.failure-grid span{color:var(--accent);font:500 11px 'DM Mono',monospace}.failure-grid strong{display:block;margin:52px 0 12px;font-size:22px}.failure-grid p{max-width:300px;margin:0;color:var(--muted);font-size:13px;line-height:1.6}.skill-principles{display:grid;gap:10px;margin-top:30px;color:var(--blue);font:500 10px 'DM Mono',monospace;letter-spacing:.06em;text-transform:uppercase}.skill-principles span{color:var(--blue)}@media(min-width:2200px){main{max-width:1960px}.hero{grid-template-columns:minmax(0,1fr) 380px}.hero h1{font-size:clamp(100px,7vw,160px)}body{font-size:18px}}@media(max-width:800px){.chapter-links{display:none}.hero{display:block}.hero-index{max-width:300px;margin-top:50px}.hero-stats{grid-template-columns:1fr 1fr;margin-bottom:80px}.hero-stats p{grid-column:1/-1}.failure-grid{grid-template-columns:1fr}.failure-grid article{min-height:0}.failure-grid strong{margin-top:30px}}