/* Site styles
 * Palette extracted from official huisstijl (visitekaartje + Insta + winkelraam):
 *   petrol blue · warm cream · off-white. Geen terracotta — niet in huisstijl.
 */

/* Self-hosted fonts — latin subset, woff2 only.
 * F-016 close-out: no more external font CDN; better privacy, faster TTFB. */
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/static/fonts/cormorant-garamond-400-italic.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: italic;
  font-weight: 500;
  font-display: swap;
  src: url('/static/fonts/cormorant-garamond-500-italic.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: italic;
  font-weight: 600;
  font-display: swap;
  src: url('/static/fonts/cormorant-garamond-600-italic.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Caveat';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/static/fonts/caveat-600-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/static/fonts/inter-400-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/static/fonts/inter-500-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/static/fonts/inter-600-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* theme tokens moved to site-tokens.css (loaded before this file) */

/* Reset */
*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Full-page snap-scroll: each section anchors to viewport top.
     Sets the brand storytelling rhythm — one section per scroll. */
  /* Geen scroll-snap meer — owner-designbesluit 2026-07-05: het snap-
     theater was 'te PowerPoint-achtig'. Eén kalme, vloeiende pagina op elk
     apparaat. De 76px offset houdt anker-sprongen onder de nav. */
  scroll-padding-top: 76px;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-snap-type: none; scroll-behavior: auto; }
}
body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--ink);
  /* Hi-res native paper master (2400×1758, downsampled from 4608×3376
     embedded raster in the original insta-post SVG). Used as a single
     cover image instead of a small repeat-tile so there are NO visible
     repeat-seams (the old 360×360 tile showed a regular dot-pattern). */
  background: url('/static/img/brand/paper-clean.jpg') center center / cover no-repeat, var(--paper);
  background-attachment: fixed;
  line-height: 1.65;
  font-size: 17px;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}

/* Snap-page-sections — minimum viewport-height so each one fills the
   screen; content vertically centered. Long content (lots of cards)
   may exceed 100vh — scroll continues until the next snap-point. */
/* Snap + full-viewport sections are the HOME one-pager's storytelling rhythm
   only (body.home). Deep public pages (over/aanbod/tarieven/klachten/contact)
   have a .about-hero <section> that must NOT stretch to 100vh or snap-stop —
   gating to body.home keeps them as normal documents. (admin/app already
   disable snap via their own overrides below.) */
.hero,
body.home main > section {
  position: relative;
  overflow: hidden;
  padding-top: clamp(4.5rem, 10vh, 8rem);
  padding-bottom: clamp(4.5rem, 10vh, 8rem);
}
/* De hero blijft de full-screen opener met nav-klaring. */
body.home main > .hero {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  justify-content: safe center;
  padding-top: calc(76px + 1.2rem);
}
/* Centred container inside a snap-section is full-width to allow
   left/right deco-blobs; inner content stays in the centred max-width. */
/* Horizontal centring only — a vertical `margin: auto` would re-introduce the
   both-sides overflow that `safe center` (above) exists to prevent. */
.hero > .container,
main > section > .container { margin: 0 auto; width: 100%; }
/* The hero's corner-leaf must grow THROUGH the transparent nav zone out of
   the screen's top edge (owner). The generic snap rule (body.home main >
   section, 0-1-3) silently out-ranks .hero's overflow:visible — restore it
   with matching weight; clip-path keeps left/right/bottom contained. */
body.home main > .hero { overflow: visible; }
/* Footer never snaps — it's a closer, not a chapter. */
.site-footer { scroll-snap-align: none; }
/* (No mobile scroll-padding/padding override: the nav measures 76px on
   mobile too — the old "shorter nav → 56px" assumption was wrong and left
   section headings 20px under the nav. Base rules apply on all widths.) */
@media (max-width: 760px) {
  /* Phones: the presentation model (one section = one screen) cannot exist
     here — sections are 1.5-2x the viewport, or mostly empty air when forced
     to 100dvh, and slow scrolling exposes every seam (owner review, with
     screenshots). So on mobile the one-pager is a NORMAL flowing page:
     no snap, content-height sections, no dead space. The desktop keeps the
     full snap presentation (sections genuinely fill the screen there). */
  html:has(body.home) { scroll-snap-type: none; }
  body.home main > section {
    scroll-snap-align: none;
    scroll-snap-stop: normal;
    min-height: 0;
    padding-top: clamp(3rem, 9vw, 4.5rem);
    padding-bottom: clamp(3rem, 9vw, 4.5rem);
  }
  /* The hero stays a full-screen opener (and clears the nav). Selector must
     out-rank the body.home main > section min-height reset above. */
  body.home main > .hero {
    scroll-snap-align: none;
    min-height: 100vh;
    min-height: 100dvh;
  }
  /* (#aanbod mobile padding restore removed 2026-07-06 — the band's
     bite-buyout padding is now breakpoint-proof by itself.) */
  /* The closing view (owner): the dark band must STOP exactly on the
     quote→contact boundary = the bar's underside, and below it PRAKTIJK +
     heading + fields + button + the complete footer fill the rest of the
     screen. min-height is DYNAMIC (100dvh − bar − measured footer; app.js
     sets --footer-h) so the boundary lands on the bar's edge at every
     viewport height; the compaction below makes the content fit the
     tightest phones (Safari bars expanded). */
  #contact {
    padding-top: 1.75rem;
    padding-bottom: 1.1rem;
    min-height: calc(100dvh - 76px - var(--footer-h, 164px));
  }
  #contact .contact-rows { gap: 0.85rem; margin-bottom: 1.6rem; }
  #contact .contact-card__title { margin-bottom: 1.4rem; }
  .site-footer__bar { padding-top: 0.65rem; padding-bottom: 0.65rem; }
}
img, svg { max-width: 100%; height: auto; display: block; }

/* Typography */
h1, h2, h3, h4 {  /* maat + ritme komen uit de STEM, zie vormtaal.css */
  font-family: var(--font-display);
  color: var(--petrol);
  font-weight: 500;
  letter-spacing: var(--kop-spatie);
  margin: 0 0 var(--kop-marge);
  line-height: var(--kop-lijn);
}
h1 { font-size: var(--kop-1); font-weight: 500; font-style: italic; }
h2 { font-size: var(--kop-2); font-style: italic; font-weight: 500; }
h3 { font-size: var(--kop-3); font-style: italic; font-weight: 500; }
h4 { font-size: var(--kop-4); font-family: var(--font-body); font-weight: 600; color: var(--petrol); letter-spacing: var(--label-spatie); }

/* ── Marketing-site headings: the visitekaart voice — clean bold SANS, not
   italic serif. Owner 2026-07-04: the Cormorant-italic headings "passen
   nergens op de site"; the business card (the real brand artifact) uses a
   bold sans. Scoped to the public/marketing context (home + classless public
   pages); the app / admin / auth keep their own type untouched. Inter tops out
   at 600 (no 700 face declared), so 600 = the heaviest real weight. ── */
body:not(.app):not(.admin):not(.auth) :is(h1, h2, h3) {
  font-family: var(--font-body);
  font-style: normal;
  font-weight: 600;
  letter-spacing: -0.01em;
}
p  { margin: 0 0 1em; }
a  {
  color: var(--petrol);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--cream-deep);
  transition: color var(--beweging-snel) var(--curve), text-decoration-color var(--beweging-snel) var(--curve);
}
a:hover { color: var(--petrol-deep); text-decoration-color: var(--petrol); }
small, .small { font-size: 0.875rem; color: var(--ink-soft); }
.muted { color: var(--muted); }
::selection { background: var(--cream); color: var(--petrol-deep); }

/* ── Native-app feel (installed PWA — iOS + Android) ──────────────────────────
   The member app must be indistinguishable from a native app (owner promise,
   2026-06-16): no web "tells". Kill the blue tap-flash, the double-tap-zoom
   delay, the rubber-band overscroll that reveals white, and the long-press
   callout/selection on UI chrome. Inputs + real content stay selectable. */
* { -webkit-tap-highlight-color: transparent; }
/* APP-SIDE ONLY (owner architecture 2026-07-05: the site is a website —
   pull-to-refresh and normal rubber-banding stay; the member/beheer app
   keeps the native no-web-tells feel). */
html:has(body.app), html:has(body.admin), html:has(body.auth),
body.app, body.admin, body.auth { overscroll-behavior: none; }
/* App, not a webpage: clip any residual horizontal overflow on the member shell
   too, so nothing can pan left-right (belt-and-suspenders with touch-action).
   APP-SIDE ONLY: overflow-x clip on html/body is a known iOS Safari
   pull-to-refresh blocker, and the site must behave like a website (owner).
   The public pages have zero horizontal overflow (audit-verified). */
html:has(body.app), html:has(body.admin), html:has(body.auth),
body.app, body.admin, body.auth { overflow-x: clip; }
a, button, [role="button"], summary, label, input[type="submit"],
.dtile, .cal-btn, .rk-btn, .cal-view, .cal-arrow, .site-nav__burger {
  touch-action: manipulation;
}
/* The app/admin/login shell behaves like native UI: no text-select, no callout,
   no pinch-zoom (pan-x pan-y allows scrolling but disables the zoom gesture —
   belt-and-suspenders with the viewport user-scalable=no). */
body.app, body.admin, .auth-wrap {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  touch-action: pan-x pan-y;
}
/* …but real fields + copyable content stay selectable. */
body.app input, body.app textarea, body.app select,
.auth-wrap input, .auth-wrap textarea,
body.app .selectable, body.app .app-row__what, body.app .cal-card__name,
body.app .cal-card__info, body.app .rk-card__body {
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}

/* Layout */
.container {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.section {
  position: relative;
  overflow: hidden;
}
/* Light sections all share the paper-fiber body bg so the texture
   flows continuously between sections (no visible boundary). Slight
   color tints applied via a translucent overlay so we still get the
   rhythm differentiation. */
/* Section bg overlays — kept as rgba so the body paper-texture shows
   through unaltered; tint differs per section to give each panel its
   own warmth. */
.section--cream      { background: var(--cream-a35); }
.section--cream-mist { background: var(--cream-a18); }
.section--paper      { background: transparent; }

/* ── Warme golf-band (design-pass): cream-sectie met dezelfde organische
   golfranden als de quote — geeft het pagina-ritme terug (papier → warm →
   papier → warm → petrol → papier) zonder één rechte lijn. ── */
/* Double class on purpose: (0,2,0) outranks the late mobile
   `.section { padding: 3.2rem 0 }` reset AND the plain .section base, so
   the bite-buyout padding below survives every breakpoint. */
.section.section--band {
  /* Plain: a band of colour with straight edges. The wave that used to be
     unconditional is one practice's signature -- days of work, and instantly
     recognisable across two boxes -- so it hangs on the shape switch now. */
  background: var(--cream-a50);
}

/* ── Foto-collage onder de hero — Instagram-taal: witte fotolijstjes,
   licht gedraaid, met de cream-blob-tekstkaart van de behandelaar in script. ── */
.collage { padding: clamp(1.6rem, 4vh, 3rem) 0 clamp(2.2rem, 5vh, 3.6rem); }
.collage__wrap {
  position: relative;
  display: grid;
  grid-template-columns: 1.35fr 1fr 1.1fr;
  gap: clamp(0.8rem, 2vw, 1.6rem);
  align-items: start;
}
.collage__photo {
  margin: 0;
  background: var(--white);
  padding: 8px 8px 12px;
  border-radius: 10px;
  box-shadow: 0 10px 30px var(--petrol-a14);
}
.collage__photo img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 6px;
  display: block;
}
/* One or two photos instead of three: the grid keeps its three columns and
   would leave a hole, so give the band exactly as many columns as it has
   frames. Zero photos never reach the CSS — the template drops the band. */
.collage__wrap--1 { grid-template-columns: 1fr; }
.collage__wrap--2 { grid-template-columns: 1.35fr 1fr; }
.collage__photo--a { transform: rotate(var(--tilt-a)); }
.collage__photo--b { transform: rotate(var(--tilt-b)) translateY(var(--tilt-lift)); }
.collage__photo--c { transform: rotate(var(--tilt-c)) translateY(calc(var(--tilt-lift) * 0.45)); }
.collage__blob {
  position: absolute;
  right: clamp(-6px, 1vw, 30px);
  bottom: clamp(-46px, -4vw, -24px);
  width: clamp(215px, 26vw, 330px);
  background: var(--cream-mist);
  border-radius: 56% 44% 52% 48% / 54% 50% 50% 46%;
  padding: clamp(1.4rem, 2.6vw, 2.2rem) clamp(1.5rem, 2.8vw, 2.4rem);
  text-decoration: none;
  box-shadow: 0 12px 34px var(--petrol-a16);
  transform: rotate(calc(var(--tilt-b) * 0.67));
  transition: transform var(--beweging-snel) var(--curve), box-shadow var(--beweging-snel) var(--curve);
}
.collage__blob:hover { transform: rotate(0.4deg) translateY(-3px); box-shadow: 0 16px 40px var(--petrol-a22); }
.collage__blob-script {
  display: block;
  font-family: var(--font-accent);
  font-size: clamp(1.5rem, 2.3vw, 1.9rem);
  line-height: 1.15;
  color: var(--petrol);
  margin-bottom: 0.35rem;
}
.collage__blob-sub {
  display: block;
  font-size: 0.85rem;
  color: var(--ink-soft);
  line-height: 1.45;
}
@media (max-width: 760px) {
  .collage__wrap { grid-template-columns: 1fr 1fr; }
  .collage__photo--c { display: none; }
  .collage__blob {
    position: static;
    width: auto;
    grid-column: 1 / -1;
    justify-self: center;
    max-width: 340px;
    margin-top: 0.4rem;
    transform: rotate(var(--tilt-c));
  }
}

/* ── Huisstijl-icoon op de aanbod-kaartfronten. ── */
/* Klacht-kaarten: sfeerfoto op de OPEN kaart, tussen de tekstblokken
   (owner 2026-07-06) — de fronts blijven schoon zodat de aanbod-iconen
   hun gewicht houden. Zachte unificatie-filter maakt zes bronnen één
   familie. */
.flip-card__inset {
  margin: 1rem 0 1.1rem;
}
.flip-card__inset img {
  width: 100%;
  aspect-ratio: 5 / 2;
  object-fit: cover;
  display: block;
  border-radius: var(--radius-md, 14px);
  filter: saturate(0.88) sepia(0.06);
}

.flip-card__icon {
  width: 46px;
  height: 46px;
  object-fit: contain;
  margin-bottom: 0.15rem;
  opacity: 0.92;
}
.section--paper-warm { background: var(--paper-warm-a50); }

body.home main { position: relative; }
/* Contain every edge-bleeding decoration horizontally at the MAIN level —
   html/body stay untouched so iOS pull-to-refresh keeps working. (Restoring
   the hero's overflow re-exposed horizontal panning on iOS: owner.) */
main { overflow-x: clip; }
.section--white      { background: var(--white-a55); }
.section--petrol     { background: var(--petrol); color: var(--cream-mist); }
/* De golfrand van deze band is vormtaal, geen product: hij hangt aan de
   keuze in het vormpakket, net als de warme band. Zonder keuze is deze
   sectie gewoon een vlak -- en dat is hoe een doos eruitziet die niemand
   heeft ingericht. */
[data-vorm-band="golf"] #quote {
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="none"><path d="M0,5 C12,1.5 22,7.5 34,5.5 C48,3 58,8 70,5.5 C82,3 92,7 100,4 L100,95.5 C88,99 76,93.5 64,96 C50,98.5 40,93 28,95.5 C16,98 8,93.5 0,96.5 Z" fill="black"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="none"><path d="M0,5 C12,1.5 22,7.5 34,5.5 C48,3 58,8 70,5.5 C82,3 92,7 100,4 L100,95.5 C88,99 76,93.5 64,96 C50,98.5 40,93 28,95.5 C16,98 8,93.5 0,96.5 Z" fill="black"/></svg>');
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
}

/* Boog: dezelfde gedachte, één rustige kromming. */
[data-vorm-band="boog"] #quote {
  -webkit-mask-image: radial-gradient(150% 64px at 50% 100%, var(--black) 99%, transparent 100%),
    radial-gradient(150% 64px at 50% 0, var(--black) 99%, transparent 100%),
    linear-gradient(var(--black), var(--black));
  mask-image: radial-gradient(150% 64px at 50% 100%, var(--black) 99%, transparent 100%),
    radial-gradient(150% 64px at 50% 0, var(--black) 99%, transparent 100%),
    linear-gradient(var(--black), var(--black));
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-size: 100% 64px, 100% 64px, 100% calc(100% - 124px);
  mask-size: 100% 64px, 100% 64px, 100% calc(100% - 124px);
  -webkit-mask-position: top, bottom, 0 62px;
  mask-position: top, bottom, 0 62px;
  padding-top: 5rem;
  padding-bottom: 5rem;
}
.section--petrol h1,
.section--petrol h2,
.section--petrol h3,
.section--petrol h4 { color: var(--cream); }
.section--petrol .section__kicker { color: var(--cream-deep); }
.section--narrow > .container { max-width: 760px; }

