Files
hallmark/site/css/components.css
T
YoussefandClaude Opus 4.7 b5b21ceebf Hero enrichment + custom-craft canon + Quiet theme
The skill now knows how to add hero visuals — demo videos, mockups,
illustrations, animated loops, abstract backgrounds, photography — and
when not to. The default answer remains typography-only; enrichment
has to earn its place.

Three new references. hero-enrichment.md is the decision file: an
enrichment hierarchy (typography → custom CSS art → hand-built SVG →
generated illustration → library + customise → Lottie last resort),
a brief-domain decision protocol (SaaS → demo video, bakery → custom
illustration, manifesto → none), eight enrichment archetypes (E1
clipped-edge demo video with the full Linear/Vercel recipe, E3/E4
mockups, E5 custom centerpiece, E6 custom animated loop, E7 subtle
gradient + grain background, E8 photography), and an eight-question
quality bar. custom-craft.md is the how-to-build-it file: pure CSS
art (Lynn Fisher / Diana Smith canon — clip-path, conic-gradient,
@property, mask, blend-mode), hand-built SVG with the Figma → SVGOMG
pipeline and declarative animation via CSS keyframes / @property /
animation-timeline / View Transitions, JS-driven motion with the
Motion / GSAP / AutoAnimate decision rule, Three.js when the 3D is
the hero value not when it isn't, generated stills via Nanobanana 2
and Recraft V4 with discipline (always post-process, reference images,
stamp the model), and Lottie explicitly demoted to last resort with
the rule "never for what CSS can do". A bakery worked example shows
all of it. assets.md is the sourcing canon: Lucide / Phosphor /
Heroicons (icons, never mix sets), Simple Icons / SVGL (logos),
Storyset / Humaaans / unDraw (library illustration with mandatory
customisation), Browserframe / Ray.so / Cleanmock (mockups), Mixkit /
Coverr / Pexels (video with the AV1 → VP9 → H.264 codec chain and
fetchpriority="high" rule), Unsplash / Nappy / Shotstash (photography),
CSS gradients + fffuel.co (abstracts, no aurora), LottieFiles / Rive
(last resort).

Three new hero archetypes in component-cookbook.md (H7 clipped video,
H8 mockup split, H9 custom illustration centerpiece) with within-
archetype variation knobs added to the table.

Eight new tells in anti-patterns.md: aurora-blob background, floating-
orb decoration, sound-on autoplay, lazy-loaded LCP, mismatched icon
sets, AI-illustration look, Lottie shortcut, Three.js for a still
object.

Slop test 29 → 33 with four hero-enrichment gates: video autoplay
discipline, abstract-background restraint, single-icon-library check,
and the Lottie-shortcut catch.

SKILL.md design flow gains Step 4 "Decide on hero enrichment" between
the macrostructure pick and the build, with the enrichment hierarchy
as a non-negotiable. Frontmatter version bumped to 0.4.0. New refs
listed as load-on-demand.

