mirror of
https://github.com/Nutlope/hallmark.git
synced 2026-08-14 12:35:33 +02:00
Hallmark was telling good models what to build. This splits it into a floor that binds and a library that offers, and bans the eyebrow outright. The eyebrow. Gate 54 goes from geometry to existence: short inert type before a heading that announces it is banned in every arrangement, and no brief earns it back. The detector inverts from CSS-first to DOM-first, so it now sees flex and block stacks, heads declared inside a media query, class-less headings, and the word "overline". Small type before a heading survives only when it carries a fact, a destination, or an identifier, which keeps captions, field labels, datelines, unit labels and linked chips legal. references/section-entry.md is the replacement: twelve ways into a section, ten of them pointing at material the skill already had. Themes stay themes. A written contract in theme-axes.md says a theme carries material and never a page plan, and all 24 are trimmed to it: 4,070 lines down to 2,861. Lumen loses a mandatory hero apparatus and a fixed section sequence; hum loses 45 lines of global layout rules filed under a theme. Fake brands, invented people and shippable taglines come out. Genre files stop mandating nav and footer archetypes they disagreed with the themes about. Tiers. All 58 gates gain one: 34 carry a Floor clause nothing ships through, 18 are Reflex gates a build with an argument can waive on the record, 6 never block. Fifteen gates split so a real floor stops dragging a taste threshold behind it. Gates 42 and 43 stop ordering a rotation through the catalog and instead ask that the default be named rather than defaulted into. A waiver declares itself in the stamp with guard evidence the linter re-derives; three per artifact, one per gate, Floor never waivable, and an over-cap waiver lets its gate fire so waiving twelve is worse than waiving none. The catalogs stop being a mandatory pick. Step 2 asks for a designed page shape stated in plain words; the named shapes are there when a starting point helps. Anti-repetition moves from "rotate the codes" to "differ from your last three and say how", which constrains sameness without constraining invention. Contradictions. Display line-height had three ranges and now has one owner. The outlier face was capped at two slots by one line and uncapped by the next. Gate 39 hard-coded 44px against finish.md's 32-40px allowance. Gate 14 banned padding animation that floating-nav.md prescribes. Gate 57's theme list had drifted to 20 of 24. F3 and gate 51 fought over overflow-wrap; break-word settles it. Evidence. 201 eyebrows removed across 38 example pages and 32 across the archived test builds, each replaced with a real opening rather than deleted; aggregate failures fell while doing it. The marketing site drops its own section labels and moves hero labels below the lede. A cold build through the revised skill lands 0 FAIL / 0 WARN, names its own structure instead of picking a code, and argues with a Reflex gate rather than waiving it.
343 lines
9.1 KiB
CSS
343 lines
9.1 KiB
CSS
/* Hallmark · macrostructure: Workbench · F2 sticky-scroll knobs: pinned=right, content=trace-panel, steps=3
|
|
* theme: custom · vibe: "industrial precision, cool, technical" · paper: oklch(13% 0.012 220) · accent: oklch(72% 0.16 220)
|
|
* display: Geist Mono 500 · body: Geist · axes: dark / mono / cool
|
|
* studied: no · context: explicit · v0.7.0
|
|
*/
|
|
|
|
:root {
|
|
/* Custom palette — dark cool, sea-blue anchor */
|
|
--color-paper: oklch(13% 0.012 220);
|
|
--color-paper-2: oklch(17% 0.014 220);
|
|
--color-paper-3: oklch(22% 0.014 220);
|
|
--color-rule: oklch(30% 0.012 220);
|
|
--color-rule-2: oklch(26% 0.012 220);
|
|
--color-muted: oklch(58% 0.012 220);
|
|
--color-neutral: oklch(50% 0.012 220);
|
|
--color-ink: oklch(94% 0.010 220);
|
|
--color-ink-2: oklch(72% 0.010 220);
|
|
--color-accent: oklch(72% 0.16 220);
|
|
--color-accent-ink: oklch(13% 0.012 220);
|
|
--color-focus: oklch(78% 0.20 220);
|
|
--color-warn: oklch(72% 0.16 70);
|
|
--color-error: oklch(64% 0.18 28);
|
|
|
|
/* Single-family pair: Geist Mono display + Geist body — same family, different widths */
|
|
--font-display: "Geist Mono", "JetBrains Mono", ui-monospace, monospace;
|
|
--font-body: "Geist", "Inter Tight", -apple-system, sans-serif;
|
|
--font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, monospace;
|
|
|
|
--space-3xs: 0.25rem;
|
|
--space-2xs: 0.5rem;
|
|
--space-xs: 0.75rem;
|
|
--space-sm: 1rem;
|
|
--space-md: 1.5rem;
|
|
--space-lg: 2rem;
|
|
--space-xl: 3rem;
|
|
--space-2xl: 4.5rem;
|
|
--space-3xl: 6.5rem;
|
|
|
|
--ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
--dur-micro: 100ms;
|
|
--dur-short: 200ms;
|
|
}
|
|
|
|
* { box-sizing: border-box; }
|
|
html, body { overflow-x: clip; }
|
|
|
|
body {
|
|
margin: 0;
|
|
background: var(--color-paper);
|
|
color: var(--color-ink);
|
|
font-family: var(--font-body);
|
|
font-size: 0.9375rem;
|
|
line-height: 1.55;
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
|
|
.page { max-width: 80rem; margin: 0 auto; padding: 0 var(--space-lg); }
|
|
|
|
.masthead {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: var(--space-md) 0;
|
|
border-block-end: 1px solid var(--color-rule);
|
|
font-family: var(--font-display);
|
|
font-size: 0.8125rem;
|
|
letter-spacing: 0.04em;
|
|
color: var(--color-ink-2);
|
|
}
|
|
|
|
.masthead__brand { color: var(--color-ink); font-weight: 500; }
|
|
.masthead__brand .dot {
|
|
display: inline-block;
|
|
width: 0.55ch;
|
|
height: 0.55ch;
|
|
background: var(--color-accent);
|
|
border-radius: 50%;
|
|
margin-inline-end: 0.5ch;
|
|
vertical-align: 0.1em;
|
|
}
|
|
|
|
.masthead__nav { display: flex; gap: var(--space-md); }
|
|
.masthead__nav a {
|
|
color: var(--color-ink-2);
|
|
text-decoration: none;
|
|
transition: color var(--dur-micro) var(--ease-out);
|
|
}
|
|
.masthead__nav a:hover, .masthead__nav a:focus-visible { color: var(--color-ink); }
|
|
.masthead__nav a:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 3px; }
|
|
|
|
/* Hero */
|
|
.hero {
|
|
padding: var(--space-3xl) 0 var(--space-2xl);
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
|
|
gap: var(--space-2xl);
|
|
align-items: end;
|
|
border-block-end: 1px solid var(--color-rule);
|
|
}
|
|
|
|
.hero__copy { max-width: 36rem; }
|
|
|
|
/* The page opens on a mark, not on a line of type: an accent square running
|
|
into a hairline. It costs no words and the reader learns it in one look.
|
|
Who Loop is for is said in the sub, in prose, where it reads. */
|
|
.hero__mark {
|
|
border: 0;
|
|
margin: 0 0 var(--space-md);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.6rem;
|
|
}
|
|
|
|
.hero__mark::before {
|
|
content: "";
|
|
width: 8px;
|
|
height: 8px;
|
|
background: var(--color-accent);
|
|
}
|
|
|
|
.hero__mark::after {
|
|
content: "";
|
|
flex: 1;
|
|
height: 1px;
|
|
background: var(--color-rule);
|
|
}
|
|
|
|
.hero__head {
|
|
font-family: var(--font-display);
|
|
font-size: clamp(2rem, 4.5vw, 3.5rem);
|
|
font-weight: 500;
|
|
line-height: 1.05;
|
|
letter-spacing: -0.025em;
|
|
margin: 0 0 var(--space-md);
|
|
color: var(--color-ink);
|
|
}
|
|
|
|
.hero__head em { font-style: normal; color: var(--color-accent); }
|
|
|
|
.hero__sub {
|
|
font-size: 1.0625rem;
|
|
line-height: 1.5;
|
|
color: var(--color-ink-2);
|
|
margin: 0 0 var(--space-lg);
|
|
max-width: 56ch;
|
|
}
|
|
|
|
.hero__cta { display: flex; gap: var(--space-sm); flex-wrap: wrap; }
|
|
|
|
.btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.5ch;
|
|
padding: var(--space-sm) var(--space-md);
|
|
font-family: var(--font-display);
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
text-decoration: none;
|
|
border: 1px solid var(--color-rule);
|
|
background: transparent;
|
|
color: var(--color-ink);
|
|
cursor: pointer;
|
|
line-height: 1;
|
|
transition: background var(--dur-micro) var(--ease-out),
|
|
border-color var(--dur-micro) var(--ease-out),
|
|
color var(--dur-micro) var(--ease-out);
|
|
}
|
|
|
|
.btn--primary { background: var(--color-accent); color: var(--color-accent-ink); border-color: var(--color-accent); }
|
|
.btn--primary:hover, .btn--primary:focus-visible { background: var(--color-ink); border-color: var(--color-ink); }
|
|
.btn:hover, .btn:focus-visible { border-color: var(--color-accent); color: var(--color-accent); }
|
|
.btn:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 3px; }
|
|
|
|
/* Hero panel — sample trace */
|
|
.hero__panel {
|
|
background: var(--color-paper-2);
|
|
border: 1px solid var(--color-rule);
|
|
border-radius: 4px;
|
|
padding: var(--space-md);
|
|
font-family: var(--font-display);
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.hero__panel-head {
|
|
display: flex; justify-content: space-between;
|
|
border-block-end: 1px solid var(--color-rule);
|
|
padding-block-end: var(--space-2xs);
|
|
margin-block-end: var(--space-sm);
|
|
color: var(--color-ink-2);
|
|
}
|
|
|
|
.trace { display: grid; gap: 4px; }
|
|
.span {
|
|
display: grid;
|
|
grid-template-columns: 14ch 1fr 6ch;
|
|
gap: var(--space-2xs);
|
|
align-items: center;
|
|
}
|
|
.span__label { color: var(--color-ink); white-space: nowrap; }
|
|
.span__bar {
|
|
position: relative;
|
|
height: 8px;
|
|
background: var(--color-paper-3);
|
|
border-radius: 1px;
|
|
overflow: hidden;
|
|
}
|
|
.span__bar > i {
|
|
position: absolute;
|
|
inset-block: 0;
|
|
inset-inline-start: 0;
|
|
background: var(--color-accent);
|
|
border-radius: 1px;
|
|
}
|
|
.span--err .span__bar > i { background: var(--color-error); }
|
|
.span--warn .span__bar > i { background: var(--color-warn); }
|
|
.span__time { font-variant-numeric: tabular-nums; color: var(--color-ink-2); text-align: end; }
|
|
|
|
/* Walkthrough */
|
|
.workbench {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
|
|
gap: var(--space-2xl);
|
|
padding: var(--space-3xl) 0;
|
|
}
|
|
|
|
.steps { display: grid; gap: var(--space-3xl); }
|
|
|
|
.step {
|
|
border-inline-start: 2px solid var(--color-rule);
|
|
padding-inline-start: var(--space-lg);
|
|
position: relative;
|
|
}
|
|
.step::before {
|
|
content: "";
|
|
position: absolute;
|
|
inset-inline-start: -2px;
|
|
inset-block-start: 0;
|
|
width: 2px;
|
|
height: 0;
|
|
background: var(--color-accent);
|
|
transition: height var(--dur-short) var(--ease-out);
|
|
}
|
|
.step:hover::before, .step:focus-within::before { height: 100%; }
|
|
|
|
.step__num {
|
|
font-family: var(--font-display);
|
|
font-size: 0.75rem;
|
|
letter-spacing: 0.12em;
|
|
color: var(--color-accent);
|
|
text-transform: uppercase;
|
|
margin-block-end: var(--space-sm);
|
|
}
|
|
|
|
.step__head {
|
|
font-family: var(--font-display);
|
|
font-size: clamp(1.5rem, 2.5vw, 2rem);
|
|
font-weight: 500;
|
|
letter-spacing: -0.015em;
|
|
line-height: 1.1;
|
|
margin: 0 0 var(--space-md);
|
|
color: var(--color-ink);
|
|
}
|
|
|
|
.step__body {
|
|
font-size: 1rem;
|
|
line-height: 1.6;
|
|
color: var(--color-ink-2);
|
|
max-width: 48ch;
|
|
}
|
|
.step__body strong { color: var(--color-ink); font-weight: 500; }
|
|
|
|
.pinned {
|
|
position: sticky;
|
|
top: var(--space-xl);
|
|
height: fit-content;
|
|
background: var(--color-paper-2);
|
|
border: 1px solid var(--color-rule);
|
|
border-radius: 4px;
|
|
padding: var(--space-lg);
|
|
}
|
|
|
|
.pinned__head {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
font-family: var(--font-display);
|
|
font-size: 0.75rem;
|
|
letter-spacing: 0.06em;
|
|
color: var(--color-ink-2);
|
|
border-block-end: 1px solid var(--color-rule);
|
|
padding-block-end: var(--space-sm);
|
|
margin-block-end: var(--space-md);
|
|
}
|
|
|
|
.pinned__chip {
|
|
font-family: var(--font-display);
|
|
font-size: 0.6875rem;
|
|
letter-spacing: 0.08em;
|
|
padding: 2px 6px;
|
|
border: 1px solid var(--color-accent);
|
|
color: var(--color-accent);
|
|
border-radius: 2px;
|
|
}
|
|
|
|
.pinned__why {
|
|
margin-block-start: var(--space-md);
|
|
padding-block-start: var(--space-md);
|
|
border-block-start: 1px solid var(--color-rule);
|
|
font-family: var(--font-body);
|
|
font-size: 0.875rem;
|
|
color: var(--color-ink-2);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.pinned__why strong { color: var(--color-error); font-weight: 500; }
|
|
|
|
.colophon {
|
|
padding: var(--space-md) 0;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
flex-wrap: wrap;
|
|
gap: var(--space-sm);
|
|
font-family: var(--font-display);
|
|
font-size: 0.75rem;
|
|
letter-spacing: 0.06em;
|
|
color: var(--color-ink-2);
|
|
border-block-start: 1px solid var(--color-rule);
|
|
}
|
|
|
|
.colophon a { color: var(--color-ink-2); text-decoration: none; transition: color var(--dur-micro) var(--ease-out); }
|
|
.colophon a:hover, .colophon a:focus-visible { color: var(--color-accent); }
|
|
.colophon a:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 3px; }
|
|
|
|
@media (max-width: 56rem) {
|
|
.hero { grid-template-columns: 1fr; }
|
|
.workbench { grid-template-columns: 1fr; }
|
|
.pinned { position: static; }
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.step::before { transition: none; }
|
|
}
|