/* ==========================================================================
   Aapiies — styles
   Design tokens sampled from the mockups
   ========================================================================== */

/* Fonts (self-hosted) ----------------------------------------------------
   Soap (fonts/soap.woff2) is kept on hand but currently unused — to bring it
   back, uncomment this block and put "Soap" first in --font-display below.
*/


@font-face {
  font-family: "Chonburi";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/chonburi-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/inter-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/inter-latin-500-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/inter-latin-600-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Caveat";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/caveat-latin-600-normal.woff2") format("woff2");
}

:root {
  --green: #004936;
  --green-hover: #00614a;
  --cream: #fdfdf6;
  --ink: #22423a;
  --ink-soft: #5c6b66;
  --rust: #70240d;
  --placeholder: #d7e0e2;
  --card-radius: 22px;
  --font-display: "Soap", "Chonburi", "Cooper Black", Georgia, serif;
  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-hand: "Caveat", "Comic Sans MS", cursive;
  --container: 1160px;
  --gutter: clamp(20px, 4vw, 48px);
}

/* Reset ------------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
img, svg { display: block; max-width: 100%; height: auto; }
ul { list-style: none; padding: 0; }
a { color: inherit; }

html { scroll-behavior: smooth; }

/* Sticky footer: on any page short enough to leave empty space below the
   footer (e.g. the contact page's post-submit state), main grows to fill
   the viewport instead of stranding the footer with a gap beneath it. On
   normal, taller pages this has no visible effect — main simply exceeds its
   flex-basis and the layout behaves exactly like block flow. */
body {
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--ink);
  background: var(--cream);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
main { flex: 1 0 auto; }

.container {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.display {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--green);
  line-height: 1.15;
  letter-spacing: 0.01em;
}

/* Skip link -------------------------------------------------------------- */
.skip-link {
  position: absolute;
  top: -100%;
  left: 16px;
  z-index: 100;
  padding: 10px 18px;
  background: var(--green);
  color: var(--cream);
  border-radius: 0 0 10px 10px;
  text-decoration: none;
}
.skip-link:focus { top: 0; }

/* Buttons ---------------------------------------------------------------- */
.btn {
  display: inline-block;
  padding: 11px 30px;
  background: var(--green);
  color: var(--cream);
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: none;
  border-radius: 9px;
  transition: background-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}
.btn:hover {
  background: var(--green-hover);
  transform: translateY(-2px);
  box-shadow: 0 6px 18px rgb(0 73 54 / 0.22);
}
.btn:active { transform: translateY(0); }

:is(a, button):focus-visible {
  outline: 3px solid var(--green);
  outline-offset: 3px;
  border-radius: 4px;
}
.services :is(a, button):focus-visible,
.site-footer a:focus-visible {
  outline-color: var(--cream);
}

/* Header ----------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--cream);
  /* Equal top/bottom padding. This used to be lopsided (18px/6px) from back
     when the logo was a plain image sitting loosely in the bar — the offset
     wasn't obvious without a visible edge to compare it to. Now that the
     logo sits inside its own rounded cream/green-contrast chip (see .logo
     img below), an uneven gap above vs. below that chip reads as a mistake,
     so this is split evenly. Total stays 24px either way, so the header's
     box height is unchanged — see the flicker note just below for why that
     matters. */
  padding-block: 12px;
  border-bottom: 1px solid rgb(0 73 54 / 0.1);
  box-shadow: 0 2px 10px rgb(0 0 0 / 0.05);
  transition: background-color 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease, transform 0.3s ease;
  /* This element sits in normal flow above the rest of the page, so any
     change to its own box height (it used to shrink slightly on scroll)
     shifts everything below it. Chrome/Firefox's scroll anchoring then
     "corrects" scrollY to hold the visible content still — which re-fires
     the scroll handler right as it crosses the is-scrolled threshold,
     flips the header back, gets corrected again, and so on. That feedback
     loop was the cause of the header flickering green/cream while
     scrolling slowly near the top. padding-block is now fixed (identical
     in both states below) so toggling .is-scrolled never changes the
     header's height, and overflow-anchor is switched off here as a second
     line of defence against the same class of bug in future. */
  overflow-anchor: none;
}
.site-header.is-scrolled {
  background: var(--green);
  border-bottom-color: rgb(253 253 246 / 0.14);
  /* Deliberately stronger than the resting-state shadow: once the header sits
     over full-bleed green sections (services, page-hero) it needs a shadow
     that reads clearly against a same-color background, not just white. */
  box-shadow: 0 10px 26px rgb(0 0 0 / 0.3);
}
/* Slides the sticky header out of view while scrolling down through a page
   (see js/main.js), so it never lingers mid-scroll clipping a card, button or
   the scalloped divider. Scrolling up, reaching the top, opening the mobile
   menu, or focusing anything inside the header all bring it straight back. */
.site-header.is-hidden { transform: translateY(-100%); }
.site-header:focus-within { transform: none; }
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}
.logo img {
  width: 66px;
  height: auto;
  /* The logo file itself is transparent (correct — it needs to sit on any
     background), but its ink is a dark green close to .is-scrolled's green
     header fill, so without its own backing chip it nearly disappears once
     scrolled (see the "logo visibility on the scrolled header" note in the
     build notes). A small cream chip keeps it legible on both the resting
     cream header and the scrolled green one. */
  background: var(--cream);
  padding: 6px;
  border-radius: 8px;
}

.nav-list {
  display: flex;
  align-items: center;
  gap: clamp(20px, 3.5vw, 44px);
}
.nav-list a {
  position: relative;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--ink);
  text-decoration: none;
  padding-block: 6px;
}
.nav-list a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: var(--green);
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.25s ease;
}
.nav-list a:hover::after,
.nav-list a:focus-visible::after { transform: scaleX(1); }

/* Current page indicator */
.nav-list a[aria-current="page"] {
  color: var(--green);
  font-weight: 600;
}
.nav-list a[aria-current="page"]::after { transform: scaleX(1); }

/* Diensten pill button in the nav */
.nav-list .btn--nav {
  padding: 8px 22px;
  border-radius: 9px;
  background: var(--green);
  color: var(--cream);
  font-weight: 500;
}
.nav-list .btn--nav::after { content: none; }
.nav-list .btn--nav:hover {
  background: var(--green-hover);
  transform: translateY(-2px);
}

