/*! Van Werven — Bootstrap 5 reconciliation layer.
 *
 *  Loaded after vw-components.css (which is generated — never hand-edit it).
 *  Everything here exists because a Bootstrap 3 behaviour the extracted legacy
 *  CSS leaned on is gone in Bootstrap 5. Each rule is a debt against a component
 *  that has not been rebuilt yet, so this file should SHRINK as pages migrate.
 *  When a component is rebuilt against Bootstrap 5, delete its entry here.
 */

/* ── Container clearfix ───────────────────────────────────────────────────
   Bootstrap 3's .container carried `&:before,&:after{content:" ";display:table}
   &:after{clear:both}`. Bootstrap 5 dropped it, because its own layout is flex
   and needs no clearing. The legacy components are float-based, so without this
   any .container holding floats collapses to zero height and its siblings
   overlap it — the footer was doing exactly that.
   Retire when no float-based legacy component remains. */
.container::after,
.container-fluid::after {
    content: "";
    display: table;
    clear: both;
}

/* ── Off-canvas mobile menu must not extend the scroll box ────────────────
   .header__nav--mobile is hidden with visibility/opacity so it can transition.
   It is position:absolute and ~2650px tall, and an absolutely positioned box
   still contributes to the document scroll height — every page below the lg
   breakpoint gained ~2000px of phantom vertical scroll.

   Collapsing it to zero height while closed fixes the scroll box without
   touching the slide-in, which animates opacity and transform, not height. */
.header__nav--mobile:not(.active) {
    height: 0;
    overflow: hidden;
    pointer-events: none;
}

/* ── Block headings are styled by class, never by element ─────────────────
   The legacy CSS sizes and colours block headings through the element:
   `.streamer h3{color:#82bf5a}`, `.scroller h2{...}`. That silently ties the
   document outline to the visual design — the moment an editor picks a different
   heading level to fix heading order, the block loses its styling. Exactly that
   happened when the streamer items moved from h3 to h2 to close an h1→h3 skip:
   they jumped from 21px green to 30px black.

   Every rebuilt block therefore carries its own heading class. The element-based
   legacy rules stay for markup not yet rebuilt.

   Each component declares its own size as a custom property so the headingStyle
   modifiers below can scale *it* rather than the inherited body size. */
.streamer__heading {
    --vw-heading-size: 21px;
    font-size: var(--vw-heading-size);
    line-height: 1.2;
    color: #82bf5a;
}

.scroller__heading {
    --vw-heading-size: 48px;
    font-size: var(--vw-heading-size);
    /* 1.2, not 1.1: the legacy `h1,h2,h3{line-height:1.2}` is what the live heading
       resolves to, and at 48px the difference is a visible 5px of box height. */
    line-height: 1.2;
    margin-bottom: 62px;
}

.scroller__slide__heading {
    --vw-heading-size: 30px;
    font-size: var(--vw-heading-size);
    line-height: 1.2;
    font-weight: bold;
    color: #82bf5a;
    margin: 40px 0 20px;
}

.garbage__heading {
    --vw-heading-size: 30px;
    font-size: var(--vw-heading-size);
    line-height: 1.2;
    color: #82bf5a;
    margin: 0 0 25px;
}

/* The card headings of cardGridBlock. Two selectors, because the two declarations
   below are outranked by different things: the bare class already beats `h2,.h2
   {font-size:30px}` (class over element), but the colour has to beat `.content h1,
   .content h2,.content h3{color:#82bf5a}` — and this block draws its own `.content`
   section, so that rule applies and outranks a bare class. Hence the second selector.

   The point of both is the same: make the heading *level* free. Overview cards were
   h3 directly under an h1, an h1→h3 skip on every card grid on the site. They are h2
   now, and this rule is why they did not jump from 21px to 30px on the way.

   font-weight and margin-top are deliberately left to the cascade — inside
   `.content` they resolve to bold/0 where live renders 500/15px. A known parity
   difference, not something this rule should decide on its own. */
.block__heading,
.content .block__heading {
    --vw-heading-size: 21px;
    font-size: var(--vw-heading-size);
    line-height: 1.2;
    color: #82bf5a;
}

