/* ============================================================
   Keuringsinbox niche sites - world: the inspection sticker.
   One stylesheet for all seven niches. Touches layer-2 tokens
   from brand/tokens.css only; zero hex values.

   CLASS NAMES ARE DUTCH ON PURPOSE. They are the existing design
   system vocabulary, shared verbatim with the portal site in
   services/supplier-portal/static-v2/static/site.css. Renaming
   them here would leave two sites in one repo calling the same
   component two different things. Comments are English.

   WHAT DIFFERS PER NICHE lives in exactly two attributes on
   <html>, set by src/layouts/Page.astro:

     data-categorie   which of the four fields (config/domains.json)
     data-vlak        light or dark, and so which lettering colour

   Both come from the registers. data-vlak is derived from the
   contrast list in config/theme.tokens.json, which records per
   category colour which lettering pair is validated (ink on
   yellow and orange, vinyl white on cobalt and violet). An eighth
   niche in a new cluster fails the build until that pair exists.
   See src/lib/registers.mjs, polarityFor().

   Consequence: a second niche costs zero lines of styling.
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0; background: var(--surface-canvas); color: var(--text-body);
  font-family: var(--font-body); font-size: var(--fs-base); line-height: var(--lh-body);
  font-variant-numeric: tabular-nums; -webkit-font-smoothing: antialiased;
}
h1, h2, h3 { margin: 0; font-family: var(--font-display); font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.005em; color: var(--text-strong); }
p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
a { color: inherit; }
main:focus { outline: none; }
img { max-width: 100%; }

/* ------------------------------------------------ the category field
   The four colours mark a category of inspection, not a year, and
   never stand alone: the name of the course is always next to them
   in text. That is what exempts them from the 3:1 requirement. */
:root { --vlak: var(--categorie-brand); }
html[data-categorie="brand"]     { --vlak: var(--categorie-brand); }
html[data-categorie="hoogte"]    { --vlak: var(--categorie-hoogte); }
html[data-categorie="arbo"]      { --vlak: var(--categorie-arbo); }
html[data-categorie="opleiding"] { --vlak: var(--categorie-opleiding); }

/* The Inverted-Action Rule (DESIGN.md section 2): the action yields the
   brightest field in view. On a light category field that is the black
   button, on a dark field the yellow one. Which of the two applies
   follows from the ground, not from taste. */
html[data-vlak="licht"] {
  --op-vlak-letter: var(--text-strong);
  --op-vlak-actie: var(--color-action);
  --op-vlak-actie-letter: var(--text-on-action);
  --op-vlak-ring: var(--ring-on-sticker);
}
html[data-vlak="donker"] {
  --op-vlak-letter: var(--text-on-inverse);
  --op-vlak-actie: var(--color-action-on-inverse);
  --op-vlak-actie-letter: var(--text-on-action-inverse);
  --op-vlak-ring: var(--ring-on-inverse);
}

:focus-visible { outline: var(--focus-ring-width) solid var(--ring); outline-offset: var(--focus-ring-offset); }
.op-donker:focus-visible { outline-color: var(--ring-on-inverse); }
.aanvraag__kop :focus-visible, .beloftes :focus-visible { outline-color: var(--op-vlak-ring); }

.overslaan { position: absolute; left: -9999px; top: 0; z-index: 10; min-height: var(--target-min);
  display: inline-flex; align-items: center; padding: 0 var(--space-6);
  background: var(--color-action-on-inverse); color: var(--text-on-action-inverse);
  font-family: var(--font-display); font-weight: 700; text-transform: uppercase; text-decoration: none; }
.overslaan:focus { left: var(--space-6); top: var(--space-6); }

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

/* ---------------------------------------------------------- buttons */
.knop { display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--target-min); padding: 0 var(--space-7);
  border: var(--rule-strong) solid var(--color-action);
  background: var(--color-action); color: var(--text-on-action);
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-base);
  text-transform: uppercase; letter-spacing: 0.06em; text-decoration: none; cursor: pointer;
  transition: background var(--motion-state) var(--motion-ease), color var(--motion-state) var(--motion-ease); }
