/* ==========================================================================
   Bureau Entre Nous — Design System
   ========================================================================== */

:root {
  --cream: #f1ebe4;
  --brown-dark: #422e21;
  --maroon: #731f32;
  --near-black: #261b13;

  --font-display: "Nanum Myeongjo", "Noto Serif", serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  --nav-height: 88px;
  --edge: clamp(24px, 6vw, 96px);
  --transition-slow: 700ms cubic-bezier(0.16, 1, 0.3, 1);
  --transition-fast: 250ms ease;
}

*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  overflow-x: hidden; /* safe here: html is the real scrolling element, unlike body */
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
}

body {
  margin: 0;
  background: var(--cream);
  color: var(--near-black);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* NB: deliberately no overflow-x:hidden here — that breaks
     position:sticky for every descendant (the browser treats body as
     the sticky scroll-ancestor, but body itself never scrolls).
     Horizontal clipping is instead scoped per-section below. */
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 400;
  margin: 0;
  line-height: 1.08;
  letter-spacing: -0.01em;
}

.eyebrow {
  font-family: var(--font-body);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--maroon);
}

.accent { color: var(--maroon); font-style: italic; }

.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;
}

/* ---- Buttons ---- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.85em 1.6em;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 0.95rem;
  font-weight: 600;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform var(--transition-fast), background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
  white-space: nowrap;
}
.btn:hover { transform: translateY(-2px); }
.btn--primary { background: var(--maroon); color: var(--cream); }
.btn--primary:hover { background: var(--near-black); }
.btn--ghost { background: transparent; color: var(--near-black); border-color: currentColor; }
.btn--ghost:hover { background: var(--near-black); color: var(--cream); }
.btn--on-dark { background: var(--cream); color: var(--near-black); }
.btn--on-dark:hover { background: var(--maroon); color: var(--cream); }

/* ---- Nav ---- */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  height: var(--nav-height);
  display: flex;
  align-items: center;
  padding: 0 var(--edge);
  /* "Liquid glass" scrim — modeled on momenti.agency's own nav (per
     the user's own reference): a much lower-opacity, blurred pane
     rather than a near-opaque block, so the panel color underneath
     still reads through it, plus a fast (not slow) transition.
     --nav-tint-rgb is set by main.js (updateNavTheme) to the *actual*
     computed background-color of whichever panel currently sits
     behind the nav — not a fixed light/dark pair. This site has three
     distinct panel colors (cream, brown-dark, near-black for
     .panel--contact), and a fixed dark tint mismatched visibly against
     whichever one of those it wasn't tuned for; reading the real color
     means it's always an exact match, so the glass blends into
     literally any panel behind it. (Dropped the saturate() filter and
     border-bottom from an earlier pass, too — saturating the blurred
     backdrop shifted its tone away from the flat, unsaturated panel
     color just past the nav's edge, which read as a visible seam/color
     mismatch there; the border was an unwanted visible line.) */
  background: rgba(var(--nav-tint-rgb, 241,235,228), 0.72);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  transition: color 0.3s, background 0.4s;
}
/* Toggled by main.js (updateNavTheme): tracks whichever panel is
   currently behind the nav (data-nav-theme="dark" on that panel — the
   brown/near-black ones) via elementFromPoint, so it works the same
   way whether the page is scrolling horizontally (desktop) or
   vertically (is-vertical/mobile fallback). Only drives the text/logo
   ink color now — the background tint itself comes from
   --nav-tint-rgb above. */
.nav--dark .nav__links a { color: var(--cream); }
.nav--dark .nav__burger span { background: var(--cream); }
.nav__inner {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}
/* The source logo files are square social-avatar lockups with generous
   padding around the mark. These rules crop into the actual artwork
   (position/size only — the source PNGs are never modified) so the mark
   reads well at nav/footer scale. */
.nav__logo {
  display: block;
  width: 176.1px;
  height: 62px;
  overflow: hidden;
  position: relative;
  /* Crop is flush with the mark's own left edge (no internal padding —
     see the img rule below), so this margin is a deliberate, exact
     1cm shift further left than the heading/word text below it.
     Capped at -var(--edge) via max() so on narrow screens (where
     --edge shrinks) it can never push the logo off the left edge of
     the viewport. */
  margin-left: max(-1cm, calc(-1 * var(--edge)));
  margin-top: 22px; /* nudges it down a bit further — the heading moved
    right, so there's room now without the two colliding */
}
.nav__logo img {
  position: absolute;
  /* A previous pass scaled content to fill the 176.1x62 container
     exactly (0px margin) — fine in this session's own (Chromium)
     testing, but with non-integer px values like these, real browsers
     don't all sub-pixel-round the same way, and the user's actual
     browser was visibly clipping the mark/wordmark at the left and
     bottom-right on a fit that tight. Rebuilt with a genuine 3px
     margin on every side (scale = min(target-w, target-h) / content
     box, not just target-h) so it can't clip regardless of rounding. */
  width: 218.97px;
  height: 218.75px;
  left: -26.31px;
  top: -78.38px;
  max-width: none;
}
/* Two stacked logo images, crossfading instead of swapping src (so it
   transitions alongside the nav's own background change rather than
   snapping instantly). Same idea/crop as above, but NOT the same exact
   numbers: logo-cream-transparent.png's own content bounding box sits
   a few px off from logo-default-transparent.png's, so reusing the
   dark-ink crop verbatim was clipping part of the mark/wordmark.
   Recomputed against this image's own measured box, same 3px-margin
   approach as above. */
.nav__logo-img--dark-ink { opacity: 1; transition: opacity 0.4s ease; }
.nav__logo-img--cream-ink {
  opacity: 0;
  transition: opacity 0.4s ease;
  width: 217.27px;
  height: 217.05px;
  left: -26.09px;
  top: -78.18px;
}
.nav--dark .nav__logo-img--dark-ink { opacity: 0; }
.nav--dark .nav__logo-img--cream-ink { opacity: 1; }
.nav__links {
  display: flex;
  gap: 32px;
  font-size: 0.92rem;
  font-weight: 500;
}
.nav__links a {
  position: relative;
  padding-bottom: 4px;
  transition: color 0.3s ease; /* matches .nav's own transition speed */
}
.nav__links a::after {
  content: "";
  position: absolute;
  left: 0; right: 100%;
  bottom: 0;
  height: 1px;
  background: var(--maroon);
  transition: right var(--transition-fast);
}
.nav__links a:hover::after { right: 0; }
.nav__cta { display: flex; align-items: center; gap: 16px; }
.nav__burger {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px;
}
.nav__burger span {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--near-black);
  margin: 5px 0;
  transition: transform var(--transition-fast), opacity var(--transition-fast), background 0.3s ease;
}

@media (max-width: 860px) {
  .nav__links { display: none; }
  .nav__burger { display: block; }
  .nav__cta .btn { display: none; }
}

/* ==========================================================================
   Whole-page horizontal scroll
   The entire site is one continuous horizontal filmstrip of <section
   class="panel"> elements inside #hscroll-content, itself inside the
   native-scrolling #hscroll-wrapper. main.js (+ self-hosted Lenis)
   translates vertical wheel/touch input into horizontal movement on
   desktop. On narrow viewports / prefers-reduced-motion it falls back
   to a plain vertical stack (see .is-vertical below) — no JS scroll
   hijacking, just the normal document flow.
   ========================================================================== */
#hscroll-wrapper {
  position: relative;
  height: 100vh;
  width: 100vw;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none; /* Firefox */
}
#hscroll-wrapper::-webkit-scrollbar { display: none; }

#hscroll-content {
  display: flex;
  height: 100vh;
  width: max-content;
  position: relative; /* containing block for .panel-seam-banner */
}

/* Vertical "Diensten" banner straddling the panel1/panel2 seam — see
   the HTML comment for why it's a sibling of the panels rather than
   nested in either. left:298vw matches .panel--hero's own (trimmed)
   width, so it's centered exactly on the seam (half over each panel's
   background) at any viewport width; no JS needed, unlike most of the
   hero's own fixed-position elements — a plain vw value is enough
   here since there's only the one seam position to hit, not a whole
   composition of interdependent elements to keep in sync. */