/* headingStyle — size only, never the outline. These were emitted by
   HeadingTagHelper from the start but had no CSS behind them, so the field did
   nothing. Scaling the component's own size keeps "groot" meaning one step up
   from whatever this block normally looks like, in every block. */
.heading--groot {
    font-size: calc(var(--vw-heading-size, 1rem) * 1.35);
}

.heading--klein {
    font-size: calc(var(--vw-heading-size, 1rem) * 0.75);
}

/* ── Hero image as a real <img> ───────────────────────────────────────────
   The old site painted the hero with a CSS background-image, so no rule for
   .imageheader__bg ever existed — the class was only a hook for the gradient.
   A background-image cannot be preloaded, cannot carry srcset and cannot have
   an alt, so the hero is now a real <img> through <vw-image>.

   .imageheader keeps its aspect ratio with padding-top:49.47%, which leaves the
   img in normal flow *below* that padding. Taking it out of flow puts it back
   where a background would have been, under the :after gradient (which paints
   later) and the .imageheader__inner text (z-index:50).

   This is a rebuild, not a debt. */
.imageheader__bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: 0;
}

/* …but below 681px the old site does not overlay the text at all: the photo sits
   on top and the heading, intro and CTA stack under it in dark type on white.
   vw-components.css still carries that whole @media block — it hides the gradient,
   flips the colours and puts .imageheader__inner back in flow — and every rule in
   it worked except one: `.imageheader__bg { position:relative; height:auto }`,
   which this file's unconditional rule above beat on load order. So the mobile
   hero rendered white-on-photo and was unreadable. Hand the img back to the flow.

   Scoped away from --home because the homepage hero was a different component on
   the old site (.flicker-slider--home) and overlays its text at every width; its
   custom.css rules absolutely position .imageheader__inner, which a static img
   would leave stranded. */
@media (max-width: 680px) {
    .imageheader:not(.imageheader--home) .imageheader__bg {
        position: static;
        inset: auto;
        width: 100%;
        height: auto;
        object-fit: initial;
    }
}

/* ── Legacy `width: 100%` on an image needs `height: auto` beside it ──────
   `<vw-image>` always writes explicit width/height attributes — that is the whole
   point, it reserves the box and kills layout shift. The legacy CSS was written for
   `<img>` tags that had no such attributes, so wherever it sets only the width, the
   height attribute survives as the used height and the picture is stretched.

   The nav thumbnail is the case in hand: `.collapser__col--img img { width: 100% }`
   turned an 800×600 crop into a 263×600 slab, six times taller than it should be, and
   the mega-menu panel grew to 680px to hold it. `height: auto` restores live's own
   293×220. Cannot be fixed globally: an `img[width][height]` attribute selector would
   outrank `.imageheader__bg`, `.detail__header__bg`, `.scroller__image__item img` and
   `.block__thumb--round img`, all of which set `height: 100%` with `object-fit: cover`
   on purpose. So it is one rule per legacy selector, added as each is hit.

   Four more legacy rules have the same shape and are **latent, not currently broken** —
   `.streamer img`, `.component--photo__img img`, `.content p img`,
   `.product__thumbs__item img`. Every image on `/` and `/afval` measures at its true
   aspect ratio today, so those four are either overridden or not yet reached by a
   `<vw-image>`. They will bite the moment one lands in them. See `B17` in backlog.md. */
.collapser__col--img img {
    height: auto;
}

/* ── Scroller: position:sticky replaces Bootstrap 3's Affix plugin ────────
   The legacy CSS pins the image column with .affix / .affix-bottom, classes
   Bootstrap 3's Affix plugin toggled from jQuery. Bootstrap 4 dropped Affix and
   Bootstrap 5 has no replacement, because position:sticky does the job in CSS.

   The legacy `.scroller__slide{height:507px}` is also overridden: a fixed height
   left large gaps under short slides and clipped long ones. Slides now size to
   their content with a floor that keeps the sticky image on screen long enough
   to read the text beside it.

   This is a rebuild, not a debt — it does not get deleted when the component is
   migrated, it IS the migration of that component. */
.scroller__col--slides .scroller__slide {
    height: auto;
}

