/* =========================================================================
   Homepage-hero "het knooppunt" (HeroKlantcontact.razor, 15 okt 2026;
   verving css/hero-klantcontact.css).

   De basis (kop, inkt, knoppen, achtergrond, binnenkomst, parallax) komt uit
   landing.css (.rg-hero). Dit bestand voegt toe:
   - de indeling: tekst links en tafereel rechts vanaf 960 px (landing.css
     wacht tot 1200 px), een kop die op het bureaublad 3-4 regels beslaat;
   - het tafereel: een vlak met de vaste verhouding van zijn viewBox
     (400 x 430) met banen, sporen, kometen, vier stations en hun ballonnen
     (het vierde station is het CRM met Claude en ChatGPT erin),
     en in dezelfde rastercel de klantkaart met de tellers eronder;
   - de productrij met het product van het moment in zijn kleur.

   De tijdlijn speelt js/heroKlantcontact.js. Het zet alleen klassen op
   elementen met data-kc-stap (is-zicht, is-weg, is-actief, is-nieuw,
   is-vol), data-kc-product en data-kc-speelt op de hero.

   Regels die overal gelden:
   - Alleen transform, opacity en (voor de sporen) stroke-dashoffset
     bewegen. Kleurwissels en ringen zijn lagen (::before/::after) die
     invagen.
   - De server-HTML staat in de beginstand. Zonder JavaScript, bij minder
     beweging, bij een fout (data-kc-speelt="fout") en via het vangnet (na
     3 s, als er geen script speelt of wacht) toont deze CSS de eindstand.
   - Alleen --rg-*-tokens: --rg-reserveren en --rg-productkleur (landing.css)
     en --rg-merk-claude en --rg-merk-chatgpt (product-hero.css) horen daarbij.
   ========================================================================= */

/* Geen draad in deze hero: de inkt begint meteen op het hoogtepunt
   (landing.css wacht vanaf 1200px op de draad van de chathero). */
.landing-root .rg-hero.rg-kc { --rg-inkt-wacht: 0ms; }

/* Geen vinkje achter de kop: het laatste accentwoord houdt alleen zijn
   gewone inktruimte, niet de plek die landing.css voor het vinkje van de
   chathero reserveert (anders balanceert de kop om een gat). */
.landing-root .rg-kc .rg-hero__accent > .rg-w:last-child { padding-inline-end: 0.06em; }

/* Een veer voor wat opspringt (stations, kaart, stempel): schiet iets door
   en komt dan tot rust. */
.landing-root .rg-kc { --rg-kn-veer: cubic-bezier(0.34, 1.56, 0.64, 1); }

/* De kleur van elk station, ook voor zijn spoor, komeet en regel. Station 4
   is het CRM (met Claude en ChatGPT erin): CRM-paars. Claude-oranje staat
   alleen in zijn badge en aan het begin van zijn spoor (het verloop
   hieronder). */
.landing-root .rg-kc :is(.rg-kn__station--tel, .rg-kn__spoor--tel, .rg-kn__komeet--tel, .rg-kn__regel--tel) { --rg-kn-kleur: var(--rg-settled); }
.landing-root .rg-kc :is(.rg-kn__station--res, .rg-kn__spoor--res, .rg-kn__komeet--res, .rg-kn__regel--res) { --rg-kn-kleur: var(--rg-reserveren); }
.landing-root .rg-kc :is(.rg-kn__station--web, .rg-kn__spoor--web, .rg-kn__komeet--web, .rg-kn__regel--web) { --rg-kn-kleur: var(--rg-primary); }
.landing-root .rg-kc :is(.rg-kn__station--ai, .rg-kn__spoor--ai, .rg-kn__komeet--ai, .rg-kn__regel--ai) { --rg-kn-kleur: var(--rg-primary); }

/* --- Indeling ------------------------------------------------------------ */

