/* Widgets — weergavemodus (sectie G, DSC-081 t/m DSC-095).
 *
 * .ds-prose rendert opgeslagen TipTap-inhoud (tekst-widget, accordion-inhoud):
 * descendant-selectors op gegenereerde HTML kunnen niet met utilities in de
 * ERB. Alles op tokens; de tekstkleur erft van de sectie-container zodat
 * rijke tekst ook op donkere/brand-presets klopt (duotone-regel 8.7).
 *
 * Preset-context (13.4): de sectie-container zet .on-dark (ink/afbeelding) of
 * .on-brand (Young Orange). Widget-elementen die direct op het sectievlak
 * staan schakelen hier per context mee. Witte kaart-widgets zetten .on-light
 * op hun kaartwrapper: dat reset de context (focus-ring en prose-kleuren)
 * binnen de kaart, ongeacht de sectie eromheen. De .on-light-regels staan
 * bewust ónder de .on-dark/.on-brand-regels. */

.ds-prose {
  font-size: 16px;
  line-height: 1.6;
}

/* TYP-1/TYP-2 (mobile UX-audit, beslissing V-2): op telefoon (< sm = 640px)
   leest lopende tekst prettiger een maatje kleiner. Hier co-gelokaliseerd met
   de basis-.ds-prose (i.p.v. in mobile.css) zodat deze override gegarandeerd
   ná de 16px-regel valt en wint; de composer-editor (.ds-prose[contenteditable])
   blijft via de FRM-1-regel op 16px staan om iOS-zoom te voorkomen. */
@media (max-width: 639.98px) {
  .ds-prose:not([contenteditable="true"]) {
    font-size: 15px;
    line-height: 1.5;
    overflow-wrap: break-word;
  }
}

.ds-prose > :first-child {
  margin-top: 0;
}
.ds-prose > :last-child {
  margin-bottom: 0;
}

.ds-prose h2,
.ds-prose h3,
.ds-prose h4 {
  margin: 1.25em 0 0.5em;
  line-height: 1.2;
  font-weight: 700;
}
.ds-prose h2 {
  font-size: 1.375em;
}
.ds-prose h3 {
  font-size: 1.125em;
}
.ds-prose h4 {
  font-size: 1em;
}

.ds-prose p {
  margin: 0.75em 0;
}

.ds-prose a {
  font-weight: 600;
  color: var(--color-brand);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--color-brand) 40%, transparent);
  text-underline-offset: 3px;
  transition: color var(--duration-fast) ease, text-decoration-color var(--duration-fast) ease;
}
.ds-prose a:hover {
  color: currentColor;
  text-decoration-color: currentColor;
}
/* Op donkere vlakken (sectie-preset ink/image) blijft de link leesbaar:
 * duotone-paar offwhite + brand-onderstreping. */
.on-dark .ds-prose a {
  color: var(--color-offwhite);
  text-decoration-color: var(--color-brand);
}
.on-dark .ds-prose a:hover {
  color: var(--color-brand);
}
/* Op Young Orange (preset brand) is oranje als linkkleur onzichtbaar: links
 * volgen het duotone-paar oranje + zwart en onderscheiden zich met de
 * onderstreping (hover: volle dekking). */
.on-brand .ds-prose a {
  color: var(--color-black);
  text-decoration-color: color-mix(in srgb, var(--color-black) 45%, transparent);
}
.on-brand .ds-prose a:hover {
  color: var(--color-black);
  text-decoration-color: var(--color-black);
}

.ds-prose ul,
.ds-prose ol {
  margin: 0.75em 0;
  padding-left: 1.5em;
}
.ds-prose ul {
  list-style: disc;
}
.ds-prose ol {
  list-style: decimal;
}
.ds-prose li {
  margin: 0.25em 0;
}
.ds-prose li::marker {
  color: var(--color-brand);
}
.on-dark .ds-prose li::marker,
.on-brand .ds-prose li::marker,
.ds-prose ol > li::marker {
  color: currentColor;
}

/* FEEDBACK jul 2026: lange, onbreekbare tekst/links (bv. een Google-Forms-URL)
 * braken uit de kaart (horizontale overflow). overflow-wrap: anywhere breekt
 * alleen als laatste redmiddel binnen een woord/URL — geërfd, dus ook op links —
 * zonder de normale woordafbreking te verstoren. */