@media (min-width: 992px) {
    /* Slides need travel only where there is a sticky image to travel past. Below lg
       that column is hidden and each slide carries its own image inline, so a 60vh
       floor there just adds ~2400px of empty scrolling on a phone. */
    .scroller__col--slides .scroller__slide {
        min-height: 60vh;
        display: flex;
        flex-direction: column;
        justify-content: center;
    }

    /* Flex instead of the legacy floats, so the image column is as tall as the
       slides column. position:sticky travels only within its own parent — with
       floats the image column ended after one slide and the image scrolled away. */
    .scroller__cols {
        display: flex;
        align-items: stretch;
    }

    .scroller__cols > .scroller__col {
        float: none;
        width: 50%;
    }

    .scroller__col--sticky .scroller__image {
        position: sticky;
        /* Clear of the fixed site header. */
        top: 120px;
        height: 60vh;
        /* The legacy box was a fixed 460×547 with 40px of top padding, sized for the
           Affix markup where it sat inside a float. Here it is a flex column that
           already has its own width, so the fixed one only makes it narrower than
           the column it lives in. */
        width: 100%;
        padding-top: 0;
    }

    /* The wrapper owns position and the fade; the img inside only has to fill it.
       Splitting them lets the shared _ImageBlock partial render the img untouched.
       The left inset is the gutter .scroller__graph occupies — the legacy layout got
       the same gap from `width:80%;right:0` on the img itself. */
    .scroller__image__item {
        position: absolute;
        inset: 0 0 0 72px;
        opacity: 0;
        transition: opacity 300ms ease-in-out;
    }

    /* ── Progress dial ─────────────────────────────────────────────────────
       A hairline down the gutter, broken in the middle by a ring that fills one
       step per slide. The legacy version was `.scroller__graph:before/:after` at a
       fixed 200px each plus a 60×60 <canvas> drawn from a scroll handler; the rule
       here is expressed as offsets instead, because the sticky box is now sized
       from the viewport rather than to a fixed 547px. */
    .scroller__graph {
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        width: 60px;
    }

    .scroller__graph::before,
    .scroller__graph::after {
        content: "";
        position: absolute;
        left: 30px;
        width: 1px;
        background: #eee;
    }

    .scroller__graph::before {
        top: 0;
        bottom: calc(50% + 38px);
    }

    .scroller__graph::after {
        top: calc(50% + 38px);
        bottom: 0;
    }

    .scroller__chart {
        position: absolute;
        top: 50%;
        left: 0;
        margin-top: -30px;
    }

    .scroller__chart circle {
        fill: none;
        stroke-width: 7;
    }

    .scroller__chart__track {
        stroke: #eee;
    }

    .scroller__chart__value {
        stroke: #82bf5a;
        /* pathLength="100" on the circle makes one dash unit one percent, so site.js
           can write a percentage straight into stroke-dashoffset without knowing the
           radius. Rotated so the arc starts at twelve o'clock and fills clockwise. */
        stroke-dasharray: 100;
        transform: rotate(-90deg);
        transform-origin: 50% 50%;
        transition: stroke-dashoffset 300ms ease-in-out;
    }

    .scroller__image__item img,
    .scroller__image__item picture {
        width: 100%;
        height: 100%;
        object-fit: cover;
        /* The legacy `.scroller__image img` faded the images themselves — they were
           siblings that the jQuery handler switched with [data-imgactive]. It leaves
           every img at `opacity:0`, offset `top:40px;right:0`, so with the fade moved
           onto the wrapper the whole column rendered blank. Hand the img back to its
           wrapper: no offset of its own, always opaque. */
        position: static;
        opacity: 1;
    }

    /* Without JS the column would be blank, so the first image shows by default.
       site.js marks the container once the observer is attached, and from then on
       only the active image is visible. */
    .scroller__image:not([data-scroller-enhanced]) .scroller__image__item:first-child {
        opacity: 1;
    }

    .scroller__image[data-scroller-enhanced] .scroller__image__item.is-active {
        opacity: 1;
    }
}