.grid {
  display: grid;
  gap: 1.1rem;
}
/* Een rij die niet volloopt hoort niet links te blijven hangen: met vijf
   kaarten in een rij van vier stond de vijfde alleen aan de rand. De laatste
   rij komt in het midden -- alles uitgelijnd, niets dat scheef staat. */
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); justify-content: center; }
.grid--3 > * { min-width: 0; }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }

/* Nav — fully transparent, no background layer at all. Three floating
   elements (logo center, Contact + Inloggen right) sit on top of the
   sections directly. No nav-bar = no horizontal seam between nav and
   section possible. The wrapper itself has pointer-events:none so the
   sections underneath remain interactive in the gaps; the children
   (brand + links) re-enable pointer events. */
.site-nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: transparent;
  border: 0;
  pointer-events: none;
  /* iOS standalone PWA (viewport-fit=cover + black-translucent status bar): the
     page background + decoration band fill UNDER the notch to the true top edge,
     but the nav/burger must sit below the status bar. env() is 0 in browsers
     that don't need it. */
  padding-top: env(safe-area-inset-top);
}
.site-nav > * { pointer-events: auto; }
/* Zodra je voorbij de hero bent krijgt de balk overal (desktop én mobiel)
   een licht papieren fond — vloeiende pagina's schuiven nu onder de balk
   door, en het logo is origineel donker (merkregel: lichte ondergrond). */
.site-nav { transition: background-color var(--beweging-snel) var(--curve), border-color var(--beweging-snel) var(--curve); }
body.scrolled .site-nav {
  background: var(--paper-a95);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--line-soft);
}
.site-nav__inner {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 76px;
  padding: 0.65rem 0 0.65rem var(--gutter);
  /* Full-width nav so the rightmost link sits flush with viewport edge */
}
.site-nav__brand {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  text-decoration: none;
}
.site-nav__logo {
  height: 56px;
  width: auto;
  display: block;
  transition: opacity var(--beweging-traag) var(--curve), transform var(--beweging-traag) var(--curve);
}
/* Alleen op de STARTPAGINA verstopt: daar draagt de hero het merk al. Elders is de
   balk het enige merkanker en het logo de enige weg terug. Tot 27-09-2026 gold dit
   overal: op /contractvrij stond het logo er aanklikbaar met opacity:0. */
body.home .site-nav__logo { opacity: 0; transform: translateY(-10px); }
body.home.scrolled .site-nav__logo { opacity: 1; transform: translateY(0); }
.site-nav__brand:hover { opacity: 0.85; }

/* Visually-hidden — for screen-reader text behind brand images */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* Skip-to-content — first focusable element in <body>. Off-screen until
   it receives keyboard focus, then slides into view so keyboard + screen-
   reader users can jump past the nav straight to <main>. */
.skip-link {
  position: absolute;
  left: 0.5rem;
  top: -3rem;
  z-index: 1000;
  background: var(--petrol);
  color: var(--white);
  padding: 0.5rem 0.9rem;
  border-radius: 0 0 6px 6px;
  text-decoration: none;
  transition: top var(--beweging-traag) var(--curve);
}
.skip-link:focus {
  top: 0;
}
.site-nav__links {
  list-style: none;
  margin: 0 0 0 auto;
  /* Right padding aligns the "Inloggen" button with the vertical snap-
     rail dots, which sit at right:1rem with ~12px width — so the login
     button's right edge meets the dots' line. */
  padding: 0 2rem 0 0;
  display: flex;
  gap: 1.5rem;
  flex-wrap: wrap;
  align-items: center;
}
.site-nav__links a {
  text-decoration: none;
  color: var(--petrol);
  font-weight: 500;
  font-size: 0.96rem;
  padding-bottom: 4px;
  border-bottom: 1.5px solid transparent;
  transition: border-color var(--beweging-snel) var(--curve);
}
.site-nav__links a:hover { border-bottom-color: var(--petrol); }
.site-nav__cta { margin-left: 0.5rem; }

/* Hero */
.hero {
  position: relative;
  /* No background overlay — hero shares the exact same paper-bg as the
     rest of the body, so nav + hero read as one continuous surface. */
  padding: 5.5rem 0 5rem;
  /* Override the section-base overflow:hidden so the TL-leaf can
     extend UP into the transparent nav-zone. clip-path keeps left,
     right and bottom edges clipped (no bleed into #aanbod below). */
  overflow: visible;
  clip-path: inset(-200px 0 0 0);
}
.hero__inner {
  max-width: 760px;
  margin: 0 auto;
  text-align: center;
  padding: 0 var(--gutter);
  position: relative;
  z-index: 2;
}
/* ── Hero welcome-sequence ─────────────────────────────────────────
   First-load: page elements are not all visible at once. Instead each
   piece arrives in sequence — paper bg → leaf grows out of the bar →
   logo scales in → tagline + lede settle in → CTAs appear. Feels like
   the practitioner greeting the visitor at the door, not a content-dump.
   Animations only run on first load (no replay on scroll-back). */
[data-vorm-onthaal="animatie"][data-vorm-onthaal="animatie"].js-ready .hero__logo,
[data-vorm-onthaal="animatie"][data-vorm-onthaal="animatie"].js-ready .hero__tagline,
[data-vorm-onthaal="animatie"][data-vorm-onthaal="animatie"].js-ready .hero__lede,
[data-vorm-onthaal="animatie"][data-vorm-onthaal="animatie"].js-ready .hero__ctas { opacity: 0; }
[data-vorm-onthaal="animatie"].js-ready .hero .deco-blob--tl {
  opacity: 0;
  animation: welcome-leaf 0.9s 0.15s var(--easing-soft) forwards;
}
/* Cluster on #home: animation fill-mode "both" — the from-state
   (opacity 0, offset transform) is applied DURING the 0.30s delay
   too, so the cluster never visibly snaps from its rest position
   into the offset position when the animation begins. */
[data-vorm-onthaal="animatie"].js-ready .hero .deco-blob--br {
  animation: welcome-cluster 1.0s 0.30s var(--easing-soft) both;
}
[data-vorm-onthaal="animatie"][data-vorm-onthaal="animatie"].js-ready .hero__logo    { animation: welcome-logo 1.2s 0.55s var(--easing-soft) forwards; }
[data-vorm-onthaal="animatie"][data-vorm-onthaal="animatie"].js-ready .hero__tagline { animation: welcome-rise 0.9s 1.00s var(--easing-soft) forwards; }
[data-vorm-onthaal="animatie"][data-vorm-onthaal="animatie"].js-ready .hero__lede    { animation: welcome-rise 0.9s 1.15s var(--easing-soft) forwards; }
[data-vorm-onthaal="animatie"][data-vorm-onthaal="animatie"].js-ready .hero__ctas    { animation: welcome-rise 0.8s 1.40s var(--easing-soft) forwards; }

@keyframes welcome-leaf {
  from { opacity: 0; transform: translateY(-40px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes welcome-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes welcome-logo {
  from { opacity: 0; transform: scale(0.94); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes welcome-rise {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: translateY(0); }
}
/* Cluster slides in diagonally from outside the BR corner via
   transform: translate (GPU-accelerated, no layout reflow). The
   .deco-blob[src$="cluster-br.svg"].deco-blob--br rule already sets
   transform: none on the cluster (no scale-flip), so the keyframe
   transform composes cleanly without any flip-rotation conflict. */
@keyframes welcome-cluster {
  from { opacity: 0; transform: translate(80px, 80px); }
  to   { opacity: 1; transform: translate(0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  [data-vorm-onthaal="animatie"][data-vorm-onthaal="animatie"].js-ready .hero__logo,
  [data-vorm-onthaal="animatie"][data-vorm-onthaal="animatie"].js-ready .hero__tagline,
  [data-vorm-onthaal="animatie"][data-vorm-onthaal="animatie"].js-ready .hero__lede,
  [data-vorm-onthaal="animatie"][data-vorm-onthaal="animatie"].js-ready .hero__ctas,
  [data-vorm-onthaal="animatie"].js-ready .hero .deco-blob { opacity: 1; transform: none; animation: none; }
}

.hero__logo {
  width: clamp(280px, 56vw, 520px);
  margin: 0 auto 1.4rem;
  display: block;
  height: auto;
}
/* De naam van de praktijk, als er geen woordmerk is.

   Deze regel bestond niet. De kop viel terug op de generieke h1 en stond dus in
   een andere letter dan de zin eronder -- op de doos die het product bouwde
   viel dat nooit op, want daar IS de naam een afbeelding en staat de h1
   verborgen. Elke praktijk zonder logo kreeg daardoor een slechtere kop dan de
   eerste. Dezelfde letter als de introzin, hetzelfde ritme als het woordmerk. */
.hero__title {
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 6.5vw, 4.4rem);
  line-height: 1.04;
  letter-spacing: -0.015em;
  font-weight: 600;
  color: var(--petrol);
  margin: 0 auto 1.4rem;
  max-width: 18ch;
  text-wrap: balance;
}

.hero__tagline {
  font-family: var(--font-body);
  font-size: 0.85rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--petrol-soft);
  margin: 0 0 2rem;
  font-weight: 600;
}
.hero__lede {
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(1.35rem, 2.6vw, 1.7rem);
  line-height: 1.5;
  color: var(--ink);
  margin: 0 auto 2.4rem;
  max-width: 580px;
  font-weight: 400;
}
.hero__ctas {
  display: flex;
  gap: 1rem;
  justify-content: center;
  flex-wrap: wrap;
}

/* Decorative blobs (organische shapes uit huisstijl) */
.deco-blob {
  position: absolute;
  pointer-events: none;
  user-select: none;
  z-index: 0;
}
.deco-blob--tl { top: -80px;  left: -100px; }
.deco-blob--tr { top: -80px;  right: -100px; transform: scaleX(-1); }
.deco-blob--bl { bottom: -80px; left: -100px; transform: scaleY(-1); }
.deco-blob--br { bottom: -80px; right: -100px; transform: scale(-1, -1); }
/* cluster-br source-shape is already BR-oriented: its clipped edges sit on
   the source bottom+right. Drop the 180° flip so those clipped edges sit
   off-viewport along the page corners and the organic curve faces inward. */
.deco-blob[src$="cluster-br.svg"].deco-blob--br { transform: none; }
/* Sizes scale with viewport — visitekaartje + insta have shapes at
   25-40% of canvas; we match that. clamp-max keeps mega-screens sane. */
.deco-blob--sm  { width: clamp(110px, 12vw, 200px); opacity: 0.88; }
.deco-blob--md  { width: clamp(160px, 18vw, 300px); opacity: 0.95; }
.deco-blob--lg  { width: clamp(220px, 26vw, 440px); opacity: 1.00; }
.deco-blob--xl  { width: clamp(280px, 32vw, 560px); opacity: 1.00; }
.deco-blob--soft { opacity: 0.55; }
.section .container,
.hero__inner { position: relative; z-index: 1; }

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.85rem 1.7rem;
  font-family: var(--font-body);
  font-size: 0.98rem;
  font-weight: 500;
  text-decoration: none;
  border-radius: var(--radius-pill);
  border: 1.5px solid transparent;
  cursor: pointer;
  transition: all var(--beweging-snel) var(--curve);
  line-height: 1.2;
  letter-spacing: 0.01em;
}
.btn--primary {
  background: var(--petrol);
  color: var(--cream-mist);
  border-color: var(--petrol);
}
.btn--primary:hover {
  background: var(--petrol-deep);
  border-color: var(--petrol-deep);
  color: var(--white);
  transform: translateY(-1px);
  box-shadow: var(--shadow-soft);
}
.btn--secondary {
  background: transparent;
  color: var(--petrol);
  border-color: var(--petrol);
}
.btn--secondary:hover {
  background: var(--petrol);
  color: var(--cream-mist);
}
.btn--ghost {
  background: var(--white);
  color: var(--petrol);
  border-color: var(--line);
}
.btn--ghost:hover {
  border-color: var(--petrol);
  color: var(--petrol-deep);
}
.btn--cream {
  background: var(--cream);
  color: var(--petrol-deep);
  border-color: var(--cream);
}
.btn--cream:hover {
  background: var(--cream-deep);
  border-color: var(--cream-deep);
}
.btn--small { padding: 0.55rem 1.1rem; font-size: 0.88rem; }
/* Touch a11y: buttons meet the 44px tap-target on coarse pointers only, so the
   desktop button rhythm is untouched. .btn is inline-flex+centred, so a
   min-height just grows short ones (e.g. .btn--small "Boek"/"Inloggen" ~36px). */
/* Touch targets ≥44px on coarse pointers (audit M4): the old rule only
   covered .btn, leaving bare submit buttons (auth pages, 26px high), the
   flip close/nav chips and small CTAs below the minimum. */
@media (pointer: coarse) {
  .btn,
  button[type="submit"],
  .flip-card__close,
  .flip-card__nav,
  .flip-card__cta,
  .card__cta { min-height: 44px; }
  .flip-card__close, .flip-card__nav { min-width: 44px; }
  .site-footer a { padding-block: 0.8rem; }
}

/* Sectie-koppen */
.section__kicker {
  font-family: var(--font-body);
  font-size: 0.78rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--petrol-soft);
  margin: 0 0 0.5rem;
  font-weight: 600;
}
/* Script-kicker (Instagram-taal, owner-approved richting v195): de
   conversationele kickers ("Loop je hier tegenaan?", "Dit ben ik") in het
   handschrift — zelfde Caveat als de collage-blob. Bewust maar op 2 plekken:
   meer wordt kermis. */
/* Dubbele class: .section__title p (0,1,1) zet anders de font-size terug. */
.section__kicker.section__kicker--script {
  font-family: var(--font-accent);
  font-size: 1.55rem;
  letter-spacing: 0.01em;
  text-transform: none;
  font-weight: 600;
  margin-bottom: 0.15rem;
}
.section__title {
  text-align: center;
  margin: 0 0 2rem;
}
.section__title h2 { margin-bottom: 0.6rem; }
.section__title p {
  color: var(--ink-soft);
  max-width: 560px;
  margin: 0 auto;
  font-size: 1.05rem;
}

/* Cards */
.card {
  background: var(--white);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  padding: 1.3rem 1.4rem;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  /* Slower + warmer ease so hover feels like a calm invitation, not a
     spring-snap. CTA underline also expands on card-hover. */
  transition:
    transform var(--beweging-snel) var(--curve),
    box-shadow var(--beweging-snel) var(--curve),
    border-color var(--beweging-snel) var(--curve);
}
.card:hover {
  transform: translateY(-5px);
  box-shadow: 0 14px 32px var(--petrol-a10);
  border-color: var(--petrol-soft);
}
.card__cta {
  border-bottom: 1px solid transparent;
  padding-bottom: 1px;
  transition: border-color var(--beweging-snel) var(--curve);
}
.card:hover .card__cta { border-bottom-color: var(--petrol); }
.card h3 {
  font-size: 1.35rem;
  margin: 0;
}
.card__meta {
  font-family: var(--font-body);
  font-size: 0.88rem;
  color: var(--petrol-soft);
  font-weight: 500;
  margin: 0;
  letter-spacing: 0.02em;
}
.card__body { color: var(--ink-soft); font-size: 0.98rem; margin: 0; flex: 1; line-height: 1.65; }
.card__cta {
  margin-top: 0.4rem;
  font-weight: 500;
  font-size: 0.95rem;
  text-decoration: none;
  color: var(--petrol);
  letter-spacing: 0.01em;
}
.card__cta:hover { color: var(--petrol-deep); }

/* Diensten — accent variant */
.card--accent {
  background: var(--cream-mist);
  border-color: var(--cream-deep);
}

/* #aanbod-only compression — 5 cards in a 3-col grid plus header
   exceeded the 100vh - 76px viewport budget on common laptop heights,
   leaving a ~1-tikje gap before scroll-snap engaged. Tighter paddings,
   gaps and line-heights here keep snap immediate without touching
   other sections. */
/* (Padding no longer compressed here: the snap-era override put the bottom
   card row inside the band's wave bite — the wave cut straight through the
   pop-up tile (owner-bug 2026-07-06). The .section--band bite-buyout padding
   now applies; it also clears the 76px nav at the top.) */
#aanbod .section__title { margin-bottom: 1.1rem; }
#aanbod .grid--3 { gap: 0.75rem; }
#aanbod .card { padding: 1rem 1.15rem; gap: 0.35rem; }
#aanbod .card__body { line-height: 1.5; font-size: 0.95rem; }

/* (The old owner-tweak that lifted these containers -1cm "so the title sits
   higher than vertical centre" is gone: the sections now start-align on
   overflow (`safe center`), which achieves the same intent — and with the nav
   overlaying the section top since the flush-snap fix, the -1cm shift pushed
   the kicker/heading INTO the nav zone on mobile (logo overprint). */

/* Klachten flip-card back — additional headers + bullet list that the
   #aanbod cards don't use. Tone-matched to the existing copy. */
.flip-card__subhead {
  font-family: var(--font-body);
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--petrol-soft);
  font-weight: 600;
  margin: 1.2rem 0 0.5rem;
}
.flip-card__list {
  list-style: none;
  margin: 0 0 0.85em;
  padding: 0;
}
.flip-card__list li {
  position: relative;
  padding-left: 1.2rem;
  margin-bottom: 0.35rem;
  font-size: 0.98rem;
  color: var(--ink-soft);
  line-height: 1.55;
}
.flip-card__list li::before {
  content: "—";
  position: absolute;
  left: 0;
  color: var(--cream-deep);
}
.flip-card__back-ctas {
  display: flex;
  gap: 1.2rem;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 1rem;
}
.flip-card__cta-secondary {
  font-family: var(--font-body);
  font-size: 0.9rem;
  color: var(--ink-soft);
  text-decoration: none;
  border-bottom: 1px dashed var(--line-soft);
  padding-bottom: 1px;
  transition: color var(--beweging-snel) var(--curve), border-color var(--beweging-snel) var(--curve);
}
.flip-card__cta-secondary:hover {
  color: var(--petrol);
  border-color: var(--petrol-soft);
}

/* ─── Flip-cards (#aanbod) ──────────────────────────────────────────
 *
 * Default state: each .flip-card sits in the .grid--flip grid like a
 * normal card. A click adds .is-open to the card and .has-flip-open
 * to <body>; the card transforms from its grid position to a centred
 * fixed-position panel and its inner faces flip 180° to reveal the
 * back. Closing reverses both at once.
 *
 * The grid keeps its placeholder space via grid-area while a card is
 * open so the rest of the layout doesn't reflow — preventing the page
 * from jumping when an item lifts out and back in.
 */
.grid--flip {
  /* perspective lives on the card itself (not the grid) — putting it
     on the grid creates a containing block that traps the .is-open
     card's `position: fixed` inside the section, defeating the modal
     escape and putting the backdrop above the card. */
  align-items: stretch;
}
.flip-card {
  position: relative;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  min-height: 220px;
  perspective: 1600px;
  /* No transform-transition here — open/close use @keyframes which
     don't play well alongside a transition watching the same property
     (caused a "slide in from bottom-right" extra animation). */
}
/* Once the card opens we drop perspective again so the inner element
   isn't a perspective-context root while it's also acting as a fixed
   modal. The flip animation still works via the inner's own
   transform-style: preserve-3d. */
.flip-card.is-open { perspective: none; }
.flip-card__inner {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 220px;
  transform-style: preserve-3d;
  transition: transform var(--beweging-omslag) var(--curve);
}
.flip-card__face {
  position: absolute;
  inset: 0;
  background: var(--white);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  padding: 1.3rem 1.4rem;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  overflow: hidden;
}
/* Closed state: the front lives in normal flow so the CARD grows with its
   content — with both faces absolute the card was stuck at min-height and
   clipped longer fronts (owner 2026-07-06: hint/tekst 'valt overal buiten',
   pop-up tile text cut). Open state (fixed modal) keeps the absolute face. */
.flip-card:not(.is-open) .flip-card__front {
  position: relative;
  inset: auto;
  min-height: 100%;
}
.flip-card__front {
  transition:
    transform var(--beweging-snel) var(--curve),
    box-shadow var(--beweging-snel) var(--curve),
    border-color var(--beweging-snel) var(--curve);
}
.flip-card:hover .flip-card__front {
  transform: translateY(-4px);
  box-shadow: 0 14px 32px var(--petrol-a10);
  border-color: var(--petrol-soft);
}
.flip-card__back {
  transform: rotateY(180deg);
  background: var(--cream-mist, var(--sand));
  display: flex;
  flex-direction: column;
}
.flip-card--accent .flip-card__front {
  background: var(--cream-mist);
  border-color: var(--cream-deep);
}

/* ── Panel variant (#over flip-fold, OPORD 02): a lone full-width card whose
   FRONT is an existing page strip, 1:1 — so the front is chromeless (no white
   card, no padding) and RELATIVE: it drives the closed card's height instead
   of the absolute-face box. The back keeps the familiar card-back look. ── */
.flip-card--panel .flip-card__inner { height: auto; }
.flip-card--panel .flip-card__front {
  position: relative;
  background: transparent;
  border: 0;
  padding: 0;
  overflow: visible;
}
/* No lift/shadow on hover — the front is page content, not a card. The
   "Lees mijn verhaal →" hint is the affordance. */
.flip-card--panel:hover .flip-card__front {
  transform: none;
  box-shadow: none;
  border-color: transparent;
}
/* The panel hint IS the opener (not the whole strip) — style it as the
   ghost button it used to be, so it reads as clearly tappable. */
.flip-card--panel .flip-card__more {
  margin-top: 0.4rem;
  display: inline-block;
  /* neutralize the circled-arrow base geometry — this one is a text button */
  width: auto;
  height: auto;
  align-self: flex-start;
  font-size: 0.84rem;
  border: 1px solid var(--petrol);
  border-radius: var(--radius-pill);
  padding: 0.5rem 1.2rem;
  color: var(--petrol);
  cursor: pointer;
}
.flip-card--panel .flip-card__more:hover {
  background: var(--petrol);
  color: var(--cream-mist);
}
/* Once open the flip geometry takes over; give the front its card chrome back
   so the close-flip doesn't flash an unstyled face. */
.flip-card--panel.is-open .flip-card__front {
  background: var(--white);
  position: absolute;
}

.flip-card__kicker {
  font-family: var(--font-body);
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--petrol-soft);
  font-weight: 600;
  margin: 0;
}
.flip-card__front h3 {
  margin: 0;
  font-size: 1.35rem;
}
.flip-card__hint {
  font-family: var(--font-body);
  font-size: 0.92rem;
  color: var(--petrol);
  font-weight: 500;
  margin: 0 0 0.35rem;
}
/* Arrow-only opener hint (owner 2026-07-06: 'overal klik hier' was noise
   and overflowed the cards) — one quiet circled arrow, bottom-right. */
