/* ==========================================================================
   Linda Rohde Acupunctuur — one stylesheet for the whole site.

   Layout order: tokens, base, skip link, header, footer, layout primitives,
   components, motion. Tokens are all at the top so colours, spacing and type
   can be changed in one place.

   Colours are fixed and come from the old site's CSS. Do not invent new ones.
   ========================================================================== */

/* ==========================================================================
   1. Design tokens
   ========================================================================== */

:root {
  /* --- Brand palette (unchanged from the old site) --- */
  --rood:   #721515;   /* borders, buttons, links on beige */
  --blauw:  #576fae;   /* links on white, active nav underline */
  --beige:  #ede8d0;   /* page section backgrounds */
  --taupe:  #b6ad9e;   /* accent border on .note */

  /* Derived from the old CSS's color-mix() calls, resolved to fixed values so
     they are visible here rather than hidden in a function. */
  --rood-donker: #5b1111;  /* was color-mix(rood 80%, black)  — button hover */
  --hover:       #edeae7;  /* was color-mix(taupe 25%, white) — hover surface */

  /* --- Neutrals --- */
  --text:     #1b1b1b;
  --text-mut: #333333;
  --text-soft:#555555;
  --bg:       #ffffff;

  /* #848484 is the lightest grey that still clears the 3:1 that WCAG 1.4.11
     requires for a form field's only visual boundary, on white AND on beige.
     The old site used #d8d8d8, which managed just 1.43:1. */
  --border:      #848484;
  --border-soft: #e6e6e6;   /* decorative rules only, no contrast requirement */

  /* --- Links: the token is swapped per background, see .bg-beige ---
     #576fae on beige is only 3.98:1, so beige sections use the red, which is
     9.30:1. Both are existing palette colours; only their placement changes. */
  --link: var(--blauw);
  --focus: var(--rood);

  /* --- Type --- */
  --font: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --step--1: clamp(0.83rem, 0.8rem + 0.15vw, 0.9rem);
  --step-0:  clamp(1rem, 0.96rem + 0.2vw, 1.075rem);
  --step-1:  clamp(1.15rem, 1.08rem + 0.35vw, 1.3rem);
  --step-2:  clamp(1.35rem, 1.2rem + 0.7vw, 1.75rem);
  --step-3:  clamp(1.6rem, 1.35rem + 1.2vw, 2.4rem);
  --leading: 1.65;       /* body line-height; .lead reuses it as an absolute value */

  /* --- Spacing --- */
  --space-2xs: 0.25rem;
  --space-xs:  0.5rem;
  --space-s:   0.75rem;
  --space-m:   1rem;
  --space-l:   1.5rem;
  --space-xl:  2.5rem;
  --space-2xl: 4rem;

  /* --- Other --- */
  --wrap: 68.75rem;      /* 1100px, the old --maxw */
  --wrap-narrow: 45rem;  /* comfortable measure for body copy */
  --radius: 0.625rem;
  --radius-lg: 1rem;
  --radius-pill: 999px;
  --shadow: 0 4px 12px rgb(0 0 0 / 0.1);
  --tap: 2.75rem;        /* 44px minimum touch target */
}

/* Breakpoints are written as literal values because custom properties cannot
   be used inside a media query. Keep these three in step with each other:
   48rem = 768px (layout splits), 69rem = 1104px (nav fits on one line).
   69rem is the first width at which --wrap (68.75rem) is fully available, so
   the one-line nav never has less room than it does on a wide screen. It was
   66rem until the Home item was added, which no longer fit there. */

/* ==========================================================================
   2. Base
   ========================================================================== */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font-family: var(--font);
  font-size: var(--step-0);
  line-height: var(--leading);
  color: var(--text);
  background: var(--bg);
}

main { flex: 1 0 auto; }

h1, h2, h3 {
  line-height: 1.2;
  text-wrap: balance;
  margin: 0 0 var(--space-s);
}

h1 { font-size: var(--step-3); }
h2 { font-size: var(--step-2); margin-top: var(--space-xl); }
h3 { font-size: var(--step-1); margin-top: var(--space-l); }

p, li { text-wrap: pretty; }
p { margin: 0 0 var(--space-m); }