/* Scrolled (green) header state */
.is-scrolled .nav-list a { color: var(--cream); }
.is-scrolled .nav-list a::after { background: var(--cream); }
.is-scrolled .nav-list .btn--nav {
  background: var(--cream);
  color: var(--green);
}
.is-scrolled .nav-list .btn--nav:hover { background: #ffffff; }
.site-header.is-scrolled :is(a, button):focus-visible { outline-color: var(--cream); }

/* Mobile nav toggle (hidden on desktop; shown under the 760px breakpoint) -- */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
  width: 40px;
  height: 40px;
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  border-radius: 8px;
  flex-shrink: 0;
}
.nav-toggle-bar {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--ink);
  border-radius: 2px;
  transition: transform 0.25s ease, opacity 0.2s ease, background-color 0.25s ease;
}
.is-scrolled .nav-toggle-bar { background: var(--cream); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* Hero ------------------------------------------------------------------- */
.hero { position: relative; }
.hero-inner {
  margin-top: 7%;
  display: grid;
  grid-template-columns: minmax(280px, 5fr) 7fr;
  align-items: start;
  gap: clamp(16px, 3vw, 48px);
}
.hero-copy {
  padding-block: clamp(40px, 7vw, 96px) clamp(48px, 6vw, 80px);
  max-width: 400px;
}
.hero-copy h1 {
  font-size: clamp(2.4rem, 4.6vw, 3.5rem);
  margin-bottom: 0.55em;
}
.hero-copy p {
  max-width: 34ch;
  margin-bottom: 2em;
}
.hero-art {
  position: relative;
  z-index: 0; /* stack below .services (z-index: 1) so the overlap reads as behind the green */
  align-self: end;
  justify-self: end;
  width: min(100%, 640px);
  pointer-events: none;
}
/* Reserved image spots (until final assets arrive) */
.img-placeholder {
  background: var(--placeholder);
  border-radius: var(--card-radius);
}
.hero-placeholder {
  width: 100%;
  aspect-ratio: 1 / 1;
  margin-bottom: 3.5%;
}
.hero-img {
  width: 100%;
  margin-bottom: -12%; /* branch overlaps the green section, as in the mockup */
}

/* Services --------------------------------------------------------------- */
.services {
  position: relative;
  z-index: 1;
  background: var(--green);
  border-radius: 28px 28px 0 0;
  color: var(--cream);
}
.services .container {
  padding-block: clamp(44px, 6vw, 72px) clamp(32px, 5vw, 56px);
}
.services h2 {
  color: var(--cream);
  font-size: clamp(1.7rem, 3vw, 2.4rem);
  margin-bottom: clamp(28px, 4vw, 52px);
}
.services-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  column-gap: clamp(20px, 3vw, 36px);
  row-gap: clamp(36px, 4.5vw, 56px);
}
.service-card {
  aspect-ratio: 1 / 0.99;
  background: var(--cream);
  border-radius: var(--card-radius);
  display: grid;
  place-items: center;
  overflow: hidden;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.service:hover .service-card {
  transform: translateY(-6px);
  box-shadow: 0 14px 30px rgb(0 0 0 / 0.22);
}
.service-icon {
  width: 42%;
  height: 42%;
}
.service h3 {
  font-size: 1rem;
  font-weight: 600;
  color: var(--cream);
  margin-top: 18px;
  margin-bottom: 4px;
}
.service p {
  font-size: 0.875rem;
  line-height: 1.5;
  color: rgb(253 253 246 / 0.62);
  max-width: 30ch;
}
.services-cta {
  display: flex;
  justify-content: center;
  margin-block: clamp(48px, 6vw, 80px) clamp(16px, 2.5vw, 36px);
}
.btn--light {
  background: var(--cream);
  color: var(--green);
}
.btn--light:hover {
  background: #ffffff;
  box-shadow: 0 6px 18px rgb(0 0 0 / 0.25);
}

/* Scalloped edge ---------------------------------------------------------
   Fixed-size scallops so they stay small on any screen width. */
.scallops {
  --scallop-h: 30px;
  /* tile width = 2 × radius, so neighbouring semicircles touch with no flat gap */
  --scallop-w: calc(var(--scallop-h) * 2);
  height: var(--scallop-h);
  background-color: var(--cream);
  background-image: radial-gradient(
    circle at 50% 0,
    var(--green) calc(var(--scallop-h) - 1px),
    rgb(0 73 54 / 0) var(--scallop-h)
  );
  background-size: var(--scallop-w) var(--scallop-h);
  background-position: top center;
  background-repeat: repeat-x;
}

/* Wie is Aapiies? ----------------------------------------------------------
   Text block (same style as .hero-copy/.custom-copy) followed by a project
   preview slider and a dot-divider — see .work-slider and .section-divider
   below for why those replaced the single illustration + white card. */
.about {
  background: var(--cream);
  margin-top: 5%;
}
.about-copy {
  max-width: 400px;
}
.about-copy h2 {
  font-size: clamp(1.7rem, 3vw, 2.4rem);
  margin-bottom: 0.8em;
}
.about-copy p {
  font-size: 0.9375rem;
  color: var(--ink-soft);
  max-width: 40ch;
  margin-bottom: 2.2em;
}

/* Work slider --------------------------------------------------------------
   Native horizontal scroll-snap carries the actual sliding (works with
   touch/trackpad/drag with zero JS); the prev/next buttons and dots are a
   thin enhancement layer on top (js/main.js) for discoverability and
   keyboard/click access. Slide width is set as an exact fraction of the
   viewport (3 per view on desktop, 2 on tablet, 1 on mobile — same 900px/
   560px breakpoints the services/diensten grids already use) rather than a
   vw-based clamp(), so there's never a partial card sitting at the edge —
   at rest you always see exactly N whole cards, and scrolling (once there
   are more than N slides) snaps cleanly to the next full group. */
.work-slider {
  margin-top: clamp(32px, 5vw, 56px);
}
/* Setting overflow-x here forces the browser to compute overflow-y as
   `auto` too, even though it's never set explicitly (a horizontal- and
   vertical-visible combination isn't possible per the CSS overflow spec) —
   so this box clips in both directions, not just the one it's meant to
   scroll. At rest that's invisible (nothing overflows), but
   .work-slide-image's hover state (a lifted translateY plus a soft
   box-shadow reaching ~44px below/~16px above and ~30px either side of its
   own box) has nowhere to go: the viewport was sized exactly to its content
   with zero slack on every edge, so the shadow got clipped hard right at
   the image's edge instead of fading out — top and bottom on every card,
   and left/right on the first and last card specifically (cards in between
   are fine; the shadow has the inter-card gap to bleed into).
   padding-block/-inline give it that missing room on all four sides; the
   matching negative margin-block/-inline cancel the padding back out so
   the track's rendered position and overall footprint are unchanged —
   card 1 still sits flush with the heading above it, and the row still
   fits exactly N whole cards per view (the inline padding shrinks the
   track's available width slightly, but since .work-slide's width is a
   percentage of that width, N cards still divide it exactly — this does
   NOT reintroduce the earlier partial-card-cutoff bug, which was about
   fractional vw units, not about the available width shrinking by a fixed
   symmetric amount). */
.work-slider-viewport {
  overflow-x: auto;
  padding-block: 20px 50px;
  padding-inline: 34px;
  margin-block: -20px -50px;
  margin-inline: -34px;
  scroll-snap-type: x mandatory;
  scroll-padding-left: 34px;
  scrollbar-width: none;
}
.work-slider-viewport::-webkit-scrollbar {
  display: none;
}
.work-slider-viewport:focus-visible {
  outline: 3px solid var(--green);
  outline-offset: 4px;
  border-radius: 4px;
}
.work-slider-track {
  --slide-gap: clamp(16px, 2.5vw, 28px);
  /* Matches the current project count (2) so both slides fill the row
     exactly on desktop with no leftover gap where a 3rd card used to sit.
     Bump this back to 3 — and reinstate the ≤900px override below that
     used to drop it from 3 to 2 — once a 3rd project is added. */
  --slides-per-view: 2;
  display: flex;
  gap: var(--slide-gap);
  list-style: none;
  margin: 0;
  padding: 0 2px;
}
.work-slide {
  flex: 0 0 calc((100% - (var(--slides-per-view) - 1) * var(--slide-gap)) / var(--slides-per-view));
  scroll-snap-align: start;
}
.work-slide-image {
  aspect-ratio: 4 / 3;
  background: var(--placeholder);
  border-radius: var(--card-radius);
  overflow: hidden;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.work-slide-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.work-slide:hover .work-slide-image {
  transform: translateY(-6px);
  box-shadow: 0 14px 30px rgb(0 73 54 / 0.14);
}
.work-slide-link {
  display: block;
  color: inherit;
  text-decoration: none;
  border-radius: var(--card-radius);
}
.work-slide-link:focus-visible .work-slide-image {
  outline: 3px solid var(--green);
  outline-offset: 4px;
}
.work-slide-label {
  margin: 14px 2px 0;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--ink);
}
.work-slider-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  margin-top: clamp(20px, 3vw, 32px);
}
.work-slider-btn {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  background: #fff;
  color: var(--green);
  border: 1px solid rgb(0 73 54 / 0.14);
  border-radius: 50%;
  cursor: pointer;
  transition: background 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease;
}
.work-slider-btn svg {
  width: 18px;
  height: 18px;
}
.work-slider-btn:hover:not(:disabled) {
  background: var(--placeholder);
}
.work-slider-btn:focus-visible {
  outline: 3px solid var(--green);
  outline-offset: 2px;
}
.work-slider-btn:disabled {
  opacity: 0.3;
  cursor: default;
  pointer-events: none;
}
.work-slider-dots {
  display: flex;
  align-items: center;
  gap: 8px;
}
.work-slider-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgb(0 73 54 / 0.2);
  cursor: pointer;
  transition: background 0.2s ease, transform 0.2s ease;
}
.work-slider-dot:hover {
  background: rgb(0 73 54 / 0.4);
}
.work-slider-dot.is-active {
  background: var(--green);
  transform: scale(1.3);
}
.work-slider-dot:focus-visible {
  outline: 3px solid var(--green);
  outline-offset: 3px;
}