.knop:hover { background: transparent; color: var(--color-action); }
.knop--op-donker { background: var(--color-action-on-inverse); color: var(--text-on-action-inverse);
  border-color: var(--color-action-on-inverse); }
.knop--op-donker:hover { background: transparent; color: var(--color-action-on-inverse); }
/* The hero has exactly one action, so it may be the loudest thing after the
   headline. Height and letter only: a second colour would break the
   Inverted-Action Rule, which says the action yields the brightest field in
   view and nothing else. */
.knop--groot { min-height: 3.5rem; padding-inline: var(--space-8); font-size: var(--fs-lg); }

/* ------------------------------------------------------------ the bar */
.balk { background: var(--surface-inverse-deep); color: var(--text-on-inverse);
  padding: var(--space-4) var(--space-7); }
.balk__rij { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--space-4) var(--space-6); }
.merk { display: inline-flex; align-items: center; gap: var(--space-5); text-decoration: none;
  min-height: var(--target-min); }
.merk img { display: block; border-radius: var(--radius-sm); }
.merk__naam { display: grid; }
.merk__woord { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-lg);
  text-transform: uppercase; letter-spacing: 0.04em; }
.merk__onder { font-size: var(--fs-2xs); color: var(--text-muted-on-inverse); }
.balk__nav { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4) var(--space-6); }
.balk__nav a { display: inline-flex; align-items: center; min-height: var(--target-min);
  font-size: var(--fs-sm); font-weight: 600; text-decoration: none;
  border-bottom: var(--rule-strong) solid transparent;
  transition: border-color var(--motion-state) var(--motion-ease); }
.balk__nav a:hover { border-bottom-color: var(--color-action-on-inverse); }

/* --------------------------------------------------- the menu, scriptless
   Below 48rem the bar wrapped onto a second line: the wordmark on one, the
   links on the next. Two lines of chrome above the fold on the smallest screen
   is the most expensive place to spend them.

   A checkbox and not details/summary. See the note in Bar.astro: details cannot
   serve both layouts, because whether it is open is an attribute and CSS cannot
   set one. Measured in Chrome, not assumed.

   The checkbox is hidden but NOT `display: none` -- it has to stay focusable, or
   the menu becomes unreachable by keyboard. Clipped to a pixel behind the label
   instead, with the focus ring drawn on the label. */
.balk__menu { position: relative; }
.balk__schakelaar { position: absolute; width: 1px; height: 1px; margin: 0;
  opacity: 0; pointer-events: none; }
.balk__knop { display: inline-flex; align-items: center; gap: var(--space-4);
  min-height: var(--target-min); padding: 0 var(--space-5);
  border: var(--rule-strong) solid var(--text-on-inverse); border-radius: var(--btn-radius);
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-2xs);
  letter-spacing: 0.06em; text-transform: uppercase; cursor: pointer; }
.balk__knop svg { display: block; }
.balk__schakelaar:focus-visible + .balk__knop {
  outline: var(--focus-ring-width) solid var(--ring-on-inverse); outline-offset: var(--focus-ring-offset); }
.balk__schakelaar:checked + .balk__knop { background: var(--color-action-on-inverse);
  color: var(--text-on-action-inverse); border-color: var(--color-action-on-inverse); }

/* Closed is the default on a narrow screen; open hangs the panel UNDER the bar
   rather than pushing the page down, because a menu that reflows the content
   behind it moves the thing the visitor was reading. */
.balk__nav { display: none; }
.balk__schakelaar:checked ~ .balk__nav { display: flex; position: absolute; right: 0; z-index: 5;
  flex-direction: column; align-items: stretch; gap: 0;
  min-width: 12rem; margin-top: var(--space-4);
  background: var(--surface-inverse-deep); border: var(--rule-width) solid var(--border-inverse);
  padding: var(--space-4) var(--space-6); }
.balk__schakelaar:checked ~ .balk__nav a { border-bottom: var(--rule-width) solid var(--border-inverse); }
.balk__schakelaar:checked ~ .balk__nav a:last-child { border-bottom: 0; }

/* Wide: no disclosure at all. The wrapper leaves the layout so the nav sits in
   the bar's own flex row, and the toggle is both hidden and taken out of the tab
   order -- a focusable control that does nothing is worse than no control. */