/* Links are underlined everywhere so colour is never the only cue (WCAG 1.4.1). */
a {
  color: var(--link);
  text-underline-offset: 0.15em;
}
a:hover { text-decoration-thickness: 2px; }

img { max-width: 100%; height: auto; }

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Red surfaces need a light ring instead, or it disappears into the button. */
.btn--primary:focus-visible,
.accordion > summary:focus-visible {
  outline-color: var(--bg);
  outline-offset: -5px;
}

/* ==========================================================================
   3. Layout helpers
   ========================================================================== */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--space-m);
}

@media (min-width: 48rem) {
  .wrap { padding-inline: var(--space-xl); }
}

.section { padding-block: var(--space-xl); }

/* Beige sections re-point the link token at the red, which passes AA there. */
.bg-beige {
  background: var(--beige);
  --link: var(--rood);
}

.measure { max-width: var(--wrap-narrow); }
.measure--center { margin-inline: auto; }

.skip-link {
  position: absolute;
  left: var(--space-m);
  top: var(--space-m);
  z-index: 100;
  padding: var(--space-s) var(--space-m);
  background: var(--bg);
  color: var(--rood);
  border: 2px solid var(--rood);
  border-radius: var(--radius);
  font-weight: 700;
  transform: translateY(-200%);
}

.skip-link:focus { transform: translateY(0); }

/* ==========================================================================
   4. Header and navigation
   ========================================================================== */

.site-header {
  position: relative;      /* anchor for the desktop language switcher */
  background: var(--bg);
  border-bottom: 4px solid var(--rood);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  padding-block: var(--space-s);
}

.site-logo { display: inline-flex; line-height: 0; }
.site-logo img { height: 2.75rem; width: auto; }

@media (min-width: 48rem) {
  .site-logo img { height: 3.375rem; }
}

/* The wordmark is the same size on every page. It used to be larger on the
   homepage, but that width is what the one-row navigation needs: with the
   bigger logo the English row cleared its budget by only 7px. Owner approved
   2026-09-20. (English has since given up its top-level FAQ item too, so the
   row now has more room than that measurement suggests.) */

/* Without JavaScript the menu is simply always open and the toggle button is
   never shown. The .js class is set by a one-line inline script in <head>, so
   the collapsed state is in place before the first paint and the menu never
   flashes open and then shut. */
.nav-toggle {
  display: none;
  align-items: center;
  gap: var(--space-xs);
  min-height: var(--tap);
  padding-inline: var(--space-s);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.js .nav-toggle { display: inline-flex; }
.nav-toggle:hover { background: var(--hover); }
.nav-toggle__bars { display: block; width: 1.25rem; height: 2px; background: currentColor; position: relative; }
.nav-toggle__bars::before,
.nav-toggle__bars::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  height: 2px;
  background: currentColor;
}
.nav-toggle__bars::before { top: -6px; }
.nav-toggle__bars::after  { top: 6px; }

.nav { width: 100%; }

.nav__list {
  list-style: none;
  margin: 0;
  padding: 0 0 var(--space-m);
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

.nav__link {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  padding: var(--space-xs) var(--space-s);
  border-radius: var(--radius);
  color: var(--text);
  font-weight: 500;
  text-decoration: none;
}

.nav__link:hover { background: var(--hover); text-decoration: underline; }

.nav__link[aria-current="page"] {
  font-weight: 800;
  box-shadow: inset 0 -3px 0 var(--blauw);
}

/* The parent of the section you are in. Weight carries the state as well as
   the rule underneath, so colour is never the only cue (WCAG 1.4.1). It is
   deliberately quieter than aria-current, which marks the actual page.

   --taupe was used here until 2026-09-20; it measured 2.22:1 on white, under
   the 3:1 WCAG 1.4.11 wants from a state indicator. --rood is an existing
   palette colour at 11.45:1 and stays distinct from the blue page marker. */
.nav__link.is-section {
  font-weight: 700;
  box-shadow: inset 0 -3px 0 var(--rood);
}

/* --- Submenu -------------------------------------------------------------
   "Acupunctuur" stays an ordinary link; the chevron beside it is a separate
   button, so the Acupunctuur page is always one click away and the submenu
   never hijacks its link. The list ships open and is collapsed by the script,
   which means the closed state only exists when there is a button to reopen
   it — without JavaScript all six pages are plain, crawlable links. */
.nav__item { display: flex; flex-wrap: wrap; align-items: center; }

.nav__item--has-sub { gap: var(--space-2xs); }

.nav__sub-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  min-width: 2.25rem;      /* 36px, clears the 24px WCAG 2.2 AA minimum */
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--text);
  font: inherit;
  cursor: pointer;
}