.panel-seam-banner {
  position: absolute;
  left: 298vw;
  top: 50%;
  /* Laid out as an ordinary horizontal row first (below), then rotated
     as one piece — width/height are the PRE-rotation box, so they're
     swapped from how they look on screen: 900 tall on screen = 900
     wide here, 260 wide on screen = 260 tall here. */
  width: 900px;
  height: 260px;
  transform: translate(-50%, -50%) rotate(-90deg);
  overflow: hidden;
  opacity: 0.55; /* less transparent than before (was 0.35) */
  z-index: 5;
  pointer-events: none;
  user-select: none;
}
.panel-seam-banner__track {
  display: flex;
  align-items: center;
  height: 100%;
  width: max-content;
  /* Scrolls left (in this pre-rotation row) = scrolls up once the
     whole banner is rotated -90deg — "van beneden naar boven",
     continuously looping, per the reference recording. -50% relies on
     the track holding the repeats twice over (see HTML): that makes
     the animation's end state pixel-identical to its start state, so
     the loop restarts with no visible seam/jump. */
  animation: panel-seam-banner-scroll 18s linear infinite;
}
.panel-seam-banner__track span {
  display: block;
  flex: none;
  font-family: var(--font-display);
  font-weight: 800; /* ExtraBold — thicker strokes */
  font-size: 160px;
  -webkit-text-stroke: 3px var(--maroon); /* extra weight beyond what
    the font's own ExtraBold cut gives, same trick used on the
    ENTRENOUS word */
  letter-spacing: 0.04em;
  color: var(--maroon);
  white-space: nowrap;
  padding: 0 56px;
}
@keyframes panel-seam-banner-scroll {
  /* -50% -> 0 (not the more common 0 -> -50%): the -90deg rotation on
     the parent flips which screen-direction a local translateX reads
     as — this order is the one that scrolls up on screen, confirmed
     by comparing two screenshots a few seconds apart. */
  from { transform: translateX(-50%); }
  to { transform: translateX(0); }
}
body.is-vertical {
  /* --edge's own clamp() floors out at 24px (~0.6cm) on anything under
     ~400px wide, which covers nearly every phone — content was sitting
     visibly tight against the screen edge there. Every mobile panel's
     horizontal padding is already driven by var(--edge) (base .panel
     rule, plus every per-section override below), so raising the floor
     here is enough to guarantee a real 1cm of breathing room on every
     phone size, without a fixed value that would look oversized once
     the panel gets wider (6vw still takes over past ~630px, e.g. on
     tablets in the 630–900px vertical-stack range). */
  --edge: max(1cm, 6vw);
  /* Belt-and-braces sideways lock. The actual source of horizontal
     scroll was .hero__word-wrap (hidden further down), but html's own
     overflow-x:hidden has a long-standing habit of not fully stopping
     touch panning on iOS Safari, so this pins the page's own width too.
     overflow-x:clip where supported rather than hidden: clip doesn't
     turn body into a scroll container, so it can't introduce its own
     scrolling quirks while preventing the sideways drag. */
  max-width: 100%;
  overflow-x: hidden;
}
@supports (overflow-x: clip) {
  body.is-vertical { overflow-x: clip; }
}
body.is-vertical .nav__logo {
  /* Desktop-only: the negative margin is a deliberate 1cm bleed past
     .nav's own padding, aligning the logo with the (also desktop-only)
     positioned heading below it. On mobile there's no such heading to
     align against, and it was cancelling out .nav's padding entirely —
     net result, the logo sat flush at the very edge instead of the
     same 1cm every other panel now gets. Nudged half a cm back to the
     left of that 1cm baseline, per request. */
  margin-left: -0.5cm;
  /* Desktop-only: nudges the logo down to clear the (also desktop-only)
     positioned heading next to it. On mobile there's no heading to
     clear, and this pushed the logo visibly below the hamburger button
     — .nav__inner's own align-items:center already lines the two up
     correctly without it. */
  margin-top: 0;
  /* Per request: a touch smaller on mobile. transform (not resized
     width/height) so the crop/positioning numbers on .nav__logo img
     and its cream-ink twin (tuned in real px for the desktop size)
     don't need re-deriving — scaling the whole already-cropped box
     keeps them proportionally correct. left center keeps it anchored
     to the edge position set above and vertically centered in place,
     rather than shrinking toward the box's own center and drifting. */
  transform: scale(0.85);
  transform-origin: left center;
}
body.is-vertical .panel-seam-banner {
  /* Desktop-only: these straddle the seams *between side-by-side
     panels*, which doesn't exist once panels stack vertically. Hidden
     by default here; the two that have a real seam to sit on in the
     stacked layout (Diensten and Werkwijze) are brought back below as
     horizontal bands. The third (over-ons) stays hidden. */
  display: none;
}
/* The Diensten and Werkwijze banners, rebuilt as horizontal marquees for
   mobile: bands across the seams they already divide on desktop —
   Diensten between the quote panel and the diensten panel, Werkwijze
   between the cards panel and "Hoe we samenwerken". Same elements and
   the same scrolling track as desktop; only the rotation comes off, so
   what reads as bottom-to-top there reads as left-to-right here. Both
   already sit between the right panels in source order, and they're in
   normal flow on mobile, so each lands on its own seam unaided. */
body.is-vertical .panel-seam-banner--diensten,
body.is-vertical .panel-seam-banner--reverse,
body.is-vertical .panel-seam-banner--over-ons {
  display: block;
  /* relative + z-index so it paints over the dark quote panel it now
     overlaps, rather than being covered by that panel's background.
     left/top must be reset with it: the desktop rule sets left:298vw
     and top:50% to place the absolutely-positioned version on its seam,
     and while position:static ignored those, position:relative applies
     them as offsets — which shunted the whole banner 298vw (1117px) off
     to the right of a 375px screen. */
  position: relative;
  left: auto;
  top: auto;
  z-index: 1;
  /* All desktop values for the rotated, absolutely-positioned version:
     width/height are its pre-rotation box (see the desktop rule), and
     the transform both centres and rotates it. */
  width: auto;
  transform: none;
  opacity: 1; /* desktop keeps it at 0.55 as a background watermark;
    here it's a foreground band, so full-strength bordeaux */
  /* Straddles the seam instead of sitting below it. Previously this had
     a cream background and sat entirely between the two panels, which
     made it read as the top of the beige section rather than as the
     divider — especially once that section became beige too and the
     two merged. Transparent background plus a negative margin of half
     its own height centres it exactly on the boundary, so the word runs
     half over the dark quote panel and half over the beige one, the
     same way the desktop banners straddle their seams. */
  background: transparent;
  height: 96px;
  padding: 0;
  margin-top: -48px; /* half of the height above */
  margin-bottom: -48px;
}
body.is-vertical .panel-seam-banner--reverse {
  /* Werkwijze banner 2cm up, per request. The extra comes off the top
     margin and goes back onto the bottom one, so the banner shifts while
     its net contribution to the flow stays zero — everything below it
     (the werkwijze panel and the rest of the page) stays put. */
  margin-top: calc(-48px - 2cm);
  margin-bottom: calc(-48px + 2cm);
}
body.is-vertical .panel-seam-banner--diensten .panel-seam-banner__track,
body.is-vertical .panel-seam-banner--reverse .panel-seam-banner__track,
body.is-vertical .panel-seam-banner--over-ons .panel-seam-banner__track {
  height: 100%;
}
body.is-vertical .panel-seam-banner--diensten .panel-seam-banner__track span,
body.is-vertical .panel-seam-banner--reverse .panel-seam-banner__track span,
body.is-vertical .panel-seam-banner--over-ons .panel-seam-banner__track span {
  /* Desktop's 160px is sized for a full-height vertical banner. */
  font-size: clamp(2.2rem, 11vw, 4rem);
  -webkit-text-stroke-width: 1.5px;
  padding: 0 24px;
}

/* "Werkwijze" banner at the cards-fan/werkwijze seam — same banner,
   further along the strip and running the other way. */
.panel-seam-banner--reverse {
  /* .panel--hero (298vw) + .panel--diensten-intro (56vw - 0.5cm) +
     .panel--cards-fan (230vw), i.e. exactly where .panel--werkwijze
     begins — see the HTML comment. Keep this in sync with
     .panel--diensten-intro's own width above (its cm offset changed
     more than once since this was first written; it fell out of sync
     once and visibly drifted off the seam). */
  left: calc(584vw - 0.5cm);
  /* +90deg instead of the base rule's -90deg: a 180deg difference,
     which is what actually flips each letter's own orientation
     upside-down (glyphs, not just scroll direction — rotating the
     whole pre-rotation row by the opposite quarter-turn is the vertical
     mirror of the "Diensten" banner's letters). Confirmed against the
     base .panel-seam-banner rule below rather than repeating its other
     properties (width/height/opacity/etc. are all still needed and are
     inherited from there — only the angle differs). */
  transform: translate(-50%, -50%) rotate(90deg);
  /* No animation-direction override needed on the track (it just runs
     the base @keyframes forward, same as "Diensten"): Diensten's
     forward keyframe reads bottom-to-top under the base -90deg
     rotation, and flipping the rotation to +90deg above flips which
     screen-direction that same forward keyframe reads as too — it's
     top-to-bottom here without touching the animation at all. (An
     animation-direction: reverse was here briefly, needed while this
     was still using -90deg like the base rule — with +90deg it would
     instead put the scroll back to bottom-to-top.) */
}

/* "Over entre nous" banner at the werkwijze/over-ons seam — same
   banner again, direction and letter-orientation both inherited
   unchanged from the base .panel-seam-banner rule (bottom-to-top,
   same as "Diensten" — no --reverse-style overrides needed here). */
.panel-seam-banner--over-ons {
  /* .panel--hero (298vw) + .panel--diensten-intro (56vw - 0.5cm) +
     .panel--cards-fan (230vw) + .panel--werkwijze (96vw + 3.5cm) added
     up to 680vw + 3cm, exactly where .panel--over-ons begins — then
     +2cm more on top of that on request, so this one sits 2cm right
     of the seam rather than centered on it. Keep the first part in
     sync with those panels' own widths if they change again (see the
     two comments above, both learned this the hard way). */
  left: calc(680vw + 5cm);
}
.panel-seam-banner--over-ons .panel-seam-banner__track {
  /* "Over entre nous" is much longer than "Diensten"/"Werkwijze" (16
     characters vs 9), so at the same 18s loop it has proportionally
     more distance to cover in the same time — reads as faster, per
     request. Slowed to match their pace instead of speeding the
     others up. */
  animation-duration: 32s;
}

.panel {
  flex-shrink: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: calc(var(--nav-height) + 24px) var(--edge) 64px;
  position: relative;
  overflow: hidden;
  box-sizing: border-box;
}

.panel__head {
  max-width: 640px;
  margin-bottom: 48px;
}
.panel__head h2 {
  font-size: clamp(2.2rem, 4.6vw, 3.6rem);
  margin-top: 16px;
}
.panel__head p {
  margin-top: 20px;
  font-size: 1.05rem;
  max-width: 46ch;
}