.flip-card__more {
  margin-top: auto;
  align-self: flex-end;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 1.5px solid var(--petrol-soft);
  border-radius: 50%;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--petrol);
  line-height: 1;
}

/* Back: scrollable content with two photo zones (top + inline) and CTA */
.flip-card__back {
  padding: 0;
}
.flip-card__close,
.flip-card__nav {
  position: absolute;
  z-index: 10;
  background: var(--white-a95);
  border: 1px solid var(--line-soft);
  color: var(--petrol);
  cursor: pointer;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 0;
  font-family: var(--font-display);
  line-height: 1;
  box-shadow: 0 6px 18px var(--petrol-a10);
  transition: background var(--beweging-snel) var(--curve), color var(--beweging-snel) var(--curve), transform var(--beweging-snel) var(--curve);
}
.flip-card.is-open .flip-card__close,
.flip-card.is-open .flip-card__nav { display: flex; }

.flip-card__close {
  top: 1rem;
  right: 1rem;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  font-size: 1.6rem;
}
.flip-card__close:hover { background: var(--petrol); color: var(--cream); }

/* ←/→ carousel-navigation chips — deliberately subtle so they don't
   pull focus from the card content. Faint chrome at rest, fill in
   petrol on hover. Mobile shrinks them a notch in the media query. */
.flip-card__nav {
  top: 50%;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  font-size: 1.35rem;
  padding-bottom: 0.18em;
  transform: translateY(-50%);
  /* Solid, clearly visible chips (owner review: the ghost-transparent
     arrows were invisible until you hunted for them, and the tapped one
     stuck in its hover state — 'half half, ligt aan richting'). */
  background: var(--white-a95);
  border: 1px solid var(--line-soft);
  color: var(--petrol);
  opacity: 1;
  box-shadow: 0 4px 14px var(--petrol-a16);
}
.flip-card__nav--prev { left: 0.7rem; }
.flip-card__nav--next { right: 0.7rem; }
.flip-card__nav:hover {
  background: var(--petrol);
  border-color: var(--petrol);
  color: var(--cream);
  opacity: 1;
  transform: translateY(-50%) scale(1.04);
}

.flip-card__back-photo {
  position: relative;
  background: linear-gradient(
    135deg,
    var(--cream-deep, var(--sand-deep)),
    var(--cream-mist, var(--sand-warm)) 55%,
    var(--line-soft)
  );
  overflow: hidden;
  flex-shrink: 0;
}
.flip-card__back-photo--top {
  width: 100%;
  height: 28vh;
  min-height: 160px;
  max-height: 280px;
}
/* Real photo fills the placeholder container, the gradient + label
   sit behind as a fallback skeleton if the image hasn't loaded yet. */
.flip-card__photo-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Klachten cards skip the photo-banner — owner doesn't want lifestyle
   imagery next to medical content. The back-body gets a thin petrol
   accent strip on top to keep the visual separation a banner provided. */
/* (Old 3px petrol top-strip removed 2026-07-06: the mid-text inset photo
   now carries the atmosphere, and a straight accent line breaks the
   no-straight-lines rule.) */
.flip-card__back-body--no-banner {
  padding-top: 1.8rem;
}
.flip-card__back-photo--inline {
  width: 100%;
  max-width: 260px;
  aspect-ratio: 5 / 4;
  border-radius: 14px;
  float: right;
  margin: 0.3rem 0 0.6rem 1.4rem;
  shape-outside: margin-box;
}
.flip-card__photo-inner {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-body);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--petrol);
  opacity: 0.5;
}
.flip-card__back-body {
  padding: 1.4rem clamp(1.5rem, 5vw, 3.5rem) 1.8rem;
  overflow-y: auto;
  flex: 1;
  /* Constrain text-column on wide opened cards so reading doesn't
     sprawl the full 1200px width. */
  max-width: 880px;
  margin: 0 auto;
  width: 100%;
}
.flip-card__back-body::after { content: ""; display: table; clear: both; }
.flip-card__back-body h3 {
  margin: 0 0 0.3rem;
  font-size: 1.4rem;
}
.flip-card__meta {
  font-family: var(--font-body);
  font-size: 0.9rem;
  color: var(--petrol-soft);
  margin: 0 0 0.9rem;
  letter-spacing: 0.01em;
}
.flip-card__back-body p {
  font-size: 0.98rem;
  line-height: 1.6;
  color: var(--ink-soft);
  margin: 0 0 0.85em;
}
.flip-card__cta {
  display: inline-block;
  margin-top: 0.6rem;
  font-weight: 500;
  font-size: 0.95rem;
  color: var(--petrol);
  text-decoration: none;
  border-bottom: 1px solid var(--cream-deep);
  padding-bottom: 2px;
  transition: color var(--beweging-snel) var(--curve), border-color var(--beweging-snel) var(--curve);
}
.flip-card__cta:hover { color: var(--petrol-deep); border-color: var(--petrol); }

/* Open state — almost full viewport with thin translucent margin.
 *
 * `.snap-reveal` is intentionally NOT applied to flip-cards (see
 * home.html) so its transform/opacity rules can't overwrite the
 * centering transform here. Plain rules suffice.
 */
.flip-card.is-open {
  position: fixed;
  top: 50%;
  left: 50%;
  /* Default transform is centred — JS overrides via inline style as
     it drives the FLIP-style animation. The default here prevents the
     "card appears at top-left" flash that happens when the class
     applies before JS has a chance to set its first inline transform. */
  transform: translate(-50%, -50%);
  z-index: 200;
  width: min(1200px, 96vw);
  max-width: 96vw;
  height: 90vh;
  max-height: 90vh;
  cursor: default;
  /* Picture-in-picture depth — multi-layer shadow makes the card
     look like it has lifted forward from the page. */
  box-shadow:
    0 60px 140px var(--petrol-a42),
    0 28px 60px var(--petrol-a26),
    0 10px 22px var(--black-a14);
  border-radius: 22px;
  /* transform is managed inline by flip.js so we can run a true
     FLIP-style two-phase animation: phase 1 zooms the card forward
     from its grid position to viewport-center; phase 2 (controlled
     via .is-flipped on the card itself) rotates the inner 180°. */
}
.flip-card.is-open .flip-card__inner {
  height: 100%;
  min-height: 0;
  /* The flip rotation only fires once .is-flipped lands, so the
     card finishes zooming forward before it spins. */
}
.flip-card.is-open.is-flipped .flip-card__inner {
  transform: rotateY(180deg);
}

/* Close-shrink: while the card frame is animating from full-size
   back to its grid slot, the inner content would otherwise reflow
   (long h3 wrapping into 3 narrow lines, etc) and read as a "blob".
   Fade the faces out in sync with the shrink so the reflow is
   invisible; snapHome() drops .is-open after, returning the card to
   its grid-rendered front face. */
.flip-card.is-open.is-shrinking .flip-card__face {
  opacity: 0;
  transition: opacity var(--beweging-traag) var(--curve);
}
.flip-card.is-open:hover .flip-card__front {
  transform: none;
  box-shadow: none;
  border-color: var(--line-soft);
}
.flip-card.is-open .flip-card__face { border-radius: 18px; }

/* Placeholder slot in the grid while a card is open — keeps layout stable */
.flip-card.is-placeholder {
  visibility: hidden;
}

/* Backdrop — stays *under* the open card. Strong blur sells the
 * picture-in-picture-feel without taking focus off the lifted card. */
.flip-backdrop {
  position: fixed;
  inset: 0;
  background: var(--petrol-a55);
  backdrop-filter: blur(8px) saturate(0.85);
  -webkit-backdrop-filter: blur(8px) saturate(0.85);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--beweging-traag) var(--curve);
  /* Hard upper-bound: never above the open card (z-index 200). */
  z-index: 100;
}
body.has-flip-open .flip-backdrop {
  opacity: 1;
  pointer-events: auto;
}
body.has-flip-open {
  overflow: hidden;
}

/* Pop-up section inside the back: past events + voting */
.popup-section-title {
  font-family: var(--font-body);
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--petrol-soft);
  font-weight: 600;
  margin: 1.2rem 0 0.55rem;
}
.popup-past {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
}
.popup-past li {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 0.9rem;
  row-gap: 0.1rem;
  padding: 0.55rem 0;
  border-bottom: 1px dashed var(--line-soft);
  font-size: 0.92rem;
}
.popup-past li:last-child { border-bottom: 0; }
.popup-past__when {
  grid-column: 1;
  grid-row: 1;
  font-family: var(--font-display);
  font-style: italic;
  color: var(--petrol);
  font-weight: 500;
}
.popup-past__title {
  grid-column: 2;
  grid-row: 1;
  font-weight: 600;
  color: var(--ink);
}
.popup-past__line {
  grid-column: 2;
  grid-row: 2;
  color: var(--ink-soft);
  font-size: 0.88rem;
}

.popup-poll { display: grid; gap: 0.5rem; }
.popup-poll__row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.7rem 0.8rem;
  align-items: center;
  padding: 0.55rem 0.7rem;
  background: var(--white);
  border: 1px solid var(--line-soft);
  border-radius: 10px;
  transition: border-color var(--beweging-snel) var(--curve);
}
.popup-poll__row.is-voted { border-color: var(--cream-deep); background: var(--paper-warm-a70); }
.popup-poll__copy { display: flex; flex-direction: column; gap: 0.05rem; }
.popup-poll__title { margin: 0; font-weight: 600; font-size: 0.94rem; color: var(--ink); }
.popup-poll__blurb { margin: 0; font-size: 0.84rem; color: var(--ink-soft); }
.popup-poll__action { display: flex; gap: 0.6rem; align-items: center; }
.popup-poll__btn {
  background: var(--petrol);
  color: var(--cream);
  border: 0;
  padding: 0.4rem 0.85rem;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  transition: background var(--beweging-snel) var(--curve);
}
.popup-poll__btn:hover { background: var(--petrol-deep); }
/* A visitor is invited, not refused: the same row, the same count, a way in
   instead of a button. Quieter than the vote button on purpose -- it is an
   offer, not the primary action of the page. */