/* Section divider ----------------------------------------------------------
   A row of small brand-green dots — the same repeat-tiled-circle technique
   as .scallops, echoing that motif's rhythm without borrowing its exact cut
   shape (which needs a solid color block above it to read correctly; here
   there's cream on both sides, nothing to cut the shape out of). Used
   between "Wie is Aapiies?" and "Iets anders?" since both sit on plain
   cream with no color change of their own to mark the boundary. */
.section-divider {
  height: 14px;
  margin-top: clamp(40px, 6vw, 64px);
  background-image: radial-gradient(circle, var(--green) 3.5px, transparent 4px);
  background-size: 26px 14px;
  background-position: center;
  background-repeat: repeat-x;
  opacity: 0.4;
}

/* Iets anders? ----------------------------------------------------------- */
.custom-idea {
  background: var(--cream);
  overflow: hidden;

}
.custom-inner {
  display: grid;
  grid-template-columns: minmax(280px, 5fr) 7fr;
  gap: clamp(24px, 4vw, 56px);
  align-items: start;
}
.custom-copy {
  padding-block: clamp(24px, 3vw, 44px) clamp(36px, 4.5vw, 60px);
  max-width: 400px;
  margin-bottom: 35%;
}
.custom-copy h2 {
  font-size: clamp(1.7rem, 3vw, 2.4rem);
  margin-bottom: 0.8em;
}
.custom-copy p {
  font-size: 0.9375rem;
  color: var(--ink-soft);
  max-width: 40ch;
  margin-bottom: 2.2em;
}
.custom-art {
  margin-top: 15%;
  position: relative;
  align-self: stretch;
  min-height: 340px;
}
.art-arrow {
  position: absolute;
  top: clamp(48px, 7vw, 88px);
  left: 0;
  width: clamp(160px, 22vw, 260px);
}
.art-brand {
  position: absolute;
  top: clamp(96px, 13vw, 150px);
  right: clamp(0px, 4vw, 48px);
  font-family: var(--font-hand);
  font-size: clamp(1.4rem, 2.2vw, 1.9rem);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--green);
  white-space: nowrap;
}
.art-hands {
  margin-top: 50px;
  position: absolute;
  bottom: 0;
  right: 0;
  width: clamp(260px, 34vw, 470px);
 
}
.custom-art .art-arrow { top: clamp(24px, 4vw, 48px); }
.custom-art .art-brand { top: clamp(64px, 9vw, 104px); }

/* Footer ----------------------------------------------------------------- */
.site-footer {
  background: var(--green);
  color: var(--cream);
  border-radius: 20px 20px 0 0;
}

.footer-main {
  display: grid;
  grid-template-columns: minmax(200px, 1.4fr) 1fr;
  gap: clamp(32px, 5vw, 64px);
  padding-block: clamp(40px, 6vw, 64px) clamp(32px, 4vw, 44px);
}
.footer-brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}
.wordmark {
  display: inline-block;
  color: var(--cream);
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  text-decoration: none;
}
.footer-tagline {
  font-size: 0.875rem;
  color: rgb(253 253 246 / 0.68);
  max-width: 30ch;
}

.footer-heading {
  font-family: var(--font-body);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgb(253 253 246 / 0.55);
  margin-bottom: 16px;
}
.footer-nav {
  display: grid;
  gap: 10px;
  justify-items: start;
}
.footer-nav a {
  font-size: 0.875rem;
  color: var(--cream);
  text-decoration: none;
  opacity: 0.9;
}
.footer-nav a:hover { text-decoration: underline; opacity: 1; }