@media (min-width: 48rem) {
  .balk__menu { display: contents; }
  .balk__schakelaar, .balk__knop { display: none; }
  .balk__nav, .balk__schakelaar:checked ~ .balk__nav {
    display: flex; position: static; flex-direction: row; align-items: center;
    gap: var(--space-4) var(--space-6); min-width: 0; margin-top: 0;
    background: none; border: 0; padding: 0; }
  .balk__schakelaar:checked ~ .balk__nav a { border-bottom: var(--rule-strong) solid transparent; }
}

/* ------------------------------------------------------------ the hero
   The first screen is a sticker: one category field, the mark, what
   this is, and one thing to do. Not a brochure with a button
   underneath, and not a floating product card beside a heading -- both
   are named in the anti-references, and the second is what stood here
   until the form moved to /offerte. */
.hero { background: var(--vlak); color: var(--op-vlak-letter);
  border-bottom: var(--die-width) solid var(--border-die);
  padding: var(--space-8) var(--space-7) var(--space-9); }
.hero__grid { display: grid; gap: var(--space-9); align-items: end; }
@media (min-width: 64rem) {
  .hero { padding-block: var(--space-10) var(--space-9); }
  .hero__grid { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    column-gap: var(--space-10); }
}
/* Not smaller than 70 px: below that the month ticks of the full mark close
   up and the compact variant is the right one (DESIGN.md section 5). */
.hero__etiket { display: block; width: 5rem; height: auto; margin-bottom: var(--space-6); }
@media (min-width: 48rem) { .hero__etiket { width: 6.25rem; } }
.hero h1 { font-size: var(--fs-3xl); line-height: var(--lh-tight); letter-spacing: -0.015em;
  max-width: 13ch; text-wrap: balance; color: inherit; }
.hero__lead { margin-top: var(--space-6); max-width: 44ch; font-size: var(--fs-lg); line-height: 1.35; }
.hero__actie { margin-top: var(--space-8); }
/* The line that answers the objection, directly under the button. Same
   colour as everything else on the field: on these four category colours
   there is no room for a muted tint that still clears 4.5:1 -- vinyl-200
   reaches 4.27:1 on kobalt and vinyl-400 only 3.10:1. The step down is
   made with size and weight instead. */
.hero__onder { margin-top: var(--space-5); font-size: var(--fs-sm); }

/* --------------------------------------------------------- the request
   The quote page. The page ground carries it and the card is the
   bundle's own, so the category colour appears here as the sticker and
   as the 3 px rule on top of that card, not as a full field. A form is
   read, not looked at. */
.aanvraag { padding: var(--space-9) var(--space-7) var(--space-10); }
.aanvraag__kop { margin-bottom: var(--space-8); }
.aanvraag__etiket { display: block; width: 4.375rem; height: auto; margin-bottom: var(--space-6); }
/* 28ch, not 20: at 20 this heading broke into three lines of caps standing
   over a form, which reads as the page shouting before it asks anything. The
   lead runs the full column rather than to a reading measure of its own,
   because a paragraph that stops well short of the card under it leaves an
   edge nothing else explains. */
.aanvraag h1 { font-size: var(--fs-2xl); line-height: var(--lh-snug); letter-spacing: -0.01em;
  max-width: 28ch; text-wrap: balance; }
.aanvraag__lead { margin-top: var(--space-5); color: var(--text-body); }

.beloftes { display: grid; gap: var(--space-4); align-content: start; max-width: 44ch; }
.beloftes li { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-5);
  align-items: baseline; font-size: var(--fs-sm); font-weight: 500;
  padding-top: var(--space-4); border-top: var(--rule-width) solid currentcolor; }
.beloftes li::before { content: ""; width: 0.75rem; height: 0.75rem;
  border-radius: var(--radius-full); background: currentcolor; }
/* On the hero the promises sit beside the headline and carry the base of
   the field; four columns would make them a card grid, which this world
   does not do. One column, ruled, aligned to the bottom of the copy. */
