/* =====================================================================
   racunaj.me — main.css  (v0.1.1)
   Premium dark / neon / glassmorphism design system
   ---------------------------------------------------------------------
   No webfonts, no external libraries. System font stack only.
   All motion uses transform/opacity and is gated on prefers-reduced-motion.
   ===================================================================== */

/* ---------- 1. DESIGN TOKENS ---------- */
:root {
    --bg-0:        #06060f;
    --bg-1:        #0a0a1c;
    --bg-2:        #10102b;
    --bg-grad-a:   #0b0722;
    --bg-grad-b:   #120b33;
    --bg-grad-c:   #06060f;

    --neon-blue:   #4d7cff;
    --neon-blue-2: #63c8f5;
    --neon-purple: #9b5cff;
    --neon-violet: #b46bff;
    --neon-cyan:   #52e2fb;

    /* Text — all values below pass WCAG AA on the page background. */
    --text:        #eef0ff;
    --text-soft:   #c3c7e8;   /* ~11:1 on --bg-1 */
    --text-dim:    #9096c2;   /* ~7:1  on --bg-1 */

    --glass-bg:    rgba(255, 255, 255, 0.045);
    --glass-bg-2:  rgba(255, 255, 255, 0.07);
    --glass-brd:   rgba(255, 255, 255, 0.10);
    --glass-brd-2: rgba(155, 92, 255, 0.34);

    --glow-blue:   0 0 40px rgba(77, 124, 255, 0.32);
    --glow-purple: 0 0 50px rgba(155, 92, 255, 0.28);
    --shadow-lg:   0 30px 80px -30px rgba(0, 0, 0, 0.9);

    --grad-brand:  linear-gradient(120deg, var(--neon-blue) 0%, var(--neon-purple) 55%, var(--neon-violet) 100%);
    --grad-text:   linear-gradient(120deg, #9dbaff 0%, #cfa6ff 55%, #ffaaee 100%);

    --maxw:        1200px;
    --radius:      22px;
    --radius-sm:   14px;

    --font-sans:   -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
    --font-mono:   ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

    --ease:        cubic-bezier(0.22, 1, 0.36, 1);
    --header-h:    74px;
}

/* ---------- 2. BASE ---------- */
body {
    background:
        radial-gradient(1100px 700px at 15% -5%, rgba(77, 124, 255, 0.16), transparent 60%),
        radial-gradient(1000px 800px at 100% 0%, rgba(155, 92, 255, 0.16), transparent 55%),
        radial-gradient(900px 900px at 50% 120%, rgba(52, 230, 255, 0.07), transparent 60%),
        linear-gradient(180deg, var(--bg-grad-a) 0%, var(--bg-grad-b) 40%, var(--bg-grad-c) 100%);
    background-attachment: fixed;
    color: var(--text);
    font-family: var(--font-sans);
    line-height: 1.6;
    /* Guards against any single element causing a horizontal scrollbar. */
    overflow-x: hidden;
}

/* Body scroll lock while the mobile menu is open. */
body.menu-open {
    overflow: hidden;
    touch-action: none;
}

.rm-container {
    width: 100%;
    max-width: var(--maxw);
    margin-inline: auto;
    padding-inline: 24px;
}

section { position: relative; z-index: 2; }

h1, h2, h3, h4 {
    line-height: 1.15;
    letter-spacing: -0.02em;
    margin: 0 0 0.5em;
    font-weight: 700;
}

p { margin: 0 0 1em; }

/*
 * Same background-clip:text technique as .hero-title .accent, so the same
 * descender rule applies: the gradient is the only visible ink, and it is
 * painted only inside the background box. Without this padding the tail of a
 * j/g/p/q/y that reaches past the box is never drawn — "konačno razumiješ" in
 * the closing CTA was losing its j. Padding on an inline box extends the paint
 * area without touching line spacing, so no compensating margin is needed.
 */
.text-grad {
    padding-bottom: 0.16em;
    overflow: visible;
    background: var(--grad-text);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}

.eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--text-soft);
    padding: 7px 14px;
    border-radius: 999px;
    background: var(--glass-bg);
    border: 1px solid var(--glass-brd);
    backdrop-filter: blur(10px);
    margin-bottom: 18px;
}
.eyebrow::before {
    content: "";
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--neon-cyan);
    box-shadow: 0 0 12px var(--neon-cyan);
    flex: none;
}

.section-head {
    max-width: 660px;
    margin: 0 auto 56px;
    text-align: center;
}
.section-head h2 { font-size: clamp(1.8rem, 3.6vw, 2.7rem); }
.section-head p { color: var(--text-soft); font-size: 1.03rem; margin: 0; }

.section-foot { text-align: center; margin-top: 44px; }

.section-pad { padding-block: clamp(64px, 9vw, 118px); }

/* ---------- 3. BUTTONS ---------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 13px 25px;
    font-family: inherit;
    font-size: 0.96rem;
    font-weight: 600;
    line-height: 1.2;
    border-radius: 999px;
    border: 1px solid transparent;
    cursor: pointer;
    transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease), border-color 0.35s var(--ease);
}
.btn-primary {
    color: #fff;
    background: var(--grad-brand);
    box-shadow: 0 10px 30px -8px rgba(120, 90, 255, 0.6), inset 0 1px 0 rgba(255,255,255,0.25);
}
.btn-primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 18px 40px -10px rgba(120, 90, 255, 0.75), var(--glow-purple);
}
.btn-ghost {
    color: var(--text);
    background: var(--glass-bg);
    border-color: var(--glass-brd);
    backdrop-filter: blur(12px);
}
.btn-ghost:hover {
    transform: translateY(-2px);
    border-color: var(--glass-brd-2);
    box-shadow: var(--glow-blue);
}
.btn-lg { padding: 16px 32px; font-size: 1.02rem; }
.btn svg { width: 18px; height: 18px; flex: none; }

/* ---------------------------------------------------------------------------
   LIGA ZNANJA — the hero's second CTA
   ---------------------------------------------------------------------------
   The same button as the primary, turned down. Not a different species: same
   pill, same padding, same weight, same white text, same brand gradient — the
   gradient is simply carried at about a third of its opacity over the dark
   page, and the glow is a third as strong.

   The earlier version filled itself with near-page-black, which on this
   background reads as no fill at all, and a button with no fill reads as a
   link. Everything below exists to make it unmistakably a button.

   Only the surface is declared here. Radius, padding, font size, weight, gap
   and the transition all come from .btn / .btn-lg, so the two CTAs cannot
   drift apart.
   ------------------------------------------------------------------------- */
.btn-liga {
    position: relative;
    color: #fff;
    /* The primary's own gradient, desaturated, over a dark base so the fill
       stays legible on any part of the hero behind it. */
    background:
        linear-gradient(120deg,
            rgba(77, 124, 255, 0.34), rgba(155, 92, 255, 0.38) 55%, rgba(180, 107, 255, 0.34)),
        linear-gradient(165deg, rgba(30, 24, 74, 0.9), rgba(18, 14, 50, 0.94));
    border-color: rgba(163, 128, 255, 0.6);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    box-shadow:
        0 10px 30px -10px rgba(120, 90, 255, 0.4),
        inset 0 1px 0 rgba(255, 255, 255, 0.18);
}

/* A brighter rim, held back until hover. A gradient cannot be a border-color,
   so it is a masked ring instead — which also keeps the pill radius exact. */
.btn-liga::before {
    content: "";
    position: absolute;
    inset: -1px;
    border-radius: inherit;
    padding: 1px;
    background: linear-gradient(120deg,
        rgba(120, 170, 255, 0.9), rgba(180, 107, 255, 0.85) 55%, rgba(212, 150, 255, 0.9));
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
            mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask-composite: exclude;
    opacity: 0;
    transition: opacity 0.35s var(--ease);
    pointer-events: none;
}

/* Same 18px as every other button icon — .btn svg sets it, and this only
   restates the size so the colour and transition can sit alongside without
   the generic rule (a class-plus-type selector) overriding them. */
.btn-liga .btn-liga__ikona {
    width: 18px;
    height: 18px;
    flex: none;
    color: #dcd2ff;
    transition: transform 0.35s var(--ease);
}

@media (hover: hover) and (pointer: fine) {

    .btn-liga:hover {
        transform: translateY(-2px);
        border-color: rgba(190, 160, 255, 0.85);
        box-shadow:
            0 18px 40px -12px rgba(120, 90, 255, 0.6),
            0 0 34px -14px rgba(155, 92, 255, 0.7),
            inset 0 1px 0 rgba(255, 255, 255, 0.24);
    }

    .btn-liga:hover::before { opacity: 1; }
    .btn-liga:hover .btn-liga__ikona { transform: scale(1.08); }
}

/* A keyboard gets the same lift, plus a ring it cannot miss. */
.btn-liga:focus-visible {
    outline: 2px solid var(--neon-cyan);
    outline-offset: 3px;
    transform: translateY(-2px);
}

.btn-liga:focus-visible::before { opacity: 1; }

/* ---------- 4. GLASS ---------- */
.glass {
    background: var(--glass-bg);
    border: 1px solid var(--glass-brd);
    border-radius: var(--radius);
    backdrop-filter: blur(18px) saturate(140%);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    box-shadow: var(--shadow-lg);
    position: relative;
    overflow: hidden;
}
.glass::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(255,255,255,0.5), transparent);
    opacity: 0.55;
}

/* ---------- 5. HEADER ---------- */
.site-header {
    position: fixed;
    inset: 0 0 auto 0;
    z-index: 100;
    border-bottom: 1px solid transparent;
    transition: background 0.4s var(--ease), border-color 0.4s var(--ease);
}
.site-header.scrolled {
    background: rgba(8, 8, 22, 0.74);
    border-bottom-color: var(--glass-brd);
    backdrop-filter: blur(16px) saturate(140%);
    -webkit-backdrop-filter: blur(16px) saturate(140%);
}
.site-header .rm-container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    height: var(--header-h);
}

