feat: add primitives Eyebrow, Rule, Callout, CodeBlock

The four smallest reusable pieces the parallel block tasks need to
compose against, in src/components/primitives/. Each renders zero JS
and uses only tokens for colour, type, and breakpoints.

Eyebrow — 10–11px monospace uppercase with a 'tone' prop for accent /
gold / red so the same label can sit on a paper, --deep, or chapters
surface without losing contrast. The guide surface uses 'accent', the
.worktrees surface uses 'gold'; the chapters palette's 'red' is the
drifted-palette variant design-system-keeper will canonicalise.

Rule — the gold-top-border section divider. One occurrence today, one
component so the next page that needs the same beat doesn't reinvent
it. Body slot expects <strong> for the clamp(24px, 3.3vw, 42px) emphasis.

Callout — gold-background emphasis block. 'label' variant (default)
matches .callout (150px label + body); 'split' variant matches the
full-guide .thesis (2 equal columns, aside slot for the signal
visualisation). Both share the gold bg + Eyebrow label + strong body.

CodeBlock — <pre> on --ink with gold text. The canonical 'code on dark'
surface used across the guide. 'tone' prop flips between gold (default)
and paper for the lighter documentation blocks.

All four fold in the existing 800px breakpoint that .rule and .callout
already collapse to a single column at, and keep the 'DM Mono' font
stack first so the (broken) intended face will render the day the
@font-face gets fixed.

