/**
 * Global design tokens + reset, loaded on every page before any component stylesheet.
 * Colors, spacing and shadows used across css/components/* are all defined here as
 * CSS custom properties so the whole site's look can be tuned from this one place.
 */
:root {
    --primary-color: #fc05cc;
    --secondary-color: #1c1d1f;
    --text-color: #2d2f31;
    --light-gray: #dbe6f1;
    --border-color: #d1d7dc;
    --white: #ffffff;
    --black: #000000;
    --orange: #d49e09;
    --purple: #050505;
    --pink: #f3a6cd;
    --background-rgb: 173, 216, 230;
    --font-primary: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    /* Koppen staan op een geometrische display-font; lopende tekst blijft Inter.
       Dat verschil tussen kop en tekst is wat een pagina "verzorgd" laat ogen. */
    --font-display: 'Poppins', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
    --shadow-hover: 0 4px 8px rgba(0, 0, 0, 0.12);
    --border-radius: 8px;
    --transition: all 0.2s ease;
    --dark_gray: #4c4f52;
    --gray: #979b9e;
    --light-light-gray: #e8ecf1;

    /* Paginakleur los van kaartkleur. --white blijft het "oppervlak" (kaarten,
       panelen, header); de pagina eronder is een tint donkerder, zodat kaarten
       vanzelf loskomen zonder dat er een rand omheen hoeft. */
    --page-bg: #f8f7fb;

    /* ---- Typografische schaal ---------------------------------------------
       Eén trap voor de hele site. De sprongen tussen de niveaus zijn bewust
       groot: een kop die maar iets groter is dan de tekst eronder leest als
       een ongeluk, een kop die duidelijk groter is leest als hiërarchie.
       Gebruik de tokens i.p.v. losse clamp()-waarden per component. */
    --fs-display: clamp(2.9rem, 6.4vw, 5.6rem);
    --fs-h1: clamp(2.2rem, 4.4vw, 3.4rem);
    --fs-h2: clamp(1.9rem, 3.4vw, 2.9rem);
    --fs-h3: clamp(1.2rem, 1.8vw, 1.55rem);
    --fs-h4: 1.05rem;
    --fs-lead: clamp(1.05rem, 1.25vw, 1.2rem);
    --fs-body: 1rem;
    --fs-small: 0.875rem;
    --fs-label: 0.72rem;

    /* Koppen strak, lopende tekst luchtig — hoe groter de tekst, hoe kleiner
       de regelafstand en de letterafstand mogen zijn. */
    --lh-display: 0.95;
    --lh-heading: 1.1;
    --lh-body: 1.6;
    --ls-display: -0.035em;
    --ls-heading: -0.02em;
    --ls-label: 0.1em;
    --fw-display: 900;
    --fw-heading: 800;

    /* Twee schaduwen met karakter naast de bestaande neutrale twee:
       --shadow-ambient is een grote, hele zachte val (diepte zonder rand),
       --shadow-hard een harde offset zonder blur (het "sticker"-effect dat
       kaarten grafisch maakt in plaats van generiek). */
    --shadow-ambient: 0 28px 90px -20px rgba(39, 27, 54, 0.16);
    --shadow-hard: 6px 6px 0 var(--secondary-color);
    --radius-pill: 999px;

    color-scheme: light;
}

/**
 * Dark theme.
 * The site's component CSS is written against these semantic tokens, so dark
 * mode is expressed almost entirely by re-pointing the tokens here (/app/core/theme.js
 * sets data-theme="dark" on <html>). `--white` is the neutral "surface" colour
 * throughout the codebase, so in dark mode it becomes a dark surface and the
 * text/heading tokens become light — flipping the whole UI with no per-component
 * edits. A few brighter accents keep contrast on the dark background.
 */
:root[data-theme="dark"] {
    --primary-color: #ff53d6;
    --secondary-color: #f4f5f7;
    --text-color: #e6e8ea;
    --white: #17181b;
    --border-color: #34363b;
    --light-gray: #2a2c31;
    --light-light-gray: #212327;
    --dark_gray: #c4c8ce;
    --gray: #9aa0a8;
    --orange: #f2b807;
    --background-rgb: 60, 64, 82;
    --shadow: 0 2px 6px rgba(0, 0, 0, 0.5);
    --shadow-hover: 0 6px 16px rgba(0, 0, 0, 0.6);
    /* Donkerder dan --white (#17181b), zodat de laagverhouding klopt: de
       pagina is de bodem, kaarten liggen er lichter bovenop. */
    --page-bg: #101014;
    --shadow-ambient: 0 28px 90px -20px rgba(0, 0, 0, 0.7);
    --shadow-hard: 6px 6px 0 rgba(255, 255, 255, 0.14);
    color-scheme: dark;
}