.ds-post-body {
  overflow-wrap: anywhere;
}

/* FEEDBACK jul 2026: nette verticale ritmiek (zelfde regels als .ds-prose) i.p.v.
 * de uniforme space-y-3, die koppen even dicht op de tekst zette als twee
 * paragrafen op elkaar. Nu: genereuze ruimte BÓVEN een kop (scheidt de sectie),
 * iets krapper eronder (kop hoort bij de tekst eronder), en foto's krijgen lucht. */
.ds-post-body > :first-child {
  margin-top: 0;
}
.ds-post-body > :last-child {
  margin-bottom: 0;
}
.ds-post-body p {
  margin: 0.75em 0;
}
.ds-post-body img {
  margin: 1.25em 0;
}

/* FEEDBACK ronde 11: post-body (channel-feed + post-detail, components/post_card)
 * rendert dezelfde rich-text als de editor, maar de opsommings-/genummerde
 * lijsten misten hun markers (de globale reset haalt list-style weg). Geef ze
 * hun bullets/nummers + inspringing terug, net als in de editor/.ds-prose. */
.ds-post-body ul,
.ds-post-body ol {
  margin: 0.75em 0;
  padding-left: 1.5em;
}
.ds-post-body ul {
  list-style: disc;
}
.ds-post-body ol {
  list-style: decimal;
}
.ds-post-body li {
  margin: 0.2em 0;
}
.ds-post-body li::marker {
  color: var(--color-brand);
}
.ds-post-body ol > li::marker {
  color: currentColor;
}

/* FEEDBACK jul 2026: links en koppen in post-bodies oogden als platte tekst —
 * zelfde globale-reset-euvel als de lijsten hierboven. Zelfde duotone-linkstijl
 * en kopmaten als .ds-prose; postkaarten zijn altijd wit (on-light), dus één
 * variant volstaat. Marges laten we aan de space-y van de kaart. */
.ds-post-body a {
  font-weight: 600;
  color: var(--color-brand);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--color-brand) 40%, transparent);
  text-underline-offset: 3px;
  transition: color var(--duration-fast) ease, text-decoration-color var(--duration-fast) ease;
}
.ds-post-body a:hover {
  color: currentColor;
  text-decoration-color: currentColor;
}
.ds-post-body h2,
.ds-post-body h3 {
  margin: 1.25em 0 0.5em;
  line-height: 1.2;
  font-weight: 700;
}
.ds-post-body h2 {
  font-size: 1.375em;
}
.ds-post-body h3 {
  font-size: 1.125em;
}

/* FEEDBACK jul 2026: meerdere opeenvolgende inline-foto's naast elkaar i.p.v.
 * elk op volle breedte (post_body_html groepeert ze in .ds-post-gallery).
 * Cover-crop voor een strak raster; klik opent de volledige foto in de
 * lightbox, dus de crop verliest niets. */
.ds-post-gallery {
  display: grid;
  gap: 0.5rem;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin: 1.25em 0;
}
.ds-post-gallery[data-count="3"] {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.ds-post-gallery img {
  margin: 0;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-md);
}

.ds-prose blockquote {
  position: relative;
  margin: 1em 0;
  padding: 0.125em 0 0.125em 1em;
  font-style: italic;
  color: var(--color-subtle);
}
/* Accenttaal 16.3: los pill-streepje links, geen meebuigende rand. */
.ds-prose blockquote::before {
  content: "";
  position: absolute;
  left: 0;
  top: 4px;
  bottom: 4px;
  width: 4px;
  border-radius: 9999px;
  background: var(--color-brand);
}
.on-dark .ds-prose blockquote,
.on-brand .ds-prose blockquote {
  color: color-mix(in srgb, currentColor 78%, transparent);
}
.on-brand .ds-prose blockquote::before {
  background: var(--color-black);
}

.ds-prose code {
  padding: 0.1em 0.4em;
  border-radius: 6px;
  background: color-mix(in srgb, var(--color-black) 6%, transparent);
  font-size: 0.875em;
}
.on-dark .ds-prose code {
  background: color-mix(in srgb, var(--color-offwhite) 16%, transparent);
}
.on-brand .ds-prose code {
  background: color-mix(in srgb, var(--color-black) 10%, transparent);
}

.ds-prose hr {
  margin: 1.5em 0;
  border: 0;
  border-top: 1px solid var(--color-line);
}
.on-dark .ds-prose hr,
.on-brand .ds-prose hr {
  border-top-color: color-mix(in srgb, currentColor 35%, transparent);
}