.brand {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-weight: 700;
    font-size: 1.16rem;
    letter-spacing: -0.02em;
    flex: none;
}
/* ---- Brand symbol ----------------------------------------------------
 * Size is driven by one custom property so the same markup works at any
 * scale. Verified legible down to 20px; 34px in the header, 30px on phones.
 */
.brand-mark {
    --brand-size: 34px;
    display: grid;
    place-items: center;
    width: var(--brand-size);
    height: var(--brand-size);
    flex: none;
}
.brand-symbol {
    display: block;
    width: 100%;
    height: 100%;
    overflow: visible;
    /* Discreet glow — enough to sit in the neon palette, not enough to bloom. */
    filter: drop-shadow(0 0 6px rgba(123, 108, 255, 0.42));
    transition: filter 0.45s var(--ease), transform 0.5s var(--ease);
}
/*
 * At rest the piece is nudged out of place and tilted; on hover it clicks
 * into alignment with the end of the rising path. transform-box:fill-box
 * makes the SVG child rotate around its own centre rather than the canvas.
 */
.brand-symbol .bs-piece {
    transform-box: fill-box;
    transform-origin: center;
    transform: translate(1.1px, -1.1px) rotate(10deg);
    transition: transform 0.5s var(--ease);
}
.brand:hover .brand-symbol,
.brand:focus-visible .brand-symbol {
    filter: drop-shadow(0 0 11px rgba(123, 108, 255, 0.72));
    transform: rotate(-3deg);
}
.brand:hover .brand-symbol .bs-piece,
.brand:focus-visible .brand-symbol .bs-piece {
    transform: translate(0, 0) rotate(0deg);
}

.brand-dot { color: var(--neon-blue-2); }
.brand-custom img { max-height: 42px; width: auto; display: block; }

.nav ul {
    display: flex;
    align-items: center;
    gap: 2px;
    list-style: none;
    margin: 0; padding: 0;
}
.nav a {
    display: inline-block;
    padding: 9px 13px;
    border-radius: 999px;
    color: var(--text-soft);
    font-size: 0.91rem;
    font-weight: 500;
    white-space: nowrap;
    transition: color 0.25s, background 0.25s;
}
.nav a:hover,
.nav .current-menu-item > a {
    color: var(--text);
    background: var(--glass-bg);
}

.header-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: none;
}
.btn-login { padding: 11px 22px; font-size: 0.92rem; }

.nav-toggle {
    display: none;
    width: 44px; height: 44px;
    border: 1px solid var(--glass-brd);
    background: var(--glass-bg);
    border-radius: 12px;
    cursor: pointer;
    align-items: center;
    justify-content: center;
    backdrop-filter: blur(10px);
    padding: 0;
}
.nav-toggle > span {
    position: relative;
    display: block;
    width: 18px; height: 2px;
    background: var(--text);
    border-radius: 2px;
    transition: background 0.2s var(--ease);
}
.nav-toggle > span::before,
.nav-toggle > span::after {
    content: "";
    position: absolute;
    left: 0;
    width: 18px; height: 2px;
    background: var(--text);
    border-radius: 2px;
    transition: transform 0.3s var(--ease), top 0.3s var(--ease);
}
.nav-toggle > span::before { top: -6px; }
.nav-toggle > span::after  { top: 6px; }
body.menu-open .nav-toggle > span { background: transparent; }
body.menu-open .nav-toggle > span::before { top: 0; transform: rotate(45deg); }
body.menu-open .nav-toggle > span::after  { top: 0; transform: rotate(-45deg); }

.nav-backdrop {
    position: fixed;
    inset: 0;
    z-index: 89;
    background: rgba(4, 4, 12, 0.6);
    opacity: 0;
    transition: opacity 0.35s var(--ease);
}
.nav-backdrop[hidden] { display: none; }
body.menu-open .nav-backdrop { opacity: 1; }