/* ---- Progress + counter (horizontal mode only) ---- */
.hscroll-progress {
  position: fixed;
  bottom: 28px;
  left: var(--edge);
  right: var(--edge);
  height: 2px;
  background: rgba(66,46,33,0.15);
  z-index: 90;
}
.hscroll-progress-bar {
  height: 100%;
  width: 0%;
  background: var(--maroon);
  transition: width 80ms linear;
}
.hscroll-counter {
  position: fixed;
  bottom: 40px;
  right: var(--edge);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  color: var(--brown-dark);
  z-index: 90;
  pointer-events: none; /* already aria-hidden/decorative — this also
    lets main.js's elementFromPoint hit-test (updateCounterTheme) see
    through it to the actual panel behind it, instead of hitting the
    counter's own text */
  transition: color 0.3s;
}
.hscroll-counter--dark {
  /* Same light/dark panel split main.js already tracks for the nav
     (data-nav-theme="dark") — cream text reads over the dark panels'
     brown/near-black backgrounds where the default brown-dark text
     wouldn't. */
  color: var(--cream);
}

/* ==========================================================================
   Hero
   ========================================================================== */
.panel--hero {
  background: var(--cream); /* explicit (was relying on body's own
    cream) — main.js reads panels' actual background-color to tint the
    nav to match exactly, which needs every panel to have one set */
  width: 298vw; /* trimmed from 320vw — that left ~470px of empty
    cream space after the "S" of ENTRENOUS before the seam with panel
    2; this leaves a more modest ~120px */
  min-width: 1400px;
  justify-content: flex-start; /* overrides .panel's centering — see children below */
  padding: 0; /* .hero__stage recreates this (see below) at a fixed size,
    scaled as a whole — panel's own (responsive) padding would double up */
}
/* Fixed "design canvas": every element below is positioned in this
   4768x900 frame (matching what .panel--hero itself measures at the
   1600px-wide reference viewport: 298vw = 4768px). assets/js/main.js
   scales it as a single unit — transform:scale(actual panel width /
   4768) — so the whole composition keeps the same proportions at any
   viewport width, rather than each element separately trying (and, at
   most widths, failing) to stay in sync via its own vw/vh math.
   Un-transformed until JS runs; sits flush at the panel's own origin. */
.hero__stage {
  position: absolute;
  top: 0;
  left: 0;
  width: 4768px;
  height: 900px;
  /* Same padding .panel's base rule would give at the 1600px reference
     (nav-height 88px + 24px top, --edge capped at 96px, 64px bottom). */
  padding: 112px 96px 64px;
  transform-origin: top left;
}
body.is-vertical .hero__stage {
  /* Mobile stacks normally — every child already has its own
     is-vertical override (position:static etc.) below; the fixed-size,
     scaled canvas is desktop-only. */
  position: static;
  width: auto;
  height: auto;
  padding: 0;
  transform: none;
}

/* Heading + paragraph: back to the original side-by-side flex pair
   (same gap/basis as before today), so the paragraph keeps its
   original horizontal position and width. The heading additionally
   stays on one line and shifts right (to clear the logo); the
   paragraph additionally shifts down via position:relative — which
   only offsets it visually, it still reserves/occupies its original
   flex-computed spot, so the heading and the flex row itself are
   unaffected by the shift. */
.hero__statement {
  /* No max-width: the heading's own margin-left already pushes it
     right, and the paragraph is capped by its own max-width (46ch,
     below) — constraining the row itself on top of that only steals
     room from the paragraph and forces extra line wraps. */
  display: flex;
  align-items: center;
  gap: 64px;
  flex-wrap: wrap;
}
.hero__statement-heading {
  flex: 0 0 auto; /* fixed to its own (nowrap) content width — no
    grow, so it doesn't compete with the paragraph for extra row space */
  font-size: 3.4rem; /* fixed (was a vw-based clamp, its max value at the
    1600px reference width) — .hero__stage's own transform:scale() now
    provides the size adaptation across viewport widths as a single,
    consistent factor; a second, independent vw-based scale here would
    fight it and drift out of sync at anything other than 1600px. */
  color: var(--brown-dark);
  white-space: nowrap; /* stays on one line */
  margin-left: 170px; /* clears the space under the logo, so the logo
    has room to sit lower without the two colliding */
}
/* "bouwen?" is a pre-rendered PNG (custom hand-lettered brand font,
   which isn't a web font we can safely embed/license) rather than
   live text — see assets/brand/bouwen-word.png. Dropped straight down
   from its inline slot (position:relative keeps its horizontal spot
   exactly as-is, only paints it lower) so it hangs in the whitespace
   between "Klaar om samen te" and the paragraph below, rather than
   sitting on the same line/baseline as the rest of the heading. */
.word-pop-img {
  height: 1.5em;
  width: auto;
  display: inline-block;
  vertical-align: -0.32em; /* tuned so the word sits on the same
    baseline as the surrounding heading text */
  margin-left: 0.06em;
  position: relative;
  top: 75px; /* ~2cm down (was 3cm, brought up 1cm) */
}
.hero__statement-text {
  flex: 1 1 320px;
  position: relative;
  top: 160px; /* nudges it down toward the word, without disturbing
    its flex-computed left position/width or the heading beside it */
  font-size: 1.05rem;
  color: var(--brown-dark);
  max-width: 46ch;
}
.accent-word {
  color: var(--maroon);
  font-weight: 600;
}
.hero__mobile-cta {
  /* Mobile-only (see body.is-vertical override below) — desktop already
     has its own "Plan een kennismaking" CTAs in the nav. */
  display: none;
}
.hero__mobile-word-wrap {
  /* Mobile-only (see body.is-vertical override below) — desktop keeps
     the wide single-line .hero__word instead. */
  display: none;
}
/* Pull-quote: left-aligned to the last "e" of "ENTRE" in the word
   below (measured via Range.getBoundingClientRect on the word's text
   node), top-aligned to the heading. Width deliberately capped well
   under a typical viewport width — this being a horizontal-scroll
   page, a wider block would mean the block itself doesn't fit in one
   screen, forcing extra side-scrolling mid-read. */
.hero__quote {
  position: absolute;
  left: 2201px; /* ~10cm left of the "e" in "entre" — its end was
    running past the panel's own (viewport-scaled) width and getting
    clipped by the panel's overflow:hidden */
  top: 176px; /* clears the fixed nav bar (88px tall) with room for the
    open quote mark to float above the text without sitting behind it —
    plus ~2cm (76px) moved down as requested */
  width: 1300px;
}
.hero__quote-text {
  margin: 0; /* the default <p> margin was collapsing with
    .hero__quote-attribution's own margin-top below, silently
    overriding it whenever the default was the larger of the two */
  font-family: var(--font-body);
  font-size: 1.15rem;
  line-height: 1.42;
  color: var(--brown-dark);
}
/* Two versions of the same pull-quote: the original (longer) one for
   desktop, a shorter rewrite for the narrow layout where it sits on
   the bordeaux block. Only ever one of them is rendered. */
.hero__quote-text--mobile { display: none; }
/* Quote marks: the Entre Nous custom font's own glyph for this
   character (rendered to assets/brand/quote-mark.png the same way as
   bouwen-word.png — as an image, since the font can't be safely
   embedded as a web font). One floats above the start of the text,
   the other above/after its end — bracketing the quote like real
   quotation marks, rather than both sitting inline within a sentence
   or bunched together in one spot. */
.hero__quote-mark {
  height: 1.6em;
  width: auto;
  position: absolute;
}
.hero__quote-mark--open {
  left: -28px;
  top: -27px; /* diagonally up-left, hovering over "Ik" */
}
.hero__quote-mark--close {
  left: 278px;
  top: 171px; /* diagonally under the closing period of "gaan.",
    still clear of the attribution below */
  transform: rotate(180deg);
}
.hero__quote-attribution {
  margin-top: 40px; /* +1cm */
  font-family: var(--font-body);
  font-size: 1.05rem;
  color: var(--maroon);
}

/* Bottom word, filled with a looping video via background-clip:text —
   NOT Canvas compositing. An earlier version drew the video into a
   canvas clipped to the word with ctx.globalCompositeOperation =
   "source-in"; confirmed broken in real Safari (it painted the video
   as a plain unclipped rectangle — the compositing step appears not
   to apply there the way it does in Chromium). background-clip:text
   is a plain, decades-old CSS feature — Safari originated the
   -webkit- version of it — so it doesn't carry that risk. main.js
   grabs video frames onto a small offscreen canvas and periodically
   pushes them into this element's background-image as a data URL. */