.js .nav__sub-toggle { display: inline-flex; }
.nav__sub-toggle:hover { background: var(--hover); }

/* aria-expanded is the single source of truth for the open state: the script
   keeps it correct for pointer, keyboard and hover alike, and this rule is the
   only thing that hides the list. */
.js .nav__sub-toggle[aria-expanded="false"] + .nav__sub { display: none; }

.nav__chevron {
  width: 0.5em;
  height: 0.5em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-0.1em, -0.1em);
  transition: transform 0.2s ease;
}

/* Same pair of transforms the accordion marker uses: the translate belongs to
   the closed state only, because it is rotated along with the shape. */
.nav__sub-toggle[aria-expanded="true"] .nav__chevron {
  transform: rotate(-135deg);
}

.nav__sub {
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
}

.nav__sub-link {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  padding: var(--space-xs) var(--space-s);
  border-radius: var(--radius);
  color: var(--text);
  font-weight: 500;
  text-decoration: none;
}

.nav__sub-link:hover { background: var(--hover); text-decoration: underline; }

.nav__sub-link[aria-current="page"] {
  font-weight: 800;
  box-shadow: inset 0 -3px 0 var(--blauw);
}

/* Language switcher: two real links, so it works without JavaScript and is
   crawlable. The current language is marked rather than hidden. It now lives
   outside the nav list, so on desktop it can sit in the header's top-right
   corner and cost the one-row navigation no width at all. */
.lang {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
}

.lang__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap);
  min-height: var(--tap);
  padding-inline: var(--space-xs);
  border-radius: var(--radius);
  color: var(--text);
  font-weight: 600;
  text-decoration: none;
}

.lang__link:hover { background: var(--hover); text-decoration: underline; }

.lang__link[aria-current="true"] {
  background: var(--rood);
  color: var(--bg);
}

.lang__sep { color: var(--text-soft); }

@media (max-width: 68.999rem) {
  .site-header__inner { flex-wrap: wrap; }
  .js .nav { display: none; }
  .js .nav.is-open { display: block; }

  /* In the stacked menu the submenu is an indented group under its parent
     rather than a dropdown, so it reads as part of the same list. */
  .nav__item--has-sub { justify-content: space-between; }
  .nav__item--has-sub > .nav__link { flex: 1; }
  .nav__sub {
    padding-inline-start: var(--space-m);
    border-inline-start: 2px solid var(--border-soft);
    margin-inline-start: var(--space-s);
  }
}

/* Wide enough for the whole menu on one line. The toggle disappears, the
   submenu becomes a dropdown, and the language switcher moves into the
   header's top-right corner so it costs the row no width.

   The nav must not wrap here, so nowrap is set deliberately: if a future menu
   item no longer fits, it will overflow visibly in testing instead of quietly
   splitting the header into two rows again. Measured at 1104px: the Dutch nav
   needs 730px of 1024px available, the English nav 820px. */
