/* ==================================================================
   Bloum — site styles
   Geometry & typography extracted from Figma (1440 frame, see design/).
   Fonts: Inter (nav/body), Averia Serif Libre (flower quotes).
   TODO before production: self-host fonts (GDPR) instead of Google CDN.

   Layout model (cf. mindmarket.com): an accent-coloured hero that opens
   with the page's own words (kicker/tagline/intro) and the flower scene,
   with a full-bleed off-white sheet below it: .page carries the papier
   surface edge-to-edge (big rounded top corners, no visible container),
   pads its content down to the Figma column, and runs long: card, then
   the secties story blocks, then the giant wordmark closing the page
   above the footer. The flower,
   vases and menu are FIXED to the viewport, with the scene in the
   FOREGROUND — sized so it never crosses the text column. scene.js adds
   scroll-driven sway and stamps .is-in on the scene for the entrance
   reveal; the sprouts (flowers from other pages) then grow out of the
   vase mouths after a long beat.
   ================================================================== */

:root {
  /* Scheme accents */
  --bladgroen:  #53a058;
  --koraalrood: #f9434f;
  --violetpaars:#7e25b7;
  --zonnegeel:  #fec339;

  /* Palette */
  --inkt:   #040404;
  --wit:    #ffffff;
  --papier: #f3efe3;

  --accent: var(--bladgroen);
  --col: 566px;              /* content column, from Figma */

  /* Averia's track, straight from the huisstijl handboek: "Letterafstand
     (Letter Spacing): -80" — Adobe tracking, 1/1000 em, so -.08em. In em
     and not px because the handbook sets it once for every size: a quote
     at theatre size has to track as tight as a card line, and a fixed px
     value drifts open as the type grows. */
  --serif-track: -.08em;
}

/* --accent (and the two inks derived from it) are REGISTERED so they
   animate: the one-pager flips data-scheme on <html> while you scroll
   and every accent-derived colour — canvas, tagline tint, quote bands —
   crossfades through the transition on html below.
   --ink-on:    ALL text ON the accent canvas, taglines included (the
                design bans greys and tints on type). Ink everywhere
                except violetpaars, which is too dark for ink (2.8:1)
                and flips to papier (7.4:1).
   --tint-deep: a darkened accent tint (lightened on violetpaars). No
                longer carries display type; it survives on the small
                solid accents: the theatre's quiet type. */
