/* ==========================================================================
   Premium Stucwerk — design tokens
   ========================================================================== */
:root{
  /* Brand palette, sampled from Logo.png */
  --espresso:      #2A1F18;
  --espresso-700:  #3D2E22;
  --bronze:        #6B4A36;
  --bronze-600:    #7C5A43;
  --bronze-300:    #C9A98A;
  --tan:           #B08A63;
  --tan-200:       #D8C0A0;
  --cream:         #FBF3EA;
  --cream-alt:     #F3E7D8;
  --white:         #FFFFFF;

  --text:          #2C221B;
  --text-muted:    #6E5D4F;
  --text-on-dark:  #F3E7D8;
  --text-on-dark-muted: #C9B8A6;

  --success:       #2F7D5A;
  --danger:        #B3261E;

  --font-display: 'Fraunces', ui-serif, Georgia, serif;
  --font-body: 'Inter', ui-sans-serif, system-ui, sans-serif;

  --space-1: 4px;  --space-2: 8px;  --space-3: 12px; --space-4: 16px;
  --space-5: 24px; --space-6: 32px; --space-7: 48px; --space-8: 64px;
  --space-9: 96px;

  --radius-sm: 8px; --radius-md: 14px; --radius-lg: 24px; --radius-pill: 999px;

  --shadow-sm: 0 1px 3px rgba(42,31,24,0.08), 0 1px 2px rgba(42,31,24,0.06);
  --shadow-md: 0 8px 24px rgba(42,31,24,0.10), 0 2px 8px rgba(42,31,24,0.06);
  --shadow-lg: 0 20px 48px rgba(42,31,24,0.16), 0 6px 16px rgba(42,31,24,0.08);

  --ease-out: cubic-bezier(.16,1,.3,1);
  --ease-spring: cubic-bezier(.34,1.56,.64,1);
  --dur-fast: 150ms;
  --dur-base: 250ms;
  --dur-slow: 450ms;

  --header-h: 76px;
  --container-w: 1200px;
}

/* ==========================================================================
   Reset & base
   ========================================================================== */
*, *::before, *::after{ box-sizing: border-box; }
html{ scroll-behavior: smooth; }
body{
  margin: 0;
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  color: var(--text);
  background: var(--cream);
  -webkit-font-smoothing: antialiased;
}
img{ max-width: 100%; display: block; }
a{ color: inherit; text-decoration: none; }
ul, ol{ margin: 0; padding: 0; list-style: none; }
h1,h2,h3,h4{ font-family: var(--font-display); font-weight: 600; line-height: 1.15; margin: 0; color: var(--espresso); text-wrap: balance; }
p{ margin: 0; }
button{ font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
input, textarea, select{ font: inherit; color: inherit; }
svg.icon{ display: inline-block; vertical-align: middle; flex-shrink: 0; }

.container{
  max-width: var(--container-w);
  margin-inline: auto;
  /* max() rather than a plain value so a notched phone in landscape keeps
     its text clear of the rounded corner / camera cutout. On any display
     without insets env() resolves to 0px, so this is exactly --space-5. */
  padding-left: max(var(--space-5), env(safe-area-inset-left));
  padding-right: max(var(--space-5), env(safe-area-inset-right));
}

.skip-link{
  position: absolute; left: 0; top: -48px;
  background: var(--espresso); color: var(--white);
  padding: var(--space-3) var(--space-5);
  z-index: 1000; border-radius: 0 0 var(--radius-sm) 0;
  transition: top var(--dur-base) var(--ease-out);
}
.skip-link:focus{ top: 0; }

:focus-visible{
  outline: 2.5px solid var(--bronze);
  outline-offset: 2px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior: auto; }
  *, *::before, *::after{
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==========================================================================
   Buttons
   ========================================================================== */
.btn{
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  padding: 14px 28px;
  border-radius: var(--radius-pill);
  font-weight: 600;
  font-size: 15px;
  white-space: nowrap;
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.btn:active{ transform: translateY(1px) scale(0.98); }
.btn-sm{ padding: 10px 20px; font-size: 14px; }
.btn-lg{ padding: 16px 32px; font-size: 16px; }

.btn-primary{
  background: var(--espresso);
  color: var(--cream);
  box-shadow: var(--shadow-sm);
}
.btn-primary:hover{ background: var(--espresso-700); box-shadow: var(--shadow-md); transform: translateY(-2px); }

.btn-ghost{
  background: transparent;
  color: var(--espresso);
  border: 1.5px solid var(--tan-200);
}
.btn-ghost:hover{ background: var(--cream-alt); border-color: var(--tan); transform: translateY(-2px); }

.btn-invert{
  background: var(--cream);
  color: var(--espresso);
}
.btn-invert:hover{ background: var(--white); transform: translateY(-2px); box-shadow: var(--shadow-md); }

/* ==========================================================================
   Header
   ========================================================================== */
.site-header{
  position: sticky; top: 0; z-index: 100;
  height: var(--header-h);
  display: flex; align-items: center;
  background: rgba(251,243,234,0.85);
  backdrop-filter: blur(10px) saturate(1.1);
  -webkit-backdrop-filter: blur(10px) saturate(1.1);
  border-bottom: 1px solid transparent;
  transition: box-shadow var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out), height var(--dur-base) var(--ease-out);
}
.site-header.is-scrolled{
  box-shadow: var(--shadow-sm);
  border-bottom-color: rgba(176,138,99,0.25);
}
.header-inner{
  width: 100%;
  /* Unlike the page-content .container, the header isn't capped at 1200px
     — but full edge-to-edge turned out to feel too spread out. This inset
     sits 25% of the way back from the true edge toward where the old
     1200px-centered layout would have placed things, and scales with the
     viewport instead of using a fixed max-width. */
  max-width: none;
  padding-left: max(var(--space-5), calc(12.5vw - 132px), env(safe-area-inset-left));
  padding-right: max(var(--space-5), calc(12.5vw - 132px), env(safe-area-inset-right));
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-5);
}
.brand{ display: inline-flex; align-items: center; gap: var(--space-3); }
.brand-mark{ border-radius: 10px; }
.brand-name{
  font-family: var(--font-display); font-weight: 600; font-size: 19px;
  color: var(--espresso); letter-spacing: 0.01em;
}
.brand-name span{ display: block; font-size: 11px; font-weight: 500; letter-spacing: 0.18em; color: var(--bronze); text-transform: uppercase; margin-top: -2px; }

.main-nav ul{ display: flex; gap: var(--space-6); }
.main-nav a{
  font-size: 15px; font-weight: 500; color: var(--text-muted);
  position: relative; padding: 6px 0;
  transition: color var(--dur-fast) var(--ease-out);
}
.main-nav a::after{
  content: ''; position: absolute; left: 0; right: 100%; bottom: 0; height: 2px;
  background: var(--bronze); border-radius: 2px;
  transition: right var(--dur-base) var(--ease-out);
}
.main-nav a:hover{ color: var(--espresso); }
.main-nav a:hover::after{ right: 0; }
.main-nav a[aria-current="page"]{ color: var(--espresso); }
.main-nav a[aria-current="page"]::after{ right: 0; }

/* --- "Diensten" submenu ---
   The parent stays a real link to the overview page; the chevron is a
   separate button so the two actions never fight each other. On desktop the
   panel opens on hover/focus and the button is hidden (pointer users never
   need it); at the hamburger breakpoint the nav becomes an off-canvas panel,
   where hover means nothing, so the button becomes the way in and the
   submenu expands inline instead. */
.nav-has-sub{ position: relative; }
.nav-sub a{ white-space: nowrap; }
/* The sliding underline belongs to the top-level items only — inside the
   panel it would animate across every row on hover. */
.nav-sub a::after{ display: none; }

@media (min-width: 1251px){
  .nav-sub-toggle{ display: none; }
  /* Scoped with .main-nav so it outranks `.main-nav ul` above, whose
     32px gap is meant for the spaced-out top-level row — inherited here it
     pushed the five services more than 100px apart. */
  .main-nav .nav-sub{
    position: absolute;
    top: 100%;
    left: 0;
    margin-top: 10px;
    min-width: 216px;
    padding: var(--space-2);
    display: flex;
    flex-direction: column;
    gap: 1px;
    background: var(--cream);
    border: 1px solid var(--tan-200);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-6px);
    transition: opacity var(--dur-base) var(--ease-out),
                transform var(--dur-base) var(--ease-out),
                visibility var(--dur-base);
  }
  /* Bridges the 10px gap above the panel, so moving the pointer from the
     link down into the menu doesn't cross un-hovered space and close it. */
  .nav-sub::before{
    content: '';
    position: absolute;
    left: 0; right: 0; top: -10px;
    height: 10px;
  }
  .nav-has-sub:hover .nav-sub,
  .nav-has-sub:focus-within .nav-sub{
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
  }
  .nav-sub a{
    display: block;
    padding: 5px var(--space-3);
    border-radius: var(--radius-sm);
    font-size: 14.5px;
    line-height: 1.4;
    transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
  }
  .nav-sub a:hover{ background: var(--cream-alt); color: var(--espresso); }
}

.header-actions{ display: flex; align-items: center; gap: var(--space-4); }
.header-phone{
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-weight: 600; font-size: 14.5px; color: var(--espresso);
  white-space: nowrap;
  flex-shrink: 0;
}
.header-phone .icon{ color: var(--bronze); }