/* Vanaf 960 px tekst links en tafereel rechts, iets meer ruimte voor het
   tafereel. Specifieker dan landing.css (één kolom tot 1200 px, daarna
   0,9fr/1,1fr), dus deze regel wint op elke breedte vanaf 960 px. */
@media (min-width: 960px) {
  .landing-root .rg-kc .rg-hero__grid {
    grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
    gap: clamp(2rem, 3.5vw, 3rem);
    align-items: center;
  }
  /* landing.css centreert de tekst tot 1200 px (tafereel eronder); naast
     het tafereel staat hij links. */
  .landing-root .rg-kc .rg-hero__copy { text-align: start; }
  .landing-root .rg-kc .rg-hero__copy .rg-measure-sm { margin-inline: 0; }
  .landing-root .rg-kc .rg-hero__actions,
  .landing-root .rg-kc .rg-hero__assurances { justify-content: flex-start; }
  /* Een kleinere kop dan de gewone hero-kop: in de halve kolom beslaat hij
     zo 3-4 regels in plaats van 5-6. */
  .landing-root .rg-kc .rg-hero__title {
    max-width: none;
    margin-inline: 0;
    font-size: clamp(2.5rem, 1.25rem + 2.4vw, 3.5rem);
  }
}

/* --- Het podium: vlak en kern in één rastercel --------------------------- */

/* Ook op de telefoon in beeld (landing.css verbergt daar het podium van de
   chathero), dan onder de tekst op de volle breedte. De knoppen en
   zekerheden houden daar de knopbaan van de support-knop vrij (landing.css);
   het tafereel is decor zonder bediening. */
.landing-root .rg-kc .rg-kc__podium {
  display: grid;
  font-family: var(--rg-body);
  width: 100%;
  max-width: 35rem;
  margin-inline: auto;
  min-width: 0;
}

/* Het vlak heeft de verhouding van de viewBox; de stations en ballonnen
   staan in procenten erop. Het deelt de rastercel met de kern: het podium
   is zo hoog als de hoogste van de twee, en de baan steekt nooit uit. */
