/* Laag: framework. De rangorde staat in skeleton/templates/page.php:
 *   @layer framework, site, theme, type, item;
 * Alles wat het framework meestuurt zit in de onderste laag, zodat site-CSS en CMS-opmaak
 * ervan winnen zonder specificiteits-trucs. Binnen deze laag telt specificiteit gewoon, dus
 * de onderlinge verhouding tussen framework-bestanden verandert er niet door.
 *
 * Een bestand dat deze wikkel MIST staat buiten elke laag en wint daarmee van ALLES —
 * ook van het CMS. `tests/Framework/CodeStyle/ModuleCssIsLayeredTest.php` bewaakt dat. */
@layer framework {
@charset "UTF-8";
/*
 * Carousel — gestyled voor `<div class="carousel">` zoals gegenereerd door
 * Framework\Carousel\CarouselRenderer. JS-laag (Embla wrapper) hangt klassen
 * dynamisch toe: `.carousel__slide--active`, `.carousel__dot--selected` etc.
 *
 * Werkt al als CSS-only scroll-snap voordat JS geladen is — geen lay-out
 * shift bij hydration.
 *
 * Elke `var()` hier heeft een fallback. Niet elke site laadt `variables.css`: sites met
 * hun eigen stylesheet-architectuur definiëren een deel van de tokens wél en een deel
 * niet, en een `var()` zónder fallback laat dan de héle declaratie vallen. Dat kostte de
 * pijl-knoppen op zo'n site hun `box-shadow` — de knop is spierwit, dus op een witte
 * sectie bleef er een zwevend chevrontje over de tekst over. Onzichtbaar in de code,
 * zichtbaar op de pagina.
 */

.carousel {
    position: relative;
    /* Container-queries op carousel-level voor slide-count breakpoints */
    container-type: inline-size;
    /* Voorkom 0-breedte in nested flex-parents */
    width: 100%;
    min-width: 0;
}

.carousel__viewport {
    overflow: hidden;
    width: 100%;
}

.carousel__container {
    display: flex;
    /* Spacing via slide-padding i.p.v. flex `gap`: Embla meet slide-breedtes en
       werkt niet betrouwbaar met `gap`. De negatieve margin compenseert de
       leading padding van de eerste slide zodat 'ie flush links staat. */
    margin-left: calc(var(--carousel-slide-gap, var(--space-3, 1rem)) * -1);
    /* Vóór JS-init: scroll-snap maakt 't al een werkende carousel */
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
}
.carousel__container::-webkit-scrollbar { display: none; }

/* Default: één slide volle viewport breed. Inline `--carousel-cols:N` (CarouselRenderer)
   verhoogt dat naar N kolommen. `--layout-peek` (custom property, inline): toon X% van de
   volgende slide.

   Eén regel bepaalt de breedte, gevoed door twee variabelen. Dat is bewust: hiervoor stond het
   kolom-aantal in de SELECTOR (`[data-layout-cols="3"]`) en de peek-variant in een selector met
   een attribuut méér (`[style*="--layout-peek"][data-layout-cols="3"]`, specificiteit 0,4,0).
   De responsive `@container`-regels hadden er maar drie (0,3,0) en verloren het dus zodra peek
   aanstond -- óók binnen een matchende container-query. Gevolg: een carousel met 3 kolommen en
   peek toonde op een smal scherm gewoon 3 opgepropte slides, terwijl de breakpoints er wel
   degelijk waren. Gevonden door de svs-agent op site 466.

   Meer selectoren met een hogere specificiteit erbij zetten lost dat op tot de volgende variant.
   Daarom staat het kolom-aantal nu in `--carousel-cols` en verzetten de breakpoints alleen die
   variabele. Peek en kolommen vermenigvuldigen niet meer in de selector, ze tellen op in de calc.

   `--carousel-cols` (RAUW, van CarouselRenderer, altijd inline) vs. `--actual-carousel-cols`
   (AFGELEID, altijd via stylesheet-regels, nooit inline) -- twee namen, niet cosmetisch. Punt 1010:
   het CMS-select-veld voor kolomaantal biedt 1-10, maar hier stond een vertaaltabel
   (`[data-layout-cols="N"]` per waarde) die alleen 2-6 dekte; elke andere waarde (1, 7-10)
   matchte geen regel en viel terug op de fallback `1`, dus één beeldvullende slide i.p.v. de
   gekozen strip. Een tweede, losstaand gevonden bug: de drie `@container`-blokken hieronder
   herschreven vóór deze fix `--carousel-cols` met een verwijzing naar zíchzelf (`var(--carousel-
   cols)` binnen een nieuwe `--carousel-cols`-declaratie op hetzelfde element) -- CSS behandelt
   dat als een cyclische referentie en dus als ONGELDIG, waardoor de mobiele afschaling al langer
   stilzwijgend nooit werkte (gemeten 18-09-2026: op ~900px en ~600px containerbreedte was de
   slide exact zo breed als de container, i.p.v. minder kolommen).

   De fix: `--carousel-cols` komt inline van de renderer (geen tabel, geen limiet op N), en
   alléén de AFGELEIDE `--actual-carousel-cols` -- nooit inline, dus vrij overschrijfbaar door
   elke site-CSS met een gewone, niet-geforceerde regel -- wordt door stylesheet-regels (incl.
   de @container-blokken) gezet en is de enige die de slide-breedte hieronder leest. Geen
   self-reference meer: elk blok leest de STATISCHE ruwe waarde, nooit z'n eigen vorige uitkomst.

   Geen `[data-layout-cols]`-wachtje meer op deze selectoren: zonder geconfigureerd aantal is het
   bedoelde gedrag toch al "1 slide, volle breedte", en dat is precies wat `var(--carousel-cols, 1)`
   al oplevert wanneer de renderer 'm nooit zet. Het attribuut voegde daar niets aan toe -- anders
   dan bij `.carousel--static`/`.strip` hieronder, waar "ongeconfigureerd" een ANDER gedrag is dan
   "N=1" en de guard dus wél nodig blijft (zie de toelichting daar). */
.carousel__slide {
    /* max() maakt de breakpoint-peek een ONDERGRENS: een smalle container laat altijd een
       randje van de volgende slide zien (dat was de 80% van de oude 24rem-regel), en een hoger
       ingestelde peek blijft gewoon staan. */
    flex: 0 0 calc(
        (100% - max(var(--layout-peek, 0%), var(--carousel-peek-min, 0%)))
        / var(--actual-carousel-cols, 1)
    );
    box-sizing: border-box;
    padding-left: var(--carousel-slide-gap, var(--space-3, 1rem));   /* layer.spacing (binnen flex-basis via border-box) */
    scroll-snap-align: start;
    min-width: 0;
}
.carousel__container { --actual-carousel-cols: var(--carousel-cols, 1); }

/* Smaller container: minder slides naast elkaar voor leesbaarheid. Deze regels zetten alleen
   het kolom-aantal; de peek erin blijft gelden in plaats van hem te overschrijven.

   Geen los CMS-veld per breekpunt (punt 971) -- dat bleek de verkeerde vraag: een redacteur
   kiest één aantal (desktop), de rest hoort daaruit te volgen. Overgenomen van de legacy-
   carousel (ecohus.nl e.a., Swiper `breakpoints`), die het aantal AL zo berekent: `ceil(N/2)`,
   `ceil(N/3)`, `ceil(N/4)`/`ceil(N/5)` naarmate het scherm smaller wordt -- nooit een vaste cap
   die de CMS-waarde negeert, wel steeds minder naarmate er minder ruimte is. Hier vertaald naar
   `round(up, N/deler, 1)` (CSS-equivalent van `ceil()`), met `max(1, …)` als ondergrens zodat
   een kleine N nooit op 0 kolommen uitkomt. Bij 6 op desktop: 3 op tablet, 2 op mobiel, 2 op de
   kleinste telefoons -- bij 3: 2, 1, 1.

   Elk blok leest `var(--carousel-cols)` -- de STATISCHE ruwe waarde van de renderer, niet
   `--actual-carousel-cols` (dat zou zowel de self-reference-bug hierboven terugbrengen als de
   verkeerde eigenschap zijn om te lezen). Op een breedte waar meerdere blokken tegelijk matchen
   wint het laatste in brondocument-volgorde (gelijke specificiteit) -- dus puur het smalste
   blok, niet een opeenstapeling van delers. */
@container (max-width: 60rem) {
    .carousel__container { --actual-carousel-cols: max(1, round(up, var(--carousel-cols) / 2, 1)); }
}
@container (max-width: 40rem) {
    .carousel__container { --actual-carousel-cols: max(1, round(up, var(--carousel-cols) / 3, 1)); }
}
@container (max-width: 24rem) {
    /* Eén slide plus een randje van de volgende -- de oude regel schreef dat als 80%. */
    .carousel__container { --actual-carousel-cols: max(1, round(up, var(--carousel-cols) / 5, 1)); --carousel-peek-min: 20%; }
}

/* Arrows */
.carousel__controls {
    position: absolute;
    inset: 0;
    pointer-events: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 var(--space-2, .5rem);
}
.carousel__buttons {
    display: contents;
}
.carousel__button {
    pointer-events: auto;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    border: 0;
    /* Volgt de achtergrond-token in plaats van een vast wit, zodat een site die
       `--color-bg-elev` verzet de knop mee laat kleuren. */
    background: color-mix(in srgb, var(--color-bg-elev, #fff) 90%, transparent);
    color: var(--color-fg, #222);
    cursor: pointer;
    display: grid;
    place-items: center;
    box-shadow: var(--shadow-1, 0 2px 10px rgba(0, 0, 0, .18));
    transition: transform .15s ease, opacity .15s ease;
}
.carousel__button:hover { transform: scale(1.05); }
.carousel__button:disabled { opacity: .4; cursor: default; }

/* Chevron via mask + currentColor — geen extra SVG-files nodig */
.carousel__button::before {
    content: '';
    width: 1rem;
    height: 1rem;
    background-color: currentColor;
    mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9 6l6 6-6 6" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>');
    mask-repeat: no-repeat;
    mask-position: center;
    mask-size: contain;
}
.carousel__prev::before { transform: rotate(180deg); }

/* Dots */
.carousel__dots {
    display: flex;
    justify-content: center;
    gap: var(--space-2, .5rem);
    padding: var(--space-3, 1rem) 0 0;
}
.carousel__dot {
    width: .6rem;
    height: .6rem;
    border-radius: 50%;
    border: 0;
    background: var(--color-border, rgba(0, 0, 0, .18));
    cursor: pointer;
    padding: 0;
    transition: transform .15s ease, background .15s ease;
}
.carousel__dot > span { position: absolute; left: -9999px; }
.carousel__dot:hover { transform: scale(1.2); }
.carousel__dot--selected {
    background: var(--color-primary, currentColor);
    transform: scale(1.3);
}

/* Fade-effect: opacity-transition i.p.v. slide-translate (Embla fade plugin) */
.carousel--fade .carousel__container > .carousel__slide {
    position: relative;
}

/* ── Uitgezet ("Actief" = Nee op de interface_carousel) ──────────────────────────────────────
 * Geen viewport, geen track, geen JS: alle slides op een rij, zodat de opmaak van de slides
 * blijft kloppen. De redacteur zette de bewéging uit, niet z'n beelden — vandaar dat ze er
 * allemaal staan en niet alleen de eerste.
 *
 * Grid en geen flex, met opzet: `.carousel__slide` draagt een `flex-basis` voor de carrousel-
 * breedte, en die hoort op precies één plek te staan (CarouselCssLayoutTest bewaakt dat, na een
 * eerdere ronde waarin twee regels om die breedte concurreerden). In een grid doet die eigenschap
 * niets, dus hier is geen tweede breedte-regel nodig en kan de eerste niet in de weg zitten. */
.carousel--static {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
    gap: var(--carousel-gap, 1rem);
}
.carousel--static[data-layout-cols] {
    /* Geen afgeleide variabele nodig: deze variant heeft (nog) geen responsieve afschaling die
       --carousel-cols zou moeten overschrijven, dus de rauwe inline waarde rechtstreeks lezen
       kan hier geen cascade-conflict geven. */
    grid-template-columns: repeat(var(--carousel-cols, 1), minmax(0, 1fr));
}

/* ── Doorlopende linear-variant ─────────────────────────────────────
 * Dezelfde generieke marquee-markup wordt gebruikt door media-albums en cards. De
 * card-variant heeft geen `.strip__item`, dus de maatvoering hoort op de gedeelde
 * `carousel__slide`-haak te zitten. */
.strip {
    overflow: hidden;
}
.strip__track {
    display: flex;
    gap: var(--carousel-gap, 1rem);
    width: max-content;
    animation: carousel-marquee var(--marquee-duration, 52s) linear infinite;
}
.strip--pause-hover:hover .strip__track {
    animation-play-state: paused;
}
.strip__track > .carousel__slide {
    flex: 0 0 auto;
}
.strip[data-layout-cols] {
    /* --carousel-strip-cols (afgeleid) i.p.v. rechtstreeks --carousel-cols lezen: @media-regels
       hieronder overschrijven 'm, en dat mag geen self-reference worden (zelfde reden als bij
       --actual-carousel-cols hierboven). Basiswaarde = de rauwe inline waarde van de renderer. */
    --carousel-strip-cols: var(--carousel-cols, 1);
    --carousel-strip-gap: var(--carousel-gap, 1rem);
}
.strip[data-layout-cols] .strip__track > .carousel__slide {
    flex-basis: calc(
        (100vw - 8vw - (var(--carousel-strip-cols) - 1) * var(--carousel-strip-gap))
        / var(--carousel-strip-cols)
    );
}
/* `min()` i.p.v. een opsomming per N: werkt voor elke kolomwaarde die het CMS ooit aanbiedt,
   niet alleen de waarden die hier toevallig benoemd zijn (punt 1010). */
@media (max-width: 1024px) {
    .strip[data-layout-cols] { --carousel-strip-cols: min(var(--carousel-cols, 1), 3); }
}
@media (max-width: 768px) {
    .strip[data-layout-cols] { --carousel-strip-cols: 2; }
}
@media (max-width: 480px) {
    .strip[data-layout-cols] { --carousel-strip-cols: 1; }
}
@keyframes carousel-marquee {
    from { transform: translateX(0); }
    to { transform: translateX(-50%); }
}
}