.hero__word-wrap {
  display: inline-block;
  /* Positioned directly off the panel, independent of the statement
     block above it — clears the paragraph with room to spare, and
     sits low enough that .panel's overflow:hidden crops a substantial
     part of the (very tall) word, matching the reference's
     heavily-cut-off look. */
  position: absolute;
  left: 96px; /* fixed (was var(--edge), capped at 96px at the 1600px
    reference anyway) — see .hero__stage for why */
  top: 630px; /* fixed (was 70vh of the 900px reference height) */
  transform: rotate(-2.5deg); /* barely-there tilt — the reference reads
    as essentially horizontal, not a diagonal line */
  transform-origin: left top;
  z-index: 2; /* above .hero__leaf, so the word's letters sit in front
    of the decorative leaf rather than behind it */
}
.hero__word {
  font-family: var(--font-display);
  font-weight: 800; /* ExtraBold — Nanum Myeongjo's heaviest cut, thicker
    strokes = more video visible inside each letter */
  font-size: 34rem; /* huge — most of it is meant to be cropped away by the
    panel, only the top third or so visible. Fixed (was a vw-based clamp,
    its max value at the 1600px reference) — see .hero__stage. */
  line-height: 1; /* was 0.82 — tighter than the font's own ascent+descent,
    so glyph tops overflowed the line box and got clipped by the panel's
    overflow:hidden once the font-size grew. 1 gives the tall ExtraBold
    ascenders room without the line box shrinking under them. */
  letter-spacing: 0.22em; /* generous spacing: the word is meant to reveal
    itself gradually as you scroll, not sit fully in the first view */
  white-space: nowrap;
  margin-left: -0.04em;
  user-select: none;
  display: block;
}
.hero__word--video-text {
  color: var(--maroon); /* fallback: shown until JS has a first video frame ready */
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
}
.hero__word--video-text.has-video-bg {
  color: transparent;
  -webkit-background-clip: text;
  background-clip: text;
  /* A transparent stroke still counts as "ink" for background-clip:text
     purposes — it widens the clipped shape (thicker letters, more video
     visible) without adding a flat-colored outline, since the stroke
     itself paints nothing. Confirmed by testing with an opaque stroke
     color first, then swapping to transparent. */
  -webkit-text-stroke: 0.045em transparent;
}
.hero__word-video-source {
  /* Never shown directly — kept off in a viewport corner, visually
     clipped away, only used as a frame source (see main.js). Real
     size (not 1x1) and inside the viewport because Chrome auto-pauses
     muted video it considers "not meaningfully visible" to save
     power; clip-path actually hides it (opacity alone doesn't
     reliably, in every engine, for a *playing* video element). */
  position: fixed;
  bottom: 0;
  right: 0;
  width: 240px;
  height: 140px;
  clip-path: inset(50%);
  -webkit-clip-path: inset(50%);
  opacity: 0;
  pointer-events: none;
  z-index: -1;
}

/* Decorative leaf: bottom-center anchored to the top of the "r" in
   "entre" (measured via Range.getBoundingClientRect on the word's
   text node), growing upward from there. Uses the shared .reveal
   fade/slide-up system so it appears as the panel scrolls into view,
   same as everything else on this page. */
.hero__leaf {
  position: absolute;
  left: 1697px; /* +5cm, then +1cm more right, so the stem sits just
    behind the R's curve rather than in front of it */
  top: 102px;
  height: 620px;
  width: auto;
  pointer-events: none;
  z-index: 1; /* behind the word (below) */
}

.hero__scrollcue {
  position: absolute;
  bottom: 32px;
  left: 96px; /* fixed (was var(--edge)) — see .hero__stage */
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--brown-dark);
}
.hero__scrollcue .line {
  width: 40px; height: 1px; background: currentColor;
  animation: scrollcue 1.8s ease-in-out infinite;
}
@keyframes scrollcue {
  0%, 100% { transform: scaleX(0.4); transform-origin: left; }
  50% { transform: scaleX(1); transform-origin: left; }
}

/* ==========================================================================
   Diensten (intro panel + fanned card stack)
   ========================================================================== */
.panel--diensten-intro,
.panel--cards-fan {
  background: var(--brown-dark);
  color: var(--cream);
}
.panel--diensten-intro {
  width: calc(56vw - 0.5cm);
  min-width: calc(460px - 0.5cm);
  /* Shrinks the panel's own trailing whitespace by the same 2cm the
     width just came down by, so the text column itself (which depends
     on width minus this padding minus the .reveal margin-left below)
     stays exactly the size it was tuned to for 3 lines — only the
     empty space after the text closes up, which is what actually
     narrows the gap to the card fan (the panel ending 2cm sooner
     moves .panel--cards-fan, and the card centered inside it, 2cm
     closer). */
  padding-right: calc(var(--edge) - 2cm);
}
.panel--diensten-intro > .reveal {
  /* Keeps this panel's own text above .panel-seam-banner (z-index:5,
     positioned outside this panel) regardless of how far it reaches
     into it. */
  position: relative;
  z-index: 6;
  margin-left: 5cm;
}
.panel--diensten-intro .eyebrow { color: var(--cream); opacity: 0.75; }
.panel--diensten-intro h2 {
  color: var(--cream);
  white-space: nowrap; /* "Waar we je mee helpen" on one line, per
    request — the column below needed room for 3 lines of the
    paragraph anyway (see .panel--diensten-intro width above), so this
    now fits with room to spare rather than needing its own shrink. */
}
.panel--diensten-intro p {
  color: rgba(241,235,228,0.75);
  text-align: justify; /* "vierkant uitlijnen" */
}

/* ---- Fanned card stack ----
   .panel--cards-fan is a wide scroll track (like every other panel), but
   its content isn't laid out left-to-right along it — .cards-fan instead
   sticks (position:sticky on the same horizontal axis the page scrolls)
   so it stays centered on screen for the panel's whole width. main.js
   turns how far the wrapper has scrolled through that width into a 0–1
   progress value and steps .is-active across the 4 cards one at a time. */
.panel--cards-fan {
  width: 230vw;
  min-width: 1500px;
  padding: 0;
  /* .panel's own overflow:hidden clips position:sticky (any non-visible
     overflow on an ancestor other than the actual scroll container
     breaks it) — .cards-fan is the thing that needs to stick here, and
     nothing in this panel needs clipping the way other panels do. */
  overflow: visible;
}
.cards-fan {
  position: sticky;
  left: 0;
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(var(--nav-height) + 24px) 0 64px;
  box-sizing: border-box;
}
.cards-fan__stack {
  position: relative;
  width: min(480px, 88vw);
  height: min(64vh, 460px);
}
.service-card {
  width: 100%;
  max-width: 480px;
  min-height: min(64vh, 460px);
  background: var(--near-black);
  border-radius: 20px;
  padding: 48px 40px;
  display: flex;
  flex-direction: column;
  /* Was space-between, anchoring the text block at the top and the
     (now-removed) tag pills at the bottom — with just the one child
     left, that pinned it to the top and left a dead gap below in a
     card this tall. Centered instead. */
  justify-content: center;
}
.cards-fan__card {
  position: absolute;
  inset: 0;
  box-shadow: 0 20px 45px rgba(19,13,8,0.4);
  filter: blur(9px);
  opacity: 0.6;
  transform-origin: 50% 115%;
  transition: filter 0.5s ease, transform 0.5s ease, opacity 0.5s ease,
    box-shadow 0.5s ease;
  will-change: transform, filter;
}
.cards-fan__card[data-fan-index="0"] { transform: rotate(-16deg) translate(-108px, 18px); z-index: 1; }
.cards-fan__card[data-fan-index="1"] { transform: rotate(-6deg) translate(-40px, 4px); z-index: 2; }
.cards-fan__card[data-fan-index="2"] { transform: rotate(6deg) translate(40px, 4px); z-index: 3; }
.cards-fan__card[data-fan-index="3"] { transform: rotate(16deg) translate(108px, 18px); z-index: 4; }
.cards-fan__card.is-active {
  filter: blur(0);
  opacity: 1;
  transform: rotate(0deg) translate(0, -18px) scale(1.04);
  box-shadow: 0 30px 65px rgba(19,13,8,0.55);
  z-index: 10;
}
.service-card__index {
  font-family: var(--font-display);
  font-size: 1rem;
  color: var(--maroon);
}
.service-card h3 {
  font-size: 1.9rem;
  margin-top: 24px;
  color: var(--cream);
}
.service-card p {
  margin-top: 18px;
  color: rgba(241,235,228,0.75);
  font-size: 1rem;
}

/* ==========================================================================
   Werkwijze
   ========================================================================== */
.panel--werkwijze {
  /* +3.5cm on both width and padding-left: shifts the whole section
     (heading + steps) 3.5cm to the right — away from the "Werkwijze"
     seam banner it was sitting too close to — while keeping the
     content's own available width the same (padding-right, and so the
     werkwijze__steps grid's room to breathe, is untouched). Doesn't
     move the banner: that sits at this panel's *start* (the cumulative
     width of the panels before it), which this rule doesn't touch —
     only this panel's own width/padding, which only affects where it
     *ends* (the werkwijze/over-ons seam after it). */
  width: calc(96vw + 3.5cm);
  min-width: calc(760px + 3.5cm);
  padding-left: calc(var(--edge) + 3.5cm);
  background: var(--cream);
}
.werkwijze__steps {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 32px;
}
.step {
  border-top: 1px solid rgba(66,46,33,0.25);
  padding-top: 24px;
}
.step__num {
  font-family: var(--font-display);
  font-size: 2.4rem;
  color: var(--maroon);
}
.step h3 {
  font-size: 1.3rem;
  margin-top: 12px;
  color: var(--brown-dark);
  font-family: var(--font-body);
  font-weight: 700;
}
.step p {
  margin-top: 10px;
  font-size: 0.95rem;
  color: var(--brown-dark);
}

/* ==========================================================================
   Over ons
   ========================================================================== */
