/* =====================================================================
   eticketskopen.nl - basisstijl
   Fase 2 van de huisstijl-feature (hoofdstuk 4.6.5): platform-restyling
   op basis van de door de klant aangeleverde designcollage ("Eticketskopen
   Collage", Claude Design, 2026-08-02) - paars (#5D5DFF) als enige
   interactiekleur, geel (#FFC80A) als signaalaccent, "glazen" panelen op
   een zacht crème/lavendel-verloop, ronde "pil"-vormige knoppen/badges/
   navigatie. Dit bestand bevat de FUNDAMENT-laag (kleuren, lettertypes,
   randen/schaduwen, basiscomponenten als .card/.button/.badge) - de
   grotere structurele stukken uit de collage (het donkere "glaspaneel"-
   dashboardschild, de zwevende pil-navigatie, het scanscherm in twee
   varianten, de white-label ticketshop) volgen in een latere ronde.

   Lettertypes ('Plus Jakarta Sans' voor tekst, 'JetBrains Mono' voor
   labels/codes) komen uit diezelfde collage - bewust ZELF gehost onder
   assets/fonts/ (uit de collage's eigen ingebedde woff2-bestanden
   gehaald) i.p.v. een Google Fonts-CDN, zodat het platform geen externe
   lettertype-afhankelijkheid krijgt (past bij de rest van het platform).
   Beide zijn variabele fonts - één bestand dekt het hele gewichtenbereik.
   ===================================================================== */

@font-face {
    font-family: "Plus Jakarta Sans";
    src: url("../fonts/PlusJakartaSans-variable.woff2") format("woff2");
    font-weight: 400 800;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "JetBrains Mono";
    src: url("../fonts/JetBrainsMono-variable.woff2") format("woff2");
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
}

/* Suez One (Google Font, OFL-licentie) - alleen voor de koppen op het
   nieuwe flyerontwerp van het printbare ticket (klantbeslissing
   2026-08-09), niet voor de rest van het platform. Eén statisch gewicht
   i.p.v. een variabel font zoals de twee hierboven, vandaar
   "-Regular" i.p.v. "-variable" in de bestandsnaam. Zolang het
   bronbestand nog niet is omgezet naar woff2 laadt deze regel simpelweg
   niets en valt --font-display (hieronder in :root) terug op Georgia. */
@font-face {
    font-family: "Suez One";
    src: url("../fonts/SuezOne-Regular.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

:root {
    --brand: #5d5dff;
    --brand-dark: #101014;
    --brand-light: #eeeaff;
    --accent: #ffc80a;
    --accent-ink: #8a6800;
    --ink: #101014;
    --muted: #7c7c89;
    --surface: #ffffff;
    --surface-alt: #f6f6ff;
    --border: #dcdce2;
    --danger: #b3352b;
    --danger-bg: #fbeceb;
    --success: #1f7a5a;
    --success-bg: #e7f5ef;
    /* UI-0 design foundation (2026-09, o.b.v. de gecorrigeerde mockup-
       selectie): losse warning-tokens i.p.v. --accent/--accent-ink
       hergebruiken voor statussemantiek - geel blijft zo de merk-
       signaalkleur, en "warning" krijgt zijn eigen naam voor toekomstige
       call sites (badge/alert), ook al is de onderliggende tint bewust
       hetzelfde geel. --accent/--accent-ink zelf blijven ongewijzigd
       (bestaande .badge--accent-gebruik elders raakt hier niets aan). */
    --warning: #8a6800;
    --warning-bg: #fff4d6;
    /* UI-0 accessibility fix (Codex-bevinding, P1): --brand (#5d5dff) als
       TEKST op --brand-light (#eeeaff) meet circa 3.99:1 - te laag voor
       kleine badge-tekst (WCAG-eis 4.5:1). --brand-ink is dezelfde
       paarse familie, alleen donkerder/verzadigder zodat de tekst zelf
       leesbaar wordt zonder de achtergrond of de betekenis ("info") aan
       te passen - zelfde naamgevingspatroon als het bestaande
       --accent/--accent-ink-paar hierboven. Circa 6:1 op --brand-light. */
    --brand-ink: #4646d6;
    /* UI-0 accessibility fix (Codex-bevinding, P1 - vervolg): focus-
       indicatoren verwezen naar --brand, maar --brand is precies het
       token dat tenant-huisstijl per pagina overschrijft (View.php zet
       een inline <style>:root{--brand:...}</style> met een door de
       organisatie gekozen kleur - elke geldige hex is toegestaan, ook
       #ffffff of een zeer lichte tint). Daardoor kon een organisatie
       zonder het zelf te willen de focusring opnieuw (bijna) onzichtbaar
       maken. --focus-ring is een LETTERLIJKE hexwaarde (bewust geen
       var(--brand)-verwijzing) - dezelfde paarse merkkleur als het
       standaard-brand, maar structureel NOOIT beïnvloed door een
       tenant-override, want tenant-huisstijl overschrijft uitsluitend
       --brand zelf. Getest (zie rapportage): ruim boven de 3:1-eis op
       zowel de lichte kaartoppervlakken als de donkere schil (scan-app/
       pil-navigatie) van dit platform - onafhankelijk van welke
       --brand-kleur een organisatie kiest, want die surfaces zelf zijn
       nooit tenant-gekleurd. */
    --focus-ring: #5d5dff;
    /* VF-1 (true visual rebuild, tenant-branding-strategie): --brand wordt
       per tenant overschreven (View.php) en hoorde daardoor voorheen ook
       de primaire koopknoppen te bepalen - bij een donkere/verzadigde
       tenantkleur (bijv. bordeaux) domineerde die daardoor de volledige
       koopreis. --brand-interactive is, net als --focus-ring hierboven,
       een LETTERLIJKE, nooit-tenant-overschreven waarde: de vaste
       Eticketskopen-interactiekleur. Tenantkleur (--brand) blijft gewoon
       bruikbaar voor identiteitsmomenten (event-visual-accent, logo-
       omgeving) - alleen de platformbrede "dit is een koopknop"-taal op
       koperspagina's (.buyer-body, zie View::render()) wijst voortaan
       hiernaar i.p.v. naar --brand. */
    --brand-interactive: #5d5dff;
    --radius: 10px;
    --radius-lg: 16px;
    --radius-panel: 22px;
    --radius-pill: 999px;
    --font-sans: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Consolas, "Liberation Mono", monospace;
    --font-display: "Suez One", Georgia, "Times New Roman", serif;
    --shadow-card: 0 10px 30px rgba(20, 20, 60, 0.05);
    --shadow-pill: 0 6px 16px rgba(20, 20, 60, 0.08);
}

* {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    /* Zonder dit blijft het canvasverloop/dashboardschild (.canvas-body/
       .dashboard-body hieronder) beperkt tot de hoogte van de content -
       op een korte pagina (bijv. inloggen) stopt de gradient dan
       halverwege het scherm i.p.v. de hele viewport te vullen. */
    min-height: 100vh;
    /* dvh waar de browser dat kent: op mobiel is 100vh de LAYOUT-viewport
       (inclusief de balk die weg kan scrollen), 100dvh de zichtbare. Het
       verschil belandde anders als lege scrollruimte onderaan de pagina. */
    min-height: 100dvh;
    /* "Sticky footer"-patroon: body is een flex-kolom van de volle
       viewporthoogte, .page (hieronder) krimpt niet mee maar groeit juist
       mee (flex-grow) om de resterende ruimte op te vullen - de voettekst
       (site-footer) wordt daardoor altijd tegen de onderkant van het
       scherm geduwd, ook als de pagina-inhoud zelf te kort is om de
       viewport te vullen. Zonder dit stapelt de voettekst gewoon direct
       onder de content, met lege ruimte er nog onder. */
    display: flex;
    flex-direction: column;
    font-family: var(--font-sans);
    color: var(--ink);
    background: var(--surface-alt);
    line-height: 1.55;
    font-size: 16px;
    /* Voorkomt in-/uitzoomen bij dubbeltikken (o.a. scan-app-inlog- en
       evenementkeuzepagina's) - de viewport-meta (user-scalable=no)
       wordt door moderne iOS Safari genegeerd voor dit specifieke
       gebaar, touch-action is de betrouwbare aanpak. Pinch-zoom blijft
       gewoon werken (manipulation staat dat toe), alleen de dubbeltik-
       snelkoppeling wordt uitgeschakeld. */
    touch-action: manipulation;
}

/* Voorkomt de andere vorm van "inzoomen" op mobiel (o.a. ticketshop-
   checkout): dubbeltikken op een <label> (bijv. een tickettype-kaart of
   een aanvinkvakje-tekst) selecteert anders de tekst, en iOS Safari
   toont daarbij een vergrotende selectie-loep + keuzemenu - dat voelt
   hetzelfde aan als inzoomen maar wordt NIET door touch-action hierboven
   tegengehouden (dat blokkeert alleen de dubbeltik-zoom-snelkoppeling
   op de pagina zelf, niet native tekstselectie). input/textarea blijven
   bewust wel gewoon selecteerbaar, anders kun je niet meer bewerken. */
label,
.button,
button,
.badge {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
}

input,
textarea,
select {
    -webkit-user-select: text;
    user-select: text;
}

h1, h2, h3 {
    font-family: var(--font-sans);
    color: var(--brand-dark);
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.2;
    margin: 0 0 0.6em;
}

h1 {
    font-size: 1.9rem;
}

/* Paginatitel + optionele "Terug naar ..."-knop (klantbeslissing
   2026-08-05, View::render()'s $backLink) op dezelfde regel i.p.v. de
   knop ergens linksonder de pagina - de ruimte die h1's eigen
   margin-bottom normaal gaf, staat nu op .page-header zelf. */
.page-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 0.6em;
}

.page-header h1 {
    margin-bottom: 0;
}

.page-header__back {
    flex: none;
}

h2 {
    font-size: 1.4rem;
}

p {
    margin: 0 0 1em;
}

a {
    color: var(--brand);
    text-decoration: underline;
    text-underline-offset: 2px;
}

code {
    font-family: var(--font-mono);
    background: var(--surface-alt);
    padding: 0.15em 0.4em;
    border-radius: 4px;
    font-size: 0.9em;
    overflow-wrap: anywhere;
}

/* UI-0 design foundation: losse utility-klasse voor JetBrains Mono waar
   dat functioneel past (ticket-/scancodes, bedragen in een tabel,
   timestamps) zonder de <code>-styling (achtergrond/padding) erbij te
   hoeven nemen - <code> hierboven blijft voor letterlijke code-achtige
   waarden, .font-mono is puur het lettertype. */
.font-mono {
    font-family: var(--font-mono);
}

/* ---------------------------------------------------------------------
   Kopieerbare link (deel-links, hoofdstuk 4.4) - de link zelf mag
   afbreken (overflow-wrap hierboven), het knopje blijft op zijn eigen
   regel staan i.p.v. mee te breken.
   --------------------------------------------------------------------- */

.copy-link {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 1em;
}

.copy-link__value {
    flex: 1 1 auto;
    min-width: 0;
}

.copy-link__btn {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--surface-alt);
    color: var(--ink);
    font-size: 0.82rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
}

.copy-link__btn:hover {
    background: var(--brand-light);
}

.copy-link__btn svg {
    width: 14px;
    height: 14px;
    flex: none;
}

/* ---------------------------------------------------------------------
   Layout chrome: header met het "ticketreep"-beeldmerk, en een simpele
   centrale container. Mobile-first: header stapelt niet, blijft compact.
   --------------------------------------------------------------------- */

/* Sticky (klantverzoek 2026-08-06) + geen rechter padding: de
   logo-pil hieronder bleedt tot de ware rechterrand van de viewport,
   zelfde foutbestendige aanpak als .dashboard-topbar (geen padding om
   een negatieve marge tegen te hoeven spiegelen). Bewust GEEN eigen
   achtergrond (meer) - klantbeslissing 2026-08-08: alleen de witte
   logo-pil zelf is zichtbaar, de rest van de balk is transparant en
   toont de hero-afbeelding/pagina-achtergrond erdoorheen. Ruimere
   padding-top dan onder (klantverzoek 2026-08-08, "meer marge boven
   het kader") - onder is nog steeds compact, dit was nooit een volle
   balk om voor te reserveren. */
.site-header {
    padding: 24px 0 8px 20px;
    position: sticky;
    top: 0;
    z-index: 30;
}

/* De vroegere ":has(+ main.page > .event-hero...)"-regel hier (posities
   de logo-pil bovenop de ticketshop-hero) is met de 1c full-journey
   shell correction vervallen: de checkout-familie (EventStorefrontController::
   renderBuyerCheckoutShell(), voorheen .event-hero) rendert de pil nu
   helemaal niet meer (View::render()'s $hideHeaderPill) - tenantidentiteit
   staat daar in het linker eventpaneel zelf (.buyer-shell__identity). Elke
   ANDERE pagina (ticketshop-hoofdpagina, e-ticket, bestelstatus,
   marketing) gebruikt gewoon de normale sticky-balk hierboven, ongewijzigd. */

/* Geen max-width/margin:auto hier (zelfde bug als .dashboard-topbar
   ooit had): dat zou op een scherm breder dan 1600px een gat overlaten
   tussen de pil en de ware rechterrand - de pil moet tot de rand van de
   viewport bleeden, niet tot de rand van de 1600px-brede inhoud. */
.site-header__inner {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
}

/* Organisatielogo als witte pil rechts, "uit de zijkant komend"
   (klantverzoek 2026-08-06, View.php $publicHeaderLogoHtml) - het
   spiegelbeeld van .dashboard-topbar__logo: hier links afgerond i.p.v.
   rechts, want de pil bleedt naar RECHTS toe. */
.site-header__logo-pill {
    display: flex;
    align-items: center;
    padding: 8px 20px 8px 18px;
    border-radius: var(--radius-pill) 0 0 var(--radius-pill);
    background: #ffffff;
    box-shadow: var(--shadow-pill);
    box-sizing: border-box;
}

.site-header__logo-pill img {
    display: block;
    max-height: 36px;
    max-width: 160px;
}

/* Groter op desktop (klantverzoek 2026-08-08) - alleen max-height/
   max-width, geen object-fit en geen losse HTML width/height-attributen
   op de <img>, dus de browser schaalt het logo altijd naar verhouding:
   werkt voor liggende, staande én vierkante logo's zonder vervorming -
   een staand/vierkant logo loopt gewoon eerder tegen max-height aan
   (en blijft dus smaller dan max-width), een liggend logo eerder tegen
   max-width. Op mobiel blijft de kleinere basisregel hierboven staan
   (weinig ruimte naast de rest van de pagina-inhoud). */
@media (min-width: 900px) {
    .site-header__logo-pill img {
        max-height: 52px;
        max-width: 240px;
    }
}

.site-header__logo-pill .logo-mark--dark span {
    background: var(--ink);
}

.site-header__logo-pill .logo-mark {
    height: 16px;
}

.site-header__logo-pill .logo-text--dark {
    color: var(--ink);
}

.logo-mark {
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 22px;
}

.logo-mark span {
    display: block;
    width: 5px;
    background: var(--surface);
    border-radius: 1px;
}

.logo-mark span:nth-child(1) { height: 60%; }
.logo-mark span:nth-child(2) { height: 100%; }
.logo-mark span:nth-child(3) { height: 45%; }
.logo-mark span:nth-child(4) { height: 80%; }

.logo-text {
    color: var(--surface);
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: -0.01em;
}

.logo-text .dot {
    color: var(--accent);
}

.page {
    max-width: 1600px;
    margin: 0 auto;
    padding: 32px 20px 64px;
    /* Groeit mee met de resterende ruimte in de flex-kolom van body
       hierboven ("sticky footer"-patroon) - duwt de voettekst altijd
       tegen de onderkant van het scherm, ook op korte pagina's. */
    flex: 1 0 auto;
    width: 100%;
    box-sizing: border-box;
    /* display:flex/column (klantbeslissing 2026-08-05, i.p.v. het
       eerdere gewone block-element) - alleen zodat .tab-dock hieronder
       `margin-top: auto` kan gebruiken om zichzelf naar de onderkant van
       .page te duwen op een korte pagina (inhoud vult het scherm niet).
       Verandert verder niets aan de opmaak: elk kind hier krijgt van
       CSS-grid/flex-column standaard dezelfde volle breedte als voorheen
       in normale block-flow, en margin-collapsing speelt in de praktijk
       toch geen rol - kaarten/koppen/paragrafen in dit project gebruiken
       uitsluitend margin-bottom, nooit margin-top, dus er was hiervoor
       ook al nooit een aangrenzende marge die kon "collapsen". */
    display: flex;
    flex-direction: column;
}

.page--narrow {
    max-width: 440px;
}

/* Tussenmaat voor de aanmaakwizard (klantverzoek 2026-08-13) - geeft
   .field-grid (minmax(260px,1fr)) ruimte voor 2-3 kolommen op desktop,
   zonder de wizard even breed te maken als de platformbrede .page
   (1600px, bedoeld voor lijstpagina's). */
.page--medium {
    max-width: 900px;
}

/* Geen eigen padding (i.p.v. een eigen, nog bredere max-width - .page
   hierboven is nu al platformbreed 1600px) - alleen voor de publieke
   ticketshop-hoofdpagina (collage "05 Ticketshop"), zodat de hero zelf
   tot de randen van de pagina loopt. De rest van de inhoud krijgt zijn
   eigen ademruimte terug via .page-inner hieronder. */
.page--full {
    padding: 0 0 64px;
}

.page-inner {
    padding: 24px 24px 0;
}

@media (min-width: 900px) {
    .page-inner {
        padding: 32px 32px 0;
    }
}

/* Platform-restyling fase 2 (hoofdstuk 4.6.5, "01 Backend - organisator"
   uit de designcollage): het dashboardschild voor ingelogde organisatie-
   schermen - zacht crème/lavendel-verloop i.p.v. de platte
   --surface-alt-achtergrond, met een zwevende "pil"-navigatie bovenaan
   i.p.v. de simpele donkere site-header. Wordt toegepast wanneer
   View::useDashboardChrome()/useAdminChrome() is aangeroepen (de
   ingelogde organisatie-/adminschermen).

   .canvas-body (restyle-opdracht, Stijling/RESTYLE_PROMPT.md - "Canvas-
   kleur: zacht paars-crème verloop, Paginabackground, geen effen wit"):
   ZELFDE verloop, maar voor de eigen platformpagina's zonder dashboard-
   chrome - inloggen/2FA/activeren, adminsetup en de marketingsite. De
   wit-label klantpagina's (ticketshop/checkout/e-ticket/deel-links, waar
   de organisatie een eigen merkkleur/logo kan hebben) krijgen dit
   BEWUST niet - zie de toelichting bij View::render(). */
body.dashboard-body,
body.canvas-body {
    background: linear-gradient(138deg, #fdfcf8 0%, #f7f7ff 30%, #ecebff 62%, #fff9e8 100%);
}

/* Grid i.p.v. flex met justify-content:space-between - dat zou de
   pil-navigatie tegen de linkerrand duwen (er staat niets links
   ernaast). Twee gelijke 1fr-kolommen aan weerszijden van de
   auto-brede navigatie houden die daadwerkelijk gecentreerd, ongeacht
   de breedte van het gebruikersbadge rechts. */
.dashboard-topbar {
    /* Bewust GEEN max-width/margin:auto (klantbeslissing 2026-08-06, na
       feedback dat de logo-/accountpil nog niet echt helemaal links/
       rechts tegen de paginarand stonden): met een max-width van 1600px
       zoals .page hieronder wel heeft, zou dat op een breder scherm dan
       1600px alsnog een zichtbare marge tussen de pil en de ware
       viewportrand overlaten. De pil-navigatie in het midden blijft
       gewoon horizontaal gecentreerd op de viewport (grid 1fr-auto-1fr),
       dus die staat nog steeds in lijn met de wél op 1600px begrensde
       .page-inhoud eronder. Ook bewust GEEN horizontale padding: met
       padding hier zou de negatieve marge op de pillen hieronder altijd
       exact het paddingcijfer moeten spiegelen om de ware rand te raken -
       foutgevoelig zodra een van beide ooit wijzigt. */
    padding: 20px 0 0;
    /* Sticky (klantbeslissing 2026-08-06): blijft bovenin staan tijdens
       het scrollen, paginainhoud schuift er gewoon achter/onderdoor -
       er zit bewust geen eigen achtergrond op .dashboard-topbar zelf
       (alleen de 3 pillen hebben er een), dus dat "doorschuiven" is ook
       zichtbaar in de gaten tussen de pillen. z-index laag genoeg om
       onder modals/overlays (900+) te blijven, hoog genoeg voor gewone
       paginainhoud. */
    position: sticky;
    top: 0;
    z-index: 30;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    /* stretch i.p.v. center (klantbeslissing 2026-08-05): logo- en
       accountpil moeten precies zo hoog worden als het menu, dat zelf de
       hoogte van de rij bepaalt (.pill-nav is de hoogste van de drie). */
    align-items: stretch;
    gap: 16px;
}

.dashboard-topbar .pill-nav {
    grid-column: 2;
    justify-self: center;
}

.dashboard-topbar .dashboard-topbar__user {
    grid-column: 3;
    justify-self: end;
}

/* Platformlogo linksboven in de dashboardschild-topbar (klantbeslissing
   2026-08-05). Witte pil (zelfde als de accountnaam-pil rechts) met het
   gekleurde platformlogo i.p.v. de witte variant - deze pil zit niet op
   een donkere achtergrond zoals de header/voettekst, dus het gewone
   logo is hier juist beter leesbaar. Komt "uit de zijkant": vlak
   (niet afgerond) aan de linkerkant, alleen rechts afgerond, en met een
   negatieve marge tot tegen de linkerrand van de topbar-container
   getrokken - het spiegelbeeld van de accountpil rechts hieronder. */
.dashboard-topbar__logo {
    grid-column: 1;
    justify-self: start;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 18px 0 20px;
    border-radius: 0 var(--radius-pill) var(--radius-pill) 0;
    background: #ffffff;
    box-shadow: var(--shadow-pill);
    box-sizing: border-box;
}

/* Zie .site-footer__logo hieronder - zelfde reden voor de ruimere
   max-height (was 24px); .dashboard-topbar__logo stretcht toch al mee
   met de hoogte van de pil-navigatie ernaast, dus er is ruim plek. */
.dashboard-topbar__logo img {
    display: block;
    max-height: 36px;
    max-width: 140px;
}

.dashboard-topbar__logo .logo-mark--dark span {
    background: var(--ink);
}

.dashboard-topbar__logo .logo-mark {
    height: 16px;
}

.dashboard-topbar__logo .logo-text--dark {
    color: var(--ink);
}

.pill-nav {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 6px;
    border-radius: var(--radius-pill);
    background: rgba(16, 16, 22, 0.92);
    box-shadow: 0 12px 30px rgba(16, 16, 40, 0.28);
    overflow-x: auto;
    max-width: 100%;
}

.pill-nav__item {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 11px 18px;
    border-radius: var(--radius-pill);
    font-size: 0.88rem;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.66);
    text-decoration: none;
    white-space: nowrap;
    flex: none;
}

.pill-nav__item:hover {
    color: #fff;
}

.pill-nav__item--active {
    background: #fff;
    color: var(--ink);
    font-weight: 700;
}

.pill-nav__item--active .pill-nav__dot {
    background: var(--brand);
}

.pill-nav__dot {
    width: 9px;
    height: 9px;
    border-radius: 3px;
    background: transparent;
    flex: none;
}

/* Spiegelbeeld van .dashboard-topbar__logo hierboven (klantbeslissing
   2026-08-05): alleen links afgerond, vlak/tegen de rechterrand van de
   topbar-container getrokken met een negatieve marge. */
.dashboard-topbar__user {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 20px 0 18px;
    border-radius: var(--radius-pill) 0 0 var(--radius-pill);
    background: #fff;
    box-shadow: var(--shadow-pill);
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--ink);
    white-space: nowrap;
    box-sizing: border-box;
}

.dashboard-topbar__user-badge {
    width: 30px;
    height: 30px;
    border-radius: var(--radius-pill);
    background: var(--brand);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.8rem;
    font-weight: 700;
    flex: none;
}

@media (max-width: 720px) {
    .dashboard-topbar {
        grid-template-columns: 1fr;
        align-items: stretch;
        justify-items: stretch;
        /* Gestapeld hebben de pillen weer gewone ademruimte tot de rand
           nodig (ze zijn dan rondom afgerond, niet meer "uit de zijkant
           komend") - de desktop-variant hierboven heeft hier bewust geen
           padding, zie de toelichting daar. */
        padding-left: 20px;
        padding-right: 20px;
    }

    /* Op één kolom gestapeld heeft "uit de zijkant komen" geen betekenis
       meer (er is geen duidelijke linker-/rechterrand-relatie tussen de
       pillen) - dus hier gewoon een normale, volledig afgeronde pil. */
    .dashboard-topbar__logo,
    .dashboard-topbar .dashboard-topbar__user {
        grid-column: 1;
        justify-self: start;
        border-radius: var(--radius-pill);
    }

    .dashboard-topbar .pill-nav {
        grid-column: 1;
        justify-self: stretch;
    }
}

/* Telefoonspecifieke polish bovenop het gestapelde @720px-blok hierboven
   (klantmelding 2026-08-14: "de weergave van o.a. de logo's menu balk en
   klantnaam niet goed weergegeven"). De klantnaam stond als kale tekst
   zonder eigen element (zie renderTopbar() in View.php - nu wél een
   <span>), dus kon nooit worden afgekapt: bij een lange organisatie-/
   gebruikersnaam werd de pil breder dan het scherm. */
@media (max-width: 480px) {
    .dashboard-topbar__user-name {
        max-width: 45vw;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* Vloeiender scrollen op iOS + iets compactere pillen zodat er meer
       tabs in beeld passen zonder te hoeven scrollen. */
    .pill-nav {
        -webkit-overflow-scrolling: touch;
    }

    .pill-nav__item {
        padding: 10px 14px;
        font-size: 0.84rem;
    }
}

/* Donkere, schermbrede voettekst uit de designcollage (klantbeslissing
   2026-08-02, View::renderSiteFooter()) - vervangt de eerdere lichte,
   gecentreerde voettekst (alleen een logo). Ronde bovenhoek net als een
   paneel (--radius-panel), net als de zwevende pil-navigatie een eigen
   "afgesloten" vlak i.p.v. een vlakke balk die de hele viewportbreedte
   pakt. */
/* position:relative + z-index hoger dan .checkout-summary-toggle
   (klantverzoek 2026-08-08: de voettekst-links vielen op mobiel achter
   die vaste "Bestelling bekijken"-balk) - position:static-elementen
   (de standaardwaarde) negeren z-index volledig, dus zonder relative
   zou dit niets doen. .checkout-summary-toggle is fixed en toont
   daardoor normaal altijd bovenop de rest van de pagina, ook bovenop de
   voettekst zodra die aan het einde van de pagina in beeld scrollt -
   deze regel laat de voettekst daar juist overheen tekenen (heeft zelf
   toch al een eigen ondoorzichtige achtergrond, dus de balk verdwijnt
   daar simpelweg achter, precies op het moment dat hij toch niets meer
   te bedienen heeft). */
.site-footer {
    position: relative;
    z-index: 90;
    background: var(--brand-dark);
    border-radius: var(--radius-panel) var(--radius-panel) 0 0;
    padding: 28px 32px;
    margin-top: 40px;
}

.site-footer__inner {
    max-width: 1600px;
    margin: 0 auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}

/* max-height/max-width samen (i.p.v. een vaste hoogte) laten een
   <img> zonder eigen width/height-attributen altijd zijn eigen
   beeldverhouding behouden - een liggend logo wordt dus door
   max-width begrensd, een staand/vierkant logo door max-height, geen
   van beide raakt ooit vervormd. max-height bewust ruimer dan
   voorheen (klantverzoek 2026-08-06, was 28px) - anders werd een
   staand/vierkant logo tot een piepklein duimnagel-formaat
   teruggeschaald terwijl er in de voettekst ruim plek voor is. De
   header heeft sinds klantverzoek 2026-08-06 zijn eigen witte
   logo-pil (.site-header__logo-pill hierboven) i.p.v. dit logo
   rechtstreeks op de donkere achtergrond te tonen - de voettekst blijft
   wél ALTIJD het platformlogo/-beeldmerk (nooit het tenant-logo - geen
   instelling die de klant kan overschrijven), dus .logo-mark/.logo-text
   hier gewoon hun eigen witte basisstijl houden (bedoeld voor een
   donkere achtergrond) i.p.v. de eerdere donker-op-licht-override die
   bij de oude lichte voettekst hoorde. */
.site-footer__logo {
    max-height: 40px;
    max-width: 200px;
}

.site-footer__brand {
    display: flex;
    align-items: center;
    gap: 12px;
}

.site-footer__brand-label {
    color: var(--muted);
    font-size: 0.82rem;
}

.site-footer__links {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 24px;
}

.site-footer__links a {
    color: var(--surface);
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 600;
}

.site-footer__links a:hover {
    color: var(--accent);
}

/* Kleiner op mobiel (klantverzoek 2026-08-08) - minder padding en een
   kleiner logo/label/links, past bij hoe compact de rest van de mobiele
   pagina's al zijn i.p.v. dezelfde ruime desktopmaten te hergebruiken.
   Gecentreerd (klantverzoek 2026-08-09, was flex-start) - .site-footer__
   brand/__links zijn zelf ook flex-rijen, dus align-items:center hier
   centreert zowel de twee rijen zelf (t.o.v. elkaar) als hun eigen
   inhoud (logo+label, resp. de losse links) t.o.v. het midden. */
@media (max-width: 640px) {
    .site-footer {
        padding: 18px 20px;
    }

    .site-footer__inner {
        flex-direction: column;
        align-items: center;
        text-align: center;
        gap: 12px;
    }

    .site-footer__links {
        justify-content: center;
    }

    .site-footer__logo {
        max-height: 28px;
        max-width: 140px;
    }

    .site-footer__brand-label {
        font-size: 0.75rem;
    }

    .site-footer__links {
        gap: 16px;
    }

    .site-footer__links a {
        font-size: 0.8rem;
    }
}

/* FASE E6G.2 - ALLEEN de losse publieke ticketpagina (donkere entree-
   shell met .ticket-page-single): de bijna-zwarte voettekst verdween in de
   pagina. Platformpaars (de standaard --brand van Eticketskopen, bewust als
   vaste waarde - niet de tenantkleur die --brand elders kan
   overschrijven), met witte tekst en links. Alle andere voetteksten
   ongewijzigd. */
body.entry-ticket-shell:has(.ticket-page-single) > .site-footer {
    background: #5d5dff;
}

body.entry-ticket-shell:has(.ticket-page-single) > .site-footer .site-footer__brand-label {
    color: rgba(255, 255, 255, 0.9);
}

body.entry-ticket-shell:has(.ticket-page-single) > .site-footer .site-footer__links a {
    color: #ffffff;
}

body.entry-ticket-shell:has(.ticket-page-single) > .site-footer .site-footer__links a:hover {
    color: #ffffff;
    text-decoration: underline;
}

/* VF-1 (true visual rebuild, mockup 4c): asymmetrische hero i.p.v. de
   vorige, volledig gecentreerde tekstkolom (was letterlijk hetzelfde
   compositiepatroon als vóór UI-1, alleen met nieuwe kleuren/tokens -
   zie de Visual Fidelity Reset). Tekst links, een decoratieve ticket/QR-
   compositie rechts (MarketingController::renderMarketingVisual()) -
   stapelt op mobiel (visual onder de tekst, kleiner), staat naast elkaar
   vanaf 900px. Zit nog steeds op het bestaande .canvas-body-verloop. */
.marketing-hero-split {
    display: grid;
    grid-template-columns: 1fr;
    gap: 40px;
    align-items: center;
    max-width: 1200px;
    margin: 0 auto;
    padding: 48px 24px 8px;
}

.marketing-hero-split__text {
    text-align: center;
}

.marketing-hero-split__visual {
    display: flex;
    justify-content: center;
}

.marketing-hero__eyebrow {
    display: inline-block;
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--brand);
    margin-bottom: 16px;
}

.marketing-hero-split__text h1 {
    font-size: 2.3rem;
    margin: 0 auto 18px;
}

.marketing-hero-split__text p {
    font-size: 1.08rem;
    color: var(--muted);
    max-width: 480px;
    margin: 0 auto 30px;
}

@media (min-width: 900px) {
    .marketing-hero-split {
        grid-template-columns: 1.05fr 0.95fr;
        gap: 56px;
        padding: 76px 24px 24px;
        text-align: left;
    }

    .marketing-hero-split__text {
        text-align: left;
    }

    .marketing-hero-split__text h1 {
        font-size: 2.9rem;
        margin: 0 0 18px;
    }

    .marketing-hero-split__text p {
        margin: 0 0 30px;
        max-width: 460px;
    }

    .marketing-hero__actions,
    .marketing-hero__stats {
        justify-content: flex-start;
    }
}

/* Decoratieve ticket/QR-compositie (MarketingController::
   renderMarketingVisual()) - hergebruikt de bestaande ticket-stub/badge-
   vormtaal (TicketViewController), GEEN screenshot van de app. */
.marketing-visual {
    position: relative;
    width: 100%;
    max-width: 340px;
    padding: 20px 0;
}

.marketing-visual__card {
    border-radius: var(--radius-panel);
    box-shadow: var(--shadow-card);
}

.marketing-visual__card--back {
    position: absolute;
    inset: 24px -12px auto 12px;
    height: 220px;
    background: var(--brand-light);
    transform: rotate(-4deg);
    z-index: 0;
}

.marketing-visual__card--front {
    position: relative;
    z-index: 1;
    background: var(--surface);
    padding: 22px 22px 26px;
    transform: rotate(2deg);
}

.marketing-visual__notch {
    position: absolute;
    top: 50%;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--surface-alt);
    transform: translateY(-50%);
}

.marketing-visual__notch--l {
    left: -11px;
}

.marketing-visual__notch--r {
    right: -11px;
}

.marketing-visual__card-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
}

.marketing-visual__card-top .marketing-visual__eyebrow {
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    color: var(--muted);
}

.marketing-visual__card-divider {
    border-top: 1px dashed var(--border);
    margin-bottom: 18px;
}

.marketing-visual__qr {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 4px;
    width: 148px;
    margin: 0 auto;
}

.marketing-visual__qr-cell {
    aspect-ratio: 1;
    border-radius: 2px;
    background: var(--brand-light);
}

.marketing-visual__qr-cell--on {
    background: var(--brand-dark);
}

.marketing-visual__chip {
    position: absolute;
    display: inline-flex;
    align-items: center;
    padding: 8px 14px;
    border-radius: var(--radius-pill);
    background: var(--surface);
    box-shadow: var(--shadow-pill);
    font-size: 0.78rem;
    font-weight: 700;
    z-index: 2;
}

.marketing-visual__chip--scan {
    top: 4px;
    right: 4px;
    color: var(--success);
}

.marketing-visual__chip--fee {
    bottom: 8px;
    left: -4px;
    color: var(--brand-dark);
}

.marketing-highlights {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 28px;
    max-width: 1000px;
    margin: 0 auto;
    padding: 8px 24px 40px;
    text-align: left;
}

.marketing-highlights__mark {
    display: block;
    width: 34px;
    height: 34px;
    border-radius: var(--radius);
    background: var(--brand-light);
    margin-bottom: 12px;
    position: relative;
}

.marketing-highlights__mark::after {
    content: "";
    position: absolute;
    inset: 10px;
    border-radius: 3px;
    background: var(--brand);
}

.marketing-highlights__item h3 {
    font-size: 1.05rem;
    margin: 0 0 6px;
}

.marketing-highlights__item p {
    margin: 0;
    color: var(--muted);
    font-size: 0.92rem;
}

@media (max-width: 720px) {
    .marketing-hero-split__text h1 {
        font-size: 2rem;
    }

    .marketing-highlights {
        grid-template-columns: 1fr;
    }

    .marketing-visual__card--back {
        display: none;
    }
}

/* UI-1 (public/buyer redesign, mockup 4c): duidelijke CTA-hiërarchie
   (primair + secundair naast elkaar i.p.v. één losse link) en het
   prijs-/waardebelofte-rijtje vroeg zichtbaar in de hero, i.p.v. pas op
   de aparte /prijzen-pagina - hergebruikt DEZELFDE Settings-waarden als
   pricing() (geen nieuwe/verzonnen bedragen). */
.marketing-hero__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 12px;
    margin-bottom: 36px;
}

.marketing-hero__stats {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 32px;
}

