Kata / leaf.kata.json compiled · 4 open
Apply design system
This page is rendered in the system it documents. The colours, the families, the type ramp and the corner grammar below were all read out of leaf.kata.json and applied to this page. If a compiled file cannot rebuild the look of the thing it came from, it is not carrying enough to teach a model either.

// Registry entry

Leaf

Landing and product pages, including satellite products on their own subdomains. Light by default, with a stated dark counterpart.

29roles
11composition rules
8patterns
6refusals
4open questions
3widths inspected

// Colour

Named for the job it does.

Every value is scoped to a surface, so nothing can be borrowed across one by mistake. The swatches above and the page you are reading are drawn from these.

marketing19 roles
page#FAF7F2The decision moves muted text #737373 to 4.44:1 on this paper — below AA, where it scraped past at 4.59:1 on the shipped value. Recorded under contrast-policy.
stated
bandrgba(245,245,245,.6) over pagefull-width alternating band behind a section
stated
card#FFFFFF#FDFBF9 is the docs card token and does not apply here. Question closed.
stated
cardHover#FAFAFA
stated
surfaceMuted#F5F5F5
stated
hairlinergba(0, 0, 0, .08)The warm hairline rgba(25,18,7,.08) recorded in the previous compile is --leaf-border, a docs-side value. Marketing hairlines are neutral black at 8%.
stated
textPrimary#0A0A0A
stated
textSecondary#7373734.59:1 on page, 4.74:1 on card. Passes AA for body text, with no margin.
stated
codeMuted#A3A3A3Fails: 2.31:1 on codeSurface #F5F5F5. Well below AA at any size.
stated
accent#D4652Eflame, the one loud colourFails: 3.56:1 as eyebrow text on page, at 11px. Below AA for text that size.
stated
accentHover#D7662F
stated
accentWarm#F5B731
stated
accentTintrgba(212, 101, 46, .07)Exists in the shared sheet. The ghost button does NOT use it on hover; it uses neutral-50.
stated
accentTintBorderrgba(212, 101, 46, .16)
stated
onAccent#FFFFFFFails: 3.68:1 against accent. Below AA for text under 18.66px bold. The primary button is 14px medium.
stated
codeSurface#F5F5F5Marketing code is LIGHT. The warm-dark #1E1714 in the previous compile is the docs code block, harvested across surfaces — the same mistake as the text trio.
stated
codeText#171717
stated
terminalSurface#FAFAFA
stated
terminalHeader#F5F5F5
stated

Applies to leafphp.dev/, *.leafphp.dev/, design.hanabira.dev/

marketingDark10 roles
page#110E0B
stated
pageAlt#0A0807
stated
textPrimary#FAFAFA
stated
accentOnDark#D4652E
stated
textSecondary#A3A3A37.63:1 on page. Passes.
stated
codeText#E5E5E5
stated
codeMuted#737373
stated
terminalSurface#0A0807
stated
terminalHeader#110E0B
stated
hairlinergba(255, 255, 255, .08)
stated

Applies to leafphp.dev/, *.leafphp.dev/

docs0 roles