.nav-toggle{
  display: none; padding: 8px; border-radius: var(--radius-sm);
  color: var(--espresso);
}
.nav-toggle .icon-close{ display: none; }
.nav-toggle[aria-expanded="true"] .icon-open{ display: none; }
.nav-toggle[aria-expanded="true"] .icon-close{ display: block; }

/* ==========================================================================
   Hero
   ========================================================================== */
/* .hero-screen groups .hero + .trust-strip and pins them to exactly one
   screen's worth of height below the header. Flexbox — not a guessed pixel
   reservation — is what makes this robust: .trust-strip (flex: none) takes
   whatever its real rendered height turns out to be (one row, two on
   narrow screens, different font metrics, whatever), and .hero (flex: 1)
   absorbs precisely what's left, so the pair always sums to exactly
   100vh - header height, no matter what. */
.hero-screen{
  /* A hard cap, not a floor: this is what guarantees no scroll, on every
     browser. (An earlier min-height version left sizing to each browser's
     own — inconsistent — handling of `min-height: auto` on a nested flex
     item, which is a known cross-browser rough edge.) The extra 20px is
     deliberate slack — an exact 100vh fit left zero margin for browser
     chrome/scrollbar/rounding differences, so the strip could still end up
     a hair below the fold. This pulls it just clear of that without
     leaving a large empty gap underneath. */
  height: calc(100vh - var(--header-h) - 20px);
  height: calc(100dvh - var(--header-h) - 20px);
  display: flex;
  flex-direction: column;
}
.hero{
  position: relative;
  flex: 1 1 auto;
  min-height: 0; /* let this shrink to fit the space left after .trust-strip, instead of forcing .hero-screen taller than the cap above */
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: var(--space-6) var(--space-5);
  overflow: clip;
  background:
    radial-gradient(1100px 520px at 82% -10%, rgba(176,138,99,0.22), transparent 60%),
    linear-gradient(180deg, var(--cream) 0%, var(--cream) 100%);
}
.hero-texture{
  position: absolute; inset: 0; pointer-events: none; z-index: -1;
  opacity: 0.5;
  background-image:
    radial-gradient(1px 1px at 10% 20%, rgba(107,74,54,0.18) 1px, transparent 1px),
    radial-gradient(1px 1px at 30% 70%, rgba(107,74,54,0.14) 1px, transparent 1px),
    radial-gradient(1.5px 1.5px at 60% 30%, rgba(107,74,54,0.16) 1px, transparent 1px),
    radial-gradient(1px 1px at 80% 60%, rgba(107,74,54,0.14) 1px, transparent 1px),
    radial-gradient(1.5px 1.5px at 90% 85%, rgba(107,74,54,0.14) 1px, transparent 1px);
  background-size: 260px 260px;
}
/* --- Hero background video ---
   Hidden by default (and whenever prefers-reduced-motion is set); only
   shown once `.hero.has-video` is confirmed — see the media-query block
   below. This keeps the original static cream hero as the true fallback
   for reduced-motion users and for autoplay failures (main.js removes
   `has-video` on a play() rejection or an `error` event). */
.hero-video, .hero-overlay{ display: none; }
.hero-video{
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  pointer-events: none;
  /* No bottom border: the .trust-strip section sits flush underneath with
     no gap, so its dark espresso band reads as the video's bottom frame.
     No left/right border either — only the top edge keeps the cream frame. */
  border-top: 15px solid var(--cream);
}
.hero-overlay{
  position: absolute; z-index: 1;
  /* Matches .hero-video's border inset exactly, so the cream frame reads
     as clean cream instead of getting darkened by the overlay too. */
  inset: 15px 0 0 0;
  /* espresso brand color at 55% — within the 45–60% contrast requirement */
  background: rgba(42, 31, 24, 0.55);
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference){
  .hero.has-video .hero-video,
  .hero.has-video .hero-overlay{
    display: block;
  }
  /* Initial page-load reveal: main.js adds `.is-visible` once the video
     starts playing, and this transition fades it in instead of a hard cut. */
  .hero.has-video .hero-video{
    opacity: 0;
    transition: opacity 1.2s ease;
  }
  .hero.has-video .hero-video.is-visible{
    opacity: 1;
  }

  /* Text/button contrast: swap the light-hero (dark-on-cream) palette for
     the dark-hero (light-on-overlay) tokens already used elsewhere on the
     site (trust strip, CTA banner, footer) — same tokens, different context. */
  .hero.has-video .eyebrow{ color: var(--tan-200); }
  .hero.has-video .hero-title{ color: var(--cream); }
  .hero.has-video .hero-title em{ color: var(--tan-200); }
  .hero.has-video .hero-sub{ color: var(--text-on-dark-muted); }
  .hero.has-video .stat dt{ color: var(--cream); }
  .hero.has-video .stat dd{ color: var(--text-on-dark-muted); }
  .hero.has-video .btn-ghost{
    color: var(--cream);
    border-color: rgba(243,231,216,0.4);
  }
  .hero.has-video .btn-ghost:hover{
    background: rgba(243,231,216,0.1);
    border-color: var(--text-on-dark);
  }
}

.hero-inner{ position: relative; z-index: 2; max-width: 820px; }
.eyebrow{
  font-size: 13.5px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--bronze); margin-bottom: var(--space-4);
}
.hero-title{
  font-size: clamp(2.4rem, 5vw, 4rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  max-width: 16ch;
  margin-bottom: var(--space-5);
}
.hero-title em{ font-style: italic; color: var(--bronze); }
.hero-sub{
  font-size: 18px; color: var(--text-muted); max-width: 56ch;
  margin-bottom: var(--space-6);
}
.hero-actions{ display: flex; flex-wrap: wrap; gap: var(--space-4); margin-bottom: var(--space-6); }

.hero-stats{
  display: grid; grid-template-columns: repeat(4, auto); gap: var(--space-7);
  /* No rule across the top — the spacing alone separates the stats from the
     buttons above them. */
  padding-top: var(--space-6);
}
.stat dt{ font-family: var(--font-display); font-size: 32px; font-weight: 600; color: var(--espresso); display: flex; align-items: baseline; gap: 2px; }
.stat dd{ font-size: 13.5px; color: var(--text-muted); margin-top: 2px; }

/* ==========================================================================
   Trust strip
   ========================================================================== */
.trust-strip{
  flex: none;
  background: var(--espresso);
  color: var(--text-on-dark);
  padding-block: var(--space-5);
}
.trust-strip-inner{
  display: flex; flex-wrap: wrap; gap: var(--space-6) var(--space-8);
  justify-content: center;
}
.trust-item{
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-size: 14px; font-weight: 500; color: var(--text-on-dark-muted);
}
.trust-item .icon{ color: var(--tan); }

/* ==========================================================================
   Sections (shared)
   ========================================================================== */
.section{ padding-top: var(--space-9); padding-bottom: calc(var(--space-9) + var(--space-3)); scroll-margin-top: var(--header-h); }
#contact, #diensten, #waarom-ons, #werkwijze, #portfolio, #reviews{ scroll-margin-top: var(--header-h); }
.section-alt{ background: var(--cream-alt); }
.section-head{ max-width: 640px; margin-bottom: var(--space-8); }
.section-head .eyebrow{ margin-bottom: var(--space-3); }
.section-head h2{ font-size: clamp(1.75rem, 3.4vw, 2.5rem); letter-spacing: -0.01em; margin-bottom: var(--space-4); }
.section-lead{ color: var(--text-muted); font-size: 17px; }

.grid{ display: grid; gap: var(--space-5); }
.grid-2{ grid-template-columns: repeat(2, 1fr); }
.grid-3{ grid-template-columns: repeat(3, 1fr); }
.grid-4{ grid-template-columns: repeat(4, 1fr); }

/* Portfolio carousel — 9 photos (a .grid-3-shaped page) at a time, paged
   with the prev/next buttons below. See assets/js/main.js for the paging
   logic; every page's markup already exists in the DOM (just [hidden]),
   so this degrades to a single static 3x3 grid with JS disabled. */
.portfolio-page{ display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-5); }
.portfolio-page[hidden]{ display: none; }
.portfolio-nav{ display: flex; align-items: center; justify-content: center; gap: var(--space-4); margin-top: var(--space-7); }
.portfolio-nav-btn{
  display: flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border-radius: 50%; flex-shrink: 0;
  background: var(--white); color: var(--espresso); box-shadow: var(--shadow-sm);
  transition: background-color var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out), opacity var(--dur-base) var(--ease-out);
}
.portfolio-nav-btn:hover:not(:disabled){ background: var(--cream-alt); transform: translateY(-2px); }
.portfolio-nav-btn:disabled{ opacity: 0.35; cursor: not-allowed; }
.portfolio-page-indicator{ font-size: 13.5px; font-weight: 600; color: var(--text-muted); min-width: 52px; text-align: center; }

.card{
  background: var(--white);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}