/* Social icons */
.social-links {
  display: flex;
  gap: 10px;
}
.social-links a {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  color: var(--cream);
  background: rgb(253 253 246 / 0.08);
  transition: background-color 0.2s ease, transform 0.2s ease;
}
.social-links svg { width: 19px; height: 19px; }
.social-links a:hover {
  background: rgb(253 253 246 / 0.18);
  transform: translateY(-2px);
}

/* Divider + legal bar */
.footer-divider {
  border: none;
  border-top: 1px solid rgb(253 253 246 / 0.14);
}
.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 28px;
  padding-block: 22px;
  font-size: 0.8125rem;
  color: rgb(253 253 246 / 0.68);
}
.footer-legal {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 22px;
}
.footer-legal a {
  color: inherit;
  text-decoration: none;
}
.footer-legal a:hover { text-decoration: underline; color: var(--cream); }
.footer-legal a[aria-current="page"] {
  color: var(--cream);
  font-weight: 600;
  text-decoration: underline;
}
.footer-credit a {
  color: var(--cream);
  text-decoration: underline;
  text-decoration-color: rgb(253 253 246 / 0.4);
  text-underline-offset: 2px;
}
.footer-credit a:hover { text-decoration-color: var(--cream); }

/* Utility page hero (legal pages, and any future non-mockup page) -------- */
.page-hero {
  background: var(--green);
  color: var(--cream);
}
.page-hero .container {
  padding-block: clamp(56px, 9vw, 96px) clamp(40px, 6vw, 64px);
}
.page-hero h1 {
  color: var(--cream);
  font-size: clamp(2rem, 4vw, 3rem);
}
.page-hero-subtitle {
  margin-top: 12px;
  font-size: 0.9375rem;
  color: rgb(253 253 246 / 0.72);
}

/* Portfolio page -----------------------------------------------------------
   Vertical list (not a grid) per the mockup and the sarahlauchli.com
   reference — same 5fr/7fr thumbnail+copy ratio already used for
   .hero-inner/.custom-inner, stacked with generous vertical rhythm between
   entries rather than side by side. */
.portfolio-section .container {
  padding-block: clamp(48px, 6vw, 80px);
}
.portfolio-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(48px, 6vw, 80px);
}
/* .portfolio-link exists only once a project has a case-study page to go
   to (see ogd-verzuimloket.html) — it carries the same grid as
   .portfolio-item so a linked row lays out identically to a still-pending
   placeholder row (plain .portfolio-item, no anchor yet). */
.portfolio-item,
.portfolio-link {
  display: grid;
  grid-template-columns: minmax(240px, 5fr) 7fr;
  gap: clamp(24px, 4vw, 56px);
  align-items: center;
}
/* .portfolio-link is itself a nested grid (rule above), but it's also the
   *sole* child of the outer .portfolio-item grid — without an explicit
   span it would auto-place into just the item's first (5fr) track instead
   of the full row, squeezing its own thumb/copy columns down inside that
   already-narrow slice. grid-column makes it span both outer tracks so it
   fills the same width a non-linked .portfolio-item's direct children do. */
.portfolio-link { grid-column: 1 / -1; text-decoration: none; color: inherit; }
.portfolio-thumb {
  aspect-ratio: 4 / 3;
  background: var(--placeholder);
  border-radius: var(--card-radius);
  overflow: hidden;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.portfolio-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.portfolio-item:hover .portfolio-thumb,
.portfolio-link:hover .portfolio-thumb {
  transform: translateY(-6px);
  box-shadow: 0 14px 30px rgb(0 73 54 / 0.14);
}
.portfolio-copy {
  max-width: 46ch;
}
.portfolio-title {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--green);
  font-size: clamp(1.4rem, 2.4vw, 1.8rem);
  margin-bottom: 0.5em;
}
.portfolio-summary {
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 46ch;
}

/* Legal content pages (Privacybeleid, Voorwaarden, Cookiebeleid) --------- */
.legal {
  padding-block: clamp(40px, 6vw, 64px) clamp(64px, 8vw, 96px);
}
.legal-container {
  max-width: 760px;
}
.legal-notice {
  display: flex;
  gap: 12px;
  padding: 16px 20px;
  margin-bottom: clamp(32px, 5vw, 48px);
  background: rgb(112 36 13 / 0.06);
  border-left: 3px solid var(--rust);
  border-radius: 8px;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--ink);
}
.legal-notice strong { color: var(--rust); }
.legal-body :is(h2, h3) {
  font-family: var(--font-body);
  color: var(--green);
  line-height: 1.3;
  scroll-margin-top: 90px;
}
.legal-body h2 {
  font-size: 1.25rem;
  font-weight: 600;
  margin-top: 2.4em;
}
.legal-body h2:first-of-type { margin-top: 0; }
.legal-body h3 {
  font-size: 1.0625rem;
  font-weight: 600;
  margin-top: 1.6em;
}
.legal-body p, .legal-body ul {
  margin-top: 1em;
  color: var(--ink);
  max-width: 68ch;
}
.legal-body ul { padding-left: 1.25em; list-style: disc; }
.legal-body li + li { margin-top: 0.4em; }
.legal-body a {
  color: var(--green);
  text-decoration-color: rgb(0 73 54 / 0.35);
  text-underline-offset: 2px;
}
.legal-body a:hover { text-decoration-color: var(--green); }
.legal-body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
  background: rgb(0 73 54 / 0.08);
  padding: 0.15em 0.4em;
  border-radius: 4px;
}
.legal-back {
  margin-top: clamp(40px, 6vw, 56px);
  padding-top: clamp(24px, 4vw, 32px);
  border-top: 1px solid rgb(0 73 54 / 0.12);
}
.legal-back a { font-weight: 500; }

.legal-toc {
  margin-bottom: clamp(32px, 5vw, 48px);
  padding: 18px 22px;
  background: var(--placeholder);
  border-radius: var(--card-radius);
}
.legal-toc-label {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 10px;
}
.legal-toc ol {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 6px;
}
.legal-toc a {
  font-size: 0.9375rem;
  color: var(--green);
  text-decoration: none;
}
.legal-toc a:hover { text-decoration: underline; }

/* Contact page ------------------------------------------------------------
   The page-hero and the whole contact body each have two states — a default
   one and a "submitted" one — toggled by js/main.js via the .is-active class
   (see .hero-state / .contact-state below). Only one of each pair is ever
   shown; [hidden]-style display:none keeps the inactive one out of layout
   entirely rather than just visually hidden. */
.hero-state,
.contact-state {
  display: none;
}
.hero-state.is-active,
.contact-state.is-active {
  display: block;
}
html.js .hero-state.is-active,
html.js .contact-state.is-active {
  animation: contact-fade-up 0.5s ease both;
}
@keyframes contact-fade-up {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}