.marketing-hero__stat {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.marketing-hero__stat-value {
    font-size: 1.6rem;
    font-weight: 800;
    color: var(--brand-dark);
    letter-spacing: -0.01em;
}

.marketing-hero__stat-label {
    font-size: 0.8rem;
    color: var(--muted);
}

/* Sectiekop boven de featuregrid ("Alles wat je nodig hebt") - voorheen
   ontbrak deze, waardoor de grid zonder duidelijke intro begon. */
.marketing-section__header {
    text-align: center;
    padding: 8px 24px 0;
}

.marketing-section__header h2 {
    font-size: 1.7rem;
    margin-bottom: 6px;
}

.marketing-section__header p {
    color: var(--muted);
    margin: 0;
}

/* Donkere tarievenpreview op de homepage (mockup 4c) - zelfde donkere
   tint/radius als .site-footer hieronder (--brand-dark, --radius-panel),
   geen nieuwe kleur geïntroduceerd. Toont dezelfde Settings-waarde als
   de volledige /prijzen-pagina, puur als korte teaser met CTA daarheen. */
.marketing-pricing {
    background: var(--brand-dark);
    border-radius: var(--radius-panel);
    max-width: 1000px;
    margin: 40px auto 0;
    padding: 48px 32px;
    text-align: center;
}

.marketing-pricing h2 {
    color: var(--surface);
    font-size: 1.7rem;
    margin-bottom: 20px;
}

.marketing-pricing__tags {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
    margin-bottom: 28px;
}

.marketing-pricing__tag {
    display: inline-flex;
    align-items: center;
    padding: 5px 14px;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.1);
    color: rgba(255, 255, 255, 0.8);
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.marketing-pricing__value {
    display: block;
    font-size: 3rem;
    font-weight: 800;
    color: var(--surface);
    letter-spacing: -0.01em;
}

.marketing-pricing__value-label {
    display: block;
    color: rgba(255, 255, 255, 0.75);
    font-size: 0.85rem;
    margin-bottom: 28px;
}

@media (max-width: 720px) {
    .marketing-pricing {
        padding: 36px 20px;
    }

    .marketing-pricing__value {
        font-size: 2.4rem;
    }
}

/* ---------------------------------------------------------------------
   1c full-journey shell correction: .buyer-shell - de EASNE persistente
   tweedeling voor de hele koperscheckout (ticketselectie, Gegevens,
   Personaliseren, Betaling - EventStorefrontController::
   renderBuyerCheckoutShell()/renderBuyerContextPanel()). Vervangt zowel
   de oude .event-hero/.event-shell (voorheen alleen stap 1, met een
   vaste-aspect-ratio "posterkaart" die dode ruimte overliet) als
   .event-context-bar (voorheen een smalle balk op stap 2-4). Mobiel
   (<768px): compacte, gestapelde band bovenaan; desktop/tablet (≥768px):
   linkerpaneel vult de VOLLEDIGE hoogte van de shell (position:sticky,
   height:100vh, geen aspect-ratio-cap meer) - geen losse kaart, een
   paneel.
   --------------------------------------------------------------------- */
.buyer-shell {
    display: flex;
    flex-direction: column;
}

.buyer-shell__context {
    display: flex;
    flex-direction: column;
    color: #ffffff;
}

.buyer-shell__frame {
    position: relative;
    aspect-ratio: 4 / 3;
    overflow: hidden;
}

.buyer-shell__visual {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: var(--hero-crop, center center);
    display: block;
}

@media (min-width: 641px) {
    .buyer-shell__visual--desktop-contain {
        background: var(--hero-bg, var(--brand));
        object-fit: contain;
    }
}

@media (max-width: 640px) {
    .buyer-shell__visual--mobile-contain {
        background: var(--hero-bg, var(--brand));
        object-fit: contain;
    }
}

/* 1c poster/viewport correction (punt 6): het verloop draagt nu zelf een
   vleugje tenantkleur mee i.p.v. een puur neutraal donker verloop - een
   echte foto blijft herkenbaar (bovenste driekwart nagenoeg ongemoeid),
   de onderste leeszone mengt geleidelijk naar de tenantkleur zodat de
   postertekst (title/pills) er goed op leest EN de organisatie zichtbaar
   "eigenaar" van het beeld blijft, zonder de 1c-paarse artwork letterlijk
   te kopiëren. */
.buyer-shell__scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(
        180deg,
        rgba(10, 10, 16, 0.15) 0%,
        rgba(10, 10, 16, 0.25) 45%,
        color-mix(in srgb, var(--hero-bg, var(--brand)) 60%, #0a0a10) 100%
    );
}

/* Geen geüploade headerafbeelding: ontworpen donker posterpaneel i.p.v.
   een verzonnen afbeelding - tenantkleur nu een volwaardig onderdeel van
   het basisverloop (punt 7: "sterker functioneren als event-identiteit"),
   niet langer alleen een kleine hoek-gloed. */
.buyer-shell__visual--fallback {
    position: absolute;
    inset: 0;
    background: linear-gradient(
        165deg,
        color-mix(in srgb, var(--hero-bg, var(--brand)) 45%, #14141c) 0%,
        #101014 55%,
        #0a0a10 100%
    );
}

.buyer-shell__glow {
    position: absolute;
    top: -15%;
    right: -15%;
    width: 65%;
    aspect-ratio: 1;
    border-radius: 50%;
    background: radial-gradient(circle, var(--hero-bg, var(--brand)) 0%, transparent 72%);
    opacity: 0.6;
    pointer-events: none;
}

.buyer-shell__body {
    position: relative;
    height: 100%;
    box-sizing: border-box;
    padding: 28px 24px;
    display: flex;
    flex-direction: column;
}

.buyer-shell__spacer {
    flex: 1 0 auto;
}

/* 1c poster/viewport correction (punt 4A/4B/4C): echte posterhiërarchie -
   compacte datum-eyebrow, grote krachtige titel, metadata-pills. Geen
   tenantidentiteit/logo meer hier (USER DECISION, punt 2). */
.buyer-shell__eyebrow {
    display: inline-block;
    font-size: 0.85rem;
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 10px;
}

.buyer-shell__title {
    color: #ffffff;
    margin: 0 0 14px;
    font-size: clamp(2.1rem, 5vw, 3.4rem);
    line-height: 1.05;
    letter-spacing: -0.03em;
    font-weight: 800;
    text-wrap: balance;
}

.buyer-shell__pills {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.buyer-shell__pill {
    display: inline-block;
    padding: 5px 12px;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.14);
    backdrop-filter: blur(6px);
    font-size: 0.76rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    color: rgba(255, 255, 255, 0.95);
}

/* "Praktisch" - onderdeel van hetzelfde posterpaneel (geen losse witte
   kaart eronder met een zichtbaar gat ertussen): lichte tekst direct op
   het verloop, beperkte tekstbreedte voor leesbaarheid, geen eigen
   "Praktisch"-kop meer (die maakte het weer een aparte sectie i.p.v.
   poster-detailtekst) - .card wordt hier volledig gestript.
   Practical-info poster hotfix: deze sectie is een FLEX-SIBLING van
   .buyer-shell__frame (dat de afbeelding/scrim draagt) - had zelf geen
   achtergrond, dus liet de lichte pagina-achtergrond erdoorheen zien.
   De lichte tekst (.card hieronder, rgba(255,255,255,...)) werd daardoor
   nagenoeg onleesbaar tegen die lichte achtergrond, en zat bovendien
   zonder enige top-padding direct tegen de rand van .buyer-shell__frame
   én (op desktop) tegen de harde overflow:hidden-viewportgrens aan - dat
   is de gerapporteerde "verschijnt tegen/buiten de onderste
   viewportgrens"-bug. Eigen achtergrond hier (dezelfde donkere/tenant-
   getinte toon als de onderkant van .buyer-shell__scrim/--fallback)
   laat deze sectie ogen als een naadloos vervolg van het posterpaneel
   i.p.v. een aparte, onzichtbare zone; padding rondom geeft de tekst
   nu echte ademruimte boven de viewport-onderrand. */
/* Full-width hotfix: max-width hoorde niet op DIT element - dat draagt
   de achtergrond, en een max-width hier liet die achtergrond zelf
   krimpen tot tekstbreedte, met een zichtbare lichte/witte strook
   ernaast binnen de linkerhelft (screenshotbevinding "wit vlak rechts
   van de praktische info"). Achtergrond loopt nu de volle breedte van
   het posterpaneel door tot aan de splitlijn met de commercekolom; de
   leesbare tekstbreedte wordt hieronder uitsluitend op de BINNENSTE
   .card gezet. */
.buyer-shell__practical {
    position: relative;
    width: 100%;
    padding: 20px 24px 28px;
    background: color-mix(in srgb, var(--hero-bg, var(--brand)) 55%, #0a0a10);
}

.buyer-shell__practical .card {
    box-shadow: none;
    background: transparent;
    border: none;
    padding: 0;
    margin: 0;
    max-width: 420px;
    color: rgba(255, 255, 255, 0.78);
    font-size: 0.85rem;
    line-height: 1.5;
}

.buyer-shell__practical .card h2 {
    display: none;
}

.buyer-shell__practical .card p {
    margin: 0 0 0.4em;
}

.buyer-shell__practical .card strong {
    color: rgba(255, 255, 255, 0.95);
}

.buyer-shell__right {
    min-width: 0;
}

/* PERSONALIZATION CLAIM 1c ALIGNMENT: begrenst de personalisatie-
   claimpagina (ShareClaimController) tot een leesbare, rustige
   contentbreedte binnen .buyer-shell__right, i.p.v. de volledige
   (mogelijk zeer brede, op een groot scherm) rechterkolom - alleen een
   MAX-breedte, dus krimpt vanzelf gewoon mee op smallere kolommen/
   viewports (geen extra media query nodig). */
.claim-page {
    max-width: 600px;
}

/* PERSONALIZATION CLAIM 1c ALIGNMENT (mobiel, 44px-aanraakdoel): het
   platformbrede .button (padding: 11px 22px) meet ~43.5px hoog - net
   onder de gevraagde minimale CTA-hoogte. Scoped tot deze pagina i.p.v.
   het platformbrede .button-component aan te passen (zou elke knop op
   het platform raken, ver buiten de scope van deze microfix). */
.claim-page form button[type="submit"] {
    padding: 13px 28px;
}

/* FASE E6G.2 - actierij op de claim-/wijzigpagina: primaire actie
   (opslaan) en secundaire knop "Ticket bekijken" naast elkaar, even hoog;
   op mobiel onder elkaar over de volle breedte. */
.claim-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-top: 16px;
}

.claim-page .claim-actions .button {
    padding: 13px 28px;
}

@media (max-width: 640px) {
    .claim-actions .button {
        flex: 1 1 100%;
        text-align: center;
    }
}

/* BUYER SHELL FINAL LAYOUT POLISH: gedeeld "stack"-patroon voor de
   rechter 1c-kolom (order-overview/claimpagina/ticket-bewerken - de 3
   pagina's die EventStorefrontController::renderBuyerCheckoutShell()'s
   nieuwe $includeFooter meegeven) - LOST 2 dingen tegelijk op met 1
   architectuur i.p.v. losse ad-hoc marges:
   1. inconsistente/ontbrekende ruimte tussen zelfstandige secties
      (klantmelding: ".ticket-grid" heeft zelf geen margin-bottom, dus
      raakte de eropvolgende "Alle tickets delen"-kaart die vrijwel
      direct aan - .card's eigen margin-bottom werkte daar niet, want
      een grid-CONTAINER draagt geen kaart-marge over) - nu regelt 1
      "gap" ALLE ruimte tussen top-level secties (kaarten, de
      tickets-grid, de kop, de nieuwe voettekst) uniform, ongeacht of
      zo'n sectie zelf een margin-bottom heeft.
   2. BUYER RIGHT-COLUMN FOOTER CORRECTION: de rechterkolom-voettekst
      (View::renderBuyerFooter()) moet op desktop ALTIJD zichtbaar
      blijven, ook bij lange inhoud (niet pas na volledig doorscrollen) -
      dit .page-inner-blok hierbeneden zit sinds deze ronde niet meer
      in dezelfde flex-kolom als de voettekst: het is nu genest in een
      APARTE scroll-wrapper (.buyer-shell__scroll hieronder), en de
      voettekst is daar een aparte, niet-scrollende sibling van (zie
      EventStorefrontController::renderBuyerCheckoutShell() en de
      .buyer-shell__scroll/.buyer-shell__right > .site-footer-regels
      verderop) - dit blok regelt dus nog uitsluitend de ONDERLINGE
      ruimte tussen secties BINNEN de scrollende inhoud zelf.
   ">*{margin-bottom:0}" neutraliseert bewust ALLEEN de DIRECTE kinderen
   van deze specifieke kolom (bijv. .card's eigen margin-bottom:20px) -
   geneste kaarten (zoals de losse ticketkaarten IN .ticket-grid) zijn
   geen directe kinderen hiervan en behouden hun eigen, al bestaande
   grid-gap-regeling (.ticket-grid{gap:20px}) volledig ongewijzigd. */
.buyer-shell__scroll .page-inner {
    display: flex;
    flex-direction: column;
    gap: 20px;
    padding-bottom: 24px;
    box-sizing: border-box;
}

.buyer-shell__scroll .page-inner > * {
    margin-bottom: 0;
}

@media (min-width: 768px) {
    .buyer-shell {
        flex-direction: row;
        align-items: stretch;
    }

    .buyer-shell__context {
        flex: 0 0 42%;
        max-width: 560px;
    }

    .buyer-shell__frame {
        aspect-ratio: auto;
        flex: 1 1 auto;
        min-height: 240px;
    }

    .buyer-shell__right {
        flex: 1 1 0;
    }
}

@media (min-width: 1024px) {
    .buyer-shell__context {
        flex-basis: 40%;
        max-width: 620px;
    }
}

/* 1c poster/viewport correction (punt 1 + 3, USER DECISION): op desktop
   gebruikt de volledige buyer-checkoutshell (View::render()'s
   $hideHeaderPill zet ook deze bodyklasse - zie View.php) minimaal de
   volledige viewporthoogte, zonder de normale sitevoettekst en zonder
   .page's platformbrede max-width:1600px (die op een breder scherm dan
   1600px een symmetrische witte strook links ÉN rechts van de shell gaf -
   de screenshotbevinding "witte strook links"). Alleen deze 3 pagina's
   (stap 1-4) krijgen dit; ticketshop-hoofdpagina/e-ticket/bestelstatus
   behouden hun gewone voettekst/maximale breedte ongewijzigd. Rechts
   scrollt zelf intern (.buyer-shell__right) zodra de checkoutinhoud
   langer is dan het scherm; links blijft daardoor volledig stabiel -
   geen position:sticky-uitschakel-edge-case meer nodig. Mobiel (<768px):
   bewust NIET gescoped - gewone documentflow/voettekst blijven daar
   ongewijzigd (sectie 11 van de opdracht). */
@media (min-width: 768px) {
    body.buyer-checkout-shell .page--full {
        max-width: none;
    }

    body.buyer-checkout-shell main.page {
        height: 100vh;
        overflow: hidden;
        padding-bottom: 0;
    }

    /* BUYER SHELL FINAL LAYOUT POLISH bugfix (live gemeten): was een
       gewone afstammeling-selector ("body.buyer-checkout-shell
       .site-footer"), die ELKE .site-footer binnen deze body raakte -
       ook de NIEUWE, bewust rechterkolom-ingebedde voettekst
       (View::renderBuyerFooter()) werd daardoor onbedoeld óók verborgen
       (gemeten: getBoundingClientRect() 0x0). De rechtstreekse-kind-
       combinator (">") hieronder raakt uitsluitend de KLASSIEKE,
       pagina-brede voettekst (die letterlijk een direct kind van
       <body> is, zie View::render()'s HTML) - checkout (dat nog
       steeds de klassieke voettekst rendert, nooit de ingebedde
       variant) blijft dus exact hetzelfde verborgen gedrag houden;
       de nieuwe ingebedde voettekst (genest in .buyer-shell__right,
       dus geen direct kind van body) wordt door deze regel niet meer
       geraakt. */
    body.buyer-checkout-shell > .site-footer {
        display: none;
    }

    body.buyer-checkout-shell .buyer-shell {
        height: 100%;
    }

    body.buyer-checkout-shell .buyer-shell__context {
        height: 100%;
        overflow-y: auto;
    }

    /* BUYER RIGHT-COLUMN FOOTER CORRECTION: .buyer-shell__right was
       hiervoor ZELF de scrollcontainer (height:100%;overflow-y:auto) -
       dat betekende dat een voettekst die ERIN zat pas zichtbaar werd
       na volledig doorscrollen (klantmelding: "gebruiker ziet hem pas
       wanneer hij helemaal naar beneden scrollt"). .buyer-shell__right
       wordt nu zelf een flex-kolom van 2 mogelijke kinderen:
       .buyer-shell__scroll (de ENIGE scrollende zone, flex:1 zodat die
       alle overgebleven ruimte opvult) en, indien aanwezig, de
       voettekst zelf als vaste, NIET-scrollende sibling daaronder
       (flex:0 0 auto - blijft dus altijd op zijn eigen, volledige
       hoogte staan, nooit ingekrompen). Voor checkout (geen voettekst-
       sibling, $includeFooter=false) is dit gedragsneutraal: de ene
       overgebleven .buyer-shell__scroll krijgt via flex:1 gewoon weer
       de volle 100% hoogte, identiek aan het oude, rechtstreeks op
       .buyer-shell__right gezette height:100%;overflow-y:auto. Geen
       gap hier tussen scroll-zone en voettekst (bewust, USER DECISION
       "strak aansluiten") - .site-footer's eigen margin-top wordt
       hieronder naar 0 gezet zodat er geen zichtbare naad ontstaat;
       links/rechts/onder sluit de voettekst vanzelf gelijk met
       .buyer-shell__right's eigen randen (geen padding op dat niveau,
       de voettekst is een rechtstreeks flex-kind, geen kaart met eigen
       marge). */
    body.buyer-checkout-shell .buyer-shell__right {
        height: 100%;
        display: flex;
        flex-direction: column;
    }

    body.buyer-checkout-shell .buyer-shell__scroll {
        flex: 1 1 auto;
        min-height: 0;
        overflow-y: auto;
    }

    body.buyer-checkout-shell .buyer-shell__right > .site-footer {
        flex: 0 0 auto;
        margin-top: 0;
    }
}

/* Tickettype-keuze (hoofdstuk 4.5, collage "05 Ticketshop") - losse
   kaart-rijen i.p.v. een <table class="data-table">: die klasse wordt
   platformbreed hergebruikt in de admin-overzichten, dus hier een eigen
   set klassen i.p.v. daaraan te sleutelen. */
.ticket-select-heading {
    margin: 0 0 4px;
}

/* UI-1 (public/buyer redesign, mockup 1c): korte feitelijke subkop
   ("3 tickettypes") onder de titel. */
.ticket-select-subheading {
    color: var(--muted);
    font-size: 0.9rem;
    margin: 0 0 14px;
}

.ticket-select-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-bottom: 20px;
}

/* Groep tickettypes van 1 (sub)evenement (klantverzoek 2026-08-06) -
   alleen toegepast als er meerdere groepen op de pagina staan
   (EventStorefrontController::renderGroup(), bijv. een hoofdevenement met
   meerdere voorstellingsdagen): dan moet de bezoeker onmiskenbaar zien
   voor welke dag hij tickets kiest. Bij één los evenement (de meeste
   gevallen) blijft dit ongewijzigd - .event-group zonder modifier heeft
   geen eigen opmaak.
   1c full-journey shell correction (punt 6): was een eigen omlijnde/
   gevulde kaart (kaart-in-kaart met de ticketrijen erin, expliciet
   afgekeurd in de screenshotreview) - nu een lichte sectiescheiding
   (dunne onderrand) binnen ÉÉN doorlopend commercevlak, hiërarchie via
   ruimte/rand i.p.v. een eigen achtergrond/omkadering. De ticketrijen
   zelf (.ticket-select-row) blijven de "objecten" met hun eigen
   kaartuitstraling. */
.event-group--bordered {
    padding-bottom: 4px;
    margin-bottom: 24px;
    border-bottom: 1px solid var(--border);
}

.event-group--bordered:last-child {
    border-bottom: none;
}

.event-group__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 14px;
}

.event-group__header h3 {
    margin: 0;
}

/* 1c full-journey shell correction (punt 5, corrigeert de vorige ronde):
   een datumlabel in de RECHTER commercezijde is geen tenant-brandingoppervlak
   alleen omdat het eventdata bevat - de screenshotreview wees dit expliciet
   aan als "bordeauxrode/tenantkleurige datumlabel rechts". Neutraal
   (ink-op-lichte-achtergrond) i.p.v. var(--brand): tenantkleur hoort links,
   in .buyer-shell__context. */
.event-group__date-badge {
    display: inline-flex;
    align-items: center;
    padding: 5px 14px;
    border-radius: var(--radius-pill);
    background: var(--surface-alt);
    color: var(--ink);
    font-size: 0.82rem;
    font-weight: 700;
    white-space: nowrap;
}

.ticket-select-row {
    display: flex;
    flex-direction: column;
    gap: 10px;
    background: rgba(255, 255, 255, 0.82);
    border: 1px solid rgba(255, 255, 255, 0.9);
    border-radius: var(--radius-panel);
    box-shadow: var(--shadow-card);
    padding: 18px 22px;
}

/* 1c poster/viewport correction (punt 9): naam + prijs als duidelijke
   bovenste rij (i.p.v. prijs los naast een info-kolom). */
.ticket-select-row__top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 14px;
}

.ticket-select-row__name {
    font-size: 1.05rem;
    font-weight: 800;
}

.ticket-select-row__description {
    font-size: 0.88rem;
    color: var(--muted);
    margin-top: -4px;
}

.ticket-select-row__price {
    flex-shrink: 0;
    font-size: 1.1rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    white-space: nowrap;
}

.ticket-select-row__divider {
    height: 1px;
    background: var(--border);
}

.ticket-select-row__bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 14px;
}

.ticket-select-row__availability {
    flex: 1;
    min-width: 0;
}

.ticket-select-row__action {
    flex-shrink: 0;
}

/* 1c-alignment: visuele statussen op de rij zelf (EventStorefrontController::
   renderTicketTypeRow()) - geen van deze wijzigt wat de rij kan/mag,
   puur presentatie boven de al bestaande status. */
.ticket-select-row--disabled {
    background: rgba(255, 255, 255, 0.5);
    border-style: dashed;
    box-shadow: none;
    opacity: 0.72;
}

.ticket-select-row--low-stock {
    border-color: var(--accent);
}

/* Platform-interactietaal (geen tenantkleur) voor "geselecteerd" - zelfde
   principe als --brand-interactive elders (VF-1): een gekozen aantal is
   een interactieve koperskeuze, geen tenant-identiteitsmoment. */
.ticket-select-row--selected {
    border-color: var(--brand-interactive, var(--brand));
    box-shadow: 0 0 0 1px var(--brand-interactive, var(--brand)), var(--shadow-card);
}

/* ---------------------------------------------------------------------
   1c-alignment (Decision 2): dagtabs boven de ticketkeuze.
   --------------------------------------------------------------------- */
.day-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 16px;
    overflow-x: auto;
}

.day-tabs__item {
    flex: none;
    padding: 10px 18px;
    min-height: 44px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--ink);
    font-weight: 700;
    font-size: 0.88rem;
    cursor: pointer;
    white-space: nowrap;
}

/* Platform-interactietaal (Decision 7): de actieve dagtab is een
   interactieve controlestatus, geen tenant-identiteitselement - altijd
   Eticketskopen-paars, ongeacht --brand. */
.day-tabs__item--active {
    background: var(--brand-interactive, var(--brand));
    border-color: var(--brand-interactive, var(--brand));
    color: #ffffff;
}

.day-tabs__item:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* ---------------------------------------------------------------------
   Kaart - voor formulieren (inloggen, 2FA, instellingen)
   --------------------------------------------------------------------- */

.card {
    background: rgba(255, 255, 255, 0.82);
    border: 1px solid rgba(255, 255, 255, 0.9);
    border-radius: var(--radius-panel);
    box-shadow: var(--shadow-card);
    padding: 28px 24px;
    margin-bottom: 20px;
}

/* Ruimte na een kaart geldt ook als er geen tweede kaart op volgt (bijv.
   een los verzendknop-element direct na een kaart) - margin-bottom op de
   kaart zelf i.p.v. een aangrenzende-kaart-selector, zodat dit nooit
   per ongeluk 0 wordt. */
.card:last-child {
    margin-bottom: 0;
}

/* Meerdere kaarten van sterk uiteenlopende hoogte naast elkaar
   (bijv. het grote evenementgegevens-formulier naast de kleine
   Deurverkoop-kaart) - CSS-kolommen i.p.v. CSS Grid, want Grid rekt de
   hele rij op naar de hoogste kaart erin (lege witruimte naast korte
   kaarten); kolommen laten elke kaart z'n eigen hoogte houden en vullen
   vanzelf top-naar-onder, dan door naar de volgende kolom. */
.card-columns {
    column-gap: 20px;
    column-count: 1;
}

@media (min-width: 700px) {
    .card-columns {
        column-count: 2;
    }
}

@media (min-width: 900px) {
    .card-columns {
        column-count: 3;
    }
}

/* Klantdetailpagina (admin, klantbeslissing 2026-08-06): hier blijft het
   op 2 kolommen staan, ook op brede schermen - bij 3 kolommen viel de
   (nu langere) Facturatie-kaart uit de pas met de kortere kaarten
   ernaast. */
.card-columns--max2 {
    column-count: 1;
}

@media (min-width: 700px) {
    .card-columns--max2 {
        column-count: 2;
    }
}

.card-columns > .card {
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
    display: inline-block;
    width: 100%;
}

/* Bovenste rij op de Gegevens-tab (klantverzoek 2026-08-13): "Algemeen"
   moet altijd de eerste 2 kolommen beslaan en de subevenementenkaart
   altijd de 3e - dat kan de .card-columns-masonry hierboven niet
   garanderen (die vult puur op volgorde/hoogte), vandaar een aparte,
   echte CSS-grid. Op smalle schermen gewoon 1 kolom (allebei vol-breed
   onder elkaar), pas vanaf 900px de 3-koloms indeling. */
.gegevens-top-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
    margin-bottom: 20px;
}

@media (min-width: 900px) {
    .gegevens-top-grid {
        grid-template-columns: repeat(3, 1fr);
    }

    .gegevens-top-grid__algemeen {
        grid-column: span 2;
    }
}

/* Aanmaakformulier achter een knop i.p.v. altijd uitgeklapt (klantverzoek
   2026-08-13, tickettypes-tab) - bewust <details>/<summary> i.p.v. een
   los JS-toggle: zit binnen 1 tab-paneel-<div>, dus onaangeraakt door
   renderTabDockScript() (die bij elke tab-wissel `display` opnieuw zet
   op ALLE elementen met hetzelfde data-tab-panel - een los getoggeld
   2e element zou daardoor steeds terugklappen naar zichtbaar). */
.details-toggle summary.button {
    list-style: none;
    cursor: pointer;
    width: fit-content;
}

.details-toggle summary.button::-webkit-details-marker {
    display: none;
}

.details-toggle summary.button::marker {
    content: '';
}

.details-toggle__body {
    margin-top: 16px;
}

/* Factuurdetail (admin): vaste 1/3-2/3 verdeling i.p.v. de vloeiende
   card-columns-masonry - hier moet de samenvattingskaart altijd smal
   links staan en de specificatietabel breed rechts. */
.split-columns {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
    align-items: start;
}

@media (min-width: 900px) {
    .split-columns {
        grid-template-columns: 1fr 2fr;
    }
}

/* VF-1g-followup (Part 3, USER DECISION: de tips-kaart mag de tickets/
   order niet meer visueel domineren) - verving voorheen een dominante
   tenantmerkkleur-achtergrond (.two-col-cards naast de deel-link-kaart,
   hier verwijderd - werd na deze hercompositie nergens anders meer
   gebruikt). Nu een rustige, secundaire kaart onderaan de pagina: eigen
   lichte achtergrond, kleinere kop/tekst, geen kleur meer die met de
   organisatiehuisstijl kan botsen. */
.entry-tips-card {
    background: var(--surface-alt);
    box-shadow: none;
}

.entry-tips-card h2 {
    font-size: 1.05rem;
}

.entry-tips-card ul {
    color: var(--muted);
    font-size: 0.88rem;
    margin: 0;
}

.entry-tips-card li {
    margin-bottom: 0.4em;
}

/* BUYER SHELL FINAL LAYOUT POLISH: de losse extra margin-top hier
   (voorheen 40px, klantverzoek 2026-08-09) is vervallen - de scrollende
   inhoud van de rechter 1c-kolom (.buyer-shell__scroll .page-inner
   hieronder) regelt de verticale ruimte tussen ALLE zelfstandige
   secties nu uniform via 1 gap-waarde, precies om te voorkomen dat één
   toevallig element (hier: deze kop) een eigen, dubbel-optellende
   marge zou hebben bovenop die gap - exact de "dubbele/overdreven
   marge"-klacht die een eerdere ronde al oploste. */
.tickets-section-heading {
    margin-top: 0;
}

/* Tickets in een echte grid i.p.v. .card-columns (CSS-multicolumn)
   hierboven - "balance" liet de kaarten bij ongelijke hoogtes soms
   allemaal in kolom 1 vallen, zichtbaar als "geen 3 kolommen op desktop"
   (klantmelding 2026-08-09). Zelfde breedte-drempels als .card-columns
   (700px/900px) voor visuele consistentie met de rest van het platform.
   .event-grid (hoofdticketshop van een klant, klantverzoek 2026-08-20)
   deelt dezelfde regels - zelfde "niet netjes uitgelijnd"-klacht.
   align-items: stretch (i.p.v. start, klantverzoek 2026-08-20) - de
   tickets in een bestelling (OrderStatusController::renderTicketRow())
   hebben ongelijke inhoud (wel/niet gepersonaliseerd, wel/geen
   bestaande deel-link erbij), waardoor de kaarten in dezelfde rij
   zonder stretch ongelijk hoog oogden. */
.ticket-grid,
.event-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
    align-items: stretch;
}

/* Bugfix (klantmelding 2026-08-20): .card:last-child { margin-bottom:0 }
   hierboven geldt maar voor de LAATSTE kaart van de hele grid (DOM-volgorde),
   niet per rij - bij bijv. 5 kaarten in 3 kolommen (rij van 3 + rij van 2)
   kreeg alleen kaart 5 geen margin-bottom, waardoor die zichtbaar hoger
   oogde dan kaart 4 ernaast, ondanks align-items:stretch (die maakt de
   GRID CELL gelijk, de marge erbinnen at nog steeds ongelijk zichtbare
   ruimte weg). .gap hierboven regelt de tussenruimte al, dus de
   kaart-marge kan hierbinnen gewoon altijd 0 zijn. */
.ticket-grid > .card,
.event-grid > .card {
    margin-bottom: 0;
}

@media (min-width: 700px) {
    .ticket-grid,
    .event-grid {
        grid-template-columns: 1fr 1fr;
    }
}

@media (min-width: 900px) {
    .ticket-grid,
    .event-grid {
        grid-template-columns: 1fr 1fr 1fr;
    }
}

/* VF-1g-followup bugfix (live gemeten, 1024px): .ticket-grid's kolomaantal
   hierboven is VIEWPORT-breedte-gekeyed (700/900px), wat prima werkte
   zolang de grid altijd de volle .page-breedte kreeg. Nu 'm ook binnen
   OrderStatusController::renderOrderManagement() in de smallere
   1c-rechterkolom (.buyer-shell__right, ~40-58% van de viewport) kan
   verschijnen, forceerde "viewport >= 900px" nog steeds 3 vaste kolommen
   terwijl er in de praktijk maar ~550px beschikbaar was - 1fr-tracks
   krimpen niet onder hun min-content-breedte, dus de 3e kolom liep buiten
   de kaart (gemeten: kaartbreedte ~250px x3 + gaps > beschikbare 550px).
   auto-fill/minmax hier i.p.v. de vaste kolomtelling: het aantal kolommen
   volgt de WERKELIJK beschikbare breedte van de kolom zelf, ongeacht de
   viewport eromheen - lost het op zonder de bestaande, elders nog steeds
   volle-breedte .ticket-grid/.event-grid-regels hierboven aan te raken. */
@media (min-width: 700px) {
    .buyer-shell__right .ticket-grid {
        grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    }
}

/* BUYER FOOTER + TENANT OVERVIEW ALIGNMENT: zelfde overloopbug/fix als
   hierboven (.buyer-shell__right .ticket-grid) - .event-grid deelt
   dezelfde viewport-breedte-gekeyde 700/900px-regels. Sinds TENANT
   OVERVIEW TRUE 1c SHELL PARITY hergebruikt de tenant-overzichtspagina
   de ECHTE .buyer-shell__right (was .tenant-shell__events, verwijderd),
   dus dezelfde selector als de ticket-grid-fix hierboven volstaat nu -
   geen aparte tenant-specifieke selector meer nodig. */
@media (min-width: 700px) {
    .buyer-shell__right .event-grid {
        grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    }
}

/* BUYER FOOTER + TENANT OVERVIEW ALIGNMENT (Part B4, live gemeten via
   DOM-simulatie): bij precies 1 evenement liet de auto-fill-regel
   hierboven die ene kaart op zijn kleinste breedte in de linkerbovenhoek
   staan, met de rest van de rechterkolom leeg - "niet één klein cardje
   [...] in een enorme lege rechterkolom" (USER DECISION). Puur
   presentationeel: dezelfde kaart, ruimer en gecentreerd i.p.v. een
   nieuwe/andere kaartcomponent. */
.event-grid--single {
    display: flex;
    justify-content: center;
}

.event-grid--single .event-card {
    width: 100%;
    max-width: 480px;
}

/* Evenementkaart op de hoofdticketshop van een klant (klantverzoek
   2026-08-20) - de afbeelding bleedt tot de kaartranden (negatieve
   marge t.o.v. .card's eigen padding) en staat boven de titel. */
.event-card__image {
    display: block;
    width: calc(100% + 48px);
    aspect-ratio: 16 / 9;
    object-fit: cover;
    margin: -28px -24px 16px;
    border-radius: var(--radius-panel) var(--radius-panel) 0 0;
}

/* UI-1 (public/buyer redesign, mockup 1c): eventkaart op de tenant-
   storefront - flex-column zodat de CTA-knop onderaan uitlijnt ongeacht
   hoeveel regels titel/datum/locatie een kaart heeft (.event-grid
   stretcht de kaarten al gelijk hoog, zie de toelichting daar). */
.event-card {
    display: flex;
    flex-direction: column;
    /* VF-1: zelfde dunne merkkleur-accent bovenaan als de organizer-
       statcards (UI-2) - kleine, herkenbare identiteitstoets i.p.v. een
       vlak wit kaartje, zonder de kaart zelf te domineren. */
    box-shadow: var(--shadow-card), inset 0 3px 0 var(--brand);
}

/* ---------------------------------------------------------------------
   TENANT OVERVIEW TRUE 1c SHELL PARITY: publieke tenant-overzichtspagina
   (TenantHomeController) - hergebruikt sinds deze ronde de ECHTE
   buyer-shell-primitives (.buyer-shell/.buyer-shell__context/
   .buyer-shell__right/.buyer-shell__scroll, dezelfde CSS als checkout/
   order-overview/claim/ticket-bewerken - geen eigen .tenant-shell-kopie
   meer, die gaf wél eenzelfde OOGopslag maar niet de daadwerkelijke
   volle-viewporthoogte/alleen-rechts-scrollt-mechaniek, vandaar de
   gerapporteerde afwijking t.o.v. de goedgekeurde 1c-ticketshop).
   .tenant-identity-panel hieronder is uitsluitend de INHOUD die binnen
   .buyer-shell__context wordt geplaatst (net zoals .buyer-shell__frame
   dat voor de eventposter doet) - zelfde "donker verloop + tenantkleur-
   accentgloed"-taal als de eventposter-fallback (EventStorefrontController::
   renderBuyerContextPanel()), met TENANT-brede i.p.v. eventspecifieke
   inhoud. min-height:100% vult de kolom pas op desktop (waar
   .buyer-shell__context een expliciete hoogte krijgt, zie de bestaande
   body.buyer-checkout-shell-regels) - op mobiel is dit vanzelf een
   no-op (compacter paneel, gewone documentflow, sectie 7/opdracht).
   --------------------------------------------------------------------- */