.landing-root .rg-kn__vlak {
  grid-area: 1 / 1;
  align-self: start;
  position: relative;
  aspect-ratio: 400 / 430;
  pointer-events: none;
}
.landing-root .rg-kn__kern {
  grid-area: 1 / 1;
  position: relative;
  z-index: 2;
}
.landing-root .rg-kn__sporen {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* --- Baan, banen, sporen en kometen (SVG) -------------------------------- */

/* De baan om de kaart draait heel langzaam, zolang de hero in beeld is:
   landing.js zet .is-uit op de hero als hij uit beeld is. De baan is een
   eigen <svg>-laag over het hele vlak (zelfde viewBox als de sporen) die als
   geheel draait, om het midden van de ellips: (200,268) in de viewBox is
   50% van de breedte en 268/430 = 62,3256% van de hoogte. Een draaiend
   element (geen SVG-kind) kan op de compositor blijven lopen terwijl Blazor
   opstart. Na de Blazor-vervanging zet js/heroKlantcontact.js de nieuwe baan
   op dezelfde stand (zetBaanInFase), zodat hij niet terugspringt naar 0°.
   .rg-hero knipt overloop af (landing.css): de hoeken van de draaiende laag
   steken nergens uit. */
.landing-root .rg-kn__orbit {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  transform-origin: 50% 62.3256%;
  animation: rgKnDraai 40s linear infinite;
}
.landing-root .rg-kn__orbit ellipse {
  fill: none;
  stroke: color-mix(in srgb, var(--rg-primary) 18%, transparent);
  stroke-width: 1;
  stroke-dasharray: 2 7;
}
.landing-root .rg-kc.is-uit .rg-kn__orbit { animation-play-state: paused; }
@keyframes rgKnDraai { to { transform: rotate(360deg); } }

.landing-root .rg-kn__banen {
  opacity: 0;
  transition: opacity 800ms ease;
}
.landing-root .rg-kn__banen path {
  fill: none;
  stroke: var(--rg-line-strong);
  stroke-width: 1.2;
  stroke-dasharray: 3 5;
}
.landing-root .rg-kn__banen.is-zicht { opacity: 1; }

/* Een spoor tekent zich (pathLength="1": de streep is het hele pad). */
.landing-root .rg-kn__spoor {
  fill: none;
  stroke: var(--rg-kn-kleur);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  opacity: 0.9;
  transition: stroke-dashoffset 900ms var(--rg-ease);
}
.landing-root .rg-kn__spoor.is-zicht { stroke-dashoffset: 0; }

/* Het spoor van het CRM verloopt van Claude-oranje (bij het station) naar
   CRM-paars (bij de kaart): Claude stelt iets voor, het landt in het CRM.
   Het verloop staat in de markup (linearGradient #rg-kn-verloop-ai in
   HeroKlantcontact.razor); hier alleen de kleuren van zijn twee stops. */
/* Met een terugvalkleur: de site heeft <base href="/">, en een browser die
   "#rg-kn-verloop-ai" tegen die basis oplost (op /en, /zh) vindt het verloop
   niet; dan wordt het spoor effen CRM-paars in plaats van onzichtbaar. */
.landing-root .rg-kn__spoor--ai { stroke: url(#rg-kn-verloop-ai) var(--rg-primary); }
.landing-root .rg-kn__verloop-begin { stop-color: var(--rg-merk-claude); }
.landing-root .rg-kn__verloop-eind { stop-color: var(--rg-primary); }

.landing-root .rg-kn__komeet { fill: var(--rg-kn-kleur); opacity: 0; }
.landing-root .rg-kn__komeet.is-zicht { opacity: 1; }
.landing-root .rg-kn__komeet-gloed { opacity: 0.25; }

/* --- Stations ------------------------------------------------------------- */

.landing-root .rg-kn__station {
  position: absolute;
  z-index: 3;
  width: 17%;
  aspect-ratio: 1;
  /* Het midden van de tegel op left/top (margin in % van de breedte). */
  margin: -8.5% 0 0 -8.5%;
  display: grid;
  place-items: center;
  border-radius: 30%;
  background: var(--rg-surface);
  border: 1px solid var(--rg-line);
  box-shadow: 0 14px 30px -18px color-mix(in srgb, var(--rg-ink) 50%, transparent);
  color: var(--rg-kn-kleur);
  font-size: clamp(0.875rem, 3.4vw, 1.375rem);
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 400ms ease, transform 700ms var(--rg-kn-veer);
}
.landing-root .rg-kn__station.is-zicht { opacity: 1; transform: none; }
/* Het begin van elk spoor (de viewBox gedeeld door 400 x 430). */
.landing-root .rg-kn__station--tel { left: 13%; top: 20%; }
.landing-root .rg-kn__station--res { left: 38%; top: 9%; }
.landing-root .rg-kn__station--web { left: 62%; top: 9%; }
.landing-root .rg-kn__station--ai  { left: 87%; top: 20%; }

/* Aan de beurt: een ring in de kleur van het station (invagen) en twee
   pulsen. */
.landing-root .rg-kn__station::before,
.landing-root .rg-kn__station::after {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  border: 2px solid var(--rg-kn-kleur);
  opacity: 0;
  pointer-events: none;
}
.landing-root .rg-kn__station::after {
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--rg-kn-kleur) 14%, transparent),
              0 18px 34px -16px color-mix(in srgb, var(--rg-kn-kleur) 70%, transparent);
  transition: opacity 300ms ease;
}
.landing-root .rg-kn__station.is-actief::after { opacity: 1; }
.landing-root .rg-kc[data-kc-speelt="1"] .rg-kn__station.is-actief::before { animation: rgKnPuls 1.2s var(--rg-ease) 2; }
@keyframes rgKnPuls {
  from { transform: scale(1); opacity: 0.7; }
  to   { transform: scale(1.55); opacity: 0; }
}

/* De twee badges op de rechterbovenhoek van de tegel van het CRM, als een
   stapeltje avatars van wie er meewerkt: Claude en ChatGPT werken ín het CRM.
   Het CRM-icoon blijft zo even groot en gecentreerd als bij de andere tegels
   (eigenaar, 15 okt: "variant A"). Elk badge een rond plaatje met het
   merkteken (wwwroot/images/merken/, Simple Icons, CC0) als masker in zijn
   merkkleur: Claude-oranje, en OpenAI zwart op wit (de merkregels van OpenAI).
   Maten in procenten van de tegel, zodat ze op elke breedte meeschalen; de
   witte ring (box-shadow) laat ze los van de tegel en van elkaar lezen. */
.landing-root .rg-kn__badge {
  position: absolute;
  top: -12%;
  width: 32%;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--rg-surface);
  box-shadow: 0 0 0 2px var(--rg-surface),
              0 3px 8px -3px color-mix(in srgb, var(--rg-ink) 45%, transparent);
}
/* Overlappend: ChatGPT steekt rechts uit de hoek, Claude ligt er half overheen. */
.landing-root .rg-kn__badge--chatgpt { right: -14%; z-index: 1; }
.landing-root .rg-kn__badge--claude { right: 8%; z-index: 2; }
.landing-root .rg-kn__badge::before {
  content: "";
  width: 62%;
  height: 62%;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
.landing-root .rg-kn__badge--claude::before {
  background: var(--rg-merk-claude);
  -webkit-mask-image: url("../images/merken/claude.svg");
  mask-image: url("../images/merken/claude.svg");
}
.landing-root .rg-kn__badge--chatgpt::before {
  background: var(--rg-merk-chatgpt);
  -webkit-mask-image: url("../images/merken/openai.svg");
  mask-image: url("../images/merken/openai.svg");
}

.landing-root .rg-kn__label {
  position: absolute;
  top: 104%;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font-size: clamp(0.5625rem, 2.2vw, 0.6875rem);
  font-weight: 600;
  color: var(--rg-text-soft);
}
/* Op een smal scherm (onder 360 px) passen de namen van de twee middelste
   stations niet naast elkaar op één regel ("ReservationsWebshop chatbot"):
   dan mag een naam op twee regels, hooguit 130% van de tegel breed. De
   middens van die stations liggen 24% van het vlak uit elkaar en een tegel
   is 17% breed, dus 2 x 65% = 130% laat er altijd ruimte tussen. */
@media (max-width: 359.98px) {
  .landing-root .rg-kn__label {
    width: max-content;
    max-width: 130%;
    white-space: normal;
    text-align: center;
    line-height: 1.15;
  }
}

/* --- Ballonnen ------------------------------------------------------------ */

.landing-root .rg-kn__ballon {
  position: absolute;
  z-index: 4;
  max-width: 44%;
  padding: 0.4375rem 0.625rem;
  border-radius: 0.75rem;
  font-size: clamp(0.625rem, 2.5vw, 0.75rem);
  line-height: 1.3;
  background: var(--rg-ink);
  color: var(--rg-surface);
  box-shadow: 0 12px 26px -14px color-mix(in srgb, var(--rg-ink) 70%, transparent);
  opacity: 0;
  transform: translateY(6px) scale(0.96);
  transition: opacity 350ms ease, transform 500ms var(--rg-kn-veer);
}
.landing-root .rg-kn__ballon.is-zicht { opacity: 1; transform: none; }
.landing-root .rg-kn__ballon.is-zicht.is-weg {
  opacity: 0;
  transform: translateY(-8px) scale(0.96);
  transition: opacity 450ms ease, transform 600ms var(--rg-ease);
}
.landing-root .rg-kn__ballon small {
  display: block;
  margin-bottom: 2px;
  font-family: var(--rg-mono);
  font-size: 0.82em;
  opacity: 0.7;
}
.landing-root .rg-kn__ballon--tel { left: 2%; top: 30%; }
.landing-root .rg-kn__ballon--res { left: 28%; top: 19.5%; }
.landing-root .rg-kn__ballon--web { left: 50%; top: 19.5%; }
.landing-root .rg-kn__ballon--ai  { right: 1%; top: 30%; }
/* Op de telefoon zijn de ballonnen van de telefonist en Claude met de echte
   teksten 4-6 regels hoog; onder hun station vielen ze dan over de kop van
   de klantkaart. Daar zijn ze breder (minder regels) en staat hun onderkant
   net boven de kaart: de bovenrand van de kaart ligt op 45% van de breedte,
   dat is 45 x 400 / 430 = 41,86% van de hoogte van het vlak, dus
   "bottom: 59%" houdt een kleine marge. Ze groeien dan omhoog, over de
   onderkant van hun eigen station: een ballon die uit het station komt. */
@media (max-width: 479.98px) {
  .landing-root .rg-kn__ballon--tel,
  .landing-root .rg-kn__ballon--ai { top: auto; bottom: 59%; max-width: 56%; }
  /* Ook de middelste twee: met een breder lettertype (Linux, een andere
     fallback) worden ze een regel hoger en vielen ze 10 px over de kaartkop.
     Met hun onderkant boven de kaart groeien ze omhoog, wat de tekst ook doet. */
  .landing-root .rg-kn__ballon--res,
  .landing-root .rg-kn__ballon--web { top: auto; bottom: 59%; }
}

/* --- De klantkaart ---------------------------------------------------------- */

/* Bovenrand precies op het eindpunt van de sporen: 180/400 = 45% van de
   breedte (een marge in procenten rekent met de breedte). */
.landing-root .rg-kn__kaart {
  position: relative;
  margin: 45% auto 0;
  width: min(78%, 20.625rem);
  padding: 4% 4.5%;
  background: var(--rg-surface);
  border: 1px solid var(--rg-line);
  border-radius: 1.125rem;
  box-shadow: 0 30px 60px -34px color-mix(in srgb, var(--rg-ink) 55%, transparent);
  opacity: 0;
  transform: scale(0.92);
  transition: opacity 500ms ease, transform 800ms var(--rg-kn-veer);
}
.landing-root .rg-kn__kaart.is-zicht { opacity: 1; transform: none; }
/* Vol: een groene rand met gloed, als laag die invaagt. */
.landing-root .rg-kn__kaart::after {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  box-shadow: 0 0 0 1px var(--rg-settled),
              0 0 0 7px color-mix(in srgb, var(--rg-settled) 12%, transparent),
              0 34px 70px -30px color-mix(in srgb, var(--rg-settled) 55%, transparent);
  opacity: 0;
  transition: opacity 800ms var(--rg-ease);
  pointer-events: none;
}
.landing-root .rg-kn__kaart.is-vol::after { opacity: 1; }

.landing-root .rg-kn__schok {
  position: absolute;
  inset: -2px;
  border-radius: 1.25rem;
  border: 2px solid var(--rg-settled);
  opacity: 0;
  pointer-events: none;
}
.landing-root .rg-kn__schok.is-zicht { animation: rgKnSchok 1.1s var(--rg-ease) forwards; }
@keyframes rgKnSchok {
  from { opacity: 0.8; transform: scale(1); }
  to   { opacity: 0; transform: scale(1.25); }
}

.landing-root .rg-kn__kaart-kop { display: flex; align-items: center; gap: 0.5rem; }
.landing-root .rg-kn__kaart-kop b { display: block; color: var(--rg-ink); font-size: clamp(0.75rem, 3vw, 0.9rem); }
.landing-root .rg-kn__kaart-kop small { display: block; color: var(--rg-text-ghost); font-size: clamp(0.6rem, 2.3vw, 0.6875rem); }
.landing-root .rg-kn__avatar {
  flex: none;
  width: clamp(1.625rem, 7vw, 2.125rem);
  aspect-ratio: 1;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-weight: 700;
  font-size: clamp(0.625rem, 2.6vw, 0.75rem);
  color: var(--rg-surface);
  background: linear-gradient(135deg, var(--rg-primary), var(--rg-primary-deep));
}
.landing-root .rg-kn__crm {
  margin-left: auto;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: clamp(0.5625rem, 2.2vw, 0.65rem);
  font-weight: 700;
  color: var(--rg-primary);
  background: var(--rg-primary-wash);
}

.landing-root .rg-kn__regels { list-style: none; margin: 0.625rem 0 0; padding: 0; display: grid; gap: 0.3125rem; }
.landing-root .rg-kn__regel {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 0.4375rem;
  align-items: center;
  padding: 0.3125rem 0.4375rem;
  border-radius: 0.5625rem;
  background: var(--rg-canvas);
  color: var(--rg-text);
  font-size: clamp(0.625rem, 2.55vw, 0.78rem);
  line-height: 1.35;
  opacity: 0;
  transform: translateX(-10px);
  transition: opacity 350ms ease, transform 550ms var(--rg-kn-veer);
}
.landing-root .rg-kn__regel.is-zicht { opacity: 1; transform: none; }
/* Net geland: kort in de kleur van het station (een laag die in- en uitvaagt). */
.landing-root .rg-kn__regel::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: color-mix(in srgb, var(--rg-kn-kleur) 12%, var(--rg-surface));
  opacity: 0;
  transition: opacity 800ms ease;
}
.landing-root .rg-kn__regel.is-nieuw::before { opacity: 1; }
.landing-root .rg-kn__regel > * { position: relative; }
.landing-root .rg-kn__regel small { display: block; color: var(--rg-text-ghost); font-size: 0.85em; }
.landing-root .rg-kn__stip { width: 8px; height: 8px; border-radius: 50%; background: var(--rg-kn-kleur); }
/* De regel van het CRM draagt hetzelfde verloop als zijn spoor (Claude-oranje
   naar CRM-paars), zodat hij niet samenvalt met het paars van de webshop. */