.panel--over-ons {
  /* Wider than 100vw (was exactly 100vw) so .over-ons__body — now three
     paragraphs instead of two — has more room to run its lines longer
     and come down closer to .over-ons__visual's own height instead of
     towering well above and below it. 150vw / .over-ons__body p's
     removed max-width (below) together get the text block down to
     ~412px tall — close enough to .over-ons__visual's fixed 400px
     (aspect-ratio 4/5 at 320px wide) that they read as matching. */
  width: 150vw;
  min-width: 1500px;
  background: var(--cream);
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 80px;
}
.over-ons__visual {
  flex: 0 0 320px;
  aspect-ratio: 4/5;
  border-radius: 20px;
  /* 50% transparent per request, so the frame reads as a translucent
     mat rather than a solid block once the cutout (see .over-ons__photo
     below) sits on top of it with the page's own cream showing through
     around the figure. rgba() instead of opacity, since opacity would
     also fade the photo/cutout sitting inside it. */
  background: rgba(115, 31, 50, 0.5);
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  /* .over-ons__body is flex:1, so this just eats into its own space —
     no need to widen the panel to compensate, unlike the diensten-intro
     shifts earlier. */
  margin-left: 5cm;
  /* Leaves the maroon background showing as a visible frame/mat around
     the photo instead of it filling the whole box edge-to-edge. */
  padding: 16px;
  box-sizing: border-box;
}
.over-ons__photo {
  /* Back to the full rectangular photo (the cutout experiment didn't
     land) — cover-fit, zoomed in past what cover alone crops to, with
     the maroon mat (padding, above) still showing around the edges. */
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Biased toward the upper portion (face/torso), not centered — the
     source photo is a full standing portrait, and centering vertically
     leaves too much forest floor/legs and not enough of her. */
  object-position: 50% 35%;
  border-radius: 8px;
  display: block;
  /* Zooms in past what object-fit:cover alone crops to — less
     background, more of the subject. Scales from center; the overflow
     gets clipped by the padded box above (not the outer frame), so
     this can't spill past the maroon mat. */
  transform: scale(1.9);
}
.over-ons__body { flex: 1; min-width: 0; }
.over-ons__body p {
  margin-top: 20px;
  font-size: 1.05rem;
  color: var(--brown-dark);
  /* Was 52ch, capping lines well short of the space actually
     available. Dropped entirely (rather than just raised) — even at
     90ch it was still the binding constraint ahead of the wider panel
     above, so height wasn't coming down any further; letting the
     paragraphs use the full flex width is what actually gets the
     block's height down near .over-ons__visual's. */
}
.over-ons__body .btn { margin-top: 32px; }

/* ==========================================================================
   Contact / CTA + footer content
   ========================================================================== */
.panel--contact {
  width: 108vw;
  min-width: 820px;
  background: var(--near-black);
  color: var(--cream);
  justify-content: space-between;
  padding-bottom: 6px;
  /* No vertical overflow/scroll at all now (back to the base .panel
     rule's overflow:hidden, like every other panel) — any vertical
     play on this one panel, even just a pixel or two, was fighting the
     rest of the site's horizontal-only scroll feel. Content is sized
     to fit 100vh at ordinary browser heights without needing it. */
}
.contact__body {
  text-align: center;
  /* Was auto on both sides (centers the whole block in the panel's
     leftover vertical space, evenly above and below) — dropping the
     top auto-margin pulls it up flush under the panel's own top
     padding instead, so the text starts higher rather than floating
     centered with a lot of empty space above it. */
  margin: 0 0 auto;
}
.contact .eyebrow { color: var(--maroon); }
.contact h2 {
  font-size: clamp(2rem, 4.4vw, 3.4rem);
  margin-top: 16px;
  color: var(--cream);
}
.contact p {
  margin: 18px auto 0;
  max-width: 46ch;
  color: rgba(241,235,228,0.75);
  font-size: 1rem;
}
.contact__form {
  margin: 20px auto 0;
  max-width: 480px;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.form__row { display: flex; gap: 14px; }
.form__row .form__field { flex: 1; min-width: 0; }
.form__field { display: flex; flex-direction: column; gap: 6px; }
.form__field label {
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(241,235,228,0.5);
}
/* Underline-only fields (was a bordered box) — matches momenti.agency's
   own contact form structure, per request, just in this site's own
   colour palette instead of theirs. */
.form__field input, .form__field select, .form__field textarea {
  width: 100%;
  background: transparent;
  border: none;
  border-bottom: 1px solid rgba(241,235,228,0.25);
  padding: 7px 0;
  font-family: var(--font-body);
  font-size: 0.9rem;
  color: var(--cream);
  outline: none;
  transition: border-color 0.2s;
  resize: none;
}
.form__field select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23731f32' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 2px center;
}
.form__field select option { color: var(--near-black); }
.form__field input:focus, .form__field select:focus, .form__field textarea:focus {
  border-bottom-color: var(--maroon);
}
.form__field textarea { resize: vertical; min-height: 36px; }
.form__field input::placeholder, .form__field textarea::placeholder {
  color: rgba(241,235,228,0.35);
}
.contact__form .btn { align-self: flex-start; margin-top: 6px; }
.form__error { display: none; margin-top: 2px; }
.form__error.is-visible { display: block; }
.form__error p {
  margin: 0;
  padding: 10px 14px;
  background: rgba(241,235,228,0.05);
  border: 1px solid rgba(115,31,50,0.4);
  border-radius: 10px;
  font-size: 0.76rem;
  line-height: 1.5;
  color: var(--cream);
}
.form__error a { color: var(--maroon); text-decoration: underline; }
.form__success { text-align: center; padding: 12px 0; }
.form__success-title {
  font-family: var(--font-display);
  font-size: 1.3rem;
  color: var(--cream);
  margin-bottom: 6px;
}
.form__success p { margin: 0; font-size: 0.85rem; color: rgba(241,235,228,0.7); }
.contact__actions {
  margin-top: 16px;
  display: flex;
  gap: 16px;
  justify-content: center;
  flex-wrap: wrap;
}

/* "Terug naar voren" / "Terug naar boven" — the wording follows the
   scroll direction, so only one of the two labels is ever rendered. */
.btn__label--mobile { display: none; }
body.is-vertical .btn__label--desktop { display: none; }
body.is-vertical .btn__label--mobile { display: inline; }

.footer {
  border-top: 1px solid rgba(241,235,228,0.12);
  padding-top: 6px;
  color: rgba(241,235,228,0.7);
}
.footer__top {
  display: flex;
  justify-content: flex-end;
  padding-bottom: 6px;
}
.footer__cols {
  /* Navigatie / Contact / Bedrijf side by side on one line (was three
     stacked rows) — each group is still its own heading followed
     inline by that heading's own items, just no longer stacked
     underneath the other two groups. */
  display: flex;
  flex-wrap: wrap;
  gap: 6px 40px;
}
.footer__col {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  row-gap: 2px;
  column-gap: 16px;
}
.footer__col h4 {
  font-family: var(--font-body);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: rgba(241,235,228,0.5);
}
.footer__col a, .footer__col span {
  font-size: 0.74rem;
  color: rgba(241,235,228,0.8);
}
.footer__col a:hover { color: var(--cream); }
.footer__bottom {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding-top: 6px;
  border-top: 1px solid rgba(241,235,228,0.12);
  font-size: 0.7rem;
}

/* ==========================================================================
   Vertical fallback — narrow viewports & prefers-reduced-motion.
   main.js adds .is-vertical to <body> instead of initializing Lenis.
   ========================================================================== */