/* Services */
.service-card:hover{ transform: translateY(-6px); box-shadow: var(--shadow-md); }
.service-icon{
  display: inline-flex; align-items: center; justify-content: center;
  width: 52px; height: 52px; border-radius: var(--radius-sm);
  background: var(--cream-alt); color: var(--bronze);
  margin-bottom: var(--space-4);
  transition: transform var(--dur-base) var(--ease-spring), background-color var(--dur-base) var(--ease-out);
}
.service-card:hover .service-icon{ background: var(--bronze); color: var(--cream); transform: scale(1.08) rotate(-4deg); }
.service-card h3{ font-size: 19px; margin-bottom: var(--space-2); }
.service-card p{ color: var(--text-muted); font-size: 15px; }
.service-card .service-desc{ margin-bottom: var(--space-4); }
.service-list{ margin-bottom: var(--space-4); }
.service-list li{
  display: flex; align-items: flex-start; gap: 8px;
  font-size: 14px; color: var(--text-muted); padding-block: 4px;
}
.service-list .icon{ color: var(--bronze); margin-top: 3px; flex-shrink: 0; }
.service-meta{ display: flex; flex-direction: column; gap: 4px; padding-top: var(--space-3); border-top: 1px solid var(--cream-alt); font-size: 13px; color: var(--text-muted); }
.service-card .link-more{ margin-top: var(--space-4); }
.service-meta strong{ color: var(--espresso); font-weight: 600; }

.compare-card h3{ display: flex; align-items: center; gap: var(--space-3); font-size: 19px; margin-bottom: var(--space-4); }
.compare-card h3 .icon{ color: var(--bronze); }
.compare-list li{ display: flex; align-items: flex-start; gap: 10px; font-size: 15px; color: var(--text-muted); padding-block: 7px; }
.compare-list .icon{ color: var(--bronze); margin-top: 3px; flex-shrink: 0; }

/* USPs */
.usp{ text-align: left; }
.usp-icon{
  display: inline-flex; align-items: center; justify-content: center;
  width: 56px; height: 56px; border-radius: 50%;
  background: var(--white); color: var(--bronze);
  box-shadow: var(--shadow-sm);
  margin-bottom: var(--space-4);
}
.usp h3{ font-size: 18px; margin-bottom: var(--space-2); }
.usp p{ color: var(--text-muted); font-size: 14.5px; }

/* Process — two-column row of icon + text tiles */
.process{
  display: grid; grid-template-columns: repeat(2, 1fr);
  column-gap: var(--space-7); row-gap: var(--space-7);
}
.process-step{ display: flex; align-items: flex-start; gap: var(--space-5); }
.process-icon{
  flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  width: 60px; height: 60px; border-radius: 50%;
  background: var(--white); color: var(--bronze);
  box-shadow: var(--shadow-sm);
}
.process-num{
  font-family: var(--font-display); font-weight: 600; font-size: 13px;
  color: var(--bronze); letter-spacing: 0.06em; text-transform: uppercase;
  display: block; margin-bottom: var(--space-1);
}
.process-body h3{ font-size: 18px; margin-bottom: var(--space-2); }
.process-body p{ color: var(--text-muted); font-size: 14.5px; }

@media (max-width: 760px){
  .process{ grid-template-columns: 1fr; row-gap: var(--space-6); }
}

/* Portfolio */
.portfolio-item{ margin: 0; border-radius: var(--radius-md); overflow: hidden; box-shadow: var(--shadow-sm); background: var(--white); transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out); }
.portfolio-item:hover{ transform: translateY(-6px); box-shadow: var(--shadow-md); }
.portfolio-media{
  aspect-ratio: 4/3;
  position: relative; overflow: hidden;
  background: var(--cream-alt);
}
.portfolio-media img{
  width: 100%; height: 100%; object-fit: cover; object-position: center;
  display: block;
  transition: transform var(--dur-slow) var(--ease-out);
}
.portfolio-item:hover .portfolio-media img{ transform: scale(1.06); }

.stars{ display: flex; justify-content: center; gap: 3px; color: var(--bronze); margin-bottom: var(--space-4); }

/* ==========================================================================
   Review marquee — reused on the homepage teaser and the full reviews
   archive alike: every card drifts past in one continuous row. No-JS/
   static fallback: a plain horizontally-scrollable strip of
   .werkspot-card. When main.js runs (and the visitor hasn't asked for
   reduced motion), it clones the card set enough times to comfortably
   outrun the visible width (so a short 3-card teaser never runs dry
   mid-loop the way one duplication of it would) and adds .is-animating,
   which is what actually sets the track adrift on a seamless, pausable
   loop. Both --marquee-distance (one set's width, in px) and
   --marquee-duration are set per-instance by JS, so rows of any length
   drift at the same visual speed and loop back exactly on a repeat.
   ========================================================================== */
.review-marquee{
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, black 6%, black 94%, transparent);
          mask-image: linear-gradient(to right, transparent, black 6%, black 94%, transparent);
}
.review-marquee-track{
  display: flex;
  gap: var(--space-4);
  width: max-content;
  padding-block: var(--space-2) var(--space-5);
  padding-inline: var(--space-5);
}
.review-marquee.is-animating{ overflow-x: hidden; }
.review-marquee.is-animating .review-marquee-track{
  animation: marquee-drift var(--marquee-duration, 75s) linear infinite;
}
/* While a row is drifting it ignores the pointer entirely, so a click can't
   select text, drag an image, or move focus into the row. That focus was the
   real culprit behind "clicking stops the carousel": the row carried
   tabindex, so a click landed focus inside it and :focus-within froze the
   animation until the visitor happened to click somewhere else.
   Scoped to .is-animating on purpose — without JS (or under
   prefers-reduced-motion) the row is a static, horizontally scrollable strip
   and must stay grabbable, and that is also the pause mechanism for anyone
   who has asked for reduced motion.
   The reviews page's arrow button sits outside .review-marquee, so it keeps
   working and remains the way to step through reviews by hand. */
.review-marquee.is-animating{ pointer-events: none; }
@keyframes marquee-drift{
  from{ transform: translateX(0); }
  to{ transform: translateX(calc(-1 * var(--marquee-distance, 50%))); }
}
@media (prefers-reduced-motion: reduce){
  .review-marquee.is-animating .review-marquee-track{ animation: none; }
}

/* Optional click-to-advance arrow for a marquee row (wired up by the
   [data-marquee-next] block in main.js). Deliberately sits outside
   .review-marquee rather than inside it: that element is overflow-hidden
   and edge-masked, so a button placed within it would get clipped and
   faded out exactly where this one needs to be legible. */
.marquee-wrap{ position: relative; }
.marquee-arrow{
  position: absolute;
  right: var(--space-5);
  bottom: 0;
  z-index: 2;
  display: flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border-radius: 50%; flex-shrink: 0;
  background: var(--white); color: var(--espresso); box-shadow: var(--shadow-md);
  transition: background-color var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.marquee-arrow:hover{ background: var(--cream-alt); transform: translateY(-2px); }
@media (max-width: 640px){
  .marquee-arrow{ right: var(--space-4); width: 38px; height: 38px; }
}

/* Photo marquee — same drift mechanic as .review-marquee above (driven by
   the same [data-marquee] JS), sized for project photos instead of cards. */
.photo-marquee-track{ gap: var(--space-3); } /* tighter than the shared 16px card gap — photos read better close together */
.photo-marquee-item{
  flex-shrink: 0; width: 420px; aspect-ratio: 4/3; /* 280px + 50% */
  border-radius: var(--radius-md); overflow: hidden; box-shadow: var(--shadow-sm);
  background: var(--cream-alt);
}
.photo-marquee-item img{ width: 100%; height: 100%; object-fit: cover; display: block; }
@media (max-width: 640px){
  /* 220px + 50% is 330px, wider than a 320px phone — at that point no whole
     photo is ever on screen and the row stops reading as a carousel. The cap
     keeps the full +50% wherever the screen can hold it, and only the
     narrowest handsets fall back to a screen-relative width. */
  .photo-marquee-item{ width: min(330px, 82vw); }
}

/* ==========================================================================
   CTA banner
   ========================================================================== */
.cta-banner{ background: var(--espresso); color: var(--text-on-dark); padding-block: var(--space-8); }
.cta-banner-inner{ text-align: center; max-width: 640px; margin-inline: auto; }
.cta-banner h2{ color: var(--cream); font-size: clamp(1.75rem, 3.4vw, 2.4rem); margin-bottom: var(--space-3); }
.cta-banner p{ color: var(--text-on-dark-muted); margin-bottom: var(--space-6); font-size: 16.5px; }

/* ==========================================================================
   Approach card — dark rounded panel used on service detail pages
   ("Hoe pakken wij dit aan?"): heading on one side, short process
   summary + button on the other.
   ========================================================================== */
.approach-card{
  background: var(--espresso);
  border-radius: var(--radius-lg);
  padding: var(--space-8) var(--space-7);
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: var(--space-7);
  align-items: center;
}
.approach-card h2{ color: var(--cream); font-size: clamp(1.75rem, 3.2vw, 2.3rem); line-height: 1.15; }
.approach-card p{ color: var(--text-on-dark-muted); margin-bottom: var(--space-4); font-size: 15.5px; line-height: 1.65; }
.approach-card p:last-of-type{ margin-bottom: var(--space-6); }

.btn-outline-invert{
  background: transparent;
  color: var(--cream);
  border: 1.5px solid rgba(243,231,216,0.35);
}
.btn-outline-invert:hover{ background: rgba(243,231,216,0.08); border-color: var(--cream); transform: translateY(-2px); }

/* ==========================================================================
   Contact
   ========================================================================== */
.contact-grid{ display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--space-8); align-items: start; }
.contact-form{ background: var(--white); padding: var(--space-7); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); }
.form-row{ display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-5); }
.form-field{ margin-bottom: var(--space-5); }
.form-field label{ display: block; font-size: 14px; font-weight: 600; color: var(--espresso); margin-bottom: var(--space-2); }
.form-field label span{ color: var(--danger); }
.form-field input, .form-field textarea, .form-field select{
  width: 100%; padding: 12px 14px; border-radius: var(--radius-sm);
  border: 1.5px solid var(--tan-200); background: var(--cream);
  transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.form-field input:focus, .form-field textarea:focus, .form-field select:focus{
  border-color: var(--bronze); box-shadow: 0 0 0 4px rgba(107,74,54,0.12); outline: none;
}
.form-field textarea{ resize: vertical; min-height: 100px; }
.field-error{ display: none; color: var(--danger); font-size: 13px; margin-top: 6px; }
.form-field.has-error input, .form-field.has-error textarea, .form-field.has-error select{ border-color: var(--danger); }
.form-field.has-error .field-error{ display: block; }

.contact-form .btn{ width: 100%; }
.form-success{
  display: none; align-items: center; gap: var(--space-2);
  margin-top: var(--space-4); padding: 12px 16px; border-radius: var(--radius-sm);
  background: rgba(47,125,90,0.12); color: var(--success); font-size: 14.5px; font-weight: 600;
}
.form-success.is-visible{ display: flex; }
.form-note{ display: none; }

.contact-info{ display: flex; flex-direction: column; gap: var(--space-5); }
.info-card{ background: var(--white); border-radius: var(--radius-lg); padding: var(--space-6); box-shadow: var(--shadow-sm); }
.info-card h3{ font-size: 18px; margin-bottom: var(--space-4); }
.info-list li{ display: flex; align-items: center; gap: var(--space-3); padding-block: var(--space-2); font-size: 15px; }
.info-list .icon{ color: var(--bronze); }
.info-list a:hover{ color: var(--bronze); }

.info-map{
  background: linear-gradient(135deg, var(--bronze), var(--espresso));
  color: var(--cream); border-radius: var(--radius-lg);
  min-height: 160px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-2);
  font-size: 14px; font-weight: 600; text-align: center; padding: var(--space-5);
}