@property --accent    { syntax: '<color>'; inherits: true; initial-value: #53a058; }
@property --ink-on    { syntax: '<color>'; inherits: true; initial-value: #040404; }
@property --tint-deep { syntax: '<color>'; inherits: true; initial-value: #234325; }
/* --accent-ink: the ink for anything PAINTED IN THE ACCENT — the nav's
   active chip, the mobile menusheet. It used to be --ink-on, and that
   was right while the canvas WAS the accent. Since the 2026-08 split it
   is not: --ink-on now answers to [data-canvas], which is paper or white
   or green on the one-pager and therefore always ink — so the Shop chip
   painted itself violetpaars and then wrote on it in BLACK (2.8:1, and
   it looked like a hole). This one answers to the scheme, where the
   accent actually lives. Registered so it crossfades with it. */
@property --accent-ink { syntax: '<color>'; inherits: true; initial-value: #040404; }
/* --leaf-light/--leaf-dark: the two leaf greens every flower SVG is
   inked with (templates/_svg, fill="var(--leaf-…)"). Registered so the
   foliage recolours THROUGH a scheme crossfade like everything else:
   leaves must keep contrast against whatever canvas is behind them —
   on bladgroen the light leaves would sink into the canvas, on
   violetpaars the dark ones sink instead (overrides below). */
@property --leaf-light { syntax: '<color>'; inherits: true; initial-value: #53a058; }
@property --leaf-dark  { syntax: '<color>'; inherits: true; initial-value: #007553; }
/* --canvas: THE SURFACE, split out from --accent (2026-08).
   Four full-bleed ~full-saturation hues, one per screen, read as
   children's illustration however good the shapes are — and on the
   photo sections the canvas fought the photographs, which carry their
   own coloured grounds (purple on yellow on green). So the accent
   stops painting the page. --accent still flips per section and still
   drives everything SMALL — type accents, CTA fills, leaf tints, bloom
   marks, the nav chip — while --canvas carries the surface, and the
   surface is paper almost everywhere. Colour became an event.
   Default: the canvas IS the accent. The one-pager opts out per
   section via [data-canvas] below. */
@property --canvas { syntax: '<color>'; inherits: true; initial-value: #f3efe3; }

/* NB: each scheme's --tint-deep mixes from its own STATIC palette var,
   never from the animating --accent — a transition toward a value that
   is itself mid-transition would chase its target and lag. */
:root {
  --ink-on: var(--inkt);
  --accent-ink: var(--inkt);
  --tint-deep: color-mix(in srgb, var(--bladgroen) 42%, var(--inkt));
  --leaf-light: #53a058;
  --leaf-dark: #007553;
  --canvas: var(--accent);
}
html { transition: --accent .9s ease, --ink-on .9s ease, --tint-deep .9s ease,
                   --leaf-light .9s ease, --leaf-dark .9s ease, --canvas .9s ease,
                   --accent-ink .9s ease; }

/* ---- the one-pager's surfaces ----
   onepage.js writes [data-canvas] on <html> from each panel's
   data-panel-canvas, defaulting to papier. The scheme keeps flipping
   underneath, so the accent crossfade still runs — you just stop
   seeing it as a wall of colour. Down the page: paper, GREEN, paper,
   WHITE, GREEN, paper. --ink-on is restated per surface because it
   means "all text ON the canvas" and the canvas is no longer the
   accent: ink clears 6.5:1 on bladgroen and ~15:1 on papier and wit,
   so every surface here takes ink.

   Qualified with html so these OUTRANK the [data-scheme] blocks below,
   which also set --ink-on and sit later in the file: on the white
   carousel the scheme is still violetpaars, and its papier ink turned
   the headline invisible. Canvas decides the ink; scheme no longer
   can. */
html[data-canvas="papier"]    { --canvas: var(--papier);    --ink-on: var(--inkt); }
html[data-canvas="wit"]       { --canvas: var(--wit);       --ink-on: var(--inkt); }
html[data-canvas="bladgroen"] { --canvas: var(--bladgroen); --ink-on: var(--inkt); }

/* --accent-ink per scheme: measured against the ACCENT (6.5:1 on
   bladgroen, 6:1 on koraalrood, 13:1 on zonnegeel — violetpaars is too
   dark for ink at 2.8:1 and takes papier at 6.4:1). */
[data-scheme="bladgroen"]   {
  --accent: var(--bladgroen);
  --accent-ink: var(--inkt);
  /* bladgroen leaves on the bladgroen canvas are invisible: all
     foliage goes donker groen here (the over-bloum hero's own ink) */
  --leaf-light: #007553;
}
[data-scheme="koraalrood"]  {
  --accent: var(--koraalrood);
  --accent-ink: var(--inkt);
  --tint-deep: color-mix(in srgb, var(--koraalrood) 42%, var(--inkt));
}
[data-scheme="violetpaars"] {
  --accent: var(--violetpaars);
  --ink-on: var(--papier);
  --accent-ink: var(--papier);
  --tint-deep: color-mix(in srgb, var(--violetpaars) 32%, var(--papier));
  /* donker groen sinks into the deep violet: dark leaves lighten up
     (moot on the one-pager, where the whole violet scene flattens
     lilac — this serves any subpage on the scheme) */
  --leaf-dark: #53a058;
}
[data-scheme="zonnegeel"]   {
  --accent: var(--zonnegeel);
  --accent-ink: var(--inkt);
  --tint-deep: color-mix(in srgb, var(--zonnegeel) 42%, var(--inkt));
}

/* ---- per-page scene geometry ----
   Each flower is a different illustration; offsets are % of the
   illustration box, sizes are vw at the 1440 reference frame.
   --quote-* places the quote inside the bloom (cx = horizontal center).
   [data-page] carries the FLOWER + quote geometry; the vase pair lives
   in its own [data-vases] scope so the one-pager can remix pairs per
   section. */
[data-page="over-bloum"] {
  --bubble-ink: #ffffff;
  --flower-w: 34.72vw; --flower-right: -2.22vw; --flower-ar: 0.4643;
  --quote-top: 28.4%; --quote-cx: 49.1%; --quote-w: 66%; --quote-fs: 4.8cqw;
}
[data-page="waar-te-koop"] {
  --bubble-ink: #040404;
  --flower-w: 46.18vw; --flower-right: -8.95vw; --flower-ar: 0.6159;
  --quote-top: 23.5%; --quote-cx: 53.7%; --quote-w: 34%; --quote-fs: 3.61cqw;
}
[data-page="producten"] {
  --bubble-ink: #040404;
  --flower-w: 44.35vw; --flower-right: -11.43vw; --flower-ar: 0.5941;
  --quote-top: 21.5%; --quote-cx: 42.2%; --quote-w: 45%; --quote-fs: 3.76cqw;
}

/* ---- per-pair vase geometry ----
   --sprout-* places each DEFAULT guest flower (the server-rendered pair)
   so its stem base sits INSIDE its vase's black mouth oval: l/b/w
   position the sprout in the vases box, o is the grow origin = the
   measured stem-base point of that flower's artwork, and `water` is the
   waterline — the y (% of the sprout box) of the mouth oval's centre,
   where the stem visually enters the vase (the sprout is clipped there,
   see .sprout). All derived from SVG geometry: mouth-oval bbox centres
   and lowest dark stem point per flower, measured by rasterizing the
   artwork (canvas rig). At every waterline only the stem crosses the
   line, inside the mouth oval — so the clipped edge is always hidden
   black-on-black. When JS re-guests a vase (section changes on the
   one-pager, vase clicks), placeSprout() recomputes the same numbers
   from the FLOWER_ANCHOR/VASE_MOUTH tables in scene.js. */
[data-vases="over-bloum"] {
  --vases-w: 16.23vw; --vases-ar: 0.8432;
  --vase-a-l: 0%;      --vase-a-t: 25.61%; --vase-a-w: 63.18%; --vase-a-z: 2;
  --vase-b-l: 57.33%;  --vase-b-t: 0%;     --vase-b-w: 42.67%; --vase-b-z: 1;
  --sprout-a-l: 1.2%;  --sprout-a-b: 69.3%; --sprout-a-w: 58.1%; --sprout-a-o: 49.8% 99.6%;  --sprout-a-water: 98.37%;
  /* sprout-b statics fit MARGRIET (the one-pager's opening guest) */
  --sprout-b-l: 56.59%; --sprout-b-b: 95.67%; --sprout-b-w: 39.26%; --sprout-b-o: 48.6% 99.5%; --sprout-b-water: 98.3%;
}
[data-vases="waar-te-koop"] {
  --vases-w: 15.39vw; --vases-ar: 0.7782;
  /* vase-b deliberately small (it used to rival vase-a in height and the
     two guest flowers tangled): floored via t = boxH − w/ar. */
  --vase-a-l: 0%;      --vase-a-t: 0%;     --vase-a-w: 63.32%; --vase-a-z: 1;
  --vase-b-l: 50%;     --vase-b-t: 22.66%; --vase-b-w: 46%;    --vase-b-z: 2;
  --sprout-a-l: -1.8%; --sprout-a-b: 86.4%;  --sprout-a-w: 58.3%; --sprout-a-o: 51.5% 90.6%;  --sprout-a-water: 89.68%;
  --sprout-b-l: 44.61%; --sprout-b-b: 73.16%; --sprout-b-w: 42.3%; --sprout-b-o: 64.2% 100%;   --sprout-b-water: 98.8%;
}
[data-vases="producten"] {
  --vases-w: 15.86vw; --vases-ar: 0.8126;
  --vase-a-l: 0%;      --vase-a-t: 27.53%; --vase-a-w: 62.06%; --vase-a-z: 2;
  --vase-b-l: 38.54%;  --vase-b-t: 0%;     --vase-b-w: 61.46%; --vase-b-z: 1;
  --sprout-a-l: 3.1%;  --sprout-a-b: 58.3%; --sprout-a-w: 57.1%; --sprout-a-o: 51.5% 90.6%;  --sprout-a-water: 89.38%;
  --sprout-b-l: 29.7%; --sprout-b-b: 95.5%; --sprout-b-w: 56.5%; --sprout-b-o: 64.2% 100%;   --sprout-b-water: 98.76%;
}

/* ---- reset ---- */
*, *::before, *::after { box-sizing: border-box; }
/* two-stop canvas bg: rubber-band overscroll shows the canvas above the
   page and papier below it, matching the hero/sheet split (on the
   one-pager's paper surfaces the two stops collapse into one) */
html { -webkit-text-size-adjust: 100%; background: linear-gradient(to bottom, var(--canvas) 0 50%, var(--papier) 50%); }
body { margin: 0; }
img, svg { display: block; max-width: 100%; height: auto; }
a { color: inherit; }

body {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  font-size: 1rem;
  line-height: 1.5;
  color: var(--inkt);
  background: var(--canvas);
  -webkit-font-smoothing: antialiased;
}

/* ==================================================================
   Menu — fixed white pill, floats over everything: wordmark on the
   left (home link), page links in the middle, socials on the right.
   Hover/active: off-white chip, text in the TARGET page's accent
   (--nav-accent, set per link in _layout.twig; mixed with a little ink
   so light accents like zonnegeel stay readable on the chip).
   ================================================================== */
.topnav {
  position: fixed;
  z-index: 20;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
  width: min(1040px, calc(100vw - 32px));
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  background: var(--wit);
  padding: 11px 20px;
  border-radius: 10px;
  box-shadow: 0 4px 5px rgba(0, 0, 0, .1);
  font-size: .875rem;
  font-weight: 600;
  line-height: 1.5;
}
.topnav__brand { display: block; }
.topnav__brand img { height: 32px; width: auto; }
.topnav__links { display: flex; gap: 2px; }
.topnav__link {
  text-decoration: none;
  white-space: nowrap;
  padding: 7px 14px;
  border-radius: 8px;
  transition: background-color .15s ease, color .15s ease;
}
.topnav__link:hover {
  background: var(--papier);
  color: var(--nav-accent, var(--accent));
  color: color-mix(in srgb, var(--nav-accent, var(--accent)) 68%, var(--inkt));
}
/* The active chip wears the TARGET section's accent, so its ink has to
   be the target's too: --nav-ink, set per link beside --nav-accent in
   _nav.twig. It used to ask --ink-on, which since the canvas/accent
   split belongs to the surface you are standing on and is ink on all
   three one-pager canvases — so the violet Shop chip got black text at
   2.8:1 and read as a hole in the pill. */
.topnav__link.is-active {
  background: var(--nav-accent, var(--accent));
  color: var(--nav-ink, var(--accent-ink));
}
.topnav__social { display: flex; gap: 4px; }
.topnav__social a {
  display: block;
  padding: 8px;
  border-radius: 8px;
  color: var(--inkt);
  transition: color .15s ease, background-color .15s ease;
}
.topnav__social a:hover { background: var(--papier); }
.topnav__social svg { width: 17px; height: 17px; fill: currentColor; }

/* ---- the small-screen menu (≤760px): the pill keeps the wordmark
   and a menu button; links and socials move onto the MENUSHEET, an
   accent sheet that springs up from the bottom edge the way a page
   transition does (nav.js). The sheet rides UNDER the pill (z 18 <
   20), so the button stays on top and its two bars spring into a
   cross. The canvas is the LIVE accent: mid-one-pager the menu opens
   in the current section's colour, with scheme-aware inks — and the
   active section wears the same papier chip as the desktop links. ---- */
.topnav__menu, .menusheet { display: none; }

@media (max-width: 760px) {
  .topnav__menu {
    display: grid;
    gap: 5px;
    border: 0;
    padding: 13px 10px;    /* a ~44px tap target… */
    margin-block: -8px;    /* …that doesn't fatten the slim pill */
    background: none;
    border-radius: 8px;
    cursor: pointer;
  }
  .topnav__menu-bar {
    width: 20px;
    height: 2px;
    border-radius: 1px;
    background: var(--inkt);
    transition: translate .3s ease, rotate .45s cubic-bezier(.34, 1.56, .64, 1);
  }
  .topnav__menu[aria-expanded="true"] .topnav__menu-bar:first-child { translate: 0 3.5px; rotate: 45deg; }
  .topnav__menu[aria-expanded="true"] .topnav__menu-bar:last-child { translate: 0 -3.5px; rotate: -45deg; }

  .menusheet {
    position: fixed;
    inset: 0;
    z-index: 18;
    display: flex;
    flex-direction: column;
    gap: 24px;
    padding: calc(92px + env(safe-area-inset-top)) 28px calc(28px + env(safe-area-inset-bottom));
    /* the sheet IS the accent, so its ink is the accent's — not the
       canvas's (--ink-on), which opened the menu in black on violet */
    background: var(--accent);
    color: var(--accent-ink);
    border-radius: clamp(28px, 4vw, 44px) clamp(28px, 4vw, 44px) 0 0;
    box-shadow: 0 -16px 48px rgba(4, 4, 4, .25);
    translate: 0 103%;   /* a hair past 100% so the shadow starts offscreen */
    overflow-y: auto;              /* tiny landscape screens still reach */
    overscroll-behavior: contain;  /* …the socials; the page stays put */
  }
  .menusheet[hidden] { display: none; }
  .menusheet.is-open { translate: 0 0; }
  .menusheet__links {
    display: grid;
    justify-items: start;
    gap: 6px;
    margin-block: auto;
  }
  .menusheet__link {
    padding: 6px 16px;
    margin-left: -16px;   /* the chip pad stays off the text's left rhythm */
    border-radius: 14px;
    text-decoration: none;
    font-size: clamp(1.9rem, 9.5vw, 2.6rem);
    font-weight: 700;
    letter-spacing: -.045em;
    line-height: 1.25;
    color: var(--accent-ink);
  }
  .menusheet__link.is-active {
    /* same vibrant chip as the topnav — but the sheet IS the accent,
       so the chip inverts: papier chip, accent text. The accent is
       mixed with ink exactly as the topnav's hover does it: zonnegeel
       at full strength on papier is 1.4:1, a yellow ghost. */
    background: var(--papier);
    color: color-mix(in srgb, var(--nav-accent, var(--accent)) 68%, var(--inkt));
  }
  .menusheet__social { display: flex; gap: 12px; }
  .menusheet__social a {
    display: grid;
    place-items: center;
    width: 52px;
    height: 52px;
    border-radius: 50%;
    background: var(--papier);
    color: var(--inkt);
  }
  .menusheet__social svg { width: 22px; height: 22px; fill: currentColor; }
}
@media (max-width: 760px) and (prefers-reduced-motion: no-preference) {
  .menusheet { transition: translate .6s cubic-bezier(.2, .9, .3, 1.15); }
  /* the words follow the sheet up, one beat apart, springing to rest;
     closing drops the delays so everything leaves with the sheet */
  .menusheet__link, .menusheet__social {
    opacity: 0;
    translate: 0 26px;
    transition: opacity .35s ease, translate .55s cubic-bezier(.3, 1.4, .45, 1);
  }
  .menusheet.is-open .menusheet__link, .menusheet.is-open .menusheet__social {
    opacity: 1;
    translate: 0 0;
    transition-delay: calc(.1s + var(--mi, 4) * .055s);
  }
}

/* ==================================================================
   Hero — the colored section opens with the page's own words
   (mindmarket-style): a giant tagline in a darkened tint of the page
   accent, then the intro. Text keeps left so the fixed foreground flower
   owns the right side; min-height leaves the sheet edge peeking at the
   fold, inviting scroll.
   ================================================================== */
.hero {
  position: relative;
  z-index: 1;
  /* hero + .page's accent top margin together stay under ~94svh, so the
     sheet edge peeks above the fold and invites the scroll */
  min-height: 80svh;
  display: flex;
  flex-direction: column;
  gap: clamp(16px, 2.2vw, 26px);
  padding: calc(88px + 5.5vw) clamp(20px, 7.8vw, 128px) clamp(64px, 10svh, 140px);
  color: var(--ink-on);
}
.hero__tagline {
  margin: 0;
  max-width: min(58vw, 10ch);
  font-size: clamp(3rem, 8.8vw, 8.25rem);
  font-weight: 700;
  line-height: .98;
  letter-spacing: -.045em;
  /* full-strength ink (papier on violetpaars): no tints, no greys */
  color: var(--ink-on);
}

/* ---- springy taglines: scrollfx.js splits each headline into .word/
   .ltr spans and stamps .is-live whenever it scrolls into view; every
   visit replays the letter-by-letter pop. The split only happens when
   JS (and motion) is on, so the plain headline stands without it. ---- */
.hero__tagline .word { display: inline-block; white-space: nowrap; }
.hero__tagline .ltr { display: inline-block; }
.hero__tagline .ltr:nth-child(even) { --tilt: -1; }
.hero__tagline.is-split .ltr {
  opacity: 0;
  transform: translateY(.6em) scale(.4) rotate(calc(var(--tilt, 1) * -8deg));
}
.hero__tagline.is-split.is-live .ltr {
  animation: ltr-pop .55s cubic-bezier(.3, 1.4, .4, 1) calc(var(--i, 0) * .04s) forwards;
}
@keyframes ltr-pop {
  0%   { opacity: 0; transform: translateY(.6em) scale(.4) rotate(calc(var(--tilt, 1) * -8deg)); }
  60%  { opacity: 1; transform: translateY(-.09em) scale(1.06) rotate(calc(var(--tilt, 1) * 3deg)); }
  100% { opacity: 1; transform: none; }
}

.wordmark img { width: 100%; height: auto; }

/* ==================================================================
   Scene — flower + vases, fixed to the viewport (scene.js animates).
   Sits ABOVE the content (z 4 > .page's 3): the flower is never
   eclipsed by anything — its width is capped instead so it cannot
   cross the text column (see .flower).
   ================================================================== */
.scene { position: fixed; inset: 0; z-index: 4; pointer-events: none; }

.flower {
  position: absolute;
  /* Foreground flower must never block text: cap the width so the left
     edge stays a 24px gutter away from the centred column. Short pages
     shrink it further via --flower-scale (set by scene.js); at the end
     of the one-pager --scene-scale (html.is-end) makes room for the
     wordmark. */
  --flower-w-r: calc(min(clamp(230px, var(--flower-w), 780px),
                         calc(50vw - var(--col) / 2 - 24px - var(--flower-right)))
                     * var(--flower-scale, 1) * var(--scene-scale, 1));
  /* Hangs level with the hero tagline — but anchored to the floor: on
     tall viewports the flower slides down so the stem's end stays
     ≥12.5% of the viewport below the bottom edge, deeper than the max
     scroll rise (12vh, scene.js), so the stem never lifts out of the
     page bottom. (112.5% = scene height + reserve; .scene is the
     containing block.) */
  top: max(calc(88px + 5.5vw),
           calc(112.5% - var(--flower-w-r) / var(--flower-ar)));
  /* the offscreen shift scales with the flower, keeping the same crop —
     BOTH scales: without --scene-scale the producten flower (×.55) kept
     its full-size shift and all but vanished off the right edge */
  right: calc(var(--flower-right) * var(--flower-scale, 1) * var(--scene-scale, 1));
  width: var(--flower-w-r);
  aspect-ratio: var(--flower-ar);
  container-type: inline-size;
  transform-origin: 55% 88%;
  will-change: transform;
}
.flower__inner {
  width: 100%; height: 100%;
  transform-origin: 55% 95%;
  animation: flower-sway 11s ease-in-out infinite alternate;
}
.flower__inner svg { width: 100%; height: 100%; display: block; overflow: visible; }
.flower__text {
  position: absolute;
  top: var(--quote-top);
  left: var(--quote-cx);
  transform: translateX(-50%) rotate(calc(var(--wind, 0) * 4deg));
  transform-origin: 50% 130%;
  width: var(--quote-w);
  margin: 0;
  text-align: center;
  font-family: "Averia Serif Libre", Georgia, serif;
  font-size: var(--quote-fs);
  line-height: 1.2;
  letter-spacing: var(--serif-track);
  color: var(--bubble-ink);
}

/* ---- the bloemtekst is TYPED into the bloom and nothing else: no fade,
   no scale, no rotate, no transition of any kind on the quote. The only
   motion is characters arriving (scene.js) — the element is simply there
   from the start, holding an empty string until the typewriter fills it.
   Anything that eased the whole line in read as a zoom, which the flower
   (flat paper artwork) can never be.
   The typed line lives on .flower__tease; the real .flower__text is
   hidden outright and kept for assistive tech. Keyed on .js: without JS
   there is no tease element and the quote simply shows. The flower's
   painted shapes take the pointer (visiblePainted), so only the artwork
   is clickable, never its empty bounding box. ---- */
.js .flower .flower__text:not(.flower__tease) {
  opacity: 0;
  pointer-events: none;
}
.js .flower .flower__tease {
  white-space: pre-line; /* typed text keeps its line breaks */
  pointer-events: auto;
  cursor: pointer;
}
.js .flower.has-quote .flower__inner svg { pointer-events: visiblePainted; cursor: pointer; }

/* The caret: an ink stroke riding the end of the line. It holds STEADY
   through the keystrokes — a caret blinking while the letters land is
   two rhythms fighting — then blinks a few times at the finished
   sentence and is gone, so the quote is left as a clean line of type.
   An empty ::after sits on the text baseline and inherits the quote's
   own colour and size. */
.js .flower .flower__tease::after {
  content: "";
  display: inline-block;
  width: .07em;
  height: .82em;
  margin-left: .06em;
  vertical-align: -.1em;
  background: currentColor;
  opacity: 0;
}
@media (prefers-reduced-motion: no-preference) {
  .js .flower.is-typing .flower__tease::after { opacity: .72; }
  .js .flower.is-open:not(.is-typing) .flower__tease::after {
    animation: quote-caret .62s steps(1) 4 forwards;
  }
  @keyframes quote-caret {
    0%, 50% { opacity: .72; }
    50.01%, 100% { opacity: 0; }
  }
}

/* ---- flower parts: idle breathing (individual `rotate` keyframes)
   composes with the wind response (`transform`, driven by --wind from
   scene.js). transform-box makes origins local to each part.
   The stem stays rigid inside the SVG — whole-plant sway lives on
   .flower/.flower__inner — so hinged parts never drift off it. ---- */
.f-bloom, .f-leaf, .f-stamen, .f-sprig {
  transform-box: fill-box;
  transform: rotate(calc(var(--wind, 0) * var(--winddir, 1) * var(--amp, 4deg)));
}
.f-bloom  { --amp: 5deg;  animation: sway-soft 6.5s -2.1s ease-in-out infinite alternate; }
.f-leaf   { --amp: 6deg;  animation: sway-leaf 5.5s ease-in-out infinite alternate; }
.f-leaf-2 { --amp: -5deg; animation-duration: 7.2s; animation-delay: -1.6s; }
.f-leaf-3 { --amp: 7deg;  animation-duration: 6.1s; animation-delay: -3.1s; }
.f-stamen { --amp: 13deg; animation: sway-stamen 4.6s ease-in-out infinite alternate; }
.f-stamen-2 { animation-delay: -1.4s; animation-duration: 5.3s; }
.f-stamen-3 { animation-delay: -2.6s; animation-duration: 4.1s; }
.f-sprig  { --amp: 5deg;  animation: sway-leaf 7.6s -2.4s ease-in-out infinite alternate; }
/* This artwork is mirrored by a wrapper <g>; flip its wind response so
   the parts lean the same way as the (screen-space) container sway. */
[data-flower="waar-te-koop"] { --winddir: -1; }

/* Hinge points — measured from the SVG geometry (closest point of each
   part's outline to the stem centerline; scratchpad/measure.html rig).
   Each part pivots exactly where it attaches — leaves/sprigs on the
   stem, the bloom on the stem overlap, stamens where they sit on the
   bloom (and they ride inside the bloom group) — so attachments cannot
   open up during movement. Keyed on the <svg data-flower> root because
   during page transitions two [data-page] scopes exist at once. */
[data-flower="over-bloum"]   .f-leaf-1   { transform-origin: 4.4% 89.9%; }
[data-flower="over-bloum"]   .f-leaf-2   { transform-origin: 4% 83.8%; }
[data-flower="over-bloum"]   .f-leaf-3   { transform-origin: 97.2% 92.8%; }
[data-flower="over-bloum"]   .f-bloom    { transform-origin: 49.1% 90.9%; }
[data-flower="over-bloum"]   .f-stamen-1 { transform-origin: 58.8% 100%; }
[data-flower="over-bloum"]   .f-stamen-2 { transform-origin: 41.4% 100%; }
[data-flower="over-bloum"]   .f-stamen-3 { transform-origin: 52.3% 100%; }
[data-flower="waar-te-koop"] .f-leaf-1   { transform-origin: 4.2% 88.8%; }
[data-flower="waar-te-koop"] .f-leaf-2   { transform-origin: 98.8% 99.5%; }
[data-flower="waar-te-koop"] .f-sprig    { transform-origin: 4.4% 98.4%; }
[data-flower="waar-te-koop"] .f-bloom    { transform-origin: 55.2% 55.8%; }
[data-flower="producten"]    .f-leaf-1   { transform-origin: 4.2% 72.2%; }
[data-flower="producten"]    .f-leaf-2   { transform-origin: 98.5% 87%; }
[data-flower="producten"]    .f-sprig    { transform-origin: 4.1% 97.4%; }
[data-flower="producten"]    .f-bloom    { transform-origin: 55.7% 98.4%; }
/* margriet/zonnebloem are drawn to spec (templates/_svg), hinges known
   by construction rather than measured */
[data-flower="margriet"]     .f-leaf-1   { transform-origin: 100% 1%; }
[data-flower="margriet"]     .f-leaf-2   { transform-origin: 0% 1%; }
[data-flower="margriet"]     .f-bloom    { transform-origin: 50.6% 65%; }
[data-flower="zonnebloem"]   .f-leaf-1   { transform-origin: 0% 1%; }
[data-flower="zonnebloem"]   .f-leaf-2   { transform-origin: 100% 1%; }
[data-flower="zonnebloem"]   .f-bloom    { transform-origin: 50.9% 67.9%; }

@keyframes sway-soft   { from { rotate: -.7deg; }  to { rotate: .9deg; } }
@keyframes sway-leaf   { from { rotate: -1.7deg; } to { rotate: 2.1deg; } }
@keyframes sway-stamen { from { rotate: -2.4deg; } to { rotate: 2.8deg; } }

/* Vases stand on the viewport floor; they pivot on their base
   (scene.js's scroll response is rotation-only) so they never lift
   off it. No idle loop: objects hold still — only flowers breathe
   (the focal map, over-bloum.twig). */
.vases {
  position: absolute;
  left: clamp(12px, 7.8vw, 128px);
  bottom: 0;
  width: calc(clamp(104px, var(--vases-w), 300px) * var(--scene-scale, 1));
  aspect-ratio: var(--vases-ar);
  transform-origin: 50% 100%;
  will-change: transform;
}
/* Geometry morphs — a section change re-themes the scene ([data-page]/
   [data-vases] swap on <html>) and the end-of-page shrink scales it —
   glide instead of jump. The flower is at scale 0 (mid-swap) or the
   vases below the floor for most of a morph. */
@media (prefers-reduced-motion: no-preference) {
  .flower { transition: width .8s ease, top .8s ease, right .8s ease,
            scale .7s cubic-bezier(.3, 1.25, .45, 1); }
  /* bowing out is quicker than coming back (the regrow above springs) */
  .is-end .flower { transition: width .8s ease, top .8s ease, right .8s ease,
                    scale .45s cubic-bezier(.55, 0, .8, .4); }
  /* opacity: the theatre fades the corner pair out and back */
  .vases  { transition: width .8s ease, opacity .45s ease; }
  .vases--end { transition: width .8s ease, translate .5s cubic-bezier(.55, 0, .8, .4); }
  .is-end .vases--end { transition: width .8s ease, translate .65s cubic-bezier(.2, .9, .3, 1.15) .1s; }
}
.is-end { --scene-scale: .76; }
/* The send-off: at the footer the flower steps aside entirely — the
   wordmark gets the whole stage width — and the .vases--end pair rises
   bottom-right to see the visitor out. !important outranks the held
   entrance fill and the inline scale the panel swaps pin on the flower. */
.is-end .scene .flower { scale: 0 !important; }
.is-end .vases--end { translate: 0 0; }
/* z stride of 10 leaves room for each vase's sprout at vase-z + 5:
   a sprout sits in FRONT of its own vase but still BEHIND the other
   vase when that one overlaps from the front (e.g. sprout-b 15 <
   vase-a 20 when --vase-a-z is 2).
   The vases themselves are clickable (swap the guest flower, scene.js)
   even though the scene overlay ignores the pointer. */
.vases img { position: absolute; height: auto; transform-origin: 50% 92%; }
.js .vases img { pointer-events: auto; cursor: pointer; }
.vases__a {
  left: var(--vase-a-l); top: var(--vase-a-t); width: var(--vase-a-w);
  z-index: calc(var(--vase-a-z) * 10);
}
.vases__b {
  left: var(--vase-b-l); top: var(--vase-b-t); width: var(--vase-b-w);
  z-index: calc(var(--vase-b-z) * 10);
}

/* ---- the send-off pair: a second vase duo, mirrored bottom-RIGHT,
   waiting under the viewport floor until the footer scrolls into view
   (html.is-end, above): the big flower bows out and these rise to see
   the visitor off. It is the producten pair — benched from the section
   rotation (its purple vase vanishes on the violet canvas), it reads
   fine against the papier footer sheet and the zonnegeel canvas. Same
   width formula as the left pair, geometry copied from
   [data-vases="producten"]. No sprouts, no click-swap: they just
   stand there. ---- */
.vases--end {
  left: auto;
  right: clamp(12px, 7.8vw, 128px);
  --vases-w: 15.86vw; --vases-ar: 0.8126;
  --vase-a-l: 0%;     --vase-a-t: 27.53%; --vase-a-w: 62.06%; --vase-a-z: 2;
  --vase-b-l: 38.54%; --vase-b-t: 0%;     --vase-b-w: 61.46%; --vase-b-z: 1;
  translate: 0 130%;
}
.js .vases--end img { pointer-events: none; cursor: default; }

/* ---- sprouts: flowers from OTHER pages that grow out of the vases
   after a long beat (delays on the .is-in animations below). Placement
   is surgical: each --sprout-* set (per [data-page], measured from the
   SVGs) puts the flower's stem base just below the centre of its vase's
   black mouth oval. The sprout sits in FRONT of its vase (z = vase-z
   ×10 + 5) so leaves drape over the neck like a real bouquet, and is
   clipped at the waterline (--sprout-*-water = the mouth oval's centre):
   the stem's cut end lands inside the black oval — black on black, an
   invisible seam — so the flower reads as coming OUT of the opening.
   The generous negative insets keep the top/side overflow of the sway
   animations unclipped. All in/out motion (the entrance below, swaps in
   scene.js/onepage.js) rides the INNER svg: the clip stays put on the
   sprout box, so a flower translated down genuinely sinks into the vase
   and one translated up climbs out of the mouth. The rotate origin is
   the stem-base point, so the flower sways around it. ---- */
.sprout {
  position: absolute;
}
/* Colour-adjacent staging per section (Jason, the product-card
   logic: art stays in the canvas's family, only the message runs
   full contrast). On koraalrood every scene flower flattens into ONE
   blush silhouette, on violetpaars into lilac — whatever artwork
   stands or gets click-swapped in (!important outranks baked-in
   style fills); stems keep the black house line. The fill transition
   lets the flatten crossfade with the scheme instead of snapping. */
.scene .sprout svg [fill],
.scene .flower svg [fill] { transition: fill .9s ease; }
[data-scheme="koraalrood"] .scene .sprout svg [fill]:not([fill="none"]),
[data-scheme="koraalrood"] .scene .flower svg [fill]:not([fill="none"]) {
  fill: #ffb4a9 !important;
}
[data-scheme="violetpaars"] .scene .sprout svg [fill]:not([fill="none"]),
[data-scheme="violetpaars"] .scene .flower svg [fill]:not([fill="none"]) {
  fill: #d9b8ef !important;
}
.sprout svg { width: 100%; height: auto; display: block; overflow: visible; will-change: translate, scale; }
/* through the waterline the flower travels TUCKED — scale x pinched
   around the stem anchor so the leaves sweep up against the stem and
   nothing wide ever meets the flat clip edge (sink/riseSprout,
   scene.js; the entrance below rises the same way). The svg pivots on
   the same stem-base origin as its sprout box. */
.sprout--a svg { transform-origin: var(--sprout-a-o); }
.sprout--b svg { transform-origin: var(--sprout-b-o); }
.sprout--a {
  left: var(--sprout-a-l);
  bottom: var(--sprout-a-b);
  width: var(--sprout-a-w);
  transform-origin: var(--sprout-a-o);
  rotate: -2.5deg;
  z-index: calc(var(--vase-a-z) * 10 + 5);
  clip-path: inset(-60% -60% calc(100% - var(--sprout-a-water)) -60%);
}
.sprout--b {
  left: var(--sprout-b-l);
  bottom: var(--sprout-b-b);
  width: var(--sprout-b-w);
  transform-origin: var(--sprout-b-o);
  rotate: 2.5deg;
  z-index: calc(var(--vase-b-z) * 10 + 5);
  clip-path: inset(-60% -60% calc(100% - var(--sprout-b-water)) -60%);
}

@keyframes flower-sway {
  from { transform: rotate(-.35deg) translateY(0); }
  to   { transform: rotate(.45deg) translateY(-4px); }
}

/* ---- entrance: nothing in the scene shows right away. scene.js stamps
   .is-in once the page has landed (initial load + after every swap):
   vases rise from the floor, the flower grows from its stem base, and
   much later the sprouts climb out of the vase mouths — same in/out
   language as the swaps (sink/riseSprout in scene.js). Hidden states
   are scoped to .js + motion-OK so the scene is simply visible without
   JS / with reduced motion. ---- */
@media (prefers-reduced-motion: no-preference) {
  .js .scene .flower { scale: 0; }
  .js .scene .vases:not(.vases--end)  { translate: 0 130%; }
  .js .scene .sprout svg { translate: 0 112%; scale: .1 1.04; }
  .js .scene.is-in .vases:not(.vases--end)  { animation: vases-rise .7s cubic-bezier(.2, .9, .3, 1.15) .1s forwards; }
  .js .scene.is-in .flower { animation: flower-grow .95s cubic-bezier(.3, 1.25, .45, 1) .4s forwards; }
  .js .scene.is-in .sprout--a svg { animation: sprout-rise .9s cubic-bezier(.3, 1.4, .45, 1) 4.5s forwards; }
  .js .scene.is-in .sprout--b svg { animation: sprout-rise .9s cubic-bezier(.3, 1.4, .45, 1) 8.5s forwards; }
}
@keyframes flower-grow { from { scale: 0; } to { scale: 1; } }
@keyframes vases-rise  { from { translate: 0 130%; } to { translate: 0 0; } }
/* 112% sits every flower below the deepest waterline (89.4%) with room
   for the sway overshoot; it climbs out TUCKED (leaves swept up along
   the stem, clear of the clip edge) and the bouncy bezier pops it past
   its rest, unfurling, and settles */
@keyframes sprout-rise {
  from { translate: 0 112%; scale: .1 1.04; }
  to   { translate: 0 0; scale: 1 1; }
}

/* ==================================================================
   Page content — a full-bleed papier sheet with big rounded top
   corners rising under the accent hero (mindmarket-style: a colour
   change, not a box). The horizontal padding centres the Figma column;
   flex: 1 stretches the sheet to the footer on short pages.
   ================================================================== */
.page {
  position: relative;
  z-index: 3;
  flex: 1;
  width: 100%;
  margin: clamp(72px, 8.82vw, 150px) 0 0;
  padding: clamp(48px, 6vw, 88px)
           max(16px, calc((100% - var(--col)) / 2))
           clamp(40px, 5vw, 72px);
  background: var(--papier);
  border-radius: clamp(28px, 4vw, 44px) clamp(28px, 4vw, 44px) 0 0;
}
/* transitions.js focuses the column after a swap (a11y); no ring needed */
.page:focus { outline: none; }

/* ==================================================================
   Footer — the giant full-bleed wordmark closes the page on the papier
   sheet (it keeps its intrinsic ratio). Nothing else lives here.
   ================================================================== */
.site-footer {
  width: 100%;
  margin: 0;
  padding: clamp(40px, 6vw, 96px) clamp(12px, 1.67vw, 32px) clamp(24px, 3vw, 48px);
  background: var(--papier);
}

/* ==================================================================
   Producten — the picture tiles + lightbox
   ================================================================== */
.gallery__item {
  border: 0; padding: 0; margin: 0; background: none; cursor: zoom-in;
  border-radius: 20px; overflow: hidden; display: block;
}
.gallery__item img { width: 100%; height: auto; }

.lightbox {
  position: fixed; inset: 0; z-index: 50;
  display: flex; align-items: center; justify-content: center;
  padding: 4vmin; background: rgba(20, 18, 14, .88);
}
.lightbox[hidden] { display: none; }
.lightbox__img { max-width: 92vw; max-height: 92vh; width: auto; height: auto; border-radius: 6px; }
.lightbox__close {
  position: absolute; top: 1rem; right: 1.25rem;
  width: 2.5rem; height: 2.5rem; border: 0; border-radius: 50%;
  background: rgba(255, 255, 255, .15); color: #fff; font-size: 1.6rem; line-height: 1; cursor: pointer;
}
.lightbox__close:hover { background: rgba(255, 255, 255, .28); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ==================================================================
   Stacked — below ~1020px the column + a side flower no longer fit,
   so the flower becomes a centred hero between wordmark and text
   (it stays in the foreground but has nothing left to block).
   Vases need clear floor space, so they bow out here.
   ================================================================== */
@media (max-width: 1020px) {
  :root { --fwm: clamp(170px, 40vw, 320px); }  /* hero flower width */
  /* NO SCENE on a stacked layout (2026-08). onepage.js deliberately
     never re-themes the scene below 1021px — --flower-ar sizes the
     content margins there, so a mid-scroll swap would jump the whole
     document under the reader — which means the scene is stuck with
     whatever the server rendered, parked at the TOP of the page. It
     used to be the opener's own flower, so that was free. Now the top
     of the page is a photograph of the product and the section under
     it is three more photographs: a 320px cartoon tulip parked across
     both is the exact thing this redesign removes. The flower is a
     desktop motif; the phone gets the photographs. */
  .scene { display: none; }
  .hero {
    min-height: 0;
    padding: calc(84px + 4vw) 20px 28px;
  }
  .hero__tagline { max-width: none; }
  /* the compact opener is full already: no sky */
  .flower {
    /* flush under the hero text; scene.js measures --hero-h */
    top: calc(var(--hero-h, calc(200px + 28vw)) + 8px);
    right: calc(50% - var(--fwm) * var(--flower-scale, 1) / 2);
    width: calc(var(--fwm) * var(--flower-scale, 1));
  }
  /* no parked flower to clear any more: the sheet starts at the top */
  .page { margin-top: 0; }
}

@media (max-width: 760px) {
  .topnav {
    top: 12px; left: 12px; right: 12px;
    transform: none;
    width: auto;
    padding: 7px 12px;
    gap: .25rem;
  }
  .topnav__brand img { height: 22px; }
  /* links and socials fold into the menusheet; the pill keeps the
     wordmark (room for it again, at every width) + the menu button */
  .topnav__links, .topnav__social { display: none; }
  .hero { padding-top: calc(64px + 4vw); }
  .page { padding-inline: max(20px, calc((100% - var(--col)) / 2)); }
  .site-footer { padding: 28px 14px 22px; }
}

@media (prefers-reduced-motion: reduce) {
  .flower__inner,
  .f-bloom, .f-leaf, .f-stamen, .f-sprig { animation: none; }
}

/* ==================================================================
   Page transitions — the next page rises from the bottom edge as an
   opaque sheet over the current one (transitions.js) while the old
   page shrinks back, then gets promoted into the document. While the
   sheet is transformed it is the containing block for its own fixed
   .scene, so the incoming page renders complete inside it. Sits under
   .topnav (z 20): the menu pill persists across pages. The sheet is
   the incoming page's accent colour (its own data-scheme).
   ================================================================== */
.transition-sheet {
  position: fixed;
  inset: 0;
  z-index: 15;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--accent);
  border-radius: clamp(28px, 4vw, 44px) clamp(28px, 4vw, 44px) 0 0;
  transform: translateY(103%);   /* a hair past 100% so the shadow starts offscreen */
  box-shadow: 0 -16px 48px rgba(4, 4, 4, .25);
  will-change: transform;
}

/* ==================================================================
   One-pager (over-bloum.twig) — four full-height panels scroll over
   ONE canvas that crossfades between the section schemes (data-scheme
   flips on <html>, the registered --accent/--ink-on/--tint-deep do the
   fading). No papier sheet between sections: the page IS the canvas,
   text sits directly on the accent in scheme-aware inks, and the fixed
   scene re-themes itself per section (onepage.js). The papier returns
   once, as the footer sheet under the giant wordmark.
   ================================================================== */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

.onepage .panel {
  --pad-x: clamp(20px, 7.8vw, 128px);
  position: relative;
  z-index: 1;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  gap: clamp(16px, 2.2vw, 26px);
  padding: calc(88px + 5.5vw) var(--pad-x) clamp(64px, 10svh, 140px);
  color: var(--ink-on);
  /* flying deck cards and the travelling filmstrip poke past the
     viewport: clip them at the panel — clip, NOT hidden, so the
     sticky mechanics keep working (no scroll container) and no rogue
     horizontal scrollbar appears */
  overflow-x: clip;
}
/* the manifesto opens on whitespace: the verhaal waits BELOW the fold
   — 55svh keeps the first verse under the edge on tall desktop
   viewports too (the stacked layout overrides this margin with its own
   flower clearance, so small screens keep their tighter open) */
.onepage #manifest .panel__content { margin-top: 55svh; }

/* ---- the focal map's scene sizes (see over-bloum.twig): the scene
   is co-lead on the opening panel and supporting cast everywhere
   after — a step smaller where a card leads, half-size
   where the photos own the whole canvas. Keyed on [data-page], which
   the one-pager flips per section (wide layout only; the stacked
   layout pins data-page and keeps the designed size). Set on BODY so
   these override the html-level subpage/is-end values by inheritance
   proximity; the is-end rule last, so the footer keeps its own step
   whatever panel owned the scroll. The .flower/.vases width
   transitions glide the resizes. ---- */
/* The scene is a MOTIF now: full size only on the manifesto, where it
   is the one thing keeping a long read company, and a step down on the
   two utility panels. Everywhere else flower-key is "none" and
   onepage.js scales it away — a vector flower over a product
   photograph is the fight this rebuild exists to end. */
[data-page="waar-te-koop"] body.onepage,
.is-end body.onepage { --scene-scale: .76; }

/* ==================================================================
   Het bloementheater — the lines live ON THE VASES, where the real
   Bloum card prints its message. While the theatre panel is active
   (html.is-theater, onepage.js) the big flower is gone (flower-key
   "none") and the scene's corner vases FADE with it: the panel
   brings its own .stage — two tone-on-tone green vases that never
   move. scene.js BloumTheater grows a flower out of the active vase
   per runway step and types the line onto its belly; the partner
   vase keeps the previous line standing. The vases are deep leaf
   greens and the typed line is papier white, so the message stays the
   full-contrast thing on the stage — but the FLOWERS carry their own
   colours (aug 2026), because a paper flower that is coloured is the
   product, and a green flower on a green stage is not showing it.
   ================================================================== */
.is-theater .scene .vases:not(.vases--end) { opacity: 0; }
.is-theater .scene .vases:not(.vases--end) img { pointer-events: none; }

/* the stage: centred in the pin's leftover height like every other
   panel's one big thing. Sized against BOTH axes (the svh term keeps
   the box under the tagline on short viewports) so headline and
   stage always share the screen without touching; shrink is off so
   the text geometry never distorts. Only the wide motion layout
   stages it — everyone else reads the fallback lines. */
.stage { display: none; }
@media (min-width: 1021px) and (prefers-reduced-motion: no-preference) {
  .js .stage {
    display: block;
    position: relative;
    container-type: inline-size;
    margin: auto;
    flex-shrink: 0;
    /* the vases run BIG — Jason, four rounds: bigger, bigger. The
       box is a FLOOR ANCHOR, not a frame: its own height (aspect
       100/46) only has to fit between the tagline and the floor,
       while the bottom-anchored pots overshoot its top and rise
       BEHIND the headline (their mouths are tone-on-tone greens in
       the theater-a|b files for exactly this — black mouths turned
       to mush behind the black tagline). The svh term keeps the box
       under the tagline; cqw stays the type ruler. */
    width: min(clamp(480px, 64vw, 1080px), 217svh - 971px);
    aspect-ratio: 100 / 46;
  }
}
/* the imgs and sprouts reuse the scene's class rig (so scene.js
   placeSprout works verbatim), but the scene's [data-vases] geometry
   vars leak in through the same classes: neutralise top/left/z here
   — the stage lays its own floor and stacks text above everything */
.stage img { position: absolute; top: auto; bottom: 0; height: auto; }
/* the pair takes turns speaking (Jason: switch between the two) — a
   stays the elder pot, b the slighter, both bellies big enough to
   carry a line. Bottom-anchored, nearly touching: two pots on one
   shelf, mouths leaning together. */
.stage .vases__a { left: 0; right: auto; width: 54%; z-index: 10; }
.stage .vases__b { left: auto; right: 1%; width: 44%; z-index: 10; }
.stage .sprout { position: absolute; z-index: 20; }
.stage .sprout svg { display: block; width: 100%; height: auto; }
/* the theatre flowers keep their OWN colours (Jason, aug 2026: restore
   the colour). They used to flatten into one pale green silhouette,
   which on a green stage made the whole panel one hue and hid the
   thing Bloum actually sells: a paper flower that is coloured. The
   artwork inks itself from templates/_svg — petals on their baked-in
   fills (yellow, orange, coral), foliage through --leaf-light /
   --leaf-dark, which the bladgroen scheme already darkens to #007553
   so leaves never sink into the canvas behind them. Stems stay the
   black house line. The transition lets the foliage recolour through
   a scheme crossfade instead of snapping. */
.stage .sprout svg [fill] { transition: fill .9s ease; }
/* the line on the vase: papier type on the belly. The PRINT card is
   the spec (Jason, round 10): ONE size on both pots, the print
   card's line rhythm, no tracking, and the block ALWAYS inside the
   silhouette with the card's healthy padding.

   --fit is the step-down scene.js applies when a quote is too long
   for its pot (see --cap below). One base size still serves both
   pots; --fit only ever takes a long quote DOWN from it, so a short
   line reads at full size on either pot and nothing is ever set at a
   size the belly cannot hold. */
.stage__text {
  position: absolute;
  z-index: 30;
  margin: 0;
  translate: -50% -50%;
  text-align: center;
  white-space: pre-line;
  pointer-events: none;
  font-family: "Averia Serif Libre", Georgia, serif;
  font-weight: 400;
  font-size: calc(3.3cqw * var(--fit, 1));
  line-height: 1.28;
  letter-spacing: var(--serif-track);
  color: var(--papier);
  transition: opacity .4s ease;
}
.stage.is-off .stage__text { opacity: 0; }
/* per pot: the block is THE LARGEST RECTANGLE THAT FITS THE POT
   (aug 2026 — the old box was hung on the silhouette's area centroid
   with no height limit at all, so a seven-line quote on the slighter
   right pot grew straight out of the belly and down the foot taper).

   Both pots are the same path (theater-b is theater-a mirrored), so
   one measurement serves both. Sampling the fill itself at 240 rows
   and searching every row pair for the biggest inscribed rectangle,
   with 5% of the pot's width of padding on all four sides:

     width  .508 × potW      centre x  .517 × potW  (b mirrors: .483)
     height .575 × potW      centre y  .554 × potH
                             ( = .412 × potH )

   That centre sits LOWER than the old centroid (.554 vs .517 H): the
   widest part of an amphora is below its middle, and hanging type on
   the area centroid pushed every block up into the shoulder.

   Tops in cqw, not %: the pots overshoot the anchor box (pot height =
   1.396 × width), so only the width ruler is stable —
   top = .554 × potH − (potH − 46). UNROTATED — the tilt-with-the-pot
   try read as childish (Jason).

   --cap is that rectangle's height in cqw, which scene.js reads to
   step the type down when a quote will not fit:
     a: .575 × 54 = 31.0    b: .575 × 44 = 25.3 */
.stage__text--a { left: 27.9%; top: 12.4cqw; width: 27.4%; --cap: 31; }
.stage__text--b { left: 76.3%; top: 18.6cqw; width: 22.4%; --cap: 25.3; }
/* the relieved line: completed, dimmed, standing on the partner vase
   while the fresh one types — one voice at full contrast */
.stage__text.is-quiet { opacity: .35; }
/* the headliner keeps the house voice and always reads: where a
   flower tip reaches the words it passes BEHIND them, the same depth
   language as the bee behind the manifesto */
.panel--theater .hero__tagline { position: relative; z-index: 1; }
.panel--theater .stage { z-index: 0; }
/* the pots stand nearly on the viewport floor (Jason: move it down a
   little): the bigger pair needs the headroom — with the house bottom
   padding the elder vase's black mouth grazed the tagline's baseline.
   (The doubled class outranks the house pin rule, which sits later
   in this file.) */
.onepage .panel--pin.panel--theater .panel__pin { padding-bottom: clamp(12px, 3svh, 36px); }
.panel--theater .stage { margin-bottom: 0; }

/* the stacked theatre: ONE pot fits a phone (Jason, round 10 — the
   static fallback list was "lazy"), so the elder amphora takes the
   stage alone and EVERY line types onto the same belly (scene.js
   solo mode; the b pot, its sprout and its text sit out). Same
   inscribed-rectangle maths as the pair, pot width .76 of the box:
   potH = 1.396 × 76 = 106.1cqw, overshoot over the box top 11.1cqw,
   top = .554 × 106.1 − 11.1. One pot carries print-ratio type
   (5.4cqw) — there is no partner to share a size with — and the same
   --cap step-down keeps a long quote inside the belly. The theatre's leaf
   streamers stay ON here (they hide on stacked everywhere else):
   the pin holds four steps, and without the leaves riding the true
   scroll nothing tracks the thumb — Jason's feels-stuck rule. */
@media (max-width: 1020px) and (prefers-reduced-motion: no-preference) {
  .js .stage {
    display: block;
    position: relative;
    container-type: inline-size;
    margin: auto auto 0; /* the pot stands on the pin's floor */
    flex-shrink: 0;
    width: min(88vw, 56svh);
    aspect-ratio: 100 / 95;
  }
  .js .stage .vases__b,
  .js .stage .sprout--b,
  .js .stage .stage__text--b { display: none; }
  .js .stage .vases__a { left: 12%; width: 76%; }
  .js .stage .stage__text--a {
    left: 51.3%; top: 47.7cqw; width: 38.6%;
    font-size: calc(5.4cqw * var(--fit, 1));
    --cap: 43.7; /* .575 × 76 */
  }
  .js .theater-fallback { display: none; }
  .panel--theater .streamers { display: block; }
}

/* the fallback: stacked layouts (no vases), reduced motion and no-JS
   read the dealt lines as quiet type instead of theatre */
.theater-fallback { gap: clamp(20px, 3vw, 36px); }
.qline {
  margin: 0;
  text-align: center;
  font-family: "Averia Serif Libre", Georgia, serif;
  font-size: clamp(1.15rem, 1rem + .8vw, 1.5rem);
  line-height: 1.4;
  letter-spacing: var(--serif-track);
  color: var(--ink-on);
}
@media (min-width: 1021px) and (prefers-reduced-motion: no-preference) {
  .js .theater-fallback { display: none; }
}

/* ==================================================================
   Streamers — passing scenery at TRUE scroll speed (_streamers.twig):
   paper LEAVES scattered down a panel's full height, runway
   included. Static content: the page itself carries them past the
   held pin, so something always moves vertically with the mouse
   while a pin holds (Jason's rule — a scroll where nothing tracks
   the hand feels stuck; flowers riding by were vetoed, a leaf may
   drift). No parallax, no spin. Tinted from the LIVE --accent, so
   they crossfade with the canvas and stay colour-adjacent on every
   scheme; z −1 keeps them behind the section's content inside the
   panel's stacking context.
   ================================================================== */
.streamers {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: clip;
  pointer-events: none;
}
.streamers__leaf {
  position: absolute;
  width: calc(var(--ss, 1) * clamp(44px, 4.5vw, 84px));
  rotate: var(--sr, 0deg);
}
.streamers__leaf svg { display: block; width: 100%; height: auto; }
.streamers__leaf svg [fill]:not([fill="none"]) {
  fill: color-mix(in srgb, var(--accent) 70%, var(--papier));
}
@media (max-width: 1020px) { .streamers { display: none; } }
/* leaves belong to the COLOURED screens. Tinted from --accent for a
   canvas of the same family they read as passing scenery; on papier
   they read as litter dropped on the page. */
html[data-canvas="papier"] .streamers,
html[data-canvas="wit"] .streamers { display: none; }

/* ==================================================================
   De vlucht — paper critters that ANSWER THE SCROLL. One at a time,
   and only on two of the six panels: the bee keeps the manifesto
   company for the long read, and a butterfly crosses the message
   cards (scrollfx.js SECTIONS). Never over the opening photograph, the
   carousel or the address list. The crossing is driven frame by frame
   from scrollfx.js — scroll velocity carries it, the cursor gives it a
   weak lean — so all that lives here is the body bob, the wingbeats
   and the --face flip. Art is contrast-checked: zonnegeel + inkt +
   papier reads on every canvas.

   z 2 — OVER the panels (z 1), under the scene (4) and the nav (20).
   It used to be 0, deliberately under the panels' text so a crossing
   could never get between the reader and the manifesto. That worked
   only while every panel was a transparent colour wash: the critter
   showed through against the body's canvas. The panels now carry
   opaque PHOTOGRAPHS, and a critter behind one is simply a critter you
   never see (Jason, from the opening screen). It flies in front now —
   which is what a thing with wings should be allowed to do.
   ================================================================== */
.bee {
  position: fixed;
  top: 0; left: 0;
  width: clamp(64px, 7vw, 108px);
  z-index: 2;
  pointer-events: none;
  will-change: transform;
  transition: opacity .6s ease;
}
/* the send-off is the wordmark's: any flyer bows out at the footer */
html.is-end .bee { opacity: 0; }
.bee svg { display: block; width: 100%; height: auto; }
/* --face flips to face the direction of travel; the transition turns
   the sprite around instead of snapping it (the companion flyer) */
.bee__face { display: block; transform: scaleX(var(--face, 1)); transition: transform .45s ease; }
@media (prefers-reduced-motion: no-preference) {
  @keyframes bee-bob  { from { translate: 0 -10px; } to { translate: 0 10px; } }
  @keyframes bee-flap { from { rotate: -16deg; }     to { rotate: 14deg; } }
  .bee__bob { display: block; animation: bee-bob var(--bob-t, 3.1s) ease-in-out infinite alternate; }
  .bee__wing {
    transform-box: fill-box;
    transform-origin: 50% 92%;
    animation: bee-flap .2s ease-in-out infinite alternate;
  }
  .bee__wing--back { animation-duration: .24s; animation-delay: -.09s; }

  /* butterflies: a floatier hover and a slower, deeper wingbeat. Each
     wing pair pivots on its base point, which the SVG puts exactly at
     the max/min corner of the pair's fill-box (scrollfx.js vlinderSVG):
     near pair bottom-right, far pair bottom-left. The pairs beat in
     mirrored phase so they open and close together. */
  @keyframes vlinder-bob       { from { translate: 0 -14px; } to { translate: 0 12px; } }
  @keyframes vlinder-flap      { from { rotate: -14deg; }     to { rotate: 16deg; } }
  @keyframes vlinder-flap-back { from { rotate: 14deg; }      to { rotate: -16deg; } }
  .bee--vlinder .bee__bob { animation-name: vlinder-bob; }
  .bee--vlinder .bee__wing {
    transform-origin: 100% 100%;
    animation: vlinder-flap .52s ease-in-out infinite alternate;
  }
  .bee--vlinder .bee__wing--back {
    transform-origin: 0% 100%;
    animation: vlinder-flap-back .52s ease-in-out infinite alternate;
  }
}

/* ==================================================================
   Verhaal — the textual opener: the story as plain typeset verses,
   TWO stanzas per screen, staggered left/right down the page (one
   per screen dragged — Jason). The column leans left so the right-
   hand verses stop short of the fixed hero flower. Same serif voice
   as the Bloum-kaarten; --ink-on keeps the words full-strength on
   the canvas. Each verse rises softly as it scrolls in (scrollfx.js
   stamps .is-live, with the same hysteresis as the taglines).
   Hidden states are scoped to .js + motion-OK, so the words simply
   stand without either.
   ================================================================== */
@media (min-width: 1021px) {
  /* the column threads the needle of the fixed scene: indented from
     the left, stopping short of the hero flower on the right — no
     verse ever settles behind it. Positioned: the garden path (below)
     anchors against it. */
  .onepage #manifest .panel__content {
    position: relative;
    align-self: start;
    margin-left: clamp(180px, 21vw, 340px);
    width: min(41vw, 660px);
    /* the strips size their type in cqw of this column (.verse__zin) */
    container-type: inline-size;
  }
}
/* the garden path: a dashed line in donker leaf-green wandering down
   the manifesto — the WHIMSICAL one, free-sketched through jittered
   waypoints (scrollfx.js drawVersePath), while the text stands
   anchored on its paper strips. z −1: it may duck BEHIND a strip and
   re-emerge, never over the words. Wide layouts only, like the
   stagger it follows. */
.verse-path {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  pointer-events: none;
  display: none;
}
@media (min-width: 1021px) { .verse-path { display: block; } }
/* [mask] scopes this to the VISIBLE path: the reveal mask's own path
   (scrollfx drawVersePath) lives on presentation attributes, and an
   unscoped rule here overrode them — the mask went full-coverage and
   the scroll-draw never clipped a thing */
.verse-path path[mask] {
  fill: none;
  stroke: var(--leaf-dark);
  stroke-width: 3.5;
  stroke-linecap: round;
  /* long-short alternation: a hand's dashes, not a machine's */
  stroke-dasharray: 15 12 6 12;
}
.verse {
  /* The manifesto as paper cut-outs (Jason's brief): every SENTENCE
     is one strip — an irregular dark leaf-green polygon with the line
     printed papier on it, ONE line always, never wrapped. The strips
     are the ANCHORED thing on the page; the garden path is the free
     spirit wandering around (and sometimes behind) them. */
  --verse-fs: clamp(1.35rem, 1rem + 1.3vw, 1.9rem);
  min-height: 42svh;
  display: grid;
  align-content: center;
  justify-items: start;
  gap: clamp(10px, 1.4vh, 18px);
}
.verse:nth-child(even) { justify-items: end; }
.verse__zin {
  margin: 0;
  width: max-content;
  max-width: 100%;
  white-space: nowrap;
  /* ELEGANT, not punk (Jason): the card serif in italic — the voice of
     a written message on paper — where bold sans read as protest */
  font-family: "Averia Serif Libre", Georgia, serif;
  font-style: italic;
  font-weight: 400;
  /* fit-to-line: ~.54em per character (Averia italic) against the
     column width — a long line sets itself smaller rather than wrap;
     most lines are clause-length (the template splits long sentences
     at their commas) and sit at the cap. */
  font-size: min(var(--verse-fs), calc(92cqw / (var(--chars, 40) * .54)));
  line-height: 1.25;
  letter-spacing: var(--serif-track);
  color: var(--papier);
  background: var(--leaf-dark);
  padding: .5em 1em .55em;
  /* gentle scissor slants — carefully cut paper, not a ripped zine */
  clip-path: polygon(0% 8%, 1.5% 0%, 100% 3%, 99.2% 95%, 97.5% 100%, .8% 97%);
  rotate: -.55deg;
}
.verse__zin:nth-of-type(even) {
  clip-path: polygon(.8% 4%, 99% 0%, 100% 90%, 98.5% 100%, 1.2% 98%, 0% 12%);
  margin-inline-start: 2em;
  rotate: .65deg;
}
/* right-aligned clusters mirror the ragged indent */
.verse:nth-child(even) .verse__zin:nth-of-type(even) {
  margin-inline-start: 0;
  margin-inline-end: 2em;
}
/* hand-placed variation: the tilt cycle shifts per cluster so no two
   stanzas repeat the same lean (all of it stays under ~1deg) */
.verse:nth-child(even) .verse__zin { rotate: .45deg; }
.verse:nth-child(even) .verse__zin:nth-of-type(even) { rotate: -.8deg; }
.verse:nth-child(3n) .verse__zin:nth-of-type(odd) { rotate: -1deg; }
.verse:nth-child(3n+1) .verse__zin:nth-of-type(even) { rotate: .9deg; }
.verse__zin:nth-of-type(3) { rotate: .3deg; }
/* stacked layout: no fit-to-line container — the strips may wrap */
@media (max-width: 1020px) {
  .verse__zin { white-space: normal; width: auto; font-size: var(--verse-fs); }
}
@media (prefers-reduced-motion: no-preference) {
  .js .verse {
    opacity: 0;
    translate: 0 34px;
    transition: opacity .7s ease, translate .8s cubic-bezier(.2, .9, .3, 1);
  }
  .js .verse.is-live { opacity: 1; translate: 0 0; }
}
/* the sheet becomes a transparent flow — the canvas shows through */
.page--flow {
  margin: 0;
  padding: 0;
  background: none;
  border-radius: 0;
}
/* panel content keeps to the centred column the flower cap respects */
/* the reading column, from Figma. The GRIDS (photo beats, message
   cards, the address list) are not reading columns and opt out: at
   566px the cards stacked two-abreast in the middle of an empty
   screen. */
.panel__content--wide { width: min(1180px, 100%) !important; }
.panel__content {
  align-self: center;
  width: min(var(--col), 100%);
  display: grid;
  gap: clamp(32px, 4vw, 56px);
  margin-top: clamp(20px, 3vw, 40px);
}

/* the papier footer rises as the final sheet under the wordmark */
.onepage .site-footer {
  border-radius: clamp(28px, 4vw, 44px) clamp(28px, 4vw, 44px) 0 0;
}

/* ==================================================================
   Pauses along the journey — a pinned panel (.panel--pin) runs
   --runway taller than the viewport while its .panel__pin sticks to
   the top: the panel's one big thing (the filmstrip) holds
   anchored mid-screen while the extra scroll passes, then travels
   on. The producten filmstrip rides the runway as the pause's own
   proof of travel. overflow-x is clipped (clip, NOT hidden — sticky
   needs no scroll container) so the parked filmstrip never widens
   the document. The runway only exists with JS and motion; otherwise
   the panel is an ordinary full-height screen.
   ================================================================== */
.onepage .panel--pin { display: block; padding: 0; }
.onepage .panel--pin .panel__pin {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  gap: clamp(16px, 2.2vw, 26px);
  padding: calc(88px + 5.5vw) var(--pad-x) clamp(64px, 10svh, 140px);
}
/* the anchored thing centres itself in the leftover height */
.onepage .panel--pin .panel__content { margin-block: auto; }
@media (prefers-reduced-motion: no-preference) {
  .js .onepage .panel--pin { min-height: calc(100svh + var(--runway, 80svh)); }
  .js .onepage .panel--pin .panel__pin { position: sticky; top: 0; }
}

/* ==================================================================
   Producten — the filmstrip: the gallery is one horizontal track that
   travels THROUGH the pinned panel (scrollfx.js maps the runway to
   the track's journey). ON WHITE since 2026-08 (Jason: the purple
   section should be white instead; let the images do the work, they
   are already rich with photos) — and the white paper mats went with
   the purple. A white mat on a white canvas is invisible, and the
   ±1.8° scatter that made the prints read as paper on a table now
   just reads as fussy: they are clean rectangles with a soft shadow,
   and the photographs carry themselves. Fallback (no JS, reduced
   motion): the strip is a native side-scroller instead.
   ================================================================== */
.strip {
  flex: 1;
  display: flex;
  align-items: center;
  margin-inline: calc(var(--pad-x) * -1);
  overflow-x: auto;
}
.strip__track {
  display: flex;
  align-items: center;
  gap: clamp(24px, 3.4vw, 52px);
  padding: 28px var(--pad-x);
}
.strip .gallery__item {
  flex: none;
  padding: 0;
  border: 0;
  background: none;
  border-radius: 10px;
  overflow: hidden;
  cursor: zoom-in;
  box-shadow: 0 10px 34px rgba(4, 4, 4, .13);
}
.strip .gallery__item img { height: min(58svh, 560px); width: auto; }
@media (prefers-reduced-motion: no-preference) {
  .js .strip { overflow: visible; }
  /* the natural layout IS the start pose — first print at the left
     padding — so the first paint already shows a photo */
  .js .strip__track { will-change: transform; }
}

@media (max-width: 1020px) {
  /* stacked layout: the scene stays at the top of the page (panel 1);
     no sheet push — panel 1's content clears the flower AND leaves a
     beat of whitespace, so the deck still arrives on a scroll.
     data-page is pinned to over-bloum here (onepage.js skips the scene
     re-theming below 1021px), so --flower-ar — and with it this margin
     and everything below it — holds still while the schemes change */
  body.onepage .page--flow { margin-top: 0; }
  /* the flower it used to clear is gone on stacked: just the breath */
  body.onepage #manifest .panel__content { margin-top: 12svh; }
}

/* (Het openingsscherm — one photograph and no words — stood here until
   aug 2026. Jason: the section that is just an image can go, start on
   "Een bloem voor altijd" instead. Its frame, its contained-print
   sizing and the scroll cue under it went with it; Over Bloum below
   opens the page now, and carries the h1.) */

/* ==================================================================
   Over Bloum — what it is, in three photographs: made by hand → it is
   paper → and it is a card you give. One caption each, in the printed
   voice (Averia, like the strips and the cards); the photographs do
   the arguing. Content is the `secties` Matrix, which had been on this
   entry type since July and rendered nowhere.
   ================================================================== */
.beats {
  display: grid;
  gap: clamp(24px, 3.4vw, 56px);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  align-items: start;
}
.beat { margin: 0; display: grid; gap: clamp(12px, 1.2vw, 20px); }
.beat__img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 10px;
  box-shadow: 0 10px 34px rgba(4, 4, 4, .13);
}
/* the middle beat drops a step: three photographs in a dead-level row
   read as a spec sheet, and this page is meant to read as a hand */
@media (min-width: 861px) {
  .beat:nth-child(even) { margin-top: clamp(28px, 5vw, 76px); }
}
.beat__zin {
  margin: 0;
  font-family: "Averia Serif Libre", Georgia, serif;
  font-size: clamp(1.02rem, .92rem + .42vw, 1.32rem);
  line-height: 1.42;
  letter-spacing: var(--serif-track);
  color: var(--ink-on);
}

/* ==================================================================
   De kaarten — the messages as things you can point at. THE COLOUR
   LIVES HERE: the brand's four hues were wallpaper before, four
   full-bleed screens, which is what made the page read as crayola. On
   a paper canvas they come back at the size they were designed for —
   small printed cards, which is exactly what the product is. Each card
   carries its own scheme via [data-scheme] in _kaarten.twig, so the
   --accent/--ink-on pairs above do its contrast for free.
   The cards are printed OBJECTS: they hold still. Only the bloom
   breathes (the focal map allows idle loops on flowers alone) — and
   under the cursor a card lifts off the paper, which is the one motion
   a printed thing is allowed: being picked up.
   ================================================================== */
.kaarten {
  display: grid;
  gap: clamp(14px, 1.6vw, 26px);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 228px), 1fr));
}
.kaart {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: clamp(18px, 1.6vw, 26px);
  min-height: clamp(280px, 30svh, 340px);
  border-radius: 14px;
  background: var(--accent);
  color: var(--ink-on);
  box-shadow: 0 8px 26px rgba(4, 4, 4, .12);
}
/* a card with a shop link is clickable ANYWHERE — the small underlined
   line was the only target on an object the size of a postcard */
.kaart:has(.kaart__actie) { cursor: pointer; }
.kaart__actie::after { content: ""; position: absolute; inset: 0; }

/* the neutral face: a white card on the cream canvas. It has no scheme
   of its own, so it states both colours outright. */
.kaart--wit { background: var(--wit); color: var(--inkt); }
.kaart__zin {
  margin: 0;
  flex: 1;
  font-family: "Averia Serif Libre", Georgia, serif;
  font-size: clamp(1.06rem, .96rem + .4vw, 1.34rem);
  line-height: 1.34;
  letter-spacing: var(--serif-track);
  text-wrap: balance;
}
/* the card's foot: the flower and the offer on ONE line, so the label
   arrives beside the flower instead of under it */
.kaart__voet {
  display: flex;
  align-items: flex-end; /* the flower stands on the line, beside the offer */
  gap: 14px;
}
/* ---- de bloemetjes -------------------------------------------------
   The illustrator's flowers are WHOLE flowers, stem and leaves and all,
   and portrait (h/w runs 1.32 to 2.09) where the old hand-built blooms
   were square heads. Sized by HEIGHT, each taking whatever width its
   own drawing needs. Nothing is recoloured.

   SIX HOUDINGEN. One flower at one size in the same bottom-left corner
   of every tile is what made the deck read serial (Jason: vary the
   location and size, right now they are all bottom left) — and ONE per
   tile, a sprig of two having been tried and cut. So the variety is
   carried entirely by WHERE it stands and HOW BIG it is.

   The flower is absolutely placed on the CARD, not laid out in the
   foot, and --x/--y are fractions of the card's own box, so a tile that
   grew for a long quote places its flower proportionally rather than
   letting it drift into the words. It sits BEHIND the text: on the
   longest quote in the pool the words win the space, which is the right
   way round for a decoration.

   THEY ALL STAND ON THE SAME FLOOR (Jason: always flush with the
   bottom). Floating each one at its own height read as unmoored — a
   drawing hanging in the middle of a card rather than a flower standing
   on it — and six different heights never resolved into a pattern, just
   into noise. One floor for the whole deck, a hair inside the card's
   bottom edge so the ink is planted rather than bleeding off it: the
   viewBoxes are cropped tight to the drawing, so the stem tip really is
   the last pixel and `bottom` really is the floor.

   Leaning is safe on that floor. transform-origin is the bottom centre,
   which is where the stem meets it, so a lean pivots on the stem tip and
   the flower stays planted; only the empty corners of the box swing.

   THE OFFER OWNS THE LEFT OF THE FOOT, and it stays visible on touch
   where there is no hover to reveal it. With every flower on the foot
   line now, none of them can cross it, so they stand in the right-hand
   band and are anchored FROM THE RIGHT EDGE: --x is the inset from that
   edge, so a wide drawing grows leftward into open card instead of
   running off the corner. The biggest sizes take the smallest insets —
   a big flower stands nearer the edge, a small one can walk further in —
   which is what keeps the band from reading as a single parked spot. */
.kaart__bloem {
  position: absolute;
  z-index: 0;
  right: calc(var(--x) * 100%);
  bottom: clamp(8px, .75vw, 12px);
  height: calc(clamp(40px, 3.3vw, 54px) * var(--s, 1));
  rotate: var(--r, 0deg);
  transform-origin: 50% 100%;
  pointer-events: none;
}
.kaart__bloem svg { height: 100%; width: auto; display: block; }
/* the words and the offer stand above the drawing */
.kaart__zin, .kaart__voet { position: relative; z-index: 1; }

/* STILL SMALL (Jason). It is a mark on a printed card, not an
   illustration the card is built around. But with the floor shared, the
   height each one used to carry is gone from the variety, so SIZE takes
   it over: about a tenth bigger across the set and a wider spread than
   before (.85–1.27 against .80–1.12), which is as far as it goes before
   the biggest stops being a mark.
                                 inset-right  size   lean            */
.kaart__bloem[data-houding="1"] { --x: .07;   --s: 1.27; --r: -3deg; }
.kaart__bloem[data-houding="2"] { --x: .13;   --s: 1.11; --r:  5deg; }
.kaart__bloem[data-houding="3"] { --x: .09;   --s: 1.19; --r:  2deg; }
.kaart__bloem[data-houding="4"] { --x: .21;   --s:  .95; --r: -7deg; }
.kaart__bloem[data-houding="5"] { --x: .24;   --s:  .85; --r:  4deg; }
.kaart__bloem[data-houding="6"] { --x: .17;   --s: 1.03; --r: -2deg; }

/* the list keeps its flowers in the gutter beside the shop name, where
   a scattered placement would only break the column — so there they
   vary in size and lean alone (one each, same as the tiles) */
.punt__bloem { flex: none; height: calc(clamp(34px, 2.8vw, 46px) * var(--s, 1)); rotate: var(--r, 0deg); margin-top: 2px; transform-origin: 50% 100%; }
.punt__bloem svg { height: 100%; width: auto; display: block; }
.punt__bloem[data-houding="1"] { --s: 1;    --r: -4deg; }
.punt__bloem[data-houding="2"] { --s: .86;  --r: 6deg; }
.punt__bloem[data-houding="3"] { --s: 1.12; --r: 2deg; }
.punt__bloem[data-houding="4"] { --s: .94;  --r: -8deg; }
.punt__bloem[data-houding="5"] { --s: .8;   --r: 5deg; }
.punt__bloem[data-houding="6"] { --s: 1.06; --r: -2deg; }
.kaart__actie {
  font-size: .82rem;
  font-weight: 600;
  letter-spacing: .01em;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 2px;
  opacity: .82;
}
.kaart__actie:hover, .kaart__actie:focus-visible { opacity: 1; }

/* ---- the pick-up. Below the rules above on purpose: a media query
   adds no specificity, so an .kaart__actie later in the file would
   simply win. Shadow for every pointer; the lift only where motion is
   welcome. */
@media (hover: hover) and (pointer: fine) {
  .kaart:hover { box-shadow: 0 20px 44px rgba(4, 4, 4, .21); }
  /* THE OFFER IS HELD BACK UNTIL YOU POINT AT THE CARD. The same line
     printed under all thirty-four at once is what read as spam; on the
     one card under the cursor it is the answer to "can I have this?".
     :focus-within keeps it for the keyboard, which lands on the card's
     own link — an offer nobody can see is not an offer. Coarse pointers
     have no hover to reveal it with, so there it simply stays. */
  .kaart__actie { opacity: 0; }
  .kaart:hover .kaart__actie,
  .kaart:focus-within .kaart__actie { opacity: 1; }
}
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .kaart {
    transition: transform .3s cubic-bezier(.2, .75, .3, 1),
                box-shadow .3s ease;
  }
  .kaart__bloem { transition: scale .5s cubic-bezier(.2, .75, .3, 1); }
  .kaart:hover { transform: translateY(-7px); }
  /* the bloom opens a little as the card comes up, pivoting on its
     stem end rather than its middle */
  .kaart:hover .kaart__bloem { scale: 1.12; }
  /* and the offer steps out from behind it */
  .kaart__actie {
    translate: -8px 0;
    transition: opacity .22s ease, translate .34s cubic-bezier(.2, .75, .3, 1);
  }
  .kaart:hover .kaart__actie,
  .kaart:focus-within .kaart__actie { translate: 0 0; }
}

/* The picture tile: the product at the size of a card, dealt into the
   deck to interrupt it. The picture IS the tile, so it fills the face
   edge to edge and the tile carries no words at all — it is a <button>
   (gallery.js opens it in the page's one lightbox), so it also has to
   shed everything the browser gives a button. */
.kaart--foto {
  padding: 0;
  overflow: clip;
  gap: 0;
  border: 0;
  font: inherit;
  color: inherit;
  text-align: inherit;
  cursor: zoom-in;
  background: var(--papier);   /* the letterbox behind a loading picture */
}
.kaart__foto { width: 100%; flex: 1; object-fit: cover; min-height: 0; }

/* Toon meer — a <details>, so the browser owns the toggle and it works
   with no JS at all. The revealed cards continue the same grid and the
   same face cycle, so the second half looks dealt from one deck. */
.meer { margin-top: clamp(14px, 1.6vw, 26px); }
.meer__knop {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 11px 22px;
  border-radius: 999px;
  background: var(--inkt);
  color: var(--papier);
  font-size: .9rem;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.meer__knop::-webkit-details-marker { display: none; }
.meer__open { display: none; }
.meer[open] .meer__dicht { display: none; }
.meer[open] .meer__open { display: inline; }
.meer[open] .meer__knop { margin-bottom: clamp(14px, 1.6vw, 26px); }

/* ==================================================================
   Waar te koop — a LIST, on purpose (Jason: readable, straightforward).
   This used to be a sticky pile of hand-tilted seven-variant cards
   that departed one per 48svh: you could not read three addresses
   without scroll-jacking through the whole deck, and the cards' coral
   faces had to skip two palette variants to avoid sinking into the
   coral canvas behind them. A decorative answer to a purely practical
   question. Inter, not Averia: this is wayfinding, it wants scanning
   rather than reading aloud. The only colour is one small bloom per
   entry, which is also the only thing that moves.
   ================================================================== */
.punten {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0 clamp(28px, 4vw, 72px);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
}
.punt {
  display: flex;
  align-items: flex-start;
  gap: clamp(14px, 1.4vw, 22px);
  padding: clamp(18px, 2vw, 28px) 0;
  border-top: 1px solid color-mix(in srgb, var(--ink-on) 16%, transparent);
}
.punt__naam {
  margin: 0 0 4px;
  font-size: clamp(1.06rem, .98rem + .34vw, 1.3rem);
  font-weight: 700;
  letter-spacing: -.015em;
  line-height: 1.24;
}
.punt__adres {
  margin: 0;
  white-space: pre-line;   /* the adres keeps the editor's line breaks */
  font-size: clamp(.94rem, .9rem + .18vw, 1.04rem);
  line-height: 1.5;
  opacity: .78;
}

/* ==================================================================
   The one call to action — an INK pill everywhere, never an accent
   one. The accent changes per section and half the four fail 4.5:1
   against both inks; ink on papier is the one pairing that is always
   safe, and it already reads as the house button.
   ================================================================== */
.panel__cta { margin: clamp(18px, 2.4vw, 34px) 0 0; }
.cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 13px 26px;
  border-radius: 999px;
  background: var(--inkt);
  color: var(--papier);
  font-size: clamp(.94rem, .9rem + .2vw, 1.06rem);
  font-weight: 600;
  text-decoration: none;
}
.cta:hover, .cta:focus-visible { background: color-mix(in srgb, var(--inkt) 84%, var(--accent)); }

/* ==================================================================
   Small-screen paint budget — the scheme crossfade restyles the
   whole document for as long as it runs; phones keep the fade but
   take it quicker. (Kept at the END of the sheet so order decides.)
   ================================================================== */
@media (max-width: 760px) {
  html { transition-duration: .55s; }
}