@media (prefers-reduced-motion: reduce) {
    .scroller__image__item,
    .scroller__chart__value {
        transition: none;
    }

    /* The pins are visible without the animation, so suppressing it costs nothing. */
    .garbage__map--active .garbage__pin {
        animation: none;
    }
}

/* ── Legacy .btn sizing ───────────────────────────────────────────────────
   The site's own .btn rules were written to layer on top of Bootstrap 3's .btn.
   Bootstrap 5's .btn sets its own padding, font-size, line-height and
   border-radius via CSS custom properties, which now win where the legacy rules
   relied on inheriting Bootstrap 3's. Reassert the site's shape.
   Retire once the button component is rebuilt. */
.btn--primary,
.btn--default,
.btn--lg {
    --bs-btn-padding-x: unset;
    --bs-btn-padding-y: unset;
    --bs-btn-font-size: unset;
    --bs-btn-line-height: unset;
    --bs-btn-border-radius: unset;
}

/* ── Quicky dropdown containing block ─────────────────────────────────────
   The offerte panel is `position:absolute; top:100%; left:15px;
   width:calc(100% - 30px)` — written when every Bootstrap 3 column carried
   `position:relative` and a 15px half-gutter, so those constants landed the
   panel exactly on the tile below it. Bootstrap 5 columns are positioned
   `static`, so the panel escaped its column and resolved against the page box.

   Give the wrapper the containing block back, and read the inset from the live
   gutter instead of the old constant — Bootstrap 5's is 24px, not 30px.
   Retire when the quicky component is rebuilt against Bootstrap 5. */
.quicky__dropdown-wrap {
    position: relative;
}

.quicky__dropdown {
    left: calc(var(--bs-gutter-x, 1.5rem) * .5);
    width: calc(100% - var(--bs-gutter-x, 1.5rem));
    max-width: calc(100% - var(--bs-gutter-x, 1.5rem));
}

/* ── Detail header photo is an <img>, not a background ────────────────────
   The legacy `.detail__header` paints a `background-image` with
   `background-attachment: fixed`, `background-size: cover` and
   `background-position: center top`. _LayoutDetail renders a real <img> instead —
   it is the LCP element on every detail page, and a background can be neither
   preloaded nor served at a sensible width. These rules put the img exactly where
   the background sat.

   The `fixed` parallax is not reproduced. It cannot be, on an <img>, without
   script — and iOS has always ignored it, so the effect was already absent for
   roughly half the site's visitors. Recorded as a deliberate divergence.

   This is a rebuild, not a debt: it does not get deleted when the component
   migrates, it IS the migration of that component. */
.detail__header__bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* `center top` — the legacy background-position. Faces sit near the top of these
       photos, so a centre crop decapitates them at narrow widths. */
    object-position: center top;
    z-index: 0;
}

/* ── Breadcrumb styling was lost in the Bootstrap split ───────────────────
   `.breadcrumb` is one of the class names Bootstrap 3 also defined, so the site's own
   rules for it were subtracted out of vw-components.css and now exist only in the
   unloaded main.css. Nothing on the site styled a breadcrumb at all — Bootstrap 5's
   own `.breadcrumb` (display:flex, margin-bottom:1rem, list-style:none) was the only
   thing applying, and the fontello separator was simply missing.

   Measured on the live page and reproduced here: block flow, no padding, 24px below,
   transparent, and a `\e830` chevron after each link.

   The right long-term fix is `split_main.py` keeping site rules whose selector merely
   collides with a framework one — this is the same class of loss the "subtract on
   selector *and* declarations" fix addressed. Retire these when that lands. */
.breadcrumb {
    display: block;
    padding: 0;
    margin: 0 0 24px;
    background: transparent;
}

.breadcrumb a,
.breadcrumb span {
    color: #786e65;
    margin: 0 3px 0 0;
}

.breadcrumb a {
    transition: color 0.25s ease-out;
}

.breadcrumb a::after {
    content: "\e830";
    font-family: "fontello";
    margin-left: 7px;
}

.breadcrumb a:hover {
    text-decoration: none;
    color: #5d9339;
}