.contact-section {
  background: var(--cream);
  padding-block: clamp(48px, 7vw, 72px) clamp(64px, 8vw, 96px);
}
/* Desktop: two matching cards side by side, stretched to equal height
   (align-items: stretch — the taller one, almost always the form, sets the
   row height and the map card fills to match it). Below 960px there isn't
   room for a real sidebar without cramping the form fields, so it collapses
   to a single stacked column of the same two cards. */
.contact-container {
  max-width: 1120px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(340px, 440px);
  align-items: stretch;
  gap: clamp(28px, 4vw, 40px);
}

.contact-card,
.contact-info-card {
  background: #fff;
  border: 1px solid rgb(0 73 54 / 0.07);
  border-radius: var(--card-radius);
  padding: clamp(28px, 4vw, 40px);
  box-shadow: 0 24px 48px rgb(0 73 54 / 0.06), 0 2px 10px rgb(0 0 0 / 0.03);
}

.contact-form {
  display: flex;
  flex-direction: column;
  gap: 22px;
}
.form-field {
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.form-field label {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.form-field .optional {
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  color: var(--ink-soft);
}
.form-field input,
.form-field select,
.form-field textarea {
  font: inherit;
  font-size: 0.9375rem;
  width: 100%;
  padding: 15px 22px;
  border: none;
  border-radius: 999px;
  background: var(--placeholder);
  color: var(--ink);
  transition: box-shadow 0.2s ease;
}
.form-field textarea {
  border-radius: var(--card-radius);
  padding: 18px 22px;
  min-height: 160px;
  resize: vertical;
}
.form-field select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 46px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%2322423A' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 7.5L10 12.5L15 7.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 20px center;
  background-size: 16px;
  cursor: pointer;
}
.form-field select:invalid { color: var(--ink-soft); }
.form-field ::placeholder { color: var(--ink-soft); opacity: 0.85; }
.form-field input:focus-visible,
.form-field select:focus-visible,
.form-field textarea:focus-visible {
  outline: 3px solid var(--green);
  outline-offset: 3px;
}
.contact-form .btn {
  align-self: flex-start;
  margin-top: 6px;
  border: none;
  cursor: pointer;
}
.contact-form .btn[disabled] {
  opacity: 0.7;
  cursor: not-allowed;
  transform: none !important;
  box-shadow: none !important;
}
/* Inline send-failure message — only ever shown if the Formspree request
   itself fails (offline, service down); client-side validation errors are
   handled natively via form.reportValidity() and never reach this. Sits in
   the same [hidden]-driven show/hide pattern as the honeypot field, so it
   takes no layout space until there's actually something to say. */
.form-status {
  margin: -10px 0 0;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--rust);
}

/* Honeypot: kept out of sight and out of the tab order, but still present
   in the DOM for basic spam-bot filtering once this form is wired up. */
.hp-field {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  left: -9999px;
}

/* Map on top, contact details below — the map grows (flex: 1) to fill
   whatever height the card is stretched to on desktop, which is what makes
   it "as big as the form" without any fixed pixel value. */
.contact-info-card {
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.contact-map {
  flex: 1;
  min-height: 220px;
  width: 100%;
  border-radius: calc(var(--card-radius) - 8px);
  overflow: hidden;
  background: var(--placeholder);
}
.contact-map iframe {
  width: 100%;
  height: 100%;
  border: 0;
  /* Approximates the dark map style from the mockup without a Maps API key
     (the keyless embed only supports the default light theme). */
  filter: invert(92%) hue-rotate(175deg) contrast(0.92) brightness(0.95);
}
.contact-info-details { flex-shrink: 0; }
.contact-card-label {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 12px;
}
.contact-details {
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 0.9375rem;
  font-weight: 600;
}
.contact-details a { color: var(--green); text-decoration: none; }
.contact-details a:hover { text-decoration: underline; }
.contact-details li:not(:has(a)) { color: var(--ink); }

@media (max-width: 960px) {
  .contact-container {
    grid-template-columns: 1fr;
    max-width: 620px;
  }
  .contact-card { margin-bottom: clamp(28px, 5vw, 40px); }
  .contact-map {
    flex: none;
    min-height: 0;
    aspect-ratio: 3 / 2;
  }
}

/* Contact — submitted confirmation card. Sits where the form/map cards were,
   so the post-submit state reads as a deliberate, complete screen rather
   than a single stray button. */
.success-card {
  max-width: 440px;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  text-align: center;
  background: #fff;
  border: 1px solid rgb(0 73 54 / 0.07);
  border-radius: var(--card-radius);
  padding: clamp(40px, 6vw, 56px) clamp(28px, 5vw, 40px);
  box-shadow: 0 24px 48px rgb(0 73 54 / 0.06), 0 2px 10px rgb(0 0 0 / 0.03);
}
.success-icon {
  width: 72px;
  height: 72px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--green);
  display: flex;
  align-items: center;
  justify-content: center;
}
.success-icon svg { width: 32px; height: 32px; }
.success-icon-check {
  fill: none;
  stroke: var(--cream);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 22;
  stroke-dashoffset: 22;
}
html.js .success-icon {
  animation: success-icon-pop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) 0.15s both;
}
html.js .success-icon-check {
  animation: success-check-draw 0.45s ease 0.5s forwards;
}
@keyframes success-icon-pop {
  from { transform: scale(0.6); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}
@keyframes success-check-draw {
  to { stroke-dashoffset: 0; }
}
.success-status {
  font-size: 1.375rem;
  font-weight: 600;
  color: var(--green);
}
.success-text {
  margin-top: -8px;
  font-size: 0.9375rem;
  color: var(--ink-soft);
}
.success-card .btn { margin-top: 6px; }

/* Diensten page ------------------------------------------------------------
   Same card language as the contact page: one big white panel on the cream
   page background, radius/shadow/border matching .contact-card. Tiles are
   sized exactly like the homepage's .services-grid (same columns, gaps and
   square aspect-ratio) so the panel is as compact as the homepage's own
   services section. Clicking a tile grows it, in place, into a full-size
   detail card centered over the grid — a FLIP (First-Last-Invert-Play)
   transform-only animation driven by js/main.js, not a plain crossfade:
   the shared #dienst-detail element is measured at its clicked tile's
   on-screen size/position (First) and at its full resting size (Last,
   always inset:0 of the panel), then animated from one to the other via
   `transform: translate()/scale()`. The rest of the grid fades out at the
   same time, so the effect reads as "this tile grows to fill the panel,
   the others dissolve behind it." Closing reverses the whole sequence,
   shrinking the card back down into the tile it came from. Because the
   card is always absolutely positioned at inset:0 (its *layout* box never
   changes, only its transform), .diensten-panel's own height is still set
   solely by .diensten-grid and never moves during the animation. */
.diensten-section {
  background: var(--cream);
  padding-block: clamp(48px, 7vw, 72px) clamp(64px, 8vw, 96px);
}
.diensten-panel {
  position: relative;
  background: #fff;
  border: 1px solid rgb(0 73 54 / 0.07);
  border-radius: var(--card-radius);
  padding: clamp(28px, 3.6vw, 40px);
  box-shadow: 0 24px 48px rgb(0 73 54 / 0.06), 0 2px 10px rgb(0 0 0 / 0.03);
}
/* Same columns/gaps/aspect-ratio as .services-grid on the homepage — see
   the 900px/560px breakpoints below, which mirror .services-grid's own. */
.diensten-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  column-gap: clamp(20px, 3vw, 36px);
  row-gap: clamp(36px, 4.5vw, 56px);
  opacity: 1;
  visibility: visible;
  transition: opacity 0.3s ease, visibility 0s linear 0s;
}
.diensten-grid.is-fading {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.3s ease, visibility 0s linear 0.3s;
}
.dienst { min-width: 0; }