.tenant-identity-panel {
    position: relative;
    overflow: hidden;
    min-height: 100%;
    box-sizing: border-box;
    background: linear-gradient(160deg, #1c1c28 0%, #101014 60%, #101014 100%);
    padding: 48px 24px;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.tenant-identity-panel__glow {
    position: absolute;
    top: -25%;
    right: -10%;
    width: 55%;
    aspect-ratio: 1;
    border-radius: 50%;
    background: radial-gradient(circle, var(--brand) 0%, transparent 72%);
    opacity: 0.55;
    pointer-events: none;
}

.tenant-identity-panel__content {
    position: relative;
}

.tenant-identity-panel__eyebrow {
    display: inline-block;
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 12px;
}

.tenant-identity-panel__title {
    color: #ffffff;
    margin: 0 0 10px;
    font-size: clamp(2rem, 5vw, 3rem);
    line-height: 1.1;
}

.tenant-identity-panel__meta {
    color: rgba(255, 255, 255, 0.8);
    font-weight: 600;
    margin: 0;
}

@media (min-width: 900px) {
    .tenant-identity-panel {
        padding: 64px 48px;
    }
}

.event-card__body {
    display: flex;
    flex-direction: column;
    flex: 1;
}

.event-card__title {
    font-size: 1.15rem;
    margin-bottom: 4px;
}

.event-card__title a {
    color: var(--brand-dark);
    text-decoration: none;
}

.event-card__title a:hover {
    text-decoration: underline;
}

.event-card__date {
    font-weight: 700;
    color: var(--brand);
    font-size: 0.88rem;
    margin: 0 0 2px;
}

.event-card__location {
    color: var(--muted);
    font-size: 0.88rem;
    margin: 0 0 16px;
}

.event-card__cta {
    margin-top: auto;
    align-self: flex-start;
}

/* ---------------------------------------------------------------------
   Dashboard-hoofdscherm: stat-cards + aankomende-evenementenlijst
   (platform-restyling, dashboard-content-ronde)
   --------------------------------------------------------------------- */

.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 16px;
    margin-bottom: 20px;
}

.stat-card {
    display: flex;
    flex-direction: column;
    gap: 4px;
    background: rgba(255, 255, 255, 0.82);
    border: 1px solid rgba(255, 255, 255, 0.9);
    /* UI-2 (organizer + login redesign, mockup 2b): dunne merkkleur-
       accent bovenaan - "belangrijkste cijfers eerst" iets sterker laten
       opvallen tussen de rest van de kaarten, zonder de kaart zelf
       drukker te maken. box-shadow i.p.v. border-top: telt niet mee in
       de box-hoogte, dus geen padding-aanpassing nodig. Volgt automatisch
       de tenant-merkkleur (var(--brand)), net als alle andere brand-
       gekleurde elementen op dit platform. */
    box-shadow: var(--shadow-card), inset 0 3px 0 var(--brand);
    border-radius: var(--radius-panel);
    padding: 20px 22px;
    text-decoration: none;
    color: inherit;
    transition: border-color 0.15s ease;
}

.stat-card:hover {
    border-color: var(--brand);
}

.stat-card__label {
    font-size: 0.78rem;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.stat-card__value {
    font-size: 1.8rem;
    font-weight: 800;
    color: var(--brand-dark);
    letter-spacing: -0.01em;
}

.stat-card__sub {
    font-size: 0.78rem;
    color: var(--muted);
}

.dashboard-event-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 0;
    border-bottom: 1px solid var(--border);
    text-decoration: none;
    color: inherit;
}

.dashboard-event-row:last-of-type {
    border-bottom: none;
}

.dashboard-event-row__name {
    font-weight: 700;
}

.dashboard-event-row:hover .dashboard-event-row__name {
    color: var(--brand);
}

/* UI-2-responsivefix: op zeer smalle schermen (320px) kon een lange
   datum/tijdrange (bijv. "do 1 juli 2027 - 12:00 - 18:00", zie
   .dashboard-event-row__date se white-space:nowrap) samen met de
   evenementnaam breder worden dan de kaart zelf - een echte document-
   brede horizontale overflow (gevonden tijdens de UI-2 responsive-test,
   niet eerder aanwezig als geïsoleerd probleem). Naam/datum stapelen
   i.p.v. naast elkaar lost dit op zonder de datum zelf te hoeven laten
   afbreken. */
@media (max-width: 480px) {
    .dashboard-event-row {
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
    }
}

.dashboard-event-row__date {
    font-size: 0.85rem;
    color: var(--muted);
    white-space: nowrap;
}

.quick-links {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

/* ---------------------------------------------------------------------
   UI-2 (organizer + login redesign, mockup 4d): split-screen auth-shell
   voor inloggen/2FA/activeren (View::renderAuthShell()) - vervangt de
   kale .page--narrow-kaart. Flexbox i.p.v. grid: .auth-shell__panel
   krijgt `order: -1` om visueel LINKS te staan (desktop) resp. BOVEN
   (mobiel) te komen, terwijl hij in de brondode NA de formulierzijde
   staat - zo blijft de kop-hiërarchie voor schermlezers correct (de
   pagina-<h1> vóór het paneel se <h2>) zonder de visuele volgorde uit
   de mockup op te geven.
   --------------------------------------------------------------------- */

.auth-shell-wrap {
    flex: 1 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 40px 20px 64px;
}

.auth-shell {
    width: 100%;
    max-width: 960px;
    display: flex;
    background: var(--surface);
    border-radius: var(--radius-panel);
    box-shadow: var(--shadow-card);
    overflow: hidden;
}

.auth-shell__form,
.auth-shell__panel {
    flex: 1 1 0;
    min-width: 0;
    padding: 48px 40px;
    box-sizing: border-box;
}

.auth-shell__form {
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.auth-shell__title {
    margin-bottom: 0.3em;
}

/* De aangeleverde inhoud is nog steeds een gewone .card (aanroepers
   wijzigen niet) - hier visueel "uitgekleed" tot een rustige
   formulierzijde zonder dubbele kaart-in-kaart-omranding, want
   .auth-shell zelf is al de kaart. */
.auth-shell__form .card {
    padding: 0;
    margin-bottom: 0;
    background: transparent;
    border: none;
    box-shadow: none;
    border-radius: 0;
}

.auth-shell__panel {
    order: -1;
    background: linear-gradient(160deg, var(--brand-dark) 0%, #1c1c3a 55%, var(--brand) 150%);
    color: #ffffff;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 14px;
}

.auth-shell__eyebrow {
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--accent);
}

.auth-shell__panel h2 {
    color: #ffffff;
    font-size: 1.5rem;
    margin-bottom: 0.3em;
}

.auth-shell__panel p {
    color: rgba(255, 255, 255, 0.8);
    margin-bottom: 0;
}

.auth-shell__points {
    list-style: none;
    padding: 0;
    margin: 6px 0 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.auth-shell__points li {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 0.88rem;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.92);
}

.auth-shell__points li::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: var(--radius-pill);
    background: var(--accent);
    flex: none;
}

/* Mobiel: gestapeld, paneel compacter boven het formulier i.p.v.
   ernaast - puntenlijst weg (klantverzoek: "geen onnodige
   viewporthoogte" op mobiel), tekst gecentreerd omdat er geen tweede
   kolom meer naast staat om links tegenaan te lijnen. */
@media (max-width: 860px) {
    .auth-shell-wrap {
        padding: 0;
        align-items: stretch;
    }

    .auth-shell {
        flex-direction: column;
        max-width: 100%;
        border-radius: 0;
        box-shadow: none;
    }

    .auth-shell__panel {
        padding: 20px 20px;
        text-align: center;
        align-items: center;
        gap: 6px;
    }

    .auth-shell__panel h2 {
        font-size: 1.15rem;
        margin-bottom: 0;
    }

    .auth-shell__panel p,
    .auth-shell__points {
        display: none;
    }

    .auth-shell__form {
        padding: 28px 20px 48px;
    }
}

/* ---------------------------------------------------------------------
   Tabbladen - scan-app-inlogpagina (code vs. account, hoofdstuk 4.7)
   --------------------------------------------------------------------- */

.login-tabs {
    display: flex;
    gap: 8px;
    margin-bottom: 16px;
}

.login-tabs__tab {
    flex: 1;
    padding: 10px 14px;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--surface-alt);
    color: var(--ink);
    font-weight: 600;
    cursor: pointer;
}

.login-tabs__tab--active {
    background: var(--brand);
    color: #ffffff;
    border-color: var(--brand);
}

/* Sticky tabbladen-balk onderin de pagina (klantbeslissing 2026-08-05,
   View::renderTabDock()/renderTabDockScript(), gebruikt door o.a.
   InvoiceController::overview() en EventController::showDetail()) -
   verving het eerdere `.detail-tabs`-patroon (een rij bovenaan de
   pagina, zelfde opmaak als .login-tabs hierboven) volledig, ook op het
   evenement-detailscherm waar het oorspronkelijk voor gebouwd was.
   Zelfde donkere-pil-uiterlijk als de scan-app-tabbalk (.scan-tab-bar),
   maar bewust position:sticky i.p.v. position:fixed. Als gewoon block-element binnen
   .page "plakt" deze aan de onderkant van het scherm tijdens het scrollen
   door de tabinhoud, maar laat hij vanzelf los zodra .page's eigen
   onderkant (net boven de voettekst) in beeld komt - position:fixed zou
   daarentegen altijd over de voettekst heen blijven zweven. */
.tab-dock {
    position: sticky;
    bottom: 16px;
    z-index: 40;
    display: flex;
    justify-content: center;
    /* margin-top: auto (klantbeslissing 2026-08-05) - duwt de balk naar
       de onderkant van .page (nu display:flex/column, zie hierboven) op
       een korte pagina waar de inhoud het scherm niet vult; op een lange
       pagina heeft dit geen effect (geen "over" ruimte om te vullen) en
       doet position:sticky hierboven gewoon zijn werk tijdens het
       scrollen. */
    margin: auto 0 0;
    padding-top: 28px;
    pointer-events: none;
}

.tab-dock__bar {
    display: flex;
    gap: 4px;
    padding: 6px;
    border-radius: 999px;
    background: rgba(16, 16, 22, 0.92);
    box-shadow: 0 12px 30px rgba(16, 16, 40, 0.28);
    max-width: calc(100vw - 24px);
    overflow-x: auto;
    pointer-events: auto;
}

.tab-dock__item {
    display: flex;
    align-items: center;
    white-space: nowrap;
    padding: 10px 16px;
    border-radius: 999px;
    border: none;
    background: transparent;
    color: rgba(255, 255, 255, 0.66);
    font-family: inherit;
    font-weight: 600;
    font-size: 0.85rem;
    cursor: pointer;
}

.tab-dock__item--active {
    background: #ffffff;
    color: #101014;
}

/* ---------------------------------------------------------------------
   Formulieren
   --------------------------------------------------------------------- */

.field {
    margin-bottom: 18px;
}

.field label {
    display: block;
    font-weight: 600;
    font-size: 0.9rem;
    margin-bottom: 6px;
}

/* Los van een formulierveld (bijv. de dashboard-welkomsttekst, een
   SEPA-mandaatstatuszin) - dezelfde gedempte stijl, alleen niet
   genest onder .field. */
.hint {
    display: block;
    font-weight: 400;
    color: var(--muted);
    font-size: 0.82rem;
}

.field .hint {
    margin-top: 4px;
}

/* 2-koloms veldgrid (klantverzoek 2026-08-09, wizard-sub-stappen) - elke
   wizard-sub-stap wrapt zijn zichtbare velden hierin i.p.v. alles onder
   elkaar. Simpele velden (tekst/datum/select) nemen automatisch een halve
   rij in; brede blokken (textarea, afbeeldingsvoorbeelden, radiogroepen
   met een lange hint, de fee-payer-matrix) worden gewrapt in
   .field--full en nemen de volle breedte. renderEventForm() (bewerken/
   nieuw subevenement) gebruikt dit bewust niet - blijft op de bestaande
   enkele kolom. */
.field-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 0 24px;
}

.field--full {
    grid-column: 1 / -1;
}

/* Live voorbeeld bij een upload (headerafbeelding EN losse
   ticketafbeelding, klantverzoek 2026-08-06) - basisverhouding 16:9,
   generiek genoeg voor beide velden. De headerafbeelding-voorbeelden
   hieronder (desktop/mobiel) overschrijven dit met hun eigen,
   hero-accurate verhoudingen via de --hero/--mobile-varianten. */
.header-image-preview {
    width: 100%;
    aspect-ratio: 16 / 9;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--surface-alt);
    border: 1px solid var(--border);
    margin-bottom: 12px;
}

.header-image-preview img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center center;
}

/* Headerafbeelding-voorbeelden - beeldverhoudingen GEMETEN aan de
   huidige ticketshop (.buyer-shell__context, de 1c-splitcompositie):
   desktop 576x900 (staand posterpaneel over de volle schermhoogte),
   mobiel 390x510 (compacte gestapelde band bovenaan).

   Stonden hier eerder op 3.5:1 en 4:3 - de liggende banden van de
   OUDE .event-hero, die bij de herbouw van de koperskant is vervangen.
   Het voorbeeld sneed de foto daardoor precies andersom bij dan de
   echte ticketshop. */
.header-image-preview--hero {
    aspect-ratio: 576 / 900;
    max-width: 300px;
}

.header-image-preview--mobile {
    aspect-ratio: 390 / 510;
    max-width: 210px;
}

/* "Passend"-stand (klantverzoek 2026-08-20): de volledige afbeelding
   blijft zichtbaar i.p.v. bijgesneden te worden - letterboxen op de
   merkkleur van de klant (of een per-evenement afwijkende kleur via
   --hero-bg, zie renderHeaderImagePreviewScript()), zodat dit voorbeeld
   overeenkomt met de daadwerkelijke hero (.event-hero--desktop-contain/
   --mobile-contain hierboven). */
.header-image-preview--contain {
    background: var(--hero-bg, var(--brand));
}

.header-image-preview--contain img {
    object-fit: contain;
}

/* Plattegrond op de Praktisch-kaart (klantverzoek 2026-08-06,
   EventStorefrontController::renderPracticalInfoCard()/TicketViewController::
   renderPracticalInfoSection()) - bewust GEEN object-fit:cover zoals
   .header-image-preview hierboven: een plattegrond mag nooit bijgesneden
   worden, dus altijd de volledige afbeelding tonen op zijn eigen
   hoogte/breedte-verhouding (Uploads::storeMapImage() schaalt al naar
   binnen i.p.v. te croppen). */
.practical-info-map {
    margin-top: 12px;
}

.practical-info-map img {
    display: block;
    max-width: 100%;
    height: auto;
    border-radius: var(--radius);
    border: 1px solid var(--border);
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
select,
textarea {
    display: block;
    width: 100%;
    margin-top: 6px;
    padding: 10px 12px;
    font-size: 1rem;
    font-family: inherit;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

textarea {
    resize: vertical;
}

input[type="text"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="number"]:focus,
select:focus,
textarea:focus {
    outline: none;
    border-color: var(--brand);
    /* UI-0 accessibility fix (Codex-bevinding, P1, vervolg): was eerst
       var(--brand) - maar --brand is tenant-overschrijfbaar (zie de
       toelichting bij --focus-ring in :root), dus daarmee kon de ring
       alsnog onzichtbaar worden bij een lichte tenant-merkkleur.
       --focus-ring is een vaste, niet-overschrijfbare kleur, ruim boven
       de 3:1-eis voor niet-tekstuele focusindicatoren (WCAG 1.4.11) op
       zowel lichte oppervlakken als de donkere schermen (scan-app/pil-
       navigatie). border-color hierboven blijft bewust wel --brand (puur
       stilistisch, geen accessibility-kritieke indicator - de ring
       hieronder is dat wel). */
    box-shadow: 0 0 0 3px var(--focus-ring);
}

/* UI-0 design foundation: per-veld foutstatus - was nog niet
   gedefinieerd (bestaande formulierfouten worden platformbreed als één
   .alert--danger-banner bovenaan het formulier getoond, nooit per veld).
   Puur additieve foundation-CSS voor toekomstig gebruik; wijzigt niets
   aan een bestaand formulier zolang niemand .field--error/.field__error
   toevoegt. */
.field--error input[type="text"],
.field--error input[type="email"],
.field--error input[type="password"],
.field--error input[type="number"],
.field--error select,
.field--error textarea {
    border-color: var(--danger);
}

.field--error input[type="text"]:focus,
.field--error input[type="email"]:focus,
.field--error input[type="password"]:focus,
.field--error input[type="number"]:focus,
.field--error select:focus,
.field--error textarea:focus {
    box-shadow: 0 0 0 3px var(--danger-bg);
}

.field__error {
    display: block;
    margin-top: 4px;
    color: var(--danger);
    font-size: 0.82rem;
    font-weight: 600;
}

/* align-items: flex-start i.p.v. center - bij een lange labeltekst die
   op meerdere regels afbreekt (bijv. de voorwaarden/privacy-checkbox op
   mobiel) drukte center het vinkje verticaal midden tussen alle regels.
   flex-start lijnt het vinkje netjes uit met de EERSTE regel; voor de
   vele kortere, 1-regelige labels elders (checkbox-instellingen) is het
   verschil met center visueel verwaarloosbaar.
   De eigenlijke oorzaak van het "in elkaar gedrukte" uiterlijk
   (klantverzoek 2026-08-09) zat in de HTML, niet in deze regel: met
   display:flex hier wordt ELK direct kind van <label> een eigen flex-
   item. Bij platte tekst met inline links (renderDetailsStep(), "Ik ga
   akkoord met de <a>algemene voorwaarden</a> en de <a>privacy-
   verklaring</a>") werd daardoor niet alleen het vinkje, maar ook ELK
   tekstfragment/losse link een eigen flex-item - die braken dan
   onafhankelijk van elkaar af i.p.v. gewoon als lopende tekst mee te
   wrappen, en de links leken zo in hun "eigen kolom" te staan. De fix
   staat in de HTML: de hele zin (incl. links) in één <span> na het
   vinkje, zodat <label> maar 2 flex-items heeft (vinkje + span) en de
   tekst BINNEN die span gewoon normaal, aaneengesloten kan doorlopen. */
.checkbox-field label {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-weight: 400;
    font-size: 0.92rem;
    line-height: 1.5;
}

.checkbox-field input {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    margin-top: 3px;
}

/* UI-0 design foundation: tint de native selectie-/keuzevakjes naar de
   merkkleur (goed ondersteund in alle huidige browsers, puur cosmetisch -
   geen invloed op afmeting/gedrag) i.p.v. de kale browserstandaard
   (meestal systeemblauw). Platformbreed, niet beperkt tot
   .checkbox-field - er staan ook losse checkboxes/radio's buiten die
   wrapper-klasse (bijv. instellingenpagina's). */
input[type="checkbox"],
input[type="radio"] {
    accent-color: var(--brand);
}

/* ---------------------------------------------------------------------
   Aantal-stepper (hoofdstuk 4.5, ticketkeuze) - +/- knoppen naast het
   aantalveld, progressive enhancement bovenop het gewone number-input
   (dat blijft ook zonder JavaScript gewoon werken).
   --------------------------------------------------------------------- */

.qty-stepper {
    display: flex;
    align-items: center;
    gap: 6px;
}

.qty-stepper input[type="number"] {
    width: 56px;
    flex: none;
    margin: 0;
    padding: 8px 4px;
    text-align: center;
    -moz-appearance: textfield;
}

.qty-stepper input[type="number"]::-webkit-outer-spin-button,
.qty-stepper input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.qty-stepper__btn {
    flex: none;
    /* UI-1 mini-fix (Codex P1): 44x44 minimaal touch-target voor de
       primaire aantal-knoppen (was 32x32) - zelfde iconen/kleuren/
       focus-ring, alleen de klikoppervlakte is vergroot. */
    width: 44px;
    height: 44px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-pill, 999px);
    border: 1px solid var(--border);
    background: var(--surface-alt);
    color: var(--ink);
    font-size: 1.15rem;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
}

.qty-stepper__btn:hover {
    background: var(--brand-light);
}

/* Plus-knop gevuld met de merkkleur i.p.v. dezelfde outline als de
   min-knop (collage) - data-step bestaat al op elke qty-stepper-knop
   in de hele app (checkout, wachtlijst, deurverkoop), dus dit werkt
   overal zonder losse markup-wijziging. */
/* VF-1 (tenant-branding-strategie, contrastcheck): een organisatie mag
   een zeer lichte/near-white --brand kiezen (getest) - zonder verdere
   maatregel wordt de witte "+" dan onleesbaar tegen een bijna
   identiek-lichte vulling. box-shadow (dunne donkere binnenrand, altijd
   zichtbaar ongeacht vulkleur) + text-shadow (houdt het glyph zelf
   afleesbaar) zijn puur defensief - onzichtbaar/verwaarloosbaar bij een
   normale (donkere/verzadigde) merkkleur, maar redden de leesbaarheid
   bij een lichte. Geen wijziging aan vorm/afmeting/functie van de knop. */
.qty-stepper__btn[data-step="1"] {
    background: var(--brand);
    border-color: var(--brand);
    color: #ffffff;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.18);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
}

.qty-stepper__btn[data-step="1"]:hover {
    filter: brightness(0.92);
}

.qty-stepper__btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* 1c-alignment (Decision 7): op koperspagina's (body.buyer-body, zie
   View.php) is de plus-knop platforminteractietaal (Eticketskopen-paars),
   geen tenant-identiteitselement - de basisregel hierboven blijft
   ONGEWIJZIGD tenantkleurig voor de scanner-deurverkoop-qty-stepper, die
   dezelfde .qty-stepper__btn[data-step="1"]-selector hergebruikt en dit
   ronde niet mag veranderen. */
body.buyer-body .qty-stepper__btn[data-step="1"] {
    background: var(--brand-interactive, var(--brand));
    border-color: var(--brand-interactive, var(--brand));
}

/* ---------------------------------------------------------------------
   Stap-indicator (hoofdstuk 4.5, bestelproces) - toont waar de koper
   zich in het bestelproces bevindt.
   --------------------------------------------------------------------- */

.step-indicator {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
    gap: 8px;
    margin-bottom: 24px;
    font-size: 0.82rem;
}

.step-indicator__item {
    display: block;
    width: 100%;
    padding: 8px 6px;
    margin: 0;
    border-radius: var(--radius);
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--muted);
    font: inherit;
    font-weight: 600;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.step-indicator__item--done {
    background: var(--brand-light);
    border-color: var(--brand-light);
    color: var(--brand-dark);
}

.step-indicator__item--active {
    background: var(--brand);
    border-color: var(--brand);
    color: #ffffff;
    /* Zelfde defensieve contrastmaatregel als .qty-stepper__btn[data-step="1"]
       hierboven - blijft afleesbaar bij een zeer lichte tenantkleur. */
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.18);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
}

/* De "done" stap-badges zijn soms een <button> in een eigen <form>
   (renderStepNavForm()) om er rechtstreeks naartoe terug te kunnen
   springen - display:contents op het formulier zorgt dat de knop zelf
   het grid-item blijft, zodat de gelijke kolombreedte van
   .step-indicator intact blijft. */
.step-indicator__form {
    display: contents;
}

button.step-indicator__item {
    cursor: pointer;
}

button.step-indicator__item--done:hover {
    background: var(--brand);
    border-color: var(--brand);
    color: #ffffff;
}

/* 1c full-journey shell correction (punt 5): op de koperscheckout is de
   voortgangsindicator interactieve platformtaal (commercezijde), geen
   tenant-identiteitselement - "checkout progress stap 2+" stond expliciet
   op de controlelijst. .step-indicator zelf wordt ook door de organizer-
   aanmaakwizard hergebruikt (EventController::renderWizardStepIndicator(),
   body.dashboard-body) - die blijft via deze scoping ongewijzigd
   tenantkleurig. */
body.buyer-body .step-indicator__item--active {
    background: var(--brand-interactive, var(--brand));
    border-color: var(--brand-interactive, var(--brand));
}

body.buyer-body button.step-indicator__item--done:hover {
    background: var(--brand-interactive, var(--brand));
    border-color: var(--brand-interactive, var(--brand));
}

/* .step-indicator__num (cirkel met alleen het stapnummer) staat verder
   altijd in de HTML mee (renderStepIndicator()), maar blijft hier
   verborgen - pas in de mobiele media query hieronder wordt hij zichtbaar
   voor niet-actieve stappen. */
.step-indicator__num {
    display: none;
}

/* Compacte stap-indicator op mobiel (klantverzoek 2026-08-07): i.p.v.
   alle stappen voluit naast elkaar (te veel tekst op een smal scherm)
   toont alleen de actieve stap zijn volledige label; de overige stappen
   worden kleine genummerde cirkels - gevuld met de merkkleur zodra ze al
   afgerond zijn, zodat in één oogopslag duidelijk is hoever de koper is. */
@media (max-width: 640px) {
    .step-indicator {
        display: flex;
        align-items: center;
        gap: 8px;
    }

    .step-indicator__item {
        flex: 0 0 auto;
        width: 32px;
        height: 32px;
        padding: 0;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 50%;
    }

    .step-indicator__label {
        display: none;
    }

    .step-indicator__num {
        display: block;
    }

    .step-indicator__item--active {
        flex: 1 1 auto;
        width: auto;
        height: auto;
        padding: 8px 10px;
        border-radius: var(--radius);
    }

    .step-indicator__item--active .step-indicator__num {
        display: none;
    }

    .step-indicator__item--active .step-indicator__label {
        display: block;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
}

/* ---------------------------------------------------------------------
   Wizard-type-tegels (evenement-aanmaakwizard, stap 0) - kies-tegels
   per evenementsoort (EventController::renderWizardTypePicker()).
   --------------------------------------------------------------------- */

.wizard-type-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 16px;
    margin-bottom: 20px;
}

.wizard-type-tile {
    display: block;
    background: rgba(255, 255, 255, 0.82);
    border: 1px solid rgba(255, 255, 255, 0.9);
    border-radius: var(--radius-panel);
    box-shadow: var(--shadow-card);
    padding: 24px 20px;
    text-decoration: none;
    color: inherit;
    transition: border-color 0.15s ease, transform 0.15s ease;
}

.wizard-type-tile:hover {
    border-color: var(--brand);
    transform: translateY(-2px);
}

.wizard-type-tile h3 {
    margin: 0;
    color: var(--brand-dark);
}

.checkout-countdown {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 8px 14px;
    margin-bottom: 16px;
    border-radius: var(--radius);
    background: var(--brand-light);
    color: var(--brand-dark);
    font-size: 0.85rem;
}

.checkout-countdown__label {
    font-weight: 500;
}

.checkout-countdown__time {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------
   Betaalmethode kiezen (hoofdstuk 4.9) - elke optie toont meteen de
   totaalprijs mét eventuele transactiekosten voor die methode.
   --------------------------------------------------------------------- */

.payment-method-option {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px;
    margin-bottom: 8px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
}

.payment-method-option:has(input:checked) {
    border-color: var(--brand);
    background: var(--brand-light);
}

/* 1c full-journey shell correction (punt 5): betaalmethode-/personaliseer-
   nu-of-later-keuze is een commerce-interactie op de koperscheckout, geen
   tenant-identiteitsmoment - --brand-light hierboven is al een vast
   platformtoken (niet tenant-overschrijfbaar), alleen de randkleur volgde
   nog var(--brand). */
body.buyer-body .payment-method-option:has(input:checked) {
    border-color: var(--brand-interactive, var(--brand));
}

.payment-method-option__name {
    flex: 1;
    font-weight: 600;
}

.payment-method-option__total {
    font-weight: 700;
    white-space: nowrap;
}

/* Kleine "?"-badge met een CSS-only tooltip-bubble (klantverzoek
   2026-08-20, "Tickets op naam zetten"-keuze) - geen JS-library nodig,
   :hover/:focus-within volstaan. tabindex="0" op de badge zelf houdt 'm
   ook met toetsenbord/touch bereikbaar (tikken = focus = bubble toont). */
.info-tooltip {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    margin-left: 6px;
    border-radius: 50%;
    background: var(--surface-alt);
    border: 1px solid var(--border);
    color: var(--muted);
    font-size: 0.75rem;
    font-weight: 700;
    cursor: help;
    flex-shrink: 0;
}

.info-tooltip__bubble {
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    width: 240px;
    padding: 10px 12px;
    background: var(--ink);
    color: #ffffff;
    font-size: 0.8rem;
    font-weight: 400;
    line-height: 1.4;
    text-align: left;
    border-radius: var(--radius);
    box-shadow: var(--shadow-card);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.15s ease;
    z-index: 20;
    pointer-events: none;
}

.info-tooltip:hover .info-tooltip__bubble,
.info-tooltip:focus .info-tooltip__bubble,
.info-tooltip:focus-within .info-tooltip__bubble {
    opacity: 1;
    visibility: visible;
}

/* Audit-fix (pre-launch P1, "checkout horizontale overflow op 375px"):
   de badge (bijv. bij "Tickets op naam zetten") zit vaak dicht tegen de
   rechterrand van de checkout-kaart - de bubble hierboven staat via
   left:50%/translateX(-50%) GECENTREERD op die badge, dus overlapt dan
   met de helft van zijn 240px breedte de viewportrand. visibility:hidden
   (i.p.v. display:none) neemt nog wel layoutruimte in, dus dit veroorzaakt
   document-brede horizontale scroll, ook al is de bubble onzichtbaar.
   Aanvankelijk hier op max-width:480px gezet, maar handmatig getest bleek
   de kaart tot 899px nog even fluid/vol-breed te zijn als op mobiel
   (.checkout-layout gaat pas bij min-width:900px hierboven naar de
   2-koloms desktop-indeling met een vaste sidebar-breedte, zie regel
   ~2188) - de overflow trad dus t/m 899px net zo goed op. Zelfde
   breakpoint hergebruikt i.p.v. een nieuwe te verzinnen. Onder die grens
   ankert de bubble daarom aan de RECHTERkant van de badge (groeit naar
   links, waar wel ruimte is) i.p.v. gecentreerd; max-width is een extra
   vangnet. Vanaf 900px (bevestigd getest op 1440px, geen overflow - de
   2-koloms indeling houdt de badge ver van de viewportrand) blijft het
   gecentreerde uiterlijk ongewijzigd. */
@media (max-width: 899px) {
    .info-tooltip__bubble {
        left: auto;
        right: 0;
        transform: none;
        max-width: calc(100vw - 40px);
    }
}

/* ---------------------------------------------------------------------
   Bestelling-samenvatting tijdens het bestelproces (hoofdstuk 4.5) - op
   desktop een vaste (sticky) kaart naast het formulier, op mobiel
   ingeklapt achter een knop die een popup opent (dezelfde bottom-sheet-
   aanpak als .scan-modal, maar losstaand: deze pagina's laden niet via
   het scan-app-JS).
   --------------------------------------------------------------------- */

.checkout-layout {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.checkout-layout__main {
    min-width: 0;
}

.checkout-layout__sidebar {
    display: none;
}

.checkout-summary-row {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 6px 0;
    font-size: 0.92rem;
}

.checkout-summary-row--total {
    margin-top: 6px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
    font-weight: 700;
    align-items: baseline;
}

.checkout-summary-row--total .js-summary-total {
    font-size: 1.5rem;
    font-weight: 800;
    letter-spacing: -0.02em;
}

/* FINAL PAYMENT COMPOSITION RESET: de laatste bevestigingsstap
   (EventStorefrontController::renderSingleMethodOverviewStep()) toont
   alles wat de koper beoordeelt in ÉÉN kaart - ticketregels,
   betaalmethode, totaal en de knoppen. Die stap rendert bewust geen
   .checkout-layout, dus geen zijkolom en geen mobiele samenvattingspopup:
   de bestelling staat daar nog maar op één plek.

   De kaart loopt bewust over de VOLLE breedte van de rechter
   checkoutkolom, dus exact even breed als de stapindicator, de
   reserveringsteller en de TESTMODUS-melding erboven. Een max-width liet
   hier eerder een grote lege strook rechts naast de kaart staan, wat de
   bestelling juist weer los in de ruimte liet zweven. */
.checkout-review {
    width: 100%;
}

/* De TESTMODUS-melding op de betaalstappen staat gecentreerd in zijn
   banner. Bewust NIET op .alert--info zelf: die klasse wordt ook gebruikt
   voor langere, meerregelige uitleg op de bestellingen-/omzettingsschermen,
   waar links uitlijnen juist beter leest. Daarom een eigen wrapper rond
   alleen deze twee checkout-banners. */
.checkout-testmode .alert {
    text-align: center;
}

/* Eigen scheidingslijn boven de betaalmethode-rij, zodat de kaart de
   volgorde tickets -> betaalmethode -> totaal ook visueel groepeert. Enkel
   binnen deze kaart gescoped: dezelfde samenvatting-HTML wordt op de
   andere stappen (zijkolom/popup) ongewijzigd hergebruikt. */
.checkout-review .js-summary-method-row {
    margin-top: 6px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
}

/* De knoppen horen bij de bestelling, niet los in de paginaruimte -
   binnen de kaart met een eigen scheidingslijn erboven.

   Bewust twee klassen diep (.checkout-review .checkout-review__actions):
   de generieke .checkout-actions-regels staan verderop in dit bestand en
   zouden bij gelijke specificiteit winnen. */
.checkout-review .checkout-review__actions {
    margin-top: 24px;
    padding-top: 20px;
    border-top: 1px solid var(--border);
}

/* Op smalle schermen passen "← Terug" en "Bestellen & betalen" niet naast
   elkaar binnen de kaartbreedte. Zonder deze regel wikkelt de flexbox ze
   half af (klein knopje links, grote knop rechts eronder), wat er
   onbedoeld uitziet. Bewust volledige breedte onder elkaar in DOM-volgorde
   - de afrekenknop blijft door zijn kleur en positie onderaan de dominante
   actie en is met de duim het best bereikbaar. */
@media (max-width: 480px) {
    .checkout-review .checkout-review__actions {
        flex-direction: column;
        align-items: stretch;
    }

    .checkout-review .checkout-review__actions .button--primary {
        margin-left: 0;
    }
}

/* Sticky onderin het scherm op mobiel (i.p.v. gewoon in de tekstflow),
   zodat de knop altijd bereikbaar is tijdens het scrollen door de
   vervolgstappen - main.page:has(...) geeft de pagina evenveel
   onderruimte terug zodat de vaste knop geen inhoud verbergt. */
.checkout-summary-toggle {
    display: block;
    width: 100%;
    margin: 0;
    padding: 14px 16px calc(14px + env(safe-area-inset-bottom));
    border-radius: 0;
    border: 1px solid var(--border);
    border-left: none;
    border-right: none;
    border-bottom: none;
    background: var(--surface);
    color: var(--ink);
    font-weight: 600;
    font-size: 0.95rem;
    cursor: pointer;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 80;
    box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.08);
}

main.page:has(.checkout-summary-toggle) {
    padding-bottom: calc(70px + env(safe-area-inset-bottom));
}

/* "Terug" en de knop voor de volgende stap horen samen in één kaart
   (stap 1 t/m 4) - het zijn twee losse <form>-elementen (kunnen niet in
   elkaar genest worden), maar de knoppen staan hier via het HTML5
   form="..."-attribuut toch samen. margin-left: auto op de primaire
   knop houdt hem rechts uitgelijnd, ook als de terug-knop een keer
   ontbreekt.
   Sticky onderin is alleen voor desktop (klantverzoek 2026-08-08: "op
   mobiel hoeft het sticky gedeelte niet") - zie de
   @media (min-width:900px)-regel hieronder. Op mobiel dus gewoon
   normale paginaflow. */
.checkout-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    /* De kaart hierboven staat in een eigen <form> en is daarbinnen
       .card:last-child, dus verliest zijn margin-bottom (bedoeld voor
       een kaart zonder iets erna) - maar hier volgt deze balk wél nog,
       dus altijd een eigen marge boven i.p.v. op de vorige kaart te
       vertrouwen. */
    margin-top: 20px;
}

.checkout-actions .button--primary {
    margin-left: auto;
}

/* Op mobiel valt de admin-instelbare stapnaam weg (klantverzoek
   2026-08-08: "← Terug naar Personaliseren" e.d. duwde de twee knoppen
   onder elkaar) - alleen "← Terug"/"Volgende" blijft over
   (EventStorefrontController::renderStepActionLabel()). Vanaf 640px is
   er weer genoeg breedte voor de volledige tekst. */
@media (max-width: 640px) {
    .checkout-actions__step-name {
        display: none;
    }
}

/* Laadindicator op de stap-navigatieknoppen (klantverzoek 2026-08-08) -
   EventStorefrontController::renderCheckoutLoadingScript() zet deze
   klasse + spinner-span erin zodra de koper op "Volgende"/"← Terug"/
   "Bestellen & betalen" klikt, zodat duidelijk is dat de pagina aan het
   laden is terwijl de browser naar de volgende stap (of Mollie)
   navigeert. Hergebruikt @keyframes scan-spin (hierboven, deurverkoop-
   QR-preloader) i.p.v. een eigen animatie te definiëren. */
.checkout-actions button.is-loading {
    opacity: 0.85;
    cursor: default;
}

.checkout-actions__spinner {
    display: inline-block;
    width: 16px;
    height: 16px;
    margin-right: 8px;
    vertical-align: -3px;
    border: 2px solid rgba(255, 255, 255, 0.45);
    border-top-color: #ffffff;
    border-radius: 50%;
    animation: scan-spin 0.8s linear infinite;
}

/* .button--secondary (de "← Terug"-knop) heeft een lichte achtergrond -
   een witte spinner zou daar bijna onzichtbaar zijn, dus hier de
   omgekeerde kleuren (donkere baan, merkkleur als draaiende rand). */
.checkout-actions .button--secondary.is-loading .checkout-actions__spinner {
    border-color: rgba(0, 0, 0, 0.15);
    border-top-color: var(--brand, #5d5dff);
}

.checkout-summary-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 900;
}

.checkout-summary-modal--open {
    display: block;
}

.checkout-summary-modal__backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
}

.checkout-summary-modal__panel {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    max-height: 80vh;
    overflow-y: auto;
    background: var(--surface);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    padding: 20px;
    box-shadow: 0 -10px 40px rgba(0, 0, 0, 0.25);
}

.checkout-summary-modal__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
}

.checkout-summary-modal__header h2 {
    margin: 0;
}

.checkout-summary-modal__close {
    width: 32px;
    height: 32px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--surface-alt);
    color: var(--ink);
    font-size: 1.2rem;
    line-height: 1;
    cursor: pointer;
}

@media (min-width: 900px) {
    .checkout-layout {
        flex-direction: row;
        align-items: flex-start;
    }

    .checkout-layout__main {
        flex: 1 1 0;
    }

    .checkout-layout__sidebar {
        display: block;
        flex: 0 0 320px;
        position: sticky;
        top: 24px;
    }

    .checkout-summary-toggle {
        display: none;
    }

    /* Sticky onderin is bewust ALLEEN voor desktop (klantverzoek
       2026-08-08: "op mobiel hoeft het sticky gedeelte niet") - blijft
       in beeld terwijl de koper door een lange ticketlijst/
       personalisatieformulier scrolt, en "laat los" zodra de kaart
       z'n eigen plek in de paginaflow bereikt (standaardgedrag van
       position:sticky, geen JS nodig). Geen mobiele
       .checkout-summary-toggle-balk om rekening mee te houden op deze
       breedte (hierboven al verborgen), dus gewoon tegen de onderkant. */
    .checkout-actions {
        position: sticky;
        bottom: 0;
        z-index: 40;
    }
}

/* ---------------------------------------------------------------------
   1c-alignment (Decision 1): stap 1 (ticketkeuze) - de commerce-kolom
   van .event-shell (hierboven, poster|commerce-tweedeling, ongewijzigd)
   krijgt hier zijn EIGEN, eenvoudige opbouw: hoofdinhoud (tabs +
   ticketkaarten) gevolgd door één geïntegreerde samenvatting/CTA
   onderaan - geen aparte derde "Jouw bestelling"-kolom meer.
   EventStorefrontController::renderTicketSelectionCommerce(). Mobiel
   blijft de bestaande .checkout-summary-toggle/__modal-oplossing
   (hierboven) intact ongewijzigd; die wordt hier alleen hergebruikt/
   opnieuw gerenderd, niet aangepast. */
