From ead4864c00ec1f5e30f32fb59dda34d57e136151 Mon Sep 17 00:00:00 2001 From: Benoit TRAVERS Date: Thu, 16 Jul 2026 01:52:08 +0200 Subject: [PATCH 1/4] =?UTF-8?q?feat(design):=20Beetroot=20Nocturne=20?= =?UTF-8?q?=E2=80=94=20dark=20atmospheric=20exploration=20(v4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original identity, elevated: deep plum canvas built for the dark, two ambient beetroot blooms (fixed, accent-derived), weighty Geist display, elevation through lightness instead of borders, warm glow on hover, and the gradient mascot floating as the one character moment. Exploration branch — sibling of the approved Beetroot Atlas (#29). - theme: dark-canonical plum scheme refined (light stays the daylight fallback), Geist + JetBrains Mono replace Montserrat, bloom tokens, glow shadows, no gradient text. Semantic token API and the one-knob --accent contract unchanged (minor bump, changeset included). - landing: Marquee Hero — the fold is the canvas (mascot + statement + scroll cue), then intro + pill CTAs, elevated package panels, quiet numbered columns, bloom-lit "why now" cluster, inspiration cards, statement footer. All copy preserved. - logos: original gradient marks kept — they were drawn for this canvas. - design.md: the locked design system for this candidate. --- .changeset/beetroot-nocturne-rebrand.md | 10 + .hallmark/log.json | 50 ++ apps/website/.vitepress/theme/Landing.vue | 600 ++++++++++++---------- design.md | 126 +++++ packages/theme/src/fonts.css | 9 +- packages/theme/src/style.css | 140 +++-- packages/theme/src/tokens.css | 174 ++++--- 7 files changed, 676 insertions(+), 433 deletions(-) create mode 100644 .changeset/beetroot-nocturne-rebrand.md create mode 100644 .hallmark/log.json create mode 100644 design.md diff --git a/.changeset/beetroot-nocturne-rebrand.md b/.changeset/beetroot-nocturne-rebrand.md new file mode 100644 index 0000000..4094dd2 --- /dev/null +++ b/.changeset/beetroot-nocturne-rebrand.md @@ -0,0 +1,10 @@ +--- +"@btravstack/theme": minor +--- + +Beetroot Nocturne rebrand — the original identity, elevated: built for the dark. + +- Deep plum canvas (`oklch(17% 0.024 305)`) stays the canonical dark-default; the light scheme remains the daylight fallback. +- Typography: Geist (display 600/700 + body) + JetBrains Mono replace Montserrat. +- Atmosphere with discipline: ambient beetroot blooms (fixed, never animated, accent-derived so they recolor per site), elevation through surface lightness instead of card borders, warm accent glow on hover, solid ink hero name (no gradient text), floating hero mark kept as the one character moment. +- Non-breaking: all semantic tokens keep their names and the one-knob rebrand contract is unchanged — consumer sites still override only `--accent` (`:root:root { --accent: … }`) and every derived shade (blooms included) follows via `color-mix`. diff --git a/.hallmark/log.json b/.hallmark/log.json new file mode 100644 index 0000000..467a823 --- /dev/null +++ b/.hallmark/log.json @@ -0,0 +1,50 @@ +[ + { + "date": "2026-07-16", + "scope": "app", + "macrostructure": "Marquee Hero", + "theme": "custom", + "theme_axes": "dark / geometric-sans / chromatic-other (beetroot-pink ~353)", + "vibe": "late-night plum, warm bloom, velvet, exact", + "enrichment": "H9 original gradient mascot (Tier-B, kept) + two fixed blooms", + "nav": "N5 floating pill", + "footer": "Ft5 statement", + "brief": "btravstack org rebrand v4 — Beetroot Nocturne (dark atmospheric); exploration branch, sibling of approved v3 Atlas" + }, + { + "date": "2026-07-16", + "scope": "app", + "macrostructure": "Catalogue", + "theme": "custom", + "theme_axes": "light / high-contrast-serif / chromatic-other (beetroot-pink ~353)", + "vibe": "botanical atlas, engraved plates, warm ivory, exact", + "enrichment": "Tier-B hand-built SVG engravings (plates + full logo set)", + "nav": "N9 edge-aligned", + "footer": "Ft1 mast-headed", + "brief": "btravstack org rebrand v3 — Beetroot Atlas (LIKED by user; PR #29, branch design/beetroot-atlas)" + }, + { + "date": "2026-07-16", + "scope": "app", + "macrostructure": "Bento Grid", + "theme": "custom", + "theme_axes": "light / rounded-sans / chromatic-other (beetroot-pink ~353)", + "vibe": "warm, rounded, charming beetroot, soft-but-exact", + "enrichment": "H9 original gradient mascot (Tier-B, restored)", + "nav": "N1b", + "footer": "Ft8 marquee", + "brief": "btravstack org rebrand v2 — Beetroot Soft (REJECTED by user; PR #28)" + }, + { + "date": "2026-07-16", + "scope": "app", + "macrostructure": "Manifesto", + "theme": "custom", + "theme_axes": "light / display-heavy / chromatic-other (beetroot-pink ~353)", + "vibe": "beetroot risograph, contract-as-document, raw, technical", + "enrichment": "Tier-B hand-built SVG (flat riso logo set)", + "nav": "N7 brutal slab", + "footer": "Ft4 dense colophon", + "brief": "btravstack org rebrand v1 — Beetroot Riso (REJECTED by user; PR #27)" + } +] diff --git a/apps/website/.vitepress/theme/Landing.vue b/apps/website/.vitepress/theme/Landing.vue index 5c7c877..d8b0bb6 100644 --- a/apps/website/.vitepress/theme/Landing.vue +++ b/apps/website/.vitepress/theme/Landing.vue @@ -106,354 +106,400 @@ onMounted(() => { diff --git a/design.md b/design.md new file mode 100644 index 0000000..ecc619d --- /dev/null +++ b/design.md @@ -0,0 +1,126 @@ +# Design — btravstack · "Beetroot Nocturne" + +A locked design system for the btravstack org (landing + `@btravstack/theme` + +the four docs sites). Every page redesign reads this file before emitting code. +Do not regenerate per page — extend or amend this file when the system needs to +grow. + +**The idea.** The original identity, elevated. A deep plum canvas built for the +dark, two warm beetroot blooms, a weighty geometric sans, elevation through +lightness instead of borders, warm glow on interaction, and the gradient +mascot floating as the one character moment per page. (This is the dark +atmospheric candidate — the sibling of "Beetroot Atlas" on +`design/beetroot-atlas`; one of the two ships.) + +## Genre + +atmospheric. Vibe: *"late-night plum, warm bloom, velvet, exact"*. + +## Macrostructure family + +- Marketing pages (landing): **Marquee Hero** — the fold is the canvas + (mascot + one statement + scroll cue, nothing else), a thick accent-wash + rule, then intro + CTAs, elevated package panels, quiet numbered columns, + a bloom-lit "why now" cluster, inspiration cards, closing CTA. +- Docs sites (VitePress content): default VitePress layout wearing the theme + tokens — floating hero mark, one ambient bloom top-right, elevated feature + cards with glow hover. +- Nav: **N5 floating pill** — content-sized, detached, blur backdrop over the + bloom. +- Footer: **Ft5 statement** — one large display sentence + a quiet meta row. + +## Theme + +**Dark "nocturne" is canonical** — the page is built for the dark. Light is +the daylight fallback on `:root:not(.dark)`. + +| Token | Dark (canonical) | Light | +| --- | --- | --- | +| `--bg` (canvas) | `oklch(17% 0.024 305)` deep plum | `#FBF7F9` warm near-white | +| `--card` | `oklch(20.5% 0.026 305)` — elevation step 1 | `#FFFFFF` | +| `--card-soft` | `oklch(24% 0.027 305)` — elevation step 2 | `#F0E6EC` | +| `--text` | `oklch(94% 0.008 340)` | `#1F0E18` | +| `--accent` | **#E0589A** = `oklch(65.5% 0.182 353)` — THE knob | same (fills stay vibrant) | +| `--text-accent` | `var(--accent)` (reads on plum) | accent darkened 26% (AA) | +| `--bloom` / `--bloom-2` | accent at 15% / deep at 13% — radial only | 11% / 8% | + +**One-knob rebrand is contractual.** Docs sites override only `--accent` +(`:root:root { --accent: … }`); every derived shade — including the blooms — +flows via `color-mix`. amqp `#FF6600` · temporal `#6B76F2` · unthrown +`#46B86C` · demesne `#B45CE0`. + +Bloom discipline: at most two per page, radial, fixed, never animated, +~20–30% footprint each. Accent fills only on pill CTAs and small tags. + +## Typography + +- Display + body: **Geist** — one weighty family (display 600/700, tracking + −0.03em; body 400/500). The single-family voice is the atmospheric register. +- Mono (outlier): **JetBrains Mono** — code, identifiers, numerals, star counts. +- Statement scale: `--fs-hero: clamp(42px, 5.5vw + 12px, 84px)`. +- Never italic headers, never gradient text. + +## Spacing / shape + +Named px scale in `packages/theme/src/tokens.css` (`--space-1…6`). Corners: +rounded (12–16px cards, 999px pills). **No hairline card borders** — elevation +comes from surface lightness (`--card`, `--card-soft`); hairlines only as +page-level dividers. Shadows: darkness for depth at rest, warm accent glow +(`--shadow-accent`) on hover. + +## Motion + +- Easings: `--ease: cubic-bezier(0.16, 1, 0.3, 1)`; durations ≤ 0.2s. +- Three primitives: the mascot bob (character moment), hover lift + glow on + interactive cards, the copy toast. Fade only otherwise — no slide, no bounce. +- Blooms never move. Reduced-motion: bob stops, transitions collapse. + +## Microinteractions stance + +- Silent success (copy button → small mono toast, 1.6s). +- Hover tooltips 800ms · focus 0ms. Focus rings instant, 2px accent. + +## CTA voice + +- Primary: confident accent-filled pill, ink text, Geist 600. One per view. +- Secondary: outlined pill, transparent fill. + +## Logos + +The original soft gradient marks are the canon here — they were drawn for +this dark canvas (mascot, rabbit, hourglass, no-throw, shield). Keep the +gradients; keep the rounded warmth. + +## What pages MUST share + +- The wordmark voice (Geist 700, "btrav" in accent + "stack" in ink). +- The one-knob accent architecture and bloom discipline. +- Geist + JetBrains Mono, pill CTAs, elevation-not-borders. +- Exactly one character moment (the floating mascot) per page. + +## What pages MAY differ on + +- Macrostructure within the family (a future page may be Feature Stack or + Split Studio — still wearing this theme). +- Per-site accent hue (docs sites) — blooms recolor automatically. +- Docs sites keep VitePress's functional layout; only the dress is shared. + +## Exports + +### tokens.css +The canonical export lives at `packages/theme/src/tokens.css` (published as +`@btravstack/theme`). It is the single source of truth; do not duplicate here. + +### Quick-reference (other projects) +```css +:root { + --color-paper: oklch(17% 0.024 305); + --color-ink: oklch(94% 0.008 340); + --color-accent: #E0589A; + --font-display: "Geist", sans-serif; + --font-body: "Geist", sans-serif; + --font-mono: "JetBrains Mono", monospace; + --ease: cubic-bezier(0.16, 1, 0.3, 1); + --radius-card: 16px; +} +``` diff --git a/packages/theme/src/fonts.css b/packages/theme/src/fonts.css index 39e3d6d..f71db08 100644 --- a/packages/theme/src/fonts.css +++ b/packages/theme/src/fonts.css @@ -1,6 +1,7 @@ /* - * btravstack web fonts. Montserrat (display/UI) + JetBrains Mono (code). - * Loaded from Google Fonts so the system stays zero-asset and portable; - * the weights here match the --fw-* tokens in tokens.css. + * btravstack web fonts — the "Beetroot Nocturne" pairing. + * Geist (display 600/700 + body 400/500 — one weighty family) + * JetBrains Mono (code + labels) + * Loaded from Google Fonts so the system stays zero-asset and portable. */ -@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap'); diff --git a/packages/theme/src/style.css b/packages/theme/src/style.css index 3afaf6d..a855924 100644 --- a/packages/theme/src/style.css +++ b/packages/theme/src/style.css @@ -1,13 +1,16 @@ +/* Hallmark · genre: atmospheric · design-system: design.md · designed-as-app + * scope: VitePress chrome mapping for all btravstack sites (docs + landing shell) + */ + /* - * @btravstack/theme — VitePress style entry. + * @btravstack/theme — VitePress style entry ("Beetroot Nocturne"). * * Maps the btravstack design tokens onto VitePress's own `--vp-*` variables so * every btravstack site (the website + the docs sites) shares one look. * Because the semantic tokens (--bg, --text, --text-accent, …) flip per scheme * in tokens.css, this mapping is written once and adapts automatically: - * - dark → the btravstack plum surfaces, pink links - * - light → clean warm-white surfaces, brand darkened to deep beetroot - * (--text-accent) so links/headings pass WCAG-AA on white + * - dark → the deep plum nocturne canvas, vibrant pink links (canonical) + * - light → warm near-white surfaces, deep-beet links (WCAG-AA) * * The `:root:root` selector raises specificity to (0,2,0) so the mapping wins * over VitePress's own `:root` / `.dark` defaults regardless of load order. @@ -38,8 +41,7 @@ --vp-c-brand-soft: color-mix(in srgb, var(--accent) 16%, transparent); --vp-c-brand: var(--text-accent); /* legacy alias */ - /* Inline code — accent-as-text so it stays readable on the (scheme-aware) - code inset: pink on dark, deep beetroot on the light code wash */ + /* Inline code — accent-as-text on the scheme-aware code inset */ --vp-code-color: var(--text-accent); --vp-code-bg: var(--code-bg); @@ -65,92 +67,79 @@ --vp-custom-block-warning-border: var(--accent-line); --vp-custom-block-warning-text: var(--text-accent); - /* Home hero: gradient name + accent glow behind the logo */ - --vp-home-hero-name-color: transparent; - --vp-home-hero-name-background: linear-gradient(120deg, var(--text-accent), var(--accent-soft)); - --vp-home-hero-image-background-image: radial-gradient(closest-side, color-mix(in srgb, var(--accent) 30%, transparent), transparent 72%); + /* Home hero: solid ink name (no gradient text) + a warm bloom that tracks + the floating mark wherever the layout places it. */ + --vp-home-hero-name-color: var(--vp-c-text-1); + --vp-home-hero-name-background: none; + --vp-home-hero-image-background-image: radial-gradient(closest-side, color-mix(in srgb, var(--accent) 26%, transparent), transparent 72%); --vp-home-hero-image-filter: blur(8px); } -/* ── Playful flourishes — shared across every btravstack site ───── */ +/* ── Nocturne chrome — shared across every btravstack site ─────── */ + +/* No horizontal scroll, ever (clip — not hidden — so sticky keeps working). */ +html, body { overflow-x: clip; } + +/* Weighty display voice on the big headings. */ +.VPHero .name, +.VPHero .text { font-family: var(--display); letter-spacing: var(--tracking-hero); } +.VPHero .name { font-weight: 700; } +.VPFeature .title { letter-spacing: var(--tracking-snug); } +.VPNavBar .title { font-weight: 700; } -/* Home hero: a gently floating logo. The beetroot glow lives BEHIND the hero - image itself (--vp-home-hero-image-background-image, set above) so it tracks - the logo wherever the layout places it. We deliberately do NOT add a separate - centered ::before glow: the landing page uses its own bespoke layout (not - .VPHome), and on the docs sites the default home hero is left-aligned with the - image on the right — a hard-centered glow there just floats, disconnected. */ -.VPHome { overflow-x: clip; } -.VPHero .image-container { animation: btv-floaty 6s ease-in-out infinite; } +/* Home hero: the gently floating mark — the one character moment per page. */ +.VPHome { overflow-x: clip; position: relative; } +.VPHero .image-container { animation: btv-floaty 6s var(--ease) infinite; } .VPHero .image-src { filter: drop-shadow(0 18px 40px color-mix(in srgb, var(--accent-deep) 45%, transparent)); } -@keyframes btv-floaty { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } } - -/* Navbar logo: VitePress's 24px mark reads as a speck next to the wordmark. - Size it up through VitePress's own variable (--vp-nav-logo-height) rather than - overriding `.logo { height }` — VitePress sets the height from a scoped - `:deep(.logo)` selector that out-specifies a plain `.VPNavBarTitle .logo`, so - the variable is the only reliable lever. Spacing stays on the logo's default - margin (no extra `gap`, which would compound with it). - Light/dark switching is left to VitePress: with `logo: { light, dark }` per - repo, its native .VPImage class toggle already shows the right artwork. */ +@keyframes btv-floaty { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } } + +/* One ambient bloom bleeding off the docs-home top-right (genre-sanctioned). */ +.VPHome { position: relative; } +.VPHome::before { + content: ""; + position: absolute; top: -40px; right: -120px; z-index: 0; + width: 620px; height: 620px; max-width: 85vw; + background: radial-gradient(closest-side, var(--bloom), transparent 70%); + pointer-events: none; +} +.VPHome .VPHero, +.VPHome .VPFeatures { position: relative; z-index: 1; } + +/* Navbar logo sizing via VitePress's own variable. */ :root:root { --vp-nav-logo-height: 34px; } @media (max-width: 768px) { :root:root { --vp-nav-logo-height: 28px; } } -/* Home hero: tighten the display type. (The hero `image:` is one file per repo, - set in index.md frontmatter; for a crisp mark in both schemes make it - scheme-aware there — hero.image.light / hero.image.dark.) */ -.VPHero .name { letter-spacing: -1.5px; } -.VPHero .text { letter-spacing: -0.5px; } - -/* Feature cards: hairline border + a soft lift on hover, echoing the landing - page's package cards; brand-tinted icon chip. */ +/* Feature cards: elevation through lightness + a warm glow on hover. */ .VPFeature { - border: 1px solid var(--vp-c-divider); + border: 1px solid transparent; border-radius: var(--radius-lg); - transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease; + transition: transform var(--speed) var(--ease), box-shadow var(--speed) var(--ease); } .VPFeature:hover { - transform: translateY(-4px); - border-color: var(--vp-c-border); - box-shadow: var(--shadow-card); + transform: translateY(-3px); + box-shadow: var(--shadow-accent); } .VPFeature .icon { border-radius: var(--radius) !important; background: var(--vp-c-brand-soft) !important; - border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent); + border: 1px solid var(--accent-line); } -.VPFeature .title { letter-spacing: -0.3px; } -/* Brand buttons: springy hover */ -.VPButton.brand { transition: filter 0.15s, transform 0.15s; } -.VPButton.brand:hover { filter: brightness(1.07); transform: translateY(-1px); } +/* Brand buttons: confident pill, quiet press. */ +.VPButton { font-weight: 600; } +.VPButton.brand { transition: background-color var(--speed-fast) var(--ease), transform var(--speed-fast) var(--ease); } +.VPButton.brand:hover { transform: translateY(-1px); } +.VPButton.brand:active { transform: translateY(0); } -/* Rounder, pinker code */ +/* Rounded code + admonitions. */ .vp-doc :not(pre) > code { border-radius: 7px; } .vp-doc div[class*="language-"] { border-radius: var(--radius); } .vp-doc .custom-block { border-radius: var(--radius); } -/* ── Home hero: a bigger mark + a large accent glow shape ───────── - The default hero only has a small glow hugging the logo; the docs - mockups show a broad accent wash bleeding off the top-right. */ -/* position: relative only — the existing `.VPHome { overflow-x: clip }` above - handles the glow's horizontal bleed; a full `overflow: clip` here would also - clip vertical content like the feature-card hover-lift shadows. */ -.VPHome { position: relative; } -.VPHome::before { - content: ""; - position: absolute; top: -40px; right: -120px; z-index: 0; - width: 620px; height: 620px; max-width: 85vw; - background: radial-gradient(closest-side, color-mix(in srgb, var(--accent) 16%, transparent), transparent 70%); - pointer-events: none; -} -.VPHome .VPHero, -.VPHome .VPFeatures { position: relative; z-index: 1; } +/* Hero mark sizing on docs homes (all project logos are square). */ @media (min-width: 960px) { .VPHero .image-container { width: 340px; height: 340px; } .VPHero .image-bg { width: 100%; height: 100%; } - /* the mark ships at a small intrinsic size, so stretch it explicitly - (all project logos are square) rather than relying on max-width */ .VPHero .image-src { width: 300px; height: 300px; @@ -160,10 +149,17 @@ } } +/* Focus is a first-class state — instant, visible, never animated. */ +:focus-visible { + outline: 2px solid var(--focus); + outline-offset: 2px; + transition: none; +} + /* ── "Part of btravstack" org-attribution strip (layout-bottom slot) ── */ .btv-partof { - border-top: 1px solid var(--vp-c-divider); - background: var(--vp-c-bg-alt); + border-top: 1px solid var(--border); + background: var(--card); padding: 16px 24px; display: flex; justify-content: center; @@ -176,18 +172,18 @@ font-weight: 600; color: var(--vp-c-text-3); text-decoration: none; - transition: color 0.15s; + transition: color var(--speed-fast) var(--ease); } -.btv-partof-link:hover { color: var(--vp-c-text-2); } +.btv-partof-link:hover { color: var(--vp-c-text-1); } .btv-partof-link:focus-visible { - outline: 2px solid var(--accent); + outline: 2px solid var(--focus); outline-offset: 3px; border-radius: 4px; color: var(--vp-c-text-1); } .btv-partof-mark { display: inline-flex; line-height: 0; } .btv-partof-word { font-weight: 700; letter-spacing: -0.3px; color: var(--vp-c-text-2); } -.btv-partof-pink { color: var(--bt-pink); } +.btv-partof-pink { color: var(--text-accent); } @media (prefers-reduced-motion: reduce) { .VPHero .image-container { animation: none; } diff --git a/packages/theme/src/tokens.css b/packages/theme/src/tokens.css index 5167a3a..55f453d 100644 --- a/packages/theme/src/tokens.css +++ b/packages/theme/src/tokens.css @@ -1,17 +1,27 @@ +/* Hallmark · genre: atmospheric · macrostructure: Marquee Hero · design-system: design.md · designed-as-app + * theme: custom · vibe: "late-night plum, warm bloom, velvet, exact" + * paper: oklch(17% 0.024 305) DARK-canonical · accent: #E0589A (oklch(65.5% 0.182 353)) + * display: Geist 600/700 · body: Geist 400 · outlier: JetBrains Mono + * axes: dark / geometric-sans / chromatic-other (beetroot-pink ~353°) + * nav: N5 floating pill · footer: Ft5 statement · studied: no · context: user-provided + * pre-emit critique: P4 H4 E4 S4 R4 V5 + */ + /* - * btravstack design tokens — the single source of truth. + * btravstack design tokens — the single source of truth ("Beetroot Nocturne"). * - * Mirrors the btravstack Design System (tokens/colors.css, themes.css, - * typography.css, spacing.css). Reference the SEMANTIC tokens (--bg, --text, - * --accent, --text-accent, --radius, --space-*) in app code; the raw --bt-* - * palette underneath is the provenance, exposed so adapters (e.g. VitePress) - * can remap freely. + * The original identity, elevated: deep plum canvas with two warm beetroot + * blooms, a weighty geometric sans, elevation through lightness (no hairline + * card borders), glow-tinted hover shadows, one floating character moment. + * Reference the SEMANTIC tokens (--bg, --text, --accent, --text-accent, + * --radius, --space-*) in app code; the raw --bt-* palette underneath is the + * provenance. * - * Dark is the canonical default. The light scheme overrides the semantic - * tokens; it activates on `:root:not(.dark)` (VitePress's appearance system) - * as well as an explicit `.light` / `[data-theme="light"]`. + * DARK is the canonical default — the page is built for the dark. The light + * scheme overrides the semantic tokens; it activates on `:root:not(.dark)` + * (VitePress's appearance system) as well as `.light` / `[data-theme=light]`. * - * Fills vs text: keep --accent / --green for FILLS (buttons, glow, washes); + * Fills vs text: keep --accent / --green for FILLS (buttons, blooms, washes); * use --text-accent / --text-green for COLORED TEXT and icons — light mode * darkens those to deep beetroot so links/labels pass WCAG-AA on white. */ @@ -26,92 +36,95 @@ --bt-leaf-dark: #2C8B4E; /* side leaves */ --bt-green: #46B86C; /* "success" green (checks) */ --bt-cream: #F5EFF3; /* near-white text */ - --bt-ink: #1a0c14; /* near-black, for text on accent */ + --bt-ink: #1A0C14; /* near-black, for text on accent */ - /* ── Surfaces (dark scheme — the canonical btravstack look) ───── */ - --bg: #15101c; - --bg-grad: #1b1326; /* radial hero glow inner stop */ - --card: #1d1726; - --card-soft: #241c31; + /* ── Surfaces (DARK scheme — canonical: the nocturne canvas) ─── */ + --bg: oklch(17% 0.024 305); /* deep plum ≈ #150f1d */ + --bg-grad: oklch(20% 0.028 310); /* bloom inner stop */ + --card: oklch(20.5% 0.026 305); /* elevation step 1 */ + --card-soft: oklch(24% 0.027 305); /* elevation step 2 */ - /* ── Borders / dividers ──────────────────────────────────────── */ - --border: rgba(255, 255, 255, 0.08); - --border-2: rgba(255, 255, 255, 0.12); + /* ── Dividers — used sparingly; elevation carries structure ──── */ + --border: color-mix(in srgb, var(--text) 9%, transparent); + --border-2: color-mix(in srgb, var(--text) 15%, transparent); /* ── Text ────────────────────────────────────────────────────── */ - --text: #F5EFF3; - --muted: #AEA1BC; - --faint: #7E7290; + --text: oklch(94% 0.008 340); + --muted: oklch(74% 0.015 330); + --faint: oklch(61% 0.015 320); - /* ── Accent — the single brand knob (v1.4.0) ───────────────────── + /* ── Accent — the single brand knob ────────────────────────────── Set ONE value, `--accent`, and the whole theme rebrands: the deep, hover, soft and wash shades below all derive from it via color-mix, - so a consumer site needs only `:root { --accent: #FF6600 }`. The - beetroot pink here is the default (the btravstack org brand); the - docs sites override it with their own accent. - (Optional finer knobs: override --text-accent for a hand-tuned - light-mode AA link color, or --accent-contrast for ink on the fill.) */ + so a consumer site needs only `:root:root { --accent: #FF6600 }`. + The beetroot pink here is the default (the btravstack org brand); + the docs sites override it with their own accent. */ --accent: #E0589A; /* ← the knob */ - --accent-contrast: #1a0c14; /* readable text on an accent fill */ - --accent-deep: color-mix(in srgb, var(--accent), #000 42%); /* deep root — active/press */ - --accent-hover: color-mix(in srgb, var(--accent), #000 18%); /* button hover fill */ - --accent-soft: color-mix(in srgb, var(--accent) 62%, #fff); /* highlight vein / brand-2 */ - --accent-rgb: 224, 88, 154; /* legacy: prefer color-mix over rgba(var(--accent-rgb),…) */ + --accent-contrast: #1A0C14; /* readable text on an accent fill */ + --accent-deep: color-mix(in srgb, var(--accent), #000 42%); /* active/press */ + --accent-hover: color-mix(in srgb, var(--accent), #000 16%); /* fill hover */ + --accent-soft: color-mix(in srgb, var(--accent) 62%, #fff); /* highlight vein */ + --accent-rgb: 224, 88, 154; /* legacy: prefer color-mix */ --green: #46B86C; --green-rgb: 70, 184, 108; - /* ── Accent-as-TEXT (split from fill; light darkens it for AA) ─── */ - --text-accent: var(--accent); /* on dark plum the accent reads fine as text */ + /* ── Accent-as-TEXT (split from fill; light darkens it for AA) ── */ + --text-accent: var(--accent); /* on deep plum the accent reads fine as text */ --text-green: #46B86C; - /* Display accent — the accent as the LARGE display wordmark color in - both schemes (large text only needs 3:1, so it can stay fully vibrant). */ + /* Display accent — the accent as the LARGE display wordmark color. */ --display-accent: var(--accent); - /* ── Glass (frosted sticky headers) ──────────────────────────── */ - --glass: rgba(21, 16, 28, 0.66); + /* ── Focus — instant, never animated ─────────────────────────── */ + --focus: var(--accent); + + /* ── Glass (the floating-pill nav backdrop) ──────────────────── */ + --glass: color-mix(in srgb, var(--bg) 72%, transparent); - /* ── Accent washes / lines / code inset ──────────────────────── */ + /* ── Blooms / washes / lines / code inset ────────────────────── */ + --bloom: color-mix(in srgb, var(--accent) 15%, transparent); /* radial bloom core */ + --bloom-2: color-mix(in srgb, var(--accent-deep) 13%, transparent); --accent-wash: color-mix(in srgb, var(--accent) 10%, transparent); --accent-wash-2: color-mix(in srgb, var(--accent) 16%, transparent); - --accent-line: color-mix(in srgb, var(--accent) 25%, transparent); + --accent-line: color-mix(in srgb, var(--accent) 26%, transparent); --code-bg: rgba(0, 0, 0, 0.35); /* inline code inset */ - /* ── Typography: families ────────────────────────────────────── */ - --sans: 'Montserrat', 'Segoe UI', system-ui, sans-serif; - --mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace; + /* ── Typography: families (weighty sans + mono — see design.md) ─ */ + --display: 'Geist', 'Segoe UI', system-ui, sans-serif; + --sans: 'Geist', 'Segoe UI', system-ui, sans-serif; + --mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace; /* ── Typography: weights ─────────────────────────────────────── */ --fw-medium: 500; --fw-semibold: 600; --fw-bold: 700; - --fw-extrabold: 800; + --fw-extrabold: 700; /* ── Typography: display / heading scale (clamped, fluid) ─────── */ - --fs-hero: clamp(52px, 9vw, 92px); + --fs-hero: clamp(42px, 5.5vw + 12px, 84px); --fs-h1: clamp(34px, 6vw, 56px); - --fs-h2: clamp(28px, 4vw, 40px); - --fs-h3: 23px; - --fs-h4: 18px; + --fs-h2: clamp(26px, 3.4vw, 36px); + --fs-h3: 21px; + --fs-h4: 17px; /* ── Typography: body / UI scale ─────────────────────────────── */ - --fs-lead: clamp(20px, 2.6vw, 26px); + --fs-lead: clamp(18px, 2.2vw, 22px); --fs-body-lg: 17px; --fs-body: 15px; --fs-body-sm: 14px; --fs-caption: 13px; - --fs-eyebrow: 13px; + --fs-eyebrow: 12px; /* ── Typography: tracking + line heights ─────────────────────── */ - --tracking-hero: -2.5px; - --tracking-tight: -1px; - --tracking-snug: -0.5px; - --tracking-eyebrow: 1.5px; + --tracking-hero: -0.03em; + --tracking-tight: -0.02em; + --tracking-snug: -0.01em; + --tracking-eyebrow: 0.1em; --lh-tight: 1.08; --lh-snug: 1.3; --lh-body: 1.6; - /* ── Radii ───────────────────────────────────────────────────── */ + /* ── Radii — rounded, confident ──────────────────────────────── */ --radius-sm: 9px; --radius: 12px; --radius-lg: 16px; @@ -127,22 +140,23 @@ --space-5: 22px; --space-6: 28px; - /* ── Shadows ─────────────────────────────────────────────────── */ - --shadow-card: 0 24px 60px -28px rgba(0, 0, 0, 0.8); - --shadow-accent: 0 12px 30px -10px color-mix(in srgb, var(--accent) 60%, transparent); - --shadow-toast: 0 18px 40px -16px rgba(0, 0, 0, 0.8); + /* ── Shadows — depth from darkness; warm glow on interaction ─── */ + --shadow-card: 0 16px 44px -18px rgba(0, 0, 0, 0.7); + --shadow-accent: 0 10px 34px -10px color-mix(in srgb, var(--accent) 45%, transparent); + --shadow-toast: 0 16px 40px -16px rgba(0, 0, 0, 0.8); /* ── Layout & motion ─────────────────────────────────────────── */ --container: 1180px; --speed-fast: 0.15s; --speed: 0.2s; - --ease: ease; + --ease: cubic-bezier(0.16, 1, 0.3, 1); } /* - * Light scheme — warm, faintly beetroot-tinted near-whites. Only the semantic - * tokens flip; the raw --bt-* palette is unchanged. Brand FILLS stay vibrant - * pink (dark ink on top); accent-as-TEXT darkens to deep beetroot for AA. + * Light scheme — warm, faintly beetroot-tinted near-whites for daylight + * readers. Only the semantic tokens flip; the raw --bt-* palette never + * changes. Brand FILLS stay vibrant (dark ink on top); accent-as-TEXT + * darkens to deep beetroot for WCAG-AA on white. */ :root:not(.dark), [data-theme="light"], @@ -152,26 +166,26 @@ --card: #FFFFFF; --card-soft: #F0E6EC; - --border: rgba(26, 12, 20, 0.16); - --border-2: rgba(26, 12, 20, 0.24); + --border: rgba(26, 12, 20, 0.14); + --border-2: rgba(26, 12, 20, 0.22); --text: #1F0E18; --muted: #5E5159; /* ~7.1:1 on white */ - --faint: #766678; /* ~5.0:1 on white (was #978996, 3.1:1 — failed AA) */ + --faint: #766678; /* ~5.0:1 on white */ - /* --accent (the FILL) is NOT overridden here — it stays the site's vibrant - accent in both schemes (dark ink sits on top). Only accent-as-TEXT darkens - for WCAG-AA on white. */ - --text-accent: color-mix(in srgb, var(--accent), #000 22%); /* darkened accent, ~AA on white */ - --text-green: #15683A; /* ~5.2:1 on white — affirmative text */ + --text-accent: color-mix(in srgb, var(--accent), #000 26%); /* AA on white */ + --text-green: #15683A; + --focus: color-mix(in srgb, var(--accent), #000 16%); - --accent-wash: color-mix(in srgb, var(--accent) 12%, transparent); - --accent-wash-2: color-mix(in srgb, var(--accent) 16%, transparent); - --accent-line: color-mix(in srgb, var(--accent-deep) 40%, transparent); - --glass: rgba(255, 255, 255, 0.72); - --code-bg: color-mix(in srgb, var(--accent) 8%, #fff); + --glass: color-mix(in srgb, #ffffff 74%, transparent); + --bloom: color-mix(in srgb, var(--accent) 11%, transparent); + --bloom-2: color-mix(in srgb, var(--accent-deep) 8%, transparent); + --accent-wash: color-mix(in srgb, var(--accent) 10%, transparent); + --accent-wash-2: color-mix(in srgb, var(--accent) 15%, transparent); + --accent-line: color-mix(in srgb, var(--accent-deep) 38%, transparent); + --code-bg: color-mix(in srgb, var(--accent) 7%, #fff); - --shadow-card: 0 18px 44px -26px color-mix(in srgb, var(--accent-deep) 55%, transparent); - --shadow-accent: 0 12px 26px -10px color-mix(in srgb, var(--accent) 45%, transparent); - --shadow-toast: 0 18px 40px -16px rgba(40, 16, 30, 0.18); + --shadow-card: 0 16px 40px -24px color-mix(in srgb, var(--accent-deep) 50%, transparent); + --shadow-accent: 0 10px 28px -10px color-mix(in srgb, var(--accent) 40%, transparent); + --shadow-toast: 0 16px 36px -16px rgba(40, 16, 30, 0.2); } From 458940e5d182ca6a9ea8c3c6543f35794de22c80 Mon Sep 17 00:00:00 2001 From: Benoit TRAVERS Date: Thu, 16 Jul 2026 02:09:59 +0200 Subject: [PATCH 2/4] =?UTF-8?q?feat(design):=20rework=20Nocturne=20into=20?= =?UTF-8?q?Beetroot=20Stack=20=E2=80=94=20studied=20from=20tanstack.com=20?= =?UTF-8?q?(v5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The user's stated inspiration. Studied DNA: a near-neutral black canvas where each package glows in ITS OWN accent — the org reads as a colorful stack of distinct tools, not a monochrome brand. Beetroot pink stays the org accent (wordmark, links, CTAs, mascot); amqp orange / temporal indigo / unthrown green / demesne violet carry the packages. - theme: near-black canonical canvas, Geist weight-contrast typography (400 body vs 800 display), new --pkg-* accent tokens, elevation through lightness, no blooms/glow washes. One-knob --accent contract unchanged (minor bump, changeset included). - landing: Ecosystem Index — wordmark-led hero + mascot + a REAL-stats strip (live GitHub stars + live npm downloads, "—" until fetched), per-package-colored stack panels with color-matched hover glows, philosophy/why-now panels, index footer (genuine hub for 4 docs sites). All copy preserved. - logos: original gradient marks kept. - design.md: locked studied-DNA system with provenance block. --- .changeset/beetroot-nocturne-rebrand.md | 10 - .changeset/beetroot-stack-rebrand.md | 11 + .hallmark/log.json | 24 +- apps/website/.vitepress/theme/Landing.vue | 406 ++++++++++++---------- design.md | 154 ++++---- packages/theme/src/fonts.css | 8 +- packages/theme/src/style.css | 18 +- packages/theme/src/tokens.css | 170 ++++----- 8 files changed, 431 insertions(+), 370 deletions(-) delete mode 100644 .changeset/beetroot-nocturne-rebrand.md create mode 100644 .changeset/beetroot-stack-rebrand.md diff --git a/.changeset/beetroot-nocturne-rebrand.md b/.changeset/beetroot-nocturne-rebrand.md deleted file mode 100644 index 4094dd2..0000000 --- a/.changeset/beetroot-nocturne-rebrand.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@btravstack/theme": minor ---- - -Beetroot Nocturne rebrand — the original identity, elevated: built for the dark. - -- Deep plum canvas (`oklch(17% 0.024 305)`) stays the canonical dark-default; the light scheme remains the daylight fallback. -- Typography: Geist (display 600/700 + body) + JetBrains Mono replace Montserrat. -- Atmosphere with discipline: ambient beetroot blooms (fixed, never animated, accent-derived so they recolor per site), elevation through surface lightness instead of card borders, warm accent glow on hover, solid ink hero name (no gradient text), floating hero mark kept as the one character moment. -- Non-breaking: all semantic tokens keep their names and the one-knob rebrand contract is unchanged — consumer sites still override only `--accent` (`:root:root { --accent: … }`) and every derived shade (blooms included) follows via `color-mix`. diff --git a/.changeset/beetroot-stack-rebrand.md b/.changeset/beetroot-stack-rebrand.md new file mode 100644 index 0000000..ec3a2b1 --- /dev/null +++ b/.changeset/beetroot-stack-rebrand.md @@ -0,0 +1,11 @@ +--- +"@btravstack/theme": minor +--- + +Beetroot Stack rebrand — studied from tanstack.com: a near-neutral black canvas where each package glows in its own accent. + +- Near-black canvas (`oklch(13% 0.006 310)`) is the canonical dark-default; the light scheme remains the daylight fallback. +- Typography: Geist (display 700/800 + body — weight contrast does the branding) + JetBrains Mono replace Montserrat. +- The multi-accent stack: new `--pkg-amqp` / `--pkg-temporal` / `--pkg-unthrown` / `--pkg-demesne` tokens expose the official per-package accents so the landing (and any consumer) can show the stack in color; the org beetroot pink stays the `--accent` knob for wordmark, links and CTAs. +- Elevation through surface lightness (no hairline card borders), solid ink hero name (no gradient text), floating hero mark kept as the one character moment, no glow washes. +- Non-breaking: all semantic tokens keep their names and the one-knob rebrand contract is unchanged — each docs site still overrides only `--accent` with its package color, which is exactly the studied per-library accent system. diff --git a/.hallmark/log.json b/.hallmark/log.json index 467a823..6a84823 100644 --- a/.hallmark/log.json +++ b/.hallmark/log.json @@ -2,14 +2,14 @@ { "date": "2026-07-16", "scope": "app", - "macrostructure": "Marquee Hero", - "theme": "custom", - "theme_axes": "dark / geometric-sans / chromatic-other (beetroot-pink ~353)", - "vibe": "late-night plum, warm bloom, velvet, exact", - "enrichment": "H9 original gradient mascot (Tier-B, kept) + two fixed blooms", - "nav": "N5 floating pill", - "footer": "Ft5 statement", - "brief": "btravstack org rebrand v4 — Beetroot Nocturne (dark atmospheric); exploration branch, sibling of approved v3 Atlas" + "macrostructure": "Ecosystem Index", + "theme": "studied-DNA (source: https://tanstack.com/)", + "theme_axes": "dark / geometric-sans / multi-accent (org beetroot + per-package)", + "vibe": "neutral black canvas, colorful stack, real numbers", + "enrichment": "H9 original gradient mascot (Tier-B, kept)", + "nav": "N1b", + "footer": "Ft3 index (genuine hub)", + "brief": "btravstack org rebrand v5 \u2014 Beetroot Stack, studied from tanstack.com (user's stated inspiration); reworked onto design/beetroot-nocturne (PR #30)" }, { "date": "2026-07-16", @@ -21,7 +21,7 @@ "enrichment": "Tier-B hand-built SVG engravings (plates + full logo set)", "nav": "N9 edge-aligned", "footer": "Ft1 mast-headed", - "brief": "btravstack org rebrand v3 — Beetroot Atlas (LIKED by user; PR #29, branch design/beetroot-atlas)" + "brief": "btravstack org rebrand v3 \u2014 Beetroot Atlas (LIKED by user; PR #29, branch design/beetroot-atlas)" }, { "date": "2026-07-16", @@ -33,7 +33,7 @@ "enrichment": "H9 original gradient mascot (Tier-B, restored)", "nav": "N1b", "footer": "Ft8 marquee", - "brief": "btravstack org rebrand v2 — Beetroot Soft (REJECTED by user; PR #28)" + "brief": "btravstack org rebrand v2 \u2014 Beetroot Soft (REJECTED by user; PR #28)" }, { "date": "2026-07-16", @@ -45,6 +45,6 @@ "enrichment": "Tier-B hand-built SVG (flat riso logo set)", "nav": "N7 brutal slab", "footer": "Ft4 dense colophon", - "brief": "btravstack org rebrand v1 — Beetroot Riso (REJECTED by user; PR #27)" + "brief": "btravstack org rebrand v1 \u2014 Beetroot Riso (REJECTED by user; PR #27)" } -] +] \ No newline at end of file diff --git a/apps/website/.vitepress/theme/Landing.vue b/apps/website/.vitepress/theme/Landing.vue index d8b0bb6..3a39e3d 100644 --- a/apps/website/.vitepress/theme/Landing.vue +++ b/apps/website/.vitepress/theme/Landing.vue @@ -1,5 +1,5 @@