/* Same pattern as the homepage's .services-grid: a big placeholder box with
   the title below it as plain text, not a filled/bordered "card" wrapped
   around both. The <button> itself stays fully naked (no background, no
   padding) — only .dienst-icon gets the visual treatment and the hover
   lift, exactly like .service-card does on the homepage. */
.dienst-tile {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.dienst-tile:focus-visible {
  outline: 3px solid var(--green);
  outline-offset: 6px;
  border-radius: 14px;
}

.dienst-icon {
  width: 100%;
  aspect-ratio: 1 / 0.99; /* matches .service-card on the homepage */
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--card-radius);
  background: var(--placeholder);
  border: 1.5px dashed rgb(0 73 54 / 0.35);
  color: var(--ink-soft);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.dienst-tile:hover .dienst-icon {
  transform: translateY(-6px);
  box-shadow: 0 14px 30px rgb(0 73 54 / 0.12);
}
.dienst-title {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--green);
  font-size: 1.125rem;
  line-height: 1.25;
  margin-top: 18px;
}
/* The full description stays in the page source (content/SEO, and a
   sane no-JS fallback if it's ever un-hidden) but is only ever shown
   inside .dienst-detail once JS has copied its text there. */
.dienst-tile .dienst-text {
  display: none;
}

/* Detail view ---------------------------------------------------------- */
/* The outer box: this is the element the FLIP transform is applied to.
   It's always laid out at full size (inset: 0) — only its `transform`
   moves/shrinks it down to a tile's size, never its box model — so
   measuring it always gives the correct "grown" target rect. Kept as a
   plain, content-free positioning/clipping box; .dienst-detail-inner
   (below) carries the actual padding, scroll and content crossfade, so
   the two concerns (position/size vs. content visibility) never fight
   the same `transition` property. */
.dienst-detail {
  position: absolute;
  inset: 0;
  background: #fff;
  border-radius: var(--card-radius);
  box-shadow: 0 24px 48px rgb(0 73 54 / 0.12), 0 4px 14px rgb(0 0 0 / 0.06);
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  transform-origin: top left;
}
.dienst-detail.is-open {
  opacity: 1;
  pointer-events: auto;
}
/* Content only fades in once the card has (almost) finished growing —
   see the timed transition-delay js/main.js sets on open/close — so text
   is never visibly stretched by the outer box's scale transform. */
.dienst-detail-inner {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: clamp(28px, 3.6vw, 40px);
  overflow-y: auto;
  opacity: 0;
  transition: opacity 0.22s ease;
}
.dienst-detail.is-content-visible .dienst-detail-inner {
  opacity: 1;
}
.dienst-back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  align-self: flex-start;
  flex-shrink: 0;
  margin: 0 0 clamp(14px, 2vw, 20px) 2px;
  padding: 6px 4px;
  background: none;
  border: none;
  font: inherit;
  font-weight: 600;
  font-size: 0.9375rem;
  color: var(--green);
  cursor: pointer;
}
.dienst-back svg { width: 16px; height: 16px; transition: transform 0.2s ease; }
.dienst-back:hover { text-decoration: underline; }
.dienst-back:hover svg { transform: translateX(-3px); }
.dienst-back:focus-visible { outline: 3px solid var(--green); outline-offset: 3px; border-radius: 6px; }

.dienst-detail-title {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--green);
  font-size: clamp(1.25rem, 3vw, 1.5rem);
  line-height: 1.25;
  margin-bottom: 14px;
}
.dienst-detail-text {
  max-width: 56ch;
  margin: 0;
  font-size: 1rem;
  line-height: 1.6;
  color: var(--ink-soft);
}
.dienst-detail-extra {
  /* Content stays top-aligned rather than pinning this to the bottom of
     .dienst-detail — the panel's fixed height is set by the grid, which is
     taller than any single service's text, so pinning the button down
     would strand it below a large empty gap. Any leftover height just
     settles as trailing space under the button instead. */
  margin-top: clamp(24px, 3vw, 32px);
}

/* Case study page (e.g. ogd-verzuimloket.html) ----------------------------
   A long-form, single-project detail page reached from a Portfolio row.
   Reuses .page-hero/.scallops/.section-divider/.reveal/.custom-idea rather
   than inventing parallel components; everything below is genuinely new:
   the hero back-link + role tags, the two-phase (lo-fi/hi-fi) narrative
   sections, the "framed print" treatment for screenshots, the handwritten
   pull-quotes (lifted from the project's real research annotations), and
   the highlight band for the one concrete design-iteration story. */
.case-hero-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-bottom: clamp(20px, 3vw, 32px);
  font-size: 0.875rem;
  font-weight: 500;
  color: rgb(253 253 246 / 0.78);
  text-decoration: none;
}
.case-hero-back svg { width: 15px; height: 15px; transition: transform 0.2s ease; }
.case-hero-back:hover { color: var(--cream); }
.case-hero-back:hover svg { transform: translateX(-3px); }

.case-hero-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: clamp(20px, 3vw, 28px);
}
.case-hero-tags li {
  padding: 7px 16px;
  border: 1px solid rgb(253 253 246 / 0.3);
  border-radius: 999px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: rgb(253 253 246 / 0.88);
}

.case-intro {
  margin-top: 48px;
  background: var(--cream);
  padding-block: clamp(8px, 2vw, 16px) clamp(40px, 6vw, 64px);
}
.case-intro-text {
  max-width: 74ch;
  font-size: clamp(1.0625rem, 1.6vw, 1.1875rem);
  line-height: 1.7;
  color: var(--ink);
}