Deliberately empty. The previous compile harvested three values from here and called them marketing tokens: the text trio (#3C3C43/#67676C/#929295), the warm hairline rgba(25,18,7,.08), and the dark code block #1E1714. All three are corrected in this compile. Do not harvest from this surface.

Applies to docs/**, leaf-docs/**

// Type

The ramp, at its own sizes.

Rendered in the family this system actually uses, at the sizes it actually states. Anything that looks wrong here is wrong in the system.

rampBricolage Grotesque
Aa
heroH12.25rem
Aa
sectionTitleclamp(1.875rem, 4vw, 2.75rem)
Aa
displayLargeclamp(2.25rem, 5.5vw, 4.5rem)
Aa
subtitle1.0625rem
Aa
heroSubtitle1.125rem

// Space

The scale, and whether it binds.

A scale that is not enforced is a habit rather than a rule, and the file says which this is.

spacenot enforced
4
8
12
16
20
24
32
40
48
64
80
96
128

Tailwind default scale, stated through utility classes across every marketing component

py-24 lg:py-32 (96px, 128px at lg)

The scale exists and is real. Whether off-scale values are a violation is not stated; arbitrary values appear for type sizes (text-[0.6875rem]) but not for spacing. See unspecified/spacing-enforce.

// Composition

The part no export format carries.

Breakpoints, grid relationships and alignment. This is where the correction effort goes, and where a token file tells you nothing.

breakpoints4
smcontainer padding steps up 16 to 24, hero type 36 to 48640px
mdhero subtitle steps up768px
lgtwo-column panels collapse below this. Hero editor/terminal pair verified stacking at 900.1024px
xlhero display reaches full 96px1280px
grid4
  • Stacked grids share column tracks and gaps. A section heading that sits above a list must use the same track definition as the list.Two grids in the same column with different tracks read as two unrelated pages.Checked by: For each section, compare grid-template-columns and gap of the heading block against the content grid beneath it.
    auto
  • Side-by-side comparison panes share row tracks, so headings and footers across the pair sit on the same line.Independently sized panes in a comparison undercut the comparison.Checked by: Paired panes use grid-template-rows: subgrid, or equivalent equal-height behaviour.
    model
  • A grid collapses at the width its content stops fitting, not at the shared breakpoint.Dense columns need to stack earlier than sparse ones. One global breakpoint clips the dense case.Checked by: manual
    manual
  • Grids of tiles use a 1px gap over a hairline-coloured bed, not per-tile borders.Shared hairlines read as one drawn grid. Doubled borders read as boxes that happen to touch.Checked by: Tile containers use gap-px with the bed background set to the hairline colour.
    auto
alignment2
  • Stacked figure-and-label rows reserve a fixed width for the figure so labels start on one axis.Checked by: Figures in a repeated row set min-width.
    auto
  • Display type balances. Body ledes balance. No line ends with an orphan of one or two words.Checked by: text-wrap: balance on display and lede, plus a rendered check that no line holds under three words.The reference run held this rule and violated it in two consecutive rounds. Distribution is not compliance.
    model
motion1
  • Buttons transition colour only. They do not lift, scale or translate.Checked by: Button classes declare transition-colors and no transform on :hover.Question hover-motion closed. One stated exception: arrow glyphs inside text links nudge 1px diagonal on hover (ui.link). The exception belongs to links, never to buttons.
    auto

// Patterns

What each part is for, and what it is not.

The second half is the one that matters. A component list says what exists; only the refusals say what to reach for.

chipUse for: A single piece of status attached to an object. Version, state, count.Never for: a list of namesNever for: tool or product wordmarksNever for: navigationNever for: anything the reader scans rather than readsFor a list of names, use wordmarkRow instead.
wordmarkRowUse for: A row of product or tool names shown as plain text on the page background, generously spaced, no container.Never for: a single itemNever for: anything with state
sectionNumberUse for: Small mono numeral above a heading, with a short accent rule beneath it.
cornerMarkerUse for: 5px square accent markers on the corners of a bordered panel. All four corners, offset half outside the border.Never for: round dots (that is the badge dot, a different element)Never for: a subset of cornersQuestion corner-tick-scope closed. The previous compile conflated this with the 6px round badge dot and the reference run shipped 2-corner round dots — wrong shape, size and count.
primaryButtonUse for: The one loud action. Accent fill, white text, square corners, 40px tall.The stated shadow contradicts the observed no-shadows prohibition. Recorded as a conflict, not resolved here.
ghostButtonUse for: Secondary action beside a primary. Hairline border, primary text, square.Question secondary-action closed. It exists, and its hover is neutral, not accent-tinted. The reference run's tint-fill hover was an invention.
terminalUse for: Command output in a bordered block with a header strip. Light neutral surfaces in light mode, near-black warm in dark.
stripesUse for: Diagonal hairline stripes as a filler texture inside empty or decorative panel areas.

// Refusals

What this system will not do.

The least recoverable section in the file. A rendered site shows only what it does, never what it declines, so every line here came from a person saying no.

// Contradictions

Where the system disagrees with itself.

Places the written intent and the shipped code do not match. The compiler surfaces both and picks neither.

paper-valueresolved
claimed

#FAF7F2 design notes

observed

#FDFBF7 index.css:1075, stated in code and measured live

decided

#FAF7F2. Michael, review 2026-08-03. Production ships #FDFBF7 and should migrate to the note value.

gradient-policyresolved
claimed

no gradient titles design notes

observed

four-stop gradient on the hero display line, stated in source Hero.vue:46 — linear-gradient(135deg, #F5B731, #E8753A, #D4542B, #C0392B) with bg-clip-text

decided

Gradient display is Leaf and Hanabira brand identity, prohibited for every other product. Michael, review 2026-08-03. Encoded as prohibition gradient-is-frontline-only.

accent-hoverresolved
claimed

#BE4A1F index.css --vp-button-brand-hover-bg

observed

#D7662F ui.ts btnPrimary hover:bg-[#d7662f]

decided

#D7662F. Michael, review 2026-08-03. The index.css token is stale.

shadow-policyresolved
claimed

no shadows anywhere (observed across all surfaces) live inspection

observed

stated accent glow on the primary button: shadow-[0_16px_34px_-24px_rgba(232,117,58,0.8)] ui.ts btnPrimary

decided

Conditional: the glow applies only where it fits the design and background in use. Michael, review 2026-08-03. No-shadows remains the default elsewhere.

hero-title-colourresolved
claimed

#0A0A0A (neutral-950), the stated title colour ui.title, --home-fg

observed

#3C3C43 on the shipped hero h1, inherited from the vitepress default --vp-c-text-1, which Leaf never overrode live inspection at 1280

decided

Not the vitepress default. Use Tailwind neutrals or brand variables (neutral-950 per ui.title). Michael, review 2026-08-03 — production hero should be fixed.

// Still open

What it does not know.

Recorded rather than guessed, and shipped into the rules files so a model asks instead of inventing. 11 further questions were raised and answered during review, and stay in the file as a record of how it was decided.

contrast-policyhigh

Four stated pairs now sit below AA (the 4.5:1 minimum for body text, 3:1 for large text): white-on-accent buttons 3.68:1, accent eyebrows 3.56:1 at 11px, code comments 2.31:1, and muted body text 4.44:1 on the newly decided #FAF7F2 paper. Which must be fixed and which are exempt as decorative?

Assumed meanwhile: Shipped as stated.

spacing-enforcelow

The Tailwind scale is real, but is an off-scale value a violation? Arbitrary values already appear for type sizes.

Assumed meanwhile: Not enforced.

eyebrow-variantslow

ui.eyebrow tracks at 0.2em, ui.codeLabel at 0.08em, and one live instance measured 0.12em. One eyebrow with drift, or three intentional variants?

Assumed meanwhile: Two components, some drift.

type-pairing-provenancelow

Bricolage Grotesque for both display and body is measured everywhere but stated nowhere found. Intentional identity or interim?

Assumed meanwhile: Intentional.

// Provenance

Where this came from.

Compiled 2026-08-03 at 1280, 900, 390 pixels wide. 1440 was not reachable (inspection pane clamps at 1280). 1280 is the site's last breakpoint (Tailwind xl), so every step of the type ramp and every grid collapse was still exercised. 390 and 900 measured directly.

sources6
codeparseddocs/.vitepress/theme/components/Home/ui.ts
tokensparseddocs/.vitepress/theme/styles/home.css
tokensparseddocs/.vitepress/theme/styles/index.css
codeparseddocs/.vitepress/theme/components/Home/Hero.vue
urlcomputed-style inspection at three widthshttps://v5-x.leafphp.dev
notehuman-written prosedesign notes, prior session

Take it with one command.

Download the file, run it in your repo, and your AI tools write in this language.

Apply design system

pnpx kata apply ./leaf.kata.json  ·  back to the registry