/* ---------- 6. BACKGROUND FX ---------- */
.bg-fx {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    overflow: hidden;
}
.grid-lines {
    position: absolute;
    inset: -2px;
    background-image:
        linear-gradient(rgba(120, 130, 220, 0.05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(120, 130, 220, 0.05) 1px, transparent 1px);
    background-size: 64px 64px;
    mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, #000 30%, transparent 75%);
    -webkit-mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, #000 30%, transparent 75%);
}
/*
 * Decorative formulas.
 *
 * The SVG inherits its colour through currentColor, so the tone is set once
 * here and the opacity is applied to the element rather than baked into the
 * fill — that keeps every formula inside the 0.04–0.10 band no matter which
 * layer it sits on. Height drives the scale; width follows the viewBox.
 */
.rm-formula {
    display: block;
    width: auto;
    height: 100%;
    overflow: visible;
}

.math-float {
    position: absolute;
    display: block;
    height: 2.1rem;
    color: #a9b6ff;
    opacity: 0.085;
    user-select: none;
    pointer-events: none;
    will-change: transform;
}

.cursor-glow {
    position: fixed;
    top: 0; left: 0;
    width: 460px; height: 460px;
    border-radius: 50%;
    pointer-events: none;
    z-index: 1;
    background: radial-gradient(circle, rgba(103, 126, 255, 0.15) 0%, rgba(155, 92, 255, 0.07) 35%, transparent 68%);
    opacity: 0;
    transition: opacity 0.4s ease;
    mix-blend-mode: screen;
}

/* ---------- 7. HERO ---------- */
.hero {
    position: relative;
    min-height: 100svh;
    display: flex;
    align-items: center;
    padding-top: calc(var(--header-h) + 48px);
    padding-bottom: 72px;
    overflow: hidden;
}
.hero-grid {
    display: grid;
    /* Text 54% / photo 46%. minmax(0,…) stops the long slogan lines from
       forcing the text column wider than its share. */
    grid-template-columns: minmax(0, 54fr) minmax(0, 46fr);
    gap: 48px;
    align-items: center;
    width: 100%;
}
.hero-copy { position: relative; z-index: 3; min-width: 0; max-width: 900px; }

/*
 * Sizing is constrained, not arbitrary. The longest phrase is
 * "Hajde da zajedno pronađemo"; it has to fit on one line inside the 54%
 * column of a 1200px container (~596px). At the clamp ceiling it fills ~89%,
 * which leaves headroom for wider system fonts (Segoe UI vs Noto Sans vs
 * Helvetica) so the line cannot wrap on someone else's machine.
 *
 * Raising the ceiling means widening the column, and widening the column past
 * the page container knocks the headline out of alignment with the logo above
 * it and the cards below. Re-measure before changing either number.
 */
.hero-title {
    font-size: clamp(1.9rem, 3.35vw, 2.6rem);
    /* 1.06 left the gradient spans barely taller than their own glyphs; 1.10
       adds headroom for fonts with deeper descenders than Segoe UI without
       visibly loosening the four rows. */
    line-height: 1.10;
    letter-spacing: -0.042em;
    max-width: 900px;
    margin-bottom: 28px;
    overflow: visible;
}
/*
 * Each .line is its own block, so the four desktop rows are ours, not the
 * browser's. text-wrap:balance is deliberately NOT used here — it would
 * re-break the phrases we just fixed.
 */
.hero-title .line { display: block; }
/* Blank line between the two sentences of the slogan. */
.hero-title .line-gap { display: block; height: 0.5em; }

/*
 * Emphasised words: gradient text + a soft puzzle-tile highlight behind.
 *
 * DESCENDER FIX — read before touching the padding/margin pair below.
 *
 * These spans paint their letters with `background-clip: text` while the glyph
 * fill itself is transparent. That means the ONLY visible ink is the gradient,
 * and the gradient is painted strictly inside the element's background box.
 * As an inline-block, that box is exactly `line-height` tall (1.06em), which is
 * shorter than the font's ink extent — so the tails of g, j, p, q, y fell
 * outside the painted area and simply were not drawn. Nothing was clipping
 * them; there was no gradient there to draw in the first place.
 *
 * The padding enlarges the background box so the descenders sit inside it; the
 * matching negative margin cancels the layout effect, so line spacing, the row
 * count and the column width all stay exactly as they were.
 */
.hero-title .accent {
    position: relative;
    display: inline-block;
    padding-top: 0.08em;
    padding-bottom: 0.22em;
    margin-top: -0.08em;
    margin-bottom: -0.22em;
    overflow: visible;
    vertical-align: baseline;
    background: var(--grad-text);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}
/*
 * Soft puzzle-tile glow behind the word — a hint, not a highlighter block.
 * Insets absorb the padding above so the glow sits where it always did.
 * z-index keeps it behind the letters; it never clips them.
 */
.hero-title .accent::before {
    content: "";
    position: absolute;
    inset: 0.24em -0.12em 0.34em;
    background: linear-gradient(120deg, rgba(77,124,255,0.16), rgba(180,107,255,0.16));
    border-radius: 10px;
    filter: blur(6px);
    z-index: -1;
}

.hero-sub {
    font-size: clamp(1rem, 1.4vw, 1.13rem);
    color: var(--text-soft);
    max-width: 520px;
    margin-bottom: 34px;
}
.hero-cta { display: flex; flex-wrap: wrap; gap: 14px; }

/* Hero visual */
.hero-visual {
    position: relative;
    z-index: 2;
    justify-self: center;
    min-width: 0;
    width: 100%;
    max-width: 600px;
    /* Pieces float outside the frame, so nothing here may clip. */
    overflow: visible;
}

/*
 * Photo bleed. Rather than touch the 54/46 grid split, the visual column
 * reclaims the container's own 24px padding, and on wide screens a slice of
 * the outer margin as well — the photograph grows ~11% and drifts slightly
 * right, while the text column is untouched. .hero has overflow:hidden, so
 * this can never produce a horizontal scrollbar.
 */
@media (min-width: 981px) {
    .hero-visual {
        /*
         * The room available to the right of the content column is the
         * container's 24px padding plus half the outer margin, i.e.
         * 24 + (100vw - 1200) / 2. This tracks that and stops ~8px short, so
         * the photo grows as far as each viewport allows and never reaches
         * the screen edge. A fixed value here overshot at 1280px.
         */
        --hero-bleed: clamp(12px, calc(16px + (100vw - 1200px) / 2), 56px);
        justify-self: stretch;
        max-width: none;
        width: calc(100% + var(--hero-bleed));
        margin-right: calc(-1 * var(--hero-bleed));
    }
}
.hero-photo-frame {
    position: relative;
    border-radius: 24px;
    /* Thinner frame → more of the column is actual photograph. */
    padding: 6px;
    background: var(--glass-bg);
    border: 1px solid var(--glass-brd);
    backdrop-filter: blur(10px);
    box-shadow: var(--shadow-lg), var(--glow-purple);
}
/* Neon gradient ring */
.hero-photo-frame::before {
    content: "";
    position: absolute;
    inset: -1px;
    border-radius: 25px;
    padding: 1.5px;
    background: var(--grad-brand);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    mask-composite: exclude;
    opacity: 0.65;
    pointer-events: none;
}
/* Cinematic blend with the page background */
.hero-photo-frame::after {
    content: "";
    position: absolute;
    inset: 6px;
    border-radius: 18px;
    background: linear-gradient(200deg, rgba(77,124,255,0.16), transparent 46%, rgba(155,92,255,0.20));
    mix-blend-mode: overlay;
    pointer-events: none;
}
.hero-photo-frame picture { display: block; }
/*
 * The source photo is 16:9. Cropping it to 3:2 makes the frame ~18% taller
 * at the same column width, so the photograph carries more of the hero
 * without touching the 54/46 grid split. object-position keeps both faces
 * in the upper-middle band as the sides get trimmed.
 */
.hero-photo {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 3 / 2;
    object-fit: cover;
    object-position: center 38%;
    border-radius: 18px;
    filter: contrast(1.04) saturate(1.06) brightness(0.99);
}
.hero-glow-blob {
    position: absolute;
    inset: -36px;
    z-index: -1;
    background: radial-gradient(circle at 50% 48%, rgba(155,92,255,0.32), transparent 62%);
    filter: blur(30px);
    pointer-events: none;
}

/* ---------- 8. PUZZLE PIECES ---------- */
/*
 * Each piece declares its own size and resting opacity. Text-side pieces stay
 * inside 0.18–0.40, photo-side pieces inside 0.22–0.45. The JS drift loop
 * reads --pz-rest back out, so each value is defined in exactly one place.
 */
.puzzle-piece {
    --pz-rest: 0.30;
    --pz-size: 40px;
    position: absolute;
    width: var(--pz-size);
    height: var(--pz-size);
    /* Visible by default: if JS never runs, the pieces still render correctly. */
    opacity: var(--pz-rest);
    pointer-events: none;
    filter: drop-shadow(0 6px 18px rgba(90, 80, 255, 0.35));
    will-change: transform, opacity;
}

/* ---- Layers -------------------------------------------------------------
 * Stacking order inside the hero, low to high:
 *   background fx  <  puzzle layer  <  copy / photo  <  badge
 * Each set lives in its own wrapper, so the whole group sits on one z-index
 * and no individual piece can climb over the type.
 */
.hero-puzzles {
    position: absolute;
    inset: 0;
    pointer-events: none;
    overflow: visible;   /* pieces float outside their box on purpose */
}
.hero-puzzles--text  { z-index: 0; }
.hero-puzzles--photo { z-index: 3; }

/* Everything that is actually read sits above the puzzle layer. */
.hero-copy > *:not(.hero-puzzles) {
    position: relative;
    z-index: 1;
}
/* The badge takes the top layer and gets extra room under it. */
.hero .eyebrow {
    position: relative;
    z-index: 2;
    margin-bottom: 26px;
}

/* ---- Around the text ----------------------------------------------------
 * BADGE SAFE ZONE. The badge occupies roughly x 0–42%, y 6–15% of .hero-copy.
 * Nothing is placed inside that band plus a ~24px margin:
 *   t1 clears it vertically — it sits above the block entirely, 60px up
 *   t2 clears it horizontally — starts at 52%, well past the badge's end
 * The remaining three sit in the right-hand gutter and below the slogan.
 *
 * Negative offsets are only ever used on the right, where the empty grid
 * gutter absorbs them; a negative left would hang off the viewport.
 *
 *   t1  above the block, far left
 *   t2  right of the badge
 *   t3  right gutter, beside the first slogan line
 *   t4  right gutter, level with the blank line between the two sentences
 *   t5  right of "pravi redosljed!" — that line ends at 46%
 */
.puzzle-piece.pz-t1 { --pz-rest: 0.24; --pz-size: 30px; top: -66px; left: 1%; }
.puzzle-piece.pz-t2 { --pz-rest: 0.20; --pz-size: 24px; top: 0;     left: 52%; }
/*
 * t3/t4 stay inside the text column rather than reaching into the gutter:
 * the photo's left-flank pieces live there, and at -7%/-5% the two sets came
 * within 13px of each other. The slogan lines end at 89% at their longest,
 * so 0–2% from the right edge is still clear of the type.
 */
.puzzle-piece.pz-t3 { --pz-rest: 0.32; --pz-size: 38px; top: 19%;   right: 0; }
.puzzle-piece.pz-t4 { --pz-rest: 0.22; --pz-size: 28px; top: 41%;   right: 2%; }
.puzzle-piece.pz-t5 { --pz-rest: 0.16; --pz-size: 26px; top: 61%;   left: 57%; }

/* ---- Around the photograph ---------------------------------------------
 * Spread around the frame rather than clustered under it, so they read as
 * floating rather than stuck to the edge. The middle band, where the faces
 * are, is left completely clear.
 *
 *   p1  above the top-left corner
 *   p2  above the right side
 *   p3  along the left flank
 *   p4  below left
 *   p5  below right
 */
.puzzle-piece.pz-p1 { --pz-rest: 0.30; --pz-size: 40px; top: -34px;    left: 2px; }
.puzzle-piece.pz-p2 { --pz-rest: 0.38; --pz-size: 44px; top: -30px;    right: 17%; }
.puzzle-piece.pz-p3 { --pz-rest: 0.22; --pz-size: 30px; top: 47%;      left: -8px; }
.puzzle-piece.pz-p4 { --pz-rest: 0.26; --pz-size: 34px; bottom: -30px; left: 13%; }
.puzzle-piece.pz-p5 { --pz-rest: 0.20; --pz-size: 28px; bottom: -22px; right: 5%; }

/* JS adds .js-anim once it takes over, which enables the entrance. */
.puzzle-piece.js-anim { opacity: 0; }

/*
 * Entrance finished. Opacity goes back to CSS so it keeps following the media
 * queries — if JS pinned an inline value here instead, a piece hidden at load
 * and revealed by a resize would stay stuck at opacity 0.
 */
.puzzle-piece.pz-settled { opacity: var(--pz-rest); animation: none !important; }
.puzzle-piece.js-anim.is-in { animation: pzSettle 1.5s var(--ease) forwards; }
.puzzle-piece.pz-t2.js-anim.is-in { animation-delay: 0.30s; }
.puzzle-piece.pz-t3.js-anim.is-in { animation-delay: 0.55s; }
.puzzle-piece.pz-t4.js-anim.is-in { animation-delay: 0.70s; }
.puzzle-piece.pz-p2.js-anim.is-in { animation-delay: 0.15s; }
.puzzle-piece.pz-p3.js-anim.is-in { animation-delay: 0.50s; }
.puzzle-piece.pz-p4.js-anim.is-in { animation-delay: 0.75s; }

@keyframes pzSettle {
    from { opacity: 0; transform: translate3d(0, 14px, 0) rotate(-8deg) scale(0.94); }
    to   { opacity: var(--pz-rest); transform: none; }
}

/*
 * Snap-into-place: .pair-b (by the photo) and .pz-snap (by the slogan) slide
 * in and visibly click into position once, on load. Afterwards they drift
 * with the shared JS loop like everything else.
 */
.puzzle-piece.pair-b.js-anim.is-in,
.puzzle-piece.pz-snap.js-anim.is-in { animation: pzInterlock 2s var(--ease) 0.35s forwards; }
@keyframes pzInterlock {
    0%   { opacity: 0; transform: translate3d(52px, 0, 0) rotate(12deg); }
    55%  { opacity: calc(var(--pz-rest) * 0.9); transform: translate3d(6px, 0, 0) rotate(2deg); }
    75%  { opacity: calc(var(--pz-rest) * 1.3); transform: translate3d(-2px, 0, 0) rotate(0deg); }
    100% { opacity: var(--pz-rest); transform: none; }
}

/* ---------- 9. QUICK LINKS ---------- */
.quick-links { padding-block: clamp(10px, 3vw, 30px) clamp(40px, 6vw, 70px); }
.quick-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 18px;
}
.quick-card {
    display: flex;
    flex-direction: column;
    padding: 26px 22px;
    transition: transform 0.4s var(--ease), border-color 0.4s var(--ease), box-shadow 0.4s var(--ease);
}
.quick-card:hover {
    transform: translateY(-6px);
    border-color: var(--glass-brd-2);
    box-shadow: var(--shadow-lg), var(--glow-blue);
}
.q-icon {
    width: 46px; height: 46px;
    border-radius: 12px;
    display: grid;
    place-items: center;
    margin-bottom: 16px;
    background: linear-gradient(140deg, rgba(77,124,255,0.22), rgba(155,92,255,0.22));
    border: 1px solid var(--glass-brd);
    color: var(--neon-blue-2);
}
.q-icon svg { width: 23px; height: 23px; }
.q-title { font-size: 1.08rem; margin-bottom: 6px; }
.quick-card p { font-size: 0.89rem; color: var(--text-dim); margin: 0 0 14px; }
.quick-card .c-arrow { margin-top: auto; }

.c-arrow {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    color: var(--neon-violet);
    font-weight: 600;
    font-size: 0.89rem;
    transition: gap 0.3s var(--ease);
}
.c-arrow svg { width: 17px; height: 17px; }
.quick-card:hover .c-arrow,