.popup-poll__join {
  display: inline-flex; align-items: center; gap: 0.35rem; white-space: nowrap;
  padding: 0.4rem 0.85rem; border-radius: 999px; text-decoration: none;
  border: 1px solid var(--petrol); color: var(--petrol);
  font-size: 0.82rem; font-weight: 500; transition: background var(--beweging-snel) var(--curve), color var(--beweging-snel) var(--curve);
}
.popup-poll__join:hover { background: var(--petrol); color: var(--cream); }
.popup-poll__voted {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.82rem;
  color: var(--petrol);
  font-weight: 500;
}
.popup-poll__count {
  font-family: var(--font-body);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--petrol);
  min-width: 1.6rem;
  text-align: right;
}
.popup-poll__lede { margin: 0 0 0.6rem; font-size: 0.84rem; color: var(--ink-soft); }
.popup-poll__footnote {
  margin: 0.9rem 0 0;
  font-size: 0.85rem;
  color: var(--ink-soft);
  font-style: italic;
}

/* Reduced-motion — skip the 3D flip, just cross-fade faces */
@media (prefers-reduced-motion: reduce) {
  .flip-card__inner { transition: none; }
  .flip-card.is-open .flip-card__inner { transform: none; }
  .flip-card__back { transform: none; opacity: 0; transition: opacity var(--beweging-traag) var(--curve); }
  .flip-card.is-open .flip-card__back { opacity: 1; }
  .flip-card.is-open .flip-card__front { opacity: 0; }
}

/* Mobile */
@media (max-width: 760px) {
  .flip-card.is-open {
    width: 96vw;
    height: 92vh;
    max-height: 92vh;
  }
  .flip-card__back-photo--inline {
    max-width: 100%;
    float: none;
    margin: 0.7rem 0;
  }
  .flip-card__back-body {
    padding: 1rem 1.1rem 1.4rem;
  }
  .flip-card__back-photo--top {
    height: 22vh;
    min-height: 130px;
  }
  /* Smaller nav chips on mobile + lift slightly off the edge so the
     thumb-safe area is clear. */
  .flip-card__nav {
    width: 32px; height: 32px;
    font-size: 1.1rem;
    padding-bottom: 0.15em;
  }
  .flip-card__nav--prev { left: 0.35rem; }
  .flip-card__nav--next { right: 0.35rem; }
  .flip-card__close { top: 0.6rem; right: 0.6rem; width: 36px; height: 36px; font-size: 1.4rem; }
}

/* Rooster — schedule list */
.schedule {
  background: var(--white);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-soft);
}
.schedule__row {
  display: grid;
  grid-template-columns: 7rem 5rem 1fr;
  gap: 1rem;
  align-items: center;
  padding: 1.1rem 1.7rem;
  border-bottom: 1px solid var(--line-soft);
  transition: background var(--beweging-snel) var(--curve);
}
.schedule__row:hover { background: var(--cream-mist); }
.schedule__row:last-child { border-bottom: 0; }
.schedule__day {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.2rem;
  color: var(--petrol);
  font-weight: 600;
}
.schedule__time { font-weight: 600; color: var(--petrol-soft); }
.schedule__name { color: var(--ink); }

/* Quote / testimonial */
.quote {
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(1.4rem, 2.6vw, 1.7rem);
  line-height: 1.5;
  color: var(--petrol);
  border-left: 3px solid var(--cream-deep);
  padding: 0.4rem 0 0.4rem 1.6rem;
  margin: 0 0 0.6rem;
  font-weight: 400;
  position: relative;
}
.quote::before {
  content: '\201C';
  position: absolute;
  left: -0.4rem;
  top: -1.5rem;
  font-size: 4rem;
  color: var(--cream-deep);
  font-family: var(--font-display);
  font-style: italic;
  line-height: 1;
}
.quote__author {
  font-family: var(--font-body);
  font-style: normal;
  font-size: 0.92rem;
  color: var(--ink-soft);
  letter-spacing: 0.04em;
}

/* Hero-variant of the quote: bigger, centered, with a large
   ornamental open-quote-mark above. Used in the petrol-anchor
   section so it reads as the emotional highlight of the page. */
.quote-section .container { max-width: 760px; position: relative; }
.quote--hero {
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(1.6rem, 3.2vw, 2.4rem);
  line-height: 1.45;
  color: var(--cream-mist);
  text-align: center;
  border: none;
  padding: 0;
  margin: 0 auto 1.5rem;
  position: relative;
  z-index: 2;
}
.quote--hero::before {
  content: '\201C';
  display: block;
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(5rem, 9vw, 7.5rem);
  line-height: 0.85;
  color: var(--cream-deep);
  opacity: 0.75;
  position: static;
  text-align: center;
  margin-bottom: 0.4rem;
}
.quote-section .quote__author {
  text-align: center;
  display: block;
  color: var(--cream-deep);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-size: 0.82rem;
  position: relative;
  z-index: 2;
}

/* Over-blok korte versie op homepage */
.about-strip {
  display: grid;
  grid-template-columns: 1fr 1.4fr;
  gap: 3rem;
  align-items: center;
}
/* No portrait -> one column. The photo frame is not rendered at all (F2),
   and a two-column grid would push the text into half a page. */
.about-strip--no-photo { grid-template-columns: 1fr; }
.about-strip__photo {
  background: var(--cream) center/cover no-repeat;
  aspect-ratio: 4/5;
  border-radius: var(--radius-lg);
  min-height: 280px;
  position: relative;
  display: grid;
  place-items: center;
  color: var(--petrol-soft);
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.05rem;
  overflow: hidden;
  box-shadow: var(--shadow-card);
}
.about-strip__photo picture, .about-strip__photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}
/* Lessen — uitnodigende groepsfoto boven de CTA */
.lessen-photo {
  max-width: 860px;
  margin: 1.6rem auto 1.8rem;
}
.lessen-photo img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  display: block;
}

/* Reviews — echte Google-reviews in de polaroid/Instagram-taal van de
   collage: witte kaarten, subtiel gedraaid, script-naam, gouden sterren. */
.reviews-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2.5vw, 2rem);
  align-items: start;
}
.review-card {
  margin: 0;
  background: var(--white);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: 1.5rem 1.5rem 1.3rem;
}
.review-card:nth-child(1) { transform: rotate(calc(var(--tilt-a) * 0.7)); }
.review-card:nth-child(2) { transform: rotate(calc(var(--tilt-b) * 0.5)); margin-top: 1.1rem; }
.review-card:nth-child(3) { transform: rotate(calc(var(--tilt-c) * 0.75)); }
.review-card__stars { color: var(--amber-deep); letter-spacing: 0.18em; margin-bottom: 0.6rem; }
.review-card blockquote {
  margin: 0 0 0.9rem;
  font-size: 0.98rem;
  line-height: 1.65;
  color: var(--ink);
}
.review-card figcaption { display: flex; align-items: baseline; gap: 0.6rem; }
.review-card__name { font-family: var(--font-accent); font-size: 1.35rem; color: var(--petrol); }
.review-card__via { font-size: 0.78rem; color: var(--ink-soft); }
@media (max-width: 900px) {
  .reviews-grid { grid-template-columns: 1fr; }
  .review-card:nth-child(2) { margin-top: 0; }
}
.about-body img { border-radius: var(--radius-lg); }
.reviews-more { text-align: center; margin: 2rem 0 0; }
.reviews-more a { color: var(--petrol); font-weight: 500; }

/* Contact — visitekaart composition (owner-approved reference, 2026-07-04):
   heading + icon rows left-aligned in ONE centered column, CTA below. The
   icons are the brand contact figures (petrol, varying canvas ratios — a
   fixed square box + object-fit:contain keeps the row rhythm even). */
.contact-card { max-width: 520px; margin: 0 auto; }
.contact-card__title { text-align: left; margin-bottom: 2.2rem; }
.contact-card__title p { margin: 0; }
.contact-rows {
  list-style: none;
  margin: 0 0 2.4rem;
  padding: 0;
  display: grid;
  gap: 1.15rem;
}
.contact-rows li {
  display: flex;
  align-items: center;
  gap: 1.05rem;
  font-size: 1.08rem;
  color: var(--ink);
}
.contact-rows a { color: var(--petrol); }
.contact-rows__icon {
  width: 28px;
  height: 28px;
  object-fit: contain;
  flex: 0 0 auto;
}
.contact-cta { text-align: left; margin-top: 0; }
/* Inline message form on the visitekaart (the /contact page is retired):
   big message field first, name + e-mail compact on one row below. */
.contact-form { text-align: left; }
.contact-form label {
  display: block;
  font-weight: 600;
  margin: 0 0 0.35rem;
}
.contact-form textarea { resize: vertical; min-height: 6.5rem; }
.contact-form__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin-top: 0.9rem;
}
.contact-form__row span { display: block; }
.contact-form .contact-cta { margin-top: 1.4rem; }
@media (max-width: 560px) {
  .contact-form__row { grid-template-columns: 1fr; }
}

/* Footer */
/* Slim closing bar (doelfeel): ONE thin line on paper — no more petrol
   banner, no duplicated contact block, no headings (so no heading-order
   concerns). Text = ink-soft for AA contrast on the translucent paper bg. */
.site-footer {
  /* Geen harde border — de balk vloeit op via een gradient (owner: geen
     rechte lijnen). */
  background: linear-gradient(to bottom, var(--paper-a00) 0, var(--paper-a85) 26px, var(--paper-a85) 100%);
  color: var(--ink-soft);
  font-size: 0.85rem;
  position: relative;
}
.site-footer a {
  color: var(--petrol-soft);
  text-decoration-color: var(--cream-deep);
}
.site-footer a:hover { color: var(--petrol); text-decoration-color: var(--petrol-soft); }
.site-footer__bar {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.45rem 1.1rem;
  padding-top: 0.9rem;
  padding-bottom: 0.9rem;
  text-align: center;
}
.site-footer__sep { opacity: 0.45; }
.site-footer__version { opacity: 0.5; font-size: 0.75rem; }

/* Inline list */
.inline-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  font-size: 0.96rem;
}

/* Over-pagina */
.about-hero {
  text-align: center;
  padding: 4.5rem 0 2.5rem;
  background: var(--cream-mist);
  position: relative;
  overflow: hidden;
}
.about-hero h1 { margin-bottom: 0.4rem; }
.about-hero p {
  color: var(--ink-soft);
  max-width: 540px;
  margin: 0 auto;
  font-size: 1.05rem;
}

.about-body {
  max-width: 720px;
  margin: 0 auto;
  padding: 3.5rem var(--gutter);
}
.about-body p { font-size: 1.08rem; line-height: 1.75; }
.about-body h2 { margin-top: 2.6rem; }

.opleidingen {
  list-style: none;
  padding: 0;
  margin: 1rem 0 0;
  display: grid;
  gap: 0.6rem;
}
.opleidingen li {
  padding: 0.8rem 1.1rem;
  border-left: 3px solid var(--cream-deep);
  background: var(--cream-mist);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-size: 0.96rem;
}
.opleidingen li strong { color: var(--petrol); font-weight: 600; }

/* Aanbod-pagina */
.aanbod-list { display: grid; gap: 1.8rem; }
.aanbod-item {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 2rem;
  padding: 2.2rem;
  background: var(--white);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  align-items: start;
  transition: box-shadow var(--beweging-snel) var(--curve), border-color var(--beweging-snel) var(--curve);
}
.aanbod-item:hover { box-shadow: var(--shadow-card); border-color: var(--cream-deep); }
.aanbod-item h2 { margin: 0 0 0.4rem; font-size: 1.7rem; }
.aanbod-item__meta {
  font-family: var(--font-body);
  font-size: 0.86rem;
  color: var(--petrol-soft);
  font-weight: 500;
  margin: 0 0 1rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.aanbod-item__price {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.6rem;
  color: var(--petrol);
  text-align: right;
  min-width: 140px;
  font-weight: 600;
}
.aanbod-item__price small {
  display: block;
  font-family: var(--font-body);
  font-style: normal;
  font-size: 0.78rem;
  color: var(--ink-soft);
  letter-spacing: 0.05em;
  font-weight: 400;
}

/* Note-block (callout) */
.note {
  background: var(--cream-mist);
  border-left: 3px solid var(--cream-deep);
  padding: 1.2rem 1.4rem;
  border-radius: 0 var(--radius) var(--radius) 0;
  margin: 2rem 0;
  font-size: 0.98rem;
  color: var(--ink);
}
.note strong { color: var(--petrol); }

/* Breadcrumb (klacht-pagina's, etc.) */
.breadcrumb {
  font-family: var(--font-body);
  font-size: 0.86rem;
  color: var(--petrol-soft);
  letter-spacing: 0.05em;
  margin-bottom: 1rem;
}
.breadcrumb a {
  color: var(--petrol-soft);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.breadcrumb a:hover { border-bottom-color: var(--petrol-soft); }
.breadcrumb span { color: var(--petrol); }

/* Tables (cookie-overview etc.) */
.cookie-table {
  width: 100%;
  border-collapse: collapse;
  margin: 1.4rem 0 2rem;
  font-size: 0.96rem;
  background: var(--white);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-soft);
}
.cookie-table thead {
  background: var(--cream-mist);
}
.cookie-table th {
  text-align: left;
  font-family: var(--font-body);
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--petrol);
  font-weight: 600;
  padding: 0.95rem 1.1rem;
  border-bottom: 1px solid var(--line-soft);
}
.cookie-table td {
  padding: 1rem 1.1rem;
  vertical-align: top;
  border-bottom: 1px solid var(--line-soft);
  color: var(--ink);
}
.cookie-table tbody tr:last-child td { border-bottom: 0; }
.cookie-table code {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
  background: var(--cream-mist);
  padding: 0.12em 0.4em;
  border-radius: 0.3em;
  font-size: 0.92em;
  color: var(--petrol-deep);
}

/* Privacy bullet-list */
.privacy-list {
  list-style: none;
  padding: 0;
  margin: 1rem 0 1.6rem;
}
.privacy-list li {
  position: relative;
  padding: 0.5rem 0 0.5rem 1.6rem;
  line-height: 1.6;
}
.privacy-list li::before {
  content: '';
  position: absolute;
  left: 0.3rem;
  top: 1.05rem;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--cream-deep);
}
.privacy-list strong { color: var(--petrol); font-weight: 600; }

/* PWA toast (update-available + install-prompt) */
.fmm-toast {
  position: fixed;
  left: 1rem;
  right: 1rem;
  bottom: 1rem;
  max-width: 480px;
  margin-left: auto;
  background: var(--petrol);
  color: var(--cream-mist);
  border-radius: var(--radius-lg);
  box-shadow: 0 10px 32px var(--petrol-a28);
  padding: 0.85rem 1.1rem;
  display: flex;
  gap: 0.7rem;
  align-items: center;
  z-index: 110;
  font-size: 0.94rem;
  font-family: var(--font-body);
}
.fmm-toast strong { color: var(--white); }
.fmm-toast__btn {
  background: var(--cream);
  color: var(--petrol-deep);
  border: none;
  border-radius: var(--radius-pill);
  padding: 0.4rem 0.9rem;
  font-family: var(--font-body);
  font-size: 0.88rem;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
}
.fmm-toast__btn:hover { background: var(--cream-deep); }
.fmm-toast__close {
  background: transparent;
  color: var(--cream-mist);
  border: none;
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 0.2rem;
  opacity: 0.75;
}
.fmm-toast__close:hover { opacity: 1; }
.fmm-toast--install { background: var(--petrol-deep); }
@media (max-width: 540px) {
  .fmm-toast { left: 0.6rem; right: 0.6rem; bottom: 0.6rem; padding: 0.7rem 0.85rem; font-size: 0.9rem; }
  .fmm-toast span { flex: 1; }
}

/* Cookie-notice banner (info-only, first-visit dismissible) */
.cookie-notice {
  position: fixed;
  /* Left-bottom corner — keeps the cluster decoration in the
     bottom-right unobstructed. */
  left: 1rem;
  bottom: 1rem;
  max-width: 420px;
  background: var(--white);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  box-shadow: 0 10px 32px var(--petrol-a18);
  padding: 1.1rem 1.3rem;
  z-index: 100;
  display: none;
  font-size: 0.94rem;
  line-height: 1.55;
  color: var(--ink);
}
.cookie-notice[data-show="true"] { display: block; }
.cookie-notice__body {
  margin: 0 0 0.8rem;
}
.cookie-notice__body strong { color: var(--petrol); }
.cookie-notice__actions {
  display: flex;
  gap: 0.7rem;
  flex-wrap: wrap;
  align-items: center;
}
.cookie-notice__dismiss {
  background: var(--petrol);
  color: var(--cream-mist);
  border: 1.5px solid var(--petrol);
  border-radius: var(--radius-pill);
  padding: 0.5rem 1.1rem;
  font-family: var(--font-body);
  font-size: 0.88rem;
  font-weight: 500;
  cursor: pointer;
  transition: background var(--beweging-snel) var(--curve);
}
.cookie-notice__dismiss:hover { background: var(--petrol-deep); }
.cookie-notice__link {
  color: var(--petrol);
  font-size: 0.88rem;
  text-decoration: underline;
  text-decoration-color: var(--cream-deep);
  text-underline-offset: 3px;
}
@media (max-width: 540px) {
  .cookie-notice { left: 0.6rem; right: 0.6rem; bottom: 0.6rem; padding: 0.95rem 1rem; }
}