@media (min-width: 69rem) {
  .nav-toggle,
  .js .nav-toggle { display: none; }
  .nav,
  .js .nav { display: block; width: auto; }

  /* Room above the row for the language switcher, which is anchored to the
     viewport edge while the nav is anchored to the content column. Between
     1104px and 1248px those two right edges nearly meet, so the row has to
     clear the switcher vertically rather than rely on horizontal space. */
  .site-header__inner { padding-top: calc(var(--space-l) + var(--space-xs)); }

  .nav__list {
    flex-direction: row;
    align-items: center;
    flex-wrap: nowrap;
    justify-content: flex-end;
    gap: var(--space-2xs);
    padding-bottom: 0;
    /* One step below body copy. The row has to hold nine items in English and
       still fit the 1020px --wrap; at the body size it cleared the budget by
       0px, which no font stack should be trusted with. */
    font-size: 1rem;
  }

  /* Items keep their natural width. Without this they shrink instead, and a
     label silently wraps to two lines rather than the overflow being visible. */
  .nav__list > .nav__item { flex: none; }

  .nav__link,
  .nav-toggle { padding-inline: var(--space-xs); }

  /* The pill is the widest item in the row ("Make an appointment"), so it
     carries the tighter padding rather than every link losing breathing room. */
  .nav__list .btn { padding-inline: var(--space-m); }

  .nav__item--has-sub { position: relative; }

  .nav__sub {
    position: absolute;
    top: 100%;
    inset-inline-start: 0;
    z-index: 20;
    width: max-content;
    max-width: 20rem;
    margin-top: var(--space-2xs);
    padding: var(--space-2xs);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
  }

  .lang {
    position: absolute;
    top: 0;
    inset-inline-end: var(--space-xl);
    font-size: var(--step--1);
  }

  /* 1.75rem = 28px, above the 24px WCAG 2.2 AA target minimum. The switcher
     is a corner control, not part of the main row, so it does not carry the
     44px comfort size the nav items do. */
  .lang__link { min-width: 1.75rem; min-height: 1.75rem; }
}

/* ==========================================================================
   5. Footer
   ========================================================================== */

.site-footer {
  background: var(--bg);
  border-top: 4px solid var(--rood);
  padding-block: var(--space-l);
  margin-top: auto;
}

.site-footer__main {
  display: grid;
  gap: var(--space-l);
  text-align: center;
}

@media (min-width: 48rem) {
  .site-footer__main {
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: var(--space-xl);
    text-align: start;
  }
}

.site-footer p { margin-bottom: var(--space-xs); }
.site-footer a { color: var(--link); }

/* Footer link column. The focus-area pages are not in the navigation, so this
   is their route from every page; the items carry the same 44px target height
   as the navigation rather than sitting as tight body-text links. */
.footer-nav { margin: 0; }

.footer-links {
  list-style: none;
  margin: 0;
  padding: 0;
}

.footer-links a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
}

.footer-logos__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-l);
  align-items: center;
  justify-content: center;
}

@media (min-width: 48rem) {
  .footer-logos__list { justify-content: flex-start; }
}

.footer-logos__list img {
  height: 2.5rem;
  width: auto;
}

.site-footer__legal {
  margin-top: var(--space-l);
  padding-top: var(--space-m);
  border-top: 1px solid var(--border-soft);
  text-align: center;
  font-size: var(--step--1);
  color: var(--text-soft);
}

/* ==========================================================================
   6. Layout primitives
   --------------------------------------------------------------------------
   The old stylesheet had three near-identical "image beside text" blocks
   (.hero-layout, .acupunctuur-layout, .overmij-layout). This is the one
   primitive that replaces all of them.
   ========================================================================== */

.media-text {
  display: grid;
  gap: var(--space-l);
  align-items: center;
}

@media (min-width: 48rem) {
  .media-text { grid-template-columns: 2fr 3fr; gap: var(--space-xl); }
  .media-text--narrow-media { grid-template-columns: 1fr 2fr; }
  /* Homepage: at 2fr the treatment-room photo looked small beside the text.
     Tablets get a modest step up; a full half would squeeze the text into a
     narrow, very tall column. The img sizes attribute mirrors both steps.
     The homepage text is more than twice the photo's height, so centring left
     a large empty band above the photo; it now lines up with the heading. */
  .media-text--wide-media { grid-template-columns: 5fr 6fr; align-items: start; }
}

@media (min-width: 69rem) {
  .media-text--wide-media { grid-template-columns: 1fr 1fr; }
}

/* The homepage photo stays in view while the longer text column scrolls past,
   so the left column never reads as an empty band. Only on screens tall enough
   to show the whole photo; on a short landscape screen a pinned image would
   hide its own lower half. It releases at the end of the section. */
@media (min-width: 48rem) and (min-height: 40rem) {
  .media-text--wide-media > .media-text__media {
    position: sticky;
    top: var(--space-l);
  }
}

.media-text__media { margin: 0; }