.case-section {
  background: var(--cream);
  padding-block: clamp(24px, 4vw, 40px) clamp(16px, 3vw, 32px);
}
.case-kicker {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--green);
  margin-bottom: 0.7em;
}
.case-kicker--light { color: rgb(253 253 246 / 0.72); }
.case-section h2 { font-size: clamp(1.7rem, 3vw, 2.4rem); }
.case-section-intro {
  max-width: 62ch;
  margin-top: 0.9em;
  color: var(--ink-soft);
  font-size: 1.0625rem;
}

.case-flow {
  margin-top: clamp(48px, 6vw, 72px);
}
.case-flow-title {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--green);
  font-size: clamp(1.25rem, 2vw, 1.5rem);
  margin-bottom: 0.6em;
}
.case-flow-text {
  max-width: 62ch;
  color: var(--ink-soft);
  margin-bottom: clamp(24px, 3vw, 32px);
}

.case-shots {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(20px, 3vw, 28px);
}
.case-shots--pair { grid-template-columns: repeat(2, 1fr); }
.case-shots--trio { grid-template-columns: repeat(3, 1fr); }
.case-shots--stack { gap: clamp(14px, 2vw, 20px); }

.case-shot { min-width: 0; }
.case-shot figcaption {
  margin-top: 12px;
  font-size: 0.8125rem;
  color: var(--ink-soft);
}

/* The "framed print" treatment: every screenshot — lo-fi grey wireframe or
   hi-fi branded mockup alike — sits on the same white mat with the site's
   premium-card shadow, so the visual inconsistency between the source
   exports (different backgrounds, different crops) reads as one deliberate
   presentation style rather than a pile of raw screenshots. */
.case-shot-frame {
  background: #fff;
  padding: clamp(10px, 1.4vw, 16px);
  border: 1px solid rgb(0 73 54 / 0.07);
  border-radius: var(--card-radius);
  box-shadow: 0 24px 48px rgb(0 73 54 / 0.07), 0 2px 10px rgb(0 0 0 / 0.03);
}
.case-shot-frame img {
  width: 100%;
  height: auto;
  border-radius: calc(var(--card-radius) - 10px);
}
.case-shot-frame--sub {
  max-width: 360px;
  margin-top: clamp(20px, 3vw, 28px);
}

/* Handwritten pull-quotes — genuine excerpts from the project's own
   research annotations, set in the site's existing (until now unused)
   hand font so they read as sticky-note research artifacts rather than
   marketing copy. Used sparingly, only where a real quote exists. */
.case-quote {
  max-width: 62ch;
  margin-top: clamp(20px, 3vw, 28px);
  padding-left: clamp(18px, 2.5vw, 24px);
  border-left: 3px solid var(--rust);
  margin-bottom: 48px;
  
}
.case-quote p {
  font-family: var(--font-hand);
  font-size: clamp(1.25rem, 2vw, 1.5rem);
  line-height: 1.4;
  color: var(--rust);
}
.case-quote p + p { margin-top: 0.4em; }
.case-quote--light { border-left-color: rgb(253 253 246 / 0.5); }
.case-quote--light p { color: rgb(253 253 246 / 0.92); }

/* Design-moment highlight — a full-width green band (same "cut from the
   page" language as .page-hero) reserved for the one documented design
   decision in the material: the process timeline's horizontal-to-vertical
   redesign. Treating it like a second, smaller hero signals it's the
   moment worth pausing on, rather than another row in the grid below. */
.case-highlight { background: var(--cream); }
.scallops--top { transform: rotate(180deg); }
.case-highlight-band {
  background: var(--green);
  color: var(--cream);
}
.case-highlight-inner {
  padding-block: clamp(40px, 6vw, 64px);
  display: grid;
  grid-template-columns: minmax(280px, 5fr) 7fr;
  gap: clamp(28px, 4vw, 56px);
  align-items: center;
}
.case-highlight-title { color: var(--cream); margin-bottom: 0.5em; }
.case-highlight-copy p { color: rgb(253 253 246 / 0.82); }
.case-highlight-media .case-shot-frame {
  border-color: transparent;
  box-shadow: 0 24px 48px rgb(0 0 0 / 0.22);
}

/* Hi-fi walkthrough rows — alternating image/text, same 5fr/7fr language
   as .hero-inner and .portfolio-item, flipped via a modifier rather than
   nth-child since each row lives in its own wrapper, not shared siblings. */
.case-row {
  display: grid;
  grid-template-columns: minmax(280px, 6fr) 6fr;
  gap: clamp(28px, 4vw, 56px);
  align-items: center;
  margin-top: clamp(48px, 6vw, 72px);
}
.case-row--flip .case-row-media { order: 2; }
.case-row--flip .case-row-text { order: 1; }
.case-row-text { max-width: 52ch; }
.case-row-text .case-flow-title { margin-top: 0; }
.case-row-text p { color: var(--ink-soft); margin-bottom: 1em; }
.case-row-text p:last-of-type { margin-bottom: 0; }

.case-reflect {
  background: var(--cream);
  padding-block: clamp(32px, 5vw, 48px) clamp(56px, 7vw, 88px);
}
.case-reflect .container p {
  max-width: 68ch;
  font-size: 1.0625rem;
  line-height: 1.7;
  color: var(--ink-soft);
}

.case-cta-inner { grid-template-columns: 1fr; max-width: 640px; }
/* .custom-copy's own bottom spacing (a large margin-bottom on desktop,
   dropped to 0 on mobile) exists to reserve room for .custom-art — the
   hands illustration that normally sits after it and supplies the mobile
   gap itself once it goes static (see the 720px breakpoint). This CTA
   reuses .custom-idea/.custom-copy but has no .custom-art, so without this
   override the mobile rule leaves it with zero space above the footer.
   Two-class selector, so this wins over both the desktop and mobile
   .custom-copy rules regardless of source order. */
.case-cta-inner .custom-copy {
  margin-bottom: 0;
  padding-bottom: clamp(48px, 7vw, 80px);
}
.case-cta-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 4px;
}
.btn--ghost {
  background: transparent;
  color: var(--green);
  box-shadow: inset 0 0 0 1.5px rgb(0 73 54 / 0.28);
}
.btn--ghost:hover {
  background: rgb(0 73 54 / 0.06);
  box-shadow: inset 0 0 0 1.5px var(--green);
}