/* ── Bootstrap moved `.active` off the tab's <li> ─────────────────────────
   The kernwaarden tab strip (`coreValuesBlock`) reuses the old site's `.about__tabs`
   styling, and all of that is written against Bootstrap 3's tab JS, which marked the
   parent <li> active:

       .about__tabs__li.active          { border-color: #82bf5a }   green underline
       .about__tabs__li.active:after    { …caret… }                 the arrow beneath
       .about__tabs__li.active a        { color: #82bf5a }
       .about__tabs__li.active svg path { fill: #82bf5a }

   Bootstrap 5 puts `.active` on the *trigger* instead and never touches the <li>, so
   every one of those would silently stop firing: the panels would change while the
   strip stayed frozen showing tab one as selected. That reads as a broken component,
   not as a styling gap.

   Re-pointed at the trigger rather than reverting to BS3 semantics with a hand-written
   controller — Bootstrap's tab JS already implements the APG keyboard pattern (arrow
   keys, Home/End, roving tabindex) correctly, and that is worth more than the four
   selectors below.

   `:has()` is Baseline-available in every browser this site targets. The `.active` the
   partial writes on the first <li> at render time is what keeps the strip correct before
   JS runs, and what a no-JS visitor keeps.

   Retire this block only if the tab strip stops using the legacy `.about__tabs` CSS. */
.about__tabs__li:has(> .about__tabs__link.active) {
    border-color: #82bf5a;
}

.about__tabs__li:has(> .about__tabs__link.active)::after {
    top: 100%;
    left: 50%;
    border: solid transparent;
    content: " ";
    height: 0;
    width: 0;
    position: absolute;
    pointer-events: none;
    border-color: rgba(32, 213, 44, 0);
    border-top-color: #82bf5a;
    border-width: 15px;
    margin-left: -15px;
}

.about__tabs__link.active {
    color: #82bf5a;
}

.about__tabs__link.active svg path {
    fill: #82bf5a;
}

/* The tab is a <button> where the old site had an <a>, so the legacy `.about__tabs__link`
   rules — written for a link — leave it with a UA button's chrome. Strip it back to text.
   Full width so the whole tab cell is the target, not just the words (2.5.8). */
.about__tabs__link {
    display: block;
    width: 100%;
    padding: 0;
    background: none;
    border: 0;
    font: inherit;
    text-align: inherit;
}

@media screen and (max-width: 991px) {
    /* Below lg the strip turns into a left rail and the caret is hidden — the legacy
       `.about__tabs__li.active:after { display: none }` has to be re-pointed too. */
    .about__tabs__li:has(> .about__tabs__link.active)::after {
        display: none;
    }
}

/* ---------------------------------------------------------------------------
   A detail page with no hero photo — 2026-08-08, with the legal pages.

   `.detail__header` is a fixed 600px box (400px below md) because its whole job is
   to hold a full-bleed image, and `--main::after` paints a dark gradient over the
   bottom half so white text stays readable on a photograph. Neither makes sense
   when there is no photograph: /disclaimer rendered 600px of grey with the word
   "Disclaimer" floating in it.

   The heading also stops being white text on a dark gradient and becomes ordinary
   text on the page background, so it has to take the body colour back.

   Scoped to the modifier, so the thirty-odd detail pages that DO have a hero are
   untouched. Delete this rule set the day every page has an image and the modifier
   stops being emitted. */
.detail__header--empty {
    height: auto;
    background: none;
}

.detail__header--empty::after {
    display: none;
}

/* `.detail__header__center` is `position: absolute; bottom: 40px; left: 10%` — it hangs off
   the bottom of the fixed-height box so the heading sits over the dark end of the gradient.
   Collapsing the box to `height: auto` takes the only in-flow content out with it, and the
   first attempt at this rule produced a page with no visible <h1> at all: still in the DOM,
   still one of it, positioned 40px up from a zero-height box and clipped out of sight. Put
   the heading back in normal flow before removing the height it was anchored to. */
.detail__header--empty .detail__container {
    height: auto;
}

.detail__header--empty .detail__header__center {
    position: static;
    width: auto;
    padding-top: 40px;
    padding-bottom: 8px;
}

.detail__header--empty .detail__container h1 {
    color: #303030;
    text-shadow: none;
}