/* Bijschriften en meta-tekst die direct op het sectievlak staan: --color-subtle
 * haalt op ink/brand geen contrast, dus daar dimmen we de geërfde tekstkleur. */
.ds-caption {
  color: var(--color-subtle);
}
.on-dark .ds-caption,
.on-brand .ds-caption {
  color: color-mix(in srgb, currentColor 78%, transparent);
}

/* Scheidingslijn (spacer-widget :lijn): op donkere/brand-vlakken volgt de
 * lijnkleur de geërfde tekstkleur in lage dekking. */
.ds-divider {
  border-color: var(--color-line);
}
.on-dark .ds-divider,
.on-brand .ds-divider {
  border-color: color-mix(in srgb, currentColor 35%, transparent);
}

/* Brand-accentjes (bv. het taart-icoon van de verjaardagen-widget): oranje op
 * wit/offwhite/ink, maar op het brand-vlak zelf volgt het accent de tekstkleur. */
.ds-accent {
  color: var(--color-brand);
}
.on-brand .ds-accent {
  color: currentColor;
}

/* Adaptieve tekstlink (DSC-022, variant :auto) voor widget-koppen die direct op
 * het sectievlak staan (bv. de feed-widget): kleur volgt het duotone-paar van
 * de actieve preset zonder dat het widget zijn context hoeft te kennen. */
.ds-link-auto {
  color: var(--color-brand);
}
.ds-link-auto:hover {
  color: var(--color-black);
}
.on-dark .ds-link-auto:hover {
  color: var(--color-offwhite);
}
.on-brand .ds-link-auto {
  color: var(--color-black);
  text-decoration-line: underline;
  text-decoration-color: color-mix(in srgb, var(--color-black) 45%, transparent);
  text-underline-offset: 4px;
}
.on-brand .ds-link-auto:hover {
  color: var(--color-black);
  text-decoration-color: var(--color-black);
}

/* Context-reset voor witte kaart-widgets (linklijst, accordion, kopieer-knop,
 * user-card, feed-postkaarten, card/banner met beeld): binnen de kaart gelden
 * de lichte kleuren en de zwarte focus-ring weer, óók in een ink/brand-sectie.
 * Deze regels staan als laatste zodat ze de contextregels hierboven winnen. */
.on-light {
  color: var(--color-black);
}
.on-light :focus-visible,
.on-light:focus-visible {
  outline-color: var(--color-black);
}
/* Uitzondering: expliciete .on-dark-vlakken ín een kaart (bv. de video-facade)
 * houden hun lichte ring. */
.on-light .on-dark :focus-visible,
.on-light .on-dark:focus-visible {
  outline-color: var(--color-offwhite);
}
.on-light .ds-prose a {
  color: var(--color-brand);
  text-decoration-line: underline;
  text-decoration-color: color-mix(in srgb, var(--color-brand) 40%, transparent);
}
.on-light .ds-prose a:hover {
  color: currentColor;
  text-decoration-color: currentColor;
}
.on-light .ds-prose ul > li::marker {
  color: var(--color-brand);
}
.on-light .ds-prose blockquote {
  color: var(--color-subtle);
}
.on-light .ds-prose blockquote::before {
  background: var(--color-brand);
}
.on-light .ds-prose code {
  background: color-mix(in srgb, var(--color-black) 6%, transparent);
}
.on-light .ds-caption {
  color: var(--color-subtle);
}
.on-light .ds-divider {
  border-color: var(--color-line);
}
.on-light .ds-accent {
  color: var(--color-brand);
}

/* FEEDBACK jul 2026 (Lennart): een 'passend' afbeelding-widget schaalt nu naar
 * een DEEL van de cel (klein 50% / middel 75% / groot 100%) i.p.v. een vaste
 * bandhoogte (120/172/236px). Een hoog kader liet 'groot' anders klein ogen: de
 * afbeelding bleef op 236px hangen midden in een veel hogere cel. Vanaf md heeft
 * de cel een definitieve hoogte (row_span × rij-eenheid), dus de percentages
 * resolveren; object-fit houdt het hele beeld zichtbaar, centreert het en
 * schaalt zo nodig OP zodat het gekozen deel écht gevuld wordt. Onder md is er
 * geen celhoogte: daar bepaalt de breedte de maat en volgt de hoogte de
 * beeldverhouding. De p-1.5 op de wrapper geeft 'groot' een smalle marge tot de
 * rand (het "5px padding"-gevoel). */