/* ==========================================================================
   Footer
   ========================================================================== */
.site-footer{ background: var(--espresso); color: var(--text-on-dark); }
.footer-inner{
  padding-block: var(--space-8);
  display: grid; grid-template-columns: 1.3fr 1fr 1fr 1fr; gap: var(--space-7);
}
.footer-brand .brand-name{ color: var(--cream); }
.footer-brand .brand-name span{ color: var(--tan); }
.footer-brand p{ color: var(--text-on-dark-muted); font-size: 14.5px; margin-block: var(--space-4); max-width: 34ch; }
.social-links{ display: flex; gap: var(--space-3); }
.social-links a{
  width: 38px; height: 38px; border-radius: 50%; background: rgba(243,231,216,0.08);
  display: flex; align-items: center; justify-content: center; color: var(--text-on-dark);
  transition: background-color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.social-links a:hover{ background: var(--bronze); transform: translateY(-3px); }

.footer-nav h3, .footer-contact h3{ font-size: 14px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--tan); margin-bottom: var(--space-4); }
.footer-nav li, .footer-contact li{ padding-block: 6px; font-size: 14.5px; color: var(--text-on-dark-muted); }
.footer-nav a:hover, .footer-contact a:hover{ color: var(--cream); }

.footer-bottom{ border-top: 1px solid rgba(243,231,216,0.12); }
.footer-bottom-inner{
  padding-block: var(--space-5);
  display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: var(--space-3);
  font-size: 13.5px; color: var(--text-on-dark-muted);
}
.footer-legal{ display: flex; gap: var(--space-5); }
.footer-legal a:hover{ color: var(--cream); }

/* ==========================================================================
   Fixed corner actions (WhatsApp + back to top)
   ========================================================================== */
.fixed-actions{
  position: fixed; right: var(--space-5); bottom: var(--space-5); z-index: 90;
  display: flex; flex-direction: column; align-items: center; gap: var(--space-3);
}
/* The cookie banner sits bottom-left on desktop, clear of these buttons, but
   goes full-width on narrow screens where it would otherwise cover them.
   assets/js/cookie-consent.js puts .psw-cc-open on <html> only while the
   banner is actually on screen, so this lift is temporary. */
@media (max-width: 640px){
  .psw-cc-open .fixed-actions{ bottom: calc(var(--space-5) + 168px); }
}

.whatsapp-float{
  width: 46px; height: 46px; border-radius: 50%;
  background: #25D366; color: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-md);
  transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
.whatsapp-float:hover{ transform: translateY(-3px) scale(1.04); box-shadow: var(--shadow-lg); }

.back-to-top{
  width: 46px; height: 46px; border-radius: 50%;
  background: var(--espresso); color: var(--cream);
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-md);
  opacity: 0; transform: translateY(12px) scale(0.9); pointer-events: none;
  transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.back-to-top.is-visible{ opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
.back-to-top:hover{ background: var(--espresso-700); transform: translateY(-3px) scale(1.04); }

/* ==========================================================================
   Page hero (inner pages)
   ========================================================================== */
.page-hero{
  position: relative; overflow: clip;
  padding-block: var(--space-8) var(--space-7);
  background:
    radial-gradient(900px 420px at 85% -20%, rgba(176,138,99,0.22), transparent 60%),
    var(--cream);
}
.page-hero-inner{ position: relative; z-index: 1; max-width: 760px; }
.breadcrumb{ display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--text-muted); margin-bottom: var(--space-4); }
.breadcrumb a:hover{ color: var(--bronze); }
.page-hero h1{ font-size: clamp(2rem, 4.2vw, 3.2rem); margin-bottom: var(--space-4); }
.page-hero-lead{ font-size: 17.5px; color: var(--text-muted); max-width: 60ch; }

/* Blog heroes carry only the H1 -- no breadcrumb, no lead. Drop the H1s
   dangling bottom margin and pull the following section up, so the title
   and the banner below it read as one block instead of two. */
.page-hero--tight{ padding-block-end: var(--space-5); }
.page-hero--tight h1{ margin-bottom: 0; }
.page-hero--tight + .section{ padding-top: var(--space-6); }

/* ==========================================================================
   Teasers (Home page section previews)
   ========================================================================== */
.teaser-head{ display: flex; align-items: flex-end; justify-content: space-between; gap: var(--space-5); margin-bottom: var(--space-7); flex-wrap: wrap; }
.teaser-head .section-head{ margin-bottom: 0; }
.link-more{
  display: inline-flex; align-items: center; gap: 6px;
  font-weight: 600; font-size: 15px; color: var(--bronze);
  white-space: nowrap; padding-bottom: 2px;
  transition: gap var(--dur-fast) var(--ease-out);
}
.link-more:hover{ gap: 10px; color: var(--espresso-700); }
.link-more .icon{ transition: transform var(--dur-fast) var(--ease-out); }

/* ==========================================================================
   FAQ (native details/summary — accessible, no JS needed)
   ========================================================================== */
.faq-list{ max-width: 760px; }
.faq-item{
  border-bottom: 1px solid var(--tan-200);
  padding-block: var(--space-5);
}
.faq-item summary{
  cursor: pointer; list-style: none;
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
  font-family: var(--font-display); font-size: 18px; font-weight: 600; color: var(--espresso);
}
.faq-item summary::-webkit-details-marker{ display: none; }
.faq-item summary .faq-plus{
  flex-shrink: 0; width: 28px; height: 28px; border-radius: 50%;
  background: var(--cream-alt); color: var(--bronze);
  display: flex; align-items: center; justify-content: center;
  transition: transform var(--dur-base) var(--ease-out), background-color var(--dur-base) var(--ease-out);
}
.faq-item[open] summary .faq-plus{ transform: rotate(45deg); background: var(--bronze); color: var(--cream); }
.faq-plus .icon{ transform: rotate(90deg); }
.faq-item p{ color: var(--text-muted); margin-top: var(--space-3); max-width: 65ch; font-size: 15.5px; }
.faq-item[open] p{ animation: faq-reveal var(--dur-base) var(--ease-out); }
@keyframes faq-reveal{ from{ opacity: 0; transform: translateY(-4px); } to{ opacity: 1; transform: translateY(0); } }

/* ==========================================================================
   Story / About layout
   ========================================================================== */
.story-grid{ display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-8); align-items: center; }
.story-media{
  aspect-ratio: 4/3; border-radius: var(--radius-lg); overflow: hidden;
  background: linear-gradient(135deg, var(--bronze), var(--espresso));
  display: flex; align-items: center; justify-content: center; color: var(--cream);
  position: relative;
}
.story-media::before{
  content:''; position:absolute; inset:0;
  background-image: radial-gradient(1px 1px at 20% 30%, rgba(255,255,255,0.3) 1px, transparent 1px), radial-gradient(1px 1px at 70% 60%, rgba(255,255,255,0.25) 1px, transparent 1px), radial-gradient(1px 1px at 40% 80%, rgba(255,255,255,0.2) 1px, transparent 1px);
  background-size: 90px 90px;
}
.story-media:has(img)::before{ display: none; }
.story-media img{ width: 100%; height: 100%; object-fit: cover; display: block; }
.story-text h2{ margin-bottom: var(--space-4); font-size: clamp(1.6rem, 3vw, 2.2rem); }
.story-text p{ color: var(--text-muted); margin-bottom: var(--space-4); font-size: 16px; }
.story-text p:last-child{ margin-bottom: 0; }
.story-text .btn{ margin-top: var(--space-5); }