/* Snap-reveal: section content fades + lifts when the section enters
   the viewport. Hidden state only applied once JS sets .js-ready so
   no-JS users + headless screenshots always see content. */
/* Geen verschijn-theater meer (owner-designbesluit 2026-07-05, samen met
   het snap-vertrek): content is gewoon zichtbaar. De hero houdt z'n eigen
   eenmalige welkomst-animatie; .in-view blijft bestaan voor de rail/hash. */
.js-ready section[data-snap-page] .snap-reveal { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js-ready section[data-snap-page] .snap-reveal { opacity: 1; transform: none; transition: none; }
}
/* Phones: no reveal theatre — content is simply always visible. On a free-
   scrolling page the fade-ins fire at arbitrary scroll moments and can be
   manipulated by scrubbing (owner review: 'ik kan het bewust manipuleren,
   overgangen liggen bloot'). The desktop snap presentation keeps them. */
@media (max-width: 760px) {
  .js-ready section[data-snap-page] .snap-reveal { opacity: 1; transform: none; transition: none; }
}

/* Side-rail anchor-dots — indicates which section is in view + quick jump. */
.snap-rail {
  position: fixed;
  right: 1rem;
  top: 50%;
  transform: translateY(-50%);
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding: 0.6rem 0.4rem;
}
/* The anchor is a >=24px touch target (WCAG 2.5.8); the visible 10px dot
   is drawn by ::before so the click/tap area is comfortable without
   enlarging the dot itself. */
.snap-rail__dot {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  cursor: pointer;
  text-decoration: none;
}
.snap-rail__dot::before {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--cream-deep);
  border: 1.5px solid var(--petrol-soft);
  transition: transform var(--beweging-snel) var(--curve), background var(--beweging-snel) var(--curve);
}
.snap-rail__dot:hover::before { transform: scale(1.25); }
/* a11y: keyboard focus ring on the section dots (was hover-only). */
.snap-rail__dot:focus-visible { outline: 2px solid var(--petrol); outline-offset: 2px; border-radius: 50%; }
.snap-rail__dot:focus-visible::before { transform: scale(1.25); }
.snap-rail__dot.is-active::before {
  background: var(--petrol);
  border-color: var(--petrol);
  transform: scale(1.35);
}
@media (max-width: 760px) { .snap-rail { display: none; } }

/* Form-basics */
input, textarea, select, button {
  font-family: var(--font-body);
  font-size: 1rem;
}
input[type="text"], input[type="email"], input[type="password"],
input[type="tel"], input[type="number"], textarea, select {
  width: 100%;
  padding: 0.75rem 0.95rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--white);
  color: var(--ink);
  transition: border-color var(--beweging-snel) var(--curve), box-shadow var(--beweging-snel) var(--curve);
}
input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--petrol);
  box-shadow: 0 0 0 3px var(--petrol-mist);
}
label {
  font-weight: 500;
  color: var(--petrol);
  display: block;
  margin: 0 0 0.4rem;
  font-size: 0.92rem;
}

/* Responsief */
@media (max-width: 760px) {
  .site-nav__inner { gap: 0.6rem; padding: 0.7rem var(--gutter); }
  .site-nav__wordmark { height: 26px; }
  .site-nav__links { gap: 0.9rem; font-size: 0.92rem; }
  /* Keep the Inloggen/Ingelogd chip visible on phones — hiding it left
     mobile visitors (F2's core audience) with NO route into the member
     portal (audit high). It fits: the nav carries only one other link. */
  .site-nav__cta { padding: 0.4rem 0.9rem; font-size: 0.88rem; }
  /* De gecentreerde merknaam liep over de rechts-uitgelijnde links op ~390px. Op smal scherm
     alles op EEN rij: merknaam links (krimpt + kapt af), Contact en Inloggen rechts naast
     elkaar -- niet meer intern wrappen, want dat gaf een 'piramide'. */
  .site-nav__brand { position: static; transform: none; flex: 0 1 auto; min-width: 0; overflow: hidden; }
  .brand-name { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .site-nav__links { flex-wrap: nowrap; flex: 0 0 auto; }
  .about-strip { grid-template-columns: 1fr; gap: 1.5rem; }
  .schedule__row {
    grid-template-columns: 6rem 1fr;
    padding: 0.95rem 1.1rem;
  }
  .schedule__time { grid-column: 2; }
  .schedule__name { grid-column: 1 / -1; padding-left: 6rem; padding-top: 0.2rem; margin-top: -0.4rem; color: var(--ink-soft); font-size: 0.95rem; }
  .aanbod-item { grid-template-columns: 1fr; gap: 1rem; padding: 1.6rem; }
  .aanbod-item__price { text-align: left; }
  .section { padding: 3.2rem 0; }
  .hero { padding: 4rem 0 3rem; }
  /* Decoration on mobile: only a corner-peek, never crowds content. */
  .deco-blob--xl { width: 210px; opacity: 0.95; }
  .deco-blob--lg { width: 120px; }
  .deco-blob--md { width: 100px; }
  .deco-blob--sm { width: 72px; }
  .deco-blob--tl { top: -100px; left: -30px; }
  .deco-blob--tr { top: -60px;  right: -60px; }
  .deco-blob--bl { bottom: -60px; left:  -60px; }
  .deco-blob--br { bottom: -60px; right: -60px; }
}
@media (max-width: 480px) {
  /* Very narrow phones: stick to a small petrol leaf top-left, drop the rest. */
  /* Mobiel hero-accent = ALLEEN het blad uit de schermhoek (owner 2026-07-06:
     de boog oogde als een misplaatst fragment op telefoons — die is voor de
     desktop-hoek ontworpen). */
  .deco-blob--tl { width: 195px; top: -95px; left: -55px; }
  .hero .deco-blob--br { display: none; }
}

/* --- /beheer admin panel: not the marketing scroll-snap story -------------
   Admin pages reuse base.html but are a functional control panel. Disable the
   full-viewport section heights + snap-scroll there so the page is compact and
   the whole menu is visible without scrolling through full-screen sections. */
body.admin { scroll-snap-type: none; }
body.admin main > section {
  min-height: 0;
  scroll-snap-align: none;
  scroll-snap-stop: normal;
}

/* --- OPORD-F: member dashboard header (/mijn) -----------------------------
   The "Hoi <naam>" greeting above the fixed tile grid. Works on body.app
   member pages, so no scroll-snap override needed here. */
.dash-head { margin: 1.5rem 0 1rem; }
.dash-head h1 { margin: 0 0 0.2rem; }
.dash-head p { margin: 0; color: var(--ink-soft); }

.dash-logout { margin-top: 1.5rem; text-align: center; }
/* Logout buttons (dashboard + drawer) in taupe, not the white outline — owner
   2026-06-15 ("everything has a colour, no more white"). Pill-shaped like the
   other buttons — Pico's default square box was the only straight-cornered
   thing on screen and clashed with the organic, rounded style (owner). */
.dash-logout button,
.site-nav__drawer-logout button {
  background: var(--taupe); color: var(--petrol-deep); border: 1px solid var(--black-a08);
  box-shadow: var(--shadow-soft); border-radius: 999px;
  display: inline-block; width: auto; padding: 0.5rem 1.5rem; font-weight: 600;
}
.dash-logout button:hover,
.site-nav__drawer-logout button:hover { background: var(--taupe-2); }

/* Slim member-app footer (replaces the marketing teal band on /mijn pages). */
.app-footer {
  margin-top: 2.5rem;
  padding: 1.25rem var(--gutter);
  text-align: center;
  font-size: 0.85rem;
  color: var(--muted);
  border-top: 1px solid var(--line-soft);
}
.app-footer a { color: var(--muted); text-decoration: none; }
.app-footer a:hover { color: var(--petrol); text-decoration: underline; }

/* --- App brand backdrop (the locked look): soft paper + the decoration band
       top + bottom, low opacity, fixed behind everything (z-index:-1) so it
       falls away behind the tiles. --------------------------------------------- */
body.app, body.auth {
  /* Trying Flexa "Firm Berry Pure" (var(--rose)) as the app background — the practitioner's
     pick (owner 2026-06-15). Flat for now so the true colour shows; can be
     softened into a berry "paper" with subtle depth if wanted. The cream-paper
     version is kept here in case we revert:
       radial-gradient(120% 80% at 100% 0, var(--mint-pale-2) 0, transparent 55%),
       radial-gradient(100% 70% at 0 100%, var(--sand-pale) 0, transparent 50%), var(--paper); */
  background: var(--rose);
  background-attachment: fixed;
}
/* Auth pages (login/register/wachtwoord) carry the same berry to the body so no
   white strip shows under the card on the installed app (home-indicator zone /
   overscroll). The .auth-wrap does the centring itself. (Owner 2026-06-16.) */
body.auth { min-height: 100dvh; }
/* ONE app content width for EVERY member page — the content scales to a sensible
   desktop size and stays consistent across all tiles; the decoration band stays
   full-bleed behind it. On a phone it's full-width with comfortable side padding. */
body.app main#main { max-width: 1080px; margin-inline: auto; padding-inline: max(20px, env(safe-area-inset-left)) max(20px, env(safe-area-inset-right)); box-sizing: border-box; }
/* App-wide brand backdrop = the approved decoration band, fixed top + bottom
   behind the tiles (z-index:-1), low opacity. */
.dash-deco { position: fixed; left: 0; width: 100%; pointer-events: none; user-select: none; z-index: -1; opacity: .16; }
/* The BOTTOM band is gone (owner decision 2026-07-13): iOS moved the element
   in the DOM but never on screen, a full day was lost, and a clean berry
   bottom edge is identical on every device by definition. The top band
   stays (owner-approved). Bring a bottom band back only via a mock-first
   owner keuring — and not as a fixed z-index:-1 element on iOS. */
/* Same band 180°-flipped; flat baseline on the top edge (invisible), all shapes
   organic → no straight line. */
.dash-deco--top { top: -24px; transform: scale(-1, -1); }
/* On a narrow phone the band would scale to a thin sliver — widen it (approved
   locked value). */
@media (max-width: 600px) {
  /* Mobile = the SAME single background as desktop, only its DIMENSIONS are
     recomputed for the narrow screen (owner steer 2026-06-15: "one background
     for both views that every page inherits; take desktop's proportions +
     opacity and recompute them for mobile; top AND bottom; everything falls
     behind the tiles"). Desktop = width:100% → band ≈ 27% of the viewport
     height; matching that proportion on a 390px screen needs ≈ 340% width.
     Centered, top + bottom, inherits the locked .16 opacity. Flat baselines
     stay bled off the top/bottom edges (scale(-1,-1) top) → no straight cuts.
     NOTE: keep the zoom close to desktop (≈100–150%) — zooming far in (340%)
     showed only the smooth INTERIOR of one shape = read as flat. Over the berry
     ground the shapes shift the colour only subtly at .16; desktop gets away
     with it because its band is large, but at mobile size .16 nearly vanishes —
     so the mobile opacity is bumped (~.40) to match desktop's VISIBLE presence.
     Desktop base stays the locked .16 (guarded). */
  /* Bigger so the bands reach further toward the middle (owner 2026-06-15:
     in proportion to desktop). Edge connection kept (right:0 + top/bottom bleed
     unchanged) so the arcs/blobs still meet the screen edges nicely. */
  /* max-width:none is REQUIRED — the global `img{max-width:100%}` reset (line
     ~161) was silently capping the band at 100%, so every width > 100% here was
     a no-op (the band stayed a thin sliver). With the cap lifted, width drives
     how far the bands reach toward the middle. */
  .dash-deco { width: 230%; max-width: none; left: auto; right: 0; opacity: .40; }
  /* Lift the content up on mobile so the bottom tile / logout no longer hug the
     screen edge — trim the top margin and add bottom breathing room (the fixed
     deco band then shows in that gap behind the content). Owner 2026-06-15. */
  body.app main#main { padding-bottom: calc(28px + env(safe-area-inset-bottom)); }
  /* Compact the dashboard on mobile so the whole stack sits higher and the
     bottom tile lifts well off the screen edge (it was scrolling with the last
     tile 22px from the bottom). Trim the tall banner + the tile chips; text
     stays readable. Owner 2026-06-15. Desktop untouched (guard green). */
  body.app .dash-head { margin-top: 0.4rem; margin-bottom: 0.55rem; }
  body.app .dash { gap: 10px; margin-bottom: 0.9rem; }
  body.app .dtile { min-height: 92px; padding: 11px 10px 10px; gap: 6px; }
  body.app .dtile__chip { width: 44px; height: 44px; border-radius: 13px; }
  body.app .dtile__chip img { width: 37px; height: 37px; }
  body.app .dash-feat { padding: 13px 18px; }
  body.app .dash-feat__big { font-size: 1.38rem; }
  body.app .dash-feat__cta { margin-top: 7px; }

  /* Dashboard locked to one screen WITHOUT resizing the tiles (owner 2026-06-16:
     "iets omhoog en vastzetten, niet resizen"). Keep the natural tile sizes;
     just pull the whole stack up (tighter header + banner spacing) so it fits,
     and lock the scroll. Only the home (/mijn). */
  /* Auto-adapt: on phones tall enough (iPhone 14 Pro+, Pixel) the stack fits, so
     there is simply nothing to scroll = locked. On a very small/old screen it
     scrolls gracefully instead of clipping. Never resizes the tiles. */
  body.app-home { overflow-y: auto; }
  /* The burger OVERLAYS (absolute) instead of taking a row of its own, so "Hoi
     Carla" sits up beside it — this is what reclaims the vertical space (the
     sticky nav was pushing the whole stack ~100px down). */
  body.app-home .site-nav { position: absolute; top: 0; left: 0; right: 0; }
  body.app-home main#main {
    padding-top: env(safe-area-inset-top);
    padding-bottom: max(8px, env(safe-area-inset-bottom));
  }
  body.app-home .dash-head { margin-top: 0; margin-bottom: 0.4rem; }
  body.app-home .dash-head h1 { font-size: 2rem; }
  body.app-home .dash-feat { padding: 11px 16px; }
  body.app-home .dash { margin-bottom: 0; }
}

/* "De onderrand" + native on EVERY device/screen size (owner hard rule,
   2026-06-16): fill the screen and centre the member content with flexbox at
   EVERY width — device-height independent, NO magic pixel guess. body fills
   100dvh, main grows into the leftover space, the content block centres via
   margin:auto (collapses to normal top-aligned scroll when content is genuinely
   taller — no clip, no forced scroll). The owner-locked deco band then frames
   the content edge instead of floating in a berry gap. 100dvh (not 100vh) so the
   mobile URL bar never forces a scroll. Band itself untouched. */
body.app { min-height: 100dvh; display: flex; flex-direction: column; }
body.app main#main { flex: 1 0 auto; display: flex; flex-direction: column; }
/* Sub-pages: the back button stays at the top; the content block centres. */
body.app:not(.app-home) main#main > .rk-wrap,
body.app:not(.app-home) main#main > .cal-wrap { margin-block: auto; }
/* Dashboard: no back button — centre the whole stack. */
body.app-home main#main { justify-content: center; }

/* --- Member calendar pages: the calendar is FIXED, only the lessons scroll ---
   (owner 2026-07-12). The whole page is pinned to the viewport; the header, the
   month grid and the legend never move. The ONLY scroller is the day's lesson
   list: ~3 lessons show, a 4th+ scrolls inside that little box — and its thin
   scrollbar only appears when there is actually something to scroll. Scoped via
   :has(.cal-wrap) so the other member pages are untouched.

   Gated to roomy viewports (min 760x760): only a desktop/tablet with enough
   vertical space gets the pinned calendar. On a phone — or a short window — the
   page keeps normal document flow, so the lessons ALWAYS render under the grid.
   The fixed shell was collapsing the lesson panel to nothing on small screens,
   so a tapped day showed no lessons at all (owner 2026-07-13). */