.beloftes--rij { max-width: none; }
.beloftes--onder { margin-top: var(--space-9); max-width: none; color: var(--text-muted); }
.beloftes--onder li { border-top-color: var(--border-hairline); }
.beloftes--onder li::before { background: var(--vlak); }

/* ---------------------------------------------------------- the card
   White field, 10 px radius, applied shadow: the card shape of this
   brand.

   WHO DRAWS IT. Exactly one of two things, never both. The funnel
   bundle carries this same card on its own root, because it has to be
   embeddable on a page that gives it nothing; so when the bundle is
   there, the bundle is the card. Until 2026-09-02 this container drew
   one as well and the result was a card inside a card: two radii, two
   shadows, and double padding, with the bundle's 3 px category rule
   reading as a stray line partway in. Nested cards are named in the
   craft floor as always wrong, and this was that.

   So this element is now a bare box. The static fallback below it
   carries its own card, which keeps the one case that still needs one:
   the bundle missing or refusing to start, with dark text that would
   otherwise sit straight on the category colour. */
.formulier { color: var(--text-body); }
.formulier__terugval { background: var(--surface-card); color: var(--text-body);
  border-top: var(--die-width) solid var(--vlak);
  border-radius: var(--card-radius); box-shadow: var(--elevation-applied);
  padding: var(--space-7) var(--space-6); }
.formulier__kop { font-size: var(--fs-lg); line-height: var(--lh-snug); }
.formulier__lead { margin-top: var(--space-4); font-size: var(--fs-sm); color: var(--text-muted); }

/* The notice block. The reason a form is still switched off belongs above it
   and not in small print underneath (DESIGN.md section 5, the Closed-State
   Rule). check-site.mjs ties this text to platformLive in both directions:
   after opening it has to disappear again. */
.melding { margin-top: var(--space-6); background: var(--status-warn-wash); color: var(--text-body);
  border-left: var(--die-width) solid var(--status-warn-line);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  padding: var(--space-5) var(--space-6); font-size: var(--fs-sm); }
.melding b { display: block; font-family: var(--font-display); font-weight: 700;
  text-transform: uppercase; color: var(--text-strong); margin-bottom: var(--space-2); }
/* The same block on the category field. It keeps its own light ground rather
   than going transparent: the warn wash and the ink on it are a validated pair,
   and on four different category colours nothing else is. */
.melding--op-vlak { margin-top: var(--space-8); max-width: 48ch; }
.melding__actie { display: block; margin-top: var(--space-5); }
.melding__actie a { font-weight: 700; }

.vgroep__kop { margin-top: var(--space-8); padding-top: var(--space-6);
  border-top: var(--rule-width) solid var(--border-hairline);
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-2xs);
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-muted); }

/* What the request asks, in sentences. This is the state before the funnel
   bundle runs and for anyone without JavaScript; the bundle replaces it. */
.gevraagd { margin-top: var(--space-5); display: grid; gap: var(--space-4); }
.gevraagd li { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-5);
  align-items: baseline; font-size: var(--fs-sm);
  padding-top: var(--space-4); border-top: var(--rule-width) solid var(--border-hairline); }
/* Ink rather than the category colour: yellow on white is all but invisible
   as a dot, and a brand mark that disappears on some niches is not a mark. */
.gevraagd li::before { content: ""; width: 0.5rem; height: 0.5rem;
  border-radius: var(--radius-full); background: var(--color-action); }

/* -------------------------------------------------------- the bands */
.band { padding: var(--space-9) var(--space-7); }
.band--tint { background: var(--surface-tint); }
@media (min-width: 62rem) { .band { padding-block: var(--space-10); } }
.band h2 { font-size: var(--fs-2xl); line-height: var(--lh-snug); }
.band__intro { margin-top: var(--space-5); max-width: 62ch; font-size: var(--fs-lg); line-height: 1.4; }
.band__tekst { margin-top: var(--space-6); max-width: 68ch; }