.teaser-more{ margin-top: var(--space-7); text-align: center; }

/* ==========================================================================
   Team
   ========================================================================== */
.team-card{ text-align: center; }
.team-avatar{
  width: 96px; height: 96px; border-radius: var(--radius-lg); margin-inline: auto;
  background: linear-gradient(135deg, var(--tan), var(--bronze-600));
  display: flex; align-items: center; justify-content: center; color: var(--cream);
  margin-bottom: var(--space-4);
}
.team-card h3{ font-size: 17px; margin-bottom: 2px; }
.team-role{ font-size: 13.5px; color: var(--bronze); font-weight: 600; margin-bottom: var(--space-2); }
.team-card p{ color: var(--text-muted); font-size: 14.5px; }

/* ==========================================================================
   Certifications strip
   ========================================================================== */
.cert-grid{ display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-6); }
.cert-item{
  display: flex; align-items: flex-start; text-align: left; gap: var(--space-4);
  padding-top: var(--space-5); border-top: 2px solid var(--tan-200);
}
.cert-item .icon{ color: var(--bronze); width: 26px; height: 26px; flex-shrink: 0; margin-top: 2px; }
.cert-item h3{ font-size: 15.5px; margin-bottom: 2px; }
.cert-item p{ font-size: 13.5px; color: var(--text-muted); }

/* ==========================================================================
   Rating summary (Reviews page)
   ========================================================================== */
.rating-summary{
  display: flex; align-items: center; gap: var(--space-7);
  background: var(--white); border-radius: var(--radius-lg); padding: var(--space-7);
  box-shadow: var(--shadow-sm); flex-wrap: wrap;
  /* Sits directly below the review carousel, whose arrow button is anchored
     to the bottom of its own wrapper — this keeps the two clearly apart
     rather than letting the card crowd up under the drifting row. */
  margin-top: var(--space-8);
  margin-bottom: var(--space-8);
}
.rating-score{ text-align: center; }
.rating-score .num{ font-family: var(--font-display); font-size: 56px; font-weight: 600; color: var(--espresso); line-height: 1; }
.rating-score .stars{ margin-block: var(--space-2) 4px; justify-content: center; }
.rating-score .count{ font-size: 13.5px; color: var(--text-muted); }
.rating-bars{ flex: 1; min-width: 220px; display: flex; flex-direction: column; gap: 8px; }
.rating-bar-row{ display: grid; grid-template-columns: 56px 1fr 34px; align-items: center; gap: var(--space-3); font-size: 13.5px; color: var(--text-muted); }
.rating-bar-track{ height: 8px; border-radius: var(--radius-pill); background: var(--cream-alt); overflow: hidden; }
.rating-bar-fill{ height: 100%; background: var(--bronze); border-radius: var(--radius-pill); }

/* ==========================================================================
   Review grid (full list, non-carousel)
   ========================================================================== */
.review-card{ display: flex; flex-direction: column; gap: var(--space-3); }
.review-card .stars{ color: var(--bronze); display: flex; gap: 2px; }
.review-card p{ color: var(--text); font-size: 15px; line-height: 1.55; }
.review-meta{ display: flex; align-items: center; gap: var(--space-3); margin-top: auto; padding-top: var(--space-3); }
.review-avatar{
  width: 38px; height: 38px; border-radius: 50%; flex-shrink: 0;
  background: linear-gradient(135deg, var(--tan), var(--bronze-600));
}
.review-meta strong{ display: block; font-size: 14px; color: var(--espresso); }
.review-meta span{ font-size: 12.5px; color: var(--text-muted); }

/* ==========================================================================
   Werkspot review card — the card style used inside .review-marquee.
   Fixed-width rounded cards, soft shadow, star row and clamped quote,
   in our own cream/bronze palette.
   ========================================================================== */
.werkspot-card{
  flex: 0 0 280px;
  scroll-snap-align: start;
  display: flex; flex-direction: column; gap: var(--space-3);
  background: var(--white);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--space-5);
}
.werkspot-card .stars{ display: flex; gap: 2px; color: var(--bronze); }
.werkspot-card p{
  font-size: 14px; color: var(--text); line-height: 1.55;
  display: -webkit-box; -webkit-line-clamp: 7; -webkit-box-orient: vertical; overflow: hidden;
}
.werkspot-meta{ margin-top: auto; padding-top: var(--space-3); border-top: 1px solid var(--cream-alt); }
/* Some reviewers leave five stars without writing anything. Rather than an
   empty card, these show the job that was rated, in a quieter style so they
   never read as a customer quote. */
.werkspot-card--nocomment .werkspot-job{
  font-size: 13px;
  color: var(--text-muted);
  font-style: italic;
  -webkit-line-clamp: 4;
}
.werkspot-meta strong{ display: block; font-size: 13.5px; color: var(--espresso); }
.werkspot-meta span{ font-size: 12px; color: var(--text-muted); }

@media (max-width: 640px){
  .werkspot-card{ flex-basis: 240px; }
}

/* ==========================================================================
   Category cards ("Wat wil je laten doen?") — large photo tiles linking
   into the offerte flow, each labelled with a project scope.
   ========================================================================== */
.container-wide{ max-width: 1480px; }
.category-section{ padding-top: var(--space-2); } /* pulled up from the default .section spacing, sits closer to the 3D logo section above it */
.category-title{ text-align: center; max-width: 720px; margin: 0 auto var(--space-7); }
.category-grid{
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--space-5);
}
.category-card{
  position: relative;
  display: block;
  aspect-ratio: 3/4;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
.category-card:hover, .category-card:focus-visible{ transform: translateY(-4px); box-shadow: var(--shadow-md); }
.category-card img{
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-out);
}
.category-card:hover img, .category-card:focus-visible img{ transform: scale(1.06); }
.category-card::after{
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 45%, rgba(42,31,24,0.8) 100%);
}
.category-card span{
  position: absolute; left: var(--space-5); right: var(--space-5); bottom: var(--space-5);
  z-index: 1;
  color: var(--cream);
  font-family: var(--font-display); font-weight: 600; font-size: 22px; line-height: 1.2;
}