@media (min-width: 760px) and (min-height: 760px) {
body.app:has(.cal-wrap) { height: 100dvh; overflow: hidden; }
body.app:has(.cal-wrap) main#main { flex: 1 1 auto; min-height: 0; overflow: hidden; }
body.app:has(.cal-wrap) main#main > .cal-wrap {
  margin-block: 0; height: 100%; min-height: 0;
  display: flex; flex-direction: column;
  /* Vangnet: op een hoog scherm past alles en scrollt dit NIET (kalender vast,
     geen balk). Op een kort scherm (mobiel) mag de wrap inline scrollen zodat de
     lessen altijd bereikbaar blijven — op mobiel is die balk overlay/onzichtbaar. */
  overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}
/* Everything except the lessons stays put. */
body.app:has(.cal-wrap) .cal-head,
body.app:has(.cal-wrap) .cal-month,
body.app:has(.cal-wrap) .cal-legend { flex: 0 0 auto; }
/* The day panel now lives inside the member pages' .page-body wrapper (the
   month grid moved out to the fixed zone) — keep the flex chain intact so
   the panel/week/day scrollers below still get their height. */
body.app:has(.cal-wrap) main#main > .cal-wrap > .page-body {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; overflow: hidden;
}
/* Month view: the day-panel fills the leftover space; only its lesson list
   scrolls (capped to ~3 lessons, shrinks gracefully on short screens). */
body.app:has(.cal-month) .cal-daypanel {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; overflow: hidden;
}
body.app:has(.cal-month) .cal-daypanel .cal-cards--day {
  flex: 1 1 auto; min-height: 0; max-height: 19rem;
  overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin;
}
/* Week / day view: their own grid is the scroller so nothing clips. */
body.app:has(.cal-week) .cal-week,
body.app:has(.cal-daylist) .cal-daylist {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
}
/* With the grid pinned, the square month cells were too tall to leave room for
   the lessons underneath. In this fixed layout the cells go a touch flatter and
   the header tightens, so ~3 lessons fit below the grid (owner 2026-07-12). */
body.app:has(.cal-month) .cal-cell { aspect-ratio: 8 / 5; }
body.app:has(.cal-month) .cal-head { margin-bottom: 0.5rem; }
body.app:has(.cal-month) .cal-head h1 { font-size: 1.4rem; margin-bottom: 0.35rem; }
body.app:has(.cal-month) .cal-lede { margin: 0.1rem 0 0.6rem; }
body.app:has(.cal-month) .cal-nav { margin-top: 0.5rem; }
body.app:has(.cal-month) .cal-daypanel { margin-top: 0.5rem; }
} /* end @media (min-width:760px) and (min-height:760px) — roomy-viewport pin */

/* --- Clean fixed dashboard grid (replaces the GridStack layout) ----------- */
.dash { display: grid; grid-template-columns: repeat(2, 1fr); gap: 13px; margin: 0 0 1.5rem; }
.dash-feat {
  grid-column: 1 / -1;
  display: flex; flex-direction: column; gap: 2px;
  background: linear-gradient(135deg, var(--petrol), var(--petrol-deep));
  color: var(--mint-pale); border-radius: var(--radius-lg); padding: 18px 20px;
  box-shadow: 0 10px 30px var(--petrol-a14); text-decoration: none; position: relative; overflow: hidden;
}
/* Brand mark (sun + waves) integrated into the banner as a soft watermark —
   replaces the plain circle so the logo feels part of the app (owner). */
.dash-feat::after {
  content: ""; position: absolute; right: 14px; top: 14px;
  width: 96px; height: 60px;
  background: url('/static/img/brand/mark.png') no-repeat right top / contain;
  filter: brightness(0) invert(1); opacity: 0.12;
}
.dash-feat__k { font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--mint-deep); font-weight: 600; }
.dash-feat__big { font-family: var(--font-display); font-size: 1.6rem; font-weight: 600; margin: 3px 0 1px; }
.dash-feat__sub { color: var(--mint); font-size: 0.9rem; }
.dash-feat__cta { margin-top: 11px; align-self: flex-start; background: var(--cream); color: var(--petrol-deep); font-weight: 600; font-size: 0.85rem; padding: 8px 16px; border-radius: 99px; }
.dtile {
  /* Card colour is set in the experiment block at the end of the file (Gentle
     Tundra sage). Base keeps the warm paper + dark text as the fallback. */
  background: var(--paper-warm); border: 1px solid var(--line-soft); border-radius: var(--radius-lg);
  padding: 18px 14px 16px; box-shadow: var(--shadow-soft); text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 8px; min-height: 128px; justify-content: center;
  text-decoration: none; color: var(--ink); transition: transform var(--beweging-snel) var(--curve), box-shadow var(--beweging-snel) var(--curve);
}
.dtile:hover { transform: translateY(-4px); box-shadow: var(--shadow-card); }
.dtile__chip { width: 52px; height: 52px; border-radius: 16px; background: var(--petrol-mist); display: flex; align-items: center; justify-content: center; font-size: 24px; box-shadow: inset 0 0 0 1px var(--line-soft); }
.dtile__chip img { width: 43px; height: 43px; object-fit: contain; display: block; }
.dtile__label { font-weight: 600; color: var(--petrol-deep); font-size: 15px; line-height: 1.25; }
.dtile__meta { font-size: 12.5px; color: var(--ink-soft); }
@media (min-width: 760px) {
  .dash { grid-template-columns: repeat(4, 1fr); gap: 16px; }
  .dash-feat__big { font-size: 1.9rem; }
}

/* --- Booking calendar (/mijn/lessen): app-native day/week/month ------------- */
/* The calendar centres/scrolls via the universal body.app flex rule (no magic
   px) — same on every screen size. */
.cal-head { max-width: 760px; margin: 0 auto 1.1rem; text-align: center; }
.cal-head h1 { margin: 0 0 0.7rem; font-size: 1.7rem; }
.cal-views {
  display: inline-flex; gap: 2px; padding: 4px; border-radius: 999px;
  background: var(--petrol-mist); box-shadow: inset 0 0 0 1px var(--line-soft);
}
.cal-view {
  padding: 0.4rem 1.1rem; border-radius: 999px; text-decoration: none;
  color: var(--petrol); font-weight: 600; font-size: 0.92rem; transition: all var(--beweging-snel) var(--curve);
}
.cal-view.is-active { background: var(--petrol); color: var(--mint-pale); box-shadow: var(--shadow-soft); }
.cal-nav { display: flex; align-items: center; justify-content: center; gap: 1rem; margin-top: 0.9rem; }
.cal-arrow {
  width: 40px; height: 40px; display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; background: var(--taupe); border: 1px solid var(--black-a08);
  color: var(--petrol-deep); text-decoration: none; font-size: 1.1rem; box-shadow: var(--shadow-soft);
}
.cal-arrow:hover { background: var(--petrol); color: var(--white); }
.cal-period { font-family: var(--font-body); font-weight: 600; font-size: 1.15rem; color: var(--petrol-deep); min-width: 12ch; }

.cal-week, .cal-cards--day { max-width: 760px; margin: 0 auto; }
.cal-day { margin-bottom: 1.4rem; }
.cal-day__label {
  font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.06em; font-weight: 700;
  /* Near-ink for max legibility + a clean calendar-grid feel on the berry
     background (owner 2026-06-16: darker still). The date is the anchor. */
  color: var(--ink); margin: 0 0 0.5rem; padding-bottom: 0.3rem; border-bottom: 1px solid var(--line-soft);
  display: flex; align-items: center; gap: 0.5rem;
}
.cal-day.is-today .cal-day__label { color: var(--ink); }
.cal-chip-today { background: var(--petrol); color: var(--white); font-size: 0.62rem; padding: 1px 7px; border-radius: 999px; letter-spacing: 0.04em; }
/* "Geen lessen" sits lighter than the date so the eye lands on days that have
   lessons (owner 2026-06-16). */
/* Empty-state messages are CONTAINED in a light sage note instead of floating on
   the bare berry, so every page reads as "in cards" (owner 2026-06-16). */
.cal-empty {
  color: var(--petrol-deep-a55); font-size: 0.88rem; font-style: italic; margin: 0 0 0.3rem;
  background: var(--sage-a50); border: 1px solid var(--petrol-mist);
  border-radius: var(--radius); padding: 0.6rem 0.9rem;
}
.cal-empty--big { text-align: center; padding: 2.2rem 1rem; }
.cal-cards { display: flex; flex-direction: column; gap: 10px; }
.cal-cards--day { gap: 12px; }

.cal-card {
  display: flex; align-items: stretch; gap: 12px; background: var(--paper-warm);
  border: 1px solid var(--line-soft); border-left: 5px solid var(--accent, var(--petrol));
  border-radius: var(--radius-lg); padding: 12px 14px; box-shadow: var(--shadow-soft);
}
.cal-card.is-booked { background: linear-gradient(0deg, var(--petrol-a04), var(--petrol-a04)), var(--paper-warm); }
.cal-card.is-past { opacity: 0.6; }
.cal-card__time {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-width: 52px; font-variant-numeric: tabular-nums; line-height: 1.1;
}
.cal-card__time strong { font-size: 1.05rem; color: var(--petrol-deep); }
.cal-card__time span { font-size: 0.78rem; color: var(--ink-soft); }
.cal-card__body { flex: 1; min-width: 0; }
.cal-card__name { margin: 0 0 0.2rem; font-size: 1.02rem; color: var(--ink); font-family: var(--font-body); font-style: normal; font-weight: 600; }
.cal-card__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; font-size: 0.8rem; color: var(--ink-soft); }
.cal-pill { background: var(--petrol-mist); color: var(--petrol); padding: 1px 8px; border-radius: 999px; font-weight: 600; font-size: 0.74rem; }
.cal-pill--few { background: var(--amber-pale); color: var(--amber-deep); }
.cal-pill--full { background: var(--rose-pale); color: var(--maroon); }
.cal-card__info { margin-top: 0.5rem; }
.cal-card__info summary { cursor: pointer; color: var(--petrol-soft); font-size: 0.8rem; font-weight: 600; }
.cal-card__info p { margin: 0.4rem 0 0; font-size: 0.86rem; color: var(--ink-soft); line-height: 1.45; }
.cal-card__action { display: flex; flex-direction: column; align-items: flex-end; justify-content: center; gap: 0.3rem; }
.cal-btn {
  background: var(--petrol); color: var(--mint-pale); border: none; border-radius: 999px;
  padding: 0.5rem 1.1rem; font-weight: 600; font-size: 0.88rem; cursor: pointer;
  box-shadow: 0 6px 16px var(--petrol-a20); transition: background var(--beweging-snel) var(--curve);
}
.cal-btn:hover { background: var(--petrol-deep); }
.cal-btn--wl { background: var(--petrol-soft); }
.cal-booked { color: var(--petrol); font-weight: 700; font-size: 0.9rem; white-space: nowrap; }
.cal-muted { color: var(--ink-soft); font-size: 0.85rem; }
.cal-flash { font-size: 0.78rem; margin: 0; text-align: right; }
.cal-flash--ok { color: var(--petrol); }
.cal-flash--error { color: var(--maroon); }

/* month grid — explicit width: as a flex item with margin:auto the grid
   otherwise shrinks to fit-content, and its width silently leaned on the
   WIDEST TEXT CHILD (the tap-hint). Removing that hint collapsed the whole
   grid to mini cells (owner photo 2026-07-14). Width must never depend on
   what text happens to sit inside. */
.cal-month { width: 100%; max-width: 760px; margin: 0 auto; }
.cal-month__dow { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; margin-bottom: 6px; }
.cal-month__dow span { text-align: center; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; color: var(--petrol-soft); }
.cal-month__week { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; margin-bottom: 6px; }
.cal-cell {
  aspect-ratio: 1 / 1; display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  padding: 6px 2px; border-radius: 12px; background: var(--white); border: 1px solid var(--line-soft);
  text-decoration: none; color: var(--ink-soft); gap: 2px;
}
.cal-cell__day { font-weight: 600; font-size: 0.9rem; }
/* out-of-month: muted but SOLID (no opacity — keeps cells 100% so the backdrop
   never bleeds through the calendar; it only shows in the gaps, behind). */
.cal-cell.is-out { background: var(--cream-mist); color: var(--ink-soft); border-color: var(--line-soft); }
.cal-cell.is-out .cal-cell__day { color: var(--cool-39); }
.cal-cell.is-today { box-shadow: inset 0 0 0 2px var(--petrol); }
.cal-month__hint { text-align: center; color: var(--ink-soft); font-size: 0.82rem; font-style: italic; margin-top: 0.8rem; }

/* Free-slot calendar (OPORD 06) — service chips, type dots, legend.
   The dot colour comes from the product (the practice owns it) via an inline
   `--dot` custom property; CSP allows inline style, never inline script. */
/* Both pill-groups sit on one row on a desktop and wrap on a phone. Without
   this they are inline-flex siblings that widen the page past the viewport. */
.cal-toolbar {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 0.5rem 0.7rem; margin-bottom: 0.3rem;
}
/* A fysio slot books through a link, a session/free slot through a form button.
   They must look identical — the member is pressing "Boek", not a hyperlink. */
.cal-card__action a.cal-btn {
  display: inline-flex; align-items: center; justify-content: center;
  text-decoration: none; width: 100%;
}
.cal-card__action form { width: 100%; }
.cal-chips {
  display: inline-flex; gap: 2px; padding: 4px; border-radius: 999px;
  background: var(--cream-mist, var(--petrol-mist)); box-shadow: inset 0 0 0 1px var(--line-soft);
}
.cal-chip {
  padding: 0.35rem 1rem; border-radius: 999px; text-decoration: none;
  color: var(--petrol); font-weight: 600; font-size: 0.88rem; transition: all var(--beweging-snel) var(--curve);
  min-height: 34px; display: inline-flex; align-items: center;
}
.cal-chip.is-active { background: var(--petrol); color: var(--mint-pale); box-shadow: var(--shadow-soft); }
.cal-lede { color: var(--ink-soft); margin: 0.2rem 0 0.9rem; }

/* Dots: colour is a hint, never a text background — the practitioner cannot break
   contrast with an unlucky pick. */
.cal-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--dot, var(--petrol)); flex: 0 0 auto; display: inline-block;
}
.cal-dots { display: flex; gap: 3px; justify-content: center; flex-wrap: wrap; margin-top: 3px; }

/* The cells are square (aspect-ratio), so their MIN width follows their content
   height — the dot row made every cell taller, hence wider, and the grid pushed
   past a phone viewport (invisibly, because main clips overflow-x). Let the
   tracks shrink below min-content. */
.cal-month__week,
.cal-month__dow { grid-template-columns: repeat(7, minmax(0, 1fr)); }
.cal-cell { min-width: 0; overflow: hidden; }

/* A day with something on it is marked by a petrol RING, not a petrol fill: on a
   filled cell the type-dots drowned in the background and the colour — the whole
   point of this calendar — said nothing. */
.cal-cell.has-items {
  background: var(--white); border-color: var(--petrol); color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--petrol);
}
.cal-cell.has-items .cal-cell__day { color: var(--petrol); }
.cal-cell.is-out.has-items {
  background: var(--cream-mist); border-color: var(--petrol-soft); box-shadow: none;
}
/* A day that has been and gone still opens (it shows what happened), but the
   ring is the promise "there is something to book here" — so it goes. */
.cal-cell.is-past.has-items {
  border-color: var(--line-soft); box-shadow: none;
}
.cal-cell.is-past.has-items .cal-cell__day { color: var(--ink-soft); }
.cal-cell.is-past .cal-dot { opacity: 0.45; }
/* The day you opened stays marked while its cards sit underneath. */
.cal-cell.is-selected {
  background: var(--petrol); border-color: var(--petrol);
  box-shadow: 0 4px 14px var(--petrol-a28);
}
.cal-cell.is-selected .cal-cell__day { color: var(--white); }
.cal-cell.is-selected .cal-dot { box-shadow: 0 0 0 1.5px var(--white-a85); }

/* A login link must look like the booking button it replaces, minus the pull. */
.cal-card__action a.cal-btn--ghost {
  background: transparent; color: var(--petrol);
  box-shadow: inset 0 0 0 1.5px var(--petrol);
}

/* Beheer Ledenweergave: the member's buttons are shown, not offered. They keep
   their shape so the practitioner checks the real thing; they just don't invite a press. */
.cal-btn[disabled], .site-nav__drawer-logout button[disabled] {
  opacity: 0.55; cursor: not-allowed;
}

/* The day's cards, inline under the grid (owner: keep it inline). */
.cal-daypanel { max-width: 760px; margin: 1.2rem auto 0; }
.cal-daypanel:empty { margin: 0; }
.cal-daypanel__title {
  text-align: center; margin: 0 0 0.8rem;
  font-size: 1.05rem; color: var(--petrol); text-transform: lowercase;
}

/* The legend sits on the app backdrop, so it needs its own surface — bare text
   on the berry reads badly (owner rule: never text floating on the backdrop). */