/* ---------- 9b. STUDENT MESSAGE ----------------------------------------
 * Bridge between choosing a class and the lesson content. Asymmetric on
 * desktop (title left, message right), single column below 900px.
 */
.student-message {
    position: relative;
    padding-block: clamp(64px, 9vw, 120px);
    overflow: hidden;          /* contains the decorative formulas */
    isolation: isolate;
}
/* Soft glow field so the block reads as its own moment on the page. */
.student-message::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -2;
    background:
        radial-gradient(760px 380px at 12% 20%, rgba(82, 226, 251, 0.10), transparent 62%),
        radial-gradient(700px 420px at 88% 85%, rgba(155, 92, 255, 0.14), transparent 62%);
    pointer-events: none;
}

.student-message__bg {
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
}
.student-message__formula {
    position: absolute;
    display: block;
    height: 1.7rem;
    color: #a9b6ff;
    opacity: 0.07;
    user-select: none;
    pointer-events: none;
    will-change: transform;
}

.student-message__grid {
    display: grid;
    /* Asymmetric on purpose — the title column carries more weight. */
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    gap: clamp(36px, 5vw, 72px);
    align-items: center;
}

/* ---- left column ---- */
.student-message__lead { min-width: 0; }

.student-message__greeting {
    font-size: clamp(1rem, 1.3vw, 1.1rem);
    color: var(--text-soft);
    letter-spacing: 0.01em;
    margin-bottom: 10px;
}

.student-message__title {
    font-size: clamp(1.8rem, 3.3vw, 2.9rem);
    line-height: 1.12;
    letter-spacing: -0.035em;
    margin-bottom: 18px;
    text-wrap: balance;
}

.student-message__after {
    font-size: clamp(0.98rem, 1.25vw, 1.08rem);
    color: var(--text-soft);
    max-width: 40ch;
    margin-bottom: 0;
}

/* Path motif: rising curve + glowing node. */
.student-message__path {
    display: block;
    width: min(320px, 100%);
    height: auto;
    margin-top: 34px;
    overflow: visible;
    filter: drop-shadow(0 0 14px rgba(93, 124, 255, 0.30));
}
.student-message__node {
    filter: drop-shadow(0 0 8px rgba(123, 108, 255, 0.85));
}

/* ---- right column ---- */
.student-message__content {
    min-width: 0;
    padding: clamp(26px, 3vw, 40px);
    border-radius: var(--radius);
    background: var(--glass-bg);
    border: 1px solid var(--glass-brd);
    backdrop-filter: blur(18px) saturate(140%);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    box-shadow: var(--shadow-lg);
    position: relative;
    overflow: hidden;
}
.student-message__content::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(255,255,255,0.5), transparent);
    opacity: 0.55;
}

.student-message__paragraph {
    font-size: clamp(1rem, 1.25vw, 1.08rem);
    line-height: 1.68;
    color: var(--text-soft);
    margin-bottom: 20px;
}
.student-message__paragraph--accent { color: var(--text); }

/* The closing line is the loudest thing in the block. */
.student-message__closing {
    font-size: clamp(1.14rem, 1.8vw, 1.5rem);
    line-height: 1.4;
    font-weight: 600;
    color: var(--text);
    letter-spacing: -0.02em;
    margin: 0;
    padding-top: 22px;
    border-top: 1px solid var(--glass-brd);
}

/*
 * Gradient accent. Same background-clip:text technique as .text-grad, so it
 * carries the same descender rule: padding-bottom keeps the tails of g/j/p/q/y
 * inside the painted background box. Without it those tails simply are not
 * drawn — "počinje", "grešaka" and "vjerujte" all depend on this.
 */
.student-message__highlight {
    padding-bottom: 0.16em;
    overflow: visible;
    background: var(--grad-text);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}

/* ---------- 10b. EXTERNAL EXAM ENTRY ----------
 * One wide horizontal panel, deliberately unlike the class cards and the
 * class chooser: the external exam is a section, not one of the classes.
 */
.ext-entry {
    position: relative;
    display: block;
    overflow: hidden;
    padding: clamp(32px, 4.4vw, 56px);
    color: inherit;
    text-decoration: none;
    background:
        radial-gradient(760px 340px at 90% 4%, rgba(99, 200, 245, 0.16), transparent 62%),
        radial-gradient(660px 340px at 4% 100%, rgba(180, 107, 255, 0.2), transparent 60%);
    transition: transform 0.45s var(--ease), border-color 0.45s var(--ease), box-shadow 0.45s var(--ease);
}
.ext-entry:hover {
    border-color: var(--glass-brd-2);
    box-shadow: var(--shadow-lg), var(--glow-blue);
}
.ext-entry__deco {
    position: absolute;
    top: 50%;
    right: clamp(20px, 3.4vw, 56px);
    transform: translateY(-50%);
    width: clamp(170px, 22vw, 280px);
    opacity: 0.5;
    pointer-events: none;
}
.ext-entry__deco svg { display: block; width: 100%; height: auto; }
/* Holds the copy clear of the curve on the right. */
.ext-entry__body { position: relative; z-index: 2; display: block; max-width: min(100%, 48ch); }
.ext-entry__title {
    font-size: clamp(1.7rem, 3vw, 2.5rem);
    line-height: 1.16;
    letter-spacing: -0.03em;
    margin: 12px 0 14px;
}
.ext-entry__text {
    color: var(--text-soft);
    line-height: 1.72;
    margin: 0 0 22px;
    max-width: 54ch;
}
.ext-entry .c-arrow { position: relative; z-index: 2; }
.ext-entry:hover .c-arrow { gap: 13px; }

/* Sign-out sits next to the account button, quieter than it. */
.btn-logout {
    margin-left: 10px;
    font-size: 0.9rem;
    color: var(--text-dim);
    text-decoration: none;
    white-space: nowrap;
}
.btn-logout:hover { color: var(--text); }

/* ---------- 11. LATEST POSTS ---------- */
.latest-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 22px;
}

/* ---------- 12. YOUTUBE CTA ----------
 * One wide glass panel: copy and buttons on the left, a video card on the
 * right. The YouTube motif is carried by the play mark alone — the palette
 * stays in the site's blue-violet range, because a red block here would read
 * as an advertisement pasted onto the page rather than part of it.
 */