@media (max-width: 1024px){
  .category-grid{ grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 640px){
  .category-grid{ grid-template-columns: repeat(2, 1fr); }
}

/* ==========================================================================
   Scroll reveal
   ========================================================================== */
.reveal{
  opacity: 0;
  transform: translateY(22px);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
  transition-delay: calc(var(--d, 0) * 60ms);
}
.reveal.is-visible{ opacity: 1; transform: translateY(0); }

/* stagger children of grids automatically */
.grid .reveal:nth-child(1){ --d: 0; } .grid .reveal:nth-child(2){ --d: 1; } .grid .reveal:nth-child(3){ --d: 2; }
.grid .reveal:nth-child(4){ --d: 3; } .grid .reveal:nth-child(5){ --d: 4; } .grid .reveal:nth-child(6){ --d: 5; }
.process .reveal:nth-child(1){ --d: 0; } .process .reveal:nth-child(2){ --d: 1; } .process .reveal:nth-child(3){ --d: 2; } .process .reveal:nth-child(4){ --d: 3; }
.trust-strip-inner .reveal:nth-child(1){ --d: 0; } .trust-strip-inner .reveal:nth-child(2){ --d: 1; } .trust-strip-inner .reveal:nth-child(3){ --d: 2; } .trust-strip-inner .reveal:nth-child(4){ --d: 3; }

/* ==========================================================================
   Responsive
   ========================================================================== */
@media (max-width: 1024px){
  .grid-4{ grid-template-columns: repeat(2, 1fr); }
  .process{ grid-template-columns: repeat(2, 1fr); row-gap: var(--space-7); }
  .contact-grid{ grid-template-columns: 1fr; }
  .footer-inner{ grid-template-columns: 1fr 1fr 1fr; }
  .footer-brand{ grid-column: 1 / -1; }
  .story-grid{ grid-template-columns: 1fr; }
  .story-media{ aspect-ratio: 16/9; order: -1; }
  .cert-grid{ grid-template-columns: repeat(2, 1fr); }
  .approach-card{ grid-template-columns: 1fr; padding: var(--space-7) var(--space-5); }
}

/* Nav collapses to the hamburger menu earlier than the 1180px grid
   breakpoint below — the longer "Plan uw project in 2 minuten" button plus
   the 6th nav item ("Veelgestelde vragen") need close to 1250px to lay out
   in one row without wrapping, so this has its own, wider threshold. */
@media (max-width: 1250px){
  /* The header must not be a containing block at this breakpoint.
     backdrop-filter (like filter and transform) makes an element the
     containing block for its position:fixed descendants — and .main-nav is
     a child of the header. That quietly demoted the off-canvas panel from
     "fixed to the viewport" to "absolutely placed inside the header", so
     parking it at translateX(100%) pushed the *document* 269-320px wider
     than the screen: every page could be panned sideways into blank space
     on a phone. Dropping the blur here restores true viewport-fixing and
     the horizontal scroll goes with it. Desktop (>1250px) keeps the frosted
     header; below it the background is opaque anyway, so the only thing
     lost is a blur nobody can see behind a solid bar — and mobile gets a
     cheaper compositing path into the bargain.

     It also settles a visible mismatch: the translucent header let page
     content show through while the opaque cream menu panel sat directly
     below it, so with the menu open the two read as different surfaces.
     Both are now the same flat --cream, so an open menu reads as one
     solid block. */
  .site-header{
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: var(--cream);
  }

  .main-nav{
    position: fixed; inset: var(--header-h) 0 0 auto; width: min(320px, 84vw);
    background: var(--cream); box-shadow: var(--shadow-lg);
    padding: var(--space-6) var(--space-5);
    padding-right: max(var(--space-5), env(safe-area-inset-right));
    padding-bottom: max(var(--space-6), env(safe-area-inset-bottom));
    transform: translateX(100%);
    /* A closed panel is hidden outright, not merely parked off-screen.
       transform alone leaves all 12 links focusable and exposed to screen
       readers, so a keyboard user tabs straight into an invisible menu —
       and it leaves a real box outside the viewport that mobile browsers
       (iOS Safari in particular) will let you pan sideways to reach.
       visibility is a discrete property: it flips to visible instantly on
       open, and waits for the slide-out to finish on close. */
    visibility: hidden;
    /* visibility is discrete: given a plain duration it would flip at the
       halfway point, so the panel would pop into view mid-slide and vanish
       mid-slide-out. Delaying it by the full duration instead keeps the
       panel visible for the whole closing animation... */
    transition: transform var(--dur-base) var(--ease-out),
                visibility 0s linear var(--dur-base);
    /* A phone on its side leaves ~300px of panel for ~380px of links.
       Without this the overflow is simply unreachable. */
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
  }
  /* ...and this drops the delay on the way in, so the panel is visible from
     the first frame of the slide. */
  .main-nav.is-open{
    transform: translateX(0);
    visibility: visible;
    transition: transform var(--dur-base) var(--ease-out),
                visibility 0s;
  }
  .main-nav ul{ flex-direction: column; gap: var(--space-2); }
  .main-nav a{ display: block; padding: var(--space-3) 0; font-size: 17px; }
  .header-phone span{ display: none; }
  .nav-toggle{ display: flex; }
  .header-actions .btn-sm{ display: none; }

  /* Link and chevron share one row; the chevron is a real button so the
     link itself still navigates to the Diensten overview. */
  .nav-has-sub{ display: flex; flex-wrap: wrap; align-items: center; }
  .nav-has-sub > a{ flex: 1 1 auto; }
  .nav-sub-toggle{
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; flex: none;
    color: var(--text-muted); border-radius: var(--radius-sm);
  }
  .nav-sub-toggle .icon{ transition: transform var(--dur-base) var(--ease-out); }
  .nav-has-sub.is-open .nav-sub-toggle .icon{ transform: rotate(90deg); }

  /* Scoped with .main-nav on purpose: the plain `.nav-sub` selector loses to
     the existing `.main-nav ul{ display: flex }` above (one class + one type
     outranks a single class), which left the submenu permanently expanded
     instead of collapsed. */
  .main-nav .nav-sub{
    flex-basis: 100%;
    display: none;
    margin: 0 0 var(--space-2) var(--space-3);
    padding-left: var(--space-4);
    border-left: 2px solid var(--tan-200);
  }
  .main-nav .nav-has-sub.is-open .nav-sub{ display: block; }
  .nav-sub a{ font-size: 15.5px; padding: var(--space-2) 0; color: var(--text-muted); }
}

@media (max-width: 1180px){
  .grid-3, .portfolio-page{ grid-template-columns: repeat(2, 1fr); }
  .hero-stats{ grid-template-columns: repeat(2, 1fr); row-gap: var(--space-5); }
}

@media (max-width: 640px){
  :root{ --header-h: 68px; }
  .container{ padding-inline: var(--space-4); }
  .hero{ padding-block: var(--space-5) var(--space-4); }
  .grid-2, .grid-3, .grid-4, .portfolio-page{ grid-template-columns: 1fr; }
  .process{ grid-template-columns: 1fr; }
  .hero-stats{ grid-template-columns: repeat(2, 1fr); }
  .form-row{ grid-template-columns: 1fr; }
  .footer-inner{ grid-template-columns: 1fr; }
  .brand-name{ font-size: 16px; }
  .cert-grid{ grid-template-columns: 1fr 1fr; }
  .rating-summary{ flex-direction: column; text-align: center; }
  .rating-bars{ width: 100%; }
  .teaser-head{ align-items: flex-start; }
}

/* ==========================================================================
   Mobile optimisation
   --------------------------------------------------------------------------
   Everything below this point re-flows the desktop composition for phones.
   The widest trigger here is 1024px (plus a height-based one for phones held
   sideways), so no rule in this section can reach a desktop viewport — the
   1200px-container layout above is left exactly as it was.
   ========================================================================== */

/* --- Defensive typography ------------------------------------------------
   A long unbroken string — the contact address, a pasted URL — is the one
   thing a fluid layout cannot absorb at 320px. :where() keeps specificity at
   zero, so every component rule still outranks it. */
:where(p, h1, h2, h3, h4, li, dd, dt, summary, figcaption){
  overflow-wrap: break-word;
}

/* --- Hero: one-screen pinning is a desktop affordance --------------------
   .hero-screen caps hero + trust strip at exactly one viewport so the pair
   lands together above the fold. That only holds when the screen is big
   enough to seat them. On a phone the same cap starved the hero: at 320x667
   the content needed 572px and was given 345px, so .hero-inner was laid out
   at top:-144px — the headline was clipped off the top, and the primary
   "Vraag een gratis offerte aan" button and all four stats were cut away
   entirely by the hero's own `overflow: clip`. A phone in landscape was
   worse: 169px of room for 376px of content.

   The cap is therefore lifted exactly where it stops being affordable —
   narrow viewports, plus any viewport too short to seat a hero whatever its
   width, which is what a phone on its side is. The hero then sizes to its
   own content and the trust strip follows it naturally. Both thresholds sit
   below every common desktop viewport (a 1366x768 laptop still has ~640px of
   height at 1366px wide), so the pinned desktop behaviour is untouched. */
@media (max-width: 1024px), (max-height: 620px){
  .hero-screen{ height: auto; }
}

@media (max-width: 640px){
  /* Now that the hero sizes itself, it can afford real breathing room again
     instead of the squeeze it needed while fighting the cap. */
  .hero{ padding-block: var(--space-7) var(--space-6); }

  /* Four trust items stacked into four full-width rows stood 234px tall —
     more than a third of a 667px screen, and the single biggest reason the
     hero above had nothing left to work with. Two columns brings that to
     roughly 90px without shrinking the text into unreadability. */
  .trust-strip-inner{
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4);
  }
  .trust-item{
    align-items: flex-start;
    font-size: 13px;
    line-height: 1.35;
  }
  .trust-item .icon{ margin-top: 1px; }
}

/* --- Vertical rhythm -----------------------------------------------------
   96px of section padding reads as generous on a 1440px canvas and as dead
   space on a 667px one. These keep the hierarchy while removing the gaps
   that make a phone feel like a scroll through emptiness. */
@media (max-width: 640px){
  .section{
    padding-top: var(--space-7);
    padding-bottom: calc(var(--space-7) + var(--space-2));
  }
  .section-head{ margin-bottom: var(--space-6); }
  .teaser-head{ margin-bottom: var(--space-6); }
  .cta-banner{ padding-block: var(--space-7); }
  .footer-inner{ padding-block: var(--space-7); gap: var(--space-6); }
  .page-hero{ padding-block: var(--space-7) var(--space-6); }
  .rating-summary{ margin-block: var(--space-6); padding: var(--space-5); }

  /* Card padding scaled to the narrower canvas — 48px of inner padding on a
     288px-wide card leaves very little room for the content itself. */
  .card{ padding: var(--space-5); }
  .contact-form{ padding: var(--space-5); }
  .info-card{ padding: var(--space-5); }
  .approach-card{ padding: var(--space-6) var(--space-5); }
}

/* --- Type scale ----------------------------------------------------------
   The desktop clamps bottom out around 38px, still a large share of a 320px
   line. These lower only the mobile end of each ramp; the upper bound every
   clamp reaches on desktop is unchanged. */
@media (max-width: 640px){
  .hero-title{ font-size: clamp(1.9rem, 7.5vw, 2.4rem); }
  .hero-sub{ font-size: 16px; }
  .stat dt{ font-size: 26px; }
  .page-hero h1{ font-size: clamp(1.75rem, 7vw, 2.4rem); }
  .page-hero-lead{ font-size: 16px; }
  .section-head h2{ font-size: clamp(1.5rem, 6.4vw, 2rem); }
  .section-lead{ font-size: 16px; }
  .faq-item summary{ font-size: 16.5px; }
  .rating-score .num{ font-size: 44px; }
  .cta-banner p{ font-size: 15.5px; }

  /* The label sits over a tile roughly 140px wide once the grid drops to two
     columns; 22px overflowed it. */
  .category-card span{
    font-size: clamp(15px, 4.4vw, 20px);
    left: var(--space-4); right: var(--space-4); bottom: var(--space-4);
  }
}

/* --- Touch targets -------------------------------------------------------
   ~44px is the smallest reliably tappable box for a fingertip. These grow
   the hit area without altering how anything looks. */
@media (max-width: 1250px){
  /* At this breakpoint .header-phone loses its label and collapses to the
     bare icon, which left an 18x18px target on the single most valuable
     action a phone visitor can take: placing the call. */
  .header-phone{
    width: 44px; height: 44px;
    justify-content: center;
    border-radius: 50%;
  }
  .nav-toggle{
    width: 44px; height: 44px;
    align-items: center; justify-content: center;
  }
  .nav-sub-toggle{ width: 44px; height: 44px; }
}