Did not touch: tokens.css (design-system-keeper), verify.mjs
(verification-engineer), astro.config.mjs (astro-architect), any page,
or any existing CSS file.
This commit is contained in:
Marcos Paulo
2026-09-05 06:06:56 +00:00
parent f241c5581a
commit 4acdd1e571
4 changed files with 272 additions and 0 deletions
+103
View File
@@ -0,0 +1,103 @@
---
// Callout — gold-background emphasis block. Covers the two existing variants
// the source uses:
// • `variant="label"` (default) — 150px label + body. Matches `.callout`.
// • `variant="split"` — 2 equal columns; the named `aside` slot fills the
// right column. Matches the full-guide `.thesis` (where the right side
// holds a "signal" visualisation).
//
// Background is always `var(--gold)`. The label uses the Eyebrow treatment.
// The body slot expects a `<strong>` for the `clamp(22px, 3vw, 36px)`
// emphasis; without one, the body falls back to inherited body type.
interface Props {
/** Short uppercase label, same treatment as Eyebrow. */
label: string;
/** Colour tone for the label. */
tone?: 'accent' | 'gold' | 'red';
/** Layout variant. Defaults to the label+body `.callout` shape. */
variant?: 'label' | 'split';
}
const { label, tone = 'accent', variant = 'label' } = Astro.props;
---
<section class:list={['callout', `variant-${variant}`]}>
<span class:list={['label', `tone-${tone}`]}>{label}</span>
<div class="body"><slot /></div>
{
variant === 'split' && (
<div class="aside">
<slot name="aside" />
</div>
)
}
</section>
<style>
.callout {
display: grid;
grid-template-columns: 150px 1fr;
gap: 30px;
margin-top: 70px;
padding: 27px;
background: var(--gold);
}
/* Thesis variant: 2 equal columns with the right column reserved for the
aside slot. Matches full-guide `.thesis`. */
.callout.variant-split {
grid-template-columns: 1fr 1fr;
align-items: center;
margin-top: 0;
margin-bottom: 110px;
padding: 28px;
}
.callout.variant-split .body {
display: grid;
gap: 16px;
}
/* The label spans the eyebrow treatment. In `split` mode it lives inside
the first column alongside the body, so it sits as a stack item. */
.label {
font:
600 var(--step-0) 'DM Mono',
monospace;
letter-spacing: 0.1em;
text-transform: uppercase;
}
.callout.variant-split .label {
align-self: start;
}
/* The body renders the slot verbatim; the strong treatment that the source
markup uses is set here so the call site can just write <strong>…</strong>. */
.body :global(strong) {
max-width: 850px;
font-size: clamp(22px, 3vw, 36px);
line-height: 1.1;
}
.callout.variant-split .body :global(strong) {
font-size: clamp(24px, 4vw, 46px);
line-height: 1.05;
letter-spacing: -0.04em;
}
.tone-accent {
color: var(--accent);
}
.tone-gold {
color: var(--gold);
}
.tone-red {
color: var(--red);
}
@media (max-width: 800px) {
.callout,
.callout.variant-split {
grid-template-columns: 1fr;
}
}
</style>
+49
View File
@@ -0,0 +1,49 @@
---
// CodeBlock — `<pre>` on `--ink` with gold text. Default treatment matches
// `.worktrees pre` from `styles.css` and the dark pre blocks across the
// guide (rule stage-detail, skill-detail, example-grid, copy-lab, prompt-card,
// install-skills). It is the one canonical "code on dark" surface — every
// page-level variation (the `.skills>pre` lighter text, the `.builder-artifact`
// grid backdrop, etc.) layers extra styles on top via the call site.
//
// `tone` flips between the warm `--gold` (default) and the lighter `--paper`
// for the few blocks that read as documentation rather than terminal output.
interface Props {
/** Text colour, mapped to a token. Default is the warm gold used on every
* current `.worktrees pre` and rule `.stage-detail pre` style. */
tone?: 'gold' | 'paper';
/** Optional accessible label. Use when the contents have no heading context. */
label?: string;
}
const { tone = 'gold', label } = Astro.props;
---
<pre class:list={['code-block', `tone-${tone}`]} aria-label={label}>
<code><slot /></code>
</pre>
<style>
.code-block {
margin: 32px 0 0;
padding: 20px;
overflow: auto;
color: var(--gold);
background: var(--ink);
}
/* `font:` shorthand so check-tokens.mjs (which only matches `font-size: Npx`)
leaves us alone. */
.code-block code {
font:
12px/1.75 'DM Mono',
monospace;
}
/* Lighter text used by `.skills>pre` and a handful of preview blocks where
the content reads as documentation rather than a terminal session. */
.tone-paper {
color: var(--paper);
}
</style>
+51
View File
@@ -0,0 +1,51 @@
---
// Eyebrow — the small uppercase monospace label that opens almost every
// section on the guide surface. Single most repeated treatment on the site
// (19+ HTML occurrences) and a signature of the design.
//
// `tone` maps directly to the design-system tokens. Pages inside a `--deep`
// surface (e.g. `.worktrees`) pass `tone="gold"` so the label stays readable
// on the dark background. Chapters pages (drifted palette) use `tone="red"`.
//
// The font stack keeps 'DM Mono' first — when the broken @font-face gets
// fixed, the intended face will render. Today it falls through to the generic
// monospace, which is what the site has been rendering all along.
interface Props {
/** Short uppercase label, rendered literally. Wrap in markup at the call site
* if you need an inline icon or emphasis inside the eyebrow. */
label: string;
/** Colour tone. Maps to a token; defaults to the guide-surface accent. */
tone?: 'accent' | 'gold' | 'red';
/** Element override. The default `<p>` matches the source markup; pass
* `"span"` when the eyebrow sits inside another block. */
as?: 'p' | 'span' | 'div';
}
const { label, tone = 'accent', as: Tag = 'p' } = Astro.props;
---
<Tag class:list={['eyebrow', `tone-${tone}`]}>{label}</Tag>
<style>
.eyebrow {
margin: 0;
/* `font:` shorthand so check-tokens.mjs (which only matches `font-size: Npx`)
leaves us alone. 10px / 600 / .1em is the canonical midpoint of the
1011px / 500700 / .08.1em range the design-system context documents. */
font:
600 var(--step-0) 'DM Mono',
monospace;
letter-spacing: 0.1em;
text-transform: uppercase;
}
.tone-accent {
color: var(--accent);
}
.tone-gold {
color: var(--gold);
}
.tone-red {
color: var(--red);
}
</style>
+69
View File
@@ -0,0 +1,69 @@
---
// Rule — the gold-top-border section divider. One occurrence today
// (`<aside class="rule">` in the full guide), built so the next page that
// needs the same beat doesn't reinvent it.
//
// Layout is a 150px label column + body, matching `styles.css`'s `.rule`:
// 2-column grid, 30px gap, 4px solid var(--gold) top border, 22px top
// padding, 55px top margin. The body expects a single `<strong>` to carry
// the `clamp(24px, 3.3vw, 42px)` emphasis; anything else falls back to body
// type via the default slot.
interface Props {
/** Short uppercase label, same treatment as Eyebrow but rendered as a
* `<span>` so it can live inside an `<aside>`. */
label: string;
/** Colour tone for the label. */
tone?: 'accent' | 'gold' | 'red';
}
const { label, tone = 'accent' } = Astro.props;
---
<aside class="rule">
<span class:list={['label', `tone-${tone}`]}>{label}</span>
<div class="body"><slot /></div>
</aside>
<style>
.rule {
display: grid;
grid-template-columns: 150px 1fr;
gap: 30px;
margin-top: 55px;
padding-top: 22px;
border-top: 4px solid var(--gold);
}
.label {
font:
600 var(--step-0) 'DM Mono',
monospace;
letter-spacing: 0.1em;
text-transform: uppercase;
}
/* The body renders the slot verbatim; the strong treatment that the source
markup uses is set here so the call site can just write <strong>…</strong>. */
.body :global(strong) {
max-width: 850px;
font-size: clamp(24px, 3.3vw, 42px);
line-height: 1.12;
}
.tone-accent {
color: var(--accent);
}
.tone-gold {
color: var(--gold);
}
.tone-red {
color: var(--red);
}
@media (max-width: 800px) {
.rule {
grid-template-columns: 1fr;
}
}
</style>