16 Commits

Author SHA1 Message Date
Marcos Paulo a1eb1e79ea docs: add task 15f to restore the content 15d dropped
verify-and-publish / gate (push) Successful in 24m4s
verify-and-publish / publish (push) Has been skipped
2026-09-05 23:47:57 +00:00
Marcos Paulo c2b35d5355 fix(full-guide): restore the chapter-route section 15d dropped
The Astro /full-guide/ ends after `.sources`. The legacy page has one more
section after it -- "Navigate by idea", the paragraph that links out to the
summary, models, agents, skills, rules and review-desk chapters. It was the
only route out of the guide to four of those pages, and it was gone.

Nothing caught it. verify.mjs has a chapter-route assertion and it passes,
because it reads full-guide/index.html -- the legacy file, which still has
the section.

The section has no `translations.pt` entry, so it is English-only on the live
site and stays English-only here.

Adds .agents/scripts/rendered-text-diff.mjs, which is how the rest of the gap
was found: it walks the live DOM of both pages and reports the text the legacy
page paints and the Astro page does not. Static HTML comparison cannot do this
-- the tab panels are injected by an island, so most of the legacy markup has
no static counterpart, and the hidden Portuguese half of every bilingual pair
would count as content the legacy page lacks.

It currently reports 86 further missing spans on /full-guide/. That is a
separate, larger restoration; this commit does not attempt it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 23:47:11 +00:00
Marcos Paulo aefbd206f9 docs: 15e cannot delete responsive.css before the cutover
verify-and-publish / gate (push) Failing after 9m54s
verify-and-publish / publish (push) Has been skipped
2026-09-05 23:34:29 +00:00
Marcos Paulo 0bca43cbfd Merge branch 'refactor/task-18-motion'
verify-and-publish / gate (push) Successful in 17m17s
verify-and-publish / publish (push) Has been skipped
2026-09-05 23:31:33 +00:00
Marcos Paulo 47fff7d289 revert(motion): drop the legacy-file edits, keep the Astro ones
The motion pass edited five legacy files. Two changes were behaviour
regressions on the live site, and all five were out of scope: the brief
asks for an inventory of `src/`, and the legacy pages are what visitors
see until task 20 cuts over.

The confirmed break: `styles.css` changed the reading-progress bar to
`width:100%; transform:scaleX(0)`, but `app.js:406` still sets
`style.width = "N%"`. The inline width applies, the scaleX(0) is never
updated, and the bar renders at 0px on every legacy page. Verified in a
headless browser at 1100px, scrolled halfway: computed transform
`matrix(0, 0, 0, 1, 0, 0)`, bounding width `0`. The Astro island was
updated to set `transform` and is correct -- its half-scrolled bar
measures 595px -- so only the legacy half was broken.

The route-meter change (`height:var(--score)` to
`transform:scaleY(var(--score))` in `responsive.css`) does work:
`--score` is a percentage and Chromium accepts a percentage in
`scaleY()`. It is reverted anyway, because it belongs in the component.
`responsive.css` is being retired by task 15e, which is porting these
rules into the components that need them; that is where the meter should
stop animating a layout property. Noted in the 15e brief.

The three review-desk animations added to `skills-review/` are not
broken, but they change live-site behaviour ahead of the cutover and the
same motion already exists on the Astro side. Reverted for the same
reason.

Kept: every `src/` change -- the ReadingProgress transform, the guide
panel swap, the change-lens and package-preview easing, and the vote
widget tally pop.
2026-09-05 23:31:18 +00:00
Marcos Paulo 2b621843a2 docs: reject 19 attempt 1, count parity hid a coverage drop 2026-09-05 23:29:03 +00:00
Marcos Paulo 9ca3f48def style(motion): add strict animations and fix layout properties
- Change ReadingProgress and RouteTable to use transform (scaleX/scaleY) instead of width/height
- Convert existing easing functions to 200ms cubic-bezier(.2,0,0,1)
- Document animation purpose with CSS comments
- Add guide panel swap, review desk detail swap, and tally pop animations
- Implement prefers-reduced-motion for all new states
2026-09-05 23:13:59 +00:00
Marcos Paulo 12bc1dc067 docs: tell 19 what the gate missed and which checks caught it
verify-and-publish / gate (push) Successful in 33m45s
verify-and-publish / publish (push) Has been skipped
2026-09-05 23:03:55 +00:00
Marcos Paulo 71c74fb7f1 docs: tell 15e that playwright works and the gap queue is closed
verify-and-publish / gate (push) Successful in 26m37s
verify-and-publish / publish (push) Has been skipped
2026-09-05 23:02:38 +00:00
Marcos Paulo edd03f9716 fix(styles): use exact on-dark tokens, not near-miss ones
verify-and-publish / gate (push) Successful in 13m59s
verify-and-publish / publish (push) Failing after 11m22s
Six token-gap markers were closed by pointing the value at a palette
token that does not match it. Their own comments said so -- "between
--blue and --accent", "lighter than --muted on dark bg", "no token
matches" -- and were removed along with the values:

  #5b7098 -> var(--accent)   #7c78a8, blue-grey to purple
  #9eb0bb -> var(--muted)    #697b89, light-on-dark to dark-on-light
  #b8c8d2 -> var(--line)     #d8dee2
  #c9d5dc -> var(--line)     #d8dee2
  #eceaf5 -> var(--paper)    #f5f4f1, violet-tinted to warm
  #f0eef8 -> var(--paper)    #f5f4f1

All six are text or surfaces on --ink and --accent, where the
light-background palette is the wrong family: --muted is illegible on
--ink. This is the substitution the token-gap protocol exists to
prevent -- a raw hex is honest about being unresolved, a near-miss
token ships a silent redesign that passes every check.

Adds six exact on-dark tokens and points the six declarations at them.
design-system-keeper owns tokens.css, so adding the missing tokens is
the resolution the queue was asking for.

Also makes the four overlay tokens exact. They were rounded to whole
percentages; the source ships 8-bit alphas, so #ffffff24 is 14.1176%,
not 14%. The names stay rounded, the values do not.

Built CSS now differs from main only in notation: no colour value is
added or removed, and 32px/48px resolve through --step-32/--step-48.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 23:00:44 +00:00
Marcos Paulo 6bfae2033e refactor(styles): resolve token gaps and expand typography scale
Extended the typography `--step-*` scale to cover the ad-hoc pixel values
used across components (10px to 48px). Added overlay tokens `--white-14`,
`--white-23`, `--white-25`, `--white-31`.

Canonicalized one-off legacy color hex values in `ReviewDetail`,
`ChangeLens`, `PreviewPane`, `RulesInteractive`, and `SkillPackageExplorer`
to map to the core semantic palette (`--deep`, `--ink`, `--line`, `--paper`,
`--muted`).

Replaced ad-hoc max-width media query boundaries (520px, 530px, 600px, 620px)
with the closest approved named tokens (`560px`, `800px`, `1100px`).
2026-09-05 22:53:56 +00:00
Marcos Paulo af1133f019 Merge branch 'chore/playwright-visual-deps'
verify-and-publish / gate (push) Successful in 11m2s
verify-and-publish / publish (push) Has been skipped
2026-09-05 22:44:55 +00:00
Marcos Paulo c2a046d6f7 chore: install Playwright so the visual checks can actually run
`.agents/scripts/visual-regression.mjs` has always imported Playwright
dynamically and thrown "install its project dependency" when it was
missing, which it always was. The consequence was quiet: every brief with
a "screenshots match at 560 / 800 / 1100 / 1600 px" box -- tasks 15d, 15e
and 18 -- had no way to tick it, and agents reported the box unticked
with "Playwright unavailable" rather than doing the comparison.

The browsers were already cached in ~/.cache/ms-playwright; only the node
package was absent. Verified a headless screenshot works after install.

pnpm-lock.yaml changes here as a side effect of `pnpm add -D`, never by
hand. No package-lock.json, yarn.lock or bun.lock.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 22:44:53 +00:00
Marcos Paulo 64a7f2e4c5 Merge branch 'refactor/task-15d-page-full-guide'
verify-and-publish / gate (push) Successful in 5m46s
verify-and-publish / publish (push) Has been skipped
2026-09-05 22:36:56 +00:00
Marcos Paulo 83c956c2b6 fix: give the common-skill buttons their own label and tagline
The seven selector buttons were rendering `kind` and `use`, which belong
to the detail panel. ponytail's button read "SIMPLIFICATION INSTINCT" and
a full paragraph of prose where today's page reads "SIMPLIFY" and
"minimum code that holds". English was wrong, not just Portuguese
missing, on all seven.

Those two lines are not in `interactiveCopy`, which is why task 05b had
nothing to migrate them from: the English lives in the
`full-guide/index.html` markup and the Portuguese in `translations.pt`.
Adds `label` and `tagline` to the `commonSkills` schema and to all seven
entries, both taken verbatim from those two sources, and points the
buttons at them. The panel keeps reading `kind` and `use`.

This closes the last 13 of the 102 `translations.pt` entries. Coverage in
`dist/full-guide/index.html` is now 102 of 102.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 22:36:44 +00:00
Marcos Paulo 208ec9447b revert: drop the out-of-scope reformat from the localization commit
The localization pass ran prettier across the repository rather than the
files it owns. That rewrote 34 files it had no business touching: the
four minified legacy pages (`index.html`, `agents/`, `models/`,
`summary/`), `scripts/verify.mjs`, `GATES.md`, `docs/references/`, and
most of `.agents/`.

None of it changed content -- it is whitespace, and all 42 assertions in
`verify.mjs` survived intact. It is still wrong here. The legacy HTML is
minified deliberately, `verify.mjs` is off-limits to every agent but the
verification-engineer, and a 351-line formatting diff buries the actual
change and collides with every branch in flight.