@media (max-width: 640px){
  /* Footer links were 17px tall — the text box and nothing more. Moving the
     padding off the <li> and onto the <a> turns that same spacing into part
     of the target instead of a dead gap beside it. */
  .footer-nav li, .footer-contact li{ padding-block: 0; }
  .footer-nav a, .footer-contact a, .footer-legal a{
    display: inline-block;
    padding-block: 10px;
  }
  .social-links a{ width: 44px; height: 44px; }
  .portfolio-nav-btn{ width: 44px; height: 44px; }
  .marquee-arrow{ width: 44px; height: 44px; }
  .link-more{ padding-block: var(--space-2); }
}

/* --- Actions stack ------------------------------------------------------
   Two pill buttons side by side fit a 390px screen only just, and a 320px
   one not at all; stacked and full-width they are unmissable and
   unmistakably tappable. */
@media (max-width: 480px){
  .hero-actions{ flex-direction: column; align-items: stretch; }
  .hero-actions .btn{ width: 100%; }
  .cta-banner .btn{ width: 100%; }
  .approach-card .btn{ width: 100%; }
  .btn-lg{ padding: 15px 24px; }
}

/* --- Notches and home indicators ----------------------------------------
   .container and .header-inner carry their own safe-area insets in their
   base rules; these are the elements pinned to a corner, where an inset
   matters most. */
@media (max-width: 640px){
  .container{
    padding-left: max(var(--space-4), env(safe-area-inset-left));
    padding-right: max(var(--space-4), env(safe-area-inset-right));
  }
  .fixed-actions{
    right: max(var(--space-4), env(safe-area-inset-right));
    bottom: max(var(--space-4), env(safe-area-inset-bottom));
  }
}

/* --- Phones held sideways ------------------------------------------------
   ~390px of height, much of it spent on browser chrome. Trimming the
   vertical padding lets a section heading and its content share a screen. */
@media (max-height: 480px) and (orientation: landscape){
  .section{
    padding-top: var(--space-6);
    padding-bottom: var(--space-6);
  }
  .page-hero{ padding-block: var(--space-6) var(--space-5); }
  .cta-banner{ padding-block: var(--space-6); }
}

/* --- Certifications strip ------------------------------------------------
   .cert-item lays its icon, heading and description out as three siblings in
   a single flex row (there is no wrapper around the text), so the item's
   min-content width is the sum of all three — about 250px. Two such tracks
   could not fit a phone, and because `1fr` resolves to `minmax(auto, 1fr)`
   the grid refused to shrink below that: the over-ons page scrolled
   sideways by ~200px at 320px wide, no matter the viewport.

   Rather than force the desktop row into a space that cannot hold it, the
   item wraps on a phone: icon and heading share the first line, the
   description takes the next. minmax(0, 1fr) is what actually lets the
   track shrink; without it the `auto` minimum wins again. */
@media (max-width: 640px){
  .cert-grid{ grid-template-columns: minmax(0, 1fr); gap: var(--space-5); }
  .cert-item{ flex-wrap: wrap; column-gap: var(--space-3); row-gap: var(--space-1); }
  .cert-item h3{ flex: 1 1 auto; }
  .cert-item p{ flex: 1 1 100%; }
}

/* --- FAQ rows and breadcrumbs -------------------------------------------
   The vertical spacing around an FAQ question lived on .faq-item (the
   <details>), not on the <summary>. Only the <summary> toggles a
   <details>, so all that padding was dead space beside a 28px-tall target —
   on the FAQ page, the one control the visitor actually came to use.

   Moving the same measurement onto the summary itself leaves the closed row
   looking identical (24px above and below the question either way) while
   turning the target into ~76px. The answer keeps the bottom spacing that
   the item used to provide. */
@media (max-width: 640px){
  .faq-item{ padding-block: 0; }
  .faq-item summary{ padding-block: var(--space-5); }
  .faq-item p{ margin-top: 0; padding-bottom: var(--space-5); }

  /* Breadcrumb links sat at 22px tall. Small for a fingertip, and they are
     how a visitor climbs back out of a service page. */
  .breadcrumb a{ display: inline-block; padding-block: 8px; }
  .breadcrumb{ margin-bottom: var(--space-3); }
}

/* --- Mobile header CTA ---------------------------------------------------
   A second offerte button, centred in the header bar, for phones only. On
   desktop it stays hidden: .header-actions already carries the long-form
   "Vraag uw offerte aan in 2 minuten" button there, and two would compete.

   Space is the whole problem here. At 320px the bar had *negative* room left
   over once the wordmark, phone link and hamburger were laid out, so the
   button can only exist if something yields. The wordmark goes first: the
   logo mark beside it already carries the brand and still links home, which
   makes the text the cheapest thing on the bar. The gaps tighten too. */
.header-cta{ display: none; }

@media (max-width: 1250px){
  .header-cta{
    display: inline-flex;
    /* A left auto-margin only, so the button is pushed over against the
       actions instead of sitting dead centre. That hands the whole left half
       of the bar back to the logo and wordmark, which is the only way the
       two can share a phone-width header. */
    margin-left: auto;
    flex-shrink: 0;
    /* Taller than the stock .btn-sm so the bar's primary action clears a
       44px touch target; the 68px header absorbs it either way. */
    padding: 12px 14px;
    font-size: 13px;
  }
  .header-inner{ gap: var(--space-3); }
  .header-actions{ gap: var(--space-2); }
}

/* The wordmark only yields where the bar genuinely runs out of room. Measured
   with the button pushed right and the phone link already gone below 400px,
   logo + wordmark + button + hamburger fit down to a 320px viewport exactly —
   with no slack at all. This cutoff keeps ~20px of headroom under that, so
   every mainstream phone (360, 375, 390, 393, 414, 430) keeps the name and
   only genuinely tiny screens fall back to the logo alone. */
@media (max-width: 339px){
  .brand-name{ display: none; }
}

/* The phone link is what yields once the wordmark is also on the bar: logo +
   wordmark + CTA + phone + hamburger measures ~399px of content, so the link
   cannot come back until there is comfortably that much room. 430 is the
   first common breakpoint clear of it — at 401 (the previous threshold) the
   link reappeared while the bar was still ~13px too narrow and the header
   overflowed. The number stays one tap away in the footer and on the
   WhatsApp button pinned to the corner of every screen. */
@media (max-width: 430px){
  .header-phone{ display: none; }
  /* Tighter gaps and side padding here buy back roughly 12px, which is what
     lets the wordmark survive down to ~369px instead of ~381 — the
     difference between an iPhone SE showing the name and not. */
  .header-inner{ gap: var(--space-2); }
  .header-cta{ padding: 12px 10px; font-size: 12.5px; }
}

/* ============================================================
   BLOG
   Index grid of article cards, plus the article page layouts.
   ============================================================ */

.blog-grid{
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
}

.blog-card{
  display: flex;
  flex-direction: column;
  background: var(--white);
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
.blog-card:hover, .blog-card:focus-visible{ transform: translateY(-6px); box-shadow: var(--shadow-md); }

.blog-card-media{
  display: block;
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--cream-alt);
}
.blog-card-media img{
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-out);
}
.blog-card:hover .blog-card-media img,
.blog-card:focus-visible .blog-card-media img{ transform: scale(1.06); }

.blog-card-body{
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5);
  flex: 1;
}
.blog-card-tag{
  align-self: flex-start;
  font-size: 12px; font-weight: 600;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--bronze);
  background: var(--cream);
  border-radius: var(--radius-pill);
  padding: 4px 12px;
}
.blog-card-title{
  font-family: var(--font-display);
  font-size: 1.2rem;
  line-height: 1.3;
  color: var(--text);
  margin: 0;
}
.blog-card .link-more{ margin-top: auto; }

/* ---- Article pages ---- */

.article-layout{
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: var(--space-7);
  align-items: start;
}
.article-figure{ margin: 0; }
.article-figure img{
  width: 100%;
  height: auto;
  /* Cropped to the same 16/9 band as .article-hero and .blog-card-media.
     The source photos are portrait and vary in size; left at their own
     proportions this figure runs far taller than the text column beside it
     (686px against 326px at desktop width) and the row reads lopsided. */
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  display: block;
}
.article-body h2{ margin-bottom: var(--space-4); }
.article-body h3{ margin-top: var(--space-5); margin-bottom: var(--space-3); }
.article-body p{ margin-bottom: var(--space-4); }

.article-hero{ margin: 0 0 var(--space-7); }
/* Inline call-to-action inside article prose. Breaks the long advice pages
   up so the reader can act without scrolling back to the footer banner. */
.article-cta{
  text-align: center;
  margin: var(--space-7) 0;
}
.article-hero img{
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  display: block;
}

.article-prose{ max-width: 760px; }
.article-prose h2{
  margin-top: var(--space-7);
  margin-bottom: var(--space-4);
}
.article-prose h2:first-child{ margin-top: 0; }
.article-prose h3{ margin-top: var(--space-5); margin-bottom: var(--space-3); }
.article-prose p{ margin-bottom: var(--space-4); }
.article-prose .compare-list{ margin-bottom: var(--space-5); }

/* ---- Price tables ---- */

.table-wrap{
  overflow-x: auto;
  margin-bottom: var(--space-4);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}