.ds-afb-passend {
  width: var(--afb-schaal, 75%);
  max-width: 100%;
  height: auto;
  object-fit: contain;
}
@media (min-width: 768px) {
  .ds-afb-passend {
    height: var(--afb-schaal, 75%);
    max-height: 100%;
  }
}

/* FEEDBACK ronde 4/5 (R4-11..R4-18, R5-2/3/6): 2D widget-grid.
 *
 * Onder md stapelt alles op volle breedte in documentvolgorde met
 * inhoud-gedreven hoogte (nooit afgeknepen). Vanaf md wordt het een 12-koloms
 * raster met vaste rij-eenheden (--ds-row-unit, 48px sinds R5-2): elke cel
 * krijgt haar plek en formaat uit de CSS-variabelen die page_widget_grid_style
 * zet (--w-col/--w-cspan/--w-row/--w-rspan; de gridlijnen zijn 1-gebaseerd). Zo
 * staan widgets naast elkaar met verschillende hoogtes en mogen er gaten in het
 * raster zitten. */
.ds-widget-grid {
  --ds-row-unit: 48px;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
}

/* FEEDBACK ronde 8 (R8-10): een iframe heeft geen intrinsieke hoogte. Onder md
 * stapelt het grid zonder vaste celhoogte, dus daar een vaste ondergrens zodat
 * het iframe niet tot ~150px inklapt. */
.ds-iframe-embed {
  min-height: 420px;
}

/* LAY-4 (mobile UX-audit): decoratieve spacer-hoogte via variabele; op telefoon
 * gehalveerd zodat een grote desktop-spacer geen dode ruimte in de smalle
 * stapel wordt. */
.ds-spacer {
  height: var(--ds-spacer-h);
}
@media (max-width: 639.98px) {
  .ds-spacer {
    height: calc(var(--ds-spacer-h) * 0.5);
  }

  /* LAY-5 (mobile UX-audit): de 420px-ondergrens voorkomt inklappen, maar mag
   * een korter ingestelde iframe (kleinere row_span) niet groter maken dan
   * bedoeld — cap op de ingestelde celhoogte (row_span × rij-eenheid). */
  .ds-iframe-embed {
    min-height: min(420px, calc(var(--w-rspan, 9) * var(--ds-row-unit, 48px)));
  }
}