Sixteenth theme: Quiet. Restraint as the design — system fonts
(no web fonts loaded for Quiet), barely-warm near-white paper
(oklch 99.5% 0.002 90, deliberately not pure #FFFFFF), barely-cool
near-black ink, accent equal to ink (no chromatic accent at all),
average-sized headlines (clamp 1.75–2.75rem, much smaller than the
3.5–8rem of every other theme), generous whitespace (section-gap
12rem). Hero archetype: Letter. Footer: Inline. No reveals — Quiet
is intentionally still. A deliberate exception to Hallmark's "pair
distinctive display + body" rule, which the theme tokens block calls
out explicitly. The user spec was "the most simple you can make it";
Quiet is.

Landing page demonstration of E1: Pastel theme now renders the
clipped-edge dashboard mockup as its hero instead of Letter. The
mockup is hand-built CSS art — no real video, no images. Browser
chrome (three dots, hallmark.studio URL), a sidebar with the active
item in indigo accent, a 3-card grid showing a stat, a sparkline, and
a rows card. Tilted -0.4° for life. Extends ~12vw past the viewport
right edge. Collapses to stacked at < 60rem. The implementation IS
the custom-craft principle: built, not picked.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 15:42:17 +01:00

1633 lines
42 KiB
CSS

/* Hallmark — components */
/* — Wordmark ——————————————————————————————————————— */
.wordmark {
font-family: var(--font-label);
font-weight: 500;
font-size: var(--text-sm);
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--color-ink);
}
[data-theme="manifesto"] .wordmark {
font-family: var(--font-display);
font-weight: 800;
letter-spacing: -0.02em;
text-transform: uppercase;
font-size: var(--text-md);
}
[data-theme="terminal"] .wordmark::before {
content: "$ ";
color: var(--color-accent);
}
/* — Banner (sticky top, thin, theme picker inline) ————————— */
.banner {
position: sticky;
top: 0;
z-index: var(--z-sticky);
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
gap: var(--space-lg);
padding: 0 var(--page-gutter);
height: 44px;
background: color-mix(in oklch, var(--color-paper) 88%, transparent);
backdrop-filter: blur(14px) saturate(1.2);
-webkit-backdrop-filter: blur(14px) saturate(1.2);
border-block-end: var(--rule-hair) solid var(--color-rule);
font-family: var(--font-label);
font-size: 0.6875rem;
letter-spacing: var(--tracking-label);
text-transform: uppercase;
color: var(--color-ink);
}
.banner__mark {
display: inline-flex;
align-items: baseline;
gap: 0.55rem;
text-decoration: none;
color: var(--color-ink);
}
.banner__name {
font-weight: 500;
letter-spacing: 0.22em;
}
.banner__ver {
font-size: 0.625rem;
color: var(--color-muted);
letter-spacing: 0.14em;
}
/* The active theme name — the centre marker. Lives in the banner so the
page restructure registers as a deliberate event, not a passive repaint. */
.banner__center {
justify-self: center;
font-family: var(--font-display);
font-weight: var(--display-weight, 400);
font-style: var(--display-style, normal);
font-size: var(--text-md);
letter-spacing: 0.04em;
text-transform: none;
color: var(--color-ink);
font-optical-sizing: auto;
transition: opacity var(--dur-short) var(--ease-out);
}
[data-theme="manifesto"] .banner__center,
[data-theme="brutal"] .banner__center,
[data-theme="sport"] .banner__center {
text-transform: uppercase;
letter-spacing: -0.01em;
}
[data-theme="terminal"] .banner__center::before {
content: "$ ";
color: var(--color-accent);
}
[data-theme="terminal"] .banner__center {
font-family: var(--font-mono);
}
.banner__picker {
display: inline-flex;
align-items: center;
gap: 0.4rem;
}
.banner__dot {
appearance: none;
width: 16px;
height: 16px;
padding: 0;
background: var(--dot, var(--color-paper));
border: 1px solid var(--color-rule-2);
border-radius: 4px;
cursor: pointer;
position: relative;
transition: transform 100ms var(--ease-out),
border-color var(--dur-micro) var(--ease-out),
box-shadow var(--dur-micro) var(--ease-out);
}
.banner__dot::after {
content: "";
position: absolute;
inset: 3px;
background: var(--dot-edge, transparent);
border-radius: 2px;
opacity: 0.85;
}
@media (hover: hover) and (pointer: fine) {
.banner__dot:hover {
transform: translateY(-1px);
border-color: var(--color-ink);
}
}
.banner__dot:focus-visible {
outline: 2px solid var(--color-focus);
outline-offset: 2px;
}
.banner__dot[aria-pressed="true"] {
border-color: var(--color-ink);
box-shadow: 0 0 0 2px var(--color-paper), 0 0 0 3px var(--color-ink);
}
.banner__sep {
width: 1px;
height: 14px;
background: var(--color-rule);
margin-inline: 0.25rem;
}
.banner__random {
appearance: none;
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
padding: 0;
background: transparent;
border: 1px solid var(--color-rule);
color: var(--color-muted);
cursor: pointer;
transition: color var(--dur-micro) var(--ease-out),
border-color var(--dur-micro) var(--ease-out),
transform 80ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
.banner__random:hover { color: var(--color-ink); border-color: var(--color-ink); }
}
.banner__random:active { transform: rotate(180deg); transition-duration: 220ms; }
.banner__random:focus-visible {
outline: 2px solid var(--color-focus);
outline-offset: 2px;
}
.banner__kbd {
display: inline-flex;
align-items: center;
justify-content: center;
margin-inline-start: 0.25rem;
padding: 0.1rem 0.4rem;
font-family: var(--font-label);
font-size: 0.625rem;
letter-spacing: 0.08em;
color: var(--color-muted);
border: 1px solid var(--color-rule);
border-radius: 3px;
min-width: 18px;
min-height: 18px;
}
@media (max-width: 60rem) {
.banner { grid-template-columns: auto 1fr auto; gap: var(--space-md); }
.banner__center { font-size: var(--text-sm); }
.banner__kbd { display: none; }
}
@media (max-width: 44rem) {
.banner__ver { display: none; }
.banner__center { display: none; }
.banner__picker { gap: 0.3rem; }
.banner__dot { width: 14px; height: 14px; }
.banner__sep { display: none; }
}
/* — Section label (01 / FOUNDATIONS) —————————————————— */
.section-label {
font-family: var(--font-label);
font-size: var(--text-xs);
font-weight: 400;
letter-spacing: var(--tracking-label);
text-transform: uppercase;
color: var(--color-muted);
display: flex;
align-items: baseline;
gap: var(--space-sm);
}
.section-label .num { color: var(--color-ink); font-weight: 500; }
.section-label .divider { color: var(--color-rule-2); font-weight: 300; }
[data-theme="terminal"] .section-label::before {
content: "> ";
color: var(--color-accent);
}
[data-theme="manifesto"] .section-label .num {
color: var(--color-accent);
font-family: var(--font-display);
font-weight: 800;
font-size: var(--text-md);
}
[data-theme="sport"] .section-label .num {
color: var(--color-accent);
font-weight: 700;
font-family: var(--font-display);
font-size: var(--text-md);
font-style: italic;
}
[data-theme="almanac"] .section-label {
font-family: var(--font-mono);
}
/* — Button (outlined default) ————————————————————————— */
.btn {
display: inline-flex;
align-items: center;
gap: var(--space-sm);
padding: var(--space-sm) var(--space-lg);
font-family: var(--font-label);
font-size: var(--text-sm);
font-weight: 500;
letter-spacing: 0.04em;
color: var(--color-ink);
background: transparent;
border: var(--rule-fine) solid var(--color-ink);
border-radius: 0;
min-height: 44px;
/* explicit properties — never `transition: all` */
transition: transform 100ms var(--ease-out),
background-color var(--dur-micro) var(--ease-out),
color var(--dur-micro) var(--ease-out),
border-color var(--dur-micro) var(--ease-out);
cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
.btn:hover {
background: var(--color-ink);
color: var(--color-paper);
transform: translateY(-1px);
}
}
.btn:active { transform: translateY(1px); transition-duration: 60ms; }
/* — Inline link ————————————————————————————————————— */
.link {
color: var(--color-ink);
text-decoration: none;
background-image: linear-gradient(var(--color-accent), var(--color-accent));
background-repeat: no-repeat;
background-position: 0 100%;
background-size: 100% 1px;
padding-bottom: 0.08em;
transition: background-size var(--dur-short) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
.link:hover { background-size: 100% 2px; }
}
[data-theme="terminal"] .link {
background: none;
text-decoration: underline;
text-underline-offset: 2px;
}
/* — Code block ——————————————————————————————————————— */
.code {
font-family: var(--font-mono);
font-size: var(--text-sm);
font-weight: 400;
color: var(--color-ink);
background: var(--color-paper-2);
border: var(--rule-hair) solid var(--color-rule);
padding: var(--space-md) var(--space-lg);
overflow-x: auto;
white-space: nowrap;
line-height: 1.7;
display: flex;
align-items: center;
gap: var(--space-md);
position: relative;
}
.code .prompt { color: var(--color-muted); user-select: none; }
.code--block { white-space: pre; display: block; }
/* — Copy-to-clipboard button (silent success pattern) ————— */
.code__copy {
position: absolute;
top: 50%;
right: var(--space-sm);
transform: translateY(-50%);
font-family: var(--font-label);
font-size: 0.6875rem;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--color-muted);
background: var(--color-paper);
border: var(--rule-hair) solid var(--color-rule);
padding: 0.35rem 0.65rem;
cursor: pointer;
opacity: 0;
transition: opacity var(--dur-short) var(--ease-out),
color var(--dur-short) var(--ease-out),
border-color var(--dur-short) var(--ease-out);
min-height: 28px;
display: inline-flex;
align-items: center;
gap: 0.4rem;
}
.code:hover .code__copy,
.code:focus-within .code__copy,
.code__copy:focus-visible {
opacity: 1;
}
@media (pointer: coarse) {
.code__copy { opacity: 1; }
}
.code__copy:hover { color: var(--color-ink); border-color: var(--color-rule-2); }
.code__copy[data-state="copied"] {
color: var(--color-accent);
border-color: var(--color-accent);
opacity: 1;
}
.code__copy-default { display: inline; }
.code__copy-done { display: none; }
.code__copy[data-state="copied"] .code__copy-default { display: none; }
.code__copy[data-state="copied"] .code__copy-done { display: inline; }
[data-theme="terminal"] .code__copy {
background: var(--color-paper-2);
border-color: var(--color-rule);
}
[data-theme="manifesto"] .code__copy {
background: var(--color-paper);
color: var(--color-paper);
border-color: var(--color-paper);
font-weight: 500;
}
[data-theme="manifesto"] .code__copy:hover {
color: var(--color-paper);
background: var(--color-accent);
border-color: var(--color-accent);
}
[data-theme="terminal"] .code {
background: var(--color-paper-3);
border-color: var(--color-rule-2);
}
[data-theme="manifesto"] .code {
background: var(--color-ink);
color: var(--color-paper);
border-color: var(--color-ink);
}
[data-theme="manifesto"] .code .prompt { color: var(--color-accent); }
/* — Specimen card ——————————————————————————————————— */
.spec {
display: flex;
flex-direction: column;
gap: var(--space-lg);
padding: var(--space-xl) 0;
border-top: var(--rule-hair) solid var(--color-rule);
}
.spec__head {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: var(--space-md);
}
.spec__name {
font-family: var(--font-display);
font-weight: var(--display-weight, 400);
font-style: var(--display-style, normal);
font-size: var(--text-xl);
letter-spacing: var(--tracking-tight);
color: var(--color-ink);
line-height: 1;
font-optical-sizing: auto;
}
.spec__num {
font-family: var(--font-label);
font-size: var(--text-xs);
color: var(--color-muted);
letter-spacing: var(--tracking-label);
}
.spec__rule {
font-family: var(--font-serif);
font-weight: 400;
font-size: var(--text-md);
line-height: var(--lh-snug);
color: var(--color-ink-2);
font-style: italic;
max-width: 40ch;
}
[data-theme="brutal"] .spec__rule,
[data-theme="manifesto"] .spec__rule,
[data-theme="terminal"] .spec__rule,
[data-theme="sport"] .spec__rule,
[data-theme="almanac"] .spec__rule {
font-style: normal;
font-family: var(--font-body);
font-weight: 500;
}
[data-theme="manifesto"] .spec__name { text-transform: uppercase; }
.spec__body { margin-top: var(--space-xs); }
/* — Swatches ——————————————————————————————————————— */
.swatch-row {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: var(--space-2xs);
height: 3rem;
}
.swatch {
display: flex;
align-items: flex-end;
padding: var(--space-2xs) var(--space-xs);
font-family: var(--font-label);
font-size: 0.625rem;
letter-spacing: 0.08em;
color: var(--color-paper);
text-transform: uppercase;
}
.swatch--light { color: var(--color-ink); }
/* — Type specimen ——————————————————————————————————— */
.type-spec { display: grid; gap: var(--space-xs); }
.type-spec__display {
font-family: var(--font-display);
font-size: var(--text-2xl);
font-weight: var(--display-weight, 400);
font-style: var(--display-style, normal);
line-height: var(--lh-tight);
letter-spacing: var(--tracking-display);
font-optical-sizing: auto;
}
.type-spec__body {
font-family: var(--font-serif);
font-style: italic;
font-size: var(--text-md);
line-height: var(--lh-normal);
color: var(--color-ink-2);
max-width: 32ch;
}
[data-theme="brutal"] .type-spec__body,
[data-theme="manifesto"] .type-spec__body,
[data-theme="terminal"] .type-spec__body,
[data-theme="sport"] .type-spec__body,
[data-theme="almanac"] .type-spec__body {
font-style: normal;
font-family: var(--font-body);
}
/* — Easing curve SVG ——————————————————————————————— */
.curve {
width: 100%;
height: 4.5rem;
color: var(--color-ink);
}
/* — Tell card (gallery) ————————————————————————————— */
.tell {
flex: 0 0 18rem;
display: grid;
grid-template-rows: 13rem auto;
border: var(--rule-hair) solid var(--color-rule);
scroll-snap-align: start;
background: var(--color-paper);
}
.tell__viz {
position: relative;
overflow: hidden;
background: var(--color-paper-2);
}
.tell__meta {
padding: var(--space-md) var(--space-md) var(--space-lg);
display: grid;
gap: var(--space-xs);
border-top: var(--rule-hair) solid var(--color-rule);
}
.tell__name {
font-family: var(--font-display);
font-weight: var(--display-weight, 400);
font-style: var(--display-style, normal);
font-size: var(--text-lg);
color: var(--color-ink);
letter-spacing: var(--tracking-tight);
line-height: 1;
font-optical-sizing: auto;
}
[data-theme="manifesto"] .tell__name { text-transform: uppercase; }
.tell__why {
font-family: var(--font-serif);
font-style: italic;
font-weight: 400;
font-size: var(--text-sm);
color: var(--color-neutral);
max-width: 34ch;
line-height: var(--lh-snug);
}
[data-theme="brutal"] .tell__why,
[data-theme="manifesto"] .tell__why,
[data-theme="terminal"] .tell__why,
[data-theme="sport"] .tell__why,
[data-theme="almanac"] .tell__why {
font-style: normal;
font-family: var(--font-body);
}
/* — Tell visualisations (intentional anti-pattern demos) ————————— */
.viz-purple-hero {
position: absolute; inset: 0;
background: linear-gradient(135deg, #6b4de0 0%, #e04db4 60%, #e0904d 100%);
display: grid; place-items: center;
color: #fff;
font-family: "Inter", sans-serif;
font-size: 1rem; font-weight: 700;
letter-spacing: -0.02em;
}
.viz-purple-hero::after { content: "Unleash the future"; }
.viz-gradient-text {
position: absolute; inset: 0;
display: grid; place-items: center;
background: #fff;
}
.viz-gradient-text::after {
content: "Supercharged";
font-family: "Inter", sans-serif;
font-weight: 800; font-size: 2rem;
letter-spacing: -0.03em;
background: linear-gradient(90deg, #8a3fe0, #e03f8a);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.viz-icon-tile {
position: absolute; inset: 0;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 0.5rem; padding: 0.75rem;
background: #fff;
}
.viz-icon-tile > div {
background: #f7f7f9;
border-radius: 8px; padding: 0.5rem;
display: grid; gap: 0.35rem;
align-content: start;
box-shadow: 0 1px 3px rgba(0,0,0,0.04);
}
.viz-icon-tile .icon {
width: 1.4rem; height: 1.4rem;
background: #e5e4ff; border-radius: 6px;
}
.viz-icon-tile .h { height: 0.45rem; background: #222; border-radius: 2px; width: 80%; }
.viz-icon-tile .t { height: 0.3rem; background: #d7d8df; border-radius: 2px; }
.viz-centered-hero {
position: absolute; inset: 0;
background: #fff;
display: grid; place-items: center; align-content: center;
gap: 0.5rem; text-align: center;
font-family: "Inter", sans-serif; padding: 1rem;
}
.viz-centered-hero .h { font-size: 1.3rem; font-weight: 800; color: #111; letter-spacing: -0.03em; }
.viz-centered-hero .s { font-size: 0.8rem; color: #666; max-width: 20ch; margin: 0 auto; }
.viz-centered-hero .c {
display: inline-block;
padding: 0.5rem 1rem;
background: linear-gradient(90deg, #6366f1, #a855f7);
color: #fff;
border-radius: 9999px;
font-size: 0.72rem; font-weight: 600;
margin-top: 0.25rem;
}
/* — Install block ————————————————————————————————————— */
.install { display: grid; gap: var(--space-sm); }
.install__head {
font-family: var(--font-label);
font-size: var(--text-xs);
letter-spacing: var(--tracking-label);
text-transform: uppercase;
color: var(--color-muted);
}
.install__body {
font-family: var(--font-mono);
font-size: var(--text-sm);
color: var(--color-ink);
padding: var(--space-md) 0;
border-top: var(--rule-hair) solid var(--color-rule);
border-bottom: var(--rule-hair) solid var(--color-rule);
line-height: 1.7;
white-space: pre-wrap;
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-md);
}
.install__body .code__copy--block {
position: static;
transform: none;
flex-shrink: 0;
}
/* — Reveals ————————————————————————————————————————— */
.reveal {
opacity: 0;
transform: translateY(10px);
}
.reveal.is-in {
animation: reveal var(--dur-long) var(--ease-out) forwards;
animation-delay: calc(var(--i, 0) * 60ms);
}
@keyframes reveal { to { opacity: 1; transform: none; } }
/* Theme-specific reveal patterns */
[data-theme="brutal"] .reveal,
[data-theme="manifesto"] .reveal,
[data-theme="sport"] .reveal {
transform: translateX(-16px);
}
@keyframes reveal-sweep { to { opacity: 1; transform: none; } }
[data-theme="brutal"] .reveal.is-in,
[data-theme="manifesto"] .reveal.is-in,
[data-theme="sport"] .reveal.is-in {
animation: reveal-sweep var(--dur-long) var(--ease-out) forwards;
animation-delay: calc(var(--i, 0) * 60ms);
}
[data-theme="atelier"] .reveal,
[data-theme="salon"] .reveal,
[data-theme="newsprint"] .reveal {
transform: none; /* no spatial reveal — fade only */
}
[data-theme="atelier"] .reveal.is-in,
[data-theme="salon"] .reveal.is-in,
[data-theme="newsprint"] .reveal.is-in {
animation: reveal-fade calc(var(--dur-long) * 1.4) var(--ease-out) forwards;
animation-delay: calc(var(--i, 0) * 80ms);
}
@keyframes reveal-fade { to { opacity: 1; } }
[data-theme="terminal"] .reveal,
[data-theme="terminal"] .reveal.is-in {
transform: none;
opacity: 1;
animation: none;
}
@media (prefers-reduced-motion: reduce) {
.reveal { transform: none; animation-duration: 150ms !important; }
@keyframes reveal { to { opacity: 1; } }
*, *::before, *::after {
animation-duration: 150ms !important;
transition-duration: 150ms !important;
}
}
/* — View transitions ————————————————————————————————— */
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 280ms;
animation-timing-function: var(--ease-out);
}
/* ───────────── STUDIO — Fraunces italic display ───────────── */
[data-theme="studio"] .hero__display,
[data-theme="studio"] .section__title,
[data-theme="studio"] .foot__wordmark,
[data-theme="studio"] .hero__quote p,
[data-theme="studio"] .hero__salutation,
[data-theme="studio"] .spec__name,
[data-theme="studio"] .tell__name {
font-style: italic;
letter-spacing: -0.02em;
font-variation-settings: "opsz" 144, "SOFT" 30;
}
[data-theme="studio"] .banner__center {
font-style: italic;
letter-spacing: 0;
font-variation-settings: "opsz" 24;
}
[data-theme="studio"] .hero__lede,
[data-theme="studio"] .hero__letter-body,
[data-theme="studio"] .spec__rule,
[data-theme="studio"] .tell__why,
[data-theme="studio"] .hero__attrib,
[data-theme="studio"] .foot__tagline {
font-family: var(--font-body);
font-style: normal;
}
[data-theme="studio"] .hero__eyebrow,
[data-theme="studio"] .label,
[data-theme="studio"] .section-label {
font-feature-settings: "ss01";
}
/* ───────────── PASTEL — Geist sans display, soft surfaces ───────────── */
[data-theme="pastel"] .hero__display,
[data-theme="pastel"] .section__title,
[data-theme="pastel"] .foot__wordmark,
[data-theme="pastel"] .spec__name,
[data-theme="pastel"] .tell__name,
[data-theme="pastel"] .hero__quote p,
[data-theme="pastel"] .hero__salutation,
[data-theme="pastel"] .hero__qualifier {
font-family: var(--font-display);
font-style: normal;
font-weight: 600;
letter-spacing: -0.025em;
}
[data-theme="pastel"] .hero__display {
font-weight: 600;
letter-spacing: -0.035em;
}
[data-theme="pastel"] .hero__stat {
font-weight: 600;
letter-spacing: -0.04em;
}
[data-theme="pastel"] .hero__lede,
[data-theme="pastel"] .hero__letter-body,
[data-theme="pastel"] .spec__rule,
[data-theme="pastel"] .tell__why,
[data-theme="pastel"] .foot__tagline {
font-family: var(--font-body);
font-style: normal;
font-weight: 400;
color: var(--color-ink-2);
}
[data-theme="pastel"] .banner__center {
font-family: var(--font-display);
font-weight: 500;
font-size: 0.875rem;
letter-spacing: 0;
text-transform: none;
}
/* Pastel uses a subtle indigo on accent — never as a flood. */
[data-theme="pastel"] .hero__eyebrow .mark,
[data-theme="pastel"] .opening__eyebrow .mark {
background: var(--color-accent);
border-radius: 1px;
}
/* ───────────── RISO — bold lowercase, off-register print ───────────── */
[data-theme="riso"] .hero__display,
[data-theme="riso"] .hero__quote p,
[data-theme="riso"] .hero__salutation,
[data-theme="riso"] .hero__qualifier,
[data-theme="riso"] .hero__stat,
[data-theme="riso"] .section__title,
[data-theme="riso"] .foot__wordmark,
[data-theme="riso"] .spec__name,
[data-theme="riso"] .tell__name {
font-family: var(--font-display);
font-weight: 800;
font-style: normal;
text-transform: lowercase;
letter-spacing: -0.04em;
}
/* The riso off-register effect — a 2px cyan ghost behind the headline.
Subtle, not garish. Reduced-motion + browsers without text-shadow are fine. */
[data-theme="riso"] .hero__display,
[data-theme="riso"] .hero__quote p,
[data-theme="riso"] .hero__stat {
text-shadow: 2px 2px 0 var(--color-accent),
-2px 0 0 var(--color-accent-2, oklch(78% 0.18 95));
}
[data-theme="riso"] .hero__lede,
[data-theme="riso"] .hero__letter-body,
[data-theme="riso"] .spec__rule,
[data-theme="riso"] .tell__why,
[data-theme="riso"] .foot__tagline {
font-family: var(--font-serif);
font-style: italic;
font-weight: 400;
}
[data-theme="riso"] .hero__attrib,
[data-theme="riso"] .label,
[data-theme="riso"] .section-label,
[data-theme="riso"] .banner__center {
text-transform: lowercase;
letter-spacing: 0.02em;
}
[data-theme="riso"] .banner__center {
font-family: var(--font-display);
font-weight: 700;
font-size: var(--text-md);
}
/* Subtle paper grain — a tiny stipple via repeating radial-gradient.
Cheap, no image asset, and disappears under prefers-reduced-data. */
[data-theme="riso"] body::before {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
z-index: 0;
background-image: radial-gradient(circle at 1px 1px, oklch(0% 0 0 / 0.045) 1px, transparent 0);
background-size: 3px 3px;
mix-blend-mode: multiply;
}
@media (prefers-reduced-data: reduce) {
[data-theme="riso"] body::before { display: none; }
}
[data-theme="riso"] .hero__photo-grid > span {
filter: contrast(1.05) saturate(1.4);
}
/* ───────────── HERO ARCHETYPES ─────────────
The hero slot picks one shape per theme, from the cookbook.
Each archetype is a different fingerprint — not a re-skin. */
.hero { display: grid; }
.hero__eyebrow {
display: inline-flex;
align-items: center;
gap: 0.6rem;
font-family: var(--font-label);
font-size: var(--text-xs);
letter-spacing: var(--tracking-label);
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: var(--space-lg);
}
.hero__eyebrow .mark {
width: 6px; height: 6px;
background: var(--color-accent);
display: inline-block;
}
.hero__display {
font-family: var(--font-display);
font-weight: var(--display-weight, 400);
font-style: var(--display-style, normal);
font-size: var(--text-display);
line-height: var(--lh-tight);
letter-spacing: var(--tracking-display);
color: var(--color-ink);
font-optical-sizing: auto;
margin: 0;
}
.hero__display--small {
font-size: var(--text-display-s);
}
.hero__lede {
font-family: var(--font-serif);
font-style: italic;
font-size: var(--text-md);
line-height: var(--lh-normal);
color: var(--color-ink-2);
max-width: 56ch;
margin-block: var(--space-lg) 0;
}
[data-theme="brutal"] .hero__lede,
[data-theme="manifesto"] .hero__lede,
[data-theme="terminal"] .hero__lede,
[data-theme="sport"] .hero__lede,
[data-theme="almanac"] .hero__lede {
font-style: normal;
font-family: var(--font-body);
}
[data-theme="manifesto"] .hero__display,
[data-theme="brutal"] .hero__display,
[data-theme="sport"] .hero__display {
text-transform: uppercase;
}
.hero__link {
margin-top: var(--space-lg);
display: inline-block;
font-family: var(--font-label);
font-size: var(--text-sm);
letter-spacing: var(--tracking-label);
text-transform: uppercase;
}
/* H1 — Marquee. Display fills the fold, install code below. */
.hero--marquee {
padding-block: var(--space-2xl) var(--space-xl);
gap: var(--space-lg);
}
.hero--marquee .hero__display {
max-width: 18ch;
}
.hero--marquee .hero__cta {
margin-top: var(--space-xl);
display: grid;
gap: var(--space-sm);
max-width: 30rem;
}
.hero--marquee .hero__cta .label {
font-family: var(--font-label);
font-size: var(--text-xs);
letter-spacing: var(--tracking-label);
text-transform: uppercase;
color: var(--color-muted);
}
/* H2 — Split Diptych. Title left, proof right. */
.hero--split {
grid-template-columns: 7fr 5fr;
gap: var(--space-2xl);
padding-block: var(--space-2xl) var(--space-xl);
align-items: end;
}
@media (max-width: 60rem) {
.hero--split { grid-template-columns: 1fr; gap: var(--space-xl); align-items: start; }
}
.hero--split .hero__col { display: grid; gap: 0; }
.hero--split .hero__proof {
display: grid;
gap: var(--space-xs);
padding-block-start: var(--space-md);
border-block-start: var(--rule-hair) solid var(--color-rule);
}
.hero--split .hero__proof .label {
font-family: var(--font-label);
font-size: var(--text-xs);
letter-spacing: var(--tracking-label);
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: var(--space-xs);
}
.hero__proof-line {
font-family: var(--font-body);
font-size: var(--text-sm);
color: var(--color-ink-2);
line-height: var(--lh-snug);
font-variant-numeric: tabular-nums;
}
.hero--split .hero__proof a { margin-top: var(--space-sm); }
/* H3 — Stat-Led. Giant number + qualifier. */
.hero--stat {
padding-block: var(--space-2xl) var(--space-xl);
gap: 0;
}
.hero__stat {
font-family: var(--font-display);
font-weight: var(--display-weight, 400);
font-style: var(--display-style, normal);
font-size: clamp(7rem, 22vw, 16rem);
line-height: 0.85;
letter-spacing: -0.04em;
color: var(--color-ink);
font-optical-sizing: auto;
display: block;
margin-block: var(--space-md) 0;
}
.hero__qualifier {
font-family: var(--font-display);
font-weight: var(--display-weight, 400);
font-style: var(--display-style, normal);
font-size: var(--text-2xl);
letter-spacing: var(--tracking-display);
color: var(--color-ink);
margin-block: var(--space-md) 0;
font-optical-sizing: auto;
}
[data-theme="manifesto"] .hero__stat,
[data-theme="sport"] .hero__stat {
color: var(--color-accent);
}
/* H4 — Quote-Led. Pull quote in italic display. */
.hero--quote {
padding-block: var(--space-2xl) var(--space-xl);
max-width: 56rem;
}
.hero__quote {
margin: 0;
padding: 0;
}
.hero__quote p {
font-family: var(--font-serif);
font-style: italic;
font-weight: 400;
font-size: clamp(2.25rem, 4vw + 1rem, 4.25rem);
line-height: 1.08;
letter-spacing: -0.015em;
color: var(--color-ink);
margin: 0;
}
.hero__attrib {
margin-block-start: var(--space-lg);
font-family: var(--font-label);
font-size: var(--text-xs);
letter-spacing: var(--tracking-label);
text-transform: uppercase;
color: var(--color-muted);
}
[data-theme="brutal"] .hero__quote p,
[data-theme="manifesto"] .hero__quote p,
[data-theme="terminal"] .hero__quote p,
[data-theme="sport"] .hero__quote p,
[data-theme="almanac"] .hero__quote p {
font-style: normal;
font-family: var(--font-display);
}
/* H5 — Letter. First-person greeting, paragraph body, signoff. */
.hero--letter {
padding-block: var(--space-2xl) var(--space-xl);
max-width: 52rem;
gap: 0;
}
.hero__salutation {
font-family: var(--font-display);
font-weight: var(--display-weight, 400);
font-style: italic;
font-size: clamp(2rem, 3vw + 1rem, 3.25rem);
line-height: 1.15;
letter-spacing: -0.01em;
color: var(--color-ink);
margin-block: var(--space-md) var(--space-lg);
font-optical-sizing: auto;
}
.hero__letter-body {
font-family: var(--font-serif);
font-size: var(--text-md);
line-height: var(--lh-relaxed);
color: var(--color-ink-2);
max-width: 60ch;
margin: 0;
}
[data-theme="brutal"] .hero__letter-body,
[data-theme="terminal"] .hero__letter-body,
[data-theme="sport"] .hero__letter-body,
[data-theme="almanac"] .hero__letter-body {
font-family: var(--font-body);
}
.hero__signoff {
margin-block: var(--space-xl) 0;
font-family: var(--font-serif);
font-size: var(--text-md);
font-style: italic;
color: var(--color-ink-2);
line-height: var(--lh-snug);
}
.hero__sign {
font-style: normal;
font-family: var(--font-display);
color: var(--color-ink);
letter-spacing: var(--tracking-display);
}
/* H6 — Photographic. Image area + small caption + text below. */
.hero--photo {
padding-block: var(--space-xl) var(--space-xl);
gap: var(--space-xl);
grid-template-columns: 1fr;
}
.hero__photo {
position: relative;
aspect-ratio: 16 / 7;
background: var(--color-paper-2);
border: var(--rule-hair) solid var(--color-rule);
overflow: hidden;
}
.hero__photo-grid {
position: absolute;
inset: 0;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 1px;
background: var(--color-rule);
}
.hero__photo-grid > span {
background: linear-gradient(135deg,
color-mix(in oklch, var(--color-paper-3) 80%, var(--color-accent) 5%),
color-mix(in oklch, var(--color-neutral) 30%, var(--color-paper) 70%));
}
.hero__photo-grid > span:nth-child(2n) { background: linear-gradient(180deg, var(--color-paper-3), var(--color-paper-2)); }
.hero__photo-grid > span:nth-child(3n) { background: linear-gradient(45deg, var(--color-paper-2), var(--color-paper-3)); }
.hero__photo-grid > span:nth-child(5n) { background: linear-gradient(90deg, var(--color-paper-3), color-mix(in oklch, var(--color-accent) 10%, var(--color-paper))); }
.hero__photo-grid > span:nth-child(7n) { background: var(--color-neutral); }
.hero__photo-caption {
position: absolute;
left: var(--space-md);
bottom: var(--space-md);
font-family: var(--font-label);
font-size: var(--text-xs);
letter-spacing: var(--tracking-label);
text-transform: uppercase;
color: var(--color-paper);
background: color-mix(in oklch, var(--color-ink) 78%, transparent);
padding: 0.35rem 0.65rem;
}
.hero__photo-text { display: grid; gap: 0; }
/* H7 — Demo Video Clipped-by-viewport-edge.
Pure-CSS dashboard mockup that extends past the right page edge.
No real video — this is a custom-craft demonstration of the clip layout. */
.hero--clipped {
display: grid;
grid-template-columns: minmax(20rem, 1fr) 1.4fr;
gap: var(--space-2xl);
padding-block: var(--space-2xl) var(--space-xl);
align-items: center;
position: relative;
}
.hero--clipped .hero__copy { display: grid; gap: 0; }
.hero--clipped .hero__display { max-width: 16ch; margin: 0; }
.hero--clipped .hero__lede { max-width: 42ch; }
.hero--clipped .hero__cta { margin-top: var(--space-xl); }
.hero__mock {
width: calc(100% + 12vw); /* the clip — 12% spills past viewport */
max-width: none;
aspect-ratio: 16 / 10;
margin: 0;
border-radius: 14px;
overflow: hidden;
box-shadow: 0 30px 60px -28px oklch(20% 0.02 260 / 0.28),
0 1px 2px oklch(20% 0.02 260 / 0.06);
background: var(--color-paper-2);
border: var(--rule-hair) solid var(--color-rule);
display: flex;
flex-direction: column;
transform: rotate(-0.4deg) translateY(-2px);
transform-origin: left center;
}
.hero__mock-chrome {
display: flex;
align-items: center;
gap: 6px;
padding: 10px 14px;
background: color-mix(in oklch, var(--color-paper-2) 100%, var(--color-rule) 12%);
border-block-end: var(--rule-hair) solid var(--color-rule);
}
.hero__mock-dot {
width: 9px; height: 9px;
border-radius: 50%;
background: color-mix(in oklch, var(--color-rule-2) 80%, transparent);
}
.hero__mock-url {
margin-inline-start: 12px;
font-family: var(--font-mono);
font-size: 0.7rem;
color: var(--color-muted);
letter-spacing: 0.02em;
}
.hero__mock-body {
flex: 1;
display: grid;
grid-template-columns: 56px 1fr;
background: var(--color-paper);
min-height: 0;
}
.hero__mock-rail {
display: flex;
flex-direction: column;
gap: 10px;
padding: 16px 12px;
background: color-mix(in oklch, var(--color-paper) 100%, var(--color-paper-2) 60%);
border-inline-end: var(--rule-hair) solid var(--color-rule);
}
.hero__mock-rail-item {
width: 28px; height: 28px;
border-radius: 6px;
background: color-mix(in oklch, var(--color-rule) 100%, transparent);
}
.hero__mock-rail-item.is-active {
background: var(--color-accent);
opacity: 0.85;
}
.hero__mock-main {
padding: 18px 22px;
display: flex;
flex-direction: column;
gap: 16px;
min-height: 0;
}
.hero__mock-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.hero__mock-row--head { padding-block-end: 4px; }
.hero__mock-bar {
height: 8px;
border-radius: 2px;
background: color-mix(in oklch, var(--color-rule) 80%, transparent);
flex: 1;
}
.hero__mock-bar--lg { height: 12px; max-width: 180px; }
.hero__mock-bar--sm { max-width: 80px; }
.hero__mock-bar--xs { height: 6px; max-width: 56px; }
.hero__mock-bar--short { max-width: 50%; }
.hero__mock-pill {
display: inline-block;
width: 64px; height: 22px;
border-radius: 999px;
background: var(--color-accent);
opacity: 0.18;
}
.hero__mock-grid {
display: grid;
grid-template-columns: 1fr 1fr 1.4fr;
grid-template-rows: 1fr;
gap: 12px;
flex: 1;
min-height: 0;
}
.hero__mock-card {
background: color-mix(in oklch, var(--color-paper) 100%, var(--color-paper-2) 60%);
border: var(--rule-hair) solid var(--color-rule);
border-radius: 8px;
padding: 12px;
display: flex;
flex-direction: column;
gap: 8px;
min-height: 0;
}
.hero__mock-card--accent {
background: color-mix(in oklch, var(--color-paper) 100%, var(--color-accent) 8%);
border-color: color-mix(in oklch, var(--color-accent) 40%, var(--color-rule));
}
.hero__mock-card--wide {
/* spans larger column already */
}
.hero__mock-stat {
font-family: var(--font-display);
font-weight: 600;
font-size: 1.75rem;
letter-spacing: -0.02em;
color: var(--color-ink);
font-variant-numeric: tabular-nums;
line-height: 1;
}
.hero__mock-spark {
flex: 1;
background:
linear-gradient(95deg,
transparent 0 6%,
var(--color-accent) 6% 7%,
transparent 7% 14%,
var(--color-accent) 14% 15%,
transparent 15% 28%,
var(--color-accent) 28% 29%,
transparent 29% 42%,
var(--color-accent) 42% 43%,
transparent 43% 60%,
var(--color-accent) 60% 61%,
transparent 61% 80%,
var(--color-accent) 80% 81%,
transparent 81% 100%);
opacity: 0.55;
border-radius: 4px;
min-height: 36px;
align-self: stretch;
}
.hero__mock-rows { display: flex; flex-direction: column; gap: 8px; }
@media (max-width: 60rem) {
.hero--clipped { grid-template-columns: 1fr; gap: var(--space-xl); }
.hero__mock { width: 100%; transform: none; aspect-ratio: 16 / 11; }
}
@media (prefers-reduced-motion: reduce) {
.hero__mock { transform: none; }
}
/* ───────────── FOOTER ARCHETYPES ───────────── */
.foot { display: grid; gap: var(--space-md); padding-block: var(--space-2xl) var(--space-xl); border-block-start: var(--rule-hair) solid var(--color-rule); }
/* Ft1 — Masthead. Wordmark + tagline + links + powered. */
.foot--masthead {
grid-template-columns: 1fr;
gap: var(--space-md);
align-items: start;
}
.foot__wordmark {
font-family: var(--font-display);
font-weight: var(--display-weight, 400);
font-style: var(--display-style, normal);
font-size: var(--text-3xl);
letter-spacing: var(--tracking-display);
color: var(--color-ink);
font-optical-sizing: auto;
line-height: 1;
}
[data-theme="manifesto"] .foot__wordmark,
[data-theme="brutal"] .foot__wordmark,
[data-theme="sport"] .foot__wordmark { text-transform: uppercase; }
.foot__tagline {
font-family: var(--font-serif);
font-style: italic;
font-size: var(--text-md);
color: var(--color-ink-2);
max-width: 50ch;
margin: 0;
line-height: var(--lh-snug);
}
[data-theme="brutal"] .foot__tagline,
[data-theme="manifesto"] .foot__tagline,
[data-theme="terminal"] .foot__tagline,
[data-theme="sport"] .foot__tagline,
[data-theme="almanac"] .foot__tagline {
font-style: normal;
font-family: var(--font-body);
}
.foot__links {
display: flex;
flex-wrap: wrap;
gap: var(--space-md);
margin-block-start: var(--space-md);
font-family: var(--font-label);
font-size: var(--text-sm);
letter-spacing: 0.04em;
}
.foot__powered {
margin-block-start: var(--space-lg);
font-family: var(--font-label);
font-size: var(--text-xs);
letter-spacing: var(--tracking-label);
text-transform: uppercase;
color: var(--color-muted);
}
.foot__powered-mark {
color: var(--color-ink);
font-weight: 500;
}
/* Ft2 — Inline. Single dense line. */
.foot--inline {
grid-template-columns: 1fr;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-md);
font-family: var(--font-label);
font-size: var(--text-xs);
letter-spacing: var(--tracking-label);
text-transform: uppercase;
color: var(--color-muted);
}
.foot__wordmark-small {
color: var(--color-ink);
font-weight: 500;
letter-spacing: 0.22em;
}
.foot__sep {
width: 1px; height: 12px; background: var(--color-rule-2);
}
/* Ft3 — Index columns. */
.foot--index {
grid-template-columns: repeat(4, 1fr);
gap: var(--space-xl);
}
@media (max-width: 60rem) {
.foot--index { grid-template-columns: repeat(2, 1fr); }
}
.foot__col-head {
font-family: var(--font-label);
font-size: var(--text-xs);
letter-spacing: var(--tracking-label);
text-transform: uppercase;
color: var(--color-muted);
margin-block-end: var(--space-sm);
padding-block-end: var(--space-xs);
border-block-end: var(--rule-hair) solid var(--color-rule);
}
.foot--index ul {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: var(--space-2xs);
font-family: var(--font-body);
font-size: var(--text-sm);
color: var(--color-ink-2);
}
/* Ft4 — Dense colophon (monospace). */
.foot--dense {
font-family: var(--font-mono);
font-size: var(--text-xs);
line-height: 1.7;
color: var(--color-ink-2);
white-space: pre-wrap;
margin: 0;
padding-block: var(--space-md);
}
/* ───────────── SLOT REVEALS ─────────────
The slot fades when its archetype is replaced — supplements the
View Transition and gives a graceful enter on first paint. */
.slot[data-populating] > * {
animation: slot-in calc(var(--dur-long) * 0.7) var(--ease-out) forwards;
opacity: 0;
}
@keyframes slot-in { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
.slot[data-populating] > * { animation: none; opacity: 1; }
}
/* ───────────── QUIET — restraint as the design ─────────────
Override every "expressive" treatment on the page when Quiet is active.
No reveals, no per-theme display weight tricks, no shadow glows.
System fonts inherit naturally; just make sure nothing yells. */
[data-theme="quiet"] .reveal,
[data-theme="quiet"] .reveal.is-in,
[data-theme="quiet"] .slot[data-populating] > * {
opacity: 1;
transform: none;
animation: none;
}
[data-theme="quiet"] .hero__display,
[data-theme="quiet"] .hero__quote p,
[data-theme="quiet"] .hero__stat,
[data-theme="quiet"] .section__title,
[data-theme="quiet"] .foot__wordmark,
[data-theme="quiet"] .spec__name,
[data-theme="quiet"] .tell__name {
font-family: var(--font-display);
font-weight: 500;
font-style: normal;
text-transform: none;
letter-spacing: -0.015em;
text-shadow: none; /* override Riso's off-register if a user toggled */
}
[data-theme="quiet"] .hero__lede,
[data-theme="quiet"] .hero__letter-body,
[data-theme="quiet"] .spec__rule,
[data-theme="quiet"] .tell__why,
[data-theme="quiet"] .foot__tagline {
font-family: var(--font-body);
font-style: normal;
color: var(--color-neutral);
}
[data-theme="quiet"] .hero__salutation {
font-family: var(--font-body);
font-style: normal;
font-weight: 500;
font-size: var(--text-xl);
letter-spacing: 0;
}
[data-theme="quiet"] .hero__sign,
[data-theme="quiet"] .hero__signoff {
font-family: var(--font-body);
font-style: normal;
}
[data-theme="quiet"] .banner__center {
font-family: var(--font-display);
font-weight: 500;
font-size: var(--text-sm);
letter-spacing: 0;
text-transform: none;
}
[data-theme="quiet"] .banner {
background: color-mix(in oklch, var(--color-paper) 92%, transparent);
}
/* No reveal animation on Quiet — the page is intentionally still. */
[data-theme="quiet"] .hero,
[data-theme="quiet"] .hero > * {
animation: none !important;
}
/* Quiet's hero never shows the clipped mockup — even if forced. */
[data-theme="quiet"] .hero--clipped .hero__mock { display: none; }
[data-theme="quiet"] .hero--clipped { grid-template-columns: 1fr; }