.yt-cta {
    position: relative;
    padding: clamp(28px, 3.4vw, 46px);
    background:
        radial-gradient(700px 320px at 88% 6%, rgba(99, 200, 245, 0.14), transparent 62%),
        radial-gradient(640px 340px at 2% 100%, rgba(180, 107, 255, 0.18), transparent 60%);
}
/* .glass already clips, so the formulas can sit anywhere inside. */
.yt-cta__deco { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.yt-cta__formula {
    position: absolute;
    display: block;
    height: 1.7rem;
    color: #a9b6ff;
    opacity: 0.07;
    user-select: none;
    pointer-events: none;
    will-change: transform;
}

.yt-cta__grid {
    position: relative;
    z-index: 1;
    display: grid;
    /*
     * The copy column carries more weight than the card: two buttons side by
     * side need about 550px, and a narrower column would stack them.
     */
    grid-template-columns: minmax(0, 1.22fr) minmax(0, 0.98fr);
    gap: clamp(26px, 3.2vw, 46px);
    align-items: center;
}
.yt-cta__copy { min-width: 0; }
.yt-cta__title {
    font-size: clamp(1.65rem, 3vw, 2.4rem);
    line-height: 1.16;
    margin: 0 0 14px;
}
/* Keeps the accented phrase whole, so the line breaks before it, not inside it. */
.yt-cta__title .text-grad { white-space: nowrap; }
.yt-cta__text {
    color: var(--text-soft);
    line-height: 1.72;
    margin: 0 0 26px;
    max-width: 52ch;
}
.yt-cta__actions { display: flex; flex-wrap: wrap; gap: 14px; }
/* A shade tighter than .btn-lg so both buttons share one row on the desktop. */
.yt-cta__actions .btn { padding: 14px 24px; font-size: 0.95rem; }
/* The external-link arrow is quieter than the label it follows. */
.yt-cta__ext { display: inline-flex; opacity: 0.75; }
.yt-cta__ext svg { width: 15px; height: 15px; }
.yt-cta__btn svg:first-of-type { width: 21px; height: 21px; }
/* The subscribe mark, a shade larger than the shared .btn svg size. */
.yt-cta__sub-icon { display: inline-flex; }
.yt-cta__sub-icon svg { width: 20px; height: 20px; }

/* ---- the video card ---- */
.yt-card { min-width: 0; }
.yt-card__frame {
    position: relative;
    aspect-ratio: 16 / 9;
    border-radius: var(--radius);
    overflow: hidden;
    border: 1px solid var(--glass-brd);
    background: linear-gradient(158deg, #0e0d28 0%, #16113a 58%, #0a091d 100%);
    box-shadow: var(--shadow-lg), 0 0 46px -12px rgba(120, 90, 255, 0.45);
    transition: transform 0.45s var(--ease), box-shadow 0.45s var(--ease), border-color 0.45s var(--ease);
}
.yt-card:hover .yt-card__frame {
    transform: translateY(-3px);
    border-color: var(--glass-brd-2);
    box-shadow: var(--shadow-lg), 0 0 62px -10px rgba(140, 105, 255, 0.62);
}

/*
 * The board: squared paper drawn with two gradients, then real formulas from
 * the site's own set written on it. Nothing here is a raster image.
 */
.yt-card__board { position: absolute; inset: 0; }
.yt-card__board::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(rgba(160, 180, 255, 0.055) 1px, transparent 1px),
        linear-gradient(90deg, rgba(160, 180, 255, 0.055) 1px, transparent 1px);
    background-size: 34px 34px;
    mask-image: radial-gradient(ellipse 78% 78% at 50% 45%, #000 35%, transparent 82%);
    -webkit-mask-image: radial-gradient(ellipse 78% 78% at 50% 45%, #000 35%, transparent 82%);
}
.yt-card__chalk {
    position: absolute;
    display: block;
    color: #b9c8ff;
    opacity: 0.3;
    user-select: none;
}
.yt-card__chalk--a { top: 12%; left: 7%;  height: 1.55rem; }
.yt-card__chalk--b { top: 63%; left: 11%; height: 1.35rem; opacity: 0.22; }
.yt-card__chalk--c { top: 26%; right: 8%; height: 1.25rem; opacity: 0.18; }

.yt-card__play {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: clamp(58px, 6.4vw, 74px);
    height: clamp(58px, 6.4vw, 74px);
    display: grid;
    place-items: center;
    border-radius: 50%;
    color: #fff;
    background: var(--grad-brand);
    border: 1px solid rgba(255, 255, 255, 0.28);
    box-shadow: 0 14px 34px -10px rgba(120, 90, 255, 0.75), inset 0 1px 0 rgba(255, 255, 255, 0.3);
    transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease);
}
.yt-card__play svg { width: 44%; height: 44%; margin-left: 8%; }
.yt-card:hover .yt-card__play {
    transform: translate(-50%, -50%) scale(1.07);
    box-shadow: 0 18px 44px -10px rgba(140, 105, 255, 0.85), inset 0 1px 0 rgba(255, 255, 255, 0.34);
}

/* ---- the facade: thumbnail now, iframe only after the click ----------
 * Everything below sits inside .yt-card__frame, which is already 16/9 and
 * already clips. The thumbnail, the overlay and the player therefore share
 * one box and none of them can change the card's size.
 */
.yt-card__thumb {
    position: absolute;
    inset: 0;
    z-index: 1;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* The dark blue-violet wash the card had before, now over the thumbnail. */
.yt-card__veil {
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    background:
        radial-gradient(58% 58% at 50% 50%, rgba(10, 8, 32, 0.30), rgba(10, 8, 32, 0.62) 78%),
        linear-gradient(158deg, rgba(14, 13, 40, 0.55) 0%, rgba(22, 17, 58, 0.42) 58%, rgba(10, 9, 29, 0.62) 100%);
}

/* The play mark is a real button once there is something to play. */
.yt-card__play--btn {
    z-index: 3;
    padding: 0;
    font: inherit;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
}
.yt-card__play--btn:focus-visible {
    outline: 3px solid var(--neon-blue-2);
    outline-offset: 4px;
}

.yt-card__iframe {
    position: absolute;
    inset: 0;
    z-index: 4;
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
}

/* Once it is a player, the card stops behaving like a hover target. */
.yt-card__frame[data-yt-playing] { transform: none; }
.yt-card:hover .yt-card__frame[data-yt-playing] { transform: none; }

.yt-card__caption {
    margin: 14px 0 0;
    text-align: center;
    color: var(--text-soft);
    font-size: 0.94rem;
}

/* ---------- 13. ABOUT ---------- */
.about-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 52px;
    align-items: center;
}
.about-media { min-width: 0; }
.about-photo-frame {
    position: relative;
    border-radius: 24px;
    padding: 8px;
    background: var(--glass-bg);
    border: 1px solid var(--glass-brd);
    box-shadow: var(--shadow-lg);
}
.about-photo-frame::after {
    content: "";
    position: absolute;
    inset: 8px;
    border-radius: 17px;
    background: linear-gradient(210deg, rgba(77,124,255,0.14), transparent 50%, rgba(155,92,255,0.18));
    mix-blend-mode: overlay;
    pointer-events: none;
}
.about-photo-frame picture { display: block; }
.about-photo-frame img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 10;
    object-fit: cover;
    object-position: center 40%;
    border-radius: 17px;
}
.about-copy { min-width: 0; }
.about-copy h2 { font-size: clamp(1.55rem, 2.7vw, 2.15rem); margin-bottom: 18px; }
.about-copy p { color: var(--text-soft); font-size: 1.03rem; margin-bottom: 28px; }

/* PHASE 2 — two individual portraits (markup commented in section-about.php). */
.about-people { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.person { margin: 0; padding: 0; overflow: hidden; border-radius: var(--radius); }
.person img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 5; object-fit: cover; }
.person figcaption { padding: 16px; text-align: center; }
.person .p-name { font-weight: 600; }

/* ---------- 14. SUBMIT WORK ---------- */
.submit-panel {
    display: flex;
    align-items: center;
    gap: 40px;
    padding: clamp(32px, 5vw, 56px);
}
.submit-icon {
    flex: none;
    width: 96px; height: 96px;
    border-radius: 26px;
    display: grid;
    place-items: center;
    background: linear-gradient(140deg, rgba(77,124,255,0.24), rgba(155,92,255,0.24));
    border: 1px solid var(--glass-brd);
    color: var(--neon-blue-2);
    box-shadow: var(--glow-purple);
}
.submit-icon svg { width: 42px; height: 42px; }
.submit-copy { min-width: 0; }
.submit-copy h2 { font-size: clamp(1.5rem, 2.6vw, 2.05rem); margin-bottom: 12px; }
.submit-copy p { color: var(--text-soft); max-width: 620px; margin-bottom: 24px; }

/* ---------- 14b. CLASS CARD (IX-c) ----------------------------------
 * Was a strip. It serves one class, but it is the only part of the front
 * page that belongs to a specific group of pupils, so it now gets a card
 * with their photograph rather than a line of text in a pill.
 *
 * Three grid items: copy, photograph, buttons. On a phone they stack in
 * that order, so the section is read, then looked at, then acted on.
 */
.class-card { padding-block: clamp(26px, 4vw, 48px); }

.class-card__inner {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    padding: clamp(24px, 3.2vw, 44px);
    border-radius: var(--radius);
    background:
        radial-gradient(680px 320px at 6% 4%, rgba(77, 124, 255, 0.14), transparent 62%),
        radial-gradient(620px 340px at 96% 100%, rgba(180, 107, 255, 0.16), transparent 60%);
    transition: transform 0.45s var(--ease), border-color 0.45s var(--ease), box-shadow 0.45s var(--ease);
}

.class-card__inner:hover {
    transform: translateY(-3px);
    border-color: var(--glass-brd-2);
    box-shadow: var(--shadow-lg), 0 0 58px -18px rgba(140, 105, 255, 0.6);
}

/* ---- background decoration ---- */
.class-card__deco {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
}

.class-card__glow {
    position: absolute;
    border-radius: 50%;
    filter: blur(80px);
}
.class-card__glow--blue {
    width: 320px; height: 320px;
    top: -22%; left: -8%;
    background: rgba(77, 124, 255, 0.16);
}
.class-card__glow--violet {
    width: 300px; height: 300px;
    right: -6%; bottom: -26%;
    background: rgba(180, 107, 255, 0.15);
}

.class-card__formula {
    position: absolute;
    display: block;
    height: 1.6rem;
    color: #a9b6ff;
    opacity: 0.07;
    user-select: none;
    will-change: transform;
}

/* ---- layout ---- */
.class-card__grid {
    position: relative;
    z-index: 1;
    display: grid;
    /* 55 / 45, with the gap taken out of the text column rather than the photo. */
    grid-template-columns: minmax(0, 1.22fr) minmax(0, 1fr);
    grid-template-areas:
        "copy    visual"
        "actions visual";
    align-items: center;
    column-gap: clamp(24px, 3.4vw, 48px);
    row-gap: 22px;
}

.class-card__copy    { grid-area: copy; align-self: end; min-width: 0; }
.class-card__actions { grid-area: actions; align-self: start; display: flex; flex-wrap: wrap; gap: 12px; }
.class-card__visual  { grid-area: visual; min-width: 0; }

.class-card__eyebrow { margin-bottom: 14px; }

.class-card__title {
    margin: 0 0 12px;
    font-size: clamp(1.6rem, 3vw, 2.3rem);
    line-height: 1.14;
    letter-spacing: -0.02em;
}

.class-card__text {
    margin: 0;
    max-width: 46ch;
    color: var(--text-soft);
    line-height: 1.72;
}

.class-card__btn { padding: 13px 22px; font-size: 0.94rem; }

/* ---- the photograph ----------------------------------------------
 * Rounded, outlined in the site's own violet, with a veil over it so it
 * sits on the page instead of on top of it. No filter: the picture is
 * the pupils' and it stays as it is.
 */
.class-card__photo {
    position: relative;
    margin: 0;
    border-radius: calc(var(--radius) - 4px);
    overflow: hidden;
    border: 1px solid rgba(155, 92, 255, 0.30);
    box-shadow: 0 24px 60px -26px rgba(0, 0, 0, 0.9), 0 0 40px -16px rgba(140, 105, 255, 0.55);
    transition: box-shadow 0.45s var(--ease);
}

.class-card__inner:hover .class-card__photo {
    box-shadow: 0 24px 60px -26px rgba(0, 0, 0, 0.9), 0 0 56px -12px rgba(150, 115, 255, 0.75);
}

.class-card__photo img {
    display: block;
    width: 100%;
    height: auto;
    object-fit: cover;
}

.class-card__veil {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        linear-gradient(180deg, rgba(10, 8, 30, 0.10) 0%, rgba(10, 8, 30, 0.34) 100%),
        radial-gradient(120% 90% at 50% 0%, rgba(99, 200, 245, 0.10), transparent 60%);
}

.class-card__badge {
    position: absolute;
    top: 12px;
    left: 12px;
    padding: 5px 12px;
    border-radius: 999px;
    font-size: 0.76rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    color: #fff;
    background: rgba(12, 10, 34, 0.62);
    border: 1px solid rgba(255, 255, 255, 0.22);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
}

@media (max-width: 900px) {
    .class-card__grid {
        grid-template-columns: minmax(0, 1fr);
        grid-template-areas:
            "copy"
            "visual"
            "actions";
        row-gap: 20px;
    }
    .class-card__text { max-width: none; }
    .class-card__formula { display: none; }
}

@media (max-width: 560px) {
    .class-card__actions { flex-direction: column; align-items: stretch; }
    .class-card__btn { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
    .class-card__inner,
    .class-card__photo { transition: none; }
    .class-card__inner:hover { transform: none; }
}

/* ---------- 15. FINAL CTA ---------- */
.cta-final { text-align: center; }
.cta-panel {
    padding: clamp(48px, 8vw, 88px) 30px;
    text-align: center;
}
.cta-panel::after {
    content: "";
    position: absolute;
    inset: 0;
    background:
        radial-gradient(600px 300px at 50% 0%, rgba(155,92,255,0.28), transparent 60%),
        radial-gradient(600px 300px at 50% 120%, rgba(77,124,255,0.22), transparent 60%);
    pointer-events: none;
}
.cta-panel h2 {
    font-size: clamp(1.9rem, 4vw, 3rem);
    max-width: 720px;
    margin: 0 auto 18px;
    position: relative;
    z-index: 2;
}
.cta-panel p {
    color: var(--text-soft);
    font-size: 1.08rem;
    max-width: 520px;
    margin: 0 auto 32px;
    position: relative;
    z-index: 2;
}
.cta-buttons {
    display: flex;
    gap: 14px;
    justify-content: center;
    flex-wrap: wrap;
    position: relative;
    z-index: 2;
}

/* ---------- 16. NEON DIVIDER ---------- */
.neon-divider {
    position: relative;
    height: 1px;
    max-width: var(--maxw);
    margin: 0 auto;
    background: linear-gradient(90deg, transparent, rgba(77,124,255,0.5), rgba(155,92,255,0.5), transparent);
    z-index: 3;
    overflow: hidden;
}
.neon-divider::before {
    content: "";
    position: absolute;
    top: -1px; left: 0;
    width: 90px; height: 3px;
    background: var(--neon-cyan);
    filter: blur(2px);
    border-radius: 4px;
    animation: dataFlow 7s linear infinite;
}
@keyframes dataFlow {
    0%   { transform: translateX(-120px); opacity: 0; }
    15%  { opacity: 1; }
    85%  { opacity: 1; }
    100% { transform: translateX(var(--maxw)); opacity: 0; }
}

/* ---------- 17. FOOTER ---------- */
.site-footer {
    position: relative;
    z-index: 3;
    margin-top: 60px;
    padding-top: 70px;
    border-top: 1px solid var(--glass-brd);
    background: rgba(6, 6, 16, 0.6);
    backdrop-filter: blur(10px);
}
.footer-grid {
    display: grid;
    grid-template-columns: 1.6fr 1fr 1fr 1fr;
    gap: 40px;
    padding-bottom: 50px;
}
.footer-brand p {
    color: var(--text-dim);
    font-size: 0.91rem;
    max-width: 320px;
    margin-top: 16px;
}
.footer-col h2 {
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-soft);
    margin-bottom: 16px;
}
.footer-col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.footer-col a { color: var(--text-dim); font-size: 0.91rem; transition: color 0.25s; }
.footer-col a:hover { color: var(--text); }

.footer-social { display: flex; gap: 10px; margin-top: 20px; }
.footer-social a {
    width: 40px; height: 40px;
    display: grid;
    place-items: center;
    border-radius: 12px;
    background: var(--glass-bg);
    border: 1px solid var(--glass-brd);
    color: var(--text-soft);
    transition: transform 0.3s var(--ease), color 0.3s, border-color 0.3s, box-shadow 0.3s;
}
.footer-social a:hover {
    transform: translateY(-3px);
    color: #fff;
    border-color: var(--glass-brd-2);
    box-shadow: var(--glow-purple);
}
.footer-social svg { width: 18px; height: 18px; }

.footer-bottom {
    border-top: 1px solid var(--glass-brd);
    padding: 22px 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    color: var(--text-dim);
    font-size: 0.85rem;
}

/* The signature. width:100% is what puts it on its own line — .footer-bottom
   already wraps, so nothing above needs changing. A step quieter than the rest
   of the row: smaller, dimmer, and it only warms up if you point at it. */
.footer-potpis {
    width: 100%;
    margin: 6px 0 0;
    text-align: center;
    font-size: 0.76rem;
    line-height: 1.65;
    letter-spacing: 0.01em;
    /* 4.7:1 on the footer background — past the AA threshold, and still a full
       step quieter than the copyright line above it, which sits at 6.8:1.
       Discreet should mean softer, not harder to read. */
    color: rgba(163, 155, 210, 0.75);
    transition: color 0.35s var(--ease);
}

/* The name and the heart never split across lines — see footer.php. */
.footer-potpis__ime { white-space: nowrap; }

.footer-potpis__srce {
    /* Slightly under the text size: present, never the loudest thing here. */
    font-size: 0.92em;
    opacity: 0.75;
    transition: opacity 0.35s var(--ease);
}

@media (hover: hover) and (pointer: fine) {
    .footer-potpis:hover { color: rgba(196, 178, 255, 0.9); }
    .footer-potpis:hover .footer-potpis__srce { opacity: 1; }
}

@media (max-width: 620px) {
    .footer-potpis {
        margin-top: 10px;
        font-size: 0.74rem;
        /* Breaks between words on a narrow screen, never mid-name. */
        overflow-wrap: break-word;
    }
}

/* ---------- 18. PAGES / POSTS ---------- */
.page-hero {
    padding-top: calc(var(--header-h) + 60px);
    padding-bottom: 40px;
    text-align: center;
}
.page-hero h1 { font-size: clamp(1.9rem, 4vw, 3rem); }
.page-hero .meta { color: var(--text-dim); font-size: 0.9rem; margin: 0; }

/* A hero that is only a heading. The 40px below the title existed to separate
   it from the meta line; with nothing there it reads as a gap, so it is cut to
   the breathing room the heading itself wants. The h1's own margin is zeroed
   for the same reason — nothing follows it inside the header. */
.page-hero--naslov { padding-bottom: 18px; }
.page-hero--naslov h1 { margin-bottom: 0; }

@media (max-width: 620px) {
    .page-hero--naslov { padding-bottom: 12px; }
}

.content-area {
    max-width: 760px;
    margin: 0 auto;
    padding: 40px 24px 90px;
}
.entry-content { color: var(--text-soft); font-size: 1.04rem; }
.entry-content a { color: var(--neon-blue-2); text-decoration: underline; text-underline-offset: 3px; }
.entry-content h2, .entry-content h3 { color: var(--text); margin-top: 1.6em; }
.entry-content img { border-radius: var(--radius-sm); height: auto; }
.entry-content blockquote {
    border-left: 3px solid var(--neon-purple);
    padding-left: 20px;
    margin-left: 0;
    color: var(--text);
    font-style: italic;
}
.entry-content pre {
    background: var(--bg-2);
    border: 1px solid var(--glass-brd);
    border-radius: var(--radius-sm);
    padding: 18px;
    overflow-x: auto;
    font-family: var(--font-mono);
    font-size: 0.9rem;
}
.entry-content code { font-family: var(--font-mono); font-size: 0.9em; }
.entry-content table { width: 100%; border-collapse: collapse; display: block; overflow-x: auto; }

.post-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
    max-width: var(--maxw);
    margin: 0 auto;
    padding: 40px 24px 90px;
}
.post-card { display: flex; flex-direction: column; }
.post-card .thumb { display: block; aspect-ratio: 16 / 10; overflow: hidden; }
.post-card .thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.post-card .thumb.placeholder {
    background: linear-gradient(140deg, rgba(77,124,255,0.2), rgba(155,92,255,0.2));
    display: grid;
    place-items: center;
    font-family: var(--font-mono);
    color: rgba(255,255,255,0.35);
}
.post-card .p-body { padding: 22px; display: flex; flex-direction: column; gap: 10px; flex: 1; }
.post-card h3 { font-size: 1.13rem; margin: 0; }
.post-card .p-excerpt { color: var(--text-dim); font-size: 0.91rem; flex: 1; margin: 0; }
.post-card .p-date { color: var(--text-dim); font-size: 0.79rem; font-family: var(--font-mono); }