.ticket-selection-layout {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

/* Verborgen op mobiel (voorlopig staat mag klantverzoek 2026-08-08's
   "op mobiel geen sticky/derde kolom" niet doorbreken) - de bestaande
   .checkout-summary-toggle-balk + modal blijven daar de enige
   samenvatting. Vanaf 900px (zelfde omslagpunt als .checkout-layout
   hierboven) wordt dit de zichtbare, geïntegreerde samenvatting/CTA
   onderaan de commerce-kolom. */
.ticket-selection-summary {
    display: none;
}

.ticket-selection-summary__cta {
    display: block;
    width: 100%;
    margin-top: 16px;
    text-align: center;
}

@media (min-width: 900px) {
    /* 1c full-journey shell correction (punt 6): geen losse witte kaart
       met eigen rand/schaduw meer (dat las als een aparte kaart onderaan
       de kolom, i.p.v. "de natuurlijke onderkant van hetzelfde
       commercevlak") - alleen een bovenrand als scheiding, zoals een
       kassabon-totaalregel die de rest van de commercekolom afsluit. */
    .ticket-selection-summary {
        display: block;
        border-top: 2px solid var(--border);
        padding-top: 20px;
    }

    /* De losse mobiele CTA-kaart (.checkout-actions-uitstraling) vervalt
       vanaf hier - de knop staat al in .ticket-selection-summary__cta
       hierboven, dubbele CTA's zou verwarrend zijn. */
    .ticket-selection-mobile-cta {
        display: none;
    }
}

/* ---------------------------------------------------------------------
   Knoppen
   --------------------------------------------------------------------- */

.button {
    display: inline-block;
    font-family: inherit;
    font-size: 0.95rem;
    font-weight: 700;
    padding: 11px 22px;
    border-radius: var(--radius-pill);
    border: 1px solid transparent;
    cursor: pointer;
    text-decoration: none;
    transition: transform 0.05s ease, background 0.15s ease;
}

.button:active {
    transform: scale(0.98);
}

.button--primary {
    background: var(--brand);
    color: var(--surface);
}

.button--primary:hover {
    background: #4747d1;
}

/* VF-1 (tenant-branding-strategie): op koperspagina's (body.buyer-body,
   zie View::render()) blijft de primaire koopactie ALTIJD de vaste
   Eticketskopen-interactiekleur - ongeacht welke --brand een organisatie
   koos. Tenantidentiteit blijft zichtbaar via het event-visual/logo/
   accentlijn, niet via elke koopknop. Extra .button-klasse in de
   selector (i.p.v. enkel .buyer-body .button--primary) verhoogt de
   specificiteit bewust boven de :hover-regel hierboven, die anders qua
   specificiteit gelijk zou zijn en puur op brondode-volgorde zou winnen. */
body.buyer-body .button.button--primary {
    background: var(--brand-interactive);
}

body.buyer-body .button.button--primary:hover {
    background: #4747d1;
}

.button--secondary {
    background: transparent;
    color: var(--ink);
    border-color: var(--border);
}

.button--secondary:hover {
    background: var(--surface-alt);
}

/* UI-0 design foundation: nieuwe, additieve knopvarianten/-toestanden -
   geen van deze klassen wordt momenteel ergens aangeroepen, dus dit raakt
   geen bestaande pagina. */

/* Compacte variant (bijv. rijacties in een tabel/lijst) - kleinere
   padding/lettergrootte, verder identiek aan .button. */
.button--compact {
    padding: 6px 14px;
    font-size: 0.82rem;
}

/* Destructieve actie (bijv. verwijderen/annuleren) - hergebruikt de
   bestaande --danger-tokens (dezelfde als .badge--danger/.alert--danger),
   geen nieuwe kleur geïntroduceerd. */
.button--destructive {
    background: var(--danger);
    color: #ffffff;
}

.button--destructive:hover {
    filter: brightness(0.92);
}

/* Disabled-toestand - was nog nergens gedefinieerd (native knoppen
   vielen terug op kale browserstijl). Werkt op zowel <button disabled>
   als een handmatig toegevoegde .is-disabled-klasse (voor niet-<button>-
   elementen met role="button"). */
.button:disabled,
.button.is-disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

/* Generieke laadtoestand - zelfde visuele patroon (spinner + gedimde
   knop) als checkout-actions button.is-loading hierboven, nu voor ELKE
   .button beschikbaar i.p.v. alleen binnen .checkout-actions. Die
   bestaande, scopedere regel blijft ongewijzigd bestaan (specificiteit
   maakt dit conflictvrij) - dit is puur een aanvulling voor knoppen
   elders die dezelfde laadindicator willen. .button__spinner is een
   losse, neutraal genoemde kopie van .checkout-actions__spinner (zelfde
   opbouw/@keyframes scan-spin) - die laatste blijft puur voor checkout,
   ".checkout-actions__spinner" op een knop ergens anders zou een
   verwarrende klassenaam zijn. */
.button.is-loading {
    opacity: 0.85;
    cursor: default;
    pointer-events: none;
}

.button__spinner {
    display: inline-block;
    width: 16px;
    height: 16px;
    margin-right: 8px;
    vertical-align: -3px;
    border: 2px solid rgba(255, 255, 255, 0.45);
    border-top-color: #ffffff;
    border-radius: 50%;
    animation: scan-spin 0.8s linear infinite;
}

.button--secondary.is-loading .button__spinner,
.button--compact.is-loading .button__spinner {
    border-color: rgba(0, 0, 0, 0.15);
    border-top-color: var(--brand, #5d5dff);
}

/* Zichtbare, gebrandmerkte focusring ook op de pil-navigatie-elementen -
   dit waren native <button>'s zonder eigen :focus-stijl, dus voorheen
   alleen de kale browserstandaard (nooit onzichtbaar, maar inconsistent
   met de rest van het platform). select/textarea NIET hier toegevoegd -
   die hebben al een eigen, volledig zichtbare :focus-behandeling (border-
   color + box-shadow-ring, zie de gedeelde input/select/textarea-regel
   hierboven) - een extra outline erbovenop zou een dubbele ring geven. */
.pill-nav__item:focus-visible,
.tab-dock__item:focus-visible,
.qty-stepper__btn:focus-visible,
.scan-tab-bar__item:focus-visible {
    /* UI-0 accessibility fix (Codex-bevinding, P1, vervolg): was eerst
       var(--brand) (zelf al een fix voor het te zwakke --brand-light),
       maar --brand is tenant-overschrijfbaar - zie de toelichting bij
       --focus-ring in :root. --focus-ring is de vaste, niet-
       overschrijfbare kleur die hier hoort te staan; werkt zowel op
       lichte achtergronden als op de donkere pil-/tabbalk zelf
       (rgba(16,16,22,.92)), waar deze knoppen typisch op staan.
       .scan-tab-bar__item hoort hier ook bij: de scan-app gebruikt een
       eigen tabbalk-klasse (los van .tab-dock) die anders op de kale
       browserstandaard terugvalt. */
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* Evenementkeuze in de scan-app (klantverzoek 2026-08-10): titel en
   datum/tijd onder elkaar i.p.v. op 1 regel achter een streepje, titel
   groter zodat die als eerste opvalt in de lijst. */
.event-picker-row {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 3px;
    text-align: left;
    padding-top: 14px;
    padding-bottom: 14px;
}

.event-picker-row__name {
    font-size: 1.1rem;
    font-weight: 700;
}

.event-picker-row__date {
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--muted);
}

/* Pil-vormig statuslabel (bijv. "Betaald"/"Open"/"Actief" in tabellen) -
   zie de collage: kleine ronde badges i.p.v. platte tekst. Nieuw
   onderdeel van het fundament; de tabellen zelf worden in een latere
   ronde omgezet om deze klasse te gebruiken. */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 5px 12px;
    border-radius: var(--radius-pill);
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.badge--success {
    background: var(--success-bg);
    color: var(--success);
}

.badge--danger {
    background: var(--danger-bg);
    color: var(--danger);
}

.badge--accent {
    background: var(--accent);
    color: var(--accent-ink);
}

.badge--neutral {
    background: var(--surface-alt);
    color: var(--muted);
}

/* UI-0 design foundation: aanvullende statussemantiek - .badge--accent
   (geel) bestaat al en blijft ongewijzigd de weg voor bestaande
   call sites (bijv. "Bijna uitverkocht"); .badge--warning is dezelfde
   visuele behandeling onder een duidelijker semantische naam voor
   toekomstig gebruik (nieuwe --warning/--warning-bg-tokens, zie :root) -
   geen bestaande aanroep hernoemd. .badge--info is nieuw (blauw/paars
   getint, dezelfde tint als .alert--info hieronder al gebruikt) voor
   neutraal-informatieve status (bijv. "wacht op koppeling",
   "uitnodiging verstuurd"), te onderscheiden van .badge--neutral (grijs,
   echt "geen bijzondere status"). */
.badge--warning {
    background: var(--warning-bg);
    color: var(--warning);
}

/* UI-0 accessibility fix (Codex-bevinding, P1): tekstkleur was --brand
   (~3.99:1 op deze achtergrond, te laag voor kleine badge-tekst) - nu
   --brand-ink (zie :root), dezelfde paarse familie dus nog steeds
   duidelijk als "info" te onderscheiden van success/warning/danger/
   neutral, alleen donkerder/leesbaarder. Achtergrond bewust ongewijzigd. */
.badge--info {
    background: var(--brand-light);
    color: var(--brand-ink);
}

/* UI-1 (public/buyer redesign): gedeelde statuskop voor de bedankt-/
   orderstatuspagina's (OrderStatusController::renderOrderStatusHeader())
   - icoon + badge communiceren de status ALTIJD ook zonder op kleur te
   vertrouwen (badge-tekst is er hoe dan ook, icoon staat los van de
   kleur). Hergebruikt de bestaande --success/--warning/--danger(-bg)
   tokens, geen nieuwe kleursemantiek. */
.order-status {
    text-align: center;
    margin-bottom: 20px;
}

.order-status__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    border-radius: var(--radius-pill);
    font-size: 1.6rem;
    font-weight: 700;
    margin-bottom: 12px;
}

.order-status--success .order-status__icon {
    background: var(--success-bg);
    color: var(--success);
}

.order-status--warning .order-status__icon {
    background: var(--warning-bg);
    color: var(--warning);
}

.order-status--danger .order-status__icon {
    background: var(--danger-bg);
    color: var(--danger);
}

.order-status__heading {
    margin: 10px 0 4px;
}

.order-status__subtext {
    color: var(--muted);
    margin: 0;
}

/* Zichtbare focusring voor toetsenbordgebruik, ook op knoppen/links.
   UI-0 accessibility fix (Codex-bevinding, P1): was --brand-light, circa
   1.18:1 op een witte/lichte achtergrond - een focusring die zo dicht bij
   de achtergrondkleur zit, maakt focus juist MINDER zichtbaar voor
   toetsenbordgebruikers dan de kale browserstandaard.
   Vervolgfix (P1, tenant-branding-blocker): een tussenstap gebruikte
   hierna var(--brand) - maar --brand is precies het token dat tenant-
   huisstijl per pagina overschrijft (View.php, inline <style>:root{
   --brand:...}</style> met een door de organisatie gekozen kleur, elke
   geldige hex toegestaan). Een organisatie met bijv. --brand:#ffffff of
   een zeer lichte tint kon de focusring zo zelf weer (bijna) onzichtbaar
   maken, zonder dat te willen. --focus-ring (zie :root) is een vaste,
   NIET tenant-overschrijfbare kleur - ruim boven de WCAG 1.4.11-eis
   (3:1 voor niet-tekstuele UI-indicatoren) op zowel witte/lichte
   oppervlakken als de donkere schermen (scan-app, pil-navigatie),
   ongeacht welke --brand-kleur een tenant kiest. */
a:focus-visible,
.button:focus-visible,
input:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* UI-3-bevinding (runtime keyboardtest): de scanapp gebruikt op veel
   plekken bewust een KALE <button> zonder .button-klasse (tabbalk-
   iconen, camera/toetsenbord-knoppen, "Uitloggen"/"Ander evenement
   kiezen", modal-sluitknoppen, "Doorgaan" na een resultaat) - die vielen
   buiten de regel hierboven en kregen daardoor de kale browserstandaard-
   focusring i.p.v. het gefrozen --focus-ring-token. Alleen scanner-
   context (.scan-body/.scan-modal/.scan-login-card) - raakt geen
   koper-/organizerpagina. */
.scan-body button:focus-visible,
.scan-modal button:focus-visible,
.scan-login-card button:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* ---------------------------------------------------------------------
   Meldingen
   --------------------------------------------------------------------- */

.alert {
    padding: 12px 16px;
    border-radius: var(--radius);
    font-size: 0.92rem;
    margin-bottom: 20px;
}

.alert--danger {
    background: var(--danger-bg);
    color: var(--danger);
}

.alert--success {
    background: var(--success-bg);
    color: var(--success);
}

/* Neutrale, informatieve melding (bijv. TenantLegalController: duidelijk
   maken dat een getoonde tekst van het platform komt, niet van de
   organisatie zelf, klantbeslissing 2026-08-05) - geen foutmelding, dus
   bewust niet .alert--danger/--success. */
.alert--info {
    background: var(--brand-light);
    color: var(--brand-dark);
}

/* UI-0 design foundation: was nog niet gedefinieerd (danger/success/info
   bestonden al) - zelfde --warning/--warning-bg-tokens als .badge--warning
   hierboven. */
.alert--warning {
    background: var(--warning-bg);
    color: var(--warning);
}

/* Openstaand betaalverzoek bij een ticketomzetting (klantverzoek
   2026-08-17: "de melding niet duidelijk... kader omheen zodat het
   opvalt") - bovenop de gewone .alert--info-styling een duidelijk
   zichtbaar kader, zodat dit niet tussen de rest van de kaart verdwijnt.
   Alleen een extra klasse i.c.m. .alert--info, geen wijziging aan die
   basisklasse zelf (die wordt ook elders al gebruikt). */
.pending-conversion-notice {
    border: 2px solid var(--brand);
}

.pending-conversion-notice p {
    margin: 4px 0;
}

.pending-conversion-notice p:first-child {
    margin-top: 0;
}

.pending-conversion-notice p:last-child {
    margin-bottom: 0;
}

/* ---------------------------------------------------------------------
   Tabellen (klanten-/gebruikersoverzichten in de adminomgeving)
   --------------------------------------------------------------------- */

.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.92rem;
}

/* Micro-fix (organizer tickettype-overzicht kreeg een extra
   Verkoopkanaal-kolom): scrolt horizontaal i.p.v. de pagina zelf te
   verbreden op een smalle viewport - alleen toegepast waar een tabel
   krap kan worden, geen wijziging aan .data-table zelf of aan tabellen
   die deze wrapper niet gebruiken. */
.table-scroll {
    overflow-x: auto;
}

.data-table th,
.data-table td {
    text-align: left;
    padding: 10px 12px;
    border-bottom: 1px solid var(--border);
}

.data-table th {
    color: var(--muted);
    font-weight: 600;
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.data-table tbody tr:last-child td {
    border-bottom: none;
}

.data-table .button {
    padding: 6px 12px;
    font-size: 0.85rem;
}

/* Groepskop per (sub)evenement in de tickettabel van een bestelling
   (klantverzoek 2026-08-21) - alleen aanwezig als de bestelling tickets
   voor meerdere evenementen bevat (OrderListController::renderOrderDetail()),
   dus bewust geen aparte toggle/instelling nodig. */
.data-table__group-row td {
    padding-top: 18px;
    font-weight: 700;
    color: var(--brand-dark);
    border-bottom: 2px solid var(--border);
}

.data-table__group-row:first-child td {
    padding-top: 10px;
}

/* Naam/e-mail per ticket pas bewerkbaar na een potlood-icoon (klantverzoek
   2026-08-20, OrderListController::renderOrderDetail()) - i.p.v. standaard
   een open tekstveld. Herzien dezelfde dag: geen potlood meer per cel (dat
   maakte bulk-bewerken onmogelijk), maar 1 potlood boven de tabel
   (.js-bulk-edit-toggle) dat alle rijen tegelijk omzet, plus een losse
   "Naam/e-mail bewerken"-actie per rij in het "⋮"-menu hieronder.
   .editable-field__input krijgt verder geen eigen opmaak (het generieke
   input[type="text"] hierboven in dit bestand geldt al), alleen de kleine
   editknop. */
.editable-field {
    white-space: nowrap;
}

.editable-field__edit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    margin-left: 6px;
    padding: 0;
    border: none;
    background: none;
    color: var(--muted);
    font-size: 0.85rem;
    cursor: pointer;
    border-radius: var(--radius);
}

.editable-field__edit:hover {
    background: var(--surface-alt);
    color: var(--ink);
}

.editable-field__input {
    display: inline-block;
    width: auto;
    min-width: 140px;
    margin-top: 0;
}

/* "⋮"-acties-menu per ticket (klantverzoek 2026-08-20: "Bekijken" +
   "Omzetten" + "Opnieuw versturen" achter 1 knop i.p.v. steeds meer
   losse links). <details>/<summary> voor de open/dicht-staat, maar de
   lijst zelf wordt position:fixed en krijgt zijn top/right via JS
   (rowMenuScript() in OrderListController) - klantfeedback 2026-08-20
   dat de eerdere in-place uitklap de pagina liet "verspringen". Fixed
   i.p.v. absolute ontsnapt ook meteen aan de overflow-x:auto hieronder
   op .card:has(table.data-table), die in de meeste browsers impliciet
   ook verticaal clipt. */
.row-menu__toggle {
    cursor: pointer;
    list-style: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--muted);
    font-weight: 700;
}

.row-menu__toggle::-webkit-details-marker {
    display: none;
}

.row-menu__toggle:hover {
    background: var(--surface-alt);
    color: var(--ink);
}

.row-menu__list {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 6px;
    background: var(--surface-alt);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
    min-width: 160px;
    /* Altijd position:fixed, niet pas via JS bij het openen (klantmelding
       2026-08-21: de popup "verspringt" nog steeds) - <details>'s native
       toggle-event vuurt VOLGENS SPEC asynchroon (een aparte taak, niet
       synchroon binnen dezelfde klik), dus de browser tekende de net
       geopende <details> eerst nog kort IN-FLOW (de tabelrij duwde open,
       vandaar de sprong) voordat rowMenuScript() 'm alsnog naar fixed
       omzette. Nu al standaard fixed, dus nooit meer in-flow, ongeacht
       wanneer die JS draait - rowMenuScript() (OrderListController)
       positioneert 'm nu bovendien synchroon in de click-handler zelf,
       vóór de browser de <details> daadwerkelijk opent. */
    position: fixed;
    z-index: 50;
}

.row-menu__list a,
.row-menu__button {
    display: block;
    width: 100%;
    text-align: left;
    padding: 6px 8px;
    border: none;
    border-radius: var(--radius);
    background: none;
    font: inherit;
    font-size: 0.88rem;
    color: var(--ink);
    cursor: pointer;
}

.row-menu__list a:hover,
.row-menu__button:hover {
    background: var(--surface);
}

/* Generieke mobiele redding voor ALLE .data-table's (klantmelding
   2026-08-14: "de weergave van o.a. bestellingen niet geschikt voor op
   mobiele telefoons") - een brede tabel scrollt horizontaal binnen zijn
   eigen kaart i.p.v. de hele pagina breder te maken. Descendant-selector
   (geen `>`) omdat sommige tabellen dieper genest zitten dan direct in
   .card. Nul HTML-wijzigingen nodig, werkt voor alle bestaande tabellen. */
.card:has(table.data-table) {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* Bestellingenoverzicht op mobiel: kaartjes i.p.v. een (horizontaal
   scrollende) tabel (klantverzoek 2026-08-14, "app-ervaring") - bekende
   CSS-only responsive-table-truc: thead verbergen, elke rij een eigen
   afgeronde kaart, elke cel een label/waarde-regel via het data-label-
   attribuut (OrderListController::renderOrderRow()). Alleen op de
   .data-table--stack-tabellen, niet op alle 33 .data-table-gebruiken -
   dat zou een veel grotere, ongeteste HTML-operatie zijn geweest voor
   pagina's die niemand als probleem heeft genoemd. */
@media (max-width: 640px) {
    .data-table--stack {
        border: none;
    }

    .data-table--stack thead {
        display: none;
    }

    .data-table--stack tbody {
        display: block;
    }

    .data-table--stack tr {
        display: block;
        border: 1px solid var(--border);
        border-radius: var(--radius);
        margin-bottom: 12px;
        padding: 4px 12px;
    }

    .data-table--stack tr:last-child {
        margin-bottom: 0;
    }

    .data-table--stack td {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
        text-align: right;
        padding: 8px 0;
    }

    .data-table--stack td:not(:last-child) {
        border-bottom: 1px solid var(--border);
    }

    .data-table--stack td[data-label=""] {
        justify-content: flex-end;
    }

    .data-table--stack td::before {
        content: attr(data-label);
        font-weight: 600;
        color: var(--muted);
        font-size: 0.82rem;
        text-align: left;
        flex: none;
    }

    .data-table--stack td[data-label=""]::before {
        content: none;
    }
}

/* Wachtlijst-aanmeldformulier bij een uitverkocht tickettype (hoofdstuk
   4.2, EventStorefrontController::renderWaitlistModal()) - een gedeelde
   modal (net als .scan-modal: mobiel beeldvullend, vanaf 640px een
   gecentreerde kaart) i.p.v. een inline rij, want een <form> nesten
   binnen de buitenste #quantities-form is ongeldige HTML. */
.waitlist-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 950;
}

.waitlist-modal--open {
    display: block;
}

.waitlist-modal__backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
}

.waitlist-modal__panel {
    position: fixed;
    inset: 0;
    overflow-y: auto;
    background: var(--surface);
    padding: 20px;
}

.waitlist-modal__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
}

.waitlist-modal__header h2 {
    margin: 0;
}

.waitlist-modal__close {
    width: 32px;
    height: 32px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--surface-alt);
    color: var(--ink);
    font-size: 1.2rem;
    line-height: 1;
    cursor: pointer;
}

@media (min-width: 640px) {
    .waitlist-modal__panel {
        inset: auto;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 90%;
        max-width: 420px;
        max-height: 85vh;
        border-radius: var(--radius-lg);
        box-shadow: 0 10px 40px rgba(0, 0, 0, 0.25);
    }
}

/* 1c-alignment (Decision 5, HYBRIDE "voorlopig"): vanaf 768px verplaatst
   de JS (renderWaitlistModal() -> positionNearCard()) de modal van het
   schermmidden naar een kaart die tegen de betreffende uitverkochte
   ticketrij aan valt (inline top/left, hier alleen de centrering
   uitgeschakeld en het formaat verkleind) - de wachtlijst-actie voelt zo
   visueel aan als onderdeel van de (disabled) ticketkaart, zonder de
   gedeelde modal-structuur zelf te vervangen (blijft dus geneste-form-vrij).
   Mobiel (<768px) krijgt deze klasse nooit toegevoegd (zie JS) en behoudt
   het bestaande beeldvullende gedrag onveranderd. */
.waitlist-modal--anchored .waitlist-modal__panel {
    top: 0;
    left: 0;
    transform: none;
    width: 360px;
    max-width: calc(100vw - 24px);
    max-height: 70vh;
}


/* ---------------------------------------------------------------------
   Ticketkaart (hoofdstuk 4.13) - mobiele kaart op scherm, A4-achtig bij
   het printen (@media print hieronder). Volgt op scherm de systeem-
   instelling licht/donker; bij printen altijd een vaste lichte
   achtergrond (voorkomt onnodig inktverbruik en blijft leesbaar).
   --------------------------------------------------------------------- */

/* VF-1g-followup (dark entrance interface, USER DECISION): de volledige
   viewport donker i.p.v. alleen de kaart zelf - minder licht bij de
   deur, en de witte QR-kaart blijft zo het meest contrastrijke object
   op het scherm. View::render()'s $darkEntryShell zet deze bodyklasse
   (TicketViewController::renderTicket()/OrderStatusController::
   renderTicketsOnlyPage()). Alle zichtbare inhoud op die 2 pagina's zit
   al in eigen donkere kaarten met een eigen tekstkleur (.ticket-card,
   .ticket-card__practical, .ticket-page__nav) - de enige stray
   lichte-op-donker-tekst is de automatische paginatitel op de
   meerdere-tickets-pagina ("Jouw tickets", .page-header h1 hieronder,
   die pagina gebruikt bewust GEEN $full zoals de losse ticketpagina).
   #0a0a10 is dezelfde donkerste toon als de kaart-verlopen elders
   (.buyer-shell__visual--fallback/.ticket-card), voor 1 consistente
   donkere kleurtaal. */
body.entry-ticket-shell {
    background: #0a0a10;
}

body.entry-ticket-shell .page-header h1 {
    color: #ffffff;
}

.ticket-page {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 16px;
    align-items: start;
}

/* VF-1 (true visual rebuild, mockup 1g): losse schil voor het ENKELE-
   ticketscherm (TicketViewController::show()) - bewust GEEN .ticket-page
   (dat blijft het meerdere-tickets-grid op de orderstatuspagina). Het
   ticket wordt hier het bewuste "hero object" van de pagina: gecentreerd,
   ruime canvas eromheen i.p.v. een kaart die klein linksboven blijft
   hangen op een verder lege pagina. */
/* VF-1g-fix (live gemeten bug, 390px): .ticket-page-single was
   flex-direction:row (de standaard) met .ticket-card als enige kind -
   werkte zolang praktische info/Jouw gegevens/PDF-knop nog GENEST binnen
   .ticket-card zaten. Nu die (mockup 1g) losse, eigen kaarten ONDER het
   ticket-object zijn geworden, zijn het aparte flex-items in dezelfde rij
   geworden en kregen ze elk maar een fractie van de breedte (gemeten:
   .ticket-card slonk naar 13px, praktische info/PDF-knop stonden ernaast
   i.p.v. eronder). flex-direction:column + align-items:center stapelt ze
   nu verticaal, elk gecentreerd op dezelfde breedte. */
.ticket-page-single {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
    padding: 24px 20px 40px;
    box-sizing: border-box;
}

.ticket-page-single > * {
    width: 100%;
    max-width: 480px;
}

@media (min-width: 900px) {
    .ticket-page-single {
        padding: 56px 20px 72px;
    }

    .ticket-page-single > * {
        max-width: 520px;
    }

    .ticket-page-single .ticket-card {
        box-shadow: 0 30px 70px rgba(20, 20, 60, 0.14);
    }
}

/* VF-1g (screenshot-driven e-ticket rebuild, mockup 1g): donkere pil-
   navigatiebalk i.p.v. de vorige twee volle-breedte tekstknoppen -
   dezelfde bestaande id's/paging-mechaniek (ticketPagingScript()),
   uitsluitend visueel herbouwd. */
.ticket-page__nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 16px auto 0;
    max-width: 380px;
    padding: 10px 10px 10px 20px;
    background: #101014;
    color: #ffffff;
    border-radius: 999px;
}

#ticket-nav-counter {
    font-weight: 700;
}

.ticket-page__nav-buttons {
    display: flex;
    gap: 8px;
}

.ticket-page__nav-btn {
    width: 40px;
    height: 40px;
    border-radius: 999px;
    border: none;
    background: rgba(255, 255, 255, 0.12);
    color: #ffffff;
    font-size: 1.3rem;
    line-height: 1;
    cursor: pointer;
}

.ticket-page__nav-btn--primary {
    background: var(--brand-interactive, #5d5dff);
}

.ticket-page__nav-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

/* BUYER ORDER MICROFIX (mobile-only rapid-view CTA, USER DECISION): de
   snelle multi-ticket QR-flow ("Alle tickets bekijken") is bedoeld voor
   mobiel/entreegebruik - op desktop/tablet is het volledige ticket-
   overzicht al goed bruikbaar, dus daar hoort deze CTA niet meer (was
   kort daarvoor, vorige ronde, juist altijd-zichtbaar gemaakt - dat
   bleek voor desktop een overcorrectie). Verborgen vanaf dezelfde
   768px-drempel waarop .buyer-shell zelf al van gestapeld naar
   splitweergave overschakelt (zie .buyer-shell hierboven) - een
   bestaande, aan de shell gekoppelde drempel i.p.v. een nieuwe eigen
   waarde. Route/functionaliteit (het bestaande /tickets-endpoint)
   ongewijzigd - uitsluitend zichtbaarheid. */
@media (min-width: 768px) {
    .rapid-view-cta {
        display: none;
    }
}

/* Krijgt de merkkleur van de organisatie (button--primary, klantbeslissing
   2026-08-06 - stond eerst op button--secondary) + gecentreerde tekst: de
   knoptekst is lang genoeg om op de meeste telefoons over 2 regels te
   lopen, en .button is display:inline-block (dus standaard links
   uitgelijnde tekst) i.p.v. het automatisch centrerende gedrag van een
   volle-breedte block-knop. */
.tickets-link__button {
    display: block;
    text-align: center;
}

/* VF-1g-followup (Part 3): GELDIG/GESCAND-badge naast de tickettype-kop
   op de orderoverzicht-ticketkaart (renderTicketRow(), lichte .card-
   achtergrond - dus de gewone platformbrede .badge--success/--neutral,
   niet de donkere .ticket-card__status-badge-varianten hierboven). */
.ticket-row__topline {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.ticket-row__topline h3 {
    margin: 0;
}

/* B1 - ticketkaart op de bestelpagina: compacte actiezone direct onder de
   ticketgegevens (primair "Ticket bekijken", daaronder de secundaire acties
   als kleine knoppen die op smalle kaarten/mobiel netjes doorlopen naar een
   volgende regel - nooit horizontaal buiten de kaart).
   B1.1 (live gezien): .ticket-grid rekt alle kaarten in een rij op tot de
   hoogste (align-items: stretch) en de actiezone stond met margin-top:auto
   onderaan de kaart - een geopend deelpaneel in één kaart duwde zo de
   knoppen van de buurkaarten omlaag, met een groot leeg vlak erboven. Deze
   kaarten houden nu hun eigen, natuurlijke hoogte (align-self: start) en
   de acties volgen direct op de inhoud. Geen vaste hoogte. */
.ticket-row {
    display: flex;
    flex-direction: column;
    align-self: start;
}

.ticket-actions {
    padding-top: 12px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.ticket-actions__primary {
    display: block;
    text-align: center;
}

.ticket-actions__secondary {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.ticket-actions__secondary > .button,
.ticket-actions__form {
    flex: 1 1 auto;
}

.ticket-actions__form {
    display: flex;
    margin: 0;
}

.ticket-actions__secondary .button {
    flex: 1 1 auto;
    text-align: center;
    white-space: nowrap;
}

/* B1 - deellink pas na "Deellink genereren/tonen" zichtbaar, in een eigen
   rustig paneel met kopieerknop, status ("Link gekopieerd") en uitleg. */
.share-panel {
    margin-top: 12px;
    padding: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-alt);
}

.share-panel__title {
    margin: 0 0 8px;
    font-weight: 700;
    font-size: 0.9rem;
}

/* Veld en kopieerknop altijd onder elkaar, over de volle paneelbreedte -
   de ticketkaarten zijn op desktop maar ~240px breed (gemeten: naast
   elkaar bleef van de link alleen "http://" zichtbaar). */
.share-panel .copy-link {
    flex-wrap: wrap;
    margin-bottom: 6px;
}

.share-panel .copy-link__btn {
    width: 100%;
    justify-content: center;
}

.share-panel input.share-panel__input {
    flex: 1 1 100%;
    min-width: 0;
    width: 100%;
    margin: 0;
    padding: 6px 10px;
    font-family: var(--font-mono);
    font-size: 0.78rem;
    background: var(--surface);
}

.share-panel__status {
    margin: 0 0 6px;
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--success);
}

.share-panel__status:empty {
    display: none;
}

.share-panel__status.is-manual {
    color: var(--ink);
    font-weight: 400;
}

.share-panel .hint {
    margin: 0;
}

.share-panel__resend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 10px 0 0;
}

.copy-link__btn.is-copied {
    background: var(--success-bg);
    border-color: var(--success);
    color: var(--success);
}

/* B1 - "Alle tickets printen / downloaden" (bestelniveau). */
.bulk-download {
    margin: 12px 0 16px;
}

.bulk-download__title {
    margin: 0 0 4px;
    font-weight: 700;
}

.bulk-download__button {
    display: block;
    text-align: center;
}

.bulk-download .hint {
    margin: 6px 0 0;
}

.bulk-download__parts {
    list-style: none;
    margin: 10px 0 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
    gap: 8px;
}

.bulk-download__parts .button {
    display: block;
    text-align: center;
}

.bulk-download__range {
    display: block;
    margin-top: 2px;
    text-align: center;
    font-size: 0.78rem;
    color: var(--muted);
}

@media (max-width: 480px) {
    .share-panel .copy-link {
        flex-wrap: wrap;
    }

    .share-panel .copy-link__btn {
        width: 100%;
        justify-content: center;
    }
}

/* ---------------------------------------------------------------------
   VF-1g (screenshot-driven e-ticket rebuild, mockup 1g): één coherent
   donker "e-ticket"-object i.p.v. de vorige drie losse blokken (grote
   merkkleur-header, donkere QR-stub, los wit praktisch-informatieblok).
   Nieuwe volgorde: compacte kop -> DOMINANTE WITTE QR-kaart bovenaan ->
   perforatie -> donkere evenementgegevens. .ticket-card__info-grid/
   __info-label/__info-value/__info-item--wide, .ticket-card__divider/
   __notch en .ticket-card__qr/__code blijven bewust gedeelde, ongewijzigde
   bouwstenen (nu ook hergebruikt door OrderStatusController's meerdere-
   tickets-kaart, zie verderop) - alleen de OMLIJSTING eromheen is nieuw.
   --------------------------------------------------------------------- */
.ticket-card {
    background: #101014;
    color: #ffffff;
    border-radius: var(--radius-lg);
    box-shadow: 0 24px 60px rgba(16, 16, 20, 0.35);
    overflow: hidden;
}

.ticket-card__topline {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 20px 22px 16px;
}

/* Tenant-identiteit als klein, ingetogen kleuraccent (USER DECISION:
   tenantbranding mag blijven bestaan maar mag het ticket niet meer
   domineren, en het tenant-LOGO blijft elders bewust verwijderd - dit is
   uitsluitend een kleurvlak, geen afbeelding). var(--brand) is dezelfde
   per-tenant CSS-variabele die View.php al injecteert. */
.ticket-card__organizer {
    display: flex;
    align-items: center;
    gap: 10px;
    font-weight: 700;
    font-size: 0.95rem;
}

.ticket-card__organizer-swatch {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    border-radius: 6px;
    background: var(--brand, #5d5dff);
}

.ticket-card__status-badge {
    flex-shrink: 0;
    text-transform: uppercase;
}

.ticket-card__status-badge--valid {
    background: rgba(31, 122, 90, 0.22);
    color: #7be3bd;
}

.ticket-card__status-badge--used {
    background: rgba(255, 255, 255, 0.12);
    color: rgba(255, 255, 255, 0.7);
}

/* Dominante witte QR-kaart (mockup 1g) - de QR moet het eerste zijn wat
   opvalt, met genoeg witruimte (rustzone) eromheen voor betrouwbaar
   scannen. */
.ticket-card__qr-stub {
    background: #ffffff;
    color: var(--ink);
    margin: 0 16px;
    border-radius: 20px 20px 0 0;
    padding: 28px 20px 26px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
}

.ticket-card__qr {
    width: min(240px, 62vw);
    margin: 0;
}

.ticket-card__qr svg {
    display: block;
    width: 100%;
    height: auto;
}

.ticket-card__code {
    margin: 0;
    font-family: var(--font-mono);
    font-size: 1.1rem;
    font-weight: 700;
    letter-spacing: 0.05em;
}

/* Geperforeerde scheidingslijn tussen de witte QR-kaart en de donkere
   evenementgegevens - visuele "afscheurstrook"-associatie (mockup 1g),
   puur decoratief. De twee "inkepingen" zijn cirkels die half buiten de
   kaart vallen; .ticket-card's overflow:hidden knipt ze af tot een halve
   maan, alsof er een rond gaatje in de kaartrand geponst is - dezelfde
   pagina-achtergrondkleur (var(--surface), wit) laat de "punch" er
   authentiek uitzien tegen zowel het witte als het donkere deel. */
.ticket-card__divider {
    position: relative;
    height: 0;
    margin: 0 16px;
    border-top: 2px dashed var(--border);
}

.ticket-card__notch {
    position: absolute;
    top: -12px;
    width: 24px;
    height: 24px;
    border-radius: 999px;
    background: var(--surface);
}

.ticket-card__notch--left {
    left: -12px;
}

.ticket-card__notch--right {
    right: -12px;
}

.ticket-card__details {
    padding: 20px 22px 24px;
}

.ticket-card__details h2 {
    color: #ffffff;
    margin: 2px 0 10px;
}

/* Platformgeel als datum-/signaalaccent (mockup 1g), consistent met
   var(--accent) elders op het platform. */
.ticket-card__date-eyebrow {
    margin: 0;
    font-family: var(--font-mono);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--accent, #ffc80a);
}

/* USER DECISION (elk_apart/pooled-nuance, zie Ticket::publicScanStatus()):
   een informatieve notitie ("eerder gescand op ...") náást de GELDIG-
   badge i.p.v. een blokkerende GESCAND-status - subtiel, geen alarm. */
.ticket-card__status-note {
    margin: 0 0 12px;
    font-size: 0.82rem;
    color: rgba(255, 255, 255, 0.55);
}

/* Datum/Aanvang + Type/Order als 2x2-rooster (collage) i.p.v. losse
   regels onder elkaar. */
.ticket-card__info-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px 20px;
    margin: 18px 0 0;
}

.ticket-card__info-label {
    display: block;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    opacity: 0.7;
    margin-bottom: 3px;
}

.ticket-card__info-value {
    display: block;
    font-weight: 700;
    font-size: 1.02rem;
}

/* Tickettype/Op naam van krijgen de volle breedte i.p.v. een halve cel -
   meer ruimte voor een langere waarde. */
.ticket-card__info-item--wide {
    grid-column: 1 / -1;
}

/* Praktische informatie/Jouw gegevens: nu EIGEN, losstaande donkere
   kaarten ONDER het ticket-object (mockup 1g), niet langer een sectie
   BINNEN .ticket-card - vandaar een eigen achtergrond/radius/schaduw
   i.p.v. simpelweg op .ticket-card's cascade te leunen. */
.ticket-card__practical {
    margin-top: 16px;
    padding: 20px 22px;
    background: #16161d;
    border-radius: var(--radius-lg);
    text-align: left;
    color: #ffffff;
}

.ticket-card__practical h3 {
    color: #ffffff;
    margin: 0 0 10px;
}

/* Volle-breedte witte pil-actieknop (mockup 1g) - blijft functioneel de
   bestaande "Ticket downloaden (PDF)"-actie, alleen visueel in de
   onderste-actie-rol van het ticket geplaatst. */
.ticket-card__pdf-btn {
    display: block;
    width: 100%;
    box-sizing: border-box;
    margin-top: 16px;
    text-align: center;
    background: #ffffff;
    color: var(--ink);
    border-color: #ffffff;
}

.ticket-card__pdf-btn:hover {
    filter: brightness(0.94);
}

/* FASE E6G.2 - "Ticketgegevens wijzigen": secundair t.o.v. de witte
   PDF-knop erboven - omlijnd, licht op de donkere ticketpagina. */
.ticket-card__edit-btn {
    display: block;
    width: 100%;
    box-sizing: border-box;
    margin-top: 10px;
    text-align: center;
    background: transparent;
    color: #ffffff;
    border-color: rgba(255, 255, 255, 0.45);
}

.ticket-card__edit-btn:hover {
    border-color: #ffffff;
}

/* VF-1g (screenshot-driven e-ticket rebuild): de kaart blijft op ELKE
   breedte staand/portrait (mockup 1g - decisions L/M: geen desktop-
   dashboard, geen liggende kaart) - de eerdere liggende-indeling-op-
   tablet/desktop-fix (klantbeslissing 2026-08-06) en de bijbehorende
   systeem-donkere-modus-tint (die een ANDER kleurenschema gaf dan de
   kaart nu altijd al heeft) zijn hier bewust verwijderd i.p.v.
   overschreven: geen van beide had nog een doel na de herbouw naar één
   permanent donker kaartontwerp. .ticket-page's basisrooster (bovenaan
   dit bestandsdeel, ongewijzigd) toont meerdere staande kaarten al
   vanzelf naast elkaar zodra de viewport breed genoeg is.

   Standaard verborgen op scherm - moet VOOR @media print hieronder staan
   zodat de "display: block" daarbinnen bij gelijke specificiteit wint
   (CSS-cascade: bij een gelijkspel wint de regel die het laatst in het
   bestand staat). Zie ook de uitgebreide toelichting bij .print-ticket
   verderop in dit bestand. */
.print-only {
    display: none;
}

@media print {
    .no-print {
        display: none !important;
    }

    .site-header,
    .site-footer {
        display: none !important;
    }

    /* Bugfix (klantmelding 2026-08-09, "3 pagina's i.p.v. 1"): body/.page
       gebruiken op scherm een "sticky footer"-flex-truc
       (min-height:100vh + flex:1 0 auto, zie hun basisregels hierboven)
       zodat de voettekst altijd onderaan het scherm blijft plakken. Dat
       botst bij het printen met .print-ticket hieronder (die zelf ook
       een vaste hoogte krijgt): de twee "min-height"-eisen stapelen dan
       op, plus .page's eigen padding (32px+64px) komt er nog eens
       bovenop - samen ruim genoeg om over te lopen naar 2-3 pagina's.
       Bij het printen is die scherm-truc sowieso zinloos (er is geen
       viewport), dus gewoon helemaal uitzetten. */
    body {
        background: #ffffff !important;
        color: #101014 !important;
        display: block;
        min-height: 0;
    }

    .page {
        display: block;
        padding: 0;
        max-width: none;
        flex: none;
    }

    .page-header {
        display: none;
    }

    .ticket-page {
        display: block;
        grid-template-columns: 1fr;
        margin: 0;
    }

    /* Flyer-herontwerp (klantbeslissing 2026-08-09): het printblok
       (.print-ticket, hieronder na dit @media print-blok) vervangt de
       schermkaart bij het printen - nooit allebei tegelijk zichtbaar.
       De kleur-strip-regels verderop in dit blok voor .ticket-card__*
       worden hierdoor dode code (die elementen zijn al helemaal
       verborgen), maar blijven bewust staan i.p.v. opgeruimd - geen
       risico, en scheelt een grotere diff. */
    .ticket-card {
        display: none !important;
    }

    .print-only {
        display: block;
    }

    /* Site-navigatie/-voettekst/pagina-titel weg bij printen (niet
       alleen voor het ticket - overal zinloos op papier), nodig zodat
       .print-ticket hieronder de volledige pagina kan vullen i.p.v. te
       moeten delen met kopregel/voettekst/titel eromheen.
       Vaste mm-hoogte i.p.v. min-height:100vh (bugfix, zie hierboven bij
       body/.page) - 297mm (A4) min 2x de @page-marge (12mm, zie
       helemaal onderaan dit bestand) = exact één pagina hoog, ongeacht
       hoe de browser vh tijdens printen interpreteert.
       Bugfix (klantmelding 2026-08-09, PDF-test): display:flex +
       margin-top:auto om de strook onderin te duwen werkte op scherm
       prima, maar printpaginering van een flex-container is browser-
       ondersteuning die niet goed gespecificeerd is - zodra de totale
       hoogte ook maar iets over de paginagrens ging, verhuisde niet de
       overtollige tekst maar het HELE laatste flex-kind (de
       strook+logo) in zijn geheel naar een 2e, verder lege pagina.
       position:relative + de strook/logo hieronder absoluut
       gepositioneerd (.print-ticket__bottom) i.p.v. flex is stabieler:
       dat is één ondeelbaar geplakt vlak, geen "content die ergens moet
       breken". Bewust min-height (geen vaste height + overflow:hidden,
       dat was een eerdere tussenstap) - bij een uitzonderlijk lange
       praktische-informatietekst mag de kaart best over 297mm heen
       groeien en eventueel op een 2e pagina doorlopen, want een vaste
       hoogte met overflow:hidden knipt bij te veel inhoud stilletjes
       zowel het einde van de tekst als de hele strook+QR+logo eraf -
       een lege plek waar de organisatie niets van merkt totdat een
       bezoeker met een niet-scanbaar ticket voor de deur staat. Content
       nooit verliezen weegt zwaarder dan altijd exact 1 pagina.
       padding-bottom reserveert vaste ruimte voor .print-ticket__bottom
       (absoluut gepositioneerd, telt zelf niet mee in de flow-hoogte) -
       zonder deze reservering overlapt de strook+logo de praktische
       informatie zodra die net te lang is om nog in de resterende
       ruimte onder min-height te passen (gemeten: strook+logo ~52mm
       hoog bij 1 regel evenementnaam, 58mm geeft marge voor een langere
       naam die naar 2 regels omslaat). */
    .print-ticket {
        position: relative;
        min-height: 273mm;
        padding-bottom: 58mm;
    }

    .print-ticket__bottom {
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
    }

    .ticket-card {
        box-shadow: none;
        border: 1px solid #101014;
        background: #ffffff !important;
    }

    /* Geen gekleurde vlakken op papier - onnodig inktverbruik, en de
       merkkleur van de organisatie is niet altijd goed leesbaar/afdrukbaar. */
    .ticket-card__header {
        background: #ffffff !important;
        color: #101014 !important;
        border-bottom: 1px solid #101014;
    }

    .ticket-card__header h2 {
        color: #101014 !important;
    }

    .ticket-card__holder {
        border-top-color: #101014 !important;
    }

    .ticket-card__divider {
        display: none;
    }

    .ticket-card__qr-panel {
        box-shadow: none;
        border-color: #101014 !important;
    }

    .ticket-card__practical {
        border-color: #101014 !important;
    }

    .ticket-card__qr {
        width: 260px;
    }

    .ticket-stub {
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: 16px;
        margin-top: 12px;
        border-top: 2px dashed #101014;
        padding: 16px 24px;
    }

    .ticket-stub__qr {
        width: 90px;
        flex-shrink: 0;
    }
}

/* ---------------------------------------------------------------------
   Printbaar ticket - flyerontwerp (klantbeslissing 2026-08-09, op basis
   van een aangeleverde referentieafbeelding). Losstaand van .ticket-card
   hierboven (die blijft de mobiele/scherm-kaart, ongewijzigd) -
   .print-only zorgt dat dit blok alleen bij het printen zichtbaar wordt,
   .ticket-card wordt dan juist verborgen (@media print hierboven), zodat
   er nooit twee varianten tegelijk op papier komen. De basisregel
   ".print-only { display: none; }" staat bewust VOOR het @media
   print-blok hierboven (i.p.v. hier) - bugfix (klantmelding 2026-08-09):
   met gelijke specificiteit wint bij het printen de regel die het laatst
   in het bestand staat, en die stond eerst per ongeluk hier, ná de
   "display: block" binnen @media print, waardoor het printblok nooit
   zichtbaar werd.
   --------------------------------------------------------------------- */

.print-ticket {
    font-family: var(--font-sans);
    color: var(--ink);
    background: #ffffff;
    border: 2px solid var(--brand);
    border-radius: var(--radius-lg);
    overflow: hidden;
    break-inside: avoid;
    page-break-inside: avoid;
    /* Forceert kleurvlakken/achtergrondafbeeldingen bij het printen, ook
       als de browserinstelling "Achtergrondafbeeldingen" uitstaat -
       zonder dit printen de meeste browsers de paarse tips-vlak
       hieronder gewoon blanco/wit. De foto zelf heeft dit niet nodig
       (dat is een echte <img>, geen CSS-achtergrond - die print altijd
       mee), maar deze regel op de hele kaart dekt ook de paarse
       tips-box en de lichte stub-achtergrond in één keer af. */
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
}

.print-ticket__photo {
    position: relative;
    height: 60mm;
    background: linear-gradient(135deg, var(--brand) 0%, color-mix(in srgb, var(--brand) 65%, #140b2e) 100%);
}

.print-ticket__photo-img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    filter: saturate(0.55) sepia(0.35) hue-rotate(200deg);
}

/* Zelfde scrim-verloop als .event-hero__scrim op de ticketshop
   (hierboven in dit bestand) - donker onderin voor leesbare witte
   tekst, lichter bovenin zodat de foto zelf nog zichtbaar blijft. */
.print-ticket__photo-scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(16, 16, 30, 0.15) 0%, rgba(16, 16, 30, 0.1) 35%, rgba(16, 16, 30, 0.85) 100%);
}