.price-table{
  width: 100%;
  min-width: 420px;
  border-collapse: collapse;
  background: var(--white);
  font-size: 15px;
}
.price-table th,
.price-table td{
  text-align: left;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--cream-alt);
}
.price-table thead th{
  background: var(--cream);
  font-weight: 600;
  color: var(--espresso);
  white-space: nowrap;
}
.price-table tbody tr:last-child td{ border-bottom: 0; }
.price-table td:last-child{ white-space: nowrap; font-weight: 600; color: var(--bronze); }

.note-line{
  font-size: 14px;
  color: var(--text-muted);
  margin-bottom: var(--space-6);
}

@media (max-width: 1024px){
  .blog-grid{ grid-template-columns: repeat(2, 1fr); }
  .article-layout{ grid-template-columns: 1fr; gap: var(--space-6); }
}

@media (max-width: 640px){
  .blog-grid{ grid-template-columns: 1fr; gap: var(--space-5); }
  .blog-card-body{ padding: var(--space-4); }
  .blog-card-title{ font-size: 1.1rem; }
  .article-prose h2{ margin-top: var(--space-6); }
}

/* Directions link in the footer contact block. */
.footer-route{
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--bronze-300);
  transition: color var(--dur-fast) var(--ease-out);
}
.footer-route:hover{ color: var(--cream); }
.footer-route .icon{ flex: none; }

/* ==========================================================================
   Sticky mobile CTA bar
   Phones only. The floating WhatsApp/back-to-top buttons get lifted clear of
   it, and the body gains bottom padding so the footer is never hidden behind
   it. While the cookie banner is up the bar steps aside entirely -- two
   stacked overlays at the bottom of a small screen is one too many.
   ========================================================================== */
.mobile-cta-bar{ display: none; }

@media (max-width: 640px){
  .mobile-cta-bar{
    display: flex;
    align-items: center;
    gap: var(--space-3);
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 95;
    padding: var(--space-3) var(--space-4);
    padding-bottom: calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
    background: rgba(251, 243, 234, 0.96);
    backdrop-filter: blur(10px);
    border-top: 1px solid var(--tan-200);
    box-shadow: 0 -4px 16px rgba(42, 31, 24, 0.08);
  }
  .mobile-cta-bar .btn{ flex: 1 1 auto; justify-content: center; }

  .mobile-cta-call{
    flex: none;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 10px 14px;
    border: 1px solid var(--tan-200);
    border-radius: var(--radius-pill);
    color: var(--espresso);
    font-weight: 600; font-size: 15px;
    background: var(--white);
  }
  .mobile-cta-call:hover{ background: var(--cream-alt); }

  /* Keep the footer clear of the bar. */
  body{ padding-bottom: 78px; }

  /* Lift the floating buttons above the bar. */
  .fixed-actions{ bottom: calc(78px + var(--space-4)); }

  /* Cookie banner wins: hide the bar, keep the existing lift for the floats. */
  .psw-cc-open .mobile-cta-bar{ display: none; }
  .psw-cc-open body{ padding-bottom: 0; }
  .psw-cc-open .fixed-actions{ bottom: calc(var(--space-5) + 168px); }
}

@media (max-width: 640px) and (prefers-reduced-motion: reduce){
  .mobile-cta-bar{ backdrop-filter: none; background: var(--cream); }
}

/* ==========================================================================
   Case studies (/projecten)
   Index reuses .blog-grid / .blog-card; these are the detail-page pieces.
   ========================================================================== */

.case-facts{
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-5);
  margin: 0 0 var(--space-7);
  padding: var(--space-5) var(--space-6);
  background: var(--cream);
  border-radius: var(--radius-md);
  border: 1px solid var(--cream-alt);
}
.case-facts div{ display: flex; flex-direction: column; gap: 4px; }
.case-facts span{
  font-size: 12.5px; font-weight: 600;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--bronze);
}
.case-facts strong{ font-weight: 600; color: var(--espresso); }
.case-facts a{ color: var(--espresso); text-decoration: underline; text-underline-offset: 3px; }
.case-facts a:hover{ color: var(--bronze); }

.case-quote{
  position: relative;
  max-width: 760px;
  margin: var(--space-7) 0 0;
  padding: var(--space-6) var(--space-6) var(--space-5);
  background: var(--white);
  border-left: 3px solid var(--tan);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  box-shadow: var(--shadow-sm);
}
.case-quote-mark{ color: var(--tan-200); margin-bottom: var(--space-3); }
.case-quote blockquote{ margin: 0; }
.case-quote blockquote p{
  margin: 0 0 var(--space-4);
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 2vw, 1.25rem);
  line-height: 1.55;
  color: var(--espresso);
}
.case-quote figcaption{ display: flex; flex-direction: column; gap: 2px; }
.case-quote figcaption strong{ color: var(--espresso); font-weight: 600; }
.case-quote figcaption span{ font-size: 14px; color: var(--text-muted); }

@media (max-width: 760px){
  .case-facts{ grid-template-columns: 1fr; gap: var(--space-4); padding: var(--space-5); }
  .case-quote{ padding: var(--space-5); }
}

/* ==========================================================================
   Article extras
   ========================================================================== */

/* A compact hero for articles where the image is supporting rather than the
   subject -- it sits centred at reading width instead of running full bleed. */
.article-hero--compact{
  max-width: 520px;
  margin-inline: auto;
}
.article-hero--compact img{
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-md);
}

/* Numbered "what drives the price" list. Counters rather than <ol> markers so
   the number can carry the brand colour and sit beside a heading. */
.factor-list{
  list-style: none;
  counter-reset: factor;
  margin: 0 0 var(--space-6);
  padding: 0;
}
.factor-list > li{
  counter-increment: factor;
  position: relative;
  padding-left: 52px;
  margin-bottom: var(--space-5);
}
.factor-list > li::before{
  content: counter(factor);
  position: absolute;
  left: 0;
  top: 2px;
  width: 34px; height: 34px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--cream);
  border: 1px solid var(--tan-200);
  font-family: var(--font-display);
  font-size: 15px; font-weight: 700;
  color: var(--bronze);
}
.factor-list > li h3{
  margin: 4px 0 var(--space-2);
  font-size: 1.05rem;
}
.factor-list > li p{ margin: 0; }

/* Three-column price tables need a little more room before they scroll. */
.price-table th:nth-child(2),
.price-table td:nth-child(2){ min-width: 240px; font-weight: 400; color: var(--text-muted); }
.price-table td:nth-child(2){ white-space: normal; }

@media (max-width: 640px){
  .factor-list > li{ padding-left: 44px; }
  .factor-list > li::before{ width: 30px; height: 30px; font-size: 14px; }
}

/* The width/height attributes on these <img> tags are there to reserve layout
   space and stop CLS, but the height attribute is a presentational hint that
   beats `aspect-ratio` -- leaving the hero stretched to its intrinsic pixel
   height. Explicit height:auto hands control back to aspect-ratio. */
.article-hero img,
.article-figure img{ height: auto; }

/* ==========================================================================
   Supplier logo strip (homepage, under the Over ons teaser)
   Rides the shared .review-marquee drift; only the item sizing is new.
   ========================================================================== */
.brand-strip{ padding-block: var(--space-6); }

.brand-strip-label{
  text-align: center;
  margin-bottom: var(--space-5);
  font-size: 13px; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--text-muted);
}

.logo-marquee-track{
  gap: var(--space-8);
  align-items: center;
  padding-block: var(--space-2);
}
.logo-marquee-item{
  flex: none;
  display: flex; align-items: center;
  height: 59px; /* 44px + 35% */
  margin: 0;
}
/* Height-constrained, width free: the logos are pre-trimmed to their ink so
   a shared height gives them even optical weight. */
.logo-marquee-item img{
  height: 100%; width: auto;
  display: block;
  opacity: 0.9;
}

@media (max-width: 640px){
  .logo-marquee-track{ gap: var(--space-6); }
  .logo-marquee-item{ height: 46px; } /* 34px + 35% */
  .brand-strip{ padding-block: var(--space-5); }
}

/* Photo sitting beside the Schilderen card on the diensten services grid.
   Four cards in a 3-column grid leave the fourth alone on its own row with
   two empty cells; this fills them instead of leaving the gap. Collapses to a
   normal full-width figure once the grid stops being three columns. */
.service-photo{
  grid-column: span 2;
  margin: 0;
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  min-height: 0;
}
.service-photo img{
  width: 100%;
  height: 100%;
  min-height: 240px;
  object-fit: cover;
  display: block;
}

@media (max-width: 1024px){
  .service-photo{ grid-column: 1 / -1; }
  .service-photo img{ min-height: 220px; }
}
@media (max-width: 640px){
  .service-photo img{ min-height: 180px; }
}

/* Uniform slot for the supplier logos. The tinted assets are all rendered on
   the same 300x96 canvas (see Images/merken/), so a fixed slot plus
   object-fit:contain keeps the row even — and stays even if a future logo
   arrives on a different canvas, instead of stretching the row to fit it. */
.logo-marquee-item{
  width: 186px; /* 138px + 35%, kept on the assets 300:96 proportion */
  justify-content: center;
}
.logo-marquee-item img{
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}

@media (max-width: 640px){
  /* Slot follows the shorter logo height (34px x the 300:96 canvas aspect),
     so the row does not carry 32px of dead space per logo on a phone. */
  .logo-marquee-item{ width: 143px; } /* 106px + 35% */
}