.rm-pagination { display: flex; justify-content: center; gap: 8px; padding-bottom: 80px; flex-wrap: wrap; }
.rm-pagination a, .rm-pagination span {
    padding: 10px 16px;
    border-radius: 12px;
    background: var(--glass-bg);
    border: 1px solid var(--glass-brd);
    color: var(--text-soft);
}
.rm-pagination .current { background: var(--grad-brand); color: #fff; border-color: transparent; }

.error-404 {
    min-height: 78vh;
    display: grid;
    place-items: center;
    text-align: center;
    padding: calc(var(--header-h) + 60px) 24px 80px;
}
.error-404 .code {
    font-size: clamp(5rem, 18vw, 11rem);
    font-weight: 800;
    line-height: 1;
    letter-spacing: -0.04em;
}
.error-404 .lead { color: var(--text-soft); max-width: 460px; margin: 0 auto 30px; }
.error-404 .actions { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }

/*
 * 404 decoration. A separate absolutely-positioned layer, so the page layout
 * above is untouched. overflow:hidden on the section keeps a formula from
 * pushing the document wider on a narrow screen.
 */
.error-404 { position: relative; overflow: hidden; }

.error-404__math {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
}
.error-404 .rm-container { position: relative; z-index: 1; }

.e404-formula {
    position: absolute;
    display: block;
    height: 2.2rem;
    color: #a9b6ff;
    opacity: 0.075;
    user-select: none;
    pointer-events: none;
}
.e404-formula--tl { top: 12%; left: 5%; }
.e404-formula--tr { top: 15%; right: 5%; }
.e404-formula--ml { top: 46%; left: 3%; }
.e404-formula--mr { top: 44%; right: 3%; height: 3.4rem; }
/* 2%, not 10% — at 10% this sat on top of the action buttons. */
.e404-formula--b  { bottom: 2%; left: 50%; transform: translateX(-50%); }

@media (max-width: 860px) {
    /* Only the corners survive; the flanks would sit under the text. */
    .e404-formula { height: 1.7rem; opacity: 0.06; }
    .e404-formula--ml,
    .e404-formula--mr { display: none; }
    .e404-formula--tl { top: 7%; left: 3%; }
    .e404-formula--tr { top: 10%; right: 3%; }
    .e404-formula--b  { bottom: 2%; }
}

/* ---------- 19. REVEAL ---------- */
[data-reveal] {
    opacity: 0;
    transform: translateY(28px);
    transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
}

/*
 * The path draws itself once the section scrolls into view. pathLength="100"
 * on the <path> means the dash values are percentages, independent of the
 * real curve length.
 *
 * Default state is fully drawn. JS adds .js-draw before it starts observing,
 * which is what winds the curve back — so if the script never runs, the motif
 * is still there rather than invisible.
 */
.student-message__curve {
    stroke-dasharray: 100;
    stroke-dashoffset: 0;
    transition: stroke-dashoffset 2.4s var(--ease);
}
.student-message.js-draw .student-message__curve { stroke-dashoffset: 100; }
.student-message.js-draw.is-visible .student-message__curve { stroke-dashoffset: 0; }

.student-message__node,
.student-message__node-ring {
    opacity: 1;
    transition: opacity 0.7s var(--ease) 1.5s;
}
.student-message.js-draw .student-message__node,
.student-message.js-draw .student-message__node-ring { opacity: 0; }
.student-message.js-draw.is-visible .student-message__node,
.student-message.js-draw.is-visible .student-message__node-ring { opacity: 1; }

.student-message.is-visible .student-message__node-ring {
    animation: smPulse 3.6s var(--ease) 2.1s infinite;
}
@keyframes smPulse {
    0%, 100% { transform: scale(1);    opacity: 0.5; }
    50%      { transform: scale(1.28); opacity: 0.12; }
}
.student-message__node-ring {
    transform-box: fill-box;
    transform-origin: center;
}
[data-reveal].is-visible { opacity: 1; transform: none; }
[data-reveal-delay="1"] { transition-delay: 0.08s; }
[data-reveal-delay="2"] { transition-delay: 0.16s; }
[data-reveal-delay="3"] { transition-delay: 0.24s; }
[data-reveal-delay="4"] { transition-delay: 0.32s; }

/* ---------- 19b. FLOATING YOUTUBE BUTTON ----------
 * A pill in the corner: circular at rest, opening on hover and on keyboard
 * focus to show its label. Deliberately not the red YouTube button — the
 * motif is the play mark, the colour is the site's indigo-violet, and red
 * appears only as a hover accent in the glow.
 *
 * z-index 80 is below the header (100), the mobile menu (90) and its backdrop
 * (89), and far below the Liga modals (9000+). A corner button must never sit
 * on top of navigation or a dialog.
 *
 * --rm-fab-bottom is the one knob another component needs: a cookie banner or
 * a second floating action can raise the button by setting it on :root or on
 * body, without touching anything here.
 */
:root { --rm-fab-bottom: 22px; }

.rm-fab {
    position: fixed;
    right: 22px;
    bottom: calc(var(--rm-fab-bottom) + env(safe-area-inset-bottom, 0px));
    z-index: 80;

    display: inline-flex;
    align-items: center;
    /* 24px icon + 16px either side + 1px border = a 58px circle at rest. */
    height: 58px;
    padding: 0 16px;
    border-radius: 999px;
    color: #fff;
    text-decoration: none;

    /*
     * Semi-transparent on purpose: the backdrop filter has something to work
     * with, so the button reads as glass over the page rather than a sticker.
     * The stops stay dark enough for white text to clear AA.
     */
    background:
        linear-gradient(135deg, rgba(96, 45, 215, 0.95) 0%, rgba(58, 72, 205, 0.94) 55%, rgba(52, 88, 200, 0.92) 100%);
    border: 1px solid rgba(255, 255, 255, 0.18);
    box-shadow:
        0 14px 34px -12px rgba(80, 55, 200, 0.9),
        0 0 0 1px rgba(255, 205, 130, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.26);
    backdrop-filter: blur(14px) saturate(150%);
    -webkit-backdrop-filter: blur(14px) saturate(150%);

    animation: rm-fab-glow 5s ease-in-out infinite;
    transition:
        transform 0.32s var(--ease),
        box-shadow 0.32s var(--ease),
        padding 0.34s var(--ease);
}
.rm-fab--left { left: 22px; right: auto; }

.rm-fab__icon {
    display: grid;
    place-items: center;
    width: 24px;
    height: 24px;
    flex: none;
    transition: transform 0.32s var(--ease);
}
.rm-fab__icon svg { width: 100%; height: 100%; display: block; }

/*
 * Closed: the label takes no width at all. Open: it gets room and fades in.
 * max-width rather than display keeps the transition animatable, and nowrap
 * means the words can never be cut mid-line while it grows.
 */
.rm-fab__label {
    max-width: 0;
    margin-left: 0;
    overflow: hidden;
    white-space: nowrap;
    opacity: 0;
    font-weight: 600;
    font-size: 0.95rem;
    letter-spacing: -0.01em;
    transition:
        max-width 0.34s var(--ease),
        margin-left 0.34s var(--ease),
        opacity 0.24s var(--ease);
}

/*
 * Opening on keyboard focus works on every device and stays unconditional.
 *
 * Opening on hover does not: a touch screen has no hover, so it synthesises
 * one on tap and leaves it applied until the next tap somewhere else. The
 * button would sit there open, mid-animation, after the finger lifted. The
 * hover half is therefore gated on a pointer that can actually hover, which
 * also fixes the touch tablet at 800px that the width-based rules missed.
 */
.rm-fab:focus-visible {
    transform: translateY(-3px);
    /* A little more air after the label than before the icon: 58px → ~174px. */
    padding-right: 22px;
    box-shadow:
        0 20px 44px -12px rgba(90, 60, 220, 0.95),
        0 0 0 1px rgba(255, 205, 130, 0.34),
        0 0 26px -6px rgba(255, 60, 60, 0.34),
        inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.rm-fab:focus-visible .rm-fab__label {
    max-width: 130px;
    margin-left: 12px;
    opacity: 1;
}
.rm-fab:focus-visible .rm-fab__icon { transform: scale(1.12); }

@media (hover: hover) and (pointer: fine) {

    .rm-fab:hover {
        transform: translateY(-3px);
        padding-right: 22px;
        box-shadow:
            0 20px 44px -12px rgba(90, 60, 220, 0.95),
            0 0 0 1px rgba(255, 205, 130, 0.34),
            0 0 26px -6px rgba(255, 60, 60, 0.34),
            inset 0 1px 0 rgba(255, 255, 255, 0.3);
    }
    .rm-fab:hover .rm-fab__label {
        max-width: 130px;
        margin-left: 12px;
        opacity: 1;
    }
    .rm-fab:hover .rm-fab__icon { transform: scale(1.12); }
}

.rm-fab:focus-visible {
    outline: 3px solid var(--neon-cyan);
    outline-offset: 3px;
}

/* The glow breathes; the button itself never moves on its own. */
@keyframes rm-fab-glow {
    0%, 100% {
        box-shadow:
            0 14px 34px -12px rgba(80, 55, 200, 0.9),
            0 0 0 1px rgba(255, 205, 130, 0.18),
            inset 0 1px 0 rgba(255, 255, 255, 0.26);
    }
    50% {
        box-shadow:
            0 14px 40px -12px rgba(120, 80, 255, 0.95),
            0 0 0 1px rgba(255, 205, 130, 0.3),
            inset 0 1px 0 rgba(255, 255, 255, 0.26);
    }
}

/* The open mobile menu owns the screen; the corner button steps aside. */
body.menu-open .rm-fab {
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.25s var(--ease), visibility 0s linear 0.25s;
}

/* ---------- 20. RESPONSIVE ---------- */
@media (max-width: 1080px) {
    .nav a { padding: 9px 10px; font-size: 0.88rem; }
}

@media (max-width: 980px) {
    .hero {
        /* Content decides the height on tablet/mobile — no forced 100vh. */
        min-height: 0;
        padding-top: calc(var(--header-h) + 36px);
        padding-bottom: 56px;
    }
    .hero-grid { grid-template-columns: 1fr; gap: 40px; }
    /* Text first, photo below. */
    .hero-copy { order: 1; max-width: none; }
    .hero-visual { order: 2; max-width: 560px; }

    .hero-title {
        font-size: clamp(1.75rem, 4.6vw, 2.4rem);
        line-height: 1.14;
        letter-spacing: -0.03em;
        max-width: none;
    }
    /*
     * Tablet and phone: drop the hand-placed breaks and let each sentence
     * reflow as a paragraph. Keeping .line as a block here would strand
     * short phrases like "pravi redosljed!" on rows of their own.
     */
    .hero-title .line { display: inline; }
    .hero-title .line-gap { height: 0.42em; }

    /*
     * Single column from here down, so there is no grid gutter for pz-t3 to
     * bleed into — a negative offset would hang off the screen edge and get
     * clipped. Pull it back inside.
     */
    .puzzle-piece.pz-t3 { right: 2%; }

    .quick-grid { grid-template-columns: repeat(2, 1fr); }
    .about-grid { grid-template-columns: 1fr; gap: 36px; }
    .about-media { order: 2; }
    .about-copy { order: 1; }
    .latest-grid { grid-template-columns: repeat(2, 1fr); }
    .footer-grid { grid-template-columns: 1fr 1fr; }
    .post-grid { grid-template-columns: repeat(2, 1fr); }
    .submit-panel { gap: 28px; }
    .submit-icon { width: 76px; height: 76px; border-radius: 20px; }
    .submit-icon svg { width: 34px; height: 34px; }

    /*
     * One column. Source order already reads copy → buttons → card, which is
     * the order asked for on a phone, so nothing needs reordering here.
     */
    .yt-cta__grid { grid-template-columns: 1fr; gap: clamp(26px, 4vw, 36px); }
    .yt-cta__text { max-width: none; }
    /*
     * Keeps the card from stretching to a strip on a wide tablet. width:100%
     * is not redundant: an auto inline margin turns off the grid item's
     * stretch, and without it the card shrinks to the width of its caption.
     */
    .yt-card { width: 100%; max-width: 560px; margin-inline: auto; }
}

@media (max-width: 860px) {
    .nav {
        position: fixed;
        inset: var(--header-h) 0 auto 0;
        max-height: calc(100svh - var(--header-h));
        overflow-y: auto;
        padding: 16px 24px 28px;
        background: rgba(8, 8, 22, 0.97);
        backdrop-filter: blur(20px);
        -webkit-backdrop-filter: blur(20px);
        border-bottom: 1px solid var(--glass-brd);
        transform: translateY(-115%);
        transition: transform 0.4s var(--ease);
        z-index: 90;
    }
    body.menu-open .nav { transform: translateY(0); }
    .nav ul { flex-direction: column; align-items: stretch; gap: 4px; }
    .nav a { padding: 14px 16px; font-size: 1rem; white-space: normal; }
    .nav-toggle { display: inline-flex; }

    .submit-panel { flex-direction: column; text-align: center; align-items: center; }
    .submit-copy .eyebrow { margin-inline: auto; }

    /* Single column: title first, then the message. */
    .student-message__grid { grid-template-columns: 1fr; gap: 32px; }
    .student-message__lead { order: 1; }
    .student-message__content { order: 2; }
    .student-message__after { max-width: none; }
    .student-message__path { margin-top: 26px; }

    /*
     * Stacking makes the section much taller, so the percentage positions that
     * sat in the padding strips on desktop would now fall behind the glass
     * panel. Pin the remaining formulas to the top strip instead.
     */
    .student-message__bg .student-message__formula:nth-child(1) { top: 2%; left: 3%; }
    .student-message__bg .student-message__formula:nth-child(2) { top: 2%; left: 58%; }
    .student-message__bg .student-message__formula:nth-child(3) { display: none; }
}

/* Below this the curve and the copy fight for the same space. */
@media (max-width: 860px) {
    .ext-entry__deco {
        position: static;
        transform: none;
        display: block;
        width: 170px;
        margin-bottom: 20px;
    }
    .ext-entry__body { max-width: none; }
}

@media (max-width: 680px) {
    .quick-grid { grid-template-columns: 1fr; }
    .latest-grid { grid-template-columns: 1fr; }
    .post-grid { grid-template-columns: 1fr; }
    .footer-grid { grid-template-columns: 1fr; gap: 30px; }
    .footer-bottom { justify-content: center; text-align: center; }

    /* CTAs stack full-width so they stay comfortable thumb targets. */
    .hero-cta, .cta-buttons, .yt-cta__actions { flex-direction: column; align-items: stretch; }
    .hero-cta .btn, .cta-buttons .btn, .yt-cta__actions .btn { width: 100%; }
    /* At 360px the primary label wrapped onto a second line; 20px keeps it on one. */
    .yt-cta__actions .btn { padding-inline: 20px; }

    /*
     * The panel is narrow enough on a phone that a formula behind the copy
     * reads as smudge rather than texture. Two survive, quieter, in the
     * corners the text does not reach.
     */
    .yt-cta__formula { height: 1.4rem; opacity: 0.055; }
    .yt-cta__formula:nth-of-type(2) { display: none; }
    .yt-card__chalk--c { display: none; }

    /*
     * Phone: a compact rounded square, not a circle.
     *
     * A 58px pill designed to open sideways is a desktop object. Shrunk onto a
     * phone it reads as an oversized bubble sitting on the photograph behind
     * it. A 50px squircle with a 15px radius belongs to the same family as
     * every other card on the site and takes up noticeably less of the screen,
     * while staying above the 44px minimum for a touch target.
     *
     * The label is gone here, and the opening animation with it: there is
     * nothing to open into, so every part of it is switched off rather than
     * left to fire invisibly on tap. min-width holds the square against the
     * padding change the hover rule would otherwise still apply.
     */
    :root { --rm-fab-bottom: 14px; }

    .rm-fab {
        right: 14px;
        width: 50px;
        min-width: 50px;
        height: 50px;
        padding: 0;
        justify-content: center;
        border-radius: 15px;
    }
    .rm-fab--left { left: 14px; right: auto; }

    .rm-fab__icon { width: 22px; height: 22px; }

    .rm-fab__label { display: none; }

    /* Nothing moves, grows or lifts on touch. */
    .rm-fab:hover,
    .rm-fab:focus-visible,
    .rm-fab:active {
        transform: none;
        padding: 0;
    }
    .rm-fab:hover .rm-fab__icon,
    .rm-fab:focus-visible .rm-fab__icon,
    .rm-fab:active .rm-fab__icon { transform: none; }
    .rm-fab:hover .rm-fab__label,
    .rm-fab:focus-visible .rm-fab__label { max-width: 0; margin-left: 0; opacity: 0; }

    .btn-login { padding: 10px 16px; font-size: 0.87rem; }
    .brand { font-size: 1.05rem; }
    .brand-mark { --brand-size: 30px; }

    /* Simpler decoration and tighter rhythm for the student message. */
    .student-message { padding-block: clamp(52px, 12vw, 76px); }
    .student-message__path { width: min(240px, 100%); margin-top: 22px; }
    .student-message__formula { font-size: 0.9rem; }
    /* Two background formulas are enough at this width. */
    .student-message__bg .student-message__formula:nth-child(3) { display: none; }
    .student-message__content { padding: 24px 20px; }
    .student-message__closing { padding-top: 18px; }

    /*
     * Phones keep 4 of the 8 pieces — two by the text, two by the photo —
     * at reduced size and opacity. The JS loop also halves its drift
     * amplitude at this width.
     */
    /*
     * Phones keep 6 of the 10 — three by the text, three by the photo — at
     * 20–30% smaller sizes. They are spread deliberately so no two land in the
     * same corner, and the whole badge row is left empty: the badge runs the
     * full width here, so any piece beside it would sit on top of it.
     */
    .puzzle-piece.pz-t1,
    .puzzle-piece.pz-t2,
    .puzzle-piece.pz-p3,
    .puzzle-piece.pz-p4 { display: none; }

    /*
     * Text pieces sit in the three bands that carry no glyphs at this width —
     * measured, not guessed:
     *   ~11–17%  the badge's bottom margin
     *   ~74–84%  the gap between the sub-heading and the buttons
     *   ~89–98%  the gap between the two stacked buttons
     * The slogan reflows to nearly full width on a phone, so anywhere else
     * would land on letters. They alternate right / left / right so no two
     * collect in the same corner.
     */
    .puzzle-piece.pz-t3 { --pz-rest: 0.24; --pz-size: 22px; top: 11.5%; right: 4%; left: auto; }
    .puzzle-piece.pz-t4 { --pz-rest: 0.19; --pz-size: 20px; top: 76%;   left: 2%;  right: auto; }
    .puzzle-piece.pz-t5 { --pz-rest: 0.16; --pz-size: 18px; top: 91%;   right: 6%; left: auto; }

    /* Photo: two above at opposite ends, one below right. */
    .puzzle-piece.pz-p1 { --pz-rest: 0.28; --pz-size: 28px; top: -16px; left: -8px; }
    .puzzle-piece.pz-p2 { --pz-rest: 0.32; --pz-size: 30px; top: -18px; right: 10%; }
    .puzzle-piece.pz-p5 { --pz-rest: 0.20; --pz-size: 24px; bottom: -16px; right: 6%; }

    .math-float { font-size: 1.1rem; }
}

/* ---------- 20b. CONTENT FORMULAS ([math] shortcode) ---------- */
/*
 * Fallback styling for when KaTeX is not installed: the LaTeX source stays
 * visible and legible instead of vanishing. Once KaTeX renders, .is-rendered
 * drops the source styling and KaTeX's own CSS takes over.
 */
.rm-math {
    font-family: var(--font-mono);
    font-size: 0.95em;
    padding: 0.1em 0.35em;
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid var(--glass-brd);
    color: var(--text);
}
.rm-math--block {
    display: block;
    margin: 22px auto;
    padding: 14px 18px;
    text-align: center;
    max-width: 100%;
    overflow-x: auto;
}
.rm-math.is-rendered {
    padding: 0;
    background: none;
    border: 0;
    font-family: inherit;
    font-size: inherit;
}
.rm-math--block.is-rendered { padding: 10px 0; }

/* ---------- 21. MOTION / ACCESSIBILITY ---------- */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
    [data-reveal] { opacity: 1; transform: none; }

    /*
     * Floating button: no breathing glow, no lift. Hover and focus still
     * change the button — the label appears and the outline shows — they just
     * arrive at once instead of sliding.
     */
    .rm-fab { animation: none !important; }
    .rm-fab:hover,
    .rm-fab:focus-visible { transform: none; }
    .rm-fab:hover .rm-fab__icon,
    .rm-fab:focus-visible .rm-fab__icon { transform: none; }
    /* Pieces still show, they just never move. */
    .puzzle-piece { opacity: var(--pz-rest); animation: none !important; }

    /*
     * Student message: the path is drawn in full from the start and the node
     * is simply present. Nothing moves, nothing fades in.
     */
    .student-message__curve { stroke-dashoffset: 0; transition: none; }
    .student-message__node,
    .student-message__node-ring { opacity: 1; transition: none; animation: none !important; }

    /*
     * Brand symbol: keep the resting composition and the glow change, drop
     * every movement. Hover still reads, it just does not animate.
     */
    .brand:hover .brand-symbol,
    .brand:focus-visible .brand-symbol { transform: none; }
    .brand:hover .brand-symbol .bs-piece,
    .brand:focus-visible .brand-symbol .bs-piece {
        transform: translate(1.1px, -1.1px) rotate(10deg);
    }
    .cursor-glow { display: none; }
    .neon-divider::before { display: none; }
}

:focus-visible {
    outline: 2px solid var(--neon-blue-2);
    outline-offset: 3px;
    border-radius: 6px;
}

.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 999;
    padding: 12px 18px;
    background: var(--bg-2);
    border: 1px solid var(--glass-brd);
    border-radius: 0 0 10px 0;
    color: var(--text);
}
.skip-link:focus { left: 0; }

.screen-reader-text {
    position: absolute !important;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}