.media-text__media img {
  width: 100%;
  border-radius: var(--radius-lg);
  display: block;
}

.lead {
  font-size: var(--step-1);
  color: var(--text-mut);
  /* A unitless line-height multiplies the element's OWN font-size, so at
     --step-1 the lead sat noticeably looser than the paragraphs under it.
     Resolving it against --step-0 gives the same line box as body copy. */
  line-height: calc(var(--step-0) * var(--leading));
}

.page-head { margin-bottom: var(--space-l); }

/* ==========================================================================
   7. Components
   ========================================================================== */

/* --- Buttons --- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  padding: var(--space-s) var(--space-l);
  border: 2px solid transparent;
  border-radius: var(--radius-pill);
  font: inherit;
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
}

.btn--primary {
  background: var(--rood);
  color: var(--bg);
}

/* Hover keeps white text. The old site switched to black on a lightened red,
   which measured 1.91:1 and failed AA outright. */
.btn--primary:hover { background: var(--rood-donker); color: var(--bg); }

.btn--ghost {
  background: transparent;
  color: var(--rood);
  border-color: var(--rood);
}

.btn--ghost:hover { background: var(--hover); }

/* The header call to action is a pill, and squares off inside the stacked
   mobile menu so it lines up with the other items. */
.nav__list .btn { width: 100%; }

@media (min-width: 69rem) {
  .nav__list .btn { width: auto; }
}

/* --- Note / callout --- */
.note {
  background: var(--hover);
  border-inline-start: 6px solid var(--taupe);
  border-radius: var(--radius);
  padding: var(--space-m);
}

.note > :last-child { margin-bottom: 0; }

/* --- Testimonial grid --- */
.quote-grid {
  display: grid;
  gap: var(--space-l);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
}

.quote {
  background: var(--bg);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: var(--space-l);
  margin: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.quote blockquote {
  margin: 0 0 var(--space-m);
  font-style: italic;
  color: var(--text-mut);
}

.quote blockquote p:last-child { margin-bottom: 0; }

.quote figcaption {
  text-align: end;
  font-weight: 600;
  color: var(--text-soft);
}

/* --- Focus-area cards ---
   The whole card is the click target, but the accessible name comes from the
   heading link alone, so a screen reader reads five distinct page titles
   instead of five identical "Lees meer" links. The visible "Lees meer" is
   decorative and aria-hidden in the markup. */
.card-grid {
  display: grid;
  gap: var(--space-l);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
}

.card {
  position: relative;          /* anchor for the stretched link below */
  display: flex;
  flex-direction: column;
  background: var(--beige);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: var(--space-l);
}

.card__title {
  font-size: var(--step-1);
  margin: 0 0 var(--space-xs);
}

.card__title a {
  color: var(--text);
  text-decoration: underline;
  text-decoration-thickness: 1px;
}

/* Stretches the heading link over the whole card so the tap target is the card,
   not just the words. Needs .card to be positioned. */
.card__title a::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.card__teaser {
  color: var(--text-mut);
  margin: 0 0 var(--space-m);
}

/* Pushed to the bottom so cards of different text lengths still line up. */
.card__more {
  margin-top: auto;
  font-weight: 700;
  color: var(--rood);
}

/* The cards became beige on 2026-09-20 and --hover (a near-white) then
   measured 1.03:1 against it — no visible feedback at all. The shadow does
   the work instead, which introduces no new colour: --shadow is black at
   10% opacity, here at 18%. The stretched link's underline also thickens. */
.card:hover {
  box-shadow: 0 6px 16px rgb(0 0 0 / 0.18);
}

/* The ring belongs on the card, because the card is what you activate. */
.card:focus-within {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* The link itself already has the card-wide ring above; a second inner ring
   would just look like a mistake. */
.card__title a:focus-visible { outline: none; }

/* --- Table --- */
.table-scroll { overflow-x: auto; }

.table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: var(--space-l);
}

.table th,
.table td {
  padding: var(--space-s);
  border-bottom: 1px solid var(--border-soft);
  text-align: start;
}

.table th { background: var(--beige); }

/* --- Accordion ---
   Native <details>/<summary>: keyboard operable, exposes its own expanded
   state to assistive tech, and the content stays in the DOM and readable when
   JavaScript is off. The old site used onclick buttons with no aria-expanded. */
.accordion {
  border-radius: var(--radius);
  margin-bottom: var(--space-s);
  background: var(--bg);
}

.accordion > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  min-height: var(--tap);
  padding: var(--space-s) var(--space-m);
  background: var(--rood);
  color: var(--bg);
  border-radius: var(--radius);
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}