.cal-legend {
  list-style: none; margin: 1.2rem auto 0; padding: 0.7rem 1rem; max-width: 760px;
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.2rem; justify-content: center;
  background: var(--paper, var(--paper)); border-radius: 14px; box-shadow: var(--shadow-soft);
}
.cal-legend li {
  display: flex; align-items: center; gap: 0.45rem;
  color: var(--ink); font-size: 0.85rem;
}

/* Desktop: scale the calendar UP (760px reads as a tiny island on a wide screen).
   Placed AFTER the base .cal-* rules so it actually wins on desktop. */
@media (min-width: 760px) {
  /* A comfortable reading width (centred in the app container) — full-width made the
     week cards look empty (content left, button stranded right) and the month cells
     oversized. width:100% so they grow to this cap despite the base margin:0 auto. */
  .cal-head, .cal-week, .cal-cards--day, .cal-month { width: 100%; max-width: 880px; }
  .cal-head h1 { font-size: 2.1rem; }
  .cal-period { font-size: 1.65rem; }
  .cal-view { font-size: 1rem; padding: 0.5rem 1.4rem; }
  .cal-day__label { font-size: 0.92rem; }
  .cal-card { padding: 16px 22px; gap: 16px; }
  .cal-card__time { min-width: 68px; }
  .cal-card__time strong { font-size: 1.3rem; }
  .cal-card__time span { font-size: 0.92rem; }
  .cal-card__name { font-size: 1.2rem; }
  .cal-card__meta { font-size: 0.92rem; }
  .cal-btn { padding: 0.62rem 1.6rem; font-size: 1rem; }
  .cal-month__week, .cal-month__dow { gap: 10px; }
  .cal-month__dow span { font-size: 0.88rem; }
  .cal-cell__day { font-size: 1.25rem; }
}

@media (max-width: 460px) {
  .cal-card { flex-wrap: wrap; }
  .cal-card__action { width: 100%; align-items: stretch; }
  .cal-card__action .cal-btn { width: 100%; }
}

/* --- Rittenkaart (/mijn/rittenkaart): status + buy, app-styled --------------- */
.rk-wrap { max-width: 820px; margin: 0 auto; }
.rk-head { text-align: center; margin: 0 0 1.4rem; }
.rk-head h1 { margin: 0 0 0.2rem; font-size: 1.7rem; }
.rk-head p { margin: 0; color: var(--ink-soft); font-size: 0.95rem; }
.rk-status {
  display: flex; flex-direction: column; gap: 4px; padding: 22px 24px; border-radius: var(--radius-lg);
  background: linear-gradient(135deg, var(--petrol), var(--petrol-deep)); color: var(--mint-pale);
  box-shadow: 0 10px 30px var(--petrol-a16); margin-bottom: 1.6rem;
}
.rk-status__k { font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase; opacity: 0.85; }
.rk-status__big { font-family: var(--font-display); font-style: italic; font-size: 1.95rem; line-height: 1.1; }
.rk-status--empty .rk-status__big { font-size: 1.5rem; }
.rk-status p { margin: 0.3rem 0 0; opacity: 0.9; font-size: 0.92rem; }
.rk-packs { list-style: none; margin: 0.9rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.rk-packs li {
  display: flex; flex-wrap: wrap; gap: 0.2rem 0.8rem; align-items: baseline;
  border-top: 1px solid var(--white-a18); padding-top: 0.5rem; margin-top: 0.4rem;
}
.rk-pack__name { font-weight: 600; }
.rk-pack__count { opacity: 0.9; }
.rk-pack__valid { font-size: 0.82rem; opacity: 0.75; margin-left: auto; }
.rk-buy h2 { font-family: var(--font-display); font-style: italic; font-size: 1.45rem; color: var(--petrol-deep); margin: 0 0 0.9rem; }
.rk-cards { display: flex; flex-direction: column; gap: 12px; }
.rk-card {
  display: flex; align-items: center; gap: 16px; background: var(--paper-warm); border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg); padding: 16px 20px; box-shadow: var(--shadow-soft);
}
.rk-card__body { flex: 1; min-width: 0; }
.rk-card__body h3 { margin: 0 0 0.15rem; font-size: 1.08rem; color: var(--ink); }
.rk-card__meta { margin: 0; font-size: 0.88rem; color: var(--petrol-soft); font-weight: 600; }
.rk-card__desc { margin: 0.3rem 0 0; font-size: 0.85rem; color: var(--ink-soft); }
.rk-card__buy { display: flex; flex-direction: column; align-items: flex-end; gap: 0.4rem; }
.rk-card__price { font-weight: 700; color: var(--petrol-deep); font-size: 1.05rem; white-space: nowrap; }
.rk-btn {
  background: var(--petrol); color: var(--mint-pale); border: none; border-radius: 999px; padding: 0.55rem 1.4rem;
  font-weight: 600; font-size: 0.92rem; cursor: pointer; box-shadow: 0 6px 16px var(--petrol-a20);
}
.rk-btn:hover { background: var(--petrol-deep); }
.rk-btn--sm { padding: 0.4rem 1rem; font-size: 0.88rem; box-shadow: var(--shadow-soft); }
/* Ghost variant — a branded, less-prominent action (e.g. Annuleren) that reads
   as secondary next to a solid petrol Boek button. Replaces the unstyled
   `.secondary.outline` classes (no CSS existed for them → iOS rendered the bare
   default blue button). */
.rk-btn--ghost { background: transparent; color: var(--petrol); border: 1px solid var(--petrol); box-shadow: none; }
.rk-btn--ghost:hover { background: var(--petrol); color: var(--mint-pale); }
/* Block variant for a text note (the base .rk-card is a flex row meant for a
   body + action; a note just stacks paragraphs). */
.rk-card--note { display: block; }
.rk-hint { font-size: 0.82rem; color: var(--ink-soft); font-style: italic; margin-top: 0.8rem; }
@media (max-width: 460px) {
  .rk-card { flex-direction: column; align-items: stretch; }
  .rk-card__buy { flex-direction: row; justify-content: space-between; align-items: center; }
}

/* --- App sub-pages (boekingen/profiel/aankopen): same card language as the
       dashboard so the member side reads as one app, not a marketing site. --- */
/* Back-one-step control on member sub-pages (data-back wired in ui.js). */
.app-back {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin: 1rem 0 0;
  padding: 0.3rem 0.7rem 0.3rem 0.5rem;
  background: none;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-pill);
  color: var(--petrol);
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  transition: background var(--beweging-snel) var(--curve), border-color var(--beweging-snel) var(--curve);
}
.app-back:hover { background: var(--petrol-mist); border-color: var(--petrol-soft); }

.app-head { margin: 1rem 0 1.25rem; }
.app-head h1 { margin: 0 0 0.2rem; }
.app-head p { margin: 0; color: var(--ink-soft); font-size: 0.95rem; }
.app-section { margin: 0 0 1.75rem; }
.app-section > h2 {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--petrol);
  margin: 0 0 0.7rem;
}
.app-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.6rem; }
.app-row {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  flex-wrap: wrap;
  padding: 0.8rem 1rem;
  background: var(--paper-warm);
  border: 1px solid var(--line-soft);
  border-left: 4px solid var(--petrol);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
}
.app-row--past { opacity: 0.72; padding: 0.55rem 0.9rem; box-shadow: none; }
.app-row__when { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }
/* min-width:0 + break-word so a long name shrinks and wraps its TEXT instead of
   overflowing under the action button (a flex item defaults to min-width:auto =
   its longest word, which both pushed the button onto an inconsistent extra line
   AND let long words like "behandeling" overflow under the button). */
.app-row__what { flex: 1; min-width: 0; overflow-wrap: break-word; }
/* Booking-slot cards: date + name stack on the left so each gets the full
   column width; the action button stays a vertically-centred right-hand item.
   This keeps the button deterministically placed on every card + every device
   regardless of how long the service name is (afspraken.html). */
.app-row__info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.15rem; }
.app-row__action { margin: 0; }
/* Right-hand group (status note / amount + the action button), stacked + kept at
   its natural width so it never collapses onto the info column. */
.app-row__meta { display: flex; flex-direction: column; align-items: flex-end; gap: 0.3rem; flex-shrink: 0; }
/* A long status note must wrap to 2 lines (right-aligned) instead of forcing the
   meta wide and squeezing the date onto multiple lines. Buttons aren't <small>,
   so they keep their natural width. */
.app-row__meta small { max-width: 12rem; text-align: right; }

/* App form card — house-style form on /mijn (profiel; reusable for other forms) */
.app-form {
  max-width: 30rem;
  margin: 0 auto;
  /* Sage card like the app tiles + auth card — no more white form on /mijn
     (owner 2026-06-16). Fields tinted lighter-Tundra to read as inputs. */
  background: var(--sage);
  border: 1px solid var(--petrol-a10);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: 1.5rem 1.4rem;
}
.app-form__field { margin: 0 0 1.05rem; }
.app-form label {
  display: block;
  font-size: 0.86rem;
  font-weight: 600;
  color: var(--ink);
  margin: 0 0 0.32rem;
}
.app-form input,
.app-form textarea {
  width: 100%;
  box-sizing: border-box;
  padding: 0.62rem 0.75rem;
  border: 1px solid var(--petrol-a16);
  border-radius: var(--radius);
  background: var(--sage-pale);
  color: var(--ink);
  font-size: 1rem;
}
.app-form textarea { resize: vertical; min-height: 7rem; font-family: inherit; line-height: 1.5; }
/* iOS renders <input type=date> with its value centred + native chrome, so it
   looked "out of the box" next to the left-aligned text fields. Normalise it:
   strip the native appearance and left-align the value (owner 2026-06-16). */
.app-form input[type="date"] { -webkit-appearance: none; appearance: none; min-height: 2.7rem; }
.app-form input[type="date"]::-webkit-date-and-time-value { text-align: left; margin: 0; }
.app-form input[type="date"]::-webkit-calendar-picker-indicator { margin-left: auto; opacity: 0.6; }
.app-form input:focus,
.app-form textarea:focus {
  outline: none;
  border-color: var(--petrol-soft);
  background: var(--sage-pale-2);
  box-shadow: 0 0 0 3px var(--petrol-soft-a13);
}
.app-form__err { display: block; color: var(--error); font-size: 0.8rem; margin-top: 0.28rem; }
/* Direct-contact block inside the contact card — contained like the login, not
   floating on the bare berry (owner 2026-06-16). */
.app-form__direct { margin-top: 1.2rem; padding-top: 1rem; border-top: 1px solid var(--line-soft); text-align: center; }
.app-form__direct p { margin: 0 0 0.4rem; color: var(--ink-soft); font-size: 0.92rem; line-height: 1.6; }
.app-form__direct p:last-child { margin-bottom: 0; }
.app-form__submit { width: 100%; margin-top: 0.4rem; padding-block: 0.7rem; font-size: 0.98rem; }
/* Opt-in row (waitlist) — 44px tap target, label reads as one line with the box */
.app-form__check {
  display: flex; align-items: center; gap: 0.7rem;
  min-height: 44px; margin: 0 0 1rem; cursor: pointer;
  color: var(--ink); font-size: 0.95rem;
}
.app-form__check input { width: 1.15rem; height: 1.15rem; flex: 0 0 auto; accent-color: var(--petrol); }
/* Quiet follow-up line under an app list (e.g. "no fitting slot? request one") */
.app-note {
  margin: 1.1rem 0 0; text-align: center;
  color: var(--ink-soft); font-size: 0.92rem; line-height: 1.6;
}
.app-note a { color: var(--petrol); }
.app-note--head { margin-top: 0.7rem; }

/* Bonnen (aankopen) — a downloadable receipt/invoice row */
.bon-status {
  font-size: 0.74rem; font-weight: 600; padding: 0.15rem 0.55rem; border-radius: 99px;
  white-space: nowrap;
}
.bon-status--paid { background: var(--mint-soft); color: var(--success); }
.bon-status--open { background: var(--amber-pale-2); color: var(--amber-deep-2); }
.bon-amount { font-weight: 700; color: var(--petrol-deep); font-variant-numeric: tabular-nums; white-space: nowrap; }
.bon-dl {
  display: inline-flex; align-items: center; min-height: 44px;  /* was 33: te klein voor een duim */
  font-size: 0.8rem; font-weight: 600; color: var(--petrol); text-decoration: none; white-space: nowrap;
  border: 1px solid var(--cream-deep); border-radius: 99px; padding: 0 0.95rem;
}
.bon-dl:hover { background: var(--petrol); color: var(--white); border-color: var(--petrol); }
.app-empty {
  color: var(--ink-soft); font-style: italic; font-size: 0.92rem; margin: 0;
  background: var(--sage-a50); border: 1px solid var(--petrol-mist);
  border-radius: var(--radius); padding: 0.7rem 1rem;
}

/* Compact contact-page header (replaced the full-viewport opening hero so the
   page lands straight on the details — no scroll-past-an-opening-screen). */
.contact-head { margin: 0 0 2rem; }
.contact-head h1 { margin: 0.2rem 0 0.4rem; }
.contact-head p { color: var(--ink-soft); max-width: 56ch; margin: 0; }

/* --- OPORD-F 2b: member hamburger + side drawer --------------------------- */
/* The `hidden` attribute must win over component display rules (the drawer is
   display:flex; the scrim + install-card toggle via `hidden`).
   Author CSS otherwise beats the UA [hidden] rule at equal specificity. */
[hidden] { display: none !important; }

.site-nav__burger {
  background: none;
  border: 0;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  color: var(--petrol);
  padding: 0.2rem 0.4rem;
}

/* App pages (/mijn): transparent nav — the logo is hidden here and the
   hamburger is its own round button, so no top fade is needed (the fade read as
   a vague top edge). Does NOT touch the owner-locked decoration band. */
body.app .site-nav { background: transparent; }
/* No floating logo at the top of the app — it doesn't read as part of the app
   (owner). The brand lives in the dashboard banner instead. Hamburger stays. */
body.app .site-nav__logo { display: none; }
body.app .site-nav__burger {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; padding: 0;
  font-size: 1.25rem; color: var(--petrol-deep);
  /* Taupe, not white — owner 2026-06-15 ("everything has a colour"). */
  background: var(--taupe); border: 1px solid var(--black-a08); border-radius: 50%;
  box-shadow: var(--shadow-soft);
}

/* Scroll-lock: while the member drawer is open, freeze the page behind it.
   ui.js toggles `nav-open` on <html>; the drawer (position:fixed) keeps its own
   scroll. overflow:hidden holds the current scroll position with no jump. */
html.nav-open { overflow: hidden; }

.site-nav__scrim {
  position: fixed;
  inset: 0;
  background: var(--petrol-deep-a35);
  z-index: 40;
}

.site-nav__drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(80vw, 300px);
  background: var(--rose);          /* Firm Berry Pure — same as the app backdrop */
  box-shadow: -6px 0 24px var(--petrol-a28);
  z-index: 41;
  /* Safe-area insets so the drawer fills under the notch + the Uitloggen button
     clears the home-indicator on the installed app (owner native-feel). */
  padding: calc(1.2rem + env(safe-area-inset-top)) 1rem calc(1.2rem + env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  overflow-y: auto;
}
.site-nav__drawer-close {
  align-self: flex-end;
  background: none;
  border: 0;
  font-size: 1.2rem;
  cursor: pointer;
  color: var(--ink-soft);
  padding: 0.2rem 0.4rem;
}
.site-nav__drawer nav { display: flex; flex-direction: column; gap: 0.5rem; margin-top: 0.3rem; }
/* Both items stack icon-over-caption (owner 2026-06-16): the house and the
   full logo read as one matched pair instead of an icon-beside-text row. */
.site-nav__drawer nav a {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.4rem;
  padding: 0.9rem 0.6rem;
  border-radius: var(--radius);
  color: var(--petrol-deep);
  font-weight: 600;
  text-decoration: none;
}
.site-nav__drawer nav a:hover { background: var(--line-soft); }
/* Drawer glyphs. House = app-style line-art, inherits the link colour via
   currentColor (= --petrol-deep). The website item shows the FULL logo (mark +
   the practice name) — rendered through a CSS mask tinted with the SAME
   --petrol-deep, so the logo is pixel-identical in colour to the house. */
.drawer-ico { width: 60px; height: 60px; flex: 0 0 auto; object-fit: contain; }
.drawer-logo {
  width: 118px;
  height: 80px;
  background: var(--petrol-deep);
  -webkit-mask: url(/static/img/brand/figures/logo-full.png) center / contain no-repeat;
  mask: url(/static/img/brand/figures/logo-full.png) center / contain no-repeat;
}
.drawer-site-cap { font-size: 0.85rem; font-weight: 600; color: var(--petrol-deep); }
.site-nav__drawer-logout { margin-top: auto; padding-top: 1rem; }
/* Small app-version stamp at the very bottom of the member drawer — the member
   app hides its footer, so this is the only version readout (owner 2026-07-13). */