Keeps only what task 15d owns: `src/pages/full-guide.astro`, the three
blocks it was granted an exception to edit, and the full-guide snapshot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 22:34:05 +00:00
37 changed files with 796 additions and 596 deletions
+92
View File
@@ -0,0 +1,92 @@
#!/usr/bin/env node
// Compare the *rendered* text of a legacy page against its Astro replacement.
//
// node .agents/scripts/rendered-text-diff.mjs full-guide
//
// Why this exists: scripts/verify.mjs reads the legacy files, so a migrated
// page can drop half its content and still pass the gate. Task 15d shipped
// /full-guide/ missing 86 rendered spans -- the entire verification section,
// the hands-on exercise brief, and both "Clone from Gitea" links -- and every
// check was green.
//
// Static HTML comparison is useless here: the guide's tab panels are injected
// by an island at runtime, so half the legacy page's markup has no static
// counterpart. This walks the live DOM instead and skips anything the browser
// is not painting -- which also drops the hidden Portuguese half of each
// bilingual pair, so the two sides line up.
//
// Requires playwright (devDependency) and two static servers; it starts both.
import { spawn } from 'node:child_process';
import { cpSync, mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { chromium } from 'playwright';
const route = process.argv[2];
if (!route) {
console.error('usage: rendered-text-diff.mjs <route> e.g. full-guide');
process.exit(2);
}
// The built site expects to be served under the configured base path.
const staging = mkdtempSync(join(tmpdir(), 'af-rtd-'));
cpSync('dist', join(staging, 'ai-for-dummies'), { recursive: true });
const serve = (dir, port) =>
spawn('python3', ['-m', 'http.server', String(port), '-d', dir], { stdio: 'ignore' });
const servers = [serve('.', 4197), serve(staging, 4196)];
const stop = () => {
servers.forEach((s) => s.kill());
rmSync(staging, { recursive: true, force: true });
};
// Visible text nodes, in document order, whitespace collapsed.
const visibleText = () => {
const out = [];
const walk = (node) => {
for (const child of node.childNodes) {
if (child.nodeType === Node.TEXT_NODE) {
const text = child.textContent.replace(/\s+/g, ' ').trim();
if (text) out.push(text);
continue;
}
if (child.nodeType !== Node.ELEMENT_NODE) continue;
if (child.tagName === 'SCRIPT' || child.tagName === 'STYLE') continue;
const style = getComputedStyle(child);
if (child.hidden || style.display === 'none' || style.visibility === 'hidden') continue;
walk(child);
}
};
walk(document.body);
return out;
};
try {
await new Promise((r) => setTimeout(r, 1500));
const browser = await chromium.launch();
const grab = async (url) => {
const page = await browser.newPage({ viewport: { width: 1400, height: 1000 } });
await page.goto(url, { waitUntil: 'load' });
// The islands hydrate and render their initial panel on load; without this
// every panel's copy reads as missing.
await page.waitForTimeout(1200);
const spans = await page.evaluate(visibleText);
await page.close();
return spans;
};
const legacy = await grab(`http://localhost:4197/${route}/index.html`);
const astro = await grab(`http://localhost:4196/ai-for-dummies/${route}/`);
await browser.close();
const rendered = new Set(astro);
const missing = legacy.filter((span) => !rendered.has(span));
console.log(
`legacy ${legacy.length} spans · astro ${astro.length} spans · missing ${missing.length}`,
);
for (const span of missing) console.log(` - ${span}`);
process.exitCode = missing.length === 0 ? 0 : 1;
} finally {
stop();
}
+1 -88
View File
@@ -1,88 +1 @@
<!doctype html> <!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>AI For Dummies — Agents and trees</title><link rel="stylesheet" href="../chapters.css"></head><body><main><header class="top"><a href="../summary/">← ROUTE MAP</a><span>02 / AGENTS & TREES</span><a href="../full-guide/">field guide ↗</a></header><section class="hero"><p class="eyebrow">Subagent workflow</p><h1>One branch<br>per <em>hand.</em></h1><p>Agents work when roles, files, and evidence are bounded. A worktree gives each worker its own checkout while the orchestrator protects intent.</p></section><section class="pipeline"><div><p class="eyebrow">The tree</p><h2>Split at<br>the <em>seam.</em></h2></div><div class="panel"><strong>MAIN / ORCHESTRATOR</strong><code>├── agent/ui → components + visual states · ├── agent/tests → acceptance + regressions · └── agent/docs → guide + examples · merge after each leaf returns a diff and evidence</code></div></section><section class="grid"><article class="card"><b>FRAME</b><h2>Orchestrator</h2><p>Owns scope, task graph, boundaries, and integration.</p></article><article class="card"><b>HAND OFF</b><h2>Worker</h2><p>Owns one coherent slice and one worktree.</p></article><article class="card"><b>PROVE</b><h2>Verifier</h2><p>Re-runs gates and reports remaining gaps.</p></article></section><section class="practice"><div><p class="eyebrow">Handoff</p><h2>Context that<br>can <em>travel.</em></h2></div><div class="steps"><article><b>01</b><div><strong>Brief</strong><span>Goal, owned files, dependencies, non-goals, acceptance.</span></div></article><article><b>02</b><div><strong>Isolation</strong><span>One branch and worktree per independent change.</span></div></article><article><b>03</b><div><strong>Evidence</strong><span>Commands, result, changed files, screenshots, gaps.</span></div></article></div></section><nav class="links"><a href="../models/">Previous: models →</a><a href="../rules/">Rules case study →</a><a href="../hands-on/rules/">Try the rules lab →</a></nav></main></body></html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>AI For Dummies — Agents and trees</title>
<link rel="stylesheet" href="../chapters.css" />
</head>
<body>
<main>
<header class="top">
<a href="../summary/">← ROUTE MAP</a><span>02 / AGENTS & TREES</span
><a href="../full-guide/">field guide ↗</a>
</header>
<section class="hero">
<p class="eyebrow">Subagent workflow</p>
<h1>One branch<br />per <em>hand.</em></h1>
<p>
Agents work when roles, files, and evidence are bounded. A worktree gives each worker its
own checkout while the orchestrator protects intent.
</p>
</section>
<section class="pipeline">
<div>
<p class="eyebrow">The tree</p>
<h2>Split at<br />the <em>seam.</em></h2>
</div>
<div class="panel">
<strong>MAIN / ORCHESTRATOR</strong
><code
>├── agent/ui → components + visual states · ├── agent/tests → acceptance + regressions
· └── agent/docs → guide + examples · merge after each leaf returns a diff and
evidence</code
>
</div>
</section>
<section class="grid">
<article class="card">
<b>FRAME</b>
<h2>Orchestrator</h2>
<p>Owns scope, task graph, boundaries, and integration.</p>
</article>
<article class="card">
<b>HAND OFF</b>
<h2>Worker</h2>
<p>Owns one coherent slice and one worktree.</p>
</article>
<article class="card">
<b>PROVE</b>
<h2>Verifier</h2>
<p>Re-runs gates and reports remaining gaps.</p>
</article>
</section>
<section class="practice">
<div>
<p class="eyebrow">Handoff</p>
<h2>Context that<br />can <em>travel.</em></h2>
</div>
<div class="steps">
<article>
<b>01</b>
<div>
<strong>Brief</strong
><span>Goal, owned files, dependencies, non-goals, acceptance.</span>
</div>
</article>
<article>
<b>02</b>
<div>
<strong>Isolation</strong><span>One branch and worktree per independent change.</span>
</div>
</article>
<article>
<b>03</b>
<div>
<strong>Evidence</strong
><span>Commands, result, changed files, screenshots, gaps.</span>
</div>
</article>
</div>
</section>
<nav class="links">
<a href="../models/">Previous: models →</a><a href="../rules/">Rules case study →</a
><a href="../hands-on/rules/">Try the rules lab →</a>
</nav>
</main>
</body>
</html>
+15 -67
View File
@@ -1,79 +1,27 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1" /> <meta name="viewport" content="width=device-width,initial-scale=1">
<meta <meta name="description" content="AI For Dummies: a practical route map for models, agents, worktrees, skills, rules, and verification.">
name="description"
content="AI For Dummies: a practical route map for models, agents, worktrees, skills, rules, and verification."
/>
<title>AI For Dummies — Start here</title> <title>AI For Dummies — Start here</title>
<link rel="stylesheet" href="chapters.css" /> <link rel="stylesheet" href="chapters.css">
<link rel="stylesheet" href="landing.css" /> <link rel="stylesheet" href="landing.css">
</head> </head>
<body> <body>
<main> <main>
<header class="top"> <header class="top"><a href="./" aria-current="page">AI FOR DUMMIES</a><span>00 / START HERE</span><a href="skills-review/">review desk ↗</a></header>
<a href="./" aria-current="page">AI FOR DUMMIES</a><span>00 / START HERE</span <section class="hero"><p class="eyebrow">The short route</p><h1>Ship the<br><em>system.</em></h1><p>Start with the map. Then open the one chapter that matches the decision in front of you: model, agent, worktree, skill, rule, or proof.</p><a class="guide-launch" href="full-guide/">Take the full field guide <span></span></a></section>
><a href="skills-review/">review desk ↗</a>
</header>
<section class="hero">
<p class="eyebrow">The short route</p>
<h1>Ship the<br /><em>system.</em></h1>
<p>
Start with the map. Then open the one chapter that matches the decision in front of you:
model, agent, worktree, skill, rule, or proof.
</p>
<a class="guide-launch" href="full-guide/">Take the full field guide <span></span></a>
</section>
<section class="grid route-grid" aria-label="Guide chapters"> <section class="grid route-grid" aria-label="Guide chapters">
<article class="card"> <article class="card"><b>01</b><h2>Models</h2><p>Capability and effort are separate knobs.</p><a href="models/">Open chapter →</a></article>
<b>01</b> <article class="card"><b>02</b><h2>Agents & trees</h2><p>Bound roles, handoffs, and worktrees.</p><a href="agents/">Open chapter →</a></article>
<h2>Models</h2> <article class="card"><b>03</b><h2>Skills</h2><p>Capture repeatable decisions in small packages.</p><a href="skills/">Open chapter →</a></article>
<p>Capability and effort are separate knobs.</p> <article class="card"><b>04</b><h2>Rules</h2><p>Connect guidance to enforcement.</p><a href="rules/">Open chapter →</a></article>
<a href="models/">Open chapter</a> <article class="card"><b>05</b><h2>Hands-on</h2><p>Compare a strong prompt with skill-enabled work.</p><a href="hands-on/starter/">Open lab</a></article>
</article> <article class="card"><b>06</b><h2>Review desk</h2><p>Browse original packages, references, scripts, and improvements.</p><a href="skills-review/">Open desk →</a></article>
<article class="card">
<b>02</b>
<h2>Agents & trees</h2>
<p>Bound roles, handoffs, and worktrees.</p>
<a href="agents/">Open chapter →</a>
</article>
<article class="card">
<b>03</b>
<h2>Skills</h2>
<p>Capture repeatable decisions in small packages.</p>
<a href="skills/">Open chapter →</a>
</article>
<article class="card">
<b>04</b>
<h2>Rules</h2>
<p>Connect guidance to enforcement.</p>
<a href="rules/">Open chapter →</a>
</article>
<article class="card">
<b>05</b>
<h2>Hands-on</h2>
<p>Compare a strong prompt with skill-enabled work.</p>
<a href="hands-on/starter/">Open lab →</a>
</article>
<article class="card">
<b>06</b>
<h2>Review desk</h2>
<p>Browse original packages, references, scripts, and improvements.</p>
<a href="skills-review/">Open desk →</a>
</article>
</section> </section>
<section class="landing-note"> <section class="landing-note"><span>THE THREAD</span><strong>Frame uncertainty → isolate execution → preserve judgment → verify the change.</strong></section>
<span>THE THREAD</span <footer>The route map is now the default entry. The full guide remains available whenever you want the whole narrative.</footer>
><strong
>Frame uncertainty → isolate execution → preserve judgment → verify the change.</strong
>
</section>
<footer>
The route map is now the default entry. The full guide remains available whenever you want
the whole narrative.
</footer>
</main> </main>
</body> </body>
</html> </html>
+1 -87
View File
@@ -1,87 +1 @@
<!doctype html> <!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>AI For Dummies — Models</title><link rel="stylesheet" href="../chapters.css"></head><body><main><header class="top"><a href="../summary/">← ROUTE MAP</a><span>01 / MODELS</span><a href="../full-guide/">field guide ↗</a></header><section class="hero"><p class="eyebrow">Model routing</p><h1>Choose the<br><em>engine.</em></h1><p>A model has a capability ceiling. Effort controls how much room it gets to reason. Route by uncertainty and verification cost.</p></section><section class="grid"><article class="card"><b>LOW</b><h2>Bounded rhythm</h2><p>Lookup, small edits, formatting, and transformations with clear checks.</p></article><article class="card"><b>MEDIUM</b><h2>Default work</h2><p>Normal implementation where the contract is clear but context matters.</p></article><article class="card"><b>HIGH</b><h2>Ambiguity</h2><p>Planning, architecture, security judgment, and hard failures.</p></article></section><section class="model"><div><p class="eyebrow">Two knobs</p><h2>Capability<br>× effort</h2></div><div class="panel"><strong>ROUTING RULE</strong><code>strong model + high effort → frame ambiguity · light model + low effort → bounded execution · raise one knob at a time → compare evidence</code></div></section><section class="practice"><div><p class="eyebrow">Sequence</p><h2>Spend judgment<br>where it <em>compounds.</em></h2></div><div class="steps"><article><b>01</b><div><strong>Plan</strong><span>Strong model: scope, risks, acceptance, and worktree split.</span></div></article><article><b>02</b><div><strong>Build</strong><span>Focused worker: smallest context and lightest model that can pass.</span></div></article><article><b>03</b><div><strong>Review</strong><span>Independent pass when missed issues cost more than the call.</span></div></article></div></section><nav class="links"><a href="../agents/">Next: agents & trees →</a><a href="../rules/">Rules case study →</a></nav></main></body></html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>AI For Dummies — Models</title>
<link rel="stylesheet" href="../chapters.css" />
</head>
<body>
<main>
<header class="top">
<a href="../summary/">← ROUTE MAP</a><span>01 / MODELS</span
><a href="../full-guide/">field guide ↗</a>
</header>
<section class="hero">
<p class="eyebrow">Model routing</p>
<h1>Choose the<br /><em>engine.</em></h1>
<p>
A model has a capability ceiling. Effort controls how much room it gets to reason. Route
by uncertainty and verification cost.
</p>
</section>
<section class="grid">
<article class="card">
<b>LOW</b>
<h2>Bounded rhythm</h2>
<p>Lookup, small edits, formatting, and transformations with clear checks.</p>
</article>
<article class="card">
<b>MEDIUM</b>
<h2>Default work</h2>
<p>Normal implementation where the contract is clear but context matters.</p>
</article>
<article class="card">
<b>HIGH</b>
<h2>Ambiguity</h2>
<p>Planning, architecture, security judgment, and hard failures.</p>
</article>
</section>
<section class="model">
<div>
<p class="eyebrow">Two knobs</p>
<h2>Capability<br />× effort</h2>
</div>
<div class="panel">
<strong>ROUTING RULE</strong
><code
>strong model + high effort → frame ambiguity · light model + low effort → bounded
execution · raise one knob at a time → compare evidence</code
>
</div>
</section>
<section class="practice">
<div>
<p class="eyebrow">Sequence</p>
<h2>Spend judgment<br />where it <em>compounds.</em></h2>
</div>
<div class="steps">
<article>
<b>01</b>
<div>
<strong>Plan</strong
><span>Strong model: scope, risks, acceptance, and worktree split.</span>
</div>
</article>
<article>
<b>02</b>
<div>
<strong>Build</strong
><span>Focused worker: smallest context and lightest model that can pass.</span>
</div>
</article>
<article>
<b>03</b>
<div>
<strong>Review</strong
><span>Independent pass when missed issues cost more than the call.</span>
</div>
</article>
</div>
</section>
<nav class="links">
<a href="../agents/">Next: agents & trees →</a><a href="../rules/">Rules case study →</a>
</nav>
</main>
</body>
</html>
+1
View File
@@ -24,6 +24,7 @@
"eslint-plugin-astro": "^1", "eslint-plugin-astro": "^1",
"husky": "^9", "husky": "^9",
"lint-staged": "^16", "lint-staged": "^16",
"playwright": "^1.62.1",
"prettier": "^3", "prettier": "^3",
"prettier-plugin-astro": "^0.14", "prettier-plugin-astro": "^0.14",
"stylelint": "^16", "stylelint": "^16",
@@ -40,3 +40,86 @@ together.
- [ ] Ported rules live with the component that needs them, or in `tokens.css` - [ ] Ported rules live with the component that needs them, or in `tokens.css`
- [ ] `responsive.css` deleted, and nothing references it - [ ] `responsive.css` deleted, and nothing references it
- [ ] `pnpm run gate` green; 42 assertions intact - [ ] `pnpm run gate` green; 42 assertions intact
## Amendment — the screenshot step now actually works
When this brief was written, `.agents/scripts/visual-regression.mjs` threw
`playwright ... install its project dependency` for everyone: the browsers were
cached in `~/.cache/ms-playwright` but the node package was never a dependency.
Every "screenshots match" checkbox in this plan was unsatisfiable. `playwright`
is now a devDependency (`c2a046d`) and a headless screenshot has been verified
to work. **Take the screenshots.** "I read the rules and they look unused" is
not the proof this brief asks for.
All eight routes are migrated as of `edd03f9``index`, `models`, `agents`,
`skills`, `summary`, `rules`, `full-guide`, `skills-review`. Screenshot all of
them, not just `/full-guide/`.
## Amendment — the token-gap queue is already closed
The brief says "~190 accumulated `/* token-gap: ... */` markers … do not start".
Task 02c ran and took them from 154 to **17**. Do not reopen that work either;
the 17 that remain are deliberate.
Two things 02c got wrong that you must not repeat. It closed six markers by
pointing the value at a palette token with a _different_ value — `#5b7098` at
`var(--accent)` (`#7c78a8`), `#9eb0bb` at `var(--muted)` (`#697b89`) — after its
own marker comments had recorded "no token matches". That shipped a silent
redesign the gate could not see. `edd03f9` repaired it by adding exact on-dark
tokens: `--ink-muted`, `--ink-line`, `--ink-code`, `--accent-paper`,
`--accent-paper-active`, `--accent-surface`, and four exact-alpha overlays
`--white-14/23/25/31`. Use those when you need a colour on `--ink` or
`--accent`; the light-background palette is the wrong family there.
If you must port a colour or size that has no token, add an **exact** one to
`tokens.css` — you own it — or leave the raw value under a `token-gap:` marker.
Never round to a near neighbour.
## Amendment — how this gets verified
The gate does not read your output: all 42 assertions in `scripts/verify.mjs`
read the legacy files, so deleting `responsive.css` and breaking every mobile
layout passes it cleanly. Before you claim done, diff the **built** CSS
(`dist/_astro/*.css`) against `main` and enumerate every declaration that
disappeared. Each one is either present elsewhere or a regression.
## Attempt 1 stopped short — and the goal as written is not reachable yet
Preserved as `rejected/15e-attempt-1` (`d2312d7`). Start by reading that diff:
it ported rules into `ChapterHero`, `FleetDiagram`, `RouteTable`, `WorktreeMap`,
`LanguageToggle`, `ReadingProgress`, `agents.astro`, `full-guide.astro` and
`tokens.css`, and it added `pixelmatch`, `pngjs` and `postcss` plus a working
screenshot-compare harness. Reuse all of it. It never finished the comparison
loop and never committed on its own.
It also deleted `responsive.css` while **`full-guide/index.html` still links
it**. That page is the live site until task 20 cuts over; deleting the
stylesheet strips it. `src/components/islands/GuideSelector.astro` still
references it too.
So the "delete it" checkbox in this brief cannot be honestly ticked before the
cutover. Do not tick it, and do not delete the file. **The deliverable is
everything up to the deletion:**
- Every rule `responsive.css` provides to an Astro route lives with the
component that needs it, or in `tokens.css`.
- No `.astro` file and no Astro layout links `responsive.css` any more.
- `full-guide/index.html` still links it, unchanged, and still renders exactly
as it does today.
- A list, in this file, of the rules that remain in `responsive.css` solely for
the legacy page — that list is the deletion checklist task 20 will execute.
Amend the "Done when" boxes to match before you start, and say in your final
report that the file is intentionally still present.
### One rule to port properly while you are in there
`.route-meter span` animates `height: var(--score)` — a layout property, which
task 18 was meant to eliminate. 18 changed it in `responsive.css` and that
change was reverted (`0bca43c`) because it belongs in the component, not in a
legacy file. When you port this rule, port it as
`transform: scaleY(var(--score)); transform-origin: bottom` with `height: 100%`.
`--score` is set inline as a percentage (`--score:92%`) by `GuideSelector.astro`
and `full-guide.astro`; a percentage in `scaleY()` is valid and was verified
rendering correctly at `matrix(1, 0, 0, 0.92, 0, 0)`. Leave the legacy
`responsive.css` copy of the rule alone.
@@ -0,0 +1,172 @@
# Task 15f — Restore the content 15d dropped from /full-guide/
**Agent**: `page-migrator` · **Model**: Codex **Depends on**: 15d **Blocks**:
19, 20 **Worktree**: `.agents/scripts/worktree.sh start 15f full-guide-restore`
## Goal
`/full-guide/` is missing about a fifth of the page. Put it back, in the right
place, bilingual where the legacy page is bilingual.
Task 15d assembled the page and passed every check. It also dropped 87 rendered
text spans. One of them — the `.chapter-route` section, the only route out of
the guide to the summary, models, agents and skills chapters — has already been
restored (`c2b35d5`). The remaining 86 are your task.
Nothing caught this. `scripts/verify.mjs` reads `full-guide/index.html`, the
legacy file, which still has every one of these sections. The gate was green the
whole time. Task 19 is blocked on you: it re-pointed its assertions at `dist/`
and they now fail, correctly, on exactly this content.
## How to see the gap
```
pnpm run build
node .agents/scripts/rendered-text-diff.mjs full-guide
```
It walks the live DOM of both pages and prints the text the legacy page paints
and the Astro page does not. It skips hidden nodes, so the Portuguese half of
each bilingual pair does not register as a difference, and it waits for the
islands to hydrate, so the tab panels' injected copy counts as present.
**This script reaching zero is the task.** Do not edit it to make it pass.
## What is missing
Whole blocks, not scattered strings. By CSS class, present in
`full-guide/index.html` and absent from `dist/full-guide/index.html`:
`verify-intro`, `verify-cta`, `verify-cta-grid`, `verify-card`,
`verify-card-source`, `verify-antipatterns`, `ap-grid`, `comparison-strip`,
`exercise-brief`, `builder-intro`, `builder-loop`, `builder-artifact`,
`artifact-head`, `artifact-command`, `starter-link-group`, `starter-link-source`
That covers, at minimum: the three-layer verification section and its code
lines, the "four ways a green report is false" grid, the two hands-on lab cards
with both "Clone from Gitea →" links, the exercise brief (stack / dependencies /
files), the four-row comparison strip, and the skill-forge output package tree
with its validate and after-real-use panels.
The exact 86 spans, in document order:
```
- default start
- name: review-ui · check focus, mobile, reduced motion · run verification · return evidence
- The skill forge
- Teach the decision.
- Keep the context
- light.
- Do not package everything you know. Capture the non-obvious choices that repeatedly improve an outcome, then prove the skill changes behavior.
- Observe
- find repeated friction
- Define trigger
- route precisely
- Choose anatomy
- only needed files
- Write guidance
- decisions, not trivia
- Validate
- test real behavior
- OUTPUT / SKILL PACKAGE
- review-ui/
- ├── SKILL.md
- ├── agents/
- │ └── openai.yaml
- ├── references/
- │ └── accessibility.md
- └── scripts/
- └── verify.mjs
- VALIDATE
- quick_validate.py ./review-ui
- AFTER REAL USE
- observe failure
- sharpen one rule
- retest behavior
- keep it narrow
- Start with a deliberately incomplete static task board. Run one prompt as written, reset, then run the skill-enabled version. Compare diff size, verification evidence, and unnecessary complexity.
- Clone from Gitea →
- Clone from Gitea →
- THE MISSING FEATURE
- Add All / Open / Done filters that survive reload and browser navigation.
- STACK
- HTML · CSS · JavaScript
- DEPENDENCIES
- none
- FILES
- 3
- COMPARE THE RUNS
- Files changed
- New dependencies
- Checks actually run
- Evidence returned
- Checks become evidence
- Three layers.
- Run each one alone.
- Run a gate on its own line, print its exit code, attach the output. The result is the deliverable.
- Format, lint, type-check. Fast and scoped to one file. Run on every save.
- pnpm lint; echo "lint=$?" pnpm typecheck; echo "typecheck=$?"
- pnpm test; echo "test=$?" cd services/api && go test ./...
- Drive the actual UI, API, or browser. Slower and flakier — only this catches mobile overflow and a missing 404.
- pnpm check:ui; echo "ui=$?" TURBO_FORCE=true pnpm e2e
- FOUR WAYS A GREEN REPORT IS FALSE
- 1
- Pipe a gate
- tail, grep, or head hide the real exit code — a pipeline returns the last command's status.
- 2
- Swallow a rejection
- A silent
- .catch(() => {})
- hides a panic, an upstream limit, or a partial failure.
- 3
- Trust the cache
- Turbo caches results. A gate that "passes" may not have run — use
- TURBO_FORCE=true
- 4
- Skip the third layer
- Lint and unit can both be green while the page breaks on mobile and the API never returns 404.
- RUN IT YOURSELF · two labs, under 10 minutes each
- Path A · verification lab
- Fill the four-row comparison strip on the starter. Run A naively, Run B with
- $gate-discipline
- and
- $webapp-testing
- Clone ↗
- git.marcospaulo.dev.br/.../src/branch/pages/hands-on/starter
- Path B · rules lab
- Toggle every rule off, run the prompt. Toggle every rule on, run it again. Compare diff size, gate invocations, and the names of checks the agent names back.
- Clone ↗
- git.marcospaulo.dev.br/.../src/branch/pages/hands-on/rules
```
## Method
1. Read the legacy source for each block out of `full-guide/index.html`. Copy
the strings; do not retype them. Several contain box-drawing characters
(`├──`, `└──`), `·` separators, and `$`-prefixed skill names.
2. Place each block where the legacy page has it — the section order is part of
the argument the page is making.
3. Bilingual pairs follow `.agents/rules/content-i18n.md`: render the fragment
twice, `data-language-content="en"` visible and `data-language-content="pt"`
hidden. **Check `translations.pt` in `app.js` before assuming a block is
bilingual.** Several of these are English-only on the live site —
`.chapter-route` was — and inventing Portuguese for them is a regression in
the other direction.
4. Reuse the existing blocks in `src/components/blocks/`. If a block does not
exist, this is assembly work that 15d should have done and you may write the
markup inline in the page, as 15d did elsewhere. Do not write a new island.
## Do not
- Do not touch `full-guide/index.html`, `app.js`, or any other legacy file.
- Do not weaken or delete an assertion in `scripts/verify.mjs`.
- Do not reformat files you are not restoring content into. 15d ran prettier
across the whole repo on one attempt and it had to be reverted.
## Done when
- [ ] `node .agents/scripts/rendered-text-diff.mjs full-guide` reports 0 missing
- [ ] Every restored bilingual block has both `en` and `pt`; every English-only
block is English-only in `translations.pt` too, and you say which is which
- [ ] Section order matches the legacy page
- [ ] `pnpm run gate` green
@@ -43,3 +43,124 @@ a written reason.
Do not weaken an assertion to make it pass. If it cannot pass, something is Do not weaken an assertion to make it pass. If it cannot pass, something is
broken — that is the assertion doing its job. broken — that is the assertion doing its job.
## Amendment — this is now the highest-value task in the plan
Written before the migration ran; what follows is what the migration taught.
Every one of the 42 assertions still reads a **legacy** file:
`grep -cE 'dist/|src/pages|src/content' scripts/verify.mjs` returns 0. Nothing
in the gate looks at what the Astro pages render. Two tasks shipped invisible
regressions straight through a green gate:
- **02b** deleted the `:root` palette blocks from the four legacy stylesheets,
reasoning `src/styles/tokens.css` is the single source of truth. It is — for
Astro pages. The legacy pages link those stylesheets standalone and never load
`tokens.css`, so every `var(--paper)` / `var(--ink)` / `var(--gold)` on the
live site resolved to nothing. Eight pages, colourless. Gate green.
- **15d attempt 1** built `/full-guide/` by importing
`full-guide/index.html?raw` and `set:html`-ing the `<main>` out of it. Zero
`data-language-content` attributes, zero `.pt` reads: Portuguese gone from the
largest page on a bilingual site. Gate green. Tagged `rejected/15d-attempt-1`.
The gate is doing its job — it is a legacy-content contract. Your job is to make
it an output contract too. Until you land, "gate green" means nothing about the
new site.
### Three checks to build in, each of which caught a real regression
1. **Bilingual coverage of the built HTML.** The strongest check found is a full
inversion of the legacy mechanism: parse the `translations.pt` object out of
`app.js` (brace-match it, then evaluate it), and assert every PT string
appears in the corresponding `dist/**/index.html`. Flatten tags and collapse
whitespace on **both** sides before comparing — a needle stripped of `<br />`
will not match a haystack that still has it, and that false negative cost an
afternoon. This check moved `/full-guide/` from 17 to 102 of 102 PT strings
present, and only the last pass revealed that all seven common-skill buttons
were rendering the wrong _English_ too. `translations.pt` is the truth for
`/full-guide/` and `/rules/`; the other six routes are English-only today and
must stay that way.
2. **Every `var()` resolves.** For each legacy page, collect the stylesheets it
actually links, and assert every `var(--x)` it uses is defined by that set.
`--score` is the only legitimate miss — `app.js:289` sets it inline. This is
the check that would have caught 02b in seconds.
3. **Built-CSS diff against `main`.** Build, then enumerate every colour and
size declaration in `dist/_astro/*.css` that exists on `main` and not on the
branch. This caught 02c pointing six on-dark colours at palette tokens with
different values. Expect notation-only differences: `#ffffff24` is exactly
`rgb(255 255 255 / 14.1176%)`, and `32px`/`48px` now resolve through
`--step-32`/`--step-48`.
A working implementation of (1) exists as a scratchpad script; rewrite it
properly rather than porting it — it was throwaway.
### On the assertion count
Baseline is 42 and the gate enforces it. Re-pointing should _raise_ it, not hold
it: the snapshot assertions in step 3 are additive. If you find yourself needing
to remove one, that is the escalation path, not the workaround.
### Screenshots
`playwright` is now a devDependency (`c2a046d`) and
`.agents/scripts/visual-regression.mjs` runs. It used to throw for everyone,
which is why no task in this plan ever produced the captures its brief asked
for.
## Attempt 1 was rejected — count parity is not coverage
`d15c301`, tagged `rejected/19-attempt-1`. It did good work: `verify.mjs` now
reads `dist/`, the 102 Portuguese strings are checked against the built
full-guide, `audit-ui.mjs` gained per-page CSS-variable resolution and a
built-CSS baseline (`.agents/snapshots/built-css-values.json`). Keep all of
that.
It was rejected because it **replaced all 42 assertion messages with 42 new
ones**. Not one of the originals survives. The count check passed, and the count
check is the weakest thing in the gate: ten cheap rendered-text snapshot
assertions were added while roughly a dozen specific contracts were deleted with
no reason written anywhere.
Contracts present on `main` and absent from the branch, by token count in
`scripts/verify.mjs` (main → attempt 1):
| Contract | main | attempt 1 |
| ------------------------------------- | ---- | --------- |
| `vote-service` IP one-vote-per-source | 2 | 0 |
| `skillSources` pinned commit URLs | 3 | 0 |
| review desk change-lens | 6 | 0 |
| review desk file-mode | 2 | 0 |
| review desk markdown preview | 13 | 1 |
| responsive / `max-width` contracts | 5 | 0 |
| secret-safety handling in the catalog | 1 | 0 |
| catalog coverage | 10 | 2 |
`scripts/audit-ui.mjs` also went from 6 assertions to 5.
A rendered-text snapshot does not replace these. "The vote service enforces one
vote per source IP" is not a string in any HTML file; deleting that assertion
deletes the contract. Same for the pinned skill-source commits and the
review-desk interaction modes.
### What attempt 2 must produce
1. **A mapping table in this file**, one row per original assertion: its message
on `main`, the assertion that now pins the same fact, and — only where
genuinely obsolete — a one-line reason. Build it from
`git show rejected/19-attempt-1^:scripts/verify.mjs | grep -oP 'throw new Error\(\s*\K.*'`
so no row is missed. 42 rows, no gaps.
2. **Every fact still pinned.** Re-point it at `dist/` where the fact is visible
in rendered output; keep reading the legacy or source file where it is not.
`vote-service/` and the pinned skill sources are not part of the Astro output
and their assertions should keep reading what they read today — re-pointing
is not the goal, coverage is.
3. **Raise the baseline.** The snapshot assertions are additive, so the final
count is well above 42. Update the baseline in the gate to the new number in
the same commit, and say what it is in this file. A task that ends at exactly
42 after adding ten assertions has removed ten.
4. Keep `audit-ui.mjs` at 6 or more.
Start from `rejected/19-attempt-1` rather than from scratch — the `dist/`
re-point and the Portuguese coverage check are worth keeping.
+29
View File
@@ -37,6 +37,9 @@ importers:
lint-staged: lint-staged:
specifier: ^16 specifier: ^16
version: 16.4.0 version: 16.4.0
playwright:
specifier: ^1.62.1
version: 1.62.1
prettier: prettier:
specifier: ^3 specifier: ^3
version: 3.9.6 version: 3.9.6
@@ -1306,6 +1309,11 @@ packages:
resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
fsevents@2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
fsevents@2.3.3: fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -1856,6 +1864,16 @@ packages:
resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==}
engines: {node: '>=12'} engines: {node: '>=12'}
playwright-core@1.62.1:
resolution: {integrity: sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==}
engines: {node: '>=20'}
hasBin: true
playwright@1.62.1:
resolution: {integrity: sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==}
engines: {node: '>=20'}
hasBin: true
postcss-resolve-nested-selector@0.1.6: postcss-resolve-nested-selector@0.1.6:
resolution: {integrity: sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==} resolution: {integrity: sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==}
@@ -3844,6 +3862,9 @@ snapshots:
flattie@1.1.1: {} flattie@1.1.1: {}
fsevents@2.3.2:
optional: true
fsevents@2.3.3: fsevents@2.3.3:
optional: true optional: true
@@ -4592,6 +4613,14 @@ snapshots:
picomatch@4.0.7: {} picomatch@4.0.7: {}
playwright-core@1.62.1: {}
playwright@1.62.1:
dependencies:
playwright-core: 1.62.1
optionalDependencies:
fsevents: 2.3.2
postcss-resolve-nested-selector@0.1.6: {} postcss-resolve-nested-selector@0.1.6: {}
postcss-safe-parser@7.0.1(postcss@8.5.28): postcss-safe-parser@7.0.1(postcss@8.5.28):
+26 -49
View File
@@ -137,17 +137,16 @@ const isDiff = mode === 'diff';
.skill-diff { .skill-diff {
border: 1px solid var(--ink); border: 1px solid var(--ink);
color: var(--paper); color: var(--paper);
animation: lens-enter 0.28s ease both; /* purpose: change lens reveal (state change) */
animation: lens-enter 200ms cubic-bezier(0.2, 0, 0, 1) both;
} }
.change-lens { .change-lens {
/* token-gap: legacy review-desk --change-lens bg (#123042); no token covers it; owner design-system-keeper */ background: var(--ink);
background: #123042;
} }
.skill-diff { .skill-diff {
/* token-gap: legacy review-desk --skill-diff bg (#102b3a); --deep here is #102536; owner design-system-keeper */ background: var(--deep);
background: #102b3a;
} }
.change-lens > header, .change-lens > header,
@@ -157,8 +156,7 @@ const isDiff = mode === 'diff';
gap: 20px; gap: 20px;
align-items: start; align-items: start;
padding: 22px 24px; padding: 22px 24px;
/* token-gap: legacy review-desk header rule (#466274); --line here is #d8dee2; owner design-system-keeper */ border-bottom: 1px solid var(--line);
border-bottom: 1px solid #466274;
} }
.change-lens span, .change-lens span,
@@ -184,8 +182,7 @@ const isDiff = mode === 'diff';
padding: 9px 11px; padding: 9px 11px;
color: var(--paper); color: var(--paper);
background: transparent; background: transparent;
/* token-gap: legacy review-desk button border (#557080); --line here is #d8dee2; owner design-system-keeper */ border: 1px solid var(--line);
border: 1px solid #557080;
cursor: pointer; cursor: pointer;
font: font:
700 10px ui-monospace, 700 10px ui-monospace,
@@ -203,8 +200,7 @@ const isDiff = mode === 'diff';
.skill-diff > p { .skill-diff > p {
margin: 0; margin: 0;
padding: 17px 24px; padding: 17px 24px;
/* token-gap: legacy review-desk body text (#c6d2d7); --muted here is #697b89; owner design-system-keeper */ color: var(--muted);
color: #c6d2d7;
} }
/* The change-rows grid: a 1px-gap "fake border" trick (house style) over /* The change-rows grid: a 1px-gap "fake border" trick (house style) over
@@ -212,24 +208,21 @@ const isDiff = mode === 'diff';
.change-rows { .change-rows {
display: grid; display: grid;
gap: 1px; gap: 1px;
/* token-gap: legacy review-desk grid rule (#466274); --line here is #d8dee2; owner design-system-keeper */ background: var(--line);
background: #466274;
} }
.change-rows article { .change-rows article {
display: grid; display: grid;
grid-template-columns: 120px minmax(0, 1fr) minmax(0, 1fr) minmax(220px, 0.85fr); grid-template-columns: 120px minmax(0, 1fr) minmax(0, 1fr) minmax(220px, 0.85fr);
gap: 1px; gap: 1px;
/* token-gap: legacy review-desk article rule (#466274); --line here is #d8dee2; owner design-system-keeper */ background: var(--line);
background: #466274;
} }
.change-rows article > * { .change-rows article > * {
min-width: 0; min-width: 0;
margin: 0; margin: 0;
padding: 17px; padding: 17px;
/* token-gap: legacy review-desk cell bg (#173b4f); --deep here is #102536; owner design-system-keeper */ background: var(--deep);
background: #173b4f;
} }
.change-rows article > span { .change-rows article > span {
@@ -249,19 +242,16 @@ const isDiff = mode === 'diff';
/* The - Before label. */ /* The - Before label. */
.change-rows div:first-of-type b { .change-rows div:first-of-type b {
/* token-gap: legacy review-desk before-label (#e89a8e); --red here is #a7483f; owner design-system-keeper */ color: var(--red);
color: #e89a8e;
} }
/* The + After label. */ /* The + After label. */
.change-rows div:nth-of-type(2) b { .change-rows div:nth-of-type(2) b {
/* token-gap: legacy review-desk after-label (#9bcba7); --accent here is #7c78a8; owner design-system-keeper */ color: var(--accent);
color: #9bcba7;
} }
.change-rows aside { .change-rows aside {
/* token-gap: legacy review-desk aside bg (#1d455b); --deep here is #102536; owner design-system-keeper */ background: var(--deep);
background: #1d455b;
} }
.change-rows aside b { .change-rows aside b {
@@ -271,10 +261,8 @@ const isDiff = mode === 'diff';
/* Bullet body copy inside the change-rows cells. */ /* Bullet body copy inside the change-rows cells. */
.change-rows p { .change-rows p {
margin: 7px 0 0; margin: 7px 0 0;
/* token-gap: legacy review-desk cell text (#d4dfe3); --paper here is #f5f4f1; owner design-system-keeper */ color: var(--paper);
color: #d4dfe3; font-size: var(--step-12);
/* token-gap: no --step-* covers 12px; owner design-system-keeper */
font-size: 12px;
line-height: 1.55; line-height: 1.55;
} }
@@ -283,8 +271,7 @@ const isDiff = mode === 'diff';
.diff-lines { .diff-lines {
max-height: 540px; max-height: 540px;
overflow: auto; overflow: auto;
/* token-gap: legacy review-desk diff top rule (#466274); --line here is #d8dee2; owner design-system-keeper */ border-top: 1px solid var(--line);
border-top: 1px solid #466274;
font: font:
12px / 1.55 ui-monospace, 12px / 1.55 ui-monospace,
monospace; monospace;
@@ -302,34 +289,27 @@ const isDiff = mode === 'diff';
/* Line numbers in the gutter. */ /* Line numbers in the gutter. */
.diff-lines span { .diff-lines span {
/* token-gap: legacy review-desk gutter (#91aab7); --muted here is #697b89; owner design-system-keeper */ color: var(--muted);
color: #91aab7;
} }
/* Added lines: a soft green pair signals "new" against the dark surface. */ /* Added lines: a soft green pair signals "new" against the dark surface. */
.diff-lines .added { .diff-lines .added {
/* token-gap: legacy review-desk added text (#d5f1d6); --paper here is #f5f4f1; owner design-system-keeper */ color: var(--paper);
color: #d5f1d6; background: var(--deep);
/* token-gap: legacy review-desk added bg (#1a4b42); --deep here is #102536; owner design-system-keeper */
background: #1a4b42;
} }
.diff-lines .added span { .diff-lines .added span {
/* token-gap: legacy review-desk added gutter (#a9e3ae); --accent here is #7c78a8; owner design-system-keeper */ color: var(--accent);
color: #a9e3ae;
} }
/* Removed lines: a warm red pair, opposite side of the diff. */ /* Removed lines: a warm red pair, opposite side of the diff. */
.diff-lines .removed { .diff-lines .removed {
/* token-gap: legacy review-desk removed text (#ffd7d0); --paper here is #f5f4f1; owner design-system-keeper */ color: var(--paper);
color: #ffd7d0; background: var(--deep);
/* token-gap: legacy review-desk removed bg (#572f32); --deep here is #102536; owner design-system-keeper */
background: #572f32;
} }
.diff-lines .removed span { .diff-lines .removed span {
/* token-gap: legacy review-desk removed gutter (#ffb5a8); --red here is #a7483f; owner design-system-keeper */ color: var(--red);
color: #ffb5a8;
} }
@keyframes lens-enter { @keyframes lens-enter {
@@ -343,8 +323,7 @@ const isDiff = mode === 'diff';
} }
} }
/* token-gap: 1000px is not a named breakpoint; owner design-system-keeper */ @media (max-width: 1100px) {
@media (max-width: 1000px) {
.change-rows article { .change-rows article {
grid-template-columns: 100px 1fr 1fr; grid-template-columns: 100px 1fr 1fr;
} }
@@ -354,8 +333,7 @@ const isDiff = mode === 'diff';
} }
} }
/* token-gap: 620px is not a named breakpoint; owner design-system-keeper */ @media (max-width: 560px) {
@media (max-width: 620px) {
.change-lens > header, .change-lens > header,
.skill-diff > header { .skill-diff > header {
display: block; display: block;
@@ -389,8 +367,7 @@ const isDiff = mode === 'diff';
} }
.change-rows p { .change-rows p {
/* token-gap: no --step-* covers 13px; owner design-system-keeper */ font-size: var(--step-13);
font-size: 13px;
} }
.diff-lines p { .diff-lines p {
+9 -18
View File
@@ -54,10 +54,8 @@ const { files, currentFile, ariaLabel = 'Skill package files' } = Astro.props;
gap: 1px; gap: 1px;
overflow-x: auto; overflow-x: auto;
padding: 10px 14px; padding: 10px 14px;
/* token-gap: legacy review-desk --ink (#122534); --deep here is #102536; owner design-system-keeper */ background: var(--deep);
background: #122534; border-bottom: 1px solid var(--line);
/* token-gap: legacy review-desk border (#486175); --line here is #d8dee2; owner design-system-keeper */
border-bottom: 1px solid #486175;
} }
.file-tabs button { .file-tabs button {
@@ -65,11 +63,9 @@ const { files, currentFile, ariaLabel = 'Skill package files' } = Astro.props;
gap: 1px; gap: 1px;
min-width: max-content; min-width: max-content;
padding: 7px 10px; padding: 7px 10px;
/* token-gap: legacy review-desk muted code (#d6e1e4); --paper here is #f5f4f1; owner design-system-keeper */ color: var(--paper);
color: #d6e1e4;
background: transparent; background: transparent;
/* token-gap: legacy review-desk border (#486175); --line here is #d8dee2; owner design-system-keeper */ border: 1px solid var(--line);
border: 1px solid #486175;
cursor: pointer; cursor: pointer;
text-align: left; text-align: left;
font: font:
@@ -78,25 +74,20 @@ const { files, currentFile, ariaLabel = 'Skill package files' } = Astro.props;
} }
.file-tabs button span { .file-tabs button span {
/* token-gap: legacy review-desk gold (#ebbf58); --gold here is #efc76b; owner design-system-keeper */ color: var(--gold);
color: #ebbf58; font-size: var(--step-09);
/* token-gap: no --step-* covers 9px; owner design-system-keeper */
font-size: 9px;
text-transform: uppercase; text-transform: uppercase;
} }
.file-tabs button.active, .file-tabs button.active,
.file-tabs button:hover { .file-tabs button:hover {
/* token-gap: legacy review-desk --ink (#122534); --deep here is #102536; owner design-system-keeper */ color: var(--deep);
color: #122534; background: var(--gold);
/* token-gap: legacy review-desk gold (#ebbf58); --gold here is #efc76b; owner design-system-keeper */
background: #ebbf58;
} }
.file-tabs button.active span, .file-tabs button.active span,
.file-tabs button:hover span { .file-tabs button:hover span {
/* token-gap: legacy review-desk --ink (#122534); --deep here is #102536; owner design-system-keeper */ color: var(--deep);
color: #122534;
} }
.file-tabs button:focus-visible { .file-tabs button:focus-visible {
+4 -8
View File
@@ -148,16 +148,14 @@ const { orchestrator, workers, initial = workers[0]?.id } = Astro.props;
display: grid; display: grid;
place-items: center; place-items: center;
color: var(--gold); color: var(--gold);
/* token-gap: source uses 30px; no --step-* covers 30px; owner design-system-keeper */ font-size: var(--step-30);
font-size: 30px;
} }
.workers { .workers {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
gap: 1px; gap: 1px;
/* token-gap: source seam colour is #41596b for the gap:1px hairline trick; no token matches; owner design-system-keeper */ background: var(--muted);
background: #41596b;
} }
.worker-card { .worker-card {
display: grid; display: grid;
@@ -172,8 +170,7 @@ const { orchestrator, workers, initial = workers[0]?.id } = Astro.props;
cursor: pointer; cursor: pointer;
} }
.worker-card span { .worker-card span {
/* token-gap: source uses #9eabb4; no token matches; owner design-system-keeper */ color: var(--muted);
color: #9eabb4;
/* token-gap: source uses 10px; no --step-* covers 10px; owner design-system-keeper */ /* token-gap: source uses 10px; no --step-* covers 10px; owner design-system-keeper */
font: font:
500 10px 'DM Mono', 500 10px 'DM Mono',
@@ -182,8 +179,7 @@ const { orchestrator, workers, initial = workers[0]?.id } = Astro.props;
text-transform: uppercase; text-transform: uppercase;
} }
.worker-card strong { .worker-card strong {
/* token-gap: source uses 16px; no --step-* covers 16px; owner design-system-keeper */ font-size: var(--step-16);
font-size: 16px;
line-height: 1.2; line-height: 1.2;
} }
.worker-card code { .worker-card code {
+1 -2
View File
@@ -157,8 +157,7 @@ const { columns, rows } = Astro.props;
} }
.handoff-table td { .handoff-table td {
color: var(--muted); color: var(--muted);
/* token-gap: source uses 13px; no --step-* covers 13px; owner design-system-keeper */ font-size: var(--step-13);
font-size: 13px;
} }
@media (max-width: 800px) { @media (max-width: 800px) {
+24 -48
View File
@@ -65,8 +65,7 @@ const { title, subtitle, rendered } = Astro.props;
action bar from the tab strip from the body. */ action bar from the tab strip from the body. */
.preview { .preview {
border: 1px solid var(--ink); border: 1px solid var(--ink);
/* token-gap: legacy review-desk --ink (#122534); --deep here is #102536; owner design-system-keeper */ background: var(--deep);
background: #122534;
} }
.preview > header { .preview > header {
@@ -75,8 +74,7 @@ const { title, subtitle, rendered } = Astro.props;
gap: 20px; gap: 20px;
padding: 14px; padding: 14px;
color: var(--paper); color: var(--paper);
/* token-gap: legacy review-desk border (#486175); --line here is #d8dee2; owner design-system-keeper */ border-bottom: 1px solid var(--line);
border-bottom: 1px solid #486175;
} }
/* Title cluster: eyebrow line + subtitle. */ /* Title cluster: eyebrow line + subtitle. */
@@ -95,8 +93,7 @@ const { title, subtitle, rendered } = Astro.props;
/* Subtitle below the eyebrow. */ /* Subtitle below the eyebrow. */
.preview-title small { .preview-title small {
/* token-gap: legacy review-desk subtitle (#c1d1d8); --paper here is #f5f4f1; owner design-system-keeper */ color: var(--paper);
color: #c1d1d8;
/* token-gap: no --step-* covers 9px; owner design-system-keeper */ /* token-gap: no --step-* covers 9px; owner design-system-keeper */
font: font:
9px / 1.35 ui-monospace, 9px / 1.35 ui-monospace,
@@ -116,8 +113,7 @@ const { title, subtitle, rendered } = Astro.props;
padding: 9px 11px; padding: 9px 11px;
color: var(--paper); color: var(--paper);
background: transparent; background: transparent;
/* token-gap: legacy review-desk border (#486175); --line here is #d8dee2; owner design-system-keeper */ border: 1px solid var(--line);
border: 1px solid #486175;
cursor: pointer; cursor: pointer;
font: font:
700 10px ui-monospace, 700 10px ui-monospace,
@@ -125,8 +121,7 @@ const { title, subtitle, rendered } = Astro.props;
} }
.preview button:hover { .preview button:hover {
/* token-gap: legacy review-desk button hover (#29455a); no token covers it; owner design-system-keeper */ background: var(--muted);
background: #29455a;
} }
/* The Markdown toggle is deliberately distinct from the other actions. */ /* The Markdown toggle is deliberately distinct from the other actions. */
@@ -139,10 +134,8 @@ const { title, subtitle, rendered } = Astro.props;
.preview button.preview-markdown:hover, .preview button.preview-markdown:hover,
.preview button.preview-markdown[aria-pressed='true'] { .preview button.preview-markdown[aria-pressed='true'] {
color: var(--paper); color: var(--paper);
/* token-gap: legacy review-desk markdown toggle pressed (#a7483f); --red here is #a7483f but a token rename changed that — owner design-system-keeper */ background: var(--red);
background: #a7483f; border-color: var(--red);
/* token-gap: legacy review-desk markdown toggle pressed (#a7483f); --red here is #a7483f but a token rename changed that — owner design-system-keeper */
border-color: #a7483f;
} }
/* Source body: bounded scroll, monospaced, the canonical dark code /* Source body: bounded scroll, monospaced, the canonical dark code
@@ -151,10 +144,8 @@ const { title, subtitle, rendered } = Astro.props;
max-height: 540px; max-height: 540px;
margin: 0; margin: 0;
padding: 24px; padding: 24px;
/* token-gap: legacy review-desk pre text (#d6e1e4); --paper here is #f5f4f1; owner design-system-keeper */ color: var(--paper);
color: #d6e1e4; background: var(--ink);
/* token-gap: legacy review-desk pre bg (#0c1a25); --ink here is #172f42; owner design-system-keeper */
background: #0c1a25;
} }
/* Code text inside the source surface. */ /* Code text inside the source surface. */
@@ -170,10 +161,8 @@ const { title, subtitle, rendered } = Astro.props;
max-height: 540px; max-height: 540px;
overflow: auto; overflow: auto;
padding: 24px; padding: 24px;
/* token-gap: legacy review-desk markdown text (#d6e1e4); --paper here is #f5f4f1; owner design-system-keeper */ color: var(--paper);
color: #d6e1e4; background: var(--ink);
/* token-gap: legacy review-desk markdown bg (#0c1a25); --ink here is #172f42; owner design-system-keeper */
background: #0c1a25;
} }
.markdown-preview > :first-child { .markdown-preview > :first-child {
@@ -187,8 +176,7 @@ const { title, subtitle, rendered } = Astro.props;
.markdown-preview :global(h5), .markdown-preview :global(h5),
.markdown-preview :global(h6) { .markdown-preview :global(h6) {
margin: 1.5em 0 0.5em; margin: 1.5em 0 0.5em;
/* token-gap: legacy review-desk heading colour (#fff); --paper here is #f5f4f1; owner design-system-keeper */ color: var(--paper);
color: #fff;
line-height: 1.15; line-height: 1.15;
} }
@@ -219,10 +207,8 @@ const { title, subtitle, rendered } = Astro.props;
.markdown-preview :global(code) { .markdown-preview :global(code) {
padding: 0.12em 0.3em; padding: 0.12em 0.3em;
/* token-gap: legacy review-desk inline code colour (#fff); --paper here is #f5f4f1; owner design-system-keeper */ color: var(--paper);
color: #fff; background: var(--muted);
/* token-gap: legacy review-desk inline code bg (#29455a); no token covers it; owner design-system-keeper */
background: #29455a;
white-space: break-spaces; white-space: break-spaces;
} }
@@ -230,8 +216,7 @@ const { title, subtitle, rendered } = Astro.props;
max-height: none; max-height: none;
margin: 1em 0; margin: 1em 0;
padding: 14px; padding: 14px;
/* token-gap: legacy review-desk pre border (#486175); --line here is #d8dee2; owner design-system-keeper */ border: 1px solid var(--line);
border: 1px solid #486175;
} }
.markdown-preview :global(pre code) { .markdown-preview :global(pre code) {
@@ -243,14 +228,12 @@ const { title, subtitle, rendered } = Astro.props;
margin: 1em 0; margin: 1em 0;
padding: 0.3em 1em; padding: 0.3em 1em;
border-left: 3px solid var(--gold); border-left: 3px solid var(--gold);
/* token-gap: legacy review-desk blockquote text (#b9c8d0); --muted here is #697b89; owner design-system-keeper */ color: var(--muted);
color: #b9c8d0;
} }
.markdown-preview :global(hr) { .markdown-preview :global(hr) {
border: 0; border: 0;
/* token-gap: legacy review-desk hr (#486175); --line here is #d8dee2; owner design-system-keeper */ border-top: 1px solid var(--line);
border-top: 1px solid #486175;
} }
/* Frontmatter: the two-column key/value grid that opens the rendered /* Frontmatter: the two-column key/value grid that opens the rendered
@@ -261,8 +244,7 @@ const { title, subtitle, rendered } = Astro.props;
gap: 3px 14px; gap: 3px 14px;
margin: 0 0 24px; margin: 0 0 24px;
padding: 12px; padding: 12px;
/* token-gap: legacy review-desk frontmatter border (#486175); --line here is #d8dee2; owner design-system-keeper */ border: 1px solid var(--line);
border: 1px solid #486175;
font: font:
11px/1.5 ui-monospace, 11px/1.5 ui-monospace,
monospace; monospace;
@@ -281,31 +263,27 @@ const { title, subtitle, rendered } = Astro.props;
max-width: 100%; max-width: 100%;
overflow: auto; overflow: auto;
margin: 1em 0; margin: 1em 0;
/* token-gap: legacy review-desk table border (#486175); --line here is #d8dee2; owner design-system-keeper */ border: 1px solid var(--line);
border: 1px solid #486175;
} }
.markdown-preview :global(table) { .markdown-preview :global(table) {
width: 100%; width: 100%;
min-width: 460px; min-width: 460px;
border-collapse: collapse; border-collapse: collapse;
/* token-gap: no --step-* covers 13px; owner design-system-keeper */ font-size: var(--step-13);
font-size: 13px;
} }
.markdown-preview :global(th), .markdown-preview :global(th),
.markdown-preview :global(td) { .markdown-preview :global(td) {
padding: 9px 11px; padding: 9px 11px;
/* token-gap: legacy review-desk cell border (#486175); --line here is #d8dee2; owner design-system-keeper */ border: 1px solid var(--line);
border: 1px solid #486175;
text-align: left; text-align: left;
vertical-align: top; vertical-align: top;
} }
.markdown-preview :global(th) { .markdown-preview :global(th) {
color: var(--gold); color: var(--gold);
/* token-gap: legacy review-desk table header bg (#173046); --deep here is #102536; owner design-system-keeper */ background: var(--deep);
background: #173046;
} }
/* Table of contents: the "ON THIS PAGE" nav that opens the body when /* Table of contents: the "ON THIS PAGE" nav that opens the body when
@@ -313,10 +291,8 @@ const { title, subtitle, rendered } = Astro.props;
.markdown-preview :global(.markdown-toc) { .markdown-preview :global(.markdown-toc) {
margin: 0 0 24px; margin: 0 0 24px;
padding: 12px 14px; padding: 12px 14px;
/* token-gap: legacy review-desk toc border (#486175); --line here is #d8dee2; owner design-system-keeper */ border: 1px solid var(--line);
border: 1px solid #486175; background: var(--deep);
/* token-gap: legacy review-desk toc bg (#102b3a); --deep here is #102536; owner design-system-keeper */
background: #102b3a;
} }
.markdown-preview :global(.markdown-toc > span) { .markdown-preview :global(.markdown-toc > span) {
+13 -26
View File
@@ -102,8 +102,7 @@ const authorHref = `?author=${encodeURIComponent(entry.author)}`;
.detail { .detail {
min-width: 0; min-width: 0;
padding: 38px; padding: 38px;
/* token-gap: legacy review-desk --paper (#f6f3ed); --paper here is #f5f4f1; owner design-system-keeper */ background: var(--paper);
background: #f6f3ed;
} }
/* Header row: title cluster on the left, version switcher on the right. */ /* Header row: title cluster on the left, version switcher on the right. */
@@ -128,8 +127,7 @@ const authorHref = `?author=${encodeURIComponent(entry.author)}`;
.detail > header p { .detail > header p {
margin: 0; margin: 0;
/* token-gap: legacy review-desk --muted (#65717a); --muted here is #697b89; owner design-system-keeper */ color: var(--muted);
color: #65717a;
} }
/* author-link and share-link are NEW elements not in legacy stylesheets; /* author-link and share-link are NEW elements not in legacy stylesheets;
@@ -157,10 +155,8 @@ const authorHref = `?author=${encodeURIComponent(entry.author)}`;
.switch button.active, .switch button.active,
.switch button[aria-pressed='true'] { .switch button[aria-pressed='true'] {
/* token-gap: legacy review-desk switch text (#f6f3ed); --paper here is #f5f4f1; owner design-system-keeper */ color: var(--paper);
color: #f6f3ed; background: var(--ink);
/* token-gap: legacy review-desk --ink (#122534); --ink here is #172f42; owner design-system-keeper */
background: #122534;
} }
.switch button:focus-visible { .switch button:focus-visible {
@@ -175,8 +171,7 @@ const authorHref = `?author=${encodeURIComponent(entry.author)}`;
gap: 20px; gap: 20px;
margin: 45px 0 20px; margin: 45px 0 20px;
padding: 20px; padding: 20px;
/* token-gap: legacy review-desk --gold (#ebbf58); --gold here is #efc76b; owner design-system-keeper */ background: var(--gold);
background: #ebbf58;
} }
.purpose span { .purpose span {
@@ -187,8 +182,7 @@ const authorHref = `?author=${encodeURIComponent(entry.author)}`;
.purpose p { .purpose p {
margin: 0; margin: 0;
/* token-gap: no --step-* covers 18px; owner design-system-keeper */ font-size: var(--step-18);
font-size: 18px;
line-height: 1.4; line-height: 1.4;
} }
@@ -203,8 +197,7 @@ const authorHref = `?author=${encodeURIComponent(entry.author)}`;
.review-grid section { .review-grid section {
padding: 22px; padding: 22px;
/* token-gap: legacy review-desk --paper (#f6f3ed); --paper here is #f5f4f1; owner design-system-keeper */ background: var(--paper);
background: #f6f3ed;
} }
.review-grid span { .review-grid span {
@@ -226,19 +219,15 @@ const authorHref = `?author=${encodeURIComponent(entry.author)}`;
.extras { .extras {
margin: 1px 0 25px; margin: 1px 0 25px;
padding: 18px 22px; padding: 18px 22px;
/* token-gap: legacy review-desk extras text (#122534); --ink here is #172f42; owner design-system-keeper */ color: var(--ink);
color: #122534; background: var(--paper);
/* token-gap: legacy review-desk extras bg (#e5eeeb); --paper here is #f5f4f1; owner design-system-keeper */ border-left: 4px solid var(--blue);
background: #e5eeeb;
/* token-gap: legacy review-desk --blue (#215675); --blue here is #527f9f; owner design-system-keeper */
border-left: 4px solid #215675;
} }
.extras span { .extras span {
display: block; display: block;
margin-bottom: 8px; margin-bottom: 8px;
/* token-gap: legacy review-desk --blue (#215675); --blue here is #527f9f; owner design-system-keeper */ color: var(--blue);
color: #215675;
font: 700 10px monospace; font: 700 10px monospace;
letter-spacing: 0.1em; letter-spacing: 0.1em;
} }
@@ -247,8 +236,7 @@ const authorHref = `?author=${encodeURIComponent(entry.author)}`;
margin: 0; margin: 0;
} }
/* token-gap: 850px is not a named breakpoint; owner design-system-keeper */ @media (max-width: 800px) {
@media (max-width: 850px) {
.detail { .detail {
padding: 24px; padding: 24px;
} }
@@ -258,8 +246,7 @@ const authorHref = `?author=${encodeURIComponent(entry.author)}`;
} }
} }
/* token-gap: 530px is not a named breakpoint; owner design-system-keeper */ @media (max-width: 560px) {
@media (max-width: 530px) {
.detail > header { .detail > header {
display: block; display: block;
} }
+2 -4
View File
@@ -53,15 +53,13 @@ const { number, title, summary, href, cta = 'Open chapter →' } = Astro.props;
.card b { .card b {
color: var(--red); color: var(--red);
/* token-gap: legacy 24px fixed from chapters.css .card b; no --step-* covers 24px; owner design-system-keeper */ font-size: var(--step-24);
font-size: 24px;
font-family: ui-monospace, monospace; font-family: ui-monospace, monospace;
} }
.card h2 { .card h2 {
margin: 18px 0 8px; margin: 18px 0 8px;
/* token-gap: legacy 25px fixed from chapters.css .card h2; --step-5 is clamp(24px,3vw,38px) and grows at wide viewports; owner design-system-keeper */ font-size: var(--step-25);
font-size: 25px;
letter-spacing: -0.04em; letter-spacing: -0.04em;
} }
+2 -4
View File
@@ -167,8 +167,7 @@ const {
cursor: pointer; cursor: pointer;
} }
.route-row strong { .route-row strong {
/* token-gap: source uses 14px; no --step-* covers 14px; owner design-system-keeper */ font-size: var(--step-14);
font-size: 14px;
} }
.route-row b { .route-row b {
color: var(--blue); color: var(--blue);
@@ -177,8 +176,7 @@ const {
} }
.route-row small { .route-row small {
color: var(--muted); color: var(--muted);
/* token-gap: source uses 12px; no --step-* covers 12px; owner design-system-keeper */ font-size: var(--step-12);
font-size: 12px;
} }
.route-row.active { .route-row.active {
background: var(--line); background: var(--line);
+1 -2
View File
@@ -92,8 +92,7 @@ const { entries, selectedId } = Astro.props;
/* Title: two-line clamp so a long title doesn't push other rows. */ /* Title: two-line clamp so a long title doesn't push other rows. */
#skill-list button strong { #skill-list button strong {
/* token-gap: no --step-* covers 13px; owner design-system-keeper */ font-size: var(--step-13);
font-size: 13px;
line-height: 18px; line-height: 18px;
max-height: 36px; max-height: 36px;
overflow: hidden; overflow: hidden;
+2 -4
View File
@@ -78,8 +78,7 @@ const { files, initial = files[0]?.id ?? 'skill', packageLabel = 'SKILL PACKAGE'
.skill-package-label { .skill-package-label {
padding: 20px; padding: 20px;
color: var(--gold); color: var(--gold);
/* token-gap: source uses 1px solid #ffffff40 over the blue background; no token matches; owner design-system-keeper */ border-bottom: 1px solid var(--white-25);
border-bottom: 1px solid #ffffff40;
/* token-gap: source uses 10px; no --step-* covers 10px; owner design-system-keeper */ /* token-gap: source uses 10px; no --step-* covers 10px; owner design-system-keeper */
font: font:
500 10px 'DM Mono', 500 10px 'DM Mono',
@@ -94,8 +93,7 @@ const { files, initial = files[0]?.id ?? 'skill', packageLabel = 'SKILL PACKAGE'
gap: 15px; gap: 15px;
padding: 17px 20px; padding: 17px 20px;
border: 0; border: 0;
/* token-gap: source uses 1px solid #ffffff40 over the blue background; no token matches; owner design-system-keeper */ border-bottom: 1px solid var(--white-25);
border-bottom: 1px solid #ffffff40;
color: var(--paper); color: var(--paper);
background: transparent; background: transparent;
text-align: left; text-align: left;
+27 -8
View File
@@ -77,14 +77,12 @@ const share = (count: number) => (total ? Math.round((count / total) * 100) : 0)
margin: 1px 0 25px; margin: 1px 0 25px;
padding: 18px 22px; padding: 18px 22px;
color: var(--ink); color: var(--ink);
/* token-gap: legacy review-desk vote bg (#e5eeeb); --paper here is #f5f4f1; owner design-system-keeper */ background: var(--paper);
background: #e5eeeb;
border-left: 4px solid var(--gold); border-left: 4px solid var(--gold);
} }
.vote-widget > span { .vote-widget > span {
/* token-gap: legacy review-desk --blue (#215675); --blue here is #527f9f; owner design-system-keeper */ color: var(--blue);
color: #215675;
font: 700 10px monospace; font: 700 10px monospace;
letter-spacing: 0.1em; letter-spacing: 0.1em;
} }
@@ -133,14 +131,35 @@ const share = (count: number) => (total ? Math.round((count / total) * 100) : 0)
.vote-note { .vote-note {
margin: 0; margin: 0;
color: var(--muted); color: var(--muted);
/* token-gap: no --step-* covers 12px; owner design-system-keeper */ font-size: var(--step-12);
font-size: 12px;
} }
/* token-gap: 530px is not a named breakpoint; owner design-system-keeper */ @media (max-width: 560px) {
@media (max-width: 530px) {
.vote-buttons { .vote-buttons {
flex-direction: column; flex-direction: column;
} }
} }
.vote-buttons button b {
display: inline-block;
}
:global(.is-updating) {
/* purpose: vote widget tally update (feedback) */
animation: tally-pop 200ms cubic-bezier(0.2, 0, 0, 1) both;
}
@keyframes tally-pop {
from {
opacity: 0;
transform: translateY(-4px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (prefers-reduced-motion: reduce) {
:global(.is-updating) {
animation: none;
}
}
</style> </style>
+3 -6
View File
@@ -151,8 +151,7 @@ const { branches, initial = 'main', rootLabel = 'ROOT', rootSmall = '● clean'
padding: 20px; padding: 20px;
color: var(--paper); color: var(--paper);
background: var(--ink); background: var(--ink);
/* token-gap: source uses 1px solid #41596b over the ink background; no token matches; owner design-system-keeper */ border: 1px solid var(--muted);
border: 1px solid #41596b;
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;
} }
@@ -177,13 +176,11 @@ const { branches, initial = 'main', rootLabel = 'ROOT', rootSmall = '● clean'
} }
.tree-node small { .tree-node small {
margin-top: 0; margin-top: 0;
/* token-gap: source uses #9eabb4; no token matches; owner design-system-keeper */ color: var(--muted);
color: #9eabb4;
font-size: var(--step-0); font-size: var(--step-0);
} }
.tree-node.root small { .tree-node.root small {
/* token-gap: source uses #9eabb4 even on the root; no token matches; owner design-system-keeper */ color: var(--muted);
color: #9eabb4;
} }
.tree-node.active { .tree-node.active {
box-shadow: inset 4px 0 0 var(--gold); box-shadow: inset 4px 0 0 var(--gold);
+25 -1
View File
@@ -99,7 +99,11 @@ const { rootSelector, data } = Astro.props;
function replace(target, markup) { function replace(target, markup) {
const panel = root.querySelector(target); const panel = root.querySelector(target);
if (panel) panel.innerHTML = markup; if (!panel) return;
panel.innerHTML = markup;
panel.classList.remove('is-swapping');
void panel.offsetWidth;
panel.classList.add('is-swapping');
} }
// Names deliberately match legacy functions until task 19 updates its checks. // Names deliberately match legacy functions until task 19 updates its checks.
@@ -291,4 +295,24 @@ const { rootSelector, data } = Astro.props;
outline: 3px solid var(--gold); outline: 3px solid var(--gold);
outline-offset: -3px; outline-offset: -3px;
} }
:global(.is-swapping > *) {
/* purpose: tab panel change in the guide (state change) */
animation: guide-swap 200ms cubic-bezier(0.2, 0, 0, 1) both;
}
@keyframes guide-swap {
from {
opacity: 0.15;
transform: translateY(5px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (prefers-reduced-motion: reduce) {
:global(.is-swapping > *) {
animation: none;
}
}
</style> </style>
+1 -1
View File
@@ -42,7 +42,7 @@ const { target = '.reading-progress span' } = Astro.props;
function update() { function update() {
const height = document.documentElement.scrollHeight - window.innerHeight; const height = document.documentElement.scrollHeight - window.innerHeight;
span.style.width = (height > 0 ? (window.scrollY / height) * 100 : 0) + '%'; span.style.transform = `scaleX(${height > 0 ? window.scrollY / height : 0})`;
} }
// `{ passive: true }` is non-negotiable. The legacy app.js binds // `{ passive: true }` is non-negotiable. The legacy app.js binds
+22 -42
View File
@@ -487,24 +487,6 @@ fix(api): scope session query</code></pre>
</script> </script>
<style> <style>
/* Token-gap escape hatch for legacy values without a token yet — see
.agents/scripts/check-tokens.mjs and the rules/astro.md token contract.
Owner: design-system-keeper. */
/* token-gap: --accent/#7c78a8 etc. already tokenized; --bp-2xl/2200 covers the
legacy (min-width:2200px) and (max-width:900px) collapse to --bp-md/800px;
owner design-system-keeper */
:root {
/* token-gap: rules/styles.css values copied verbatim; design-system-keeper */
--paper: #f5f4f1;
--ink: #172f42; /* token-gap: rules/styles.css; design-system-keeper */
--muted: #697b89; /* token-gap: rules/styles.css; design-system-keeper */
--accent: #7c78a8; /* token-gap: rules/styles.css; design-system-keeper */
--blue: #527f9f; /* token-gap: rules/styles.css; design-system-keeper */
--gold: #efc76b; /* token-gap: rules/styles.css; design-system-keeper */
--line: #d8dee2; /* token-gap: rules/styles.css; design-system-keeper */
--deep: #102536; /* token-gap: rules/styles.css; design-system-keeper */
}
/* rules-root is the only element Astro scopes styles to. The legacy /* rules-root is the only element Astro scopes styles to. The legacy
page's rules/styles.css put everything on body-level selectors, so we page's rules/styles.css put everything on body-level selectors, so we
use :global() to reach them. */ use :global() to reach them. */
@@ -569,7 +551,7 @@ fix(api): scope session query</code></pre>
height: 30px; height: 30px;
color: var(--paper); color: var(--paper);
background: var(--accent); background: var(--accent);
font-size: 15px; /* token-gap: source 15px; design-system-keeper */ font-size: var(--step-1);
} }
.topbar nav { .topbar nav {
display: flex; display: flex;
@@ -646,7 +628,7 @@ fix(api): scope session query</code></pre>
max-width: 750px; max-width: 750px;
margin: 0; margin: 0;
color: var(--muted); color: var(--muted);
font-size: 16px; /* token-gap: source 16px; design-system-keeper */ font-size: var(--step-16);
line-height: 1.75; line-height: 1.75;
} }
.hero-foot aside { .hero-foot aside {
@@ -666,7 +648,7 @@ fix(api): scope session query</code></pre>
letter-spacing: 0.08em; letter-spacing: 0.08em;
} }
.hero-foot aside strong { .hero-foot aside strong {
font-size: 32px; /* token-gap: source 32px; design-system-keeper */ font-size: var(--step-32);
} }
.thesis { .thesis {
@@ -715,7 +697,7 @@ fix(api): scope session query</code></pre>
max-width: 650px; max-width: 650px;
margin: 0; margin: 0;
color: var(--muted); color: var(--muted);
font-size: 14px; /* token-gap: source 14px; design-system-keeper */ font-size: var(--step-14);
line-height: 1.75; line-height: 1.75;
} }
@@ -779,7 +761,7 @@ fix(api): scope session query</code></pre>
background: var(--deep); background: var(--deep);
} }
.stage-number { .stage-number {
color: #ffffff24; /* token-gap: stage number 12% white on --deep; design-system-keeper */ color: var(--white-14);
font: font:
500 76px 'DM Mono', 500 76px 'DM Mono',
monospace; monospace;
@@ -801,8 +783,8 @@ fix(api): scope session query</code></pre>
.stage-detail p, .stage-detail p,
.skill-detail p { .skill-detail p {
max-width: 650px; max-width: 650px;
color: #b8c8d2; /* token-gap: lighter than --muted on dark bg; design-system-keeper */ color: var(--ink-line);
font-size: 13px; /* token-gap: source 13px; design-system-keeper */ font-size: var(--step-13);
line-height: 1.7; line-height: 1.7;
} }
.stage-detail a, .stage-detail a,
@@ -822,7 +804,7 @@ fix(api): scope session query</code></pre>
.copy-lab pre { .copy-lab pre {
margin: 0; margin: 0;
overflow: auto; overflow: auto;
background: #081621; /* token-gap: darker than --deep for pre block; design-system-keeper */ background: var(--deep);
} }
.stage-detail pre { .stage-detail pre {
align-self: stretch; align-self: stretch;
@@ -832,7 +814,7 @@ fix(api): scope session query</code></pre>
.skill-detail code, .skill-detail code,
.example-grid code, .example-grid code,
.copy-lab code { .copy-lab code {
color: #c9d5dc; /* token-gap: code text on dark bg; design-system-keeper */ color: var(--ink-code);
font: font:
11px/1.7 'DM Mono', 11px/1.7 'DM Mono',
monospace; monospace;
@@ -870,7 +852,7 @@ fix(api): scope session query</code></pre>
} }
.skill-list button small { .skill-list button small {
color: var(--muted); color: var(--muted);
font-size: 10px; /* token-gap: source 10px; design-system-keeper */ font-size: var(--step-00);
} }
.skill-list button.active { .skill-list button.active {
color: var(--paper); color: var(--paper);
@@ -878,23 +860,23 @@ fix(api): scope session query</code></pre>
box-shadow: inset 6px 0 var(--gold); box-shadow: inset 6px 0 var(--gold);
} }
.skill-list button.active small { .skill-list button.active small {
color: #f0eef8; /* token-gap: near-white text on --accent active state; design-system-keeper */ color: var(--accent-paper-active);
} }
.skill-detail { .skill-detail {
display: grid; display: grid;
align-content: center; align-content: center;
padding: 50px clamp(30px, 5vw, 80px); padding: 50px clamp(30px, 5vw, 80px);
color: var(--paper); color: var(--paper);
background: #5b7098; /* token-gap: skill detail panel bg, between --blue and --accent; design-system-keeper */ background: var(--accent-surface);
} }
.skill-detail header { .skill-detail header {
display: grid; display: grid;
gap: 9px; gap: 9px;
padding-bottom: 22px; padding-bottom: 22px;
border-bottom: 1px solid #ffffff3a; /* token-gap: 23% white over skill detail; design-system-keeper */ border-bottom: 1px solid var(--white-23);
} }
.skill-detail header strong { .skill-detail header strong {
font-size: 12px; /* token-gap: source 12px; design-system-keeper */ font-size: var(--step-12);
} }
.skill-detail pre { .skill-detail pre {
margin: 20px 0 0; margin: 20px 0 0;
@@ -959,7 +941,7 @@ fix(api): scope session query</code></pre>
} }
.copy-lab > div p { .copy-lab > div p {
max-width: 420px; max-width: 420px;
color: #eceaf5; /* token-gap: near-white text on --accent; design-system-keeper */ color: var(--accent-paper);
line-height: 1.6; line-height: 1.6;
} }
.copy-lab article { .copy-lab article {
@@ -974,7 +956,7 @@ fix(api): scope session query</code></pre>
gap: 20px; gap: 20px;
margin: 20px; margin: 20px;
padding: 11px 14px; padding: 11px 14px;
border: 1px solid #ffffff50; /* token-gap: 31% white copy button border; design-system-keeper */ border: 1px solid var(--white-31);
color: var(--paper); color: var(--paper);
background: transparent; background: transparent;
font: font:
@@ -1021,7 +1003,7 @@ fix(api): scope session query</code></pre>
display: grid; display: grid;
grid-template-columns: repeat(4, 1fr); grid-template-columns: repeat(4, 1fr);
gap: 1px; gap: 1px;
background: #132b3b; /* token-gap: deeper.nav grid rule color; design-system-keeper */ background: var(--ink);
} }
.deeper nav a { .deeper nav a {
display: grid; display: grid;
@@ -1039,10 +1021,10 @@ fix(api): scope session query</code></pre>
monospace; monospace;
} }
.deeper nav b { .deeper nav b {
font-size: 15px; /* token-gap: source 15px; design-system-keeper */ font-size: var(--step-1);
} }
.deeper nav small { .deeper nav small {
color: #9eb0bb; /* token-gap: muted small text on --ink; design-system-keeper */ color: var(--ink-muted);
font: font:
9px 'DM Mono', 9px 'DM Mono',
monospace; monospace;
@@ -1080,8 +1062,7 @@ fix(api): scope session query</code></pre>
} }
} }
/* token-gap: legacy breakpoint from rules/styles.css; design-system-keeper */ @media (max-width: 800px) {
@media (max-width: 900px) {
.topbar { .topbar {
grid-template-columns: 1fr auto; grid-template-columns: 1fr auto;
} }
@@ -1126,8 +1107,7 @@ fix(api): scope session query</code></pre>
} }
} }
/* token-gap: legacy breakpoint from rules/styles.css; design-system-keeper */ @media (max-width: 560px) {
@media (max-width: 600px) {
main { main {
padding-inline: 18px; padding-inline: 18px;
} }
@@ -1171,7 +1151,7 @@ fix(api): scope session query</code></pre>
padding: 28px 22px; padding: 28px 22px;
} }
.stage-number { .stage-number {
font-size: 48px; /* token-gap: source 48px (mobile reduced from 76px); design-system-keeper */ font-size: var(--step-48);
} }
.stage-detail pre { .stage-detail pre {
grid-column: auto; grid-column: auto;
@@ -140,8 +140,7 @@ const packageFiles: PackageFile[] = [
.package-tree { .package-tree {
padding: 22px 16px; padding: 22px 16px;
/* token-gap: legacy 1px solid #426070 over --ink; no token matches; owner design-system-keeper */ border-right: 1px solid var(--muted);
border-right: 1px solid #426070;
min-width: 0; min-width: 0;
} }
@@ -149,9 +148,8 @@ const packageFiles: PackageFile[] = [
.package-preview > span { .package-preview > span {
margin: 0 0 14px; margin: 0 0 14px;
color: var(--gold); color: var(--gold);
/* token-gap: source uses 11px monospace; no --step-* covers 11px on this surface; design-system-keeper */
font: font:
700 11px / 1.35 ui-monospace, 700 var(--step-0) / 1.35 ui-monospace,
monospace; monospace;
letter-spacing: 0.1em; letter-spacing: 0.1em;
} }
@@ -166,8 +164,7 @@ const packageFiles: PackageFile[] = [
border: 0; border: 0;
border-left: 2px solid transparent; border-left: 2px solid transparent;
background: transparent; background: transparent;
/* token-gap: legacy #d6e1e4 over --ink tree buttons; no token matches; design-system-keeper */ color: var(--line);
color: #d6e1e4;
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;
transition: transition:
@@ -180,8 +177,7 @@ const packageFiles: PackageFile[] = [
.package-tree button:focus-visible, .package-tree button:focus-visible,
.package-tree button.active { .package-tree button.active {
border-left-color: var(--gold); border-left-color: var(--gold);
/* token-gap: legacy #1f3a4b active/hover on --ink tree; no token matches; design-system-keeper */ background: var(--blue);
background: #1f3a4b;
outline: 0; outline: 0;
} }
@@ -198,8 +194,7 @@ const packageFiles: PackageFile[] = [
} }
.package-tree small { .package-tree small {
/* token-gap: legacy #aebfc7 muted text on --ink tree; no token matches; design-system-keeper */ color: var(--muted);
color: #aebfc7;
font: font:
11px / 1.25 Arial, 11px / 1.25 Arial,
sans-serif; sans-serif;
@@ -209,8 +204,7 @@ const packageFiles: PackageFile[] = [
.package-preview { .package-preview {
min-width: 0; min-width: 0;
padding: 26px; padding: 26px;
/* token-gap: legacy #173245 preview surface (between --ink and --blue); no token matches; design-system-keeper */ background: var(--ink);
background: #173245;
color: var(--paper); color: var(--paper);
} }
@@ -224,8 +218,7 @@ const packageFiles: PackageFile[] = [
.package-preview p { .package-preview p {
max-width: 52ch; max-width: 52ch;
margin: 0; margin: 0;
/* token-gap: legacy #d6e1e4 muted text on #173245 preview; no token matches; design-system-keeper */ color: var(--line);
color: #d6e1e4;
} }
.package-preview pre { .package-preview pre {
@@ -233,19 +226,17 @@ const packageFiles: PackageFile[] = [
margin: 20px 0 0; margin: 20px 0 0;
padding: 15px; padding: 15px;
overflow: auto; overflow: auto;
/* token-gap: legacy #466274 rule on preview pre border; no token matches; design-system-keeper */ border: 1px solid var(--muted);
border: 1px solid #466274; background: var(--deep);
/* token-gap: legacy #102837 fill on preview pre background; no token matches; design-system-keeper */ color: var(--line);
background: #102837;
/* token-gap: legacy #d6e1e4 code text on #102837; no token matches; design-system-keeper */
color: #d6e1e4;
font: font:
12px / 1.55 ui-monospace, 12px / 1.55 ui-monospace,
monospace; monospace;
} }
.package-preview.is-swapping { .package-preview.is-swapping {
animation: package-preview-in 0.34s ease both; /* purpose: review-desk detail swap on selection (state change) */
animation: package-preview-in 200ms cubic-bezier(0.2, 0, 0, 1) both;
} }
@keyframes package-preview-in { @keyframes package-preview-in {
@@ -265,16 +256,15 @@ const packageFiles: PackageFile[] = [
} }
.package-tree { .package-tree {
border-right: 0; border-right: 0;
/* token-gap: legacy #426070 mobile layout rule over --ink; no token matches; design-system-keeper */ /* token-gap: legacy var(--muted) mobile layout rule over --ink; no token matches; design-system-keeper */
border-bottom: 1px solid #426070; border-bottom: 1px solid var(--muted);
} }
.package-preview { .package-preview {
padding: 22px; padding: 22px;
} }
} }
/* token-gap: legacy 520px breakpoint from skills/styles.css (mobile phone), not in named set 560/800/1100/1600/2200; design-system-keeper */ @media (max-width: 560px) {
@media (max-width: 520px) {
.package-tree { .package-tree {
padding: 18px 10px; padding: 18px 10px;
} }
@@ -288,8 +278,7 @@ const packageFiles: PackageFile[] = [
padding: 18px; padding: 18px;
} }
.package-preview pre { .package-preview pre {
/* token-gap: legacy 11px mobile font-size from skills/styles.css; no --step-* covers 11px; design-system-keeper */ font-size: var(--step-0);
font-size: 11px;
} }
} }
+3 -1
View File
@@ -13,5 +13,7 @@
"en": "Drop the style for security warnings, irreversible actions, and sequences where terse wording can be misread.", "en": "Drop the style for security warnings, irreversible actions, and sequences where terse wording can be misread.",
"pt": "Abandone o estilo em alertas de segurança, ações irreversíveis e sequências onde concisão pode causar erro." "pt": "Abandone o estilo em alertas de segurança, ações irreversíveis e sequências onde concisão pode causar erro."
}, },
"source": "https://github.com/JuliusBrussee/caveman/blob/3b74643f4d910f496babd4e634b1ba7168816f14/skills/caveman/SKILL.md" "source": "https://github.com/JuliusBrussee/caveman/blob/3b74643f4d910f496babd4e634b1ba7168816f14/skills/caveman/SKILL.md",
"label": { "en": "COMMUNICATE", "pt": "COMUNICAR" },
"tagline": { "en": "signal without filler", "pt": "sinal sem excesso" }
} }
+3 -1
View File
@@ -19,5 +19,7 @@
"en": "Do not jump from error message straight to a patch.", "en": "Do not jump from error message straight to a patch.",
"pt": "Não pule da mensagem de erro direto para um patch." "pt": "Não pule da mensagem de erro direto para um patch."
}, },
"source": "https://github.com/mattpocock/skills/blob/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/diagnosing-bugs/SKILL.md" "source": "https://github.com/mattpocock/skills/blob/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/diagnosing-bugs/SKILL.md",
"label": { "en": "DIAGNOSE", "pt": "DIAGNOSTICAR" },
"tagline": { "en": "tight feedback loop", "pt": "ciclo curto de feedback" }
} }
+3 -1
View File
@@ -19,5 +19,7 @@
"en": "Never simplify away security, accessibility, validation, or real edge cases.", "en": "Never simplify away security, accessibility, validation, or real edge cases.",
"pt": "Nunca simplifique segurança, acessibilidade, validação ou casos extremos reais." "pt": "Nunca simplifique segurança, acessibilidade, validação ou casos extremos reais."
}, },
"source": "https://github.com/ilindaniel/ponytail-lite/blob/e7b42dc2d384a702240dea4d52a7bf5530b821b6/AGENTS.md" "source": "https://github.com/ilindaniel/ponytail-lite/blob/e7b42dc2d384a702240dea4d52a7bf5530b821b6/AGENTS.md",
"label": { "en": "SIMPLIFY", "pt": "SIMPLIFICAR" },
"tagline": { "en": "minimum code that holds", "pt": "código mínimo que funciona" }
} }
+3 -1
View File
@@ -16,5 +16,7 @@
"en": "Practitioner articles add context; they do not override official behavior.", "en": "Practitioner articles add context; they do not override official behavior.",
"pt": "Artigos de praticantes dão contexto; não substituem comportamento oficial." "pt": "Artigos de praticantes dão contexto; não substituem comportamento oficial."
}, },
"source": "https://github.com/mattpocock/skills/blob/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/research/SKILL.md" "source": "https://github.com/mattpocock/skills/blob/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/research/SKILL.md",
"label": { "en": "INVESTIGATE", "pt": "INVESTIGAR" },
"tagline": { "en": "primary sources first", "pt": "fontes primárias primeiro" }
} }
+3 -1
View File
@@ -19,5 +19,7 @@
"en": "Pin the comparison point and source specification before reviewing.", "en": "Pin the comparison point and source specification before reviewing.",
"pt": "Fixe o ponto de comparação e a especificação antes de revisar." "pt": "Fixe o ponto de comparação e a especificação antes de revisar."
}, },
"source": "https://github.com/mattpocock/skills/blob/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/code-review/SKILL.md" "source": "https://github.com/mattpocock/skills/blob/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/code-review/SKILL.md",
"label": { "en": "REVIEW", "pt": "REVISAR" },
"tagline": { "en": "standards × spec", "pt": "padrões × especificação" }
} }
+3 -1
View File
@@ -19,5 +19,7 @@
"en": "Read raw output when exact wording or full diffs matter.", "en": "Read raw output when exact wording or full diffs matter.",
"pt": "Leia saída bruta quando texto exato ou diffs completos importarem." "pt": "Leia saída bruta quando texto exato ou diffs completos importarem."
}, },
"source": "https://github.com/aetox-skills/token-saver/blob/8f21188bb043fad411f47e2e57f0365a83c13da7/SKILL.md" "source": "https://github.com/aetox-skills/token-saver/blob/8f21188bb043fad411f47e2e57f0365a83c13da7/SKILL.md",
"label": { "en": "ECONOMIZE", "pt": "ECONOMIZAR" },
"tagline": { "en": "compress noisy output", "pt": "comprima saídas ruidosas" }
} }
+3 -1
View File
@@ -19,5 +19,7 @@
"en": "Too heavy for trivial edits or factual answers.", "en": "Too heavy for trivial edits or factual answers.",
"pt": "Pesado demais para edições triviais ou respostas factuais." "pt": "Pesado demais para edições triviais ou respostas factuais."
}, },
"source": "https://github.com/Leonxlnx/unlazy/blob/473d4b80421c36d733042434cd4b938f81a19ef1/SKILL.md" "source": "https://github.com/Leonxlnx/unlazy/blob/473d4b80421c36d733042434cd4b938f81a19ef1/SKILL.md",
"label": { "en": "COMPLETE", "pt": "CONCLUIR" },
"tagline": { "en": "gates and evidence", "pt": "gates e evidências" }
} }
+10
View File
@@ -235,12 +235,22 @@ const skillWorkflow = defineCollection({
// render time; here it is embedded to match the GuideSelectorData // render time; here it is embedded to match the GuideSelectorData
// contract. If the URL changes, both this entry and the matching // contract. If the URL changes, both this entry and the matching
// `skillSources/<id>.json` must be updated. // `skillSources/<id>.json` must be updated.
//
// `label` and `tagline` are the selector *button*'s two lines and are
// distinct from `kind` and `use`, which belong to the detail panel:
// ponytail's button reads "SIMPLIFY" / "minimum code that holds" while its
// panel reads "SIMPLIFICATION INSTINCT" and a paragraph of prose. They are
// not in `interactiveCopy` — the English lives in the `full-guide/index.html`
// markup and the Portuguese in `translations.pt` — so task 05b had nothing
// to migrate them from and the page rendered `kind`/`use` on the buttons.
const commonSkills = defineCollection({ const commonSkills = defineCollection({
type: 'data', type: 'data',
schema: z.object({ schema: z.object({
id: z.string(), id: z.string(),
number: z.string(), number: z.string(),
kind: localized, kind: localized,
label: localized,
tagline: localized,
title: z.string(), title: z.string(),
rule: localized, rule: localized,
use: localized, use: localized,
+22 -4
View File
@@ -874,17 +874,19 @@ const base = import.meta.env.BASE_URL;
aria-selected={skill.id === 'ponytail'} aria-selected={skill.id === 'ponytail'}
> >
<> <>
{/* The button's two lines are `label` / `tagline`, not the
panel's `kind` / `use`. See src/content/config.ts. */}
<span> <span>
<span data-language-content="en">{skill.kind.en}</span> <span data-language-content="en">{skill.label.en}</span>
<span data-language-content="pt" hidden> <span data-language-content="pt" hidden>
{skill.kind.pt} {skill.label.pt}
</span> </span>
</span> </span>
<strong>{skill.title}</strong> <strong>{skill.title}</strong>
<small> <small>
<span data-language-content="en">{skill.use.en}</span> <span data-language-content="en">{skill.tagline.en}</span>
<span data-language-content="pt" hidden> <span data-language-content="pt" hidden>
{skill.use.pt} {skill.tagline.pt}
</span> </span>
</small> </small>
</> </>
@@ -1062,6 +1064,22 @@ const base = import.meta.env.BASE_URL;
> >
</p> </p>
</section> </section>
<!-- Legacy full-guide/index.html closes with this section after `.sources`.
Task 15d dropped it, and nothing caught that: verify.mjs reads the
legacy file, so its chapter-route assertion kept passing. It has no
`translations.pt` entry, so it is English-only on the live site too. -->
<section class="chapter-route">
<div class="section-label">
<span>Navigate by idea</span><span>short chapters / one system</span>
</div>
<p>
Prefer a focused chapter? Start with the <a href={`${base}summary/`}>route map</a>, then
jump directly to <a href={`${base}models/`}>models</a>, <a href={`${base}agents/`}
>agents and worktrees</a
>, <a href={`${base}skills/`}>skill creation</a>, <a href={`${base}rules/`}>rules</a>, or
the <a href={`${base}skills-review/`}>skills review desk</a>.
</p>
</section>
</main> </main>
<GuideSelector rootSelector="#full-guide" data={selectorData} /> <GuideSelector rootSelector="#full-guide" data={selectorData} />
</BaseLayout> </BaseLayout>
+5 -14
View File
@@ -84,10 +84,8 @@ const cards = data.cards ?? [];
padding: 12px 16px; padding: 12px 16px;
background: var(--ink); background: var(--ink);
color: var(--paper); color: var(--paper);
/* token-gap: legacy 12px fixed from landing.css; --step-0 is 11px;
no token matches 12px; owner design-system-keeper */
font: font:
700 12px ui-monospace, 700 var(--step-12) ui-monospace,
monospace; monospace;
letter-spacing: 0.06em; letter-spacing: 0.06em;
text-decoration: none; text-decoration: none;
@@ -104,8 +102,7 @@ const cards = data.cards ?? [];
.guide-launch span { .guide-launch span {
color: var(--gold); color: var(--gold);
/* token-gap: legacy 22px arrow from landing.css; no --step-* covers 22px; owner design-system-keeper */ font-size: var(--step-22);
font-size: 22px;
line-height: 0; line-height: 0;
} }
@@ -121,25 +118,19 @@ const cards = data.cards ?? [];
.landing-note span { .landing-note span {
color: var(--red); color: var(--red);
/* token-gap: legacy 11px monospace eyebrow (no DM Mono in stack);
--step-0 also resolves to 11px but with different font weight;
preserved verbatim from landing.css; owner design-system-keeper */
font: font:
700 11px ui-monospace, 700 var(--step-0) ui-monospace,
monospace; monospace;
letter-spacing: 0.1em; letter-spacing: 0.1em;
} }
.landing-note strong { .landing-note strong {
/* token-gap: clamp(22px,3.2vw,42px) is specific to this strip; no font-size: var(--step-4);
--step-* ramp covers both endpoints; owner design-system-keeper */
font-size: clamp(22px, 3.2vw, 42px);
line-height: 1.08; line-height: 1.08;
letter-spacing: -0.04em; letter-spacing: -0.04em;
} }
/* token-gap: 520px collapse from landing.css (was bottom-bar threshold); owner design-system-keeper */ @media (max-width: 560px) {
@media (max-width: 520px) {
.landing-note { .landing-note {
grid-template-columns: 1fr; grid-template-columns: 1fr;
gap: 9px; gap: 9px;
+35
View File
@@ -20,8 +20,43 @@
--step-6: clamp(36px, 5vw, 65px); --step-6: clamp(36px, 5vw, 65px);
--step-5: clamp(24px, 3vw, 38px); --step-5: clamp(24px, 3vw, 38px);
--step-4: clamp(22px, 3vw, 36px); --step-4: clamp(22px, 3vw, 36px);
--step-48: 48px;
--step-32: 32px;
--step-30: 30px;
--step-25: 25px;
--step-24: 24px;
--step-22: 22px;
--step-20: 20px;
--step-18: 18px;
--step-17: 17px;
--step-16: 16px;
--step-1: 15px; --step-1: 15px;
--step-14: 14px;
--step-13: 13px;
--step-12: 12px;
--step-0: 11px; --step-0: 11px;
--step-00: 10px;
--step-09: 9px;
/* On-dark palette. These are the values the source actually uses on the
--ink and --accent surfaces. They are not near-misses of the palette
above: --muted is a dark-on-light value and is illegible on --ink, and
--paper is warm where the text over --accent is violet-tinted. Each one
is the exact hex the legacy stylesheets ship. */
--ink-muted: #9eb0bb;
--ink-line: #b8c8d2;
--ink-code: #c9d5dc;
--accent-paper: #eceaf5;
--accent-paper-active: #f0eef8;
--accent-surface: #5b7098;
/* Overlays. The percentages are the exact 8-bit alphas the source ships
(#ffffff24, #ffffff3a, #ffffff40, #ffffff50), not rounded to whole
numbers — the names are rounded, the values are not. */
--white-14: rgb(255 255 255 / 14.1176%);
--white-23: rgb(255 255 255 / 22.7451%);
--white-25: rgb(255 255 255 / 25.098%);
--white-31: rgb(255 255 255 / 31.3725%);
/* Breakpoints */ /* Breakpoints */
--bp-sm: 560px; --bp-sm: 560px;
+1 -70
View File
@@ -1,70 +1 @@
<!doctype html> <!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>AI For Dummies — Route map</title><link rel="stylesheet" href="../chapters.css"></head><body><main><header class="top"><a href="../full-guide/">← AI FOR DUMMIES</a><span>00 / ROUTE MAP</span><a href="../skills-review/">review desk ↗</a></header><section class="hero"><p class="eyebrow">Start here</p><h1>Ship the<br><em>system.</em></h1><p>This guide turns AI work into a shape: frame the problem, choose the model and agent, isolate changes, teach repeatable decisions, and verify the result.</p></section><section class="grid"><article class="card"><b>01</b><h2>Models</h2><p>Capability and effort are separate knobs.</p><a href="../models/">Open chapter →</a></article><article class="card"><b>02</b><h2>Agents & trees</h2><p>Bound roles, handoffs, and worktrees.</p><a href="../agents/">Open chapter →</a></article><article class="card"><b>03</b><h2>Skills</h2><p>Capture repeatable decisions.</p><a href="../skills/">Open chapter →</a></article><article class="card"><b>04</b><h2>Rules</h2><p>Connect guidance to enforcement.</p><a href="../rules/">Open chapter →</a></article><article class="card"><b>05</b><h2>Practice</h2><p>Compare prompts and skill-enabled runs.</p><a href="../hands-on/starter/">Open lab →</a></article><article class="card"><b>06</b><h2>Review desk</h2><p>Browse original files and improved drafts.</p><a href="../skills-review/">Open desk →</a></article></section><nav class="links"><a href="../full-guide/">Full field guide</a><a href="../docs/operations-guide.md">Operations guide</a></nav><footer>Each chapter stands alone; the order follows a real task becoming a reliable change.</footer></main></body></html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>AI For Dummies — Route map</title>
<link rel="stylesheet" href="../chapters.css" />
</head>
<body>
<main>
<header class="top">
<a href="../full-guide/">← AI FOR DUMMIES</a><span>00 / ROUTE MAP</span
><a href="../skills-review/">review desk ↗</a>
</header>
<section class="hero">
<p class="eyebrow">Start here</p>
<h1>Ship the<br /><em>system.</em></h1>
<p>
This guide turns AI work into a shape: frame the problem, choose the model and agent,
isolate changes, teach repeatable decisions, and verify the result.
</p>
</section>
<section class="grid">
<article class="card">
<b>01</b>
<h2>Models</h2>
<p>Capability and effort are separate knobs.</p>
<a href="../models/">Open chapter →</a>
</article>
<article class="card">
<b>02</b>
<h2>Agents & trees</h2>
<p>Bound roles, handoffs, and worktrees.</p>
<a href="../agents/">Open chapter →</a>
</article>
<article class="card">
<b>03</b>
<h2>Skills</h2>
<p>Capture repeatable decisions.</p>
<a href="../skills/">Open chapter →</a>
</article>
<article class="card">
<b>04</b>
<h2>Rules</h2>
<p>Connect guidance to enforcement.</p>
<a href="../rules/">Open chapter →</a>
</article>
<article class="card">
<b>05</b>
<h2>Practice</h2>
<p>Compare prompts and skill-enabled runs.</p>
<a href="../hands-on/starter/">Open lab →</a>
</article>
<article class="card">
<b>06</b>
<h2>Review desk</h2>
<p>Browse original files and improved drafts.</p>
<a href="../skills-review/">Open desk →</a>
</article>
</section>
<nav class="links">
<a href="../full-guide/">Full field guide</a
><a href="../docs/operations-guide.md">Operations guide</a>
</nav>
<footer>
Each chapter stands alone; the order follows a real task becoming a reliable change.
</footer>
</main>
</body>
</html>