.kaarten { display: grid; gap: var(--space-5); margin-top: var(--space-7); }
@media (min-width: 48rem) { .kaarten { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 76rem) { .kaarten { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.kaarten li { background: var(--surface-card); border-radius: var(--card-radius);
  padding: var(--space-6); border-left: var(--die-width) solid var(--vlak); }
.band--tint .kaarten li { box-shadow: var(--elevation-applied); }
.kaarten b { display: block; font-family: var(--font-display); font-weight: 700;
  font-size: var(--fs-lg); line-height: 1.25; color: var(--text-strong); }
.kaarten span { display: block; margin-top: var(--space-4); font-size: var(--fs-sm); color: var(--text-muted); }

/* The course cards as the second way in to /offerte.
   The link fills the card rather than sitting inside it, so the whole block is
   the target instead of the four words of the title. The padding therefore moves
   from the li to the a: keeping it on both would put an untappable ring of dead
   space around a control that looks tappable, which is the worst of the two.
   Underline only on the title, and only on hover: a card that underlines all its
   text on hover reads as broken rather than as interactive. */
.kaarten--klikbaar li { padding: 0; }
.kaarten--klikbaar a { display: block; padding: var(--space-6); min-height: var(--target-min);
  text-decoration: none; color: inherit;
  transition: background var(--motion-state) var(--motion-ease); }
/* The title is underlined ALWAYS, not on hover. Directly under this section sit
   four Spelregels cards in the same shape that are not links, and with the cue
   held back until hover the two grids are indistinguishable -- on a touch screen
   there is no hover at all, so half the visitors would never learn these four
   lead somewhere. An underline is the one link affordance this world already
   uses in running text, and it needs no icon set. */
.kaarten--klikbaar b { text-decoration: underline; text-underline-offset: 0.15em;
  text-decoration-thickness: from-font; }
.kaarten--klikbaar a:hover { background: var(--color-action-wash); }

/* ------------------------------------------------------------ the FAQ */
.vraag { border-top: var(--rule-width) solid var(--border-strong); }
.vraag:last-of-type { border-bottom: var(--rule-width) solid var(--border-strong); }
.vraag summary { display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-5); min-height: var(--target-min); padding-block: var(--space-4);
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-lg);
  color: var(--text-strong); cursor: pointer; list-style: none; }
.vraag summary::-webkit-details-marker { display: none; }
.vraag summary::after { content: "+"; font-size: var(--fs-lg); line-height: 1; }
.vraag[open] summary::after { content: "\2212"; }
.vraag p { padding-bottom: var(--space-6); max-width: 68ch; font-size: var(--fs-sm); }
#faq h2 { margin-bottom: var(--space-6); }

/* --------------------------------------------------------- the closer */
.slot { background: var(--surface-inverse); color: var(--text-on-inverse);
  padding: var(--space-9) var(--space-7); }
.slot h2 { color: var(--text-on-inverse); font-size: var(--fs-2xl); line-height: var(--lh-snug); }
.slot p { margin-top: var(--space-5); max-width: 52ch; color: var(--text-muted-on-inverse); }
.acties { margin-top: var(--space-7); }

/* --------------------------------------------------------- the footer */
.voet { background: var(--surface-inverse-deep); color: var(--text-muted-on-inverse);
  padding: var(--space-9) var(--space-7) var(--space-7); }
.voet__grid { display: grid; gap: var(--space-8); }
@media (min-width: 62rem) { .voet__grid { grid-template-columns: minmax(0, 2fr) repeat(2, minmax(0, 1fr));
  column-gap: var(--space-9); } }
.voet__wat { max-width: 46ch; font-size: var(--fs-sm); }
.voet__wat + .voet__wat { margin-top: var(--space-5); }
.voet h2 { font-size: var(--fs-2xs); letter-spacing: 0.14em; color: var(--text-on-inverse);
  margin-bottom: var(--space-4); }
.voet ul { display: grid; gap: var(--space-2); }
.voet li a { display: inline-flex; align-items: center; min-height: var(--target-min);
  font-size: var(--fs-sm); text-decoration: none; border-bottom: var(--rule-width) solid transparent; }
.voet li a:hover { border-bottom-color: var(--color-action-on-inverse); }
.voet__regel { margin-top: var(--space-8); padding-top: var(--space-5);
  border-top: var(--rule-width) solid var(--border-inverse); font-size: var(--fs-sm); }
.voet__regel a { color: var(--text-on-inverse); }

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