.drawer-version {
  flex: 0 0 auto; margin: 0.5rem 0 0; text-align: center;
  font-size: 0.7rem; letter-spacing: 0.06em; color: var(--ink-a45);
}

/* --- OPORD-F Fase 2: install ("make this an app") card -------------------- */
.install-card {
  position: relative;
  display: flex;
  gap: 0.8rem;
  align-items: flex-start;
  margin: 1rem 0 1.2rem;
  padding: 0.9rem 2.2rem 0.9rem 1rem;
  background: var(--petrol);
  color: var(--white);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
}
.install-card__icon { font-size: 1.8rem; line-height: 1; }
.install-card__body strong { display: block; margin-bottom: 0.15rem; }
.install-card__body p { margin: 0 0 0.5rem; font-size: 0.9rem; opacity: 0.92; }
.install-card__ios { margin: 0 !important; opacity: 1 !important; }
.install-card__btn {
  background: var(--white);
  color: var(--petrol-deep);
  border: 0;
  border-radius: var(--radius-pill);
  padding: 0.45rem 1rem;
  font-weight: 600;
  cursor: pointer;
}
.install-card__close {
  position: absolute;
  top: 0.4rem;
  right: 0.5rem;
  background: none;
  border: 0;
  color: var(--white);
  opacity: 0.8;
  font-size: 1rem;
  cursor: pointer;
}
.install-card__close:hover { opacity: 1; }

/* --- OPORD-F: member app pages (/mijn) are an app, not the marketing scroll
   story. Disable full-viewport snap-sections so the dashboard flows from the
   top like a normal app screen (mirrors body.admin). */
body.app { scroll-snap-type: none; }
body.app main > section {
  min-height: 0;
  scroll-snap-align: none;
  scroll-snap-stop: normal;
  display: block;
  overflow: visible;
  padding-top: 0;
  padding-bottom: 0;
}

/* --- Branded auth card (login / register / reset) — the locked app-wide look:
   soft paper bg · the post decoration band top + bottom, LOW opacity, BEHIND
   the card · white card · logo with depth, separated from the heading. -------- */
.auth-wrap {
  position: relative;
  display: flex;
  align-items: center;          /* vertical centring in the viewport */
  justify-content: center;
  min-height: 100dvh;           /* full viewport; 100dvh (not vh) so the mobile URL bar never forces a scroll */
  padding: 3rem 1rem;
  overflow: hidden;             /* clip the band cut-edges past the screen edge */
  /* Auth = the app threshold: same identity as body.app (Firm Berry Pure bg),
     so pressing "inloggen" lands you in the member look, not a different page.
     (Owner steer 2026-06-15: bring the whole auth flow into the app style.) */
  background: var(--rose);
}
/* Decoration = individual FULLY-ORGANIC shapes (no straight cut on-screen): the
   blob (insta-g09) is organic all round; arcs are placed in corners with their
   straight cut-ends pushed off BOTH screen edges, so only the curve shows. The
   .auth-wrap clips (overflow:hidden), so the only "edge" is the viewport border. */
/* The approved decoration band (deco-band.png = the real post bottom-band, 1:1),
   full-bleed top + bottom, low opacity, behind the card. */
.auth-band { position: absolute; left: 0; width: 100%; pointer-events: none; user-select: none; z-index: 0; opacity: .22; }
.auth-band--bottom { bottom: -24px; }
/* Top copy = same band, 180°-flipped (point reflection → different arrangement,
   not a plain mirror). Its flat baseline sits ON the top edge (invisible, exactly
   like the bottom band's baseline on the bottom edge); all shapes are organic
   (the boxy pill was swapped for a g09 blob) so no straight line. */
.auth-band--top { top: -24px; transform: scale(-1, -1); }
/* On mobile, match the app's decoration exactly so login feels like the same app
   (owner 2026-06-16): bigger band reaching toward the middle, right-anchored,
   same opacity as the /mijn band. (Desktop base stays the owner-locked .22.) */
@media (max-width: 600px) {
  .auth-band { width: 230%; max-width: none; left: auto; right: 0; opacity: .40; }
}
.auth-card {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 380px;
  background: var(--sage);          /* Gentle Tundra sage — same card colour as the app tiles */
  border: 1px solid var(--petrol-a10);
  border-radius: 20px;
  box-shadow: 0 22px 60px var(--petrol-deep-a18), 0 6px 16px var(--petrol-deep-a08);
  padding: 1.9rem 1.7rem 1.8rem;
  text-align: center;
}
.auth-card__content { position: relative; z-index: 1; }
.auth-card__logo {
  position: relative; z-index: 1; display: block; height: 96px; width: auto; margin: 0.2rem auto 0;
  /* razor sharp — no shadow (the source logo is hi-res line-art; a drop-shadow
     read as 'smudgie'). Crispness IS the effect. */
}
.auth-card__div { width: 46px; height: 2px; border-radius: 2px; background: var(--line-soft); margin: 1.1rem auto 1rem; }
.auth-card h1 { margin: 0 0 0.3rem; font-size: 1.55rem; }
.auth-card__lede { margin: 0 0 1.1rem; color: var(--ink-soft); font-size: 0.92rem; }
.auth-card form { text-align: left; }
.auth-card label { display: block; margin: 0.7rem 0 0.2rem; font-size: 0.9rem; font-weight: 600; }
/* Fields tinted out of the same family as the sage card (lighter Tundra) so
   they rest in the card instead of reading as stark white, while staying clearly
   a field. (Owner steer 2026-06-15.) */
.auth-card input { width: 100%; background: var(--sage-pale); border-color: var(--petrol-a16); }
.auth-card input:focus { background: var(--sage-pale-2); }
.auth-card button[type="submit"] {
  width: 100%; margin-top: 1.2rem;
  background: var(--petrol); border-color: var(--petrol); color: var(--mint-pale); font-weight: 600;
  box-shadow: 0 8px 20px var(--petrol-a22);
}
.auth-card button[type="submit"]:hover { background: var(--petrol-deep); border-color: var(--petrol-deep); }
.auth-card__error { background: var(--rose-pale); color: var(--maroon-deep); padding: 0.5rem 0.7rem; border-radius: var(--radius); font-size: 0.9rem; text-align: left; }
.auth-card__error a { color: var(--maroon-deep); }
.auth-card__links { margin-top: 1.1rem; }

/* Auth branding scales down on phones so it frames, not crowds, the card. */
@media (max-width: 760px) {
  .auth-deco--leaf { width: 96px; top: 1.5vh; left: -8px; opacity: 0.9; }
  .auth-deco--cluster { width: 130px; right: -6px; opacity: 0.9; }
}

/* ============================================================================
   EXPERIMENT (owner 2026-06-15) — member cards (tiles + booking rows + ritten-
   kaart + lesson cards) in Flexa "Gentle Tundra Pure" (var(--sage) soft sage), a
   harmonising combination with the Firm Berry background. Petrol (the logo
   house colour) stays on the banner, buttons, chips and accents. Sage is light,
   so the cards keep their original DARK text — only the background changes.
   Reverts by deleting this block / `git checkout static/css/site.css`.
   ========================================================================== */
body.app .dtile,
body.app .app-row,
body.app .rk-card,
body.app .cal-card,
body.app .cal-card.is-booked { background: var(--sage); }

/* ==========================================================================
   FUNNEL PAGES (fix B, 2026-06-20) — bring the raw transactional pages
   (rooster, afspraken, intake, afspraak-intake, bedankt) up to the house
   style. Two small new components; everything else reuses .about-hero /
   .btn / .schedule / .note. No redesign — owner-approved.
   ========================================================================== */
/* Shared form-error token — replaces scattered var(--error-2) / var(--tan) (off-palette;
   var(--tan) is terracotta-adjacent, the one banned colour). */
.form-error { color: var(--accent, var(--terracotta)); font-size: 0.9rem; }
.form-error--block {
  background: var(--peach-pale); border-left: 3px solid var(--accent, var(--terracotta));
  border-radius: 0 var(--radius) var(--radius) 0; padding: 0.7rem 1rem; margin: 0 0 1rem;
}
/* Booking row — a .schedule variant carrying a Boek action (rooster + afspraken
   lists). Colour-coded left border per class type (inline, data-driven). */
.book-row {
  display: grid; grid-template-columns: 4.6rem 1fr auto; gap: 1rem; align-items: center;
  padding: 1rem 1.4rem; border-bottom: 1px solid var(--line-soft);
  border-left: 4px solid var(--petrol);
}
.book-row:last-child { border-bottom: 0; }
.book-row__time { font-weight: 600; color: var(--petrol-soft); font-variant-numeric: tabular-nums; }
.book-row__name { color: var(--ink); font-weight: 500; }
.book-row__meta { display: block; color: var(--muted); font-size: 0.82rem; margin-top: 0.1rem; }
.book-row form { margin: 0; }
@media (max-width: 560px) {
  .book-row { grid-template-columns: 3.6rem 1fr auto; gap: 0.7rem; padding: 0.9rem 1rem; }
}
/* Funnel form fields in house style. */
.form-stack { max-width: 34rem; }
.form-field { display: block; margin-bottom: 1.1rem; }
.form-field > label { display: block; font-weight: 600; color: var(--petrol); margin-bottom: 0.35rem; font-size: 0.95rem; }
.form-field textarea, .form-field input[type="text"] {
  width: 100%; border: 1.5px solid var(--line); border-radius: var(--radius);
  padding: 0.7rem 0.85rem; font: inherit; background: var(--white); color: var(--ink);
}
.form-field textarea:focus, .form-field input:focus { outline: 2px solid var(--petrol-soft); border-color: var(--petrol-soft); }
.form-field .hint { display: block; color: var(--muted); font-size: 0.82rem; margin-top: 0.35rem; line-height: 1.45; }
/* Day-group heading on the rooster week view. */
.daygroup { margin: 0 0 1.3rem; }
.daygroup__h { font-family: var(--font-display); font-style: italic; font-size: 1.3rem; color: var(--petrol); margin: 0 0 0.5rem 0.2rem; }
.daygroup__h a { text-decoration: none; }

/* ==========================================================================
   FASE 1 — member sub-pages PINNED on mobile (owner spec 2026-07-13).
   The page stands still: title + back can never be pushed off-screen; only
   the content scrolls, inside its own pane. Opt-in per page via .page-fix so
   every page is converted AND verified one by one (rittenkaart first). The
   deco band is untouched: position:fixed behind everything — and steadier
   than before, because the document itself no longer scrolls at all.
   Mobile-first: >=760px keeps the existing document flow for now (the
   mobile->desktop parity pass carries it over deliberately). */
@media (max-width: 759px) {
  /* The v235 pattern the owner's walkthrough approved: a HARD 100dvh on the
     body is the one height constraint the whole flex chain hangs from — with
     only min-height the chain grows with content, the pane never overflows
     and everything below the fold is unreachable (owner 2026-07-14:
     "scrollt niet in de boekingen"). The fixed-frame + --viewport-gap
     machinery that replaced it (v243-v250, the bottom-edge night) is
     removed: the bottom-edge dossier is PARKED; function wins. The old
     objection to body-level height (it shifted the fixed BOTTOM deco band)
     died with that band's removal (fe3e9a0). */
  /* --screen-extend (ui.js, standalone only) closes the gap between the
     layout viewport and the physical screen on the owner's letterboxed
     install: the frame grows by the measured amount so the scroll pane ends
     on the real edge (the home-indicator stripe), not 59pt above it. Plain
     in-flow height — the canvas paints past the layout viewport (proven
     13-07: height extension moved the visible cut ~1:1); position:fixed
     tricks are forbidden (doctrine ⛔). 0 on healthy installs. */
  body.app:has(.page-fix) {
    height: calc(100dvh + var(--screen-extend, 0px));
    overflow: hidden;
  }
  body.app:has(.page-fix) main#main { flex: 1 1 auto; min-height: 0; }
  /* ⛔ Do NOT pin the document with overflow:hidden on html: iOS clips the
     canvas back to the short layout viewport and the whole --screen-extend
     band disappears (13-07 doctrine; re-proven the hard way in v254 — owner:
     "scroll komt nog steeds niet uit onderkant"). The 59px document pan on
     the letterboxed install is the lesser evil; body overflow:hidden already
     keeps the page itself still.
     ⛔ And do NOT compact the top bar row: the space above the v253 title
     position IS the notch/status zone — the 44px row put back/title/burger
     behind the clock, island and battery (owner 2026-07-14). 76px stands. */

  /* The date above the day's bookable slots: bold, and pinned at the top of
     the scroll pane while the slots scroll away beneath it (owner
     2026-07-14). Solid berry backdrop so cards slide under it cleanly. */
  .page-fix .page-body .cal-daypanel__title {
    position: sticky; top: 0; z-index: 2;
    font-weight: 700;
    background: var(--rose);
    padding: 0.35rem 0;
    margin: 0 0 0.5rem;
  }

  /* A pinned page fills the viewport; the short-page centring (margin-block:
     auto on the wrap) would float it — switch it off for converted pages. */
  body.app:not(.app-home) main#main > .page-fix { margin-block: 0; }
  .page-fix { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
  /* Everything that is not the scroll pane is part of the FIXED top (title,
     status card, filter chips, …) — the pane is the only thing that moves. */
  .page-fix > :not(.page-body) { flex: 0 0 auto; }
  .page-fix .page-body {
    flex: 1 1 auto; min-height: 0;
    overflow-y: auto;
    overscroll-behavior: none;
    -webkit-overflow-scrolling: touch;
    /* Native feel: iOS overlay scrollbars are invisible anyway; hide the rest. */
    scrollbar-width: none;
    /* 10px, not 28: on a real device the safe-area inset (~34px) already
       lifts the content off the home indicator — the extra 18px made the
       profiel form overflow its pane by a few px on the owner's iPhone,
       i.e. a scroll on a page that visually fits (owner 2026-07-13). */
    padding-bottom: calc(10px + env(safe-area-inset-bottom));
  }
  .page-fix .page-body::-webkit-scrollbar { display: none; }

  /* The tile name joins the BAR ROW, between back and burger (owner
     2026-07-13: use the whole top). The bar overlays instead of taking its
     own row; the page h1 becomes the bar's centre — everything below it
     moves up by a full row. */
  body.app:has(.page-fix) .site-nav { position: absolute; top: 0; left: 0; right: 0; }
  .page-fix .page-head { margin: 0; }
  .page-fix .page-head h1 {
    box-sizing: border-box;
    margin: 0;
    /* 88px clears the back control (left) and the burger (right); the
       safe-area padding mirrors the bar's own notch offset. */
    padding: env(safe-area-inset-top, 0px) 88px 0;
    line-height: 76px; /* = the bar row height: single line, centred in it */
    font-size: 1.35rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-align: center;
  }

  /* Pinned mobile calendar (beheer model): flatter cells + tight spacing so
     the FIXED grid and a couple of lesson cards share one screen; only the
     day panel beneath the grid scrolls. 11/8 with trimmed padding is the
     flattest a ~45px-wide cell can go and still show day number + dots
     (8/5 clipped the dots — the hint points at them, so they must show). */
  .page-fix .cal-month .cal-cell { aspect-ratio: 11 / 8; padding: 3px 2px; }
  .page-fix .cal-cell__day { font-size: 0.85rem; line-height: 1.2; }
  .page-fix .cal-toolbar { margin: 0.4rem 0 0.2rem; }
  .page-fix .cal-nav { margin: 0.2rem 0 0.3rem; }
  .page-fix .cal-month__hint { margin: 0.3rem 0 0.1rem; font-size: 0.8rem; }

  /* The back control is the ANCHOR (owner spec pt 3): it lives IN the top bar
     (left, opposite the hamburger — partials/nav.html), which already sits
     below the notch via the nav's safe-area padding. Quiet text style — the
     pill border read as a form element. */
  body.app .site-nav .app-back {
    padding: 0.3rem 0.55rem 0.3rem 0.2rem;
    border: 0;
    background: none;
    font-size: 0.95rem;
  }

  /* Hamburger goes unobtrusive (owner spec pt 4: doorzichtig/onopvallend —
     gets replaced later). Same 42px tap target, just quieter. */
  body.app .site-nav__burger {
    background: var(--cream-a28);
    border-color: var(--black-a05);
    box-shadow: none;
  }
}

/* In the top bar the back control aligns to the bar's flex row (its page-flow
   top margin would push it off-centre) — every viewport. */
.site-nav .app-back { margin: 0; }