body.is-vertical #hscroll-wrapper {
  height: auto;
  width: auto;
  overflow: visible;
}
body.is-vertical #hscroll-content {
  display: block;
  height: auto;
  width: auto;
}
body.is-vertical .panel {
  width: 100% !important;
  min-width: 0 !important;
  height: auto;
  /* Was min-height:100vh — forced every section to be at least a full
     screen tall even when its own content (e.g. the short diensten
     intro) was nowhere near that, so base .panel's justify-content:
     center then centered it inside all that leftover space, leaving a
     dead, empty-looking gap above and below. Sections now size to
     their own content plus padding instead, matching how momenti's
     mobile site is actually built (generous section padding, no
     forced full-viewport minimum) — this is the same fix
     .panel--contact already got on its own further down, just never
     generalised to every panel. */
  overflow: visible;
  /* Only .panel--hero (below) actually needs to clear the fixed nav —
     every other panel already starts well below it once panels are
     content-sized instead of forced to 100vh each, so giving all of
     them that same nav-height buffer just piled extra dead space
     between every section. */
  padding-top: 48px;
  padding-bottom: 72px;
}
body.is-vertical .panel--hero {
  padding-top: calc(var(--nav-height) + 48px);
  /* Desktop-only: base .panel--hero zeroes this out because .hero__stage
     is a fixed-size canvas scaled as one unit, so the panel's own
     padding would double up against .hero__stage's own math. On mobile
     .hero__stage's children flow normally instead (see the
     .hero__statement rules below) — nothing left to double up against,
     and without this the hero text was sitting flush against the
     screen edge, unlike every other panel. */
  padding-left: var(--edge);
  padding-right: var(--edge);
  /* The quote panel is the last thing in this panel and runs edge to
     edge, so the shared 72px bottom padding just added a band of cream
     under it — together with the (now hidden) scroll cue that was the
     white strip between this section and the dark one below. */
  padding-bottom: 0;
  /* Scopes .hero__mobile-word-wrap's negative z-index (below) to this
     panel alone — without a stacking context of its own here, "behind
     everything in this panel" could just as easily mean "behind the
     previous/next panel" once compared against the page's root
     stacking context instead. */
  isolation: isolate;
}
body.is-vertical .hero__mobile-word-wrap {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  /* First-screen-only background, same reasoning as everything else
     pinned to one screen's height on this page: not meant to follow
     .hero__quote and the rest of the panel further down. svh falls
     back to plain vh where unsupported. */
  height: 100vh;
  height: 100svh;
  overflow: hidden; /* crops the oversized/rotated word at the edges —
    the "playful cut-off" look, per request */
  z-index: -2;
  pointer-events: none;
  opacity: 0.22; /* per request — stepped down again from 0.3 */
}
.hero__mobile-word {
  font-family: var(--font-display);
  font-weight: 800; /* ExtraBold — matches .hero__word's own weight (the
    desktop word). No -webkit-text-stroke on top of it: that was making
    the strokes read as too thick, and fattening each glyph by ~0.09em
    per side is also what pushed neighbouring letters into each other
    (the "RE" of REN was visibly fused). The font's own heaviest cut is
    enough. */
  /* Big enough, combined with the line-height below, that 3 stacked
     lines span well past the screen's own height before rotation even
     widens that further — the request was for this to fill the *whole*
     first screen top-to-bottom, not sit as a modest accent. */
  font-size: clamp(9rem, 44vw, 17.5rem);
  /* 2 (briefly) read as too spread out — pulled back in so the 3 lines
     sit closer together, per request. Still looser than .hero__word's
     own tight 0.92, which was cramped enough to read as one solid
     block instead of 3 distinct lines. */
  line-height: 1.4;
  /* Opened up from 0.05em — at this weight and size the glyphs were
     running into each other horizontally. */
  letter-spacing: 0.12em;
  text-align: center;
  white-space: nowrap; /* only the explicit <br>s in the markup break it
    — 3 fixed lines of 3 letters, not reflowed by the viewport width */
  user-select: none;
  display: block;
  position: absolute;
  left: 50%;
  /* Was 42% (top cropped, per the reference sketch) — per request,
     pulled back down so ENT starts right around where .nav ends
     instead of running well up behind it, with only a small overlap.
     The size bump above is what keeps OUS still reaching the bottom
     edge despite starting lower now. */
  top: 52%;
  /* Centered then rotated as one 3-line block — rotating a stack of
     lines this way is what actually produces the ascending-diagonal
     "staircase" from the sketch (each line ends up offset from the
     next along the tilt) rather than needing each line individually
     repositioned. Steeper than .hero__word's barely-there -2.5deg —
     the sketch reads as a real diagonal, not a nearly-horizontal one. */
  transform: translate(-50%, -50%) rotate(-18deg);
  /* letter-spacing adds its trailing space after the final letter of
     each line too, which would throw the centering off by half a step. */
  text-indent: 0.12em;
  /* Sits on the text rather than on .hero__mobile-word-wrap: the wrap is
     what crops the letters at the screen edges (overflow:hidden), and a
     filter there would blur that crop line too, softening the deliberate
     hard cut-off into a vignette. Blurring the inner element keeps those
     edges razor-sharp and only softens the letterforms themselves. */
  filter: blur(3px);
  color: var(--maroon); /* fallback for engines without background-clip:text */
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .hero__mobile-word {
    /* A plain CSS gradient, NOT the desktop word's grabbed video frame.
       That frame is a 3:1 wide strip; background-size:cover on this
       block (0.75:1 — taller than wide) scaled it up until only a
       narrow, essentially flat brown slice of it was visible, which is
       why no gradient showed here however the fill was tuned. The
       brand's own two colours run across the block directly instead —
       same bordeaux-to-brown range as the desktop word, no video, no
       canvas, and nothing that can fail to load on a phone.
       135deg follows the block's own diagonal, so the sweep runs along
       the ENT -> REN -> OUS cascade rather than across it. */
    background-image: linear-gradient(135deg, var(--maroon) 0%, var(--maroon) 18%, #5c3a30 50%, var(--brown-dark) 82%, var(--brown-dark) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}
body.is-vertical .panel--over-ons {
  /* Was a column flex, which stacked the photo above the text as two
     separate blocks. Plain block layout instead so the photo can float
     and the copy can run around it — flex items can't be floated. */
  display: block;
}
body.is-vertical .panel--werkwijze {
  /* Desktop-only shift (see the desktop rule) — would just eat most of
     the narrow mobile column otherwise. */
  padding-left: var(--edge);
  /* "Hoe we samenwerken" 1cm up, per request — off the panel's top
     padding (the shared mobile value is 48px), so the block and the
     steps under it keep their spacing and move together, the same way
     the diensten panel's copy was shifted. */
  padding-top: calc(48px - 1cm);
}
body.is-vertical .werkwijze__steps {
  /* Was still the desktop 4-column grid — never had a mobile override,
     so all 4 steps got squeezed into ~90-140px-wide columns on a phone
     screen (confirmed: computed grid-template-columns was
     "142px 109px 104px 88px" at 375px wide), wrapping mid-word and
     running the last column off the edge. One column, stacked, like
     momenti's own .steps mobile override. */
  grid-template-columns: 1fr;
  gap: 40px;
}
/* Two portraits in the markup, only ever one shown: the original (a flex
   column beside the text on desktop) and a copy sitting inside the body
   after the heading, which is the only way to float it alongside the
   paragraphs rather than the heading. */
.over-ons__visual--inline { display: none; }
body.is-vertical .over-ons__visual:not(.over-ons__visual--inline) { display: none; }
body.is-vertical .over-ons__visual--inline {
  display: block;
  flex: none;
  /* Floated right, per request, and smaller than before so the copy has
     room to run past it on the left. */
  float: right;
  width: 46%;
  max-width: 164px;
  /* Desktop-only shift (see the desktop rule) — the stacked mobile
     layout has no room for it.
     The top margin drops it a few lines into the first paragraph, per
     request, rather than starting level with the paragraph's first line:
     a float sits where it falls in the flow, so pushing it down is what
     lets those opening lines run full width above it. */
  margin: 58px 0 14px 20px;
}
/* Deliberately NOT overflow:hidden on .over-ons__body — that would give
   it its own block formatting context, and the text would sit beside the
   photo as one rigid column instead of wrapping around it. The float is
   cleared on the panel instead, so the section still contains it. */
body.is-vertical .panel--over-ons::after {
  content: "";
  display: block;
  clear: both;
}
body.is-vertical .panel--contact {
  min-height: auto;
  /* The footer is the last thing inside this panel, so the shared
     body.is-vertical .panel padding-bottom:72px was leaving a 72px
     band of empty cream *below the footer* at the very end of the page
     (measured: panel ended at 8013, footer at 7941). Nothing follows
     the footer, so there's nothing for that padding to separate. */
  padding-bottom: 0;
}
/* Footer on mobile: more air around the block, tighter type inside it,
   so it reads as a distinct closing section without taking much height.
   The desktop footer is a single right-aligned row tuned for a wide
   panel; these only touch the stacked version. */
body.is-vertical .footer {
  margin-top: 44px;
  padding-top: 22px;
}
body.is-vertical .footer__top { padding-bottom: 14px; }
body.is-vertical .footer__cols { gap: 10px 26px; }
body.is-vertical .footer__col { column-gap: 10px; row-gap: 1px; }
body.is-vertical .footer__col h4 { font-size: 0.56rem; }
body.is-vertical .footer__col a,
body.is-vertical .footer__col span { font-size: 0.68rem; line-height: 1.35; }
body.is-vertical .footer__bottom {
  padding-top: 12px;
  gap: 2px;
  font-size: 0.62rem;
  line-height: 1.35;
}
body.is-vertical .panel--diensten-intro {
  /* Desktop-only: the -2cm trim (see the desktop rule) is sized for a
     several-hundred-px-wide edge; at mobile's own already-small
     var(--edge) (~24px) it goes negative and clamps to 0, leaving text
     flush against the screen's right edge. Restore the normal edge
     padding here. */
  padding-right: var(--edge);
  /* Beige, per request. The panel's copy is written for a dark
     background (cream heading, translucent cream body — see the desktop
     rules), so every text colour has to flip to dark ink here.
     Its data-nav-theme="dark" is cleared in main.js to match, or the
     nav would go cream-on-cream over this now-light panel. */
  background: var(--cream);
  color: var(--brown-dark);
  /* 48px (the shared mobile .panel value) + 1cm, per request — also
     gives "Waar we je mee helpen" clearance from the Diensten banner,
     whose bottom half overlaps the top 48px of this panel. */
  padding-top: calc(48px + 1cm);
}
body.is-vertical .panel--diensten-intro h2 { color: var(--brown-dark); }
body.is-vertical .panel--diensten-intro p { color: rgba(66, 46, 33, 0.8); }
body.is-vertical .panel--diensten-intro .eyebrow { color: var(--maroon); opacity: 1; }
body.is-vertical .panel--diensten-intro > .reveal {
  /* Desktop-only nudge (clears room next to .panel-seam-banner /
     balances the wide panel) — would just eat into the narrow mobile
     column, so reset to flush-left there. */
  margin-left: 0;
}
body.is-vertical .panel--diensten-intro h2 {
  /* Desktop-only: nowrap keeps "Waar we je mee helpen" on one line in
     the (wide) desktop column — on a 390px phone screen that would run
     off the edge instead, so let it wrap normally there. */
  white-space: normal;
}
body.is-vertical .panel--cards-fan {
  /* Desktop-only: the fan/blur/scroll-reveal effect relies on
     position:sticky along the horizontal scroll axis and a wide
     (230vw) scroll track — meaningless once .panel is forced to a
     plain 100%-width, auto-height block above. Fall back to a normal
     stacked list of fully-legible cards instead. */
  height: auto;
  /* Beige behind the cards, per request. Only the panel changes — the
     cards keep their own near-black background and set their own text
     colours (see .service-card h3/p/__index), so nothing inherits an
     unreadable colour from here. data-nav-theme="dark" is cleared in
     main.js for the same reason as the diensten panel. */
  background: var(--cream);
  /* Runs on past the cards, per request, so the section has room to
     breathe before the Werkwijze banner on the seam below it. (The
     fan itself was pulled 2cm up, which had tightened the gap further.) */
  padding-bottom: 170px;
}
/* Card fan on mobile: the same fanned stack as desktop, stepped through
   by swiping horizontally on the cards instead of by the page scrolling
   sideways.

   The first version made .cards-fan itself the scroll container with the
   stack sticky inside it — mirroring desktop's mechanism. It rendered
   correctly in every browser tested here, at every width, but showed a
   completely blank section on a real iPhone. Two known iOS Safari
   problems stack up in that arrangement: the (deprecated since iOS 13)
   -webkit-overflow-scrolling:touch creates a legacy compositing context
   that breaks position:sticky descendants, and heavily filtered,
   absolutely-positioned children inside it can drop out of the render
   entirely.

   So nothing about the fan's *visibility* depends on scrolling any more.
   The stack is an ordinary positioned block — cards render the same way
   they do on desktop — and the swipe comes from a transparent scroller
   overlaid on top (.cards-fan__swipe, built in main.js). Worst case if
   that overlay ever fails is a fan that doesn't swipe, rather than a
   section that isn't there. */
body.is-vertical .cards-fan {
  position: static;
  width: auto;
  height: auto;
  padding: 0;
  display: block;
  /* Whole fan 2cm up, per request, bringing it closer to the "Waar we je
     mee helpen" copy above. On this container rather than the stack
     inside it: on the stack, its top 2cm sat outside this box, and this
     box's mask (below) then clipped that overhang. */
  margin-top: -2cm;
  /* Vertical half of the fade. The stack below carries the left/right
     gradient; this carries the bottom one, so each element runs a
     single-axis mask and neither needs mask-composite — which is the
     kind of newer compositing feature that already rendered this whole
     section blank on real iOS once.
     Without it the mask cut straight across the bottom and sliced the
     cards' drop shadows off in a hard horizontal line. Opaque until 88%
     (just past the front card's lower edge, so it stays crisp) and
     transparent by 100%, letting the shadows dissolve into the beige. */
  -webkit-mask-image: linear-gradient(to bottom, #000 0, #000 88%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0, #000 88%, transparent 100%);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
body.is-vertical .cards-fan__stack {
  position: relative;
  width: 100%;
  /* Taller than the card itself (which is inset from it, below) so the
     fanned neighbours have somewhere to splay into. Sized off the card:
     card height + the 30px inset top and bottom. */
  /* Taller than the card needs, all of the extra below it (see the
     card's bottom inset), so the drop shadows have somewhere to finish.
     The card's own height and position are unchanged. */
  height: min(62vh, 466px);
  /* NB: the 2cm upward shift lives on .cards-fan (the parent), not here.
     On the stack it pushed the stack's top 2cm outside the parent's box,
     and once that parent gained a mask the overhang was clipped — which
     sliced the top off the card and its "01". */
  /* Was overflow:hidden, which sliced the fanned cards off at a hard
     vertical line. A mask does the same containment (anything outside
     the box still doesn't paint, since the gradient isn't repeated) but
     with a soft edge, so the cards behind dissolve into the beige.
     The fade is deliberately short — 7% ≈ 27px a side. An earlier 8%
     fade sounded similar but was fatal in practice: the neighbours only
     protruded ~26px, so the ramp covered the entire strip of them that
     was visible and faded away the very thing it was meant to soften.
     The card is narrower now (below), so the neighbours clear the ramp
     with solid card to spare and only their outer tips dissolve. */
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 7%, #000 93%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 7%, #000 93%, transparent 100%);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
/* Transparent horizontal scroller laid over the fan — the swipe surface.
   Built by main.js on mobile only (see setupFanSwipe) so desktop's markup
   is untouched. Carries no visible content of its own: it exists purely
   so the browser gives us a native horizontal scroll to read a position
   from, which means the browser also arbitrates the gesture — a mostly
   horizontal swipe scrubs the fan, a mostly vertical one scrolls the
   page, with real momentum and nothing calling preventDefault. */
.cards-fan__swipe { display: none; } /* mobile-only; see below */
body.is-vertical .cards-fan__swipe {
  display: block;
  position: absolute;
  inset: 0;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain; /* a swipe past the last card stays
    here instead of triggering the browser's back-gesture */
  scrollbar-width: none;
  /* Must clear .cards-fan__card.is-active's z-index:10 — at 2 the front
     card sat on top of this overlay, so a finger on the card never
     reached the scroller and the fan wouldn't swipe at all. */
  z-index: 20;
  touch-action: pan-x; /* tells iOS this surface pans horizontally;
    vertical drags still fall through to the page scroll */
}
body.is-vertical .cards-fan__swipe::-webkit-scrollbar { display: none; }
body.is-vertical .cards-fan__swipe > div {
  /* The scroll range itself: 4 screens, one per card. */
  width: 400%;
  height: 100%;
}
body.is-vertical .cards-fan__card {
  /* Inherits the desktop fan positioning (absolute, blur, rotation,
     .is-active bringing one card flat to the front).
     Inset on all four sides, not just the sides: the card previously
     filled the stack edge to edge and ran taller than it, so it was
     sliced off top and bottom by the clip and there was no room for the
     neighbours to show — one big cropped card instead of a fan. The
     margin left here is what the fan splays into.
     Kept square-ish per request. Rather than narrowing the card to make
     room for the fan (which forced it tall and thin, since the copy
     then needs more height), the fan is simply allowed to run out past
     the sides and be cropped there — cropping in the fan is fine, and
     it's what lets the splay be wide while the card stays square. */
  inset: 30px auto 60px 9%;
  width: 82%;
  max-width: none;
  min-height: 0;
  height: auto; /* derived from the top/bottom insets above */
  /* Extra bottom padding reserves the strip the "— scroll" hint sits
     in, so the copy (vertically centred) can't run into it. */
  padding: 26px 24px 48px;
  /* Desktop pivots below the card (50% 115%) for a wide arc; at this
     size that swings the outer cards much further sideways than the
     margin above allows, so pivot from the centre instead. */
  transform-origin: 50% 50%;
}
/* Fan spread retuned for a phone: desktop's ±108px offsets and 16deg
   rotations are sized for a 480px card on a wide screen. These angles
   are chosen so the outermost card's rotated corners land just inside
   the stack — enough splay to read clearly as a fan, without anything
   touching the clip. */
/* Spread much wider than before: at ±14px the neighbours barely cleared
   the front card and read as shadow rather than as other cards. They now
   stand well clear on both sides, like desktop's fan, and run into the
   mask's soft edge instead of a hard clip. */
body.is-vertical .cards-fan__card[data-fan-index="0"] { transform: rotate(-14deg) translate(-74px, 18px); }
body.is-vertical .cards-fan__card[data-fan-index="1"] { transform: rotate(-6deg) translate(-32px, 7px); }
body.is-vertical .cards-fan__card[data-fan-index="2"] { transform: rotate(6deg) translate(32px, 7px); }
body.is-vertical .cards-fan__card[data-fan-index="3"] { transform: rotate(14deg) translate(74px, 18px); }
body.is-vertical .cards-fan__card.is-active {
  transform: rotate(0deg) translate(0, -6px) scale(1.03);
}
/* Type scaled to the smaller, squarer card so the longest copy ("Content
   & Meta advertenties") still fits inside it without overflowing. */
body.is-vertical .cards-fan__card {
  /* Desktop's drop shadow is a wide, heavy pool meant for a big card on
     cream. At this size it read as a dark halo around the card and, cut
     off by the mask, as the "line" at the edges. Tighter and lighter. */
  box-shadow: 0 12px 26px rgba(19, 13, 8, 0.28);
}
body.is-vertical .cards-fan__card:not(.is-active) {
  /* This is what actually made the fan unreadable, more than the spread
     did: at desktop's 9px blur the neighbours have no discernible edge,
     so the strip of them showing past the front card looks like more
     shadow rather than like other cards. Desktop gets away with it
     because they protrude ~108px; here it's a few dozen, so they need a
     defined edge to register at all. Still clearly behind, just legible
     as cards. */
  filter: blur(1.5px);
  opacity: 0.78;
}
body.is-vertical .service-card h3 { font-size: 1.15rem; margin-top: 6px; }
body.is-vertical .service-card p { font-size: 0.72rem; line-height: 1.42; margin-top: 10px; }
body.is-vertical .service-card__index {
  font-size: 1.9rem; /* was 0.72rem — a proper numeral on the card, per
    request, rather than a small label */
  line-height: 1;
  display: block;
}
/* "— scroll" hint in the front card's bottom-left corner, so it's clear
   the fan can be paged through. Only on the active card: on the faded,
   blurred ones behind it would just be noise. Built from the card's own
   two pseudo-elements (neither was in use) rather than new markup, which
   keeps it out of the DOM on desktop entirely. */
body.is-vertical .cards-fan__card.is-active::before,
body.is-vertical .cards-fan__card.is-active::after {
  position: absolute;
  bottom: 22px;
  pointer-events: none;
}
body.is-vertical .cards-fan__card.is-active::before {
  content: "";
  left: 24px;
  width: 22px;
  height: 1px;
  bottom: 30px; /* sits on the text's optical centre line */
  background: var(--maroon);
}
body.is-vertical .cards-fan__card.is-active::after {
  content: "scroll";
  left: 56px;
  font-family: var(--font-body);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--maroon);
}
body.is-vertical .service-card p { font-size: 0.95rem; }
/* Scroll progress: the same element as desktop, stood on its end. There
   it's a horizontal rail along the bottom tracking sideways progress;
   here it's a thin vertical rail down the right edge tracking ordinary
   page scroll (main.js fills it by height rather than width in this
   mode), with the numeric counter under its foot. */
body.is-vertical .hscroll-counter {
  /* Sits under the foot of the rail, aligned to the same edge. */
  bottom: 18px;
  right: 10px;
  font-size: 0.62rem;
}
body.is-vertical .hscroll-progress {
  display: block;
  left: auto;
  right: 16px;
  top: calc(var(--nav-height) + 20px);
  /* Stops short of the bottom to leave the counter its own room. */
  bottom: 46px;
  width: 2px;
  height: auto;
  border-radius: 2px;
  /* Tinted maroon rather than desktop's brown-on-cream: this rail
     crosses both the cream sections and the dark quote/contact panels,
     and a brown track disappears against those. */
  background: rgba(115, 31, 50, 0.18);
}
body.is-vertical .hscroll-progress-bar {
  width: 100%;
  height: 0%;
  border-radius: 2px;
  transition: height 80ms linear;
}
body.is-vertical .panel--hero { justify-content: flex-start; }
body.is-vertical .hero__statement {
  flex-direction: column;
  /* Was flex-start (shrink-wrapped each child to its own content
     width, e.g. the heading only as wide as "Klaar om samen te" —
     no room for its own text-align to do anything). Stretch instead,
     so each child spans the full column and its own text-align
     (center / justify, below) has width to actually work with. */
  align-items: stretch;
  /* Claims the whole first screen for itself and centers the
     heading/paragraph/CTA vertically inside it, so .hero__quote and
     everything after it (next in normal flow, following this block)
     only comes into view on a second scroll. svh (falls back to plain
     vh where unsupported) — mobile Safari's collapsing address bar
     makes 100vh taller than what's actually on screen on load, which
     would let the quote peek in early.
     The negative margin-top cancels out .panel--hero's own
     padding-top (nav clearance) so this box spans the *true* screen
     (0 to 100vh) instead of starting 136px down it — without this,
     centering happens inside a box that itself starts a third of the
     way down the screen, so the "centered" content actually lands
     well into the lower half of what's visible, not the true middle.
     Content ends up centered ~232px down either way (well clear of
     the 88px nav), just measured from the real top now. The + 2cm on
     top of that cancellation shifts this whole box (and everything
     centered inside it) 2cm further down the screen than true-center,
     per request — box height is unchanged, so it moves as a uniform
     block rather than changing how it's centered. */
  margin-top: calc(-1 * (var(--nav-height) + 48px) + 2cm);
  min-height: 100vh;
  min-height: 100svh;
  justify-content: center;
  gap: 28px;
  flex: none;
  max-width: none;
}
body.is-vertical .hero__statement-heading,
body.is-vertical .hero__statement-text { flex: none; }
body.is-vertical .hero__statement-heading {
  /* Desktop-only: the right-shift and forced single line exist to
     clear the logo and leave it room to sit lower — not relevant once
     the layout is a plain narrow stack. */
  white-space: normal;
  margin-left: 0;
  /* The desktop font-size is now a flat 3.4rem (.hero__stage handles
     size adaptation there) — restore the narrow-screen size the old
     vw-based clamp used to settle on at mobile widths, then a touch
     smaller again per request. */
  font-size: 2rem;
  /* Was centered — per request, its first line now starts at the same
     x as .hero__statement-text below (justify always starts flush
     left, so this needs to match that rather than sit centered). Both
     share the same box width (.hero__statement's align-items:stretch),
     so plain left-align is enough to line the two up exactly. */
  text-align: left;
}
body.is-vertical .hero__samen-word {
  /* Just a measurement hook (main.js reads its own position to place
     .word-pop-img below) — no visual styling of its own. */
  display: inline-block;
}
body.is-vertical .word-pop-img {
  /* Desktop-only downward drop — on the narrow stack "bouwen?" gets
     its own explicit line + offset below instead (positionBouwenWord
     in main.js sets margin-left to start it under the middle of
     "samen" above, per request — "schuin onder de eerste regel"). */
  position: static;
  top: auto;
  display: block;
  height: 1.3em; /* was 1.5em (the shared base rule) — a touch smaller */
}
body.is-vertical .hero__statement-text {
  /* Desktop-only downward nudge (toward the word) — the stack's own
     gap (below) separates it from the heading here instead. */
  position: static;
  top: auto;
  text-align: justify; /* "vierkant uitgelijnd" */
  margin-top: 12px; /* a bit more room under the heading, on top of
    .hero__statement's own 28px gap */
}
body.is-vertical .hero__mobile-cta {
  display: inline-flex;
  align-self: center;
}
body.is-vertical .hero__word-wrap {
  /* Desktop's own ENTRENOUS word. Fully replaced on mobile by
     .hero__mobile-word-wrap (the 3-line ENT/REN/OUS background above),
     so showing it here as well meant the word appeared twice — and it
     was the page's one real source of horizontal scroll: even reflowed
     into normal flow it measured 428px wide against a 375px screen
     (document scrollWidth was exactly 428 to match), which is the strip
     of empty page that appeared when you could drag sideways.
     Hiding it removes the duplicate and the sideways scroll in one go,
     and stops phones downloading hero-word-loop.mp4 (~1.5MB) for a
     word they never see. */
  display: none;
}
body.is-vertical .hero__quote-text--desktop { display: none; }
body.is-vertical .hero__quote-text--mobile { display: block; }
body.is-vertical .hero__quote {
  /* Desktop-only: the fixed left/top/width position the quote against
     the (also desktop-only) diagonal word — just stack it normally,
     full-width, below everything else. */
  position: static;
  width: auto;
  max-width: none;
  /* Bordeaux panel starting right where the cropped "O" of OUS ends,
     i.e. exactly at the bottom of the first screen. .hero__statement
     above is a full 100svh box, but it was also shifted down by 2cm
     (see its own margin-top) — so its bottom edge sits 2cm *past* the
     fold, which left a band of cream between the cut-off O and this
     block. This cancels exactly that shift, nothing more: measured
     quote top 888 vs a fold at 812 = the same 2cm (75.6px). */
  margin-top: -2cm;
  background: var(--near-black); /* the darker of the site's two browns
    (--near-black #261b13, vs --brown-dark #422e21) */
  color: var(--cream);
  /* Full-bleed: cancels .panel--hero's own var(--edge) side padding so
     the bordeaux runs edge to edge, then re-applies that same padding
     inside itself so the text keeps the site's standard 1cm margin. */
  margin-left: calc(-1 * var(--edge));
  margin-right: calc(-1 * var(--edge));
  /* Top: 48px + 1.5cm, dropping the whole quote block (mark, paragraph
     and attribution together) 1.5cm further down the brown panel per
     request — the panel itself stays anchored to the fold.
     Bottom: generous, because the Diensten banner overlaps 48px up into
     this panel (see .panel-seam-banner--diensten), so the last ~48px is
     sat on by the banner. The rest is deliberate brown breathing room
     between the attribution line and that banner. */
  padding: calc(48px + 1.5cm) var(--edge) 150px;
}
body.is-vertical .hero__quote-text--mobile {
  color: var(--cream);
  /* Matched to .hero__statement-text (the "Van contentstrategie..."
     paragraph on the first screen) — same family already, this brings
     the size and leading in line too: 1.15rem/1.42 -> 1.05rem/1.6. */
  font-size: 1.05rem;
  line-height: 1.6;
}
body.is-vertical .hero__quote-strong {
  font-weight: 700;
  color: var(--maroon);
}
body.is-vertical .hero__quote-attribution { color: var(--cream); }
body.is-vertical .hero__quote-mark {
  /* Desktop-only: the fixed left/top offsets float each mark
     diagonally against a specific word in the (much wider) desktop
     column — meaningless at this width, and since .hero__quote is no
     longer their positioning context here, would otherwise place them
     off in a wrong, unrelated spot. Back into normal flow instead. */
  position: static;
  display: block;
  /* Recoloured to bordeaux. There's no maroon variant of this asset
     (unlike the logo, which ships two ink colours), and a filter chain
     can only approximate a specific target colour — so the glyph's own
     alpha is used as a mask and the colour comes from background-color,
     which lands on the exact palette value. object-position pushes the
     original dark bitmap outside the box so only the masked background
     shows; without it the dark glyph would still paint over the top. */
  background-color: var(--maroon);
  -webkit-mask-image: url("/assets/brand/quote-mark.png");
  mask-image: url("/assets/brand/quote-mark.png");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  object-position: -99999px 99999px;
}
body.is-vertical .hero__quote-mark--open {
  margin-bottom: 8px;
}
body.is-vertical .hero__quote-mark--close {
  margin-left: auto;
  margin-top: 8px;
}
body.is-vertical .hero__leaf {
  /* Desktop-only: draped specifically over the (also desktop-only)
     positioned first paragraph and the diagonal word — no equivalent
     spot in the narrow stacked layout, so just hidden there rather
     than showing it somewhere unrelated. */
  display: none;
}
body.is-vertical .hero__scrollcue {
  /* Removed on mobile per request: it sat in a strip of cream between
     the dark quote panel and the (also dark) diensten panel below,
     breaking the run of colour. The hero panel's own bottom padding
     goes with it (below) so the two dark blocks meet directly — a
     scroll cue also earns its keep far less here, where plain vertical
     scrolling is the obvious affordance, than on the desktop
     horizontal-scroll layout it was designed for. */
  display: none;
}

@media (max-width: 700px) {
  .footer__bottom { flex-direction: column; }
}

/* ---- Scroll reveal ---- */
.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 800ms ease, transform 800ms cubic-bezier(0.16, 1, 0.3, 1);
}
.reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* ---- Mobile nav drawer ---- */
.nav__drawer {
  position: fixed;
  inset: 0;
  background: var(--cream);
  z-index: 99;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 28px;
  padding: 0 var(--edge);
  transform: translateY(-100%);
  transition: transform var(--transition-slow);
}
.nav__drawer.is-open { transform: translateY(0); }
.nav__drawer a {
  font-family: var(--font-display);
  font-size: 2.2rem;
  color: var(--brown-dark);
}
body.nav-open { overflow: hidden; }
.nav__burger.is-active span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav__burger.is-active span:nth-child(2) { opacity: 0; }
.nav__burger.is-active span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