/* Smooth the switch between themes for the large surfaces. */
body,
.header,
.card,
.chapter-sidebar,
.course-popup {
    transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

/* Reset and Base Styles */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

/**
 * The UA's `[hidden] { display: none }` has the lowest possible specificity, so any
 * component rule with its own `display:` (e.g. a `display: flex` modal overlay) silently
 * wins and leaves the element in the layout. When that element is a fixed, full-screen,
 * opacity:0 overlay it becomes an invisible click-blocker over the whole page. Since the
 * codebase toggles visibility with the `hidden` attribute everywhere, enforce it here once.
 */
[hidden] {
    display: none !important;
}

/* Geen sleep-hoekje op tekstvelden: het botst met de strakke, "premium" look en
   voegt niets toe nu elke textarea al meegroeit of ruim genoeg is. Een enkele
   plek die het écht nodig heeft zet zelf `resize: vertical` terug. */
textarea {
    resize: none;
}

/* Blocks page scroll while an absolutely-positioned overlay anchored to normal
   document flow (e.g. the header's Explore mega-menu) is open. Without this, scrolling
   the page moves the overlay out from under a stationary pointer and fires a spurious
   mouseleave, closing the panel mid-hover. */
html.no-scroll {
    overflow: hidden;
}

html {
    min-height: 100%;
}

body {
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
    font-family: var(--font-primary);
    font-size: var(--fs-body);
    line-height: var(--lh-body);
    color: var(--text-color);
    background-color: var(--page-bg);
}

/* ---------------------------------------------------------------------------
   Koppen
   Alleen de dingen die overal hetzelfde horen te zijn staan hier: de
   display-font, een strakke regelafstand en negatieve letterafstand. De
   grootte blijft per component, want die hangt van de context af. Dit zijn
   element-selectors (laagste specificiteit), dus elke component die er iets
   anders van wil maken wint gewoon.
--------------------------------------------------------------------------- */
h1,
h2,
h3,
h4,
h5,
h6 {
    font-family: var(--font-display);
    font-weight: var(--fw-heading);
    line-height: var(--lh-heading);
    letter-spacing: var(--ls-heading);
    /* Bewust géén `color` hier: de hero en de scroll-film zijn donkere secties
       waar de kop zijn witte kleur van de sectie erft. Een kleur op deze regel
       zou die koppen donker-op-donker maken. */
}

h1 {
    font-size: var(--fs-h1);
}
h2 {
    font-size: var(--fs-h2);
}
h3 {
    font-size: var(--fs-h3);
}
h4 {
    font-size: var(--fs-h4);
}

/* Sticky footer: whatever content precedes the footer include, push the
   footer to the bottom of the viewport on short pages instead of leaving a
   background-less gap below it. */
body > div[data-include="/app/partials/footer/footer.html"] {
    margin-top: auto;
}

.container {
    width: 100%;
    max-width: min(1340px, 97vw);
    margin: 0 auto;
    padding: 0 24px;
}

/* ===========================================================================
   PREMIUM DESIGN LAYER
   Reusable primitives introduced with the teach.html redesign, promoted here so
   every page can share one polished, animated look. All additive — existing
   markup is unaffected until it opts in via these classes / [data-reveal].
   =========================================================================== */

:root {
    --accent-purple: #7b2ff7;
    --grad-brand: linear-gradient(135deg, var(--primary-color), #7b2ff7);
    --grad-brand-text: linear-gradient(120deg, var(--primary-color), #7b2ff7);
    --grad-hero: linear-gradient(150deg, #2a0930 0%, #4a0f52 46%, #7d1073 100%);
    --grad-cta: linear-gradient(135deg, #2a0930 0%, #5a1160 50%, #9a1288 100%);
    --shadow-lift: 0 22px 44px -20px rgba(80, 10, 90, 0.4);
    --radius-lg: 16px;
    --radius-xl: 26px;
}
:root[data-theme="dark"] {
    --grad-hero: linear-gradient(150deg, #1a0620 0%, #2f0a38 48%, #4c0a48 100%);
    --grad-cta: linear-gradient(135deg, #1a0620 0%, #3a0a44 50%, #5e0a58 100%);
    --shadow-lift: 0 22px 44px -18px rgba(0, 0, 0, 0.65);
}

/* --- Scroll reveal ---------------------------------------------------------
   The hidden start state only applies once /app/shared/scroll-reveal/scroll-reveal.js adds
   `.reveal-on` to <html>. So with no JS (or prefers-reduced-motion) the content
   is always visible. Stagger neighbours with style="--reveal-delay: N". */
.reveal-on [data-reveal] {
    opacity: 0;
    transform: translateY(28px);
    transition:
        opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
        transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
    transition-delay: calc(var(--reveal-delay, 0) * 90ms);
    will-change: opacity, transform;
}
.reveal-on [data-reveal].is-visible {
    opacity: 1;
    transform: none;
}

/* --- Section heading kit --------------------------------------------------- */
.section-head {
    text-align: center;
    max-width: 760px;
    margin: 0 auto 3rem;
}
.section-head--left {
    text-align: left;
    margin-left: 0;
}
.section-eyebrow {
    display: inline-block;
    font-size: var(--fs-label);
    font-weight: 700;
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    color: var(--primary-color);
    margin-bottom: 0.75rem;
}
.section-head__title {
    font-family: var(--font-display);
    font-size: var(--fs-h2);
    font-weight: var(--fw-heading);
    line-height: var(--lh-heading);
    letter-spacing: var(--ls-heading);
    color: var(--secondary-color);
    margin-bottom: 0.9rem;
}
.section-head__sub {
    font-size: var(--fs-lead);
    color: var(--dark_gray);
    line-height: var(--lh-body);
}
.text-gradient {
    background: var(--grad-brand-text);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

/* --- Premium pill button --------------------------------------------------- */
.btn-premium {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.9rem 2rem;
    background: var(--primary-color);
    color: #fff;
    border: none;
    border-radius: 100px;
    font-family: inherit;
    font-size: 1.02rem;
    font-weight: 700;
    cursor: pointer;
    text-decoration: none;
    box-shadow: 0 10px 30px -8px rgba(252, 5, 204, 0.6);
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.btn-premium i {
    transition: transform 0.2s ease;
}
.btn-premium:hover {
    transform: translateY(-2px);
    box-shadow: 0 16px 40px -8px rgba(252, 5, 204, 0.8);
}
.btn-premium:hover i {
    transform: translateX(4px);
}
.btn-premium--light {
    background: #fff;
    color: #4a0f52;
    box-shadow: 0 12px 34px -8px rgba(0, 0, 0, 0.4);
}
.btn-premium--ghost {
    background: transparent;
    color: var(--primary-color);
    border: 1.5px solid var(--border-color);
    box-shadow: none;
}
.btn-premium--ghost:hover {
    border-color: var(--primary-color);
    box-shadow: none;
}

/* --- Gradient CTA band ----------------------------------------------------- */
.cta-band {
    position: relative;
    overflow: hidden;
    isolation: isolate;
    text-align: center;
    padding: 4rem 2rem;
    border-radius: var(--radius-xl);
    background: var(--grad-cta);
    color: #fff;
    box-shadow: 0 30px 70px -30px rgba(80, 10, 90, 0.6);
}
.cta-band__glow {
    position: absolute;
    width: 520px;
    height: 520px;
    top: -60%;
    left: 50%;
    transform: translateX(-50%);
    background: radial-gradient(circle, rgba(255, 90, 220, 0.5), transparent 62%);
    filter: blur(30px);
    z-index: -1;
}

/* --- Premium card (opt-in helper) ------------------------------------------ */
.premium-card {
    position: relative;
    background: var(--white);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    overflow: hidden;
    transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
}
.premium-card::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: var(--grad-brand);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.3s ease;
}
.premium-card:hover {
    transform: translateY(-6px);
    box-shadow: var(--shadow-lift);
    border-color: transparent;
}
.premium-card:hover::before {
    transform: scaleX(1);
}

@media (prefers-reduced-motion: reduce) {
    .reveal-on [data-reveal] {
        opacity: 1;
        transform: none;
        transition: none;
    }
}

/* --- "Binnenkort beschikbaar" (opt-in helper) -------------------------------
   Voor knoppen/menu-items die nog niet zijn aangesloten. Dimt de trigger en
   toont de melding als tooltip bij hover/focus in plaats van een window.alert.
   Gebruik: class="is-coming-soon" + data-coming-soon="Tekst van de melding". */
.is-coming-soon {
    position: relative;
    opacity: 0.55;
    cursor: not-allowed;
}
.is-coming-soon::after {
    content: attr(data-coming-soon);
    position: absolute;
    bottom: calc(100% + 10px);
    left: 50%;
    transform: translateX(-50%) translateY(4px);
    width: max-content;
    max-width: 220px;
    padding: 0.5rem 0.75rem;
    border-radius: var(--radius-md, 8px);
    background: var(--secondary-color);
    color: var(--white);
    font-size: 0.78rem;
    font-weight: 500;
    line-height: 1.35;
    text-align: center;
    box-shadow: var(--shadow-hover);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease, transform 0.15s ease;
    z-index: 50;
}
.is-coming-soon::before {
    content: "";
    position: absolute;
    bottom: calc(100% + 5px);
    left: 50%;
    transform: translateX(-50%);
    border: 5px solid transparent;
    border-top-color: var(--secondary-color);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
    z-index: 50;
}
.is-coming-soon:hover::after,
.is-coming-soon:hover::before,
.is-coming-soon:focus-visible::after,
.is-coming-soon:focus-visible::before {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

/* Set by /app/core/page-guard.js on pages that require a session: hides the
   page while the auth check is in flight, so a logged-out visitor never sees
   a flash of protected content before being redirected to login. */
html[data-page-guard="pending"] body {
    visibility: hidden;
}

/* Google "One Tap" aanmeldkaart (/app/core/google-one-tap.js).
   Google rendert de kaart zelf in een iframe dat we niet kunnen herstijlen,
   maar de container en de iframe zelf mogen we wel positioneren. Zonder dit
   plakt hij in de hoek tegen de header en wordt hij aan de rand afgekapt.
   Op desktop: netjes rechts onder de header. Op mobiel: als een strakke balk
   helemaal bovenaan, over de volle breedte, zonder de witte iframe-rand. */
#credential_picker_container,
#credential_picker_iframe {
    position: fixed !important;
    top: 84px !important;
    right: 20px !important;
    left: auto !important;
    z-index: 1200 !important;
}

@media (max-width: 640px) {
    #credential_picker_container,
    #credential_picker_iframe {
        /* Onder de vaste header (68px) laten vallen in plaats van eroverheen,
           met een kleine marge zodat de kaart als kaart oogt en niet in de
           statusbalk hangt. */
        top: 76px !important;
        right: 8px !important;
        left: 8px !important;
        width: auto !important;
        max-width: calc(100vw - 16px) !important;
        /* De iframe heeft standaard een witte achtergrond; die zag je als een
           blok (met een witte rand bovenaan) om de donkere kaart heen zodra de
           iframe hoger/breder werd dan de kaart. Transparant maken laat alleen
           de kaart zelf zien. */
        background: transparent !important;
        border: 0 !important;
        box-shadow: none !important;
        color-scheme: light dark;
    }
}

/* --- Skeleton-loaders (placeholder tijdens laden vanuit de backend) ---------
   Toon een grijze "vorm" op de plek waar straks echte content komt, met een
   zacht bewegende glans eroverheen. Zo is het laadmoment niet leeg maar laat
   het zien dat er iets aankomt.

   Gebruik: geef een leeg element de class "skeleton". Vorm het met de helpers
   (skeleton--text / --title / --avatar / --thumb) of met eigen width/height.
   Zet aria-hidden="true" op de placeholder en verwijder 'm zodra de fetch klaar
   is (element.replaceWith(...) of container.innerHTML = ...).

       <div class="da-card" aria-hidden="true">
         <div class="skeleton skeleton--thumb"></div>
         <div class="skeleton skeleton--title"></div>
         <div class="skeleton skeleton--text"></div>
         <div class="skeleton skeleton--text" style="width:60%"></div>
       </div>
*/
.skeleton {
    display: block;
    border-radius: var(--radius-md, 8px);
    /* Eén doorlopende glans-golf die van links naar rechts over de héle pagina
       loopt (zoals Udemy): de gradient is met background-attachment:fixed aan
       het scherm gekoppeld, dus elk skeleton-blok laat dezelfde golf zien op
       het moment dat die zijn plek passeert. Dat leest als één beweging in
       plaats van losse blokjes die elk apart flikkeren. */
    background-color: var(--light-light-gray, #e8ecf1);
    background-image: linear-gradient(
        100deg,
        transparent 30%,
        rgba(255, 255, 255, 0.7) 50%,
        transparent 70%
    );
    background-size: 200vw 100%;
    background-repeat: no-repeat;
    background-attachment: fixed;
    animation: skeleton-sweep 1.6s linear infinite;
}
[data-theme="dark"] .skeleton {
    background-color: #2a2c30;
    background-image: linear-gradient(
        100deg,
        transparent 30%,
        rgba(255, 255, 255, 0.09) 50%,
        transparent 70%
    );
}
@keyframes skeleton-sweep {
    from { background-position: -100vw 0; }
    to   { background-position: 100vw 0; }
}

/* Zit het skeleton in een scrollend/klein paneel i.p.v. de pagina, zet dan
   op de container class="skeleton-local": de golf loopt dan over dát blok
   in plaats van over het scherm. */
.skeleton-local .skeleton {
    position: relative;
    overflow: hidden;
    background-image: none;
    animation: none;
}
.skeleton-local .skeleton::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(
        100deg,
        transparent 30%,
        rgba(255, 255, 255, 0.7) 50%,
        transparent 70%
    );
    transform: translateX(-100%);
    animation: skeleton-slide 1.6s linear infinite;
}
[data-theme="dark"] .skeleton-local .skeleton::after {
    background: linear-gradient(
        100deg,
        transparent 30%,
        rgba(255, 255, 255, 0.09) 50%,
        transparent 70%
    );
}
@keyframes skeleton-slide {
    to { transform: translateX(100%); }
}

/* Standaardvormen */
.skeleton--text   { height: 0.8em; margin: 0.4em 0; border-radius: var(--radius-pill, 999px); }
.skeleton--title  { height: 1.4em; width: 55%; margin: 0.3em 0 0.7em; border-radius: var(--radius-pill, 999px); }
.skeleton--thumb  { width: 100%; aspect-ratio: 16 / 9; border-radius: var(--radius-md, 8px); }
.skeleton--avatar { width: 44px; height: 44px; border-radius: 50%; }

/* Toegankelijkheid: geen bewegende glans, wel een subtiele puls. */
@media (prefers-reduced-motion: reduce) {
    .skeleton,
    .skeleton-local .skeleton::after { animation: none; }
    .skeleton { background-image: none; animation: skeleton-pulse 1.6s ease-in-out infinite; }
    @keyframes skeleton-pulse { 50% { opacity: 0.55; } }
}

/* --- Pagina-skeletons -------------------------------------------------------
   Volledige laad-layouts die de vorm van een pagina nabootsen (zoals Udemy).
   /app/core/include.js zet er automatisch één neer in elke <main aria-busy>
   (of #dashboard) zolang het feature-script nog aan het ophalen is; welke
   vorm hoort bij welke pagina staat in de SKELETONS-map daar.

   Bouwstenen hieronder erven allemaal de glans-golf van .skeleton. */
.sk-wrap {
    width: 100%;
    max-width: min(1340px, 97vw);
    margin: 0 auto;
    padding: 2rem 24px 4rem;
}
/* Zit de <main> zelf al in een .container (of eigen padding), dan niet nog eens
   inspringen. */
.container > .sk-wrap,
.ov > .sk-wrap,
.chapter > .sk-wrap { padding-left: 0; padding-right: 0; max-width: none; }

.sk-hero {
    height: 148px;
    border-radius: var(--radius-lg, 12px);
    margin-bottom: 1.75rem;
}
.sk-chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-bottom: 1.5rem;
}
.sk-chip { width: 96px; height: 34px; border-radius: var(--radius-pill, 999px); }
.sk-chip:nth-child(2) { width: 128px; }
.sk-chip:nth-child(3) { width: 76px; }
.sk-chip:nth-child(4) { width: 110px; }
.sk-chip:nth-child(5) { width: 88px; }

.sk-rows { display: flex; flex-direction: column; gap: 0.75rem; }
.sk-row { height: 68px; border-radius: var(--radius-lg, 12px); }

.sk-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 1rem;
}
.sk-card { height: 210px; border-radius: var(--radius-lg, 12px); }

.sk-title { height: 2rem; width: min(320px, 60%); border-radius: var(--radius-pill, 999px); margin-bottom: 0.6rem; }
.sk-sub   { height: 1rem; width: 200px; border-radius: var(--radius-pill, 999px); margin-bottom: 1.75rem; }

/* Twee kolommen: media/canvas links, lijstje rechts (speler, bouwers). */
.sk-split {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: 1.5rem;
    align-items: start;
}
.sk-media { aspect-ratio: 16 / 9; border-radius: var(--radius-lg, 12px); }
.sk-side  { height: 420px; border-radius: var(--radius-lg, 12px); }
.sk-toolbar { height: 52px; border-radius: var(--radius-md, 8px); margin-bottom: 1.25rem; }
@media (max-width: 820px) {
    .sk-split { grid-template-columns: 1fr; }
    .sk-side { height: 200px; }
}
