/* body.css: the body system (references/body.md). Added 2026-10-26.
   Every section after the hero declares a tone and, at most once or twice a page, a texture or a stage.
   Colours come only from brand.css tokens; set these in brand.css for each site:
     --tone-1  base surface        --tone-2  tinted surface      --tone-3  deeper tint
     --tone-ink  the dark proof band  --tone-brand  the brand band (used once or twice)
     --on-tone-ink / --on-tone-brand  text colour on those bands
     --accent  the one accent       --accent-on-light / --accent-on-dark  accent as TEXT (must pass 4.5:1)
     --motif   url("data:image/svg+xml,...") the business's own pattern (optional)
   Defaults below derive a ladder from --accent so a layout never falls back to plain off-white. */
:where(:root) {   /* zero specificity: a site's brand.css values always win */
  --tone-1: oklch(from var(--accent) 97.5% 0.012 h);
  --tone-2: oklch(from var(--accent) 93.5% 0.03 h);
  --tone-3: oklch(from var(--accent) 88% 0.045 h);
  --tone-ink: oklch(from var(--accent) 19% 0.025 h);
  --tone-brand: var(--accent);
  --on-tone-ink: oklch(from var(--accent) 96% 0.01 h);
  --on-tone-brand: var(--on-accent, #000);
  --accent-on-light: oklch(from var(--accent) min(l, 0.48) c h);
  --accent-on-dark: oklch(from var(--accent) max(l, 0.74) c h);
  --tex-o: 0.07;
}

/* tones: the section's whole surface, edge to edge */
[data-tone] { position: relative; isolation: isolate; }
[data-tone="1"] { background: var(--tone-1); }
[data-tone="2"] { background: var(--tone-2); }
[data-tone="3"] { background: var(--tone-3); }
[data-tone="ink"] { background: var(--tone-ink); color: var(--on-tone-ink); }
[data-tone="brand"] { background: var(--tone-brand); color: var(--on-tone-brand); }
[data-tone="ink"] :is(h1, h2, h3, h4) { color: var(--on-tone-ink); }
[data-tone="brand"] :is(h1, h2, h3, h4) { color: var(--on-tone-brand); }
/* on the brand band the button flips to ink: the action must contrast with what is around it */
[data-tone="brand"] .btn { background: var(--tone-ink); color: var(--on-tone-ink); border-color: var(--tone-ink); }
/* a gradient tone: two stops of the same family, mixed in oklch (never a default purple-blue) */
[data-tone="fade"] { background: linear-gradient(in oklch 170deg, var(--tone-1), var(--tone-3)); }
[data-tone="ink-glow"] { background: radial-gradient(60% 80% at 100% 0%, oklch(from var(--accent) 40% 0.09 h / 0.55), transparent 70%), var(--tone-ink); color: var(--on-tone-ink); }
[data-tone="ink-glow"] :is(h1, h2, h3, h4) { color: var(--on-tone-ink); }

/* textures: one per page at most twice, faint, never behind body text at full strength */
[data-tex]::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; opacity: var(--tex-o); }
[data-tex="dots"]::before { background: radial-gradient(circle, currentColor 1px, transparent 1.6px) 0 0 / 22px 22px; }
[data-tex="lines"]::before { background: repeating-linear-gradient(90deg, currentColor 0 1px, transparent 1px 72px); opacity: calc(var(--tex-o) * 0.8); }
[data-tex="grid"]::before { background: linear-gradient(currentColor 1px, transparent 1px) 0 0 / 48px 48px, linear-gradient(90deg, currentColor 1px, transparent 1px) 0 0 / 48px 48px; opacity: calc(var(--tex-o) * 0.6); }
[data-tex="motif"]::before { background: var(--motif) center / 520px auto repeat; opacity: calc(var(--tex-o) * 1.1); }
[data-tex="grain"]::before { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); opacity: 0.06; mix-blend-mode: multiply; }
[data-tone="ink"][data-tex="grain"]::before, [data-tone="ink-glow"][data-tex="grain"]::before { mix-blend-mode: screen; opacity: 0.05; }
/* a texture that fades out toward the bottom so the next tone starts clean */
[data-tex-fade]::before { -webkit-mask-image: linear-gradient(#000 40%, transparent); mask-image: linear-gradient(#000 40%, transparent); }

/* accents inside the body: scarce, purposeful */
.mark-hl { background: linear-gradient(var(--accent), var(--accent)) 0 88% / 100% 0.2em no-repeat; padding-bottom: 0.04em; }
[data-tone="brand"] .mark-hl { background-image: linear-gradient(var(--tone-ink), var(--tone-ink)); }
.num-accent { color: var(--accent-on-light); font-variant-numeric: tabular-nums; }
:is([data-tone="ink"], [data-tone="ink-glow"]) .num-accent { color: var(--accent-on-dark); }
.edge-accent { border-top: 3px solid var(--accent); }
.rule-accent { height: 3px; width: 56px; background: var(--accent); border: 0; margin: 0 0 18px; }

/* windows: containers chosen by purpose (references/body.md, "windows") */
.split-bleed { display: grid; gap: clamp(24px, 4vw, 56px); align-items: center; }
@media (min-width: 900px) { .split-bleed { grid-template-columns: 1fr 1fr; } .split-bleed.flip > :first-child { order: 2; } }
.overlap { display: grid; }
@media (min-width: 900px) { .overlap { grid-template-columns: 7fr 5fr; align-items: center; } .overlap > .overlap-card { margin-left: -12%; position: relative; z-index: 1; } }
.bento { display: grid; gap: clamp(16px, 2vw, 24px); grid-template-columns: repeat(2, 1fr); }
@media (min-width: 900px) { .bento { grid-template-columns: repeat(4, 1fr); grid-auto-rows: minmax(150px, auto); } .bento .b-wide { grid-column: span 2; } .bento .b-tall { grid-row: span 2; } }
.bento > * { border-radius: var(--r-l); overflow: hidden; }
.photo-break { position: relative; min-height: clamp(260px, 52vh, 560px); display: grid; align-items: end; color: #fff; overflow: hidden; }
.photo-break > img, .photo-break > picture { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -2; }
.photo-break::after { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(to top, oklch(from var(--tone-ink) l c h / 0.85), transparent 65%); }
.sticky-side { display: grid; gap: 32px; }
@media (min-width: 900px) { .sticky-side { grid-template-columns: 5fr 7fr; } .sticky-side > :first-child { position: sticky; top: 110px; align-self: start; } }
.proof-beside { display: flex; flex-wrap: wrap; gap: 10px 18px; align-items: center; font-size: 0.95em; }

/* duotone: one photo style across uneven phone photos (multiply over the ink tone) */
.duo { background: var(--tone-ink); }
.duo img { filter: grayscale(1) contrast(1.05); mix-blend-mode: multiply; opacity: 0.92; }

/* the colour stage: a fixed layer that cross-fades between section tones as you scroll (body.js); opacity only */
.stage { position: fixed; inset: 0; z-index: -5; pointer-events: none; }
.stage > i { position: absolute; inset: 0; opacity: 0; transition: opacity 0.6s ease; }
.stage > i.on { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .stage > i { transition: none; } }
/* with body.js running, sections inside main[data-stage] hand their colour to the stage so it cross-fades */
/* only the light tones hand over their colour: dark and brand bands always keep their own, so light text never sits on a light stage */
html.stage-on main[data-stage] :is([data-tone="1"], [data-tone="2"], [data-tone="3"]) { background: transparent; }

/* tint ramp: each child a step deeper (body.js numbers them) */
.ramp > * { background: color-mix(in oklch, var(--tone-1), var(--tone-3) calc(var(--i, 0) * 28%)); }
[data-tone="ink"] .ramp > * { background: color-mix(in oklch, var(--tone-ink), oklch(from var(--tone-ink) calc(l + 0.12) c h) calc(var(--i, 0) * 30%)); }
/* drifting texture (body.js sets --drift-y while the section is on screen) */
[data-drift]::before { inset: -80px 0; transform: translate3d(0, var(--drift-y, 0px), 0); will-change: transform; }
@media (prefers-reduced-motion: reduce) { [data-drift]::before { transform: none; } }

/* the kit's own variables follow the tone, so headings, text, lines, cards and scroll icons read on every band */
[data-tone="ink"], [data-tone="ink-glow"] {
  --head: var(--on-tone-ink); --text: oklch(from var(--on-tone-ink) calc(l - 0.07) c h); --mute: oklch(from var(--on-tone-ink) calc(l - 0.25) c h);
  --line: oklch(from var(--tone-ink) calc(l + 0.16) c h); --line-strong: var(--on-tone-ink);
  --card: oklch(from var(--tone-ink) calc(l + 0.06) c h); --mark: var(--on-tone-ink); --mark-2: var(--accent-on-dark); --mark-3: oklch(from var(--tone-ink) calc(l + 0.2) c h);
  color: var(--text);
}
[data-tone="brand"] { --head: var(--on-tone-brand); --text: var(--on-tone-brand); --mute: var(--on-tone-brand); --line: var(--on-tone-brand); --line-strong: var(--on-tone-brand); --mark: var(--on-tone-brand); --mark-2: var(--on-tone-brand); --mark-3: var(--on-tone-brand); }
[data-tone="brand"] .section-head h2::after { background: var(--on-tone-brand); }
[data-tone="2"] { --card: var(--tone-1); }
[data-tone="3"] { --card: var(--tone-1); }
[data-tone="1"] { --card: oklch(from var(--tone-1) calc(l + 0.02) c h); }

/* light tones on a dark-first site (his own; layouts 00, 13, 18, 20): text, lines, cards and icons switch to the light set */
[data-tone="1"], [data-tone="2"], [data-tone="3"], [data-tone="fade"] {
  color: var(--light-text, #23272b);
  --head: var(--light-head, #111); --text: var(--light-text, #23272b); --mute: var(--light-mute, #5b636b);
  --line: var(--light-line-soft, #c9cfd5); --line-strong: var(--light-line, #111); --shadow: var(--light-shadow, #111);
  --mark: var(--light-head, #111); --mark-2: var(--light-mute, #5b636b); --accent-text: var(--accent-on-light);
}
[data-tone="1"] { --card: var(--tone-2); } [data-tone="2"], [data-tone="3"] { --card: var(--light-card, #fff); }

/* edges between sections (body.js, references/body.md "Edges"; his pick 2026-10-29). No see-through fades.
   Light bands on a dark site (dark bands on a light one) float as raised panels above the one moving gradient */
.edge-panel {
  margin-inline: var(--panel-in, 22px); border-radius: var(--panel-r, 28px); overflow: clip;
  box-shadow: 0 30px 70px rgb(0 0 0 / 0.7), 0 -10px 40px rgb(0 0 0 / 0.4),
              inset 0 26px 30px -16px rgb(0 0 0 / 0.38), inset 0 -26px 30px -16px rgb(0 0 0 / 0.38);
}
.edge-ground-light .edge-panel { box-shadow: 0 24px 60px rgb(0 0 0 / 0.28), 0 -6px 30px rgb(0 0 0 / 0.12), inset 0 26px 30px -16px rgb(0 0 0 / 0.3), inset 0 -26px 30px -16px rgb(0 0 0 / 0.3); }
.edge-open-bottom { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.edge-open-top { border-top-left-radius: 0; border-top-right-radius: 0; }
.edge-panel > .amb-bg { -webkit-mask-image: none; mask-image: none; }   /* the panel's own edge is the edge */
@media (max-width: 760px) {
  :root { --panel-in: 8px; --panel-r: 20px; }
  .edge-panel > .wrap { padding-inline: max(24px, var(--s3)); }
}
/* the brand trim where a photo ends and under the big last call: dark 3 px, accent 6 px, dark 3 px (like his buttons) */
.edge-trim {
  position: absolute; left: 0; right: 0; bottom: 0; height: 12px; z-index: 6; pointer-events: none;
  background: linear-gradient(var(--trim-dark, #000) 0 3px, var(--trim, var(--accent)) 3px 9px, var(--trim-dark, #000) 9px);
}
/* under a band that is already the accent, an accent stripe vanishes into it: the stripe takes the light colour instead */
[data-tone="brand"] > .edge-trim { --trim: var(--trim-on-brand, var(--on-tone-ink)); }
/* jump links and the floating menu: a section scrolled to never starts under the menu */
[id] { scroll-margin-top: 108px; }
@media (max-width: 760px) { [id] { scroll-margin-top: 88px; } }

/* the transition bank (js/joins.js, references/joins.md): an empty strip between two sections */
[data-join] { position: relative; height: clamp(190px, 34vh, 340px); overflow: clip; }
[data-join] svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