.landing-root .rg-kn__regel--ai .rg-kn__stip { background: linear-gradient(135deg, var(--rg-merk-claude), var(--rg-primary)); }

.landing-root .rg-kn__voet {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.5625rem;
  font-size: clamp(0.6rem, 2.3vw, 0.6875rem);
  color: var(--rg-text-ghost);
}
.landing-root .rg-kn__stempel {
  display: inline-block;
  padding: 2px 8px;
  border: 1.5px solid var(--rg-settled);
  border-radius: 0.5rem;
  font-weight: 700;
  color: var(--rg-settled);
  /* Een stempel breekt nooit: "Regular guest ✓" liep op 320 px over twee regels. */
  white-space: nowrap;
  opacity: 0;
  transform: scale(1.8) rotate(-8deg);
  transition: opacity 200ms ease, transform 450ms var(--rg-kn-veer);
}
.landing-root .rg-kn__stempel.is-zicht { opacity: 1; transform: rotate(-4deg); }

/* --- Tellers ------------------------------------------------------------- */

.landing-root .rg-kn__tellers {
  margin-top: 0.875rem;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.375rem;
}
.landing-root .rg-kn__teller {
  padding: 0.375rem 0.25rem;
  border-radius: 0.75rem;
  border: 1px solid var(--rg-line);
  background: color-mix(in srgb, var(--rg-surface) 70%, transparent);
  text-align: center;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 400ms ease, transform 600ms var(--rg-ease);
}
.landing-root .rg-kn__teller.is-zicht { opacity: 1; transform: none; }
.landing-root .rg-kn__teller b {
  display: block;
  color: var(--rg-ink);
  font-size: clamp(0.9375rem, 4.2vw, 1.3125rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.landing-root .rg-kn__teller span { font-size: clamp(0.5625rem, 2.2vw, 0.6875rem); color: var(--rg-text-soft); }

/* --- Productrij ----------------------------------------------------------- */

.landing-root .rg-kc__rij {
  position: relative;
  font-family: var(--rg-body);
  z-index: 1;
  padding-bottom: clamp(1.375rem, 3vw, 1.875rem);
}
.landing-root .rg-kc__rij-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.5rem;
}
@media (min-width: 700px) {
  .landing-root .rg-kc__rij-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.landing-root .rg-kc__product {
  position: relative;
  display: grid;
  gap: 0.125rem;
  padding: 0.625rem 0.75rem;
  border-radius: 0.875rem;
  background: var(--rg-surface);
  border: 1px solid var(--rg-line);
  text-decoration: none;
  color: var(--rg-ink);
  font-size: 0.875rem;
  font-weight: 600;
  transition: transform 350ms var(--rg-ease);
}
.landing-root .rg-kc__product small { color: var(--rg-text-soft); font-weight: 400; font-size: 0.75rem; }
/* De rand in de kleur van het product (--rg-productkleur, landing.css): bij
   hover en focus, en voor het product dat in de tijdlijn aan de beurt is. */
.landing-root .rg-kc__product::after {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  border: 1px solid var(--rg-productkleur);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--rg-productkleur) 16%, transparent);
  opacity: 0;
  transition: opacity 350ms ease;
  pointer-events: none;
}
.landing-root .rg-kc__product:hover::after,
.landing-root .rg-kc__product:focus-visible::after { opacity: 1; }
.landing-root .rg-kc[data-kc-product="crm"] .rg-kc__product[data-p="crm"],
.landing-root .rg-kc[data-kc-product="telefonist"] .rg-kc__product[data-p="telefonist"],
.landing-root .rg-kc[data-kc-product="reserveren"] .rg-kc__product[data-p="reserveren"],
.landing-root .rg-kc[data-kc-product="webshop"] .rg-kc__product[data-p="webshop"] { transform: translateY(-2px); }
.landing-root .rg-kc[data-kc-product="crm"] .rg-kc__product[data-p="crm"]::after,
.landing-root .rg-kc[data-kc-product="telefonist"] .rg-kc__product[data-p="telefonist"]::after,
.landing-root .rg-kc[data-kc-product="reserveren"] .rg-kc__product[data-p="reserveren"]::after,
.landing-root .rg-kc[data-kc-product="webshop"] .rg-kc__product[data-p="webshop"]::after { opacity: 1; }