.accordion > summary::-webkit-details-marker { display: none; }

.accordion > summary::after {
  content: "";
  flex: none;
  width: 0.6em;
  height: 0.6em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-0.1em, -0.1em);
  transition: transform 0.2s ease;
}

.accordion[open] > summary::after { transform: rotate(-135deg); }
.accordion > summary:hover { background: var(--rood-donker); }

.accordion[open] > summary { border-radius: var(--radius) var(--radius) 0 0; }

.accordion__body {
  /* Only ever painted while the <details> is open, so this is the expanded
     state. Beige needs the same link swap as .bg-beige: --blauw measures
     3.98:1 here and fails AA, --rood measures 9.30:1. */
  background: var(--beige);
  --link: var(--rood);
  padding: var(--space-m);
  border: 1px solid var(--border-soft);
  border-inline-start: 4px solid var(--rood);
  border-top: 0;
  border-radius: 0 0 var(--radius) var(--radius);
}

.accordion__body > :last-child { margin-bottom: 0; }

/* ==========================================================================
   8. Contact form
   ========================================================================== */

.form { max-width: var(--wrap-narrow); }

/* The fieldset groups the inputs for assistive tech; its default border and
   padding would otherwise draw a box the design does not have. */
.form__fieldset {
  border: 0;
  margin: 0;
  padding: 0;
  min-inline-size: 0;
}

.form__grid {
  display: grid;
  gap: var(--space-m);
}

@media (min-width: 45rem) {
  .form__grid { grid-template-columns: 1fr 1fr; }
  .form__field--full { grid-column: 1 / -1; }
}

.form__field { display: flex; flex-direction: column; }

.form__label {
  font-weight: 600;
  margin-bottom: var(--space-2xs);
}

.form__required {
  color: var(--rood);
  font-weight: 700;
}

.form__hint {
  font-size: var(--step--1);
  color: var(--text-mut);
  margin-bottom: var(--space-2xs);
}

.form__input,
.form__textarea {
  width: 100%;
  min-height: var(--tap);
  padding: var(--space-s);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--text);
  font: inherit;
}

.form__textarea {
  min-height: 8rem;
  resize: vertical;
}

.form__input:user-invalid,
.form__textarea:user-invalid {
  border-color: var(--rood);
  border-width: 2px;
}

/* Error text carries an icon-free prefix in the markup, so colour is not the
   only thing distinguishing it. */
.form__error {
  color: var(--rood);
  font-weight: 600;
  font-size: var(--step--1);
  margin-top: var(--space-2xs);
}

.form__error:empty { display: none; }

.form__status { margin-top: var(--space-m); font-weight: 600; }

/* Honeypot: hidden from everyone, including screen readers, because a real
   visitor should never fill it in. */
.form__botcheck {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Confirmation dialog --- */
.dialog {
  max-width: 28rem;
  padding: var(--space-xl);
  border: 0;
  border-radius: var(--radius-lg);
  box-shadow: 0 6px 24px rgb(0 0 0 / 0.25);
  color: var(--text);
  text-align: center;
}

.dialog::backdrop { background: rgb(0 0 0 / 0.45); }
.dialog p { margin-bottom: var(--space-l); }

/* ==========================================================================
   9. Motion
   --------------------------------------------------------------------------
   Opacity and transform only, so nothing reflows and nothing shifts layout.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  .fade-in {
    animation: fade-in 0.5s ease-out both;
  }

  @keyframes fade-in {
    from { opacity: 0; transform: translateY(0.75rem); }
    to   { opacity: 1; transform: none; }
  }
}

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

/* ==========================================================================
   10. Utilities
   ========================================================================== */

.visually-hidden:not(:focus):not(:active) {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.flow > * + * { margin-top: var(--space-m); }
.text-center { text-align: center; }
.mt-l { margin-top: var(--space-l); }