@media (min-width: 768px) {
  .ds-widget-grid {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    grid-auto-rows: var(--ds-row-unit);
    gap: 1.5rem;
  }

  /* Vanaf md vult h-full de gridcel EXACT (row_span); geen min-height, anders
   * wordt een lager ingestelde iframe-hoogte afgekapt (R8-10). */
  .ds-iframe-embed {
    min-height: 0;
  }

  .ds-grid-cell {
    grid-column: var(--w-col, 1) / span var(--w-cspan, 12);
    grid-row: var(--w-row, auto) / span var(--w-rspan, 1);
    min-width: 0;
    min-height: 0;
  }

  /* R5-3: de inhoud vult de cel (row_span × rij-eenheid) — het directe kind
   * strekt mee tot de celranden (flex-fill), zodat kaarten/afbeeldingen de hele
   * X-Y-ruimte benutten i.p.v. bovenaan te blijven hangen. Bewust op een
   * binnenlaag, niet op .ds-grid-cell zelf: in de editor staan de zwevende
   * toolbar en de selectie-omlijning buiten de celrand en die mogen niet
   * meegeknipt worden. */
  /* FEEDBACK ronde 6 (R6-5): de CEL klemt niet. Zou hij dat wel doen (overflow:
   * hidden), dan knipt de celrand de box-shadow én de hover-lift van elk widget
   * af — precies het "plakken aan het grid"-effect. Het afklemmen van overtollige
   * INHOUD (truncation) gebeurt daarom op het widget zelf (hieronder), niet op de
   * cel: de eigen schaduw van een widget valt buiten zijn rand en blijft zo altijd
   * zichtbaar, terwijl de inhoud netjes binnen de widgetrand wordt geklemd. */
  .ds-cell-body {
    height: 100%;
    overflow: visible;
    display: flex;
    flex-direction: column;
  }
  /* FEEDBACK ronde 7 (R7-1): elk widget vult de ingestelde celhoogte (flex-fill).
   * De widget-root klemt zijn eigen overtollige inhoud af (truncation); de eigen
   * box-shadow valt daarbuiten en blijft zichtbaar (R6-5). Geen fade meer aan de
   * onderkant (R7-0: niet mooi) en geen nofill-uitzondering meer — widgets die
   * hun inhoud niet horen uit te rekken (knop, sectiekop) centreren die zelf in
   * de gevulde cel. */
  .ds-cell-body > * {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
  }

  /* FEEDBACK ronde 8 (R8-1/R8-9): de widget-root klemt zijn eigen inhoud strak af
   * (o.a. een card_banner-beeld tot de afgeronde hoeken). Maar bij widgets waar
   * de geschaduwde/liftende kaart GENEST zit in een transparante layout-wrapper
   * (user_card: .ds-usercard-card in .ds-usercard-widget) knipt die wrapper de
   * box-shadow én de hover-lift van de kaart af. De wrapper hoeft zelf niets te
   * klemmen (de kaart erin klemt haar eigen inhoud), dus zetten we hem op
   * overflow:visible zodat schaduw + lift vrij tekenen. Principe: transparante
   * layout-lagen klemmen niet; alleen de zichtbare kaart klemt haar eigen inhoud.
   * (overflow-clip-margin op de root zelf kan niet: dat verruimt óók de
   * beeld-klem en breekt de afgeronde hoeken van card_banner — R8-9.) */
  .ds-cell-body > .ds-usercard-widget {
    overflow: visible;
  }

  /* FEEDBACK ronde 7 (R7-5): content-gedreven cel. De inhoud (lijst/feed/FAQ)
   * staat op natuurlijke hoogte (geen flex-fill), zodat de client-layout-engine
   * hem kan meten en row_span erop afstemt. De cel is dan altijd minstens zo hoog
   * als de inhoud, dus niets wordt afgeklemd. */
  .ds-cell-auto .ds-cell-body {
    display: block;
  }
  .ds-cell-auto .ds-cell-body > * {
    overflow: visible;
  }

  /* FEEDBACK ronde 8 (R8-3): een auto-cel is door de row_span-afronding (ceil)
   * bijna altijd iets hoger dan zijn inhoud. Laat de card die restruimte VULLEN
   * (min-height:100% tot de celrand) i.p.v. de sectie-achtergrond eronder te
   * tonen — de inhoud staat bovenin, de rest is card-vlak. Alleen voor widgets
   * met een .ds-cell-measure-laag: de layout-engine meet en observeert die
   * (natuurlijke) laag, niet de opgerekte card, dus meten blijft lus-vrij. */
  .ds-cell-auto .ds-cell-body > *:has(.ds-cell-measure) {
    min-height: 100%;
  }
  .ds-cell-auto .ds-cell-measure {
    flex: 0 0 auto;
  }

  /* FEEDBACK ronde 10 (R10-1): de nieuws-carousel vult de auto-cel; de viewport
   * (flex-1) en de slides (items-stretch) groeien mee tot de celrand, zodat het
   * beeld de ceil-restruimte vult i.p.v. grijze sectie-achtergrond eronder. */
  .ds-cell-auto .ds-carousel-widget {
    min-height: 100%;
  }

  /* FEEDBACK ronde 7 (R7-3): de contactkaart-widget is vanaf md een
   * size-container (de cel heeft dan een vaste hoogte). */
  .ds-usercard-widget {
    container-type: size;
  }
}

/* FEEDBACK ronde 7 (R7-3): bij een lage cel (hoogte 1 = ~48px) compacteert de
 * contactkaart zodat de inhoud past i.p.v. af te kappen: kleinere avatar, geen
 * functie-regel, minder padding. Onder md is er geen size-container, dus dan
 * rendert de kaart gewoon op ware hoogte. */
@container (max-height: 78px) {
  .ds-usercard-card {
    padding: 0.375rem 0.625rem;
    gap: 0.5rem;
  }
  /* avatar_tag zet een inline width/height; alleen !important wint daarvan in
   * deze responsive-compacte staat. */
  .ds-usercard-card .avatar {
    width: 32px !important;
    height: 32px !important;
    font-size: 0.75rem;
  }
  .ds-usercard-functie {
    display: none;
  }
}