/* --- Het vangnet en de eindstand ------------------------------------------ */

/* De eindstand staat op VIJF plekken hieronder, met steeds dezelfde
   elementen: banen, stations, kaart, regels, tellers, sporen, stempel en de
   groene rand van de kaart (.rg-kn__kaart::after). 1) het vangnet, 2) de
   uitzondering voor een hero die speelt of wacht, 3) "fout", 4) minder
   beweging, 5) zonder JavaScript. Komt er een element bij de eindstand, zet
   het dan in alle vijf; HeroKlantcontactTests.De_vijf_eindstanden_noemen_
   dezelfde_elementen bewaakt dat. */

/* Het vangnet: speelt js/heroKlantcontact.js niet (niet geladen, of een
   fout), dan na 3 s toch de eindstand. Een hero die speelt
   (data-kc-speelt="1") of op beeld wacht ("wacht") zet het uit: zo springt
   een tafereel onder de vouw niet na 3 s alsnog naar de eindstand. Andersom
   ("verbergen zodra het script er is") kan niet: dan stond de eindstand
   eerst in beeld en verdween hij weer. Vaste easing, geen token: het
   vangnet moet ook werken als landing.css ontbreekt. Ballonnen, kometen en
   de schokgolf horen niet bij de eindstand. */
.landing-root .rg-kc :is(.rg-kn__banen, .rg-kn__station, .rg-kn__kaart, .rg-kn__regel, .rg-kn__teller) { animation: rgKcVangnetToon 450ms ease-out 3s forwards; }
.landing-root .rg-kc .rg-kn__spoor { animation: rgKcVangnetSpoor 900ms ease-out 3s forwards; }
.landing-root .rg-kc .rg-kn__stempel { animation: rgKcVangnetStempel 450ms ease-out 3s forwards; }
.landing-root .rg-kc .rg-kn__kaart::after { animation: rgKcVangnetToon 450ms ease-out 3s forwards; }
.landing-root .rg-kc:is([data-kc-speelt="1"], [data-kc-speelt="wacht"]) :is(.rg-kn__banen, .rg-kn__station, .rg-kn__kaart, .rg-kn__regel, .rg-kn__teller, .rg-kn__spoor, .rg-kn__stempel) { animation: none; }
.landing-root .rg-kc:is([data-kc-speelt="1"], [data-kc-speelt="wacht"]) .rg-kn__kaart::after { animation: none; }
@keyframes rgKcVangnetToon { to { opacity: 1; transform: none; } }
@keyframes rgKcVangnetSpoor { to { stroke-dashoffset: 0; } }
@keyframes rgKcVangnetStempel { to { opacity: 1; transform: rotate(-4deg); } }