/* Scroll reveal ---------------------------------------------------------- */
html.js .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}
html.js .reveal.is-visible {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  html.js .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .btn, .service-card, .nav-list a::after, .site-header, .logo img, .nav-list, .nav-toggle-bar { transition: none; }
  .btn:hover, .service:hover .service-card { transform: none; }
  /* The hide-on-scroll header is a motion effect; under reduced motion, js/main.js
     skips adding .is-hidden entirely, so it simply stays put. */
  html.js .hero-state.is-active,
  html.js .contact-state.is-active {
    animation: none;
  }
  html.js .success-icon {
    animation: none;
  }
  html.js .success-icon-check {
    animation: none;
    stroke-dashoffset: 0;
  }
  /* Expand/collapse still happens, just as an instant state swap — js/main.js
     also skips the whole FLIP grow/shrink animation under this same media
     query, going straight to the open/closed end state. */
  .dienst-icon, .diensten-grid, .dienst-detail, .dienst-detail-inner, .dienst-back {
    transition: none;
  }
}

/* Responsive ------------------------------------------------------------- */
@media (max-width: 900px) {
  .services-grid { grid-template-columns: repeat(2, 1fr); }
  .diensten-grid { grid-template-columns: repeat(2, 1fr); }
  /* --slides-per-view is already 2 by default (see .work-slider-track)
     while the site only has 2 projects, so no override is needed here. */
  .case-shots--trio { grid-template-columns: repeat(2, 1fr); }
  .case-highlight-inner { grid-template-columns: 1fr; }
  .case-highlight-media { max-width: 480px; }
}

@media (max-width: 760px) {
  .nav-toggle { display: inline-flex; }

  /* Dropdown panel: the desktop inline nav becomes a full-width sheet that
     drops down from the header. It's positioned relative to .site-header
     (the nearest positioned ancestor), so it always sits flush under the
     header regardless of the header's own scrolled/unscrolled height. */
  .nav-list {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    padding: 8px var(--gutter) 24px;
    background: var(--cream);
    border-top: 1px solid rgb(0 73 54 / 0.1);
    box-shadow: 0 20px 34px rgb(0 0 0 / 0.16);
    transform: translateY(-10px);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: transform 0.25s ease, opacity 0.2s ease, visibility 0s linear 0.25s;
  }
  .nav-list.is-open {
    transform: translateY(0);
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: transform 0.25s ease, opacity 0.2s ease, visibility 0s;
  }
  .nav-list a { padding-block: 13px; font-size: 1rem; }
  .nav-list a::after { content: none; }
  .nav-list .btn--nav { margin-top: 8px; text-align: center; }
  .is-scrolled .nav-list {
    background: var(--green);
    border-top-color: rgb(253 253 246 / 0.14);
  }
}

@media (max-width: 720px) {
  /* Hero: keep the lemur beside "Welkom" instead of stacking it underneath —
     the heading and image share a row, the paragraph and button then run
     full width below. Achieved by turning .hero-copy's box into `contents`
     so its children become direct grid items alongside .hero-art. */
  .hero-inner {
    grid-template-columns: minmax(0, 1fr) minmax(112px, 40%);
    grid-template-areas:
      "heading image"
      "text    image";
    align-items: start;
    column-gap: clamp(14px, 5vw, 24px);
    row-gap: 10px;
    margin-top: 0;
    padding-block: 28px 20px;
  }
  .hero-copy {
    display: contents;
    max-width: none;
  }
  .hero-copy h1 {
    grid-area: heading;
    font-size: clamp(1.6rem, 7.2vw, 2.2rem);
    margin-bottom: 0;
    align-self: center;
  }
  .hero-copy p {
    grid-area: text;
    max-width: none;
    margin-bottom: 0;
    font-size: 0.9375rem;
  }
  /* The hero's own Contact button is redundant on mobile — the "Iets
     anders?" section ends with the same CTA, so only that one shows. */
  .hero-copy .btn {
    display: none;
  }
  .hero-art {
    grid-area: image;
    justify-self: end;
    align-self: start;
    width: 100%;
  }
  .hero-img { margin-bottom: 0; }

  .about-copy { max-width: none; }

  .portfolio-item,
  .portfolio-link { grid-template-columns: 1fr; }
  .portfolio-copy { max-width: none; }
  .portfolio-summary { max-width: none; }

  .case-shots--pair,
  .case-shots--trio { grid-template-columns: 1fr; }
  .case-row {
    grid-template-columns: 1fr;
  }
  /* Row order always follows source order on mobile — the flip only makes
     sense as a side-by-side rhythm; stacked, alternating would just look
     random. */
  .case-row--flip .case-row-media,
  .case-row--flip .case-row-text { order: initial; }
  .case-row-text { max-width: none; }
  .case-shot-frame--sub { max-width: 320px; }

  .custom-inner { grid-template-columns: 1fr; }
  .custom-copy { padding-block: 40px 0; margin-bottom: 0; }
  .custom-art {
    position: static;
    min-height: 0;
    margin-top: 28px;
    margin-bottom: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
  }
  /* Arrow + "[ your brand ]" are a desktop-only flourish pointing at the
     custom-copy text beside them; on mobile that pairing is gone (stacked
     layout), so the pointing arrow has nothing to point at — drop both and
     keep just the hands illustration, centered. */
  .custom-art .art-arrow,
  .custom-art .art-brand {
    display: none;
  }
  .custom-art .art-hands {
    position: static;
    margin-top: 0;
    width: min(100%, 380px);
    align-self: center;
  }

  .footer-bottom {
    flex-direction: column;
    align-items: flex-start;
  }
}

@media (max-width: 480px) {
  .footer-main { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
  .services-grid { grid-template-columns: 1fr; }
  .service-card { aspect-ratio: 16 / 10.5; }
  .work-slider-track { --slides-per-view: 1; padding-inline: 0; }
  /* .work-slider-viewport's 34px inline padding (+ matching negative
     margin) exists so a hovered card's lifted box-shadow has room to bleed
     sideways without being clipped — see the comment on that rule. Hover
     doesn't fire on touch devices, so at this single-slide breakpoint that
     padding only costs something: it eats into the "current" card's own
     width from both sides, letting the *next* card's edge peek in at rest
     (reported as "a weird space" appearing on swipe). Zeroing it here makes
     one slide fill the viewport exactly, edge to edge, with nothing else
     visible until the swipe completes. */
  .work-slider-viewport {
    padding-inline: 0;
    margin-inline: 0;
    scroll-padding-left: 0;
  }
  /* Same reasoning as .service-card above: a square box at full mobile
     width would be needlessly tall once the grid drops to 1 column. */
  .dienst-icon { aspect-ratio: 16 / 10.5; }
  .service p { max-width: 42ch; }
  .logo img { width: 48px; }
  .nav-list { gap: 14px; }
  .nav-list a { font-size: 0.875rem; }
  .nav-list .btn--nav { padding: 7px 14px; }
  .diensten-grid { grid-template-columns: 1fr; }
}