.print-ticket__photo-content {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 6mm 40mm 5mm 8mm;
    color: #ffffff;
    box-sizing: border-box;
}

.print-ticket__photo-title {
    margin: 0 0 2mm;
    font-family: var(--font-display);
    font-size: 1.5rem;
    line-height: 1.1;
}

.print-ticket__photo-meta {
    margin: 0;
    font-size: 0.92rem;
    font-weight: 600;
    opacity: 0.9;
}

.print-ticket__qr-box {
    position: absolute;
    top: 50%;
    right: 8mm;
    transform: translateY(-50%);
    width: 30mm;
    height: 30mm;
    background: #ffffff;
    border-radius: var(--radius-lg);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 3mm;
    box-sizing: border-box;
}

.print-ticket__qr-box svg {
    display: block;
    width: 100%;
    height: auto;
}

.print-ticket__body {
    padding: 8mm 10mm;
    border-left: 4px solid var(--accent);
    margin: 6mm 8mm 0;
}

.print-ticket__visitor-name {
    margin: 0 0 3mm;
    font-family: var(--font-display);
    font-size: 1.7rem;
    line-height: 1.15;
}

.print-ticket__visitor-type {
    margin: 0;
    font-size: 0.88rem;
    color: var(--muted);
}

/* Meer lucht tussen het goudaccent-blok (naam/type) en de daaropvolgende
   Praktische informatie/Jouw gegevens-sectie, en de dunne lijn ertussen
   mag weg (klantverzoek 2026-08-09) - alleen binnen .print-ticket:
   .ticket-card__practical is een gedeelde class met de schermkaart, die
   blijft daar bewust ongewijzigd (heeft de lijn nog wel nodig). */
.print-ticket .ticket-card__practical {
    border-top: none;
    margin-top: 10mm;
}

.print-ticket__stub {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin: 0;
    border-top: 2px dashed #101014;
    padding: 6mm 8mm;
}

.print-ticket__stub-qr {
    width: 24mm;
    flex-shrink: 0;
}

.print-ticket__stub-qr svg {
    display: block;
    width: 100%;
    height: auto;
}

.print-ticket__footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding: 4mm 8mm 8mm;
}

.print-ticket__footer-logo {
    max-height: 28px;
    max-width: 160px;
}

/* .logo-mark/.logo-text zijn standaard voor een gekleurde/donkere
   achtergrond gebouwd (wit) - net als .site-header__logo-pill en
   .dashboard-topbar__logo elders in dit bestand hun eigen donkere
   variant scopen, doet de flyer-footer (witte achtergrond) dat hier
   ook, anders zijn de logo-balkjes onzichtbaar (wit-op-wit). */
.print-ticket__footer .logo-mark--dark span {
    background: var(--ink);
}

.print-ticket__footer .logo-mark {
    height: 16px;
}

.print-ticket__footer .logo-text--dark {
    color: var(--ink);
    font-size: 0.85rem;
}

@page {
    margin: 12mm;
}

/* ---------------------------------------------------------------------
   Sleutel-weergave (2FA-secret, ticketcodes)
   --------------------------------------------------------------------- */

.secret-key {
    display: inline-block;
    font-family: var(--font-mono);
    background: var(--surface-alt);
    border: 1px dashed var(--border);
    padding: 10px 14px;
    border-radius: var(--radius);
    letter-spacing: 0.04em;
    word-break: break-all;
}

@media (min-width: 640px) {
    /* :not(.page--full) toegevoegd (1c full-journey shell correction) -
       .page--full wordt uitsluitend door de nieuwe .buyer-shell-koperspagina's
       gebruikt (EventStorefrontController), die zelf al met $hideHeaderPill
       geen site-header meer tonen; deze padding-top liet daar 48px lege
       ruimte bovenaan het linker eventpaneel ontstaan (screenshotbevinding
       "geen grote lege canvasruimte boven/onder"). Alle andere .page-
       pagina's (zonder --full) behouden deze marge ongewijzigd. */
    .page:not(.page--full) {
        padding-top: 48px;
    }

    h1 {
        font-size: 2.2rem;
    }
}

/* ---------------------------------------------------------------------
   Scanscherm (hoofdstuk 4.7) - losse, minimale pagina (geen site-chrome),
   achtergrond in klantkleur. Bewust hoog contrast en grote knoppen/tekst:
   dit scherm wordt op een tablet/telefoon bij de deur gebruikt, vaak in
   fel licht en onder tijdsdruk.
   --------------------------------------------------------------------- */

.scan-body {
    margin: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    font-family: var(--font-sans);
    /* Ondoorzichtige achtergrond i.p.v. de standaard (lichte)
       body-achtergrond hierboven laten doorschemeren (klantmelding
       2026-08-21: de bovenkant van het scanscherm oogde mintgroen/te
       licht) - de kind-elementen hieronder mixen hun merkkleurtint tegen
       DEZE donkere kleur i.p.v. tegen transparent, maar dit is het
       vangnet voor elk stukje dat toch nog blootligt (bijv. tijdens de
       overgang tussen tabs). */
    background: #0f0f16;
    /* touch-action: manipulation staat al op de algemene body-regel. */
}

/* UI-3 (scannerredesign, punt 9): scanner-login/-evenementkeuze lopen nog
   gewoon via View::render(..., narrow: true) (gewone lichte paginaromp,
   .card/.login-tabs/.field ongewijzigd qua markup/CSRF/formulier) - alleen
   de kaart zelf (ScanController::renderLoginPage()) krijgt hier een
   scanner-donkere opmaak, zodat inloggen al aanvoelt als het begin van de
   donkere operationele scanomgeving i.p.v. een generiek platformformulier.
   Bewust GEEN kopie van .scan-body/de merkkleur-gradient (die kleur is pas
   bekend NA het invullen van de klantnaam) - een effen donkere kaart is
   hier voldoende en simpeler. */
.scan-login-card {
    background: #14141f;
    border-radius: var(--radius-panel);
    padding: 28px 24px;
    color: #ffffff;
}

.scan-login-card h2 {
    color: #ffffff;
}

.scan-login-card .hint {
    color: rgba(255, 255, 255, 0.62);
}