/* Het script liep op een fout (data-kc-speelt="fout"): meteen de eindstand,
   niet eerst nog 3 s een leeg tafereel. */
.landing-root .rg-kc[data-kc-speelt="fout"] :is(.rg-kn__banen, .rg-kn__station, .rg-kn__kaart, .rg-kn__regel, .rg-kn__teller) { opacity: 1; transform: none; animation: none; }
.landing-root .rg-kc[data-kc-speelt="fout"] .rg-kn__spoor { stroke-dashoffset: 0; animation: none; }
.landing-root .rg-kc[data-kc-speelt="fout"] .rg-kn__stempel { opacity: 1; transform: rotate(-4deg); animation: none; }
.landing-root .rg-kc[data-kc-speelt="fout"] .rg-kn__kaart::after { opacity: 1; animation: none; }

/* Minder beweging: landing.css zet in de hero alle animaties en overgangen
   uit; hier de eindstand, en de baan staat stil. */
@media (prefers-reduced-motion: reduce) {
  .landing-root .rg-kc :is(.rg-kn__banen, .rg-kn__station, .rg-kn__kaart, .rg-kn__regel, .rg-kn__teller) { opacity: 1; transform: none; }
  .landing-root .rg-kc .rg-kn__spoor { stroke-dashoffset: 0; }
  .landing-root .rg-kc .rg-kn__stempel { opacity: 1; transform: rotate(-4deg); }
  .landing-root .rg-kc .rg-kn__kaart::after { opacity: 1; }
  .landing-root .rg-kc .rg-kn__orbit { animation: none; }
}

/* Zonder JavaScript: de eindstand meteen, en de baan staat stil. */
@media (scripting: none) {
  .landing-root .rg-kc :is(.rg-kn__banen, .rg-kn__station, .rg-kn__kaart, .rg-kn__regel, .rg-kn__teller) { opacity: 1; transform: none; animation: none; }
  .landing-root .rg-kc .rg-kn__spoor { stroke-dashoffset: 0; animation: none; }
  .landing-root .rg-kc .rg-kn__stempel { opacity: 1; transform: rotate(-4deg); animation: none; }
  .landing-root .rg-kc .rg-kn__kaart::after { opacity: 1; }
  .landing-root .rg-kc .rg-kn__orbit { animation: none; }
}