.scan-login-card a {
    color: var(--accent, #ffc80a);
}

/* De kaart zelf is nu .scan-login-card - een geneste .card zou een
   kaart-in-kaart-dubbeling geven (zelfde aanpak als .auth-shell__form
   .card in de UI-2-loginshell). */
.scan-login-card .card {
    background: transparent;
    border: none;
    box-shadow: none;
    padding: 0;
    margin-bottom: 24px;
}

.scan-login-card .card:last-child {
    margin-bottom: 0;
}

.scan-login-card .login-tabs__tab {
    background: rgba(255, 255, 255, 0.08);
    color: rgba(255, 255, 255, 0.7);
}

.scan-login-card .login-tabs__tab--active {
    background: var(--brand);
    color: #ffffff;
}

/* Scannen-tab (04 Scanapp - collage): donkere achtergrond die de eigen
   merkkleur van de organisatie behoudt via color-mix() i.p.v. platte
   achtergrondkleur (was: background-color: var(--scan-color) direct op
   body). Herzien 2026-08-21: color-mix(...,  transparent) liet de LICHTE
   standaard-bodyachtergrond erdoorheen schemeren (klantmelding "nog niet
   donker genoeg"/"mintgroen") - nu mixt elke stop tegen de eigen donkere
   basiskleur i.p.v. tegen transparent, dus altijd 100% dekkend.
   flex: 1 i.p.v. min-height:100vh (was hard vastgezet, waardoor de
   voettekst hieronder altijd een extra volledige schermhoogte verderop
   stond) - binnen .scan-body (flex-kolom, min-height:100vh) vult dit nu
   automatisch de ruimte BOVEN de voettekst, en op mobiel (voettekst
   display:none) nog steeds de volledige hoogte, want het is dan het
   enige zichtbare flex-kind. */
.scan-tab-scannen {
    width: 100%;
    flex: 1;
    position: relative;
    /* 4a/4b fidelity-correctie: display:flex + align/justify:center hier
       (i.p.v. min-height:100% + justify-content:center op .scan-app zelf,
       gevonden bug bij live runtime-test) - een percentage-hoogte op een
       kind resolvet onbetrouwbaar tegen een ouder wiens eigen hoogte via
       flex:1 tot stand komt, waardoor .scan-app terugviel op zijn eigen,
       kortere inhoudshoogte en bovenaan bleef "plakken" i.p.v. verticaal
       gecentreerd te worden. Deze ouder centreren is de standaard,
       betrouwbare flex-aanpak - .scan-app zelf heeft geen min-height meer
       nodig. */
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(
        180deg,
        color-mix(in srgb, var(--scan-color, var(--brand)) 28%, #0f0f16) 0%,
        color-mix(in srgb, var(--scan-color, var(--brand)) 6%, #0f0f16) 55%,
        #0f0f16 100%
    );
    transition: background 0.2s ease;
}

/* Sobere voettekst, alleen op desktopbreedte (klantverzoek 2026-08-20:
   "onderin bij de desktop moet de footer ook in beeld zijn, alleen dan
   niet de linkjes naar de algemene voorwaarden") - .scan-body wordt
   hieronder een kolom i.p.v. een enkele gecentreerde rij, zodat deze
   footer gewoon als volgend blok ONDER .scan-tab-scannen verschijnt.
   Verborgen op mobiel: daar is dit scherm bewust 1 beeldvullende
   kiosk-pagina en heeft de zwevende tabbalk al de onderkant in gebruik. */
.scan-footer {
    display: none;
    width: 100%;
    box-sizing: border-box;
    background: #101014;
    padding: 20px 32px;
}

@media (min-width: 900px) {
    .scan-footer {
        display: block;
    }
}

.scan-footer__inner {
    max-width: 1600px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: 12px;
}

.scan-footer__label {
    color: rgba(255, 255, 255, 0.6);
    font-size: 0.82rem;
}

.scan-footer__logo {
    display: block;
    max-height: 32px;
    max-width: 180px;
}

/* QR-kader (collage "04 Scanapp") - visuele scan-affordance. Op mobiel
   verschijnt hierin ook het live camerabeeld zodra de camera aan staat
   (zie .scan-viewfinder__video); op desktop/tablet is er geen camera
   (isMobilePhone() in scan.js) en verdwijnt het kader zelf via de
   --plain-variant hieronder, want een leeg decoratief kader zonder
   functie oogt daar als een gat in de pagina. De resultaatkaart valt
   hier middenin, zowel in de wachtstand als na een scan. */
.scan-viewfinder {
    position: relative;
    width: 100%;
    max-width: 260px;
    aspect-ratio: 1 / 1;
    margin: 20px auto;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    border-radius: 24px;
}

.scan-viewfinder--plain {
    aspect-ratio: auto;
    max-width: 320px;
    overflow: visible;
}

.scan-viewfinder--plain .scan-viewfinder__corner,
.scan-viewfinder--plain .scan-viewfinder__scanline {
    display: none;
}

.scan-viewfinder__video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: 0;
}

.scan-viewfinder__corner {
    position: absolute;
    z-index: 2;
    width: 46px;
    height: 46px;
    border: 4px solid var(--scan-color, var(--brand));
    opacity: 0.85;
}

.scan-viewfinder__corner--tl {
    top: 0;
    left: 0;
    border-right: none;
    border-bottom: none;
    border-radius: 16px 0 0 0;
}

.scan-viewfinder__corner--tr {
    top: 0;
    right: 0;
    border-left: none;
    border-bottom: none;
    border-radius: 0 16px 0 0;
}

.scan-viewfinder__corner--bl {
    bottom: 0;
    left: 0;
    border-right: none;
    border-top: none;
    border-radius: 0 0 0 16px;
}

.scan-viewfinder__corner--br {
    bottom: 0;
    right: 0;
    border-left: none;
    border-top: none;
    border-radius: 0 0 16px 0;
}

.scan-viewfinder__scanline {
    position: absolute;
    z-index: 2;
    left: 8%;
    right: 8%;
    top: 50%;
    height: 2px;
    background: var(--accent, #ffc80a);
    box-shadow: 0 0 22px rgba(255, 200, 10, 0.7);
    animation: scan-line-move 2.4s ease-in-out infinite;
}

@keyframes scan-line-move {
    0%, 100% { top: 18%; }
    50% { top: 82%; }
}


/* Floating pil-navigatiebalk onderin (collage: "balk onderin = zelfde
   pil als de header, alleen onderaan") - zelfde vorm/gedrag als
   .pill-nav in het backend-dashboardschild (View.php), hier los
   gehouden omdat het scanscherm zijn eigen HTML-document is (geen
   gedeeld dashboardschild). --glass op de donkere Scannen-tab,
   --solid (effen donkere pil) op de lichte Bezoekers/Deurverkoop/
   Stats-tabs. */
/* Audit-fix (pre-launch P1-verificatie, "scanner tabbar 375px"): de
   vorige versie was een INTRINSIEK-brede pil (auto width, gecentreerd via
   left:50%/translateX(-50%)), begrensd door max-width met overflow-x:auto
   zodra de inhoud (tot 4 tabs: Scannen/Bezoekers/Stats/Deurverkoop) breder
   werd dan die max-width - de balk werd dan intern horizontaal
   scrollbaar, met als gevolg dat latere tabs (bijv. "Stats") buiten het
   zichtbare deel van de pil kwamen te staan (Codex mat op 375px:
   Stats-rect liep tot x≈415.9, ver buiten de 375px-viewport) i.p.v.
   gewoon zichtbaar/bereikbaar te zijn. Nu een ECHTE full-width balk
   (left/right-marges i.p.v. max-width+centrering) waarbinnen elk item
   via flex:1 een gelijk aandeel van de beschikbare breedte krijgt - geen
   interne scroll meer nodig, dus nooit meer een tab die buiten beeld
   staat, ongeacht hoeveel tabs er zijn. */
.scan-tab-bar {
    position: fixed;
    left: 12px;
    right: 12px;
    /* Audit-fix (pre-launch P1, "scanner mobile/tablet"): zonder de
       safe-area-inset kon de balk op een notch-/gebarenbalk-toestel
       (bijv. iPhone met homebar) net buiten het veilige viewport
       vallen/erdoorheen overlappen - .checkout-summary-toggle gebruikt
       dezelfde compensatie al elders in dit bestand. */
    bottom: calc(18px + env(safe-area-inset-bottom));
    z-index: 960;
    display: flex;
    gap: 4px;
    padding: 6px;
    border-radius: 999px;
    max-width: 420px;
    margin: 0 auto;
}

.scan-tab-bar--glass {
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.16);
    backdrop-filter: blur(18px);
    box-shadow: 0 12px 30px rgba(16, 16, 40, 0.28);
}

.scan-tab-bar--solid {
    background: rgba(16, 16, 22, 0.92);
    box-shadow: 0 12px 30px rgba(16, 16, 40, 0.28);
}

.scan-tab-bar__item {
    /* Audit-fix (pre-launch P1-verificatie, "scanner tabbar 375px"):
       flex:1 verdeelt de beschikbare breedte werkelijk gelijk over alle
       tabs (i.p.v. een intrinsieke breedte die kon overflowen) - min-width:0
       is noodzakelijk, anders weigert een flex-item onder zijn eigen
       inhoudsbreedte te krimpen en overflowt de balk alsnog. */
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding: 10px 8px;
    /* Audit-fix (pre-launch P1, "scanner mobile/tablet"): het
       oorspronkelijke padding+font-size-formaat kwam op circa 36-41px
       hoogte uit - onder de circa 44px-richtlijn voor touch targets.
       min-height garandeert dit ongeacht lettergrootte/regelhoogte. */
    min-height: 44px;
    border-radius: 999px;
    border: none;
    background: transparent;
    color: rgba(255, 255, 255, 0.66);
    font-weight: 600;
    font-size: 0.8rem;
    cursor: pointer;
}

/* Audit-fix (pre-launch P1-verificatie, "scanner tabbar 375px"): de balk
   is begrensd op max-width:420px (zie .scan-tab-bar) - pas vanaf een
   viewport van ruim boven de ~460px (24px marges + 420px) bereikt de
   balk die volledige, comfortabele breedte. Onder die grens (dus ook op
   375/390px, expliciet vereiste testbreedtes) is er met 4 tabs (incl.
   "Deurverkoop", het langste label) te weinig ruimte voor de losse
   dot-indicator naast de tekst - empirisch getest tot en met 320px met
   scrollWidth/clientWidth-metingen (geen enkele label meer afgekapt). De
   actieve tab blijft duidelijk via de witte pil-achtergrond
   (.scan-tab-bar__item--active) zelf, dus de dot is hier puur decoratief
   overtollig. */
@media (max-width: 460px) {
    .scan-tab-bar {
        gap: 2px;
        padding: 5px;
    }

    .scan-tab-bar__item {
        gap: 0;
        padding: 10px 2px;
        font-size: 0.66rem;
    }

    .scan-tab-bar__dot {
        display: none !important;
    }
}

.scan-tab-bar__item--active {
    background: #ffffff;
    color: #101014;
}

.scan-tab-bar__dot {
    display: none;
    width: 9px;
    height: 9px;
    border-radius: 3px;
    background: var(--brand, #5d5dff);
}

.scan-tab-bar__item--active .scan-tab-bar__dot {
    display: inline-block;
}

/* Bezoekerslijst/statistieken/deurverkoop als volwaardige, beeldvullende
   tabs (collage "04 Scanapp") i.p.v. een los pop-up-venster: dezelfde
   .scan-modal-elementen als voorheen, nu altijd beeldvullend zodat ze
   samen met de vaste tabbalk hierboven als "tab" aanvoelen. De
   backdrop-klik-logica (ScanApp.requestCloseModal) blijft functioneel
   bestaan maar is nooit meer zichtbaar, omdat het paneel er altijd
   overheen ligt. */
.scan-modal-backdrop {
    position: fixed;
    inset: 0;
    background: transparent;
    z-index: 900;
}

.scan-modal {
    position: fixed;
    inset: 0;
    z-index: 950;
    color: #ffffff;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    padding: 20px 20px 110px;
    overflow-y: auto;
}

/* Koppen erven color:#fff hierboven NIET (klantmelding 2026-08-21: titel
   bleef zwart) - de generieke h1,h2,h3-regel elders in dit bestand zet
   color:var(--brand-dark) rechtstreeks op het element zelf, en een
   expliciete regel wint altijd van een geërfde waarde, ongeacht de
   specificiteit van de ouder-selector. Dekt elke kop binnen elk
   scan-modal-paneel (Bezoekerslijst/Statistieken/Deurverkoop, incl. de
   kwitantie) in 1 keer af. */
.scan-modal h2,
.scan-modal h3 {
    color: #ffffff;
}

/* Echte donkere modus (klantmelding 2026-08-20: de eerdere lichte,
   pastelkleurige achtergrond was "niet mooi gedaan... eigenlijk te
   licht") - zelfde donkere basis als .scan-tab-scannen (de merkkleur
   vervaagt naar bijna-zwart), zodat Bezoekers/Statistieken/Deurverkoop
   er als 1 samenhangende, donkere app uitzien i.p.v. 1 donkere tab
   tussen 3 lichte pop-ups. De bestaande witte/lichttransparante kaarten
   (.scan-search-result, #scan-search-input, .scan-stats-table, ...)
   waren getuned op een lichte achtergrond met te weinig contrast - op
   deze donkere achtergrond springen ze er vanzelf juist wél uit, dus
   die kaart-CSS blijft ongewijzigd. Herzien 2026-08-21 (klantmelding: de
   Scannen-tab schemerde zichtbaar door de bovenkant van deze panelen
   heen) - color-mix(..., transparent) is NOOT 100% dekkend, dus wat
   eronder ligt (.scan-tab-scannen, altijd in de DOM, nooit verwijderd)
   bleef zichtbaar door de rand van dit paneel heen ondanks position:fixed
   + hogere z-index. Elke stop mixt nu tegen de eigen donkere basiskleur
   i.p.v. tegen transparent, dus altijd volledig dekkend. */
.scan-modal--bezoekers {
    background: linear-gradient(
        180deg,
        color-mix(in srgb, var(--scan-color, var(--brand)) 24%, #0f0f16) 0%,
        color-mix(in srgb, var(--scan-color, var(--brand)) 5%, #0f0f16) 55%,
        #0f0f16 100%
    );
}

.scan-modal--stats {
    background: linear-gradient(
        180deg,
        color-mix(in srgb, var(--scan-color, var(--brand)) 24%, #0f0f16) 0%,
        color-mix(in srgb, var(--scan-color, var(--brand)) 5%, #0f0f16) 55%,
        #0f0f16 100%
    );
}

.scan-modal--deurverkoop {
    background: linear-gradient(
        180deg,
        color-mix(in srgb, var(--scan-color, var(--brand)) 24%, #0f0f16) 0%,
        color-mix(in srgb, var(--scan-color, var(--brand)) 5%, #0f0f16) 55%,
        #0f0f16 100%
    );
}

@media (min-width: 640px) {
    .scan-modal {
        padding-left: max(20px, calc(50% - 260px));
        padding-right: max(20px, calc(50% - 260px));
    }
}

/* UI-3-bevinding (runtime-test, deurverkoop): .button--secondary is
   platformbreed een TRANSPARANTE knop met donkere tekst (bedoeld voor
   lichte pagina's) - op de donkere scan-modal-/scan-login-achtergrond
   werd "Contant"/"Annuleren"/"Uitloggen"/de evenementkeuze-knoppen
   daardoor onleesbaar (donkere tekst op transparant-over-donker). Alleen
   binnen deze twee donkere containers een lichte achtergrond geven -
   .button--secondary zelf blijft ongewijzigd voor de rest van het
   platform (koper-/organizer-pagina's). */
.scan-modal .button--secondary,
.scan-login-card .button--secondary {
    background: rgba(255, 255, 255, 0.85);
}

.scan-modal .button--secondary:hover,
.scan-login-card .button--secondary:hover {
    background: rgba(255, 255, 255, 1);
}

.scan-modal__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
}

.scan-modal__header h2 {
    margin: 0;
    font-size: 1.1rem;
    /* Expliciet i.p.v. inheritance (klantmelding 2026-08-21: titel bleef
       zwart) - de generieke h1,h2,h3-regel elders in dit bestand zet
       color:var(--brand-dark) rechtstreeks op het element zelf, en een
       expliciete regel wint altijd van een geërfde waarde, ongeacht de
       specificiteit van de ouder-selector (.scan-modal { color:#fff }
       hierboven kwam dus nooit aan bod). */
    color: #ffffff;
}

.scan-modal__header-actions {
    display: flex;
    gap: 8px;
}

.scan-modal__header-actions button {
    padding: 8px 12px;
    border-radius: var(--radius-pill, 999px);
    border: 1px solid var(--border);
    background: rgba(255, 255, 255, 0.7);
    color: var(--ink);
    cursor: pointer;
    font-weight: 600;
    font-size: 0.85rem;
}

.scan-modal__body {
    flex: 1;
    overflow-y: auto;
}

#scan-search-input {
    width: 100%;
    box-sizing: border-box;
    padding: 12px 16px;
    margin-bottom: 8px;
    border-radius: var(--radius-pill, 999px);
    border: 1px solid var(--border);
    background: rgba(255, 255, 255, 0.9);
    font-size: 1rem;
}

/* Overlay-melding bovenop de bezoekerslijst na het inchecken (i.p.v. de
   pop-up te sluiten - zo kun je meteen doorgaan met de rest van je
   zoekopdracht, hoofdstuk 4.7). */
.scan-toast {
    position: absolute;
    inset: 0;
    display: none;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 24px;
    font-size: 1.15rem;
    font-weight: 700;
    color: #ffffff;
    z-index: 5;
}

.scan-toast--success {
    background: rgba(41, 115, 79, 0.96);
}

.scan-toast--duplicate {
    background: rgba(179, 53, 43, 0.96);
}

/* Kleine laadindicator (deurverkoop, QR-betaling starten - hoofdstuk 4.8). */
.scan-spinner {
    display: inline-block;
    width: 18px;
    height: 18px;
    border: 3px solid rgba(0, 0, 0, 0.15);
    border-top-color: var(--brand, #5d5dff);
    border-radius: 50%;
    animation: scan-spin 0.8s linear infinite;
    vertical-align: middle;
    margin-right: 8px;
}

@keyframes scan-spin {
    to {
        transform: rotate(360deg);
    }
}

/* Handgeschreven SVG-grafieken (statistieken - hoofdstuk 4.9). */
.stats-chart {
    width: 100%;
    height: auto;
    margin-top: 8px;
}

.stats-chart__label {
    font-size: 11px;
    fill: var(--text-muted, #6b7280);
}

.stats-chart__legend {
    display: flex;
    gap: 16px;
    margin-top: 8px;
    font-size: 13px;
}

.stats-chart__legend-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.stats-chart__legend-swatch {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 2px;
}

.stats-chart rect,
.stats-chart circle {
    cursor: default;
}

.stats-chart rect:hover,
.stats-chart circle:hover {
    opacity: 0.75;
}

.stats-table-toggle {
    margin-top: 12px;
}

.stats-table-toggle summary {
    cursor: pointer;
    color: var(--brand, #5d5dff);
    font-size: 0.9rem;
}

.stats-table-toggle table {
    margin-top: 8px;
}

/* Eigen hover-tooltip voor de grafieken (ChartRenderer::tooltipScript())
   i.p.v. het native SVG <title>-element - dat heeft de eerste keer per
   element een trage OS-vertraging, deze verschijnt meteen. */
.stats-chart-tooltip {
    position: fixed;
    z-index: 100;
    transform: translate(-50%, calc(-100% - 10px));
    background: #101014;
    color: #fff;
    padding: 6px 10px;
    border-radius: 6px;
    font-size: 0.8rem;
    line-height: 1.3;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    visibility: hidden;
}

.stats-chart-tooltip--visible {
    opacity: 1;
    visibility: visible;
}

.scan-search-result {
    padding: 10px 14px;
    margin-bottom: 8px;
    border-radius: var(--radius-panel, 16px);
    background: rgba(255, 255, 255, 0.82);
    box-shadow: var(--shadow-card, 0 10px 30px rgba(20, 20, 60, 0.05));
    font-size: 0.9rem;
    /* Expliciet i.p.v. leunen op inheritance (klantmelding 2026-08-21:
       onleesbaar witte tekst op deze lichte kaart) - .scan-modal
       hierboven zet color:#fff voor de DONKERE modal-achtergrond zelf,
       maar deze kaart heeft zijn eigen lichte achtergrond en heeft dus
       zijn eigen (donkere) tekstkleur nodig, ongeacht wat de ouder zet. */
    color: var(--ink);
}

/* Klik op de naam/rij toont pas de actieknop (inchecken of ongedaan
   maken) - voorkomt een per ongeluk gemiste of dubbele tik, hoofdstuk 4.7. */
.scan-search-result__toggle {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 4px 0;
    border: none;
    background: none;
    text-align: left;
    cursor: pointer;
    font: inherit;
    color: inherit;
}

.scan-search-result__avatar {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 999px;
    background: var(--brand-light, #eeeaff);
    color: var(--brand, #5d5dff);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 0.8rem;
}

.scan-search-result__name {
    flex: 1;
}

.scan-search-result__actions {
    display: flex;
    gap: 8px;
    padding-top: 8px;
}

.scan-search-result__actions button {
    padding: 8px 14px;
    border-radius: var(--radius);
    border: none;
    cursor: pointer;
    font-weight: 600;
    flex-shrink: 0;
}

.scan-search-result__actions button[data-action="checkin"] {
    background: var(--brand);
    color: #ffffff;
}

.scan-search-result__actions button[data-action="revert"] {
    background: #b3352b;
    color: #ffffff;
}

.scan-search-result__actions button[data-action="cancel"] {
    background: var(--surface-alt);
    color: var(--ink);
}

/* Totaalkaart deurverkoop-formulier (collage: donkere samenvattingskaart
   boven de Contant/QR-knoppen). */
.scan-doorsale-total {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background: #101014;
    color: #ffffff;
    border-radius: var(--radius-panel, 16px);
    padding: 16px 18px;
    margin: 12px 0;
}

.scan-doorsale-total__label {
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.66);
}

.scan-doorsale-total__amount {
    font-size: 1.4rem;
    font-weight: 700;
}

/* UI-3 (scannerredesign): de knoppenrij/QR-weergave/kwitantie binnen het
   Deurverkoop-paneel had voorheen alleen generieke .button/.field-opmaak
   (geen eigen scan-doorsale-*-stijl) - hier gericht aangevuld, zonder de
   onderliggende betaal-/voorraadlogica (scan.js) aan te raken. */
.scan-doorsale__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 4px 0 12px;
}

.scan-doorsale__actions .button {
    flex: 1 1 calc(50% - 5px);
    min-height: 44px;
}

/* Contant vs. QR/Mollie moeten niet door elkaar gehaald kunnen worden
   (UI-3-eis) - "Contant" blijft de neutrale secundaire knopstijl,
   "QR betaling" krijgt bovenop de bestaande primary-knopstijl ook nog
   een klein icoon, zodat het onderscheid niet alleen op de knopkleur
   (die door tenant-huisstijl kan verschuiven) hoeft te steunen. */
#scan-doorsale-mollie-btn::before {
    content: "▦ ";
}

/* Witte kaart om de gegenereerde QR-code (qrcode.js) heen - de code zelf
   moet ook in fel entreelicht scherp scanbaar zijn tegen de donkere
   paneelachtergrond. */
#scan-doorsale-qr {
    display: flex;
    align-items: center;
    justify-content: center;
    background: #ffffff;
    border-radius: var(--radius-lg, 16px);
    padding: 16px;
    margin: 12px auto;
    width: fit-content;
    max-width: 100%;
}

/* qrcode.js levert createSvgTag({scalable:true}) - een <svg> ZONDER
   width/height-attributen, alleen een viewBox. Zonder expliciete
   CSS-breedte heeft zo'n svg geen intrinsieke maat en klapt hij als
   flex-item samen tot 0x0: de QR werd wel volledig gegenereerd, maar
   was onzichtbaar en de kaart eromheen bleef als leeg wit blokje van
   32x32 (2x16px padding) over. Zelfde oplossing als bij de e-ticket-
   en bestelpagina (.ticket-card__qr svg / .print-ticket__qr-box svg),
   die dit al goed deden. canvas/img blijven staan voor het geval de
   encoder ooit weer een raster-QR levert. */
#scan-doorsale-qr svg,
#scan-doorsale-qr canvas,
#scan-doorsale-qr img {
    display: block;
    width: min(220px, 60vw);
    max-width: 220px;
    height: auto;
}

/* Wachten-op-betaling-tekst iets sterker dan gewone paragraaftekst -
   dit is de status waar de deurverkoper het langst naar kijkt. */
#scan-doorsale-mollie-status {
    font-weight: 700;
    font-size: 1.05rem;
}

#scan-doorsale-cancel-mollie-btn,
#scan-doorsale-cancel-mollie-btn-2 {
    opacity: 0.85;
}

/* Kwitantie-ticketlijst (renderDoorSaleReceipt() in scan.js) - lichte
   rijen op de donkere paneelachtergrond, zelfde "kaart springt eruit"-
   aanpak als .scan-search-result elders in dit bestand. */
.scan-doorsale-tickets {
    list-style: none;
    margin: 12px 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.scan-doorsale-tickets li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    background: rgba(255, 255, 255, 0.96);
    border-radius: var(--radius, 10px);
    padding: 10px 14px;
}

.scan-doorsale-ticket-code {
    font-family: var(--font-mono);
    font-size: 0.92rem;
    color: var(--ink);
}

.scan-doorsale-ticket-checkin {
    flex: none;
    min-height: 44px;
    padding: 8px 16px;
    border-radius: var(--radius-pill, 999px);
    border: none;
    background: var(--brand);
    color: #ffffff;
    font-weight: 600;
    cursor: pointer;
}

.scan-doorsale-ticket-checkin:disabled {
    background: var(--success, #1f7a5a);
    opacity: 1;
    cursor: default;
}

/* Staafdiagram incheck-verloop op het statistieken-tabblad van de
   scan-app (klantverzoek 2026-08-20: per 15/30/60 minuten, met knoppen om
   te schakelen) - bewust simpele HTML/CSS-staven i.p.v. de SVG-
   ChartRenderer van de organisatie-statistiekenpagina's (.stats-chart
   hierboven): dit scherm is al volledig JS-gedreven, geen server-render-
   rondje nodig voor zoiets eenvoudigs. Zelfde "witte kaart op donkere
   achtergrond"-aanpak als .scan-stats-table hieronder. */
.scan-stats-chart__title {
    margin: 0 0 10px;
    font-size: 1rem;
    /* Zelfde inheritance-bug als .scan-modal__header h2 hierboven - deze
       h3 zit op de donkere modal-achtergrond zelf (niet op de lichte
       kaart eronder), dus moet ook expliciet wit zijn. */
    color: #ffffff;
}

.scan-stats-interval-toggle {
    display: flex;
    gap: 4px;
    margin-bottom: 12px;
    padding: 4px;
    background: rgba(255, 255, 255, 0.1);
    border-radius: var(--radius-pill, 999px);
    width: fit-content;
}

.scan-stats-interval-toggle__item {
    padding: 6px 14px;
    border: none;
    border-radius: var(--radius-pill, 999px);
    background: transparent;
    color: rgba(255, 255, 255, 0.7);
    font-weight: 600;
    font-size: 0.82rem;
    cursor: pointer;
}

.scan-stats-interval-toggle__item--active {
    background: #ffffff;
    color: #101014;
}

.scan-stats-chart {
    background: rgba(255, 255, 255, 0.85);
    border-radius: var(--radius-panel, 16px);
    box-shadow: var(--shadow-card, 0 10px 30px rgba(20, 20, 60, 0.05));
    padding: 16px 14px 10px;
    margin-bottom: 20px;
}

.scan-stats-chart__bars {
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 120px;
}

.scan-stats-chart__bar-wrap {
    flex: 1;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
}

.scan-stats-chart__bar {
    width: 100%;
    min-height: 0;
    background: var(--brand, #5d5dff);
    border-radius: 3px 3px 0 0;
}

/* Aantal incheckingen zichtbaar boven de staaf (klantverzoek 2026-08-21) -
   niet alleen als hover-tooltip, die is op een touchscreen sowieso niet
   bruikbaar. */
.scan-stats-chart__bar-count {
    font-size: 0.68rem;
    font-weight: 700;
    color: var(--ink);
    margin-bottom: 2px;
    line-height: 1;
}

.scan-stats-chart__labels {
    display: flex;
    justify-content: space-between;
    margin-top: 8px;
    font-size: 0.75rem;
    color: var(--muted);
}

/* Schermvullende scanresultaat-overlay (hoofdstuk 4.7) - gedeeld door
   zowel het typte/hardware-scanner-pad als het camera-scanpad (zie
   ScanApp.showResult() in scan.js): één volledig kleurvlak over de
   HELE viewport (los van de 480px-brede .scan-screen-kolom, ook op
   desktop) is nodig omdat een kleursignaal op de resultaatkaart of de
   achtergrond van de tab bleek te subtiel te zijn voor deurpersoneel
   dat in een oogopslag, snel achter elkaar, moet zien of een scan goed
   of fout was. Staat boven de tabbalk (z-index 960) en alle panelen. */
.scan-result-overlay {
    position: fixed;
    inset: 0;
    z-index: 980;
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 28px;
    padding: 40px 24px;
    text-align: center;
    color: #ffffff;
    animation: scan-result-pop 0.18s ease-out;
}

.scan-result-overlay--success {
    background: var(--success, #1f7a5a);
}

/* UI-3 (scannerredesign, belangrijkste bevinding): "al gescand" en
   "ongeldig" deelden voorheen dezelfde rode achtergrond (#b3352b) - voor
   deurpersoneel dat in een oogopslag moet zien of een bezoeker een
   TWEEDE keer binnenkomt (mogelijk fraude/dubbel gebruik) versus een
   ticket dat helemaal niet bestaat, is dat te verwarrend. "Al gescand"
   krijgt nu de bestaande --warning-kleur (amber, al gebruikt voor
   waarschuwingsbadges/-meldingen elders op het platform) i.p.v. rood -
   duidelijk anders dan zowel het groene "geldig" als het rode
   "ongeldig", zonder een nieuwe kleur te verzinnen. */
.scan-result-overlay--duplicate {
    background: var(--warning, #8a6800);
}

.scan-result-overlay--invalid {
    background: #b3352b;
}

/* Groot icoon/symbool (scan.js se showResult()) - communiceert de status
   ook zonder op kleur te vertrouwen (WCAG "niet uitsluitend via kleur"),
   en is het "in een fractie van een seconde begrijpen"-signaal dat de
   UI-3-opdracht vraagt. aria-hidden in de markup zelf (puur decoratief,
   de tekst eronder blijft de echte statusmelding voor schermlezers). */
.scan-result-overlay__icon {
    font-size: 4.5rem;
    line-height: 1;
    font-weight: 700;
}

.scan-result-overlay__content {
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.35;
}

.scan-result-overlay__content p {
    margin: 0 0 6px;
}

.scan-result-overlay__continue {
    padding: 16px 40px;
    border-radius: var(--radius-pill, 999px);
    border: none;
    background: rgba(255, 255, 255, 0.18);
    color: #ffffff;
    font-weight: 700;
    font-size: 1.05rem;
    cursor: pointer;
}

@keyframes scan-result-pop {
    from {
        transform: scale(0.94);
        opacity: 0;
    }
    to {
        transform: scale(1);
        opacity: 1;
    }
}

/* Camerabeeld (optioneel, naast typen/hardware-scanner) - leeft IN het
   viewfinder-kader zelf (.scan-viewfinder__video hierboven) i.p.v. een
   aparte fullscreen zwarte overlay, zodat de rest van het scherm
   (tabbalk, kop) zichtbaar blijft terwijl de camera aanstaat. Het
   scanresultaat zelf (geldig/dubbel/ongeldig) verschijnt via de
   gedeelde .scan-result-overlay hierboven. */
.scan-camera-controls {
    width: 100%;
    max-width: 260px;
    margin: 10px auto 0;
    padding: 0;
    display: flex;
    gap: 10px;
    justify-content: center;
}

.scan-camera-controls button {
    padding: 12px 24px;
    border-radius: var(--radius-pill, 999px);
    border: none;
    background: rgba(255, 255, 255, 0.92);
    color: var(--ink);
    font-weight: 600;
    cursor: pointer;
}

/* ---------------------------------------------------------------------
   4a/4b SCANNER FIDELITY CORRECTION - reverses the previous round's
   desktop sidebar/workspace direction entirely (explicitly rejected: a
   verticale navigatierail + brede lege workspace + losse content in het
   midden las als een admin-dashboard, niet als de compacte, sterke,
   donkere scan-app-identiteit uit mockup 4a). ALLE oude sidebar-CSS
   hierboven is verwijderd, niet aangepast.

   Nieuwe aanpak: EEN compacte, donkere "scan-app"-schil
   (.scan-app/.scan-app__*), gecentreerd in het bestaande volle-breedte/
   volle-hoogte .scan-tab-scannen-canvas, op ELKE viewportbreedte -
   mobiel en desktop delen dezelfde compositionele identiteit; alleen de
   schil zelf wordt op grotere breedtes een fractie ruimer (nooit de
   volledige viewport opvullend, nooit een sidebar/dashboardstructuur).
   De onderin-tabbalk blijft op ELKE breedte de navigatie (nu een echte
   platte donkere appbar i.p.v. een zwevende glaspil met een witte
   "geselecteerd"-vulling), niet een zijbalk.
   --------------------------------------------------------------------- */

/* .scan-app: de gecentreerde, compacte schil (identiek concept aan de
   oude .scan-screen, hier hernoemd omdat de interne opbouw - header/
   scanner/handmatige invoer - nu duidelijk in 3 blokken is opgeknipt
   i.p.v. 1 platte kolom kinderen). */
.scan-app {
    width: 100%;
    max-width: 420px;
    margin: 0 auto;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: 18px;
    padding: 20px 20px 130px;
    color: #ffffff;
}

/* Compacte operationele header (4a: eventnaam + context + status), i.p.v.
   het vorige "los groot eventlabel + zwevend groot tenantlogo". */
.scan-app__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.scan-app__header-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.scan-app__event-name {
    font-weight: 800;
    font-size: 1rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.scan-app__event-context {
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.6);
}

.scan-app__header-aside {
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
}

.scan-app__counter {
    font-size: 0.85rem;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.85);
    font-family: var(--font-mono, monospace);
}

/* Operator-acties (evenement wisselen/uitloggen) + tenantlogo: bewust
   klein/secundair in een compacte menuzone i.p.v. dominant tussen
   scanactie en navigatie in (screenshotbevinding "event-switch link,
   daarna pas tabbar"). */
.scan-app__header-menu {
    display: flex;
    align-items: center;
    gap: 8px;
}

.scan-app__header-menu form {
    margin: 0;
}

.scan-app__header-menu button {
    background: transparent;
    border: none;
    color: rgba(255, 255, 255, 0.55);
    font-size: 0.72rem;
    text-decoration: underline;
    cursor: pointer;
    padding: 4px;
}

/* Scanner-zone: het viewfinder-kader + de compacte instructietekst
   ERONDER (was: een groot wit instructie-/resultaatkaartje MIDDEN IN het
   kader - de screenshotbevinding "groot wit instructieblok in de
   viewfinder"). */
.scan-app__scanner {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
}

.scan-app__instruction {
    margin: 0;
    text-align: center;
    font-size: 0.92rem;
    color: rgba(255, 255, 255, 0.75);
}

/* Handmatige invoer: compact, rustig - geen "enorme witte lege balk"
   meer. BEWUST GEEN progressive-disclosure/verberg-toggle op #scan-input
   zelf (ondanks de opdracht se voorkeur daarvoor "wanneer veilig
   mogelijk"): de bestaande code (zie scan.js se armScanInput()-
   toelichting) bevestigt dat dit veld ook het doelveld is voor een
   fysieke/Bluetooth-barcodescanner die als toetsenbord in een GEFOCUST
   veld "typt" - een verborgen/niet-gefocust veld zou zo'n scanner
   stilzwijgend laten stoppen met werken. Alleen de VISUELE grootte/
   nadruk is verkleind, functioneel exact hetzelfde veld/gedrag. */
.scan-app__manual {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

#scan-input {
    width: 100%;
    box-sizing: border-box;
    font-size: 1rem;
    padding: 12px 16px;
    border-radius: var(--radius-pill, 999px);
    border: 1px solid rgba(255, 255, 255, 0.16);
    background: rgba(255, 255, 255, 0.08);
    color: #ffffff;
    text-align: center;
    margin: 0;
}

#scan-input::placeholder {
    color: rgba(255, 255, 255, 0.4);
}

#scan-input:focus {
    outline: none;
    border-color: var(--brand-interactive, #5d5dff);
    background: rgba(255, 255, 255, 0.12);
}

/* Camera/Toetsenbord: compacte secundaire acties naast elkaar i.p.v.
   twee enorme primaire pillen (screenshotbevinding). Functioneel
   ongewijzigd (zelfde IDs/click-handlers/verberg-logica in scan.js). */
.scan-app__quickactions {
    display: flex;
    gap: 8px;
}

.scan-app__quickactions button {
    flex: 1 1 0;
    padding: 10px 8px;
    border-radius: var(--radius-pill, 999px);
    border: 1px solid rgba(255, 255, 255, 0.14);
    background: rgba(255, 255, 255, 0.05);
    color: rgba(255, 255, 255, 0.8);
    font-weight: 600;
    font-size: 0.82rem;
    cursor: pointer;
}

/* ---------------------------------------------------------------------
   4b RESULT STATES - herbouwd van "platte kleuroverlay + losse <p>-
   regels" naar een echte, gestructureerde app-screen: icon -> headline
   -> (subline) -> detailcard -> actie. Zelfde overlay/element
   (.scan-result-overlay, altijd al schermvullend en dominant - dat
   deel klopte al) en dezelfde databron; alleen de INHOUD/opmaak van
   .scan-result-overlay__content is nu gestructureerd (zie scan.js
   buildResultCard()/showResult()).
   --------------------------------------------------------------------- */
.scan-result-overlay__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 96px;
    height: 96px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.16);
    font-size: 3rem;
    line-height: 1;
    font-weight: 700;
}

.scan-result-overlay__content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    width: 100%;
    max-width: 360px;
}

.scan-result__headline {
    margin: 0;
    color: #ffffff;
    font-size: 1.6rem;
    font-weight: 800;
}

.scan-result__subline {
    margin: 0 0 4px;
    font-size: 1rem;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.85);
}

.scan-result__card {
    width: 100%;
    box-sizing: border-box;
    margin-top: 10px;
    padding: 14px 16px;
    border-radius: var(--radius-panel, 16px);
    background: rgba(0, 0, 0, 0.18);
    text-align: left;
}

.scan-result__row {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 6px 0;
    font-size: 0.9rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

.scan-result__row:last-child {
    border-bottom: none;
}

.scan-result__row-label {
    color: rgba(255, 255, 255, 0.68);
}

.scan-result__row-value {
    font-weight: 700;
    text-align: right;
}

/* De "Volgende scannen"-actie (nu altijd zichtbaar, zie scan.js) als
   krachtige, witte primaire knop - mockup 4b se "grote witte 'Volgende
   scannen'-actie". */
.scan-result-overlay__continue {
    background: #ffffff;
    color: var(--ink);
}

/* ---------------------------------------------------------------------
   Tenantkleur is IDENTITY, niet interaction - de vorige, dominante
   28%/24%-kleurmenging bovenin elk scanscherm (screenshotbevinding
   "tenantkleur/burgundy domineert bijna de hele achtergrond") is
   teruggebracht tot een subtiele tint; het platform-paars is nu de
   scanner-interactiekleur (viewfinder-hoeken), consistent met de rest
   van het platform (--brand-interactive elders). Geen wijziging aan
   business-/scanlogica - puur kleurintensiteit/-bron.
   --------------------------------------------------------------------- */
.scan-tab-scannen {
    background: linear-gradient(
        180deg,
        color-mix(in srgb, var(--scan-color, var(--brand)) 10%, #0f0f16) 0%,
        color-mix(in srgb, var(--scan-color, var(--brand)) 3%, #0f0f16) 55%,
        #0f0f16 100%
    );
}

.scan-modal--bezoekers,
.scan-modal--stats,
.scan-modal--deurverkoop {
    background: linear-gradient(
        180deg,
        color-mix(in srgb, var(--scan-color, var(--brand)) 10%, #0f0f16) 0%,
        color-mix(in srgb, var(--scan-color, var(--brand)) 3%, #0f0f16) 55%,
        #0f0f16 100%
    );
}

.scan-viewfinder__corner {
    border-color: var(--brand-interactive, #5d5dff);
}

/* ---------------------------------------------------------------------
   Bottom navigation - platte, donkere appbar (4a) i.p.v. de zwevende
   glaspil met een witte "geselecteerd"-vulling. --glass/--solid blijven
   bestaande, harmless class-toggles vanuit scan.js (setActiveTab()) -
   allebei resolven nu naar dezelfde vlakke stijl, dus geen JS-wijziging
   nodig om dit verschil weg te nemen.
   --------------------------------------------------------------------- */
.scan-tab-bar,
.scan-tab-bar--glass,
.scan-tab-bar--solid {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    top: auto;
    z-index: 960;
    max-width: none;
    margin: 0;
    padding: 8px 8px calc(8px + env(safe-area-inset-bottom));
    border-radius: 0;
    background: #101014;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.35);
    backdrop-filter: none;
}

.scan-tab-bar__item {
    border-radius: var(--radius, 12px);
}

.scan-tab-bar__item--active {
    background: rgba(93, 93, 255, 0.18);
    color: #ffffff;
}

.scan-tab-bar__dot {
    background: var(--brand-interactive, #5d5dff);
}

/* ---------------------------------------------------------------------
   Tablet/desktop (>=768px): DEZELFDE scan-app-identiteit, bewust GEEN
   sidebar/dashboardstructuur. De schil mag iets ruimer, de tabbalk mag
   iets ruimer/gecentreerder - meer niet. .scan-tab-scannen zelf blijft
   het volle-viewport donkere canvas eromheen (sfeer, geen lege witruimte
   rond de app), .scan-app blijft de bewust begrensde, gecentreerde
   functionele kern erbinnen.
   --------------------------------------------------------------------- */
@media (min-width: 768px) {
    .scan-app {
        max-width: 480px;
        padding-bottom: 100px;
    }

    .scan-tab-bar {
        max-width: 560px;
        left: 50%;
        right: auto;
        transform: translateX(-50%);
        bottom: 20px;
        border-radius: 999px;
        border-top: none;
        box-shadow: 0 12px 30px rgba(16, 16, 40, 0.35);
    }
}

@media (min-width: 1024px) {
    .scan-app {
        max-width: 520px;
    }

    .scan-app__event-name {
        font-size: 1.05rem;
    }
}

/* .scan-footer wordt pas vanaf 900px zichtbaar (bestaande, ongewijzigde
   regel hierboven) - de zwevende tabbalk-pil (bottom:20px sinds 768px)
   overlapte 'm dan gedeeltelijk (live gemeten: tabbalk y 819-880 vs
   footer y 834-900 op 1024px - een echte overlap, niet aangenomen).
   Alleen vanaf hier de tabbalk hoger optillen zodat hij de voettekst
   ontwijkt. */
@media (min-width: 900px) {
    .scan-tab-bar {
        bottom: 90px;
    }
}

/* ---------------------------------------------------------------------
   FINAL SCREENSHOT-DRIVEN 4a/4b CORRECTION - de vorige ronde was zelf-
   gescoord op code/CSS-inspectie (9/10), maar echte screenshots (desktop
   + iPhone, door de klant zelf gemaakt) toonden 10 concrete, nog niet
   opgeloste problemen: een dwergformaat-app in een enorme lege desktop-
   viewport, een rommelige mobile header met afgekapt eventnaam en een
   zwevend tenantlogo tussen operationele acties, een te dominante
   viewfinder/invoer die Camera/Toetsenbord onder de vaste tabbalk
   drukte, een generieke segmented-control-tabbalk, en Bezoekers/Stats/
   Invalid die nog als platte legacy-schermen aanvoelden. Alle regels
   hieronder overschrijven gericht bovenstaande, eerder al toegevoegde
   4a/4b-regels (zelfde bewezen patroon in dit bestand: later-in-bestand
   wint bij gelijke specificiteit) - er is niets aan business-/scanlogica
   veranderd, uitsluitend presentatie.
   --------------------------------------------------------------------- */

/* --- 4/5: viewfinder-proporties + geklipte Camera/Toetsenbord -------
   Root cause (live gemeten op 390x560, realistische Safari-hoogte met
   zichtbare toolbar): de viewfinder had een VASTE max-width:260px
   (aspect-ratio 1/1 -> ook 260px hoog), ongeacht viewporthoogte. Op een
   korte viewport werd de totale .scan-app-inhoud (incl. de vaste 130px
   onderpadding die de tabbalk moest ontwijken) hoger dan de viewport
   zelf - de tabbalk blijft altijd op zijn vaste viewport-positie
   (position:fixed) staan, dus de laatste zichtbare rij (Camera/
   Toetsenbord, destijds y 501-539) kwam GEDEELTELIJK ONDER de tabbalk
   (y 498-560) te liggen: een echte, gemeten overlap, geen aanname. Een
   viewport-hoogte-afhankelijke max-width (min(260px, 34vh)) laat de
   viewfinder vanzelf meekrimpen op korte schermen, zodat de rest van de
   kolom (instructie/invoer/quickactions) altijd ruim boven de vaste
   tabbalk blijft - getest en herbevestigd na deze wijziging. */
.scan-viewfinder {
    max-width: min(260px, 34vh);
    margin: clamp(8px, 2.5vh, 20px) auto;
}

@media (max-height: 700px) {
    .scan-app {
        gap: 12px;
    }

    .scan-app__scanner {
        gap: 8px;
    }

    .scan-app__instruction {
        font-size: 0.85rem;
    }
}

/* Extra veiligheidsnet: op een toestel dat ondanks bovenstaande krimp
   toch nog te kort is, mag de pagina scrollen - maar dan moet scrollen
   ook echt de volledige inhoud tonen (geen dubbele, verborgen
   bodemruimte). overflow-y hier is een expliciete garantie, geen gok. */
.scan-tab-scannen {
    overflow-y: auto;
}

/* --- 2/3: mobile header herbouw - eventnaam kreeg te weinig breedte
   (moest delen met een logo-pil + 2 actielinks in dezelfde smalle
   kolom). header-aside krijgt hier minder gewicht zodat header-info
   (eventnaam) het merendeel van de breedte krijgt.
   Scanner functional completion (USER DECISION): het tenantlogo zelf is
   inmiddels volledig uit de scanner-UI gehaald (geen markup meer die
   .scan-app__tenant-logo/.scan-app__event-title gebruikt) - die twee
   klassen zijn hier bewust verwijderd i.p.v. als dode CSS achter te
   laten. */
.scan-app__header-info {
    flex: 1 1 auto;
}

.scan-app__header-aside {
    flex: 0 0 auto;
}

/* Secundaire operator-acties (evenement wisselen/uitloggen): nog kleiner/
   rustiger dan voorheen, staan nu niet meer naast een logo te concurreren
   om ruimte - puur nog "er zijn, indien nodig", niet prominent. */
.scan-app__header-menu {
    gap: 6px;
}

.scan-app__header-menu button {
    font-size: 0.68rem;
    color: rgba(255, 255, 255, 0.45);
}

/* --- 6: handmatige invoer iets rustiger/kleiner, met een duidelijk
   label zodat het zich presenteert als "de invoer-zone" i.p.v. de
   grootste/dominantste vorm op het scherm. Zelfde #scan-input-veld/id/
   focusgedrag/hardware-scanner-compatibiliteit, alleen visueel compacter. */
.scan-app__manual-label {
    display: block;
    margin: 0 0 -2px 6px;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: rgba(255, 255, 255, 0.4);
}

#scan-input {
    font-size: 0.92rem;
    padding: 10px 16px;
}

/* --- 7: tabbalk dichter naar 4a - het actieve item vulde voorheen de
   VOLLE breedte van zijn flex:1-slot met een paars vlak (las als een
   brede segmented control, screenshotbevinding). Nu krijgt een INNERLIJKE
   label-span de actieve achtergrond (fit-content, gecentreerd) i.p.v. de
   volledige buitenste knop - leest als een los, individueel "mode"-chipje
   i.p.v. een doorlopend geselecteerd segment. De buitenste knop blijft de
   volle 44px+ tikzone (toegankelijkheid ongewijzigd). */
.scan-tab-bar__item {
    background: transparent !important;
    padding: 4px;
}

.scan-tab-bar__item--active {
    background: transparent !important;
}

.scan-tab-bar__label {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 8px 14px;
    border-radius: 999px;
}

.scan-tab-bar__item--active .scan-tab-bar__label {
    background: rgba(93, 93, 255, 0.22);
    color: #ffffff;
}

@media (max-width: 460px) {
    .scan-tab-bar__label {
        padding: 8px 6px;
    }
}

/* --- 11/12/13/16: 4b result states waren nog een volledig effen
   groen/amber/rood vlak (.scan-result-overlay--success/--duplicate/
   --invalid zetten nog steeds een platte `background` direct op de
   schermvullende overlay, ongewijzigd sinds vóór de vorige ronde) - de
   screenshot van "Ongeldig" toonde letterlijk een volledig rood scherm.
   Nu: donkere basis (consistent met de rest van de scan-app), met een
   zachte, gecentreerde kleurtint als achtergrond (radial-gradient, zelfde
   color-mix-techniek als .scan-tab-scannen elders in dit bestand) i.p.v.
   een platte verzadigde kleur. De inhoud krijgt een eigen, afgebakende
   "shell"-kaart met een subtiele per-status randkleur en een getint
   icoon-badge - VALID/DUPLICATE/INVALID delen nu dezelfde structuur,
   alleen de tint/het icoon verschilt (geen wijziging aan welke data per
   status getoond wordt). */
.scan-result-overlay {
    background: #0f0f16;
}

.scan-result-overlay--success {
    background: radial-gradient(
        ellipse at 50% 32%,
        color-mix(in srgb, var(--success, #1f7a5a) 40%, #0f0f16) 0%,
        #0f0f16 70%
    );
}

.scan-result-overlay--duplicate {
    background: radial-gradient(
        ellipse at 50% 32%,
        color-mix(in srgb, var(--warning, #8a6800) 40%, #0f0f16) 0%,
        #0f0f16 70%
    );
}

.scan-result-overlay--invalid {
    background: radial-gradient(
        ellipse at 50% 32%,
        color-mix(in srgb, #b3352b 40%, #0f0f16) 0%,
        #0f0f16 70%
    );
}

.scan-result-overlay__content {
    background: rgba(255, 255, 255, 0.045);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 28px;
    padding: 32px 24px 28px;
}

.scan-result-overlay--success .scan-result-overlay__content {
    border-color: rgba(31, 122, 90, 0.5);
}

.scan-result-overlay--duplicate .scan-result-overlay__content {
    border-color: rgba(138, 104, 0, 0.5);
}

.scan-result-overlay--invalid .scan-result-overlay__content {
    border-color: rgba(179, 53, 43, 0.5);
}

.scan-result-overlay--success .scan-result-overlay__icon {
    background: rgba(31, 122, 90, 0.4);
    color: #8ff0c8;
}

.scan-result-overlay--duplicate .scan-result-overlay__icon {
    background: rgba(138, 104, 0, 0.4);
    color: #ffd873;
}

.scan-result-overlay--invalid .scan-result-overlay__icon {
    background: rgba(179, 53, 43, 0.4);
    color: #ff9c92;
}

/* --- 16: desktop result-scaling - was 1440px effen kleurvlak + een
   klein ~250px-kaartje in het midden. De shell-kaart schaalt nu mee. */
@media (min-width: 1024px) {
    .scan-result-overlay__content {
        max-width: 480px;
        padding: 44px 40px;
    }

    .scan-result-overlay__icon {
        width: 112px;
        height: 112px;
        font-size: 3.4rem;
    }

    .scan-result__headline {
        font-size: 2rem;
    }
}

@media (min-width: 1440px) {
    .scan-result-overlay__content {
        max-width: 560px;
        padding: 52px 48px;
    }
}

/* --- 1: desktop scanner scaling - was een 480-520px "mini-telefoon"
   midden in een lege 1440px-viewport (screenshotbevinding). Geen sidebar
   - wel een substantieel groter, zelfbewust "product-object": een eigen
   subtiele kaart (rand/schaduw/achtergrond) i.p.v. tekst die los in het
   donker zweeft, met een merkbaar grotere header/viewfinder/invoer. De
   tabbalk krijgt dezelfde max-width als de kaart, zodat navigatie en app
   optisch bij elkaar horen i.p.v. een smalle zwevende pil onder een
   bredere kaart. */
@media (min-width: 768px) {
    .scan-app {
        padding-top: 32px;
        background: rgba(255, 255, 255, 0.02);
        border: 1px solid rgba(255, 255, 255, 0.06);
        border-radius: 28px;
        box-shadow: 0 30px 70px rgba(0, 0, 0, 0.32);
    }

    .scan-tab-bar {
        width: 480px;
        max-width: 480px;
    }
}

@media (min-width: 1024px) {
    .scan-app {
        max-width: 640px;
        padding: 44px 52px 128px;
        gap: 28px;
        background: rgba(255, 255, 255, 0.025);
        border: 1px solid rgba(255, 255, 255, 0.08);
        border-radius: 32px;
        box-shadow: 0 40px 100px rgba(0, 0, 0, 0.4);
    }

    .scan-app__event-name {
        font-size: 1.3rem;
    }

    .scan-app__event-context {
        font-size: 0.92rem;
    }

    .scan-app__counter {
        font-size: 1.05rem;
    }

    .scan-viewfinder {
        max-width: min(320px, 34vh);
    }

    .scan-app__instruction {
        font-size: 1rem;
    }

    #scan-input {
        font-size: 1.05rem;
        padding: 14px 20px;
    }

    .scan-app__quickactions button {
        font-size: 0.9rem;
        padding: 12px 10px;
    }

    .scan-tab-bar {
        width: 640px;
        max-width: 640px;
    }
}

@media (min-width: 1440px) {
    .scan-app {
        max-width: 760px;
        padding: 52px 64px 136px;
    }

    .scan-viewfinder {
        max-width: min(360px, 36vh);
    }

    .scan-app__event-name {
        font-size: 1.5rem;
    }

    .scan-tab-bar {
        width: 760px;
        max-width: 760px;
    }
}

/* --- 8/9/10/12: Bezoekers/Stats voelden nog als losse legacy-pop-ups
   ("Sluiten" als grote primaire knop verraadt de oude overlay-
   architectuur). Kop wordt compacter/consistenter met .scan-app__header;
   "Sluiten" wordt een klein rond icoonknopje (bestaande id/click-handler
   ongewijzigd, alleen kleiner/visueel secundair) i.p.v. een brede
   tekstknop die naast de titel om aandacht concurreert. */
.scan-modal__header {
    padding-bottom: 12px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.scan-modal__header h2 {
    font-size: 1.05rem;
    font-weight: 800;
}

.scan-modal__close-btn {
    width: 32px;
    height: 32px;
    padding: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.08) !important;
    border: 1px solid rgba(255, 255, 255, 0.16);
    color: #ffffff !important;
    font-size: 1.1rem;
    line-height: 1;
}

/* Lege staten (Bezoekerslijst zonder resultaten, Stats zonder
   tickettypes/incheckingen) - was een losse <p>Geen resultaten.</p> op
   een verder leeg scherm (screenshotbevinding). Zelfde donkere-kaart-
   taal als de rest van de app-shell, geen nieuwe/verzonnen data. */
.scan-empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 56px 20px;
    text-align: center;
    color: rgba(255, 255, 255, 0.6);
}

.scan-empty-state--compact {
    padding: 24px 12px;
}

.scan-empty-state__icon {
    font-size: 2.2rem;
    opacity: 0.7;
}

.scan-empty-state__text {
    margin: 0;
    font-size: 0.92rem;
}

/* Statistieken: samenvattingskaart + per-tickettype-kaart met
   voortgangsbalk i.p.v. een kale <table> (screenshotbevinding "nog
   grotendeels een legacy/utility screen") - uitsluitend al bestaande,
   al opgehaalde checkedIn/total-waarden (zie scan.js renderStats()). */
.scan-stats-summary {
    display: flex;
    gap: 12px;
    margin-bottom: 16px;
}

.scan-stats-summary__card {
    flex: 1;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 16px;
    padding: 14px 16px;
}

.scan-stats-summary__value {
    font-size: 1.4rem;
    font-weight: 800;
}

.scan-stats-summary__label {
    font-size: 0.72rem;
    color: rgba(255, 255, 255, 0.55);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.scan-stats-cards {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.scan-stats-card {
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 16px;
    padding: 12px 16px;
}

.scan-stats-card__top {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 8px;
    gap: 10px;
}

.scan-stats-card__name {
    font-weight: 700;
    font-size: 0.95rem;
}

.scan-stats-card__count {
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.6);
    flex-shrink: 0;
}

.scan-stats-card__bar {
    height: 6px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.1);
    overflow: hidden;
}

.scan-stats-card__bar-fill {
    height: 100%;
    background: var(--brand-interactive, #5d5dff);
    border-radius: 999px;
}

/* Incheck-verloopgrafiek: was nog een lichte kaart (klantverzoek 2026-08-21
   voor de organisatie-statistiekenpagina's, hier ongewijzigd meegekomen) -
   deze klasse (.scan-stats-chart, met scan-prefix) wordt UITSLUITEND op dit
   scherm gebruikt, dus hier veilig om te zetten naar dezelfde donkere-kaart-
   taal als de rest van de app-shell, zonder de organisatiepagina's te raken. */
.scan-stats-chart {
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: none;
}

.scan-stats-chart__bar-count {
    color: rgba(255, 255, 255, 0.85);
}

.scan-stats-chart__labels {
    color: rgba(255, 255, 255, 0.5);
}

/* Bezoekers/Stats/Deurverkoop op desktop matchen dezelfde bredere kolom
   als .scan-app, i.p.v. de losse 640px-kaart (blijft daarnaast bestaan
   als bodybreedte-begrenzer via padding-left/right op .scan-modal). */
@media (min-width: 1024px) {
    .scan-modal {
        padding-left: max(20px, calc(50% - 320px));
        padding-right: max(20px, calc(50% - 320px));
    }
}

/* ---------------------------------------------------------------------
   SCANNER FUNCTIONAL COMPLETION - order drilldown (discovery C/D): een
   los, zichzelf-sluitend paneel BOVEN de Bezoekerslijst (hogere z-index
   dan .scan-modal, lager dan .scan-result-overlay) - geen eigen tabbar-
   item, sluiten onthult gewoon de onderliggende Bezoekers-tab weer.
   Zelfde donkere .scan-modal-basis/-koptekst als Bezoekers/Stats
   hierboven, geen nieuw visueel systeem.
   --------------------------------------------------------------------- */
.scan-modal--order {
    z-index: 965;
    background: linear-gradient(
        180deg,
        color-mix(in srgb, var(--scan-color, var(--brand)) 10%, #0f0f16) 0%,
        color-mix(in srgb, var(--scan-color, var(--brand)) 3%, #0f0f16) 55%,
        #0f0f16 100%
    );
    padding-bottom: 100px;
}

.scan-order-summary {
    padding: 14px 16px;
    margin-bottom: 14px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 16px;
}

.scan-order-summary__name {
    font-weight: 700;
    font-size: 1rem;
    margin-bottom: 2px;
}

.scan-order-summary__status {
    font-size: 0.82rem;
    color: rgba(255, 255, 255, 0.6);
    text-transform: capitalize;
}

.scan-order-result {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.85);
}

.scan-order-result p {
    margin: 0 0 4px;
}

.scan-order-tickets {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.scan-order-ticket {
    padding: 10px 14px;
    background: rgba(255, 255, 255, 0.82);
    border-radius: var(--radius-panel, 16px);
    box-shadow: var(--shadow-card, 0 10px 30px rgba(20, 20, 60, 0.05));
    color: var(--ink);
}

.scan-order-ticket--disabled {
    opacity: 0.55;
}

.scan-order-ticket__row {
    display: flex;
    align-items: center;
    gap: 12px;
    cursor: pointer;
    font: inherit;
}

.scan-order-ticket--disabled .scan-order-ticket__row {
    cursor: default;
}

.scan-order-ticket__checkbox {
    flex: none;
    width: 20px;
    height: 20px;
}

.scan-order-ticket__checkbox--disabled {
    display: inline-block;
    border-radius: 5px;
    border: 1px solid var(--border);
    background: var(--surface-alt);
}

.scan-order-ticket__info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.scan-order-ticket__name {
    font-weight: 700;
    font-size: 0.92rem;
}

.scan-order-ticket__meta {
    font-size: 0.78rem;
    color: var(--muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Vaste actiebalk onderin, boven de tabbalk - zelfde soort sticky
   bottom-actiepatroon als .scan-doorsale__actions elders in dit bestand,
   nu met 2 acties naast elkaar ("Alle geldige selecteren" is secundair/
   optioneel, "Geselecteerde inchecken" de primaire actie). */
.scan-order-actionbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 966;
    display: flex;
    gap: 8px;
    padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
    background: #101014;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

/* Live-gemeten bug (390px): de standaard .button-opmaak (0.95rem,
   padding 11px 22px) liet "Geselecteerde inchecken (0)" intern
   afbreken naar 2 regels binnen zijn eigen (te smalle) knop - oogde als
   een gestapelde layout terwijl beide knoppen wél op dezelfde rij
   stonden (bevestigd via getBoundingClientRect: zelfde top, andere
   left). Kleiner lettertype/padding + white-space:nowrap lost dit op;
   de secundaire knop mag desnoods ellipsen, de primaire (met de
   dynamische teller) nooit. */
.scan-order-actionbar .button--secondary {
    flex: 0 1 auto;
    font-size: 0.8rem;
    padding: 12px 14px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.scan-order-actionbar .button--primary {
    flex: 1;
    font-size: 0.8rem;
    padding: 12px 10px;
    white-space: nowrap;
}

.scan-order-actionbar .button--primary:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

@media (min-width: 640px) {
    .scan-order-actionbar {
        left: max(20px, calc(50% - 260px));
        right: max(20px, calc(50% - 260px));
        bottom: 20px;
        border-radius: 999px;
        border: 1px solid rgba(255, 255, 255, 0.1);
        box-shadow: 0 12px 30px rgba(16, 16, 40, 0.35);
    }
}

@media (min-width: 1024px) {
    .scan-order-actionbar {
        left: max(20px, calc(50% - 320px));
        right: max(20px, calc(50% - 320px));
    }
}

/* ---------------------------------------------------------------------
   SCANNER FINAL MICRO-FIX - platformfooter consistent over alle modi.
   Root cause (bevestigd, geen aanname): .scan-footer stond in de gewone
   documentflow, als volgend blok NA .scan-tab-scannen binnen .scan-body
   (flex-column) - dat werkte zolang Scannen de enige zichtbare inhoud
   was. Bezoekers/Stats/Deurverkoop zijn echter GEEN aparte pagina's maar
   losse .scan-modal-panelen (position:fixed; inset:0; z-index:950) die
   BOVENOP de hele viewport getekend worden zodra ze open zijn - de
   footer verdween dus niet, hij lag gewoon in de documentflow ONDER dat
   volledige-viewport-paneel en werd er letterlijk door bedekt. Er is en
   blijft maar ÉÉN .scan-footer-element in de DOM (nooit gedupliceerd
   per mode) - de fix maakt 'm simpelweg net zo'n vaste, altijd-boven-de-
   panelen-liggende laag als de bestaande tabbalk hierboven, i.p.v. 'm
   vier keer te dupliceren. Alleen relevant vanaf 900px (dezelfde,
   ongewijzigde display:none/block-drempel hierboven) - op mobiel blijft
   het scherm bewust 1 beeldvullende kiosk-pagina zonder footer. */
@media (min-width: 900px) {
    .scan-footer {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 955;
    }
}

/* ---------------------------------------------------------------------
   Overervingseenheid van een subevenement (migratie 062)
   ---------------------------------------------------------------------
   Eén herkenbaar patroon per eenheid: een echte schakelaar plus TWEE
   toestanden die allebei in de HTML staan. Welke van de twee zichtbaar is,
   volgt puur uit de stand van het vinkje - dus zonder JavaScript. Het
   scriptje in EventController houdt daarnaast het hidden-attribuut gelijk,
   voor hulpsoftware en browsers zonder :has()-ondersteuning.

   Bewust GEEN globale omzetting van checkbox naar schakelaar: deze
   schakelaar geldt alleen waar een vinkje een overervingsbesluit is, niet
   voor gewone instellingen zoals "Direct personaliseren".

   FASE E6A: eigen componentnaam .inherit-switch (was .switch). De latere,
   input-gebaseerde schakelaar (<input class="switch">, widgets/scan-codes,
   verderop in dit bestand) gebruikte dezelfde klassenaam en tekende daardoor
   ook op dit <label> een tweede bolletje en perste het label in 42x24px.
   Twee losse componenten, twee losse namen - geen !important nodig.
   --------------------------------------------------------------------- */

.inherit-switch {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    font-weight: 500;
    font-size: 0.92rem;
    line-height: 1.4;
}

/* De echte checkbox blijft bestaan (formulierwaarde, toetsenbord,
   hulpsoftware) maar wordt visueel vervangen door het spoor hieronder -
   niet display:none, want dan verdwijnt hij ook uit de tabvolgorde. */
.inherit-switch__input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    margin: 0;
    pointer-events: none;
}

.inherit-switch__track {
    position: relative;
    flex-shrink: 0;
    width: 40px;
    height: 22px;
    border-radius: 999px;
    background: var(--border, #d5d7e0);
    transition: background-color 0.15s ease;
}

.inherit-switch__thumb {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
    transition: transform 0.15s ease;
}

.inherit-switch__input:checked + .inherit-switch__track {
    background: var(--brand);
}

.inherit-switch__input:checked + .inherit-switch__track .inherit-switch__thumb {
    transform: translateX(18px);
}

/* Alleen bij toetsenbordbediening een ring - een muisklik hoort geen
   focusring achter te laten (zelfde afweging als elders in de admin).

   Bewust --focus-ring en NIET --brand: View.php overschrijft --brand met de
   huisstijlkleur van de organisatie, en bij een witte of zeer lichte keuze
   zou de focusring op een lichte kaart onzichtbaar worden. --focus-ring is
   juist daarvoor een letterlijke hexwaarde die geen enkele tenant kan
   overschrijven. Zelfde vorm (3px + 2px offset) als elke andere
   focus-visible-regel in dit bestand. */
.inherit-switch__input:focus-visible + .inherit-switch__track {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

.inherit-unit {
    margin: 4px 0 12px;
}

.inherit-unit__state {
    margin: 10px 0 6px;
    font-size: 0.82rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--muted, #6b6f80);
}

/* Kern van de eenheid: precies één van de twee toestanden is zichtbaar. */
.inherit-unit:has(.inherit-switch__input:checked) .inherit-unit__inherited,
.inherit-unit:not(:has(.inherit-switch__input:checked)) .inherit-unit__own {
    display: none;
}

/* ---------------------------------------------------------------------
   Veldgroep binnen één kaart (062-nazorg)
   ---------------------------------------------------------------------
   Op het bewerkformulier van een SUBEVENEMENT staan in de kaart "Algemeen"
   drie soorten velden onder elkaar: eigen gegevens (naam/begin/einde), de
   overerfbare sectie (locatie + verkoopperiode, mét schakelaar) en de
   capaciteit. Zonder scheiding stond de schakelaar direct onder de
   datumvelden en leek hij ook daarover te gaan.

   Alleen een lijn plus een klein kopje - geen nieuwe kaart, geen extra
   ruimte-opbouw, zodat de kaartcompositie zelf onveranderd blijft. Wordt
   niet gebruikt op een top-level evenement.
   --------------------------------------------------------------------- */

.field-group + .field-group {
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
}

.field-group__title {
    margin: 0 0 10px;
    font-size: 0.82rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--muted, #6b6f80);
}

/* =====================================================================
   ORGANISATORSCHIL — Fase A, mockup 2b
   =====================================================================
   Donkere zijbalk links, licht werkvlak rechts. Alle waarden komen uit
   2b zelf (DESIGN_REFERENCE.html, sectie #2b), niet uit een omschrijving:
   raster 270px + rest, werkvlak #fdfbf7, zijbalk als diagonale
   streepgradient #0f0f16/#14141f, zijbalkpadding 26px 22px met 28px
   tussen de blokken, actief navigatie-item als witte pil (11px 16px,
   radius 999px), inactief rgba(255,255,255,.65), organisatieblok
   rgba(255,255,255,.07) met radius 20px en 16px padding.

   ALLES hieronder hangt onder .org-body / .org-shell. Dat is bewust: de
   View-laag bedient ook de koperspagina's, de marketingsite, de
   inlogschermen en de platformadmin, en die mogen hier niets van merken.
   Geen enkele generieke selector (.card, .page, .button, .badge) wordt
   aangepast.
   ===================================================================== */

.org-body {
    background: var(--surface-warm, #fdfbf7);
}

/* De schil vult de body i.p.v. zelf nog eens 100vh te claimen.

   Er stonden twee ONAFHANKELIJKE viewportvloeren in deze pagina: body
   (min-height:100vh) en .org-shell (min-height:100vh). Zodra die twee
   het bij een echte browser niet eens zijn over hoe hoog "100vh" is -
   browserzoom, een horizontale schuifbalk, of mobiele browserchrome
   die de visuele viewport kleiner maakt dan de layoutviewport - komt
   het verschil als een scrollbare band lege achtergrond ONDER de
   inhoud terecht. Precies het gemelde beeld: inhoud, Opslaan, tabbalk,
   en daaronder nog een groot leeg licht vlak.

   Nu is er nog maar EEN vloer (body). De schil groeit daar met
   flex-grow in mee, dus de documenthoogte kan per definitie niet
   verder komen dan de body: is de inhoud korter dan het scherm, dan
   vult de schil precies het scherm; is de inhoud langer, dan volgt de
   documenthoogte de inhoud en komt er niets bovenop. */
.org-shell {
    display: grid;
    grid-template-columns: 270px minmax(0, 1fr);
    flex: 1 0 auto;
    min-height: 0;
}

/* ---------- zijbalk ---------- */

.org-sidebar {
    display: flex;
    flex-direction: column;
    gap: 28px;
    padding: 26px 22px;
    /* Railkleur staat op EEN plek, verderop in dit bestand ("PAARSE
       ORGANISATOR-ZIJBALK"). */
    /* Blijft staan bij lange pagina's (het evenementformulier is ruim
       3700px hoog): zonder dit rekt de zijbalk mee en staat het
       accountblok duizenden pixels onder de vouw. */
    position: sticky;
    top: 0;
    align-self: start;
    /* Even hoog als het scherm, maar via de schil (die de body vult)
       i.p.v. via een eigen 100vh - anders zet de zijbalk alsnog een
       tweede viewportvloer op de gridrij. dvh waar beschikbaar: op
       mobiel is dat de ECHTE zichtbare hoogte, zonder de band die
       browserchrome anders overhoudt. */
    height: 100vh;
    height: 100dvh;
    max-height: 100%;
    overflow-y: auto;
}

.org-sidebar__logo {
    display: flex;
    align-items: center;
    gap: 9px;
    min-height: 34px;
}

.org-sidebar__logo img {
    max-height: 26px;
    width: auto;
}

.org-sidebar__org {
    padding: 16px;
    border-radius: 20px;
    background: rgba(255, 255, 255, 0.07);
}

.org-sidebar__eyebrow {
    margin: 0 0 6px;
    font: 600 9px "JetBrains Mono", ui-monospace, monospace;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.45);
}

.org-sidebar__orgname {
    margin: 0;
    font: 700 14px "Plus Jakarta Sans", system-ui, sans-serif;
    color: #fff;
}

/* De enige gele toets in de organisatorschil - precies zoals 2b het doet.
   Geel blijft verder voorbehouden aan platformbeheer-signalering. */
.org-sidebar__slug {
    margin: 3px 0 0;
    font: 500 11px "JetBrains Mono", ui-monospace, monospace;
    color: #ffc80a;
}

.org-nav {
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.org-nav__item {
    padding: 11px 16px;
    border-radius: 999px;
    font: 600 13px "Plus Jakarta Sans", system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.65);
    text-decoration: none;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.org-nav__item:hover {
    background: rgba(255, 255, 255, 0.08);
    color: #fff;
}

.org-nav__item--active,
.org-nav__item--active:hover {
    background: #fff;
    color: #101014;
}

.org-nav__item:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* Account onderaan - duwt zichzelf naar beneden zodat de navigatie bovenin blijft. */
.org-sidebar__account {
    margin-top: auto;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: 10px;
    padding: 12px;
    border-radius: 20px;
    background: rgba(255, 255, 255, 0.07);
}

.org-sidebar__avatar {
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: 999px;
    background: #fff;
    font: 700 12px "Plus Jakarta Sans", system-ui, sans-serif;
    color: #101014;
}

.org-sidebar__identity {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.org-sidebar__username {
    font: 700 12px "Plus Jakarta Sans", system-ui, sans-serif;
    color: #fff;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.org-sidebar__role {
    font: 500 10px "JetBrains Mono", ui-monospace, monospace;
    color: rgba(255, 255, 255, 0.5);
}

.org-sidebar__logout {
    grid-column: 1 / -1;
    margin: 2px 0 0;
}

.org-sidebar__logout-button {
    width: 100%;
    padding: 8px 12px;
    border: 0;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.12);
    font: 600 11px "Plus Jakarta Sans", system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.85);
    cursor: pointer;
}

.org-sidebar__logout-button:hover {
    background: rgba(255, 255, 255, 0.2);
    color: #fff;
}

.org-sidebar__logout-button:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* ---------- werkvlak ---------- */

.org-main {
    display: flex;
    flex-direction: column;
    min-width: 0;
    background: #fdfbf7;
}

/* 2b geeft het werkvlak 30px/34px padding; de bestaande .page houdt zijn
   eigen breedtevarianten, dus alleen de buitenruimte wordt hier gezet. */
.org-body .org-main > main.page {
    width: 100%;
    max-width: none;
    margin: 0;
    padding: 30px 34px 40px;
    /* .page krijgt in de basisregel flex: 1 0 auto voor het "sticky
       footer"-patroon van de KOPERSkant: daar staat er een voettekst
       onder .page in dezelfde flex-kolom, en moet .page de resterende
       ruimte opvullen. In de organisatorschil staat er geen voettekst
       onder .page - daar rekte die groei het werkvlak dus zonder reden
       uit tot de volle hoogte van .org-shell (min-height: 100vh),
       waardoor onder de inhoud een leeg licht vlak bleef staan en de
       pagina verder liep dan zijn eigen inhoud. Hier dus geen groei:
       de paginahoogte volgt de inhoud, en .org-shell zorgt nog steeds
       voor de viewporthoogte als ondergrens. */
    flex: 0 0 auto;
}

.org-body .org-main > main.page--narrow {
    max-width: 720px;
}

.org-body .org-main > main.page--medium {
    max-width: 1040px;
}

.org-body .page-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin: 0 0 22px;
}

.org-body .page-header h1 {
    margin: 0;
    font: 800 30px "Plus Jakarta Sans", system-ui, sans-serif;
    letter-spacing: -0.025em;
    color: #101014;
}

.page-header__titles {
    min-width: 0;
}

.page-header__subtitle {
    margin: 6px 0 0;
    font-size: 0.9rem;
    color: var(--muted, #6b6f80);
}

.page-header__actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

/* De oude voettekst hoort niet in een dashboardschil thuis. */
.org-body .site-footer {
    display: none;
}

/* ---------- mobiele balk + lade ---------- */

.org-mobilebar {
    display: none;
}

@media (max-width: 900px) {
    .org-shell {
        grid-template-columns: minmax(0, 1fr);
    }

    .org-mobilebar {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
        padding: 12px 16px;
        /* Zie de paarse railregels verderop in dit bestand. */
    }

    .org-mobilebar__toggle {
        display: inline-flex;
        align-items: center;
        gap: 9px;
        padding: 9px 14px;
        border: 0;
        border-radius: 999px;
        background: rgba(255, 255, 255, 0.12);
        font: 600 13px "Plus Jakarta Sans", system-ui, sans-serif;
        color: #fff;
        cursor: pointer;
    }

    .org-mobilebar__toggle:focus-visible {
        outline: 3px solid var(--focus-ring);
        outline-offset: 2px;
    }

    .org-mobilebar__bars {
        display: grid;
        gap: 3px;
    }

    .org-mobilebar__bars span {
        display: block;
        width: 15px;
        height: 2px;
        border-radius: 2px;
        background: #fff;
    }

    .org-mobilebar__logo img {
        max-height: 20px;
        width: auto;
    }

    /* Zonder JavaScript blijft de zijbalk gewoon in de flow staan (dus
       bereikbaar); met JavaScript wordt hij een lade die van links komt. */
    .org-sidebar {
        position: fixed;
        z-index: 40;
        inset: 0 auto 0 0;
        width: min(280px, 84vw);
        transform: translateX(-100%);
        transition: transform 0.18s ease;
        overflow-y: auto;
    }

    .org-shell--nav-open .org-sidebar {
        transform: translateX(0);
    }

    .org-shell__scrim {
        display: none;
    }

    .org-shell--nav-open .org-shell__scrim {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 39;
        background: rgba(12, 12, 16, 0.5);
    }

    .org-body .org-main > main.page {
        padding: 18px 16px 32px;
    }

    .org-body .page-header h1 {
        font-size: 24px;
    }

    .org-body .page-header {
        margin-bottom: 16px;
    }
}

/* Geen JavaScript: geen lade, dus de zijbalk hoort weer gewoon mee te lopen. */
@media (max-width: 900px) {
    .org-shell:not(.org-shell--nav-open) .org-sidebar:focus-within {
        transform: translateX(0);
    }
}

/* =====================================================================
   ORGANISATOR-INHOUDSSYSTEEM — Fase B, mockup 2b
   =====================================================================
   Waarden gemeten in #2b: kaart rgba(255,255,255,.82) + 1px rand
   rgba(16,16,20,.06) + radius 22px + padding 20px; statrooster 3 kolommen
   met 16px gap; paneel padding 22px 24px; paneelkop 700 16px; label
   600 10px JetBrains Mono op rgba(16,16,20,.45); waarde 800 30px/30px;
   subregel 500 11px JetBrains Mono op rgba(16,16,20,.5); blokafstand 20px.

   Alles scoped onder .org-body - geen generieke selector aangepast.
   ===================================================================== */

.org-body .page-header {
    align-items: flex-end;
}

.org-body .page-header__aside {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.org-eyebrow {
    margin: 0 0 6px;
    font: 600 10px "JetBrains Mono", ui-monospace, monospace;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--brand);
}

.page-header__meta {
    margin: 0;
    font: 500 11px "JetBrains Mono", ui-monospace, monospace;
    color: rgba(16, 16, 20, 0.5);
    white-space: nowrap;
}

/* ---------- statkaarten ---------- */

.org-stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 16px;
    margin: 0 0 20px;
}

.org-stat {
    display: block;
    padding: 20px;
    border: 1px solid rgba(16, 16, 20, 0.06);
    border-radius: 22px;
    background: rgba(255, 255, 255, 0.82);
    text-decoration: none;
}

.org-stat--link:hover {
    border-color: rgba(93, 93, 255, 0.35);
}

.org-stat--link:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

.org-stat__label {
    margin: 0 0 8px;
    font: 600 10px "JetBrains Mono", ui-monospace, monospace;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(16, 16, 20, 0.45);
}

.org-stat__value {
    margin: 0;
    font: 800 30px/30px "Plus Jakarta Sans", system-ui, sans-serif;
    letter-spacing: -0.02em;
    color: #101014;
}

.org-stat__sub {
    margin: 8px 0 0;
    font: 500 11px "JetBrains Mono", ui-monospace, monospace;
    color: rgba(16, 16, 20, 0.5);
}

/* ---------- panelen ---------- */

.org-panel {
    padding: 22px 24px;
    border: 1px solid rgba(16, 16, 20, 0.06);
    border-radius: 22px;
    background: rgba(255, 255, 255, 0.82);
    margin: 0 0 20px;
}

.org-panel__header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin: 0 0 14px;
}

.org-panel__title {
    margin: 0;
    font: 700 16px "Plus Jakarta Sans", system-ui, sans-serif;
    letter-spacing: -0.01em;
    color: #101014;
}

/* ---------- hero: eerstvolgende evenement ---------- */

.org-hero {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    border-radius: 22px;
    overflow: hidden;
    margin: 0 0 20px;
    border: 1px solid rgba(16, 16, 20, 0.06);
}

.org-hero__main {
    padding: 24px 26px;
    background: #fff;
}

.org-hero__title {
    margin: 0 0 6px;
    font: 800 22px/1.15 "Plus Jakarta Sans", system-ui, sans-serif;
    letter-spacing: -0.02em;
    color: #101014;
}

.org-hero__actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin: 16px 0 0;
}

.org-hero__side {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 16px;
    padding: 24px 26px;
    background: #101014;
}

.org-hero__figures {
    display: flex;
    gap: 32px;
    flex-wrap: wrap;
}

.org-hero__label {
    margin: 0 0 6px;
    font: 600 10px "JetBrains Mono", ui-monospace, monospace;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.5);
}

.org-hero__value {
    margin: 0;
    font: 800 26px/26px "Plus Jakarta Sans", system-ui, sans-serif;
    color: #fff;
}

.org-hero__sub {
    margin: 6px 0 0;
    font: 500 11px "JetBrains Mono", ui-monospace, monospace;
    color: rgba(255, 255, 255, 0.5);
}

.org-hero__bar {
    height: 8px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.14);
    overflow: hidden;
}

.org-hero__bar span {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: #ffc80a;
}

.org-hero__barrow {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin: 0 0 6px;
}

.org-hero__percent {
    font: 700 12px "JetBrains Mono", ui-monospace, monospace;
    color: #ffc80a;
}

/* ---------- lijsten ---------- */

.org-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.org-list__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 0;
    border-top: 1px solid rgba(16, 16, 20, 0.07);
}

.org-list__row:first-child {
    border-top: 0;
    padding-top: 0;
}

.org-list__main {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.org-list__title {
    font: 700 14px "Plus Jakarta Sans", system-ui, sans-serif;
    color: #101014;
    text-decoration: none;
}

a.org-list__title:hover {
    color: var(--brand);
}

.org-meta {
    font: 500 11px "JetBrains Mono", ui-monospace, monospace;
    color: rgba(16, 16, 20, 0.5);
}

.org-list__aside {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-shrink: 0;
}

/* ---------- status + acties ---------- */

.org-status {
    display: inline-block;
    padding: 4px 10px;
    border-radius: 999px;
    font: 700 9px "JetBrains Mono", ui-monospace, monospace;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    white-space: nowrap;
}

.org-status--neutral { background: rgba(16, 16, 20, 0.07); color: rgba(16, 16, 20, 0.6); }
.org-status--success { background: rgba(31, 158, 90, 0.14); color: #1a7a48; }
.org-status--warning { background: rgba(255, 200, 10, 0.22); color: #7a5c00; }
.org-status--accent  { background: rgba(93, 93, 255, 0.12); color: var(--brand); }

.org-actionlink {
    font: 600 12px "Plus Jakarta Sans", system-ui, sans-serif;
    color: var(--brand);
    text-decoration: none;
    white-space: nowrap;
}

.org-actionlink:hover { text-decoration: underline; }

.org-actionlink:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* ---------- lege staat ---------- */

.org-empty {
    padding: 24px;
    border: 1px dashed rgba(16, 16, 20, 0.14);
    border-radius: 18px;
    text-align: center;
    color: rgba(16, 16, 20, 0.55);
}

.org-empty p {
    margin: 0 0 10px;
    font-size: 0.92rem;
}

.org-empty p:last-child {
    margin-bottom: 0;
}

/* ---------- takenpaneel (alleen bij echte items) ---------- */

.org-todo {
    padding: 18px 20px;
    border-radius: 22px;
    background: var(--brand);
    color: #fff;
    margin: 0 0 20px;
}

.org-todo__label {
    margin: 0 0 8px;
    font: 600 9px "JetBrains Mono", ui-monospace, monospace;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.7);
}

.org-todo__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.org-todo__list a {
    font: 600 13px "Plus Jakarta Sans", system-ui, sans-serif;
    color: #fff;
}

/* ---------- mobiel ---------- */

@media (max-width: 900px) {
    .org-hero {
        grid-template-columns: minmax(0, 1fr);
    }

    .org-stat-grid {
        grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
        gap: 12px;
    }

    .org-stat {
        padding: 16px;
    }

    .org-stat__value {
        font-size: 26px;
        line-height: 26px;
    }

    .org-panel {
        padding: 18px 16px;
    }

    /* Naam/meta boven, status/actie eronder - niet een bureaubladrij in een
       smalle kolom persen. */
    .org-list__row {
        flex-direction: column;
        align-items: flex-start;
        gap: 8px;
    }

    .org-list__aside {
        width: 100%;
        justify-content: space-between;
    }

    .org-body .page-header__aside {
        width: 100%;
    }
}

/* Secundaire beheertools in de zijbalk (Fase B) - bewust rustiger dan de
   hoofdnavigatie: kleiner, geen pil, zodat de zes primaire items de
   hiërarchie van 2b houden. */
.org-tools {
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    padding-top: 16px;
}

.org-tools__label {
    margin: 0 0 8px 16px;
    font: 600 9px "JetBrains Mono", ui-monospace, monospace;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.35);
}

.org-nav__tools {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.org-nav__tool {
    padding: 7px 16px;
    border-radius: 999px;
    font: 500 12px "Plus Jakarta Sans", system-ui, sans-serif;
    color: rgba(255, 255, 255, 0.5);
    text-decoration: none;
}

.org-nav__tool:hover {
    background: rgba(255, 255, 255, 0.06);
    color: rgba(255, 255, 255, 0.85);
}

.org-nav__tool--active {
    background: rgba(255, 255, 255, 0.12);
    color: #fff;
}

.org-nav__tool:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* De terugverwijzing is context, geen actie: in de organisatieomgeving een
   compacte tekstlink in plaats van een pil die met de echte acties
   concurreert (Fase B). Buiten .org-body blijft het de bestaande knop. */
.org-body .page-header__back {
    padding: 0;
    border: 0;
    background: none;
    font: 600 12px "Plus Jakarta Sans", system-ui, sans-serif;
    color: rgba(16, 16, 20, 0.55);
    text-decoration: none;
    min-height: 0;
}

.org-body .page-header__back::before {
    content: "\2190";
    margin-right: 5px;
}

.org-body .page-header__back:hover {
    color: var(--brand);
    text-decoration: underline;
}

/* =====================================================================
   FASE C - GEDEELD LIJST-/FILTERSYSTEEM (organisatieschermen)

   Losse, afgeronde rijen op de paginaondergrond i.p.v. een tabel in één
   grote witte kaart: de lijst groeit exact mee met de inhoud, dus één
   rij is één rij hoog. Maten uit mockup 2b/2d.

   Uitsluitend nieuwe klassen - .card/.data-table/.button/.badge blijven
   ongewijzigd omdat de koperspagina's en de platformadmin die delen.
   ===================================================================== */

.org-records {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.org-record {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 6px 18px;
    background: #fff;
    border: 1px solid rgba(16, 16, 20, 0.07);
    border-radius: 16px;
    padding: 14px 16px;
}

.org-record--attention {
    border-color: rgba(255, 200, 10, 0.55);
}

.org-record--muted {
    background: rgba(255, 255, 255, 0.6);
}

.org-record__main {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.org-record__title {
    font-weight: 700;
    font-size: 13.5px;
    line-height: 1.3;
    color: var(--ink, #101014);
    text-decoration: none;
    overflow-wrap: anywhere;
}

a.org-record__title:hover {
    text-decoration: underline;
}

a.org-record__title:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 3px;
    border-radius: 6px;
}

.org-record__meta {
    margin: 0;
    font: 500 11px 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    color: rgba(16, 16, 20, 0.5);
    overflow-wrap: anywhere;
}

.org-record__meta a {
    color: inherit;
}

.org-record__trail {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 14px;
    flex-wrap: wrap;
}

.org-record__value {
    font: 700 13px 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    color: var(--ink, #101014);
    white-space: nowrap;
}

.org-record--muted .org-record__value {
    color: rgba(16, 16, 20, 0.45);
    text-decoration: line-through;
}

.org-record__aside {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    justify-content: flex-end;
}

/* Filterbalk - compacte pillen i.p.v. losse formuliervelden boven een tabel. */

.org-filterbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px;
    background: rgba(255, 255, 255, 0.82);
    border: 1px solid rgba(16, 16, 20, 0.06);
    border-radius: 22px;
    padding: 14px 16px;
    margin-bottom: 16px;
}

.org-filterbar__field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 180px;
}

.org-filterbar__field--wide {
    flex: 1 1 260px;
}

.org-filterbar__label {
    font: 600 10px 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(16, 16, 20, 0.45);
}

.org-filterbar__field input,
.org-filterbar__field select {
    width: 100%;
    background: #fff;
    border: 1px solid rgba(16, 16, 20, 0.12);
    border-radius: 999px;
    padding: 10px 16px;
    font-size: 12.5px;
    color: var(--ink, #101014);
}

.org-filterbar__field input:focus-visible,
.org-filterbar__field select:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

.org-filterbar__actions {
    display: flex;
    align-items: center;
    gap: 14px;
}

/* Actieve-filtermelding boven de lijst. */

.org-filternote {
    margin: 0 0 14px;
    font: 500 11.5px 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    color: rgba(16, 16, 20, 0.55);
}

.org-filternote a {
    color: var(--brand);
}

.org-code {
    font: 600 11.5px 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    background: rgba(16, 16, 20, 0.06);
    border-radius: 6px;
    padding: 2px 7px;
    color: var(--ink, #101014);
    overflow-wrap: anywhere;
}

/* Verwijderactie: echt POST-formulier, maar oogt als een actielink. */

.org-dangeraction {
    display: inline;
    margin: 0;
}

.org-dangeraction button {
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    font: 600 12px 'Plus Jakarta Sans', system-ui, sans-serif;
    color: #a52a2a;
}

.org-dangeraction button:hover {
    text-decoration: underline;
}

.org-dangeraction button:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 3px;
    border-radius: 6px;
}

@media (max-width: 700px) {
    .org-record {
        grid-template-columns: minmax(0, 1fr);
        gap: 10px;
    }

    .org-record__trail {
        justify-content: flex-start;
        gap: 12px;
    }

    .org-record__aside {
        justify-content: flex-start;
    }

    .org-filterbar {
        flex-direction: column;
        align-items: stretch;
        border-radius: 18px;
    }

    .org-filterbar__field {
        min-width: 0;
    }

    /* In een kolom-flex wordt flex-basis de HOOGTE: zonder deze reset
       werd het zoekveld 260px hoog i.p.v. 260px breed. */
    .org-filterbar__field--wide {
        flex: 0 0 auto;
    }
}

/* =====================================================================
   FASE C ACCEPTATIE - ZIJBALKBRANDING + EXTERNE LINKS

   Het platformbeeldmerk stond als klein mark-plus-tekstje linksboven in
   de donkere zijbalk en viel daardoor weg. Groter en met meer lucht
   eromheen, en met een subtiele paarse merkband erboven - variant B uit
   de vergelijking (zie het rondeverslag): de zijbalk blijft bijna-zwart
   zoals in mockup 2b, zodat het werkvlak het rustpunt van het scherm
   blijft en de actieve navigatiepil het duidelijkst contrasteert.
   ===================================================================== */

.org-sidebar__logo {
    gap: 11px;
    min-height: 44px;
    padding-bottom: 20px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    position: relative;
}

/* Smalle paarse merkband: brengt het platformpaars in de zijbalk zonder
   het hele vlak paars te maken (dat zou luider worden dan de inhoud). */
.org-sidebar__logo::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: -1px;
    width: 46px;
    height: 2px;
    border-radius: 2px;
    background: #5d5dff;
}

.org-sidebar__logo img {
    max-height: 34px;
}

.org-sidebar__logo .logo-mark {
    height: 28px;
    gap: 4px;
}

.org-sidebar__logo .logo-mark span {
    width: 6px;
}

.org-sidebar__logo .logo-text {
    font-size: 1.22rem;
}

/* Het publieke pad is voortaan een echte link naar de ticketshop. */
a.org-sidebar__slug {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    text-decoration: none;
}

a.org-sidebar__slug:hover {
    text-decoration: underline;
}

a.org-sidebar__slug:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 3px;
    border-radius: 4px;
}

.org-sidebar__slug-icon {
    font-size: 0.85em;
    opacity: 0.75;
}

/* Gedeelde toegankelijkheidshulp: tekst die alleen voor schermlezers is. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* Panelen naast elkaar op één rooster - grid-items rekken standaard mee,
   dus siblings op dezelfde rij delen dezelfde hoogte en lijnen boven- én
   onderaan uit. Vervangt .card-columns op de deelbare statistiekpagina,
   waar de korte totaalkaart anders naast een veel langere kaart stond. */
.org-panel-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 16px;
    align-items: stretch;
}

.org-panel-grid > .org-panel {
    margin: 0;
    display: flex;
    flex-direction: column;
}

/* =====================================================================
   PAARSE ORGANISATOR-ZIJBALK (productbeslissing)

   Vervangt de bijna-zwarte rail door het platformpaars. Niet één vlak
   #5D5DFF: wit op #5D5DFF haalt maar ~3.6:1 contrast en dat is te weinig
   voor navigatietekst. De rail staat daarom op een dieper paars uit
   dezelfde familie (wit erop ~9:1) met een subtiele diagonale streep -
   dezelfde streep-DNA als de vorige rail - en #5D5DFF blijft de heldere
   accenttoets. Geen nieuwe kleuren buiten het systeem.

   Alle regels hieronder staan bewust NA de basisregels van de zijbalk, en
   overschrijven alleen kleur/contrast - geen maten, geen structuur.
   ===================================================================== */

.org-sidebar {
    --rail-diep: #2f2596;
    --rail-streep: #392eae;
    background:
        repeating-linear-gradient(
            120deg,
            var(--rail-diep) 0 18px,
            var(--rail-streep) 18px 36px
        );
    border-right: 1px solid rgba(255, 255, 255, 0.08);
}

/* Zachte paarse gloed bovenin, zodat de rail diepte houdt en niet als
   één platte knop leest. */
.org-sidebar::before {
    content: "";
    position: absolute;
    inset: 0 0 auto;
    height: 240px;
    background: linear-gradient(180deg, rgba(93, 93, 255, 0.55) 0%, rgba(93, 93, 255, 0) 100%);
    pointer-events: none;
}

/* Alleen een stapelcontext voor de gloed hierboven. BEWUST geen
   position hier: de mobiele mediaquery zet de zijbalk op
   position:fixed (uit de flow, off-canvas lade), en dit blok staat
   later in het bestand - een position:sticky hier trok de zijbalk op
   mobiel terug in de gridflow en duwde de hele pagina een scherm naar
   beneden. */
.org-sidebar {
    isolation: isolate;
}

.org-sidebar > * {
    position: relative;
    z-index: 1;
}

/* Merkband onder het logo in het heldere platformpaars. */
.org-sidebar__logo {
    border-bottom-color: rgba(255, 255, 255, 0.16);
}

.org-sidebar__logo::after {
    background: #fff;
    width: 54px;
    opacity: 0.9;
}

/* Navigatie: iets hoger contrast dan op zwart nodig was. */
.org-nav__item {
    color: rgba(255, 255, 255, 0.82);
}

.org-nav__item:hover {
    background: rgba(255, 255, 255, 0.14);
    color: #fff;
}

/* Actief item blijft een witte pil met donkere tekst - op paars is dat
   het sterkst mogelijke contrastverschil (≈13:1). */
.org-nav__item--active,
.org-nav__item--active:hover {
    background: #fff;
    color: #201a5e;
    box-shadow: 0 6px 18px rgba(16, 12, 60, 0.28);
}

/* BEHEER blijft secundair, maar leesbaar. */
.org-tools__label {
    color: rgba(255, 255, 255, 0.6);
}

.org-nav__tool {
    color: rgba(255, 255, 255, 0.72);
}

.org-nav__tool:hover,
.org-nav__tool--active {
    color: #fff;
}

/* Organisatiekaart en accountkaart: iets meer body dan op zwart, anders
   verdwijnen ze in de paarse ondergrond. */
.org-sidebar__org,
.org-sidebar__account {
    background: rgba(12, 8, 56, 0.34);
    border: 1px solid rgba(255, 255, 255, 0.12);
}

.org-sidebar__eyebrow {
    color: rgba(255, 255, 255, 0.6);
}

.org-sidebar__avatar {
    background: #fff;
    color: #2f2596;
}

.org-sidebar__role {
    color: rgba(255, 255, 255, 0.68);
}

.org-sidebar__logout-button {
    background: rgba(255, 255, 255, 0.16);
    color: #fff;
}

.org-sidebar__logout-button:hover {
    background: rgba(255, 255, 255, 0.26);
}

/* De mobiele balk is dezelfde rail - dus dezelfde kleur. */
@media (max-width: 900px) {
    .org-mobilebar {
        background: linear-gradient(135deg, #2f2596 0%, #392eae 100%);
        border-bottom: 1px solid rgba(255, 255, 255, 0.12);
    }
}

/* =====================================================================
   PUBLIEK DEELRAPPORT (/statistieken/{token})

   Een eigen, compacte paginacompositie: een echte kopbalk met het
   platformmerk erin (i.p.v. de losse zwevende logo-pil), daaronder één
   leesblok met een bewuste maximale breedte. Zonder dat rekte de inhoud
   over de volle schermbreedte uit en bleef de onderste helft leeg.
   ===================================================================== */

body:has(.report) {
    background: var(--surface-warm, #fdfbf7);
}

.report {
    width: 100%;
    max-width: 900px;
    margin: 0 auto;
    padding: 0 20px 48px;
    box-sizing: border-box;
}

/* Ingetogen merkregel i.p.v. een volvlaks paarse banner: die las als
   een losse microsite bovenop een Eticketskopen-pagina. Nu dezelfde
   rustige opzet als de andere publieke oppervlakken - merk links,
   rapportlabel rechts, een haarlijn eronder, en paars uitsluitend als
   accent (het beeldmerk en de eyebrow). */
.report__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin: 0 0 28px;
    padding: 22px 0 16px;
    border-bottom: 1px solid rgba(16, 16, 20, 0.09);
}

.report__brand {
    display: flex;
    align-items: center;
    gap: 9px;
}

.report__brand img {
    max-height: 26px;
    width: auto;
}

/* Het generieke beeldmerk is van zichzelf WIT (bedoeld voor donkere
   ondergronden); de --dark-varianten krijgen hun kleur alleen onder
   specifieke ouders. Deze merkregel staat op een lichte ondergrond,
   dus hier expliciet de inktkleur - anders staat er onzichtbaar wit
   op wit. */
.report__brand .logo-mark span {
    background: var(--ink, #101014);
}

.report__brand .logo-text {
    color: var(--ink, #101014);
    font-size: 1rem;
}

.report__kicker {
    font: 600 10px "JetBrains Mono", ui-monospace, monospace;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: rgba(16, 16, 20, 0.45);
}

.report__head {
    margin-bottom: 22px;
}

.report__title {
    margin: 8px 0 0;
    font-size: 30px;
    font-weight: 800;
    letter-spacing: -0.025em;
    line-height: 1.15;
    color: var(--ink, #101014);
}

.report__date {
    margin: 8px 0 0;
    font: 500 12px "JetBrains Mono", ui-monospace, monospace;
    color: rgba(16, 16, 20, 0.55);
}

/* KPI-rooster niet over de volle breedte uitrekken: twee kaarten van
   ~260px lezen als een cijferblok, één kaart van 980px als een leeg vlak. */
.report .org-stat-grid {
    grid-template-columns: repeat(auto-fit, minmax(0, 260px));
    justify-content: start;
    margin-bottom: 22px;
}

/* Panelen: uitgelijnde bovenkanten, NATUURLIJKE hoogte. Gelijke hoogte
   afdwingen maakte van een paneel met één regel een half leeg vlak naast
   een paneel met drie regels. */
.report__panels {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 16px;
    align-items: start;
}

.report__panels > .org-panel {
    margin: 0;
}

.report__panelcount {
    font: 600 11px "JetBrains Mono", ui-monospace, monospace;
    color: rgba(16, 16, 20, 0.5);
    white-space: nowrap;
}

/* Voettekst volgt de inhoud, ook bij een kort rapport.

   .page groeit standaard mee (flex: 1 0 auto) om de voettekst tegen de
   onderkant van het scherm te duwen - het "sticky footer"-patroon van
   de koperspagina's. Op een kort rapport levert dat een grote lege
   band tussen de panelen en de voettekst op. Hier dus niet: de
   voettekst komt gewoon na het rapport, met normale ruimte ertussen.
   Gescoped op de aanwezigheid van .report, zodat geen enkele andere
   pagina dit merkt. */
body:has(.report) > main.page {
    flex: 0 0 auto;
}

/* RUNTIME-BUG: onder de donkere voettekst bleef een lichte strook
   staan. body is een flex-kolom met min-height:100vh; sinds .page hier
   niet meer meegroeit, telden inhoud + voettekst samen minder dan een
   schermhoogte en werd het verschil ONDER de voettekst als
   body-achtergrond zichtbaar.

   Nu vangt de VOETTEKST die restruimte op (margin-top:auto in de
   flex-kolom): op een kort rapport eindigt het document met de
   donkere voettekst tegen de onderkant, op een lang rapport volgt hij
   gewoon de inhoud. Geen position:fixed, geen vaste hoogtes. */
body:has(.report) > .site-footer {
    margin-top: auto;
}

/* (de voettekstpositie staat hierboven bij body:has(.report) > .site-footer) */

@media (max-width: 700px) {
    .report {
        padding: 0 14px 32px;
    }

    .report__bar {
        margin-bottom: 20px;
        padding: 12px 16px;
    }

    .report__title {
        font-size: 24px;
    }

    .report .org-stat-grid {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* =====================================================================
   ORGANISATOR OP MOBIEL: PLAKKENDE KOPBALK + LADE VAN RECHTS

   Alleen binnen de organisatorschil (.org-body) - de koperskant en de
   scan-app hebben hun eigen mobiele koppen en worden hier niet geraakt.
   ===================================================================== */

@media (max-width: 900px) {
    /* Kopbalk blijft in beeld terwijl de inhoud eronder doorscrollt. */
    .org-body .org-mobilebar {
        position: sticky;
        top: 0;
        z-index: 41;
    }

    /* Lade komt van RECHTS en hangt aan de rechter schermrand. */
    .org-body .org-sidebar {
        inset: 0 0 0 auto;
        transform: translateX(100%);
        border-right: 0;
        border-left: 1px solid rgba(255, 255, 255, 0.12);
    }

    .org-body .org-shell--nav-open .org-sidebar,
    .org-body .org-shell:not(.org-shell--nav-open) .org-sidebar:focus-within {
        transform: translateX(0);
    }

    /* De scrim ligt onder de lade maar boven de kopbalk, zodat de rest van
       het scherm echt afgedekt is. */
    .org-body .org-shell--nav-open .org-shell__scrim {
        z-index: 42;
    }

    .org-body .org-sidebar {
        z-index: 43;
    }

    /* Menu-knop rechts: label eerst, streepjes erachter. */
    .org-body .org-mobilebar__toggle {
        flex-direction: row;
    }
}

/* =====================================================================
   FASE D - INSTELLINGENSCHIL EN FORMULIERTAAL

   Vervangt de masonry-kolommen (.card-columns) met 7 losse kaarten door
   één leesbare kolom met sectienavigatie ernaast. Elke sectie houdt zijn
   eigen formulier en eigen POST-route - de groepering is puur visueel.
   ===================================================================== */

.org-settings {
    display: grid;
    grid-template-columns: 216px minmax(0, 1fr);
    gap: 28px;
    align-items: start;
}

.org-settings__nav {
    position: sticky;
    top: 24px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px;
    background: rgba(255, 255, 255, 0.82);
    border: 1px solid rgba(16, 16, 20, 0.06);
    border-radius: 20px;
}

.org-settings__navitem {
    padding: 9px 14px;
    border-radius: 999px;
    font-weight: 600;
    font-size: 13px;
    color: rgba(16, 16, 20, 0.7);
    text-decoration: none;
}

.org-settings__navitem:hover {
    background: rgba(16, 16, 20, 0.05);
    color: var(--ink, #101014);
}

.org-settings__navitem:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

.org-settings__main {
    display: flex;
    flex-direction: column;
    gap: 22px;
    min-width: 0;
}

.org-settings__section {
    scroll-margin-top: 24px;
}

.org-settings__head {
    margin-bottom: 12px;
}

.org-settings__title {
    margin: 0;
    font-size: 19px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--ink, #101014);
}

.org-settings__intro {
    margin: 6px 0 0;
    font-size: 13px;
    line-height: 1.5;
    color: rgba(16, 16, 20, 0.6);
    max-width: 62ch;
}

/* Eén blok = één formulier = één opslaanactie. */
.org-settings__block {
    background: rgba(255, 255, 255, 0.82);
    border: 1px solid rgba(16, 16, 20, 0.06);
    border-radius: 22px;
    padding: 22px 24px;
}

.org-settings__block + .org-settings__block {
    margin-top: 14px;
}

.org-settings__fields {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.org-settings__fields .field {
    margin: 0;
}

.org-settings__actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 14px;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid rgba(16, 16, 20, 0.07);
}

/* Maakt expliciet WAT er met deze knop wordt opgeslagen. */
.org-settings__scope {
    margin-right: auto;
    font: 500 11px "JetBrains Mono", ui-monospace, monospace;
    color: rgba(16, 16, 20, 0.5);
}

.org-settings__status {
    display: flex;
    align-items: center;
    gap: 9px;
    margin: 0 0 12px;
    font-size: 13px;
    font-weight: 600;
    color: var(--ink, #101014);
}

.org-settings__status span {
    width: 9px;
    height: 9px;
    border-radius: 999px;
    flex: none;
    background: rgba(16, 16, 20, 0.3);
}

.org-settings__status--success span { background: #1f9e5a; }
.org-settings__status--warning span { background: #ffc80a; }
.org-settings__status--danger span { background: #c83232; }

.org-settings__block--static .org-settings__status:last-child {
    margin-bottom: 0;
}

@media (max-width: 900px) {
    .org-settings {
        grid-template-columns: minmax(0, 1fr);
        gap: 18px;
    }

    /* Sectienavigatie wordt een horizontaal schuivende pillenrij; de
       organisatorkopbalk is al sticky, dus deze niet ook - twee plakkende
       balken boven elkaar eten het halve scherm op. */
    .org-settings__nav {
        position: static;
        flex-direction: row;
        overflow-x: auto;
        gap: 6px;
        border-radius: 999px;
        padding: 8px;
        -webkit-overflow-scrolling: touch;
    }

    .org-settings__navitem {
        white-space: nowrap;
        flex: none;
    }

    .org-settings__block {
        padding: 18px 16px;
        border-radius: 18px;
    }

    .org-settings__actions {
        flex-wrap: wrap;
    }

    .org-settings__actions .button {
        width: 100%;
    }

    .org-settings__scope {
        margin: 0 0 10px;
        width: 100%;
    }
}

/* Twee korte velden naast elkaar (postcode + plaats) - vouwt vanzelf op
   smalle schermen. */
.field-row {
    display: flex;
    gap: 14px;
    flex-wrap: wrap;
}

.field-row > .field {
    flex: 1 1 160px;
    min-width: 0;
}

/* Blok dat alleen de opslaanactie draagt (formulieren met eigen secties). */
.org-settings__block--actionsonly {
    padding: 14px 24px;
}

.org-settings__block--actionsonly .org-settings__actions {
    margin: 0;
    padding: 0;
    border-top: 0;
}

/* =====================================================================
   MICROCORRECTIE - GEEN TWEEDE SCHUIFBALK IN DE ORGANISATORRAIL

   Gemeten oorzaak: de zijbalk is altijd precies één viewport hoog
   (height:100dvh) MET overflow-y:auto, terwijl zijn eigen inhoud 806px
   mat - 643px echte inhoud plus 164px aan eigen ruimte (4 tussenruimtes
   van 28px en 26px padding boven en onder). Op elk scherm lager dan
   806px werd de rail daardoor een eigen scrollcontainer, met een smalle
   extra schuifbalk aan zijn rechterrand (x=270) pal naast de inhoud.

   Opgelost bij de bron: de eigen ruimte van de rail is teruggebracht,
   zodat de inhoud op een normale laptophoogte gewoon past en er dus geen
   tweede scrollcontainer meer ontstaat. overflow-y:auto blijft staan -
   op een écht lage viewport moet het accountblok bereikbaar blijven, en
   dat is precies het toegestane geval.

   Geen overflow:hidden, geen verborgen schuifbalken, geen vaste hoogtes,
   geen negatieve marges.
   ===================================================================== */

.org-sidebar {
    gap: 18px;
    padding: 18px 20px;
}

.org-sidebar__logo {
    padding-bottom: 14px;
}

.org-sidebar__org {
    padding: 13px 14px;
}

.org-sidebar__account {
    padding: 13px 14px;
}

.org-tools {
    padding-top: 2px;
}

/* Nog iets compacter, zodat de rail ook op een 1440x720-werkgebied (een
   veelvoorkomende laptop met browserchrome) zonder eigen schuifbalk past.
   Raakt alleen de maatvoering, niet de opbouw of de kleuren. */

.org-nav__item {
    padding: 9px 16px;
}

.org-nav__tool {
    padding: 6px 16px;
}

.org-tools__label {
    margin-bottom: 4px;
}

/* =====================================================================
   MICROCORRECTIE - MOBIELE SECTIENAVIGATIE PLAKT ONDER DE KOPBALK

   De organisatorkopbalk was al sticky; de pillenrij met secties schoof
   weg zodra je begon te scrollen. Nu plakken ze als één blok: kopbalk
   bovenaan, sectienavigatie er direct onder, inhoud eronder door.

   De hoogte van de kopbalk staat op ÉÉN plek (--org-header-h) en wordt
   door beide regels hergebruikt - geen tweemaal hetzelfde getal in
   losse selectors.
   ===================================================================== */

@media (max-width: 900px) {
    .org-body {
        /* 12px padding boven + 12px onder + 49px inhoud (logo/knop) */
        --org-header-h: 73px;
    }

    .org-body .org-settings__nav {
        position: sticky;
        /* Direct onder de kopbalk. Geen tussenruimte: anders schemert de
           inhoud er in een strook van 1px doorheen. */
        top: var(--org-header-h);
        z-index: 40;
        /* Ondoorzichtig, anders leest de doorscrollende inhoud mee. */
        background: var(--surface-warm, #fdfbf7);
        border: 1px solid rgba(16, 16, 20, 0.08);
        /* Één schaduw, van de balk zelf - de kopbalk heeft er geen, dus
           stapelt er niets op. */
        box-shadow: 0 6px 14px rgba(20, 20, 60, 0.06);
        margin: 0 0 4px;
    }

    /* De eerste sectiekop mag niet onder de plakkende balk verdwijnen bij
       het springen naar een anker. */
    .org-body .org-settings__section {
        scroll-margin-top: calc(var(--org-header-h) + 74px);
    }
}

/* =====================================================================
   MICROCORRECTIE - VELDFORMULIER IN TWEE KOLOMMEN OP DESKTOP

   "Wat vraag je?" en "Hoe vaak en hoe zichtbaar?" naast elkaar; de
   opslaanactie blijft ÉÉN knop, onder het raster. Panelen houden hun
   natuurlijke hoogte (align-items:start) - de rechterkolom heeft minder
   inhoud en hoeft niet kunstmatig even hoog te worden.
   ===================================================================== */

.org-formgrid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 22px;
    align-items: start;
}

@media (min-width: 900px) {
    .org-formgrid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* =====================================================================
   FASE E1 - STATISTIEKENDETAIL

   Uitsluitend de omhullende compositie: grafieken komen ongewijzigd uit
   ChartRenderer, de cijfers ongewijzigd uit EventStats. Alle gebruikte
   bouwstenen (org-stat-grid, org-panel, org-records) bestonden al.
   ===================================================================== */

/* Omhulsel om grafiek + tabel-uitklap. BEWUST een andere naam dan
   .stats-chart: die klasse staat al op de SVG die ChartRenderer zelf
   uitgeeft, en die renderer blijft ongewijzigd. */
.stats-block {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
}

/* De SVG schaalt binnen het paneel i.p.v. de pagina te verbreden, met
   een hoogtebegrenzing zodat een grafiek met weinig punten niet
   beeldvullend wordt uitgerekt. */
.stats-block > svg.stats-chart {
    display: block;
    max-width: 100%;
    max-height: 260px;
    height: auto;
    margin-top: 0;
}

/* Selector in de paneelkop - compact, in dezelfde taal als de filterbalk. */
.stats-select {
    margin: 0;
}

.stats-select label {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0;
}

.stats-select__label {
    font: 600 10px "JetBrains Mono", ui-monospace, monospace;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(16, 16, 20, 0.45);
    white-space: nowrap;
}

.stats-select select {
    background: #fff;
    border: 1px solid rgba(16, 16, 20, 0.12);
    border-radius: 999px;
    padding: 7px 14px;
    font-size: 12.5px;
    color: var(--ink, #101014);
    max-width: 100%;
}

.stats-select select:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* De deelbare URL is één lang, onafgebroken woord. Zonder expliciete
   breekregel duwde die de HELE pagina breder dan de viewport (gemeten:
   scrollWidth 394 bij een viewport van 390). Hij breekt nu binnen zijn
   eigen regel; de pagina schuift nooit horizontaal. */
/* B1.1 - "Publieke statistieken": zichtbaarheid van de openbare
   statistiekenpagina, onder de deelbare link. Hergebruikt de bestaande
   schakelaars (.switch-row/.switch, FASE E3). */
.stats-visibility {
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
}

.stats-visibility__title {
    margin: 0 0 4px;
    font-size: 1rem;
}

.stats-visibility form {
    display: grid;
    gap: 10px;
    margin-top: 12px;
}

.stats-visibility form .button {
    justify-self: start;
}

.stats-share__url {
    margin: 0 0 12px;
    font: 500 12px "JetBrains Mono", ui-monospace, monospace;
    color: rgba(16, 16, 20, 0.7);
    overflow-wrap: anywhere;
    word-break: break-all;
    min-width: 0;
}

.stats-share__actions {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

.stats-share__actions .copy-link {
    margin: 0;
}

/* Tabel-uitklap onder een grafiek: mag zelf schuiven, de pagina niet.
   Zonder de overflow hieronder duwt een tabel die smaller dan zijn
   min-content-breedte moet worden, het paneel (en daarmee de pagina)
   breder; nu schuift alleen de uitklap zelf. */
.stats-table-toggle {
    min-width: 0;
    overflow-x: auto;
}

.stats-table-toggle .data-table {
    width: 100%;
}

/* Vergelijkscherm: dezelfde twee selectors naast elkaar, met de knop
   op dezelfde regel zolang er ruimte is. */
.stats-compare {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px 20px;
}

.stats-compare .stats-select {
    min-width: 0;
}

.stats-compare .stats-select select {
    max-width: 260px;
}

@media (max-width: 700px) {
    .stats-compare {
        display: grid;
        gap: 14px;
    }

    .stats-compare .stats-select select {
        max-width: none;
    }

    .stats-select label {
        display: flex;
        width: 100%;
    }

    .stats-select select {
        flex: 1 1 auto;
        min-width: 0;
    }

    .stats-share__actions .button,
    .stats-share__actions .copy-link__btn {
        flex: 1 1 auto;
        justify-content: center;
    }
}

/* =====================================================================
   FASE E3 - WIDGETCONFIGURATOR

   Alleen de omhullende compositie van het organisatiescherm. De publieke
   widget zelf houdt zijn eigen kleine stylesheet in
   WidgetController::renderBareShell() - die staat los, omdat de widget in
   een iframe van willekeurige breedte op de site van de klant terechtkomt.
   ===================================================================== */

/* Instellingen links, voorbeeld + embedcode rechts. minmax(0, ...) zodat
   een lange URL of embedcode de kolom nooit breder kan duwen dan het
   raster toestaat. */
.widget-config {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 420px);
    gap: 20px;
    align-items: start;
    min-width: 0;
}

.widget-config__form,
.widget-config__side {
    display: flex;
    flex-direction: column;
    gap: 20px;
    min-width: 0;
}

/* Opslaan staat onderaan de instellingenkolom, altijd op dezelfde plek -
   zelfde regel als de instellingenschermen uit fase D. */
.widget-config__actions {
    display: flex;
    justify-content: flex-end;
}

.widget-toggles {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* Eén schakelrij: de schakelaar links, label + uitleg rechts. Het <label>
   omsluit de input, dus klikken op de tekst schakelt ook. */
.switch-row {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 12px;
    border-radius: 12px;
    cursor: pointer;
    min-width: 0;
}

.switch-row:hover {
    background: rgba(16, 16, 20, 0.03);
}

/* De schakelaar IS de checkbox: appearance:none laat ons hem zelf tekenen,
   maar hij blijft een echt formulierveld - tabvolgorde, spatiebalk,
   :checked-status en toegankelijkheidsboom blijven dus vanzelf kloppen. */
.switch {
    appearance: none;
    -webkit-appearance: none;
    position: relative;
    flex: 0 0 auto;
    width: 42px;
    height: 24px;
    margin: 1px 0 0;
    border-radius: 999px;
    background: rgba(16, 16, 20, 0.18);
    cursor: pointer;
    transition: background 0.15s ease;
}

.switch::after {
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 2px rgba(16, 16, 20, 0.28);
    transition: transform 0.15s ease;
}

.switch:checked {
    background: var(--brand, #5d5dff);
}

.switch:checked::after {
    transform: translateX(18px);
}

.switch:focus-visible {
    outline: 3px solid var(--focus-ring, #5d5dff);
    outline-offset: 2px;
}

.switch:disabled {
    opacity: 0.5;
    cursor: default;
}

.switch-row__text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.switch-row__label {
    font-weight: 700;
    font-size: 0.92rem;
}

.switch-row__hint {
    font-size: 0.82rem;
    line-height: 1.45;
    color: rgba(16, 16, 20, 0.55);
}

/* Het voorbeeld is de ECHTE publieke widget in een iframe. Vaste hoogte
   met eigen scroll, zodat een widget met veel evenementen het paneel niet
   eindeloos oprekt. */
.widget-preview {
    border: 1px solid rgba(16, 16, 20, 0.1);
    border-radius: 12px;
    overflow: hidden;
    background: var(--surface-muted, #f7f6f3);
}

.widget-preview__frame {
    display: block;
    width: 100%;
    height: 560px;
    border: 0;
}

/* De embedcode is één lang, onafbreekbaar fragment: hij mag binnen zijn
   eigen veld schuiven/afbreken, nooit de pagina verbreden. */
.widget-config__side textarea,
.widget-config__side input[type="text"] {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
}

@media (max-width: 1100px) {
    .widget-config {
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (max-width: 700px) {
    .widget-preview__frame {
        height: 460px;
    }

    .widget-config__actions .button {
        width: 100%;
    }
}

/* FASE E3 - "Toon subevenementen afzonderlijk" hoort alleen bij
   'Altijd alle evenementen'. Expliciet, omdat een auteursregel met een
   display-waarde het standaard [hidden]-gedrag anders kan overschrijven. */
.widget-mode-all-only {
    margin: 4px 0 0 26px;
}

.widget-mode-all-only[hidden] {
    display: none;
}

/* =====================================================================
   FASE E2 - FACTUURDETAIL (organisatie)

   Alleen compositie. Bedragen, btw, betaaltekst en groepering komen
   ongewijzigd uit InvoicePdfRenderer; hier staat alleen hoe dat oogt.
   ===================================================================== */

/* Status direct onder de paginakop: de kop zelf is gedeelde schil en
   ontsnapt elke tekst, dus de pil staat in een eigen balk eronder. */
.inv-status {
    margin: -6px 0 16px;
}

/* Specificatie breed links, betaling/gegevens/adres rechts. */
.inv-detail-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
    gap: 16px;
    align-items: start;
    min-width: 0;
}

.inv-detail-grid__main,
.inv-detail-grid__side {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

/* .org-panel heeft standaard margin-bottom 20px; binnen deze kolommen
   regelt de flex-gap de afstand (zelfde reset als .org-panel-grid). */
.inv-detail-grid .org-panel {
    margin: 0;
}

.inv-spec__group {
    margin: 14px 0 8px;
    font: 600 10.5px "JetBrains Mono", ui-monospace, monospace;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(16, 16, 20, 0.5);
}

.inv-spec__group:first-child {
    margin-top: 0;
}

/* Totaalblok onder de regels: rustige scheidingslijnen, totaal vet. */
.inv-totals {
    margin: 16px 0 0;
    padding-top: 8px;
    border-top: 1px solid rgba(16, 16, 20, 0.1);
}

.inv-totals__row,
.inv-facts__row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 16px;
    padding: 8px 0;
    min-width: 0;
}

.inv-totals__row dt,
.inv-facts__row dt {
    color: rgba(16, 16, 20, 0.6);
    font-size: 0.88rem;
}

.inv-totals__row dd,
.inv-facts__row dd {
    margin: 0;
    font-weight: 600;
    text-align: right;
    overflow-wrap: anywhere;
}

.inv-totals__row dd {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.inv-totals__row--total {
    margin-top: 4px;
    padding-top: 12px;
    border-top: 1px solid rgba(16, 16, 20, 0.12);
}

.inv-totals__row--total dt,
.inv-totals__row--total dd {
    color: var(--ink, #101014);
    font-size: 1.05rem;
    font-weight: 800;
}

.inv-facts {
    margin: 0;
}

.inv-facts__row + .inv-facts__row {
    border-top: 1px solid rgba(16, 16, 20, 0.06);
}

.inv-pay__text {
    margin: 0 0 10px;
    line-height: 1.5;
}

.inv-pay__action {
    margin: 4px 0 12px;
}

.inv-pay__note {
    margin: 8px 0 0;
    font-size: 0.82rem;
    color: rgba(16, 16, 20, 0.55);
}

.inv-address {
    margin: 0;
    line-height: 1.6;
}

@media (max-width: 1100px) {
    .inv-detail-grid {
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (max-width: 700px) {
    /* Smal: label boven de waarde, zodat een datumbereik of lange
       evenementnaam niet midden in een datum afbreekt. */
    .inv-facts__row {
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
    }

    .inv-facts__row dd {
        text-align: left;
    }

    .inv-pay__action .button {
        width: 100%;
        justify-content: center;
    }
}

/* =====================================================================
   FASE E2B - FACTURENOVERZICHT: BLADEREN + SEPA-AFSTAND

   De factuurlijst (.org-records, margin 0) stond direct boven het
   SEPA-paneel, dat alleen een ondermarge heeft - de kaart plakte dus
   tegen de laatste factuurrij. Lijst + paginering vormen nu één blok
   met dezelfde 20px ondermarge als tussen gestapelde .org-panels.
   ===================================================================== */

.inv-list {
    margin: 0 0 20px;
}

.org-pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 14px 0 0;
}

.org-pager__status {
    font: 600 10.5px 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(16, 16, 20, 0.55);
    text-align: center;
}

/* Vorige/Volgende blijven altijd op hun plek staan; op de eerste/laatste
   pagina alleen gedempt, zodat de balk niet verspringt. */
.org-pager__step.is-disabled {
    opacity: 0.4;
    pointer-events: none;
}

@media (max-width: 480px) {
    .org-pager {
        flex-wrap: wrap;
    }

    .org-pager__status {
        order: -1;
        flex-basis: 100%;
    }
}

/* =====================================================================
   FASE E4 - SCAN-CODE AANMAKEN / BEWERKEN

   Normale organisatorbreedte (niet meer page--narrow), panelen in een
   raster. Op desktop staan de instellingen links en code, geldigheid en
   verwijderen rechts; op mobiel stapelt alles in de DOM-volgorde, zodat
   de code bovenaan staat. Bestaande bouwstenen: .org-panel, .field,
   .switch-row, .copy-link, .org-status, .org-dangeraction.
   ===================================================================== */

.sc-form,
.sc-grid,
.sc-grid > div {
    min-width: 0;
}

.sc-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 20px;
    align-items: start;
}

/* Het raster regelt de afstand; de standaard ondermarge van een paneel
   zou die gap verdubbelen (zelfde reset als .org-panel-grid). */
.sc-grid .org-panel {
    margin: 0;
}

@media (min-width: 1100px) {
    .sc-grid--create,
    .sc-grid--edit {
        grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    }

    /* De laatste rij is flexibel: is de linkerkolom hoger, dan komt de
       extra ruimte onder het laatste rechterpaneel en niet ertussen. */
    .sc-grid--create {
        grid-template-areas: "toegang deur" "toegang geldig";
        grid-template-rows: auto 1fr;
    }

    .sc-grid--edit {
        grid-template-areas: "settings code" "settings geldig" "settings danger";
        grid-template-rows: auto auto 1fr;
    }

    .sc-grid__toegang { grid-area: toegang; }
    .sc-grid__deur { grid-area: deur; }
    .sc-grid__geldig { grid-area: geldig; }
    .sc-grid__settings { grid-area: settings; }
    .sc-grid__code { grid-area: code; }
    .sc-grid__danger { grid-area: danger; }
}

.sc-status {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: -6px 0 16px;
}

.sc-actions {
    display: flex;
    justify-content: flex-end;
    margin-top: 20px;
}

.sc-settings .sc-actions {
    margin-top: 16px;
}

.sc-lead {
    margin: 0 0 8px;
    font-weight: 600;
    line-height: 1.45;
}

.sc-subhead {
    margin: 22px 0 4px;
    font: 700 0.95rem "Plus Jakarta Sans", system-ui, sans-serif;
}

/* De schakelrij heeft eigen binnenruimte (hovervlak); in een paneel
   lijnt de tekst zo uit met de velden erboven. */
.sc-grid .switch-row {
    margin: 0 -12px;
}

.sc-note {
    margin: 14px 0 0;
    padding: 10px 14px;
    border-radius: 12px;
    background: rgba(93, 93, 255, 0.07);
    font-size: 0.85rem;
    line-height: 1.45;
    color: rgba(16, 16, 20, 0.7);
}

.sc-code {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    margin: 0 0 14px;
}

.sc-code__value {
    padding: 10px 16px;
    border-radius: 12px;
    background: rgba(16, 16, 20, 0.05);
    font: 700 1.6rem/1.2 "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
    letter-spacing: 0.08em;
    color: var(--ink, #101014);
    overflow-wrap: anywhere;
}

.sc-code .copy-link {
    margin: 0;
}

.sc-code__hint {
    margin: 10px 0 0;
}

.sc-facts {
    margin: 0 0 8px;
}

.sc-facts__row {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 0;
    border-top: 1px solid rgba(16, 16, 20, 0.07);
}

.sc-facts__row dt {
    color: rgba(16, 16, 20, 0.55);
}

.sc-facts__row dd {
    margin: 0;
    font-weight: 600;
    text-align: right;
}

/* Verwijderen staat los, onderaan, en oogt als gevaarzone. */
.sc-danger {
    border-color: rgba(165, 42, 42, 0.22);
    background: rgba(165, 42, 42, 0.03);
}

.sc-danger .org-panel__title {
    color: #a52a2a;
}

@media (max-width: 700px) {
    .sc-code__value {
        font-size: 1.3rem;
    }

    .sc-actions .button {
        width: 100%;
    }

    .sc-facts__row {
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
    }

    .sc-facts__row dd {
        text-align: left;
    }
}

/* FASE E5A - "Scan-code intrekken" en "Scan-code verwijderen" staan
   onder elkaar in de gevaarkolom van de bewerkpagina. */
.sc-grid__danger {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

/* =====================================================================
   FASE F1 - DEURVERKOOP: "BESTELLING AFGEROND" NA EEN CONTANTE VERKOOP

   Zelfde donkere scanner-modal, zelfde witte kaarten als de bestaande
   ticketregels. "Link kopiëren" en "QR-code tonen" tonen allebei EXACT
   dezelfde beveiligde bestel-URL. Het QR-paneel gebruikt het hidden-
   attribuut; de display-regel hieronder mag dat niet overschrijven.
   ===================================================================== */

.scan-doorsale-done {
    margin: 4px 0 14px;
    padding: 16px 18px;
    border-radius: var(--radius-panel, 16px);
    background: #101014;
    color: #ffffff;
}

.scan-doorsale-done__order {
    margin: 0 0 8px;
    font: 600 0.8rem "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
    letter-spacing: 0.06em;
    color: rgba(255, 255, 255, 0.66);
}

.scan-doorsale-done__summary {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    margin: 0 0 14px;
}

.scan-doorsale-done__amount {
    font-size: 1.35rem;
    font-weight: 800;
}

.scan-doorsale-done__count {
    font-size: 0.88rem;
    color: rgba(255, 255, 255, 0.72);
}

.scan-doorsale-done__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.scan-doorsale-done__actions .button {
    flex: 1 1 calc(50% - 5px);
    min-height: 44px;
}

.scan-doorsale-done__feedback {
    min-height: 1.2em;
    margin: 8px 0 0;
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.8);
}

.scan-doorsale-done__qr {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    margin-top: 12px;
}

.scan-doorsale-done__qr[hidden] {
    display: none;
}

.scan-doorsale-done__qr-code {
    background: #ffffff;
    border-radius: var(--radius-lg, 16px);
    padding: 14px;
    max-width: 100%;
}

/* qrcode.js levert een <svg> met alleen een viewBox: expliciete maat. */
.scan-doorsale-done__qr-code svg {
    display: block;
    width: min(260px, 64vw);
    height: auto;
}

.scan-doorsale-done__qr-hint {
    margin: 0;
    font-size: 0.82rem;
    text-align: center;
    color: rgba(255, 255, 255, 0.72);
}

/* FASE F1B - neutrale melding op het scanscherm als een voorverkoopcode
   (nog) niet kan verkopen: dan gewoon de scanner, met deze uitleg. */
.scan-app__notice {
    margin: 0 0 12px;
    padding: 10px 14px;
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.1);
    color: rgba(255, 255, 255, 0.86);
    font-size: 0.85rem;
    line-height: 1.45;
}

/* FASE F1C - scan-codes: weergave Actief / Inactief. Zelfde mono-pillen
   als .org-status en de filtermelding; gewone links (GET), geen JS. */
.sc-viewtabs {
    display: inline-flex;
    gap: 4px;
    margin: 0 0 14px;
    padding: 4px;
    border-radius: 999px;
    background: rgba(16, 16, 20, 0.06);
}

.sc-viewtabs__item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 14px;
    border-radius: 999px;
    font: 700 10px 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(16, 16, 20, 0.6);
    text-decoration: none;
}

.sc-viewtabs__item:hover {
    color: var(--ink, #101014);
}

.sc-viewtabs__item.is-active {
    background: #fff;
    color: var(--ink, #101014);
    box-shadow: 0 1px 2px rgba(16, 16, 20, 0.08);
}

.sc-viewtabs__count {
    font-weight: 600;
    color: rgba(16, 16, 20, 0.45);
}

.sc-viewtabs__item:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}

/* FASE F1D - deurverkoop op mobiel (iPhone/Safari).
   Oorzaak: het paneel is position:fixed; inset:0 met een VASTE
   padding-bottom van 110px, terwijl de mobiele tabbalk
   8 + 44 + 8 + 1 = 61px + env(safe-area-inset-bottom) hoog is. Zonder
   safe-area (deze pagina heeft geen viewport-fit=cover, dus op de iPhone
   in portret is die 0) bleef er een dode, zwarte band van 110 - 61 = 49px
   boven de tabbalk over. Daarbovenop scrolde het formulier in een TWEEDE
   scrollgebied (.scan-modal__body, flex:1 + overflow-y:auto) binnen het
   vaste paneel: de onderkant (totaal, Contant, QR-betaling) werd bij die
   band afgeknipt en op iOS pakt de vinger het buitenste paneel, dat zelf
   niets te scrollen heeft - de knoppen waren dan niet te bereiken.
   Oplossing, alleen onder 768px (daarboven zweeft de tabbalk en blijft
   alles zoals het was): het paneel stopt precies bij de bovenkant van de
   tabbalk (dezelfde maten als .scan-tab-bar, safe-area één keer) en is
   zelf het ENIGE scrollgebied. Meldingen (.scan-toast) dekken het
   zichtbare paneel, ook als er gescrold is. */
@media (max-width: 767px) {
    .scan-modal--deurverkoop {
        --scan-tabbar-space: calc(61px + env(safe-area-inset-bottom));
        bottom: var(--scan-tabbar-space);
        padding-bottom: 20px;
        overflow-y: auto;
        overscroll-behavior: contain;
        -webkit-overflow-scrolling: touch;
    }

    .scan-modal--deurverkoop > .scan-modal__body {
        flex: 0 0 auto;
        overflow: visible;
    }

    .scan-modal--deurverkoop .scan-toast {
        position: fixed;
        inset: 0 0 var(--scan-tabbar-space);
    }
}

/* FASE F1D - geldigheid bij het aanmaken van een scan-code: echte
   radioknoppen, getekend als dezelfde pillen als .sc-viewtabs. */
.sc-validity {
    margin: 0;
    padding: 0;
    border: 0;
    min-width: 0;
}

.sc-validity__options {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 4px 0 10px;
}

.sc-validity__option {
    position: relative;
    display: inline-flex;
}

.sc-validity__option input {
    position: absolute;
    inset: 0;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.sc-validity__option span {
    display: inline-block;
    padding: 8px 14px;
    border-radius: 999px;
    border: 1px solid rgba(16, 16, 20, 0.12);
    background: #fff;
    font: 700 10.5px 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(16, 16, 20, 0.65);
    white-space: nowrap;
}

.sc-validity__option input:checked + span {
    background: var(--brand);
    border-color: var(--brand);
    color: #fff;
}

.sc-validity__option input:focus-visible + span {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}


/* FASE E6A - overerving leesbaarder maken (alleen presentatie).
   Bron van de overgenomen instellingen, met de naam van het hoofdevenement
   als link naar diens beheerpagina. Normale hoofdletters, zodat een lange
   evenementnaam op mobiel gewoon kan afbreken. */
.inherit-unit__source {
    margin: 10px 0 6px;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--muted, #6b6f80);
    overflow-wrap: anywhere;
}

.inherit-unit__source a {
    color: var(--brand);
}

.inherit-switch__text {
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Samenvattingsregel bovenaan een subevenement: "Subevenement van … ·
   5 van 7 onderdelen overgenomen · Eigen instellingen: …". */
.inherit-overview {
    margin: 0 0 16px;
    font-size: 0.88rem;
    color: var(--muted, #6b6f80);
    overflow-wrap: anywhere;
}

.inherit-overview a {
    color: var(--brand);
    font-weight: 600;
}

.inherit-note a {
    font-weight: 600;
}

/* FASE E6B - dashboard-hero voor een reeks (hoofdevenement met
   subevenementen). Drie lagen die elk hun eigen scope tonen: links de
   identiteit van de hele reeks (naam, bereik, aantal), daaronder in een
   eigen vlak het eerstvolgende subevenement, en rechts - onder het label
   "Hele reeks" - de cijfers over de hele reeks. Een los evenement krijgt
   geen van deze elementen en ziet er dus ongewijzigd uit. */
.org-hero__title,
.org-hero__next-name {
    overflow-wrap: anywhere;
}

.org-hero__next {
    margin: 14px 0 0;
    padding: 10px 12px;
    border-left: 3px solid var(--brand);
    border-radius: 10px;
    background: rgba(16, 16, 20, 0.04);
}

.org-hero__next-label {
    margin: 0 0 4px;
    font: 600 10px "JetBrains Mono", ui-monospace, monospace;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(16, 16, 20, 0.5);
}

.org-hero__next-name {
    margin: 0 0 2px;
    font: 700 14px/1.3 "Plus Jakarta Sans", system-ui, sans-serif;
    color: #101014;
}

.org-hero__next .org-meta {
    margin: 0;
}

.org-hero__scope {
    margin: 0;
    font: 600 10px "JetBrains Mono", ui-monospace, monospace;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: #ffc80a;
}

/* FASE E6C - beheerpagina van een evenement (Gegevens-tab).
   Een bewuste compositie i.p.v. de .card-columns-masonry: hoofdkolom
   (Basis, Subevenementen, Ticketshop, Afbeeldingen) en een smalle
   zijkolom (Publicatie bovenaan, daaronder Verkoop en Kosten & betaling).
   Het breekpunt kijkt naar de BESCHIKBARE breedte van het formulier
   (container query), niet naar het venster: naast de organisatie-zijbalk
   is er op een 1024px-scherm maar ~690px inhoudsruimte, te smal voor twee
   kolommen met datumvelden. Kaarten houden hun eigen hoogte (geen
   min-height, geen gelijkgetrokken kolommen). */
.em-form {
    container-type: inline-size;
}

.em-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 20px;
    align-items: start;
}

.em-layout__top,
.em-layout__main,
.em-layout__side {
    display: flex;
    flex-direction: column;
    gap: 20px;
    min-width: 0;
}

.em-layout .card {
    margin-bottom: 0;
}

.em-layout__top .card,
.em-layout__side .card {
    padding: 22px 20px;
}

@container (min-width: 600px) and (max-width: 859px) {
    .em-layout__side {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        align-items: start;
    }
}

@container (min-width: 860px) {
    .em-layout {
        grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr);
        grid-template-rows: auto 1fr;
    }

    .em-layout__top {
        grid-column: 2;
        grid-row: 1;
    }

    .em-layout__main {
        grid-column: 1;
        grid-row: 1 / span 2;
    }

    .em-layout__side {
        grid-column: 2;
        grid-row: 2;
    }
}

.em-card__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin: 0 0 14px;
}

.em-card__head h3 {
    margin: 0;
}

/* Velden binnen een kaart: halve breedte waar het past, vanzelf onder
   elkaar waar het niet past; brede cellen (naam, locatie, tekstvak)
   over de volle kaartbreedte, maar niet eindeloos breed. */
.em-fields {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0 20px;
}

.em-cell {
    min-width: 0;
}

.em-cell--wide {
    grid-column: 1 / -1;
}

.em-cell--wide input[type="text"],
.em-cell--wide textarea {
    max-width: 680px;
}

.em-doors {
    max-width: 520px;
}

/* Datum/tijd/getal onder hun label (zoals de tekstvelden), niet er los
   achter geplakt. */
.em-card .em-fields input[type="datetime-local"],
.em-card .em-doors input[type="time"],
.em-card .em-doors input[type="number"] {
    display: block;
    width: 100%;
    max-width: 320px;
}

/* Doorverwijzingen (tickettypes, deurverkoop, bestelformulier): compacte
   tekstlinks i.p.v. knoppen - het zijn geen acties op dit formulier. */
.em-links {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    margin: 0 0 16px;
}

.em-note {
    margin: 0 0 8px;
}

/* FASE E6F - capaciteit in de Verkoop-kaart: de scopekeuze als echte
   fieldset (vraag + keuzes horen bij elkaar), de stand van de gedeelde
   reekscapaciteit en de subevenementen met een eigen capaciteit. */
.em-radio-group {
    margin: 0 0 16px;
    padding: 0;
    border: 0;
}

.em-radio-group legend {
    margin: 0 0 6px;
    padding: 0;
    font-weight: 600;
    font-size: 0.9rem;
}

.em-radio-group label {
    display: block;
    margin: 0 0 8px;
    font-weight: 500;
}

.em-radio-group label .hint {
    margin: 2px 0 0 22px;
}

.em-capacity__status {
    margin: 0 0 10px;
    font-weight: 600;
}

.em-capacity__label {
    margin: 0 0 4px;
    font-size: 0.85rem;
    font-weight: 600;
}

.em-capacity__list {
    margin: 0 0 12px;
    padding-left: 18px;
    font-size: 0.9rem;
}

/* Wachtkamer: het maximum pas tonen als de wachtkamer aan staat. Het
   veld blijft in het formulier (en wordt gewoon meegestuurd). */
.em-queue:not(:has(input[name="queue_enabled"]:checked)) > .field:not(.checkbox-field) {
    display: none;
}

.em-images {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 20px;
}

.em-image {
    min-width: 0;
}

.em-image__title {
    margin: 0 0 8px;
    font-weight: 700;
}

/* Uitklapper (native <details>: open/dicht wordt vanzelf aan hulpsoftware
   doorgegeven en werkt met het toetsenbord). */
.em-disclosure {
    margin: 4px 0 14px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.6);
}

.em-disclosure > summary {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 44px;
    padding: 0 14px;
    cursor: pointer;
    font-weight: 600;
    font-size: 0.9rem;
    list-style: none;
}

.em-disclosure > summary::-webkit-details-marker {
    display: none;
}

.em-disclosure > summary::before {
    content: "";
    flex-shrink: 0;
    border-left: 6px solid currentColor;
    border-top: 5px solid transparent;
    border-bottom: 5px solid transparent;
    transition: transform 0.15s ease;
}

.em-disclosure[open] > summary::before {
    transform: rotate(90deg);
}

.em-disclosure > summary:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

.em-disclosure__body {
    padding: 6px 14px 2px;
    overflow-x: auto;
}

.em-facts {
    display: grid;
    gap: 10px;
    margin: 0 0 14px;
}

.em-facts div {
    display: grid;
    gap: 2px;
}

.em-facts dt {
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--muted, #6b6f80);
}

.em-facts dd {
    margin: 0;
    font-size: 0.92rem;
}

.em-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 16px;
}

.em-status {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 0 0 14px;
}

.em-save {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 16px;
    margin: 20px 0 0;
    padding: 16px 20px;
    border: 1px solid rgba(16, 16, 20, 0.06);
    border-radius: var(--radius-panel);
    background: rgba(255, 255, 255, 0.82);
}

.em-crumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin: 0 0 4px;
    font-size: 0.92rem;
    overflow-wrap: anywhere;
}

.em-crumbs a {
    font-weight: 600;
}

.em-crumbs__sep {
    color: var(--muted, #6b6f80);
}

@media (max-width: 699px) {
    .em-save .button,
    .em-actions .button {
        flex: 1 1 auto;
        text-align: center;
    }

    .em-save .button {
        width: 100%;
    }
}

/* B2 - "E-mailbranding" (instellingen): voorbeeld van het e-maillogo op
   dezelfde witte ondergrond als de kop van de e-mails zelf. Alleen de
   organisatie-instellingen - de publieke ticketshop gebruikt deze klassen
   niet. */
.email-logo__preview {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 88px;
    margin: 12px 0 6px;
    padding: 16px;
    background: #ffffff;
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.email-logo__preview img {
    display: block;
    max-width: 240px;
    max-height: 64px;
    width: auto;
    height: auto;
}

.email-logo__fallback {
    font-weight: 700;
    font-size: 1.1rem;
    color: #101014;
    text-align: center;
    word-break: break-word;
}

.email-logo__upload {
    margin-top: 12px;
}

.email-logo__remove {
    margin-top: 10px;
}

@media (max-width: 480px) {
    .email-logo__preview img {
        max-width: 100%;
    }
}

/* Huisstijl-split (migratie 070) - Instellingen > Huisstijl in drie blokken
   (ticketshop / e-mail / PDF-ticket). Alleen de organisatie-instellingen;
   geen koperspagina gebruikt deze klassen. */
.branding-group + .branding-group {
    margin-top: 28px;
    padding-top: 20px;
    border-top: 1px solid var(--border);
}

.branding-group__title {
    margin: 0 0 12px;
    font-size: 1rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted, #6b6b7b);
}

.branding-group__label {
    margin: 0 0 4px;
    font-weight: 700;
}

.branding-color {
    margin: 0;
    padding: 0;
    border: 0;
    min-width: 0;
}

.branding-color legend {
    margin-bottom: 6px;
    padding: 0;
    font-weight: 600;
}

.branding-color__option {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 4px 0;
    font-weight: 400;
}

.branding-color__option input[type="color"] {
    width: 48px;
    height: 32px;
    padding: 0;
}

/* Voorbeeld van de logopil op het PDF-ticket: links afgerond, rechts recht
   (zelfde vorm als TicketPdfRenderer), achtergrond = opgeloste pilkleur. */
.pdf-pill-preview {
    display: inline-flex;
    align-items: center;
    max-width: 100%;
    padding: 12px 20px;
    border-radius: 999px 0 0 999px;
}

.pdf-pill-preview img {
    display: block;
    max-width: 200px;
    max-height: 48px;
    width: auto;
    height: auto;
}
