/* ─────────────────────────────────────────────────────────
   CSS variables on .slide – each theme overrides these
   ───────────────────────────────────────────────────────── */
.slide {
    /* Colors */
    --s-bg:               #ffffff;
    --s-text:             #111827;
    --s-text-muted:       #6b7280;
    --s-accent:           #0077ff;
    --s-heading:          #0f3460;
    --s-surface:          #f8f9fa;
    --s-border:           #e5e7eb;
    --s-bullet:           #0077ff;
    --s-col-heading:      #0077ff;
    /* Title slide */
    --s-title-bg:         linear-gradient(135deg, #1a1a2e 0%, #16213e 60%, #0f3460 100%);
    --s-title-text:       #ffffff;
    --s-title-sub:        rgba(255,255,255,0.75);
    /* Title-image slide */
    --s-title-image-tint: rgba(15, 52, 96, 0.78);
    --s-title-image-text: #ffffff;
    --s-title-image-sub:  rgba(255,255,255,0.8);
    /* Quote slide */
    --s-quote-bg:         linear-gradient(135deg, #0077ff 0%, #0f3460 100%);
    --s-quote-text:       #ffffff;
    --s-quote-attr:       rgba(255,255,255,0.8);
    /* Section slide */
    --s-section-bg:       #111111;
    --s-section-text:     #ffffff;
    --s-section-num-op:   0.15;
    --s-section-sub-op:   0.6;
    /* Fonts */
    --s-font:             -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --s-font-display:     var(--s-font);
    /* Background pattern (theme canvas texture, layered over --s-bg) */
    --s-bg-image:         none;
    --s-bg-size:          auto;
    /* A second heading colour, so a slide heading and the card titles under it
       need not be the same colour. Defaults to the heading colour, which is
       what every theme did before this existed. */
    --s-heading-alt:      var(--s-heading);
    /* Photo mount. A white border plus a soft shadow is what makes an ordinary
       photograph look placed rather than pasted - but only on a tinted ground,
       so it is off by default and themes opt in. */
    --s-image-frame:      none;
    --s-image-frame-radius: 12px;
    --s-image-shadow:     none;
    /* The ring around a circle-cropped photo. Its own variable because a
       theme usually wants a second colour here, not the one already doing
       the work everywhere else on the slide. */
    --s-image-ring:       var(--s-accent);
    /* The disc behind an icon. A flat colour so it needs no alpha. */
    --s-icon-badge-bg:    var(--s-surface);
    /* Whether a theme draws anything on its canvas at all. An empty string
       generates the ::before/::after pseudo-elements; `none` does not generate
       them, which is how a theme opts out entirely.

       WHAT each theme draws is written per theme further down, not here: one
       motif restated in thirteen palettes is still one motif, and the themes
       are meant to look like different products.

       Three rules constrain every treatment, all of them learned the hard way:
       a gradient carrying alpha exports from Chromium's PDF path as a dark
       blob; a sized element hanging past the BOTTOM edge inflates scrollHeight
       and the export's auto-fit pass then shrinks every word on the slide; and
       box-shadow is ink rather than layout, so it may spill anywhere for free.
       clip-path, blurred and multiple box-shadows, opaque banded gradients,
       border-radius domes and ring outlines were all checked against a
       rasterised export. */
    --s-shape:            none;
    /* Bookend panels: a box around the title slide's words, and the same box
       in a second colour around the recap's. Off by default - every existing
       theme has an opinion about its title slide already, and a border
       appearing on it unasked would be a regression, not a polish. */
    --s-panel-border:     none;
    --s-panel-bg:         transparent;
    --s-panel-radius:     20px;
    /* Zero by default: with no border drawn, padding here would only eat
       the width a long heading has to wrap in, on every other theme. */
    --s-panel-padding:    0;
    --s-panel-alt-border: var(--s-panel-border);
    /* The title panel needs its own background, because the title slide is the
       one place the canvas is not --s-bg: eleven of the thirteen themes paint a
       dark gradient there and set a light --s-title-text to suit. Reusing
       --s-panel-bg (white, correct for a body slide) put white text on a white
       panel and the heading disappeared. The default is a faint white scrim,
       which reads as a panel on any dark title background; a theme with a
       LIGHT title slide overrides it with an opaque fill. */
    --s-title-panel-bg:   rgba(255,255,255,0.07);
    /* The title panel's border. Separate from --s-panel-border because that one
       is a body-slide colour: the two monochrome themes draw it in near-black,
       which is invisible on their own black title slide. */
    --s-title-panel-border: var(--s-panel-border);
    /* The title slide's heading colour, split from --s-title-sub so the panel
       reads two-tone - an accent heading over a muted subtitle - the way the
       primary theme's does, instead of two near-identical whites. */
    --s-title-heading:    #7dd3fc;
    /* The title slide's own canvas art. Separate from --s-bg-image because a
       theme whose title is a full-bleed gradient wants no shapes on it, and one
       whose title is a flat tint wants the same shapes as every other slide. */
    --s-title-bg-image:   var(--s-title-bg);

    position: relative;
    /* Gives the shapes below something to sit inside: without it, a z-index:-1
       pseudo-element would fall behind the slide's own background and vanish. */
    isolation: isolate;
    width: 960px;
    height: 540px;
    overflow: hidden;
    box-sizing: border-box;
    font-family: var(--s-font);
    /* A slide is a fixed 960x540 canvas that gets scaled down to fit, so on a
       phone it is a 960px block inside a ~390px viewport – exactly what iOS
       Safari's text autosizing inflates. Boosted type overflows the authored
       layout and the bottom of the slide gets clipped by the overflow above,
       so the sizes here are the sizes rendered. */
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

/* ══ THEMES ═══════════════════════════════════════════════ */

/* ── Classic ──────────────────────────────────────────────
   The default palette, but written out as a theme rather than left to the
   root block: the root holds the OFF values every other theme starts from,
   so putting ornament there would hand it to all thirteen. */
[data-theme="classic"] .slide {
    --s-heading-alt:      #0077ff;
    --s-image-frame:      6px solid #ffffff;
    --s-image-shadow:     0 6px 18px rgba(15,52,96,0.14);
    --s-image-ring:       #0077ff;
    --s-icon-badge-bg:    #e8f1fb;
    --s-panel-border:     3px dashed #0077ff;
    --s-panel-alt-border: 3px solid #0f3460;
    --s-panel-bg:         #ffffff;
    --s-panel-padding:    30px 46px;
    --s-shape:            '';
}

/* ── Dark ─────────────────────────────────────────────── */
[data-theme="dark"] .slide {
    --s-bg:               #1e293b;
    --s-text:             #e2e8f0;
    --s-text-muted:       #94a3b8;
    --s-accent:           #818cf8;
    --s-heading:          #c4b5fd;
    --s-surface:          #0f172a;
    --s-border:           #334155;
    --s-bullet:           #818cf8;
    --s-col-heading:      #818cf8;
    --s-title-bg:         linear-gradient(135deg, #0f0c29 0%, #302b63 60%, #24243e 100%);
    --s-title-text:       #f1f5f9;
    --s-title-sub:        rgba(241,245,249,0.65);
    --s-title-heading:    #a5b4fc;
    --s-title-image-tint: rgba(15, 12, 41, 0.8);
    --s-title-image-text: #f1f5f9;
    --s-title-image-sub:  rgba(241,245,249,0.75);
    --s-quote-bg:         linear-gradient(135deg, #3730a3 0%, #1e1b4b 100%);
    --s-quote-text:       #e0e7ff;
    --s-quote-attr:       rgba(224,231,255,0.7);
    --s-section-bg:       linear-gradient(135deg, #0f0c29, #1a1040);
    --s-section-text:     #f1f5f9;
    --s-section-num-op:   0.12;
    --s-section-sub-op:   0.55;
    --s-heading-alt:      #818cf8;
    --s-image-frame:      6px solid #334155;
    --s-image-shadow:     0 8px 22px rgba(0,0,0,0.45);
    --s-image-ring:       #818cf8;
    --s-icon-badge-bg:    #334155;
    --s-panel-border:     3px dashed #818cf8;
    --s-panel-alt-border: 3px solid #c4b5fd;
    --s-panel-bg:         #0f172a;
    --s-panel-padding:    30px 46px;
    --s-shape:            '';
}

/* ── Minimal ──────────────────────────────────────────── */
[data-theme="minimal"] .slide {
    --s-bg:               #ffffff;
    --s-text:             #000000;
    --s-text-muted:       #555555;
    --s-accent:           #000000;
    --s-heading:          #000000;
    --s-surface:          #f9fafb;
    --s-border:           #e5e5e5;
    --s-bullet:           #000000;
    --s-col-heading:      #000000;
    --s-title-bg:         #000000;
    --s-title-text:       #ffffff;
    --s-title-sub:        rgba(255,255,255,0.6);
    --s-title-heading:    #ffffff;
    --s-title-image-tint: rgba(0, 0, 0, 0.75);
    --s-title-image-text: #ffffff;
    --s-title-image-sub:  rgba(255,255,255,0.7);
    --s-quote-bg:         #f5f5f5;
    --s-quote-text:       #000000;
    --s-quote-attr:       #555555;
    --s-section-bg:       #f9fafb;
    --s-section-text:     #000000;
    --s-section-num-op:   0.08;
    --s-section-sub-op:   0.5;
    --s-font-display:     Georgia, 'Times New Roman', serif;
    --s-heading-alt:      #000000;
    --s-image-frame:      1px solid #e5e5e5;
    --s-image-shadow:     0 2px 10px rgba(0,0,0,0.08);
    --s-image-ring:       #000000;
    --s-icon-badge-bg:    #f2f2f2;
    --s-panel-border:     3px dashed #000000;
    --s-title-panel-border: 3px dashed rgba(255,255,255,0.55);
    --s-panel-alt-border: 3px solid #000000;
    --s-panel-bg:         #ffffff;
    --s-panel-padding:    30px 46px;
}

/* ── Vibrant ──────────────────────────────────────────── */
[data-theme="vibrant"] .slide {
    --s-bg:               #fffbf5;
    --s-text:             #1c1917;
    --s-text-muted:       #78716c;
    --s-accent:           #f97316;
    --s-heading:          #9d174d;
    --s-surface:          #fff7ed;
    --s-border:           #fed7aa;
    --s-bullet:           #f97316;
    --s-col-heading:      #be185d;
    --s-title-bg:         linear-gradient(135deg, #be123c 0%, #7c2d12 100%);
    --s-title-text:       #fff7ed;
    --s-title-sub:        rgba(255,247,237,0.75);
    --s-title-heading:    #fdba74;
    --s-title-image-tint: rgba(124, 45, 18, 0.8);
    --s-title-image-text: #fff7ed;
    --s-title-image-sub:  rgba(255,247,237,0.8);
    --s-quote-bg:         linear-gradient(135deg, #f97316 0%, #dc2626 100%);
    --s-quote-text:       #ffffff;
    --s-quote-attr:       rgba(255,255,255,0.8);
    --s-section-bg:       linear-gradient(135deg, #0f766e 0%, #065f46 100%);
    --s-section-text:     #ecfdf5;
    --s-section-num-op:   0.15;
    --s-section-sub-op:   0.65;
    --s-font-display:     'Georgia', serif;
    --s-heading-alt:      #f97316;
    --s-image-frame:      6px solid #ffffff;
    --s-image-shadow:     0 6px 18px rgba(124,45,18,0.16);
    --s-image-ring:       #f97316;
    --s-icon-badge-bg:    #ffedd5;
    --s-panel-border:     3px dashed #f97316;
    --s-panel-alt-border: 3px solid #be185d;
    --s-panel-bg:         #ffffff;
    --s-panel-padding:    30px 46px;
    --s-shape:            '';
}

/* ── Ocean ────────────────────────────────────────────── */
[data-theme="ocean"] .slide {
    --s-bg:               #eef7fa;
    --s-text:             #0b3142;
    --s-text-muted:       #4c7d8c;
    --s-accent:           #0891b2;
    --s-heading:          #075985;
    --s-surface:          #e0f2fe;
    --s-border:           #bae6fd;
    --s-bullet:           #0891b2;
    --s-col-heading:      #0891b2;
    --s-title-bg:         linear-gradient(135deg, #0c4a6e 0%, #0891b2 60%, #06b6d4 100%);
    --s-title-text:       #f0fdff;
    --s-title-sub:        rgba(240,253,255,0.75);
    --s-title-heading:    #fde68a;
    --s-title-image-tint: rgba(8, 74, 110, 0.78);
    --s-title-image-text: #f0fdff;
    --s-title-image-sub:  rgba(240,253,255,0.8);
    --s-quote-bg:         linear-gradient(135deg, #0891b2 0%, #0c4a6e 100%);
    --s-quote-text:       #f0fdff;
    --s-quote-attr:       rgba(240,253,255,0.8);
    --s-section-bg:       linear-gradient(135deg, #082f3a, #0c4a6e);
    --s-section-text:     #f0fdff;
    --s-section-num-op:   0.15;
    --s-section-sub-op:   0.6;
    --s-font:             'Century Gothic', 'Trebuchet MS', sans-serif;
    --s-font-display:     'Century Gothic', 'Trebuchet MS', sans-serif;
    --s-heading-alt:      #0891b2;
    --s-image-frame:      6px solid #ffffff;
    --s-image-shadow:     0 6px 18px rgba(8,74,110,0.16);
    --s-image-ring:       #0891b2;
    --s-icon-badge-bg:    #cffafe;
    --s-panel-border:     3px dashed #0891b2;
    --s-panel-alt-border: 3px solid #075985;
    --s-panel-bg:         #ffffff;
    --s-panel-padding:    30px 46px;
    --s-shape:            '';
}

/* ── Forest ───────────────────────────────────────────── */
[data-theme="forest"] .slide {
    --s-bg:               #f4f7f0;
    --s-text:             #1f2b1a;
    --s-text-muted:       #5b6b52;
    --s-accent:           #4d7c0f;
    --s-heading:          #365314;
    --s-surface:          #eef3e6;
    --s-border:           #d9e4c9;
    --s-bullet:           #4d7c0f;
    --s-col-heading:      #4d7c0f;
    --s-title-bg:         linear-gradient(135deg, #1a2e1a 0%, #365314 60%, #4d7c0f 100%);
    --s-title-text:       #f7faf0;
    --s-title-sub:        rgba(247,250,240,0.75);
    --s-title-heading:    #bef264;
    --s-title-image-tint: rgba(26, 46, 26, 0.78);
    --s-title-image-text: #f7faf0;
    --s-title-image-sub:  rgba(247,250,240,0.8);
    --s-quote-bg:         linear-gradient(135deg, #4d7c0f 0%, #1a2e1a 100%);
    --s-quote-text:       #f7faf0;
    --s-quote-attr:       rgba(247,250,240,0.8);
    --s-section-bg:       linear-gradient(135deg, #14200f, #2b3a1f);
    --s-section-text:     #f7faf0;
    --s-section-num-op:   0.15;
    --s-section-sub-op:   0.6;
    --s-font:             Garamond, 'Palatino Linotype', 'Book Antiqua', serif;
    --s-font-display:     Garamond, 'Palatino Linotype', 'Book Antiqua', serif;
    --s-heading-alt:      #4d7c0f;
    --s-image-frame:      6px solid #ffffff;
    --s-image-shadow:     0 6px 18px rgba(26,46,26,0.16);
    --s-image-ring:       #4d7c0f;
    --s-icon-badge-bg:    #e6f0d5;
    --s-panel-border:     3px dashed #4d7c0f;
    --s-panel-alt-border: 3px solid #365314;
    --s-panel-bg:         #ffffff;
    --s-panel-padding:    30px 46px;
    --s-shape:            '';
}

/* ── Sunset ───────────────────────────────────────────── */
[data-theme="sunset"] .slide {
    --s-bg:               #fff6f0;
    --s-text:             #3a1a12;
    --s-text-muted:       #8a5a44;
    --s-accent:           #ea580c;
    --s-heading:          #9a3412;
    --s-surface:          #ffede0;
    --s-border:           #fed7aa;
    --s-bullet:           #ea580c;
    --s-col-heading:      #c2410c;
    --s-title-bg:         linear-gradient(135deg, #7c2d12 0%, #c2410c 50%, #db2777 100%);
    --s-title-text:       #fff6f0;
    --s-title-sub:        rgba(255,246,240,0.75);
    --s-title-heading:    #fde68a;
    --s-title-image-tint: rgba(124, 45, 18, 0.78);
    --s-title-image-text: #fff6f0;
    --s-title-image-sub:  rgba(255,246,240,0.8);
    --s-quote-bg:         linear-gradient(135deg, #ea580c 0%, #9d174d 100%);
    --s-quote-text:       #fff6f0;
    --s-quote-attr:       rgba(255,246,240,0.8);
    --s-section-bg:       linear-gradient(135deg, #431407, #7c2d12);
    --s-section-text:     #fff6f0;
    --s-section-num-op:   0.15;
    --s-section-sub-op:   0.6;
    --s-font:             'Trebuchet MS', 'Segoe UI', sans-serif;
    --s-font-display:     'Palatino Linotype', Georgia, serif;
    --s-heading-alt:      #ea580c;
    --s-image-frame:      6px solid #ffffff;
    --s-image-shadow:     0 6px 18px rgba(154,52,18,0.16);
    --s-image-ring:       #ea580c;
    --s-icon-badge-bg:    #ffe4d0;
    --s-panel-border:     3px dashed #ea580c;
    --s-panel-alt-border: 3px solid #9a3412;
    --s-panel-bg:         #ffffff;
    --s-panel-padding:    30px 46px;
    --s-shape:            '';
    /* A sky, graded top to bottom. Every stop is an opaque hex - a gradient
       carrying alpha exports from the PDF path as a dark blob. */
    --s-bg-image:         linear-gradient(#fff8f3 0%, #fff1e6 46%, #ffe4cd 76%, #ffd6b6 100%);
}

/* ── Blueprint ────────────────────────────────────────── */
[data-theme="blueprint"] .slide {
    --s-bg:               #f3f8fc;
    --s-text:             #0b2c46;
    --s-text-muted:       #4a6b85;
    --s-accent:           #1d4ed8;
    --s-heading:          #1e3a5f;
    --s-surface:          #e6eef6;
    --s-border:           #c7dcef;
    --s-bullet:           #1d4ed8;
    --s-col-heading:      #1d4ed8;
    --s-title-bg:         repeating-linear-gradient(0deg, rgba(255,255,255,0.09) 0 1px, rgba(255,255,255,0) 1px 24px), repeating-linear-gradient(90deg, rgba(255,255,255,0.09) 0 1px, rgba(255,255,255,0) 1px 24px), linear-gradient(135deg, #0b1f3a 0%, #1e3a5f 55%, #1d4ed8 100%);
    --s-title-text:       #f3f8fc;
    --s-title-sub:        rgba(243,248,252,0.75);
    --s-title-heading:    #93c5fd;
    --s-title-image-tint: rgba(11, 31, 58, 0.8);
    --s-title-image-text: #f3f8fc;
    --s-title-image-sub:  rgba(243,248,252,0.8);
    --s-quote-bg:         repeating-linear-gradient(0deg, rgba(255,255,255,0.08) 0 1px, rgba(255,255,255,0) 1px 24px), repeating-linear-gradient(90deg, rgba(255,255,255,0.08) 0 1px, rgba(255,255,255,0) 1px 24px), linear-gradient(135deg, #1d4ed8 0%, #0b1f3a 100%);
    --s-quote-text:       #f3f8fc;
    --s-quote-attr:       rgba(243,248,252,0.8);
    --s-section-bg:       repeating-linear-gradient(0deg, rgba(255,255,255,0.08) 0 1px, rgba(255,255,255,0) 1px 24px), repeating-linear-gradient(90deg, rgba(255,255,255,0.08) 0 1px, rgba(255,255,255,0) 1px 24px), linear-gradient(135deg, #061225, #0b1f3a);
    --s-section-text:     #f3f8fc;
    --s-section-num-op:   0.15;
    --s-section-sub-op:   0.6;
    --s-font:             'Lucida Console', 'Courier New', monospace;
    --s-font-display:     'Lucida Console', 'Courier New', monospace;
    --s-heading-alt:      #1d4ed8;
    --s-image-frame:      6px solid #ffffff;
    --s-image-shadow:     0 6px 18px rgba(11,44,70,0.14);
    --s-image-ring:       #1d4ed8;
    --s-icon-badge-bg:    #dbeafe;
    --s-panel-border:     3px dashed #1d4ed8;
    --s-panel-alt-border: 3px solid #1e3a5f;
    --s-panel-bg:         #ffffff;
    --s-panel-padding:    30px 46px;
    --s-shape:            '';
    /* Ruled one way only, in OPAQUE colours. Two directions would need the
       upper layer to be transparent between its lines, and alpha in a
       gradient exports from the PDF path as a smooth wash - the grid
       vanished and the slide picked up a vertical gradient instead. One
       direction is also simply less busy, which is what this needed. */
    --s-bg-image:         repeating-linear-gradient(90deg, #d3e3f3 0 1px, #f3f8fc 1px 120px);
}

/* ── Pastel ───────────────────────────────────────────── */
[data-theme="pastel"] .slide {
    --s-bg:               #fdf6fb;
    --s-text:             #3a2a3f;
    --s-text-muted:       #8a7690;
    --s-accent:           #c026d3;
    --s-heading:          #86198f;
    --s-surface:          #f3e8fb;
    --s-border:           #e9d5f5;
    --s-bullet:           #c026d3;
    --s-col-heading:      #a21caf;
    --s-title-bg:         linear-gradient(135deg, #701a75 0%, #a21caf 50%, #c026d3 100%);
    --s-title-text:       #fdf4ff;
    --s-title-sub:        rgba(253,244,255,0.75);
    --s-title-heading:    #fef08a;
    --s-title-image-tint: rgba(58, 10, 68, 0.78);
    --s-title-image-text: #fdf4ff;
    --s-title-image-sub:  rgba(253,244,255,0.8);
    --s-quote-bg:         linear-gradient(135deg, #c026d3 0%, #701a75 100%);
    --s-quote-text:       #fdf4ff;
    --s-quote-attr:       rgba(253,244,255,0.8);
    --s-section-bg:       linear-gradient(135deg, #4c1d55, #701a75);
    --s-section-text:     #fdf4ff;
    --s-section-num-op:   0.15;
    --s-section-sub-op:   0.6;
    --s-font:             Verdana, Tahoma, Geneva, sans-serif;
    --s-font-display:     'Trebuchet MS', Verdana, sans-serif;
    --s-heading-alt:      #c026d3;
    --s-image-frame:      6px solid #ffffff;
    --s-image-shadow:     0 6px 18px rgba(58,42,63,0.14);
    --s-image-ring:       #c026d3;
    --s-icon-badge-bg:    #f8e7fb;
    --s-panel-border:     3px dashed #c026d3;
    --s-panel-alt-border: 3px solid #86198f;
    --s-panel-bg:         #ffffff;
    --s-panel-padding:    30px 46px;
    --s-shape:            '';
}

/* ── Slate ────────────────────────────────────────────── */
[data-theme="slate"] .slide {
    --s-bg:               #f1f5f9;
    --s-text:             #0f172a;
    --s-text-muted:       #64748b;
    --s-accent:           #2563eb;
    --s-heading:          #1e293b;
    --s-surface:          #e2e8f0;
    --s-border:           #cbd5e1;
    --s-bullet:           #2563eb;
    --s-col-heading:      #2563eb;
    --s-title-bg:         linear-gradient(135deg, #0f172a 0%, #1e293b 55%, #334155 100%);
    --s-title-text:       #f1f5f9;
    --s-title-sub:        rgba(241,245,249,0.7);
    --s-title-heading:    #93c5fd;
    --s-title-image-tint: rgba(15, 23, 42, 0.8);
    --s-title-image-text: #f1f5f9;
    --s-title-image-sub:  rgba(241,245,249,0.75);
    --s-quote-bg:         linear-gradient(135deg, #334155 0%, #0f172a 100%);
    --s-quote-text:       #f1f5f9;
    --s-quote-attr:       rgba(241,245,249,0.75);
    --s-section-bg:       linear-gradient(135deg, #0a0f1a, #1e293b);
    --s-section-text:     #f1f5f9;
    --s-section-num-op:   0.12;
    --s-section-sub-op:   0.55;
    --s-font:             Arial, Helvetica, sans-serif;
    --s-font-display:     Arial, Helvetica, sans-serif;
    --s-heading-alt:      #2563eb;
    --s-image-frame:      6px solid #ffffff;
    --s-image-shadow:     0 6px 18px rgba(15,23,42,0.14);
    --s-image-ring:       #2563eb;
    --s-icon-badge-bg:    #dbeafe;
    --s-panel-border:     3px dashed #2563eb;
    --s-panel-alt-border: 3px solid #1e293b;
    --s-panel-bg:         #ffffff;
    --s-panel-padding:    30px 46px;
    --s-shape:            '';
    /* Opaque, and one layer. The alpha stripes this replaces were invisible
       in the PDF export at 0.06 - faint alpha in a repeating gradient does
       not survive rasterising - so screen and print disagreed. */
    --s-bg-image:         repeating-linear-gradient(45deg, #e7edf4 0 2px, #f1f5f9 2px 16px);
}

/* ── Autumn ───────────────────────────────────────────── */
[data-theme="autumn"] .slide {
    --s-bg:               #fdf8f1;
    --s-text:             #3a2416;
    --s-text-muted:       #8a6b4f;
    --s-accent:           #b45309;
    --s-heading:          #78350f;
    --s-surface:          #f6ead9;
    --s-border:           #ecd9b8;
    --s-bullet:           #b45309;
    --s-col-heading:      #92400e;
    --s-title-bg:         linear-gradient(135deg, #451a03 0%, #78350f 55%, #b45309 100%);
    --s-title-text:       #fef6e8;
    --s-title-sub:        rgba(254,246,232,0.75);
    --s-title-heading:    #fcd34d;
    --s-title-image-tint: rgba(69, 26, 3, 0.78);
    --s-title-image-text: #fef6e8;
    --s-title-image-sub:  rgba(254,246,232,0.8);
    --s-quote-bg:         linear-gradient(135deg, #b45309 0%, #451a03 100%);
    --s-quote-text:       #fef6e8;
    --s-quote-attr:       rgba(254,246,232,0.8);
    --s-section-bg:       linear-gradient(135deg, #2e1204, #451a03);
    --s-section-text:     #fef6e8;
    --s-section-num-op:   0.15;
    --s-section-sub-op:   0.6;
    --s-font:             Georgia, 'Times New Roman', serif;
    --s-font-display:     Georgia, 'Times New Roman', serif;
    --s-heading-alt:      #b45309;
    --s-image-frame:      6px solid #ffffff;
    --s-image-shadow:     0 6px 18px rgba(58,36,22,0.16);
    --s-image-ring:       #b45309;
    --s-icon-badge-bg:    #fbead4;
    --s-panel-border:     3px dashed #b45309;
    --s-panel-alt-border: 3px solid #78350f;
    --s-panel-bg:         #ffffff;
    --s-panel-padding:    30px 46px;
    --s-shape:            '';
}

/* ── Mono ─────────────────────────────────────────────── */
[data-theme="mono"] .slide {
    --s-bg:               #f7f7f7;
    --s-text:             #111111;
    --s-text-muted:       #555555;
    --s-accent:           #111111;
    --s-heading:          #000000;
    --s-surface:          #ececec;
    --s-border:           #d4d4d4;
    --s-bullet:           #111111;
    --s-col-heading:      #111111;
    --s-title-bg:         repeating-linear-gradient(45deg, rgba(255,255,255,0.07) 0 1px, rgba(255,255,255,0) 1px 10px), repeating-linear-gradient(-45deg, rgba(255,255,255,0.07) 0 1px, rgba(255,255,255,0) 1px 10px), linear-gradient(135deg, #000000 0%, #262626 100%);
    --s-title-text:       #f7f7f7;
    --s-title-sub:        rgba(247,247,247,0.7);
    --s-title-heading:    #f7f7f7;
    --s-title-image-tint: rgba(0, 0, 0, 0.8);
    --s-title-image-text: #f7f7f7;
    --s-title-image-sub:  rgba(247,247,247,0.75);
    --s-quote-bg:         repeating-linear-gradient(45deg, rgba(255,255,255,0.07) 0 1px, rgba(255,255,255,0) 1px 10px), repeating-linear-gradient(-45deg, rgba(255,255,255,0.07) 0 1px, rgba(255,255,255,0) 1px 10px), linear-gradient(135deg, #262626 0%, #000000 100%);
    --s-quote-text:       #f7f7f7;
    --s-quote-attr:       rgba(247,247,247,0.75);
    --s-section-bg:       repeating-linear-gradient(45deg, rgba(255,255,255,0.07) 0 1px, rgba(255,255,255,0) 1px 10px), repeating-linear-gradient(-45deg, rgba(255,255,255,0.07) 0 1px, rgba(255,255,255,0) 1px 10px), #000000;
    --s-section-text:     #f7f7f7;
    --s-section-num-op:   0.12;
    --s-section-sub-op:   0.55;
    --s-font:             'Courier New', Courier, monospace;
    --s-font-display:     'Courier New', Courier, monospace;
    --s-bg-image:         linear-gradient(225deg, rgba(0,0,0,0.12) 0%, rgba(0,0,0,0) 40%), radial-gradient(circle, rgba(0,0,0,0.18) 1.6px, rgba(0,0,0,0) 1.6px);
    --s-bg-size:          auto, 16px 16px;
    --s-heading-alt:      #111111;
    --s-image-frame:      6px solid #ffffff;
    --s-image-shadow:     0 6px 18px rgba(0,0,0,0.14);
    --s-image-ring:       #111111;
    --s-icon-badge-bg:    #e4e4e4;
    --s-panel-border:     3px dashed #111111;
    --s-title-panel-border: 3px dashed rgba(247,247,247,0.5);
    --s-panel-alt-border: 3px solid #111111;
    --s-panel-bg:         #ffffff;
    --s-panel-padding:    30px 46px;
    --s-shape:            '';
}

/* ── Primary ──────────────────────────────────────────────
   For KS1/KS2, and the default theme at those levels (see VALID_THEMES and
   defaultThemeFor in routes/presentations.js). Every other theme reads as a
   business deck, which is the wrong register for a Year 4 class however good
   the content on it is.

   Warm blush ground rather than white, a geometric display face with round
   letterforms, and soft corner blobs in --s-bg-image so the canvas is never a
   blank rectangle. Deliberately keeps Verdana for body copy: its wide spacing
   and open counters are the reason it survives being read from the back of a
   classroom, and that matters more here than matching the display face.

   Fonts are system stacks like every other theme. A proper rounded webfont
   would sell this considerably harder, but the PDF path renders through
   page.setContent() with no base URL, so a webfont has to be base64-embedded
   the way public/css/a11y-fonts.css does it - 308KB for OpenDyslexic, unsubset.
   Worth doing, worth subsetting first, and not worth blocking the palette on. */
[data-theme="primary"] .slide {
    --s-bg:               #eef6fd;
    --s-text:             #1a3a63;
    --s-text-muted:       #4b6b93;
    --s-accent:           #2563eb;
    --s-heading:          #d97706;
    --s-heading-alt:      #2563eb;
    --s-surface:          #ffffff;
    --s-border:           #c7ddf5;
    --s-bullet:           #2563eb;
    --s-col-heading:      #2563eb;
    --s-title-bg:         #eef6fd;
    --s-title-bg-image:   none;
    --s-title-text:       #2563eb;
    --s-title-sub:        #1a3a63;
    --s-title-image-tint: rgba(26, 58, 99, 0.62);
    --s-title-image-text: #ffffff;
    --s-title-image-sub:  rgba(255,255,255,0.9);
    --s-quote-bg:         linear-gradient(135deg, #2563eb 0%, #1a3a63 100%);
    --s-quote-text:       #eef6fd;
    --s-quote-attr:       rgba(238,246,253,0.85);
    --s-section-bg:       linear-gradient(135deg, #2563eb, #1a3a63);
    --s-section-text:     #eef6fd;
    --s-section-num-op:   0.18;
    --s-section-sub-op:   0.65;
    --s-font:             Verdana, Geneva, Tahoma, sans-serif;
    --s-font-display:     'Century Gothic', 'Trebuchet MS', Verdana, sans-serif;
    /* CRISP shapes, not diffuse washes: the colour holds to 99% and then stops,
       so these read as two big circles bleeding off opposite corners - a motif
       the deck carries on every slide - where the soft gradients they replace
       read as a smudge and did nothing to fill the space.
       Two details here are both about the PDF export, not the screen:

       1. An ordinary two-stop gradient, not the newer multi-position form
          ("#fdf0b5 0 100%"). Identical on screen; the older syntax is what the
          other twelve themes already prove exports cleanly.
       2. It fades to the SAME COLOUR at zero alpha, never to `transparent`.
          `transparent` is rgba(0,0,0,0), and a renderer that interpolates it
          without honouring premultiplied alpha fades toward BLACK - which is
          exactly what the PDF export did: two flat discs came out as shaded
          spheres and the whole slide picked up a grey cast. */
    --s-bg-image:         none;
    /* Centres and radii lifted verbatim from what these were as radial
       gradients, so they sit exactly where they did. */
    --s-shape:            '';
    --s-image-frame:      6px solid #ffffff;
    --s-image-frame-radius: 14px;
    --s-image-shadow:     0 6px 18px rgba(26, 58, 99, 0.16);
    --s-image-ring:       #fbbf24;
    --s-icon-badge-bg:    #dbeafe;
    --s-panel-border:     3px dashed #2563eb;
    --s-panel-bg:         #ffffff;
    --s-panel-alt-border: 3px solid #fbbf24;
    --s-title-panel-bg:   #ffffff;
    --s-title-heading:    var(--s-title-text);
    --s-panel-padding:    30px 46px;
}

/* A star reads as friendlier than a triangle for this age group, and it is the
   one place a small glyph earns its place. */
[data-theme="primary"] .slide--content .slide__bullets li::before {
    content: '★';
    width: auto;
    height: auto;
    border: 0;
    top: 0.1em;
    left: 0;
    color: #fbbf24;
    font-size: 0.95rem;
}

/* Cards get a hairline and a radius so a row of them reads as a set of cards
   rather than three floating captions. */
/* ══ TEMPLATES ════════════════════════════════════════════ */

/* ── Title ────────────────────────────────────────────── */
.slide--title {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background-color: var(--s-title-bg);
    background-image: var(--s-title-bg-image, none);
    color: var(--s-title-text);
    padding: 60px 80px;
    text-align: center;
}

.slide--title .slide__heading {
    font-family: var(--s-font-display);
    font-size: 3rem;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -0.02em;
    margin-bottom: 1rem;
    color: var(--s-title-heading);
}

.slide--title .slide__subtitle {
    font-size: 1.4rem;
    font-weight: 400;
    color: var(--s-title-sub);
    line-height: 1.5;
    white-space: pre-line;
}

/* ── Title (image background) ────────────────────────── */
.slide--title-image {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--s-surface);
    overflow: hidden;
}

.slide--title-image .slide__title-image-bg,
.slide--title-image .slide__title-image-placeholder {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.slide--title-image .slide__title-image-placeholder {
    background: var(--s-surface);
}

.slide--title-image .slide__title-tint {
    position: absolute;
    inset: 0;
    background: var(--s-title-image-tint);
}

.slide--title-image .slide__title-image-content {
    position: relative;
    z-index: 1;
    max-width: 640px;
    padding: 0 44px;
    text-align: center;
}

.slide--title-image .slide__title-image-content .slide__heading {
    font-family: var(--s-font-display);
    font-size: 2.5rem;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -0.02em;
    margin-bottom: 1rem;
    color: var(--s-title-image-text);
}

.slide--title-image .slide__title-image-content .slide__subtitle {
    font-size: 1.2rem;
    font-weight: 400;
    color: var(--s-title-image-sub);
    line-height: 1.5;
    white-space: pre-line;
}

/* ── Content ──────────────────────────────────────────── */
.slide--content {
    display: flex;
    flex-direction: column;
    padding: 52px 64px;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide--content .slide__heading {
    font-family: var(--s-font-display);
    font-size: 2rem;
    font-weight: 700;
    color: var(--s-heading);
    padding-bottom: 0.6rem;
    border-bottom: 3px solid var(--s-accent);
    margin-bottom: 1.4rem;
    line-height: 1.2;
}

/* A slide is a fixed 540px canvas, so a short list left at its natural height
   stacks under the heading and leaves the bottom half visibly empty - the
   single most common way one of these decks looks unfinished.

   flex:1 + space-evenly, the same fill .slide--timeline uses. The gap stays as
   the floor on spacing, so a list long enough to fill the body keeps its
   original tight rhythm and only a short one opens out. */
.slide--content .slide__bullets {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    flex: 1;
    justify-content: space-evenly;
    gap: 0.65rem;
}

.slide--content .slide__bullets li {
    font-size: 1.2rem;
    line-height: 1.5;
    padding-left: 1.4rem;
    position: relative;
    color: var(--s-text);
}

.slide--content .slide__bullets li::before {
    content: '';
    position: absolute;
    left: 0.1rem;
    top: 0.55em;
    width: 0;
    height: 0;
    border-top: 0.32em solid transparent;
    border-bottom: 0.32em solid transparent;
    border-left: 0.4em solid var(--s-bullet);
}

/* ── Two-Column ───────────────────────────────────────── */
.slide--two-column {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto 1fr;
    gap: 0 48px;
    padding: 48px 56px;
    background-color: var(--s-surface);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide--two-column .slide__heading {
    grid-column: 1 / -1;
    font-family: var(--s-font-display);
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--s-heading);
    margin-bottom: 1.2rem;
    padding-bottom: 0.5rem;
    border-bottom: 3px solid var(--s-accent);
}

.slide--two-column .slide__col {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.slide--two-column .slide__col-heading {
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--s-col-heading);
    letter-spacing: 0.05em;
    margin-bottom: 0.25rem;
}

/* Deliberately NOT given the flex:1 fill .slide--content has. A column holds
   2-4 short items in half the width, so pushing them down to sit in the middle
   of the column only moves the gap from below the list to between the list and
   the heading it belongs to - and that grouping matters more here than filling
   does. Tried both ways; top-aligned reads better. */
.slide--two-column .slide__col-body {
    font-size: 1.05rem;
    line-height: 1.65;
    color: var(--s-text-muted);
}

.slide--two-column .slide__col-bullets {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
}

.slide--two-column .slide__col-bullets li {
    font-size: 1rem;
    line-height: 1.5;
    padding-left: 1.2rem;
    position: relative;
    color: var(--s-text);
    word-wrap: break-word;
    overflow-wrap: break-word;
}

.slide--two-column .slide__col-bullets li::before {
    content: '';
    position: absolute;
    left: 0.05rem;
    top: 0.55em;
    width: 0;
    height: 0;
    border-top: 0.28em solid transparent;
    border-bottom: 0.28em solid transparent;
    border-left: 0.36em solid var(--s-bullet);
}

/* ── Comparison + Diagram ─────────────────────────────── */
.slide--comparison-diagram {
    display: flex;
    flex-direction: column;
    padding: 40px 56px 32px;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide--comparison-diagram .slide__heading {
    font-family: var(--s-font-display);
    font-size: 1.9rem;
    font-weight: 700;
    color: var(--s-heading);
    margin-bottom: 1rem;
    line-height: 1.2;
    flex-shrink: 0;
}

.slide--comparison-diagram .slide__comparison-cols {
    display: flex;
    gap: 48px;
    margin-bottom: 1.1rem;
    flex-shrink: 0;
}

.slide--comparison-diagram .slide__col {
    flex: 1;
    min-width: 0;
}

.slide--comparison-diagram .slide__col-heading {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--s-col-heading);
    margin-bottom: 0.4rem;
}

.slide--comparison-diagram .slide__col-bullets {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}

.slide--comparison-diagram .slide__col-bullets li {
    font-size: 0.92rem;
    line-height: 1.5;
    padding-left: 1rem;
    position: relative;
    color: var(--s-text);
}

.slide--comparison-diagram .slide__col-bullets li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.6em;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--s-bullet);
}

.slide--comparison-diagram .slide__image-wrap {
    flex: 1;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 10px;
    border-radius: 10px;
    border: 1px solid var(--s-border);
    background: var(--s-surface);
    overflow: hidden;
}

.slide--comparison-diagram .slide__image {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.slide--comparison-diagram .slide__image-placeholder {
    width: 100%;
    height: 100%;
    border-radius: 8px;
    background: linear-gradient(135deg, var(--s-surface) 0%, var(--s-border) 100%);
}

/* ── Process Flow ─────────────────────────────────────── */
.slide--process-flow {
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 48px 60px;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide--process-flow .slide__heading {
    font-family: var(--s-font-display);
    font-size: 2rem;
    font-weight: 700;
    color: var(--s-heading);
    margin-bottom: 2.5rem;
    line-height: 1.2;
    flex-shrink: 0;
}

.slide--process-flow .slide__flow-row {
    display: flex;
    align-items: flex-start;
}

.slide--process-flow .slide__flow-step {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 0 8px;
}

.slide--process-flow .slide__flow-num {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--s-accent);
    color: #ffffff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 1.05rem;
    margin-bottom: 0.9rem;
    flex-shrink: 0;
}

.slide--process-flow .slide__flow-label {
    font-weight: 700;
    font-size: 1rem;
    color: var(--s-heading);
    margin-bottom: 0.35rem;
}

.slide--process-flow .slide__flow-text {
    font-size: 0.85rem;
    color: var(--s-text-muted);
    line-height: 1.45;
}

.slide--process-flow .slide__flow-arrow {
    width: 28px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--s-text-muted);
    font-size: 1.4rem;
    flex-shrink: 0;
    opacity: 0.55;
}

/* ── Quote ────────────────────────────────────────────── */
.slide--quote {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 64px 96px;
    background: var(--s-quote-bg);
    color: var(--s-quote-text);
    text-align: center;
}

.slide--quote .slide__quote {
    font-family: var(--s-font-display);
    font-size: 1.85rem;
    font-style: italic;
    line-height: 1.55;
    font-weight: 400;
    color: var(--s-quote-text);
}

.slide--quote .slide__attribution {
    margin-top: 2rem;
    font-size: 1rem;
    color: var(--s-quote-attr);
    font-weight: 500;
    letter-spacing: 0.04em;
}

/* ── Section break ────────────────────────────────────── */
.slide--section {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    background: var(--s-section-bg);
    color: var(--s-section-text);
    padding: 72px 80px 72px 88px;
    position: relative;
    overflow: hidden;
}

/* Left accent bar */
.slide--section::before {
    content: '';
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 8px;
    background: var(--s-accent);
    opacity: 0.85;
}

.slide--section .slide__section-number {
    font-size: 5rem;
    font-weight: 800;
    line-height: 1;
    color: var(--s-accent);
    margin-bottom: 0.6rem;
    letter-spacing: -0.03em;
}

.slide--section .slide__section-title {
    font-family: var(--s-font-display);
    font-size: 2.9rem;
    font-weight: 700;
    line-height: 1.1;
    color: var(--s-section-text);
    margin: 0;
}

.slide--section .slide__section-subtitle {
    font-size: 1.1rem;
    margin-top: 0.85rem;
    opacity: 0.6;
    font-weight: 400;
    color: var(--s-section-text);
    max-width: 560px;
    line-height: 1.55;
}

/* ── Image + Text ─────────────────────────────────────── */
.slide--image-text {
    display: grid;
    grid-template-columns: 1fr 1fr;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide--image-text .slide__content {
    padding: 52px 48px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 1rem;
}

.slide--image-text .slide__heading {
    font-family: var(--s-font-display);
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--s-heading);
    line-height: 1.2;
}

.slide--image-text .slide__body {
    font-size: 1.05rem;
    line-height: 1.7;
    color: var(--s-text-muted);
}

.slide--image-text .slide__image-wrap {
    overflow: hidden;
}

.slide--image-text .slide__image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.slide--image-text .slide__image-placeholder {
    width: 100%;
    height: 100%;
    background: linear-gradient(135deg, var(--s-surface) 0%, var(--s-border) 100%);
}

/* ── Term grid ────────────────────────────────────────── */
.slide--term-grid {
    display: flex;
    flex-direction: column;
    padding: 40px 64px 48px;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide--term-grid .slide__heading {
    font-family: var(--s-font-display);
    font-size: 2rem;
    font-weight: 800;
    color: var(--s-accent);
    margin-bottom: 1.4rem;
}

.slide--term-grid .slide__term-grid-row {
    display: flex;
    flex: 1;
    gap: 32px;
    align-items: stretch;
}

.slide--term-grid .slide__term-item {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* Centred, because the cards are stretched to a common height and a short
       caption would otherwise leave a band of empty card beneath it. */
    justify-content: center;
    text-align: center;
}

.slide--term-grid .slide__term-image,
.slide--term-grid .slide__term-image-placeholder {
    width: 100%;
    height: 130px;
    object-fit: contain;
    margin-bottom: 0.9rem;
}

.slide--term-grid .slide__term-image-placeholder {
    background: var(--s-surface);
    border-radius: 8px;
}

.slide--term-grid .slide__term-name {
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--s-heading-alt);
    margin-bottom: 0.4rem;
}

.slide--term-grid .slide__term-definition {
    font-size: 0.88rem;
    line-height: 1.5;
    color: var(--s-text-muted);
}

/* ── Concept card ─────────────────────────────────────── */
.slide--concept {
    display: grid;
    grid-template-columns: 1.2fr 1fr;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide--concept .slide__content {
    padding: 34px 40px;
    display: flex;
    flex-direction: column;
    gap: 0.65rem;
    justify-content: center;
    min-width: 0;
    overflow: hidden;
}

.slide--concept .slide__badge {
    align-self: flex-start;
    padding: 5px 14px;
    border-radius: 999px;
    background: var(--s-heading);
    color: var(--s-bg);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.08em;
}

.slide--concept .slide__heading {
    font-family: var(--s-font-display);
    font-size: 1.9rem;
    font-weight: 800;
    color: var(--s-heading);
    line-height: 1.15;
}

.slide--concept .slide__body {
    font-size: 1rem;
    line-height: 1.5;
    color: var(--s-text-muted);
}

.slide--concept .slide__key-fact-box {
    padding: 4px 0;
}

.slide--concept .slide__key-fact {
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--s-text);
    line-height: 1.35;
}

/* KaTeX display math ships with 1em top+bottom margins – inside a fixed
   540px slide that's ~40px per formula, a major cause of concept-slide
   overflow. Tighten it slide-wide. */
.slide .katex-display {
    margin: 0.3em 0;
}

/* KaTeX keeps a display formula on one line whatever its width, so a long one
   (a word equation) ran out of its box and across the picture beside it. Let
   it break at its top-level operators, as inline math already does. */
.slide .katex-display > .katex {
    white-space: normal;
}

/* One box, four framings. Only the tint and the label colour change between
   them, so each variant is two custom properties rather than a copy of the
   rule. --callout-tint is a bare "r, g, b" triplet because both uses need it at
   a different alpha.

   Not scoped to .slide--concept: the recap slide reuses the same box for its
   closing "Remember", and a callout should look the same wherever a deck puts
   one. */
.slide__example-box {
    --callout-tint: 16, 163, 74;
    --callout-label: #0f9d58;
    padding: 12px 18px;
    border-radius: 10px;
    background: rgba(var(--callout-tint), 0.08);
    border: 1px solid rgba(var(--callout-tint), 0.18);
}

.slide__example-box--fun-fact {
    --callout-tint: 99, 102, 241;
    --callout-label: #4f46e5;
}

.slide__example-box--remember {
    --callout-tint: 236, 72, 153;
    --callout-label: #db2777;
}

.slide__example-box--try-this {
    --callout-tint: 245, 158, 11;
    --callout-label: #d97706;
}

.slide__example-label {
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--callout-label);
    margin-bottom: 0.3rem;
}

.slide__example-text {
    font-size: 0.9rem;
    line-height: 1.55;
    color: var(--s-text);
}

.slide--concept .slide__image-wrap {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 32px;
    overflow: hidden;
}

.slide--concept .slide__image {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.slide--concept .slide__image-placeholder {
    width: 100%;
    height: 100%;
    border-radius: 8px;
    background: linear-gradient(135deg, var(--s-surface) 0%, var(--s-border) 100%);
}

/* ── Timeline ─────────────────────────────────────────── */
.slide--timeline {
    display: flex;
    flex-direction: column;
    padding: 48px 60px;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide--timeline .slide__heading {
    font-family: var(--s-font-display);
    font-size: 2rem;
    font-weight: 700;
    color: var(--s-heading);
    padding-bottom: 0.6rem;
    border-bottom: 3px solid var(--s-accent);
    margin-bottom: 1.2rem;
    line-height: 1.2;
}

.slide--timeline .slide__timeline-list {
    display: flex;
    flex-direction: column;
    flex: 1;
    position: relative;
    padding-left: 26px;
    justify-content: space-evenly;
}

.slide--timeline .slide__timeline-line {
    position: absolute;
    left: 5px;
    width: 2px;
    background: var(--s-border);
}

.slide--timeline .slide__event {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    position: relative;
}

.slide--timeline .slide__event-dot {
    position: absolute;
    left: -26px;
    top: 5px;
    width: 12px; height: 12px;
    border-radius: 50%;
    background: var(--s-accent);
    border: 2px solid var(--s-bg);
    box-shadow: 0 0 0 2px var(--s-accent);
    flex-shrink: 0;
}

.slide--timeline .slide__event-content {
    display: flex;
    align-items: baseline;
    gap: 8px;
    flex-wrap: nowrap;
}

.slide--timeline .slide__event-label {
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--s-accent);
    white-space: nowrap;
    flex-shrink: 0;
}

.slide--timeline .slide__event-text {
    font-size: 1rem;
    color: var(--s-text);
    line-height: 1.4;
}

/* ── Definition ───────────────────────────────────────── */
.slide--definition {
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 52px 72px;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide--definition .slide__term-label {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    color: var(--s-accent);
    margin-bottom: 0.35rem;
}

.slide--definition .slide__term {
    font-family: var(--s-font-display);
    font-size: 2.4rem;
    font-weight: 700;
    color: var(--s-heading);
    line-height: 1.15;
    margin-bottom: 1.1rem;
}

.slide--definition .slide__definition-box {
    padding: 22px 28px;
    background: var(--s-surface);
    border-left: 5px solid var(--s-accent);
    border-radius: 0 8px 8px 0;
    margin-bottom: 1rem;
}

.slide--definition .slide__definition {
    font-size: 1.2rem;
    line-height: 1.65;
    color: var(--s-text);
}

.katex-inline {
    display: inline-block;
    vertical-align: middle;
}

.katex-display-wrap {
    display: block;
    margin: 0.5em 0;
    text-align: center;
}

.slide--definition .slide__example {
    font-size: 1rem;
    color: var(--s-text-muted);
    line-height: 1.6;
    font-style: italic;
}

/* ─────────────────────────────────────────────────────────
   Organisation branding
   ─────────────────────────────────────────────────────────
   A school's mark in the corner of every slide, and the "made by" line in the
   corner of the first.

   Drawn as an opaque light pill rather than as text tinted from the theme's
   own variables, for two reasons. The theme variables live on .slide and this
   sits beside it in .slide-page, so it cannot read them; and a crest is a piece
   of artwork designed against white — recolouring it for a dark theme is not
   something CSS can do, so the honest answer is to give it the background it
   was drawn for. The pill reads on every theme, dark ones included.

   Bottom left, because the bottom right of a deck is where a presenter's own
   slide numbers and controls go. */

.slide-brand,
.slide-credit {
    position: absolute;
    left: 24px;
    bottom: 20px;
    z-index: 5;
    display: flex;
    align-items: center;
    gap: 8px;
    max-width: 45%;
    padding: 5px 12px 5px 8px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.92);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18);
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.2;
    color: #3d4457;
    /* Nothing here is part of the lesson: it must never be what a pupil at the
       back reads first, and it must never grow a scrollbar. */
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* The first slide's line is longer and says more, so it is quieter still. */
.slide-credit {
    font-weight: 500;
    font-size: 12px;
    color: #5b6376;
}

.slide-brand-logo,
.slide-credit-logo {
    flex-shrink: 0;
    height: 26px;
    width: auto;
    max-width: 90px;
    object-fit: contain;
}

.slide-credit-logo { height: 22px; max-width: 70px; }

.slide-brand-name,
.slide-credit span {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* A slide with no logo is a pill of pure text, which needs its left padding
   back — the 8px above is there to sit tight against an image. */
.slide-brand--text,
.slide-credit--text { padding-left: 12px; }

/* ── Activities: questions and ordering ─────────────
   Both activities are a column of full-width panels that stretch to fill the
   slide - no dead band at the bottom, and only two things in each panel: the
   number and the words. Deliberately plain: an earlier pass had rails, spines,
   circles and a corner badge all at once, which was both fussy and too close to
   the layout it was inspired by.

   The task slide and its reveal share every rule, so advancing between them
   changes what is written and nothing about where it sits. */
.slide--questions,
.slide--ordering {
    display: flex;
    flex-direction: column;
    padding: 38px 56px;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide--questions .slide__heading,
.slide--ordering .slide__heading {
    font-family: var(--s-font-display);
    font-size: 2rem;
    font-weight: 700;
    color: var(--s-heading);
    line-height: 1.2;
}

.slide__q-instruction {
    font-size: 1rem;
    color: var(--s-text-muted);
    margin-top: 0.15rem;
    margin-bottom: 0.75rem;
}

.slide__q-list,
.slide__order-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    flex: 1;
    gap: 0.55rem;
}

/* Every panel takes an equal share of the height left over, which is what keeps
   a 3-question slide as full as a 5-question one. */
.slide__q-item,
.slide__order-row {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 1.1rem;
    padding: 0 26px;
    border-radius: 14px;
    background: var(--s-surface);
}

.slide__q-num,
.slide__order-num {
    flex: 0 0 40px;
    font-size: 1.7rem;
    font-weight: 700;
    color: var(--s-accent);
    font-variant-numeric: tabular-nums;
}

/* Before the reveal the ordering rows have no number yet, but the slot is still
   drawn - otherwise every line of text shifts sideways when it appears. */
.slide__order-num--blank {
    color: var(--s-border);
}

.slide__q-body {
    display: block;
    min-width: 0;
}

.slide__q-text,
.slide__order-text {
    display: block;
    font-size: 1.3rem;
    line-height: 1.3;
    color: var(--s-text);
}

/* On the reveal the question stays, demoted, and the answer sits under it. */
.slide--questions-answers .slide__q-text {
    font-size: 1.02rem;
    color: var(--s-text-muted);
}

.slide__q-answer {
    display: block;
    font-size: 1.28rem;
    font-weight: 700;
    line-height: 1.35;
    color: var(--s-heading);
}

/* ── Support ladder: starters, frame, worked example, talk task ─────────────
   The same family as the activities above, and built from the same panel - a
   task slide should look like a task slide whichever rung it is. What each one
   adds is the question it is all in service of, set large under the heading. */
.slide--task {
    display: flex;
    flex-direction: column;
    padding: 38px 56px;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide--task .slide__heading {
    font-family: var(--s-font-display);
    font-size: 2rem;
    font-weight: 700;
    color: var(--s-heading);
    line-height: 1.2;
}

.slide__task-question {
    font-size: 1.3rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--s-text);
    margin-top: 0.3rem;
    margin-bottom: 0.9rem;
}

.slide__task-label {
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--s-text-muted);
}

/* The second line of a step: the opening words to continue from, or the reason
   the step was taken. Quieter than the step itself, which is the thing to read. */
.slide__step-note {
    display: block;
    margin-top: 0.1rem;
    font-size: 1.02rem;
    line-height: 1.35;
    color: var(--s-text-muted);
}

.slide--structured-prompt .slide__q-text,
.slide--worked-example .slide__q-text {
    font-size: 1.18rem;
    font-weight: 600;
}

/* Starters on the left, the words to use on the right. */
.slide__task-cols {
    flex: 1;
    display: grid;
    grid-template-columns: 1.7fr 1fr;
    gap: 1.4rem;
    min-height: 0;
}

.slide__starter-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
}

.slide__starter {
    flex: 1;
    display: flex;
    align-items: center;
    padding: 0 26px;
    border-radius: 14px;
    background: var(--s-surface);
    font-size: 1.25rem;
    font-style: italic;
    line-height: 1.3;
    color: var(--s-heading);
}

.slide__word-bank {
    display: flex;
    flex-direction: column;
    gap: 0.7rem;
    padding: 20px 22px;
    border-radius: 14px;
    border: 1px solid var(--s-border);
}

.slide__word-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.slide__word-chip {
    padding: 6px 14px;
    border-radius: 999px;
    background: var(--s-surface);
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--s-text);
}

.slide__worked-answer {
    display: flex;
    align-items: baseline;
    gap: 1rem;
    margin-top: 0.6rem;
    padding: 12px 26px;
    border-radius: 14px;
    border: 2px solid var(--s-accent);
    font-size: 1.28rem;
    font-weight: 700;
    line-height: 1.35;
    color: var(--s-heading);
}

.slide__talk-row {
    flex: 1;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1.1rem;
    min-height: 0;
}

.slide__talk-card {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 0.35rem;
    padding: 22px 24px;
    border-radius: 14px;
    background: var(--s-surface);
}

.slide__talk-card .slide__q-num {
    flex: none;
}

.slide__talk-text {
    font-size: 1.35rem;
    line-height: 1.35;
    color: var(--s-text);
}

/* ── Canvas art ───────────────────────────────────────────
   Two pseudo-elements per slide, drawn differently by every theme - see
   --s-shape and the per-theme rules in the THEME ART section below. */
.slide::before,
.slide::after {
    content: var(--s-shape);
    position: absolute;
    z-index: -1;
    pointer-events: none;
}

/* ══ THEME ART ════════════════════════════════════════════
   What each theme draws on its canvas. Deliberately NOT one motif in thirteen
   palettes: a teacher choosing a theme should get a different-looking product,
   not the same slide recoloured.

   Every treatment obeys the same three constraints - no alpha in a gradient
   (exports as a dark blob), no sized element past the BOTTOM edge (inflates
   scrollHeight and the export's auto-fit then shrinks the text), and box-shadow
   is ink so it may spill anywhere. All were checked against a rasterised PDF. */

/* Classic - a spine down the left edge and one large soft rounded block easing
   in from the right. Rounded rectangles rather than circles or wedges, so the
   default theme has a vocabulary of its own without raising its voice. */
[data-theme="classic"] .slide::before {
    left: 0; top: 0; bottom: 0; width: 10px;
    background: #0077ff;
}
[data-theme="classic"] .slide::after {
    right: -120px; bottom: 0; width: 380px; height: 380px;
    border-radius: 72px;
    background: #eef4fd;
}
/* Dark - two soft glows, the one thing a dark canvas can do that a light one
   cannot. Blur is ink, so these spill off the edges freely. */
[data-theme="dark"] .slide::before {
    left: 88%; top: 12%; width: 2px; height: 2px; border-radius: 50%;
    box-shadow: 0 0 200px 130px #3b3b8f;
}
[data-theme="dark"] .slide::after {
    left: 6%; top: 92%; width: 2px; height: 2px; border-radius: 50%;
    box-shadow: 0 0 180px 110px #4c1d70;
}

/* Vibrant - a diagonal band slicing the lower right. */
[data-theme="vibrant"] .slide::before {
    inset: 0;
    background: #fde3c7;
    clip-path: polygon(100% 22%, 100% 62%, 0 100%, 0 74%);
}
[data-theme="vibrant"] .slide::after {
    inset: 0;
    background: #fbd5e4;
    clip-path: polygon(100% 66%, 100% 100%, 42% 100%);
}

/* Ocean - two swells across the foot of the slide. */
[data-theme="ocean"] .slide::before {
    left: -12%; right: -12%; bottom: 0; height: 190px;
    border-radius: 50% 50% 0 0 / 100% 100% 0 0;
    background: #d3ecf7;
}
[data-theme="ocean"] .slide::after {
    left: -20%; right: -4%; bottom: 0; height: 110px;
    border-radius: 50% 50% 0 0 / 100% 100% 0 0;
    background: #bfe3f2;
}

/* Forest - rolling hills, the same device as ocean's swells but overlapped and
   asymmetric so it reads as landscape rather than water. */
[data-theme="forest"] .slide::before {
    left: -25%; width: 90%; bottom: 0; height: 230px;
    border-radius: 50% 50% 0 0 / 100% 100% 0 0;
    background: #dfeacb;
}
[data-theme="forest"] .slide::after {
    right: -18%; width: 80%; bottom: 0; height: 165px;
    border-radius: 50% 50% 0 0 / 100% 100% 0 0;
    background: #cfe0b4;
}

/* Sunset - a low sun and its halo over a graded sky. Both are centred on (640, 307);
   the numbers are pixels rather than percentages so they stay concentric. */
[data-theme="sunset"] .slide::before {
    left: 540px; bottom: 133px; width: 200px; height: 200px;
    border-radius: 50%;
    background: #ffd49b;
}
[data-theme="sunset"] .slide::after {
    left: 500px; bottom: 93px; width: 280px; height: 280px;
    border-radius: 50%;
    border: 2px solid #ffd9b3;
}
/* Blueprint - the frame and title block of a drawing sheet, over one faint
   grid. It previously carried four overlapping grids AND two circles, which is
   a lot of ink for something meant to sit behind the words. */
[data-theme="blueprint"] .slide::before {
    inset: 14px;
    border: 1px solid #b9d3ea;
}
[data-theme="blueprint"] .slide::after {
    right: 14px; bottom: 14px; width: 196px; height: 44px;
    border: 1px solid #b9d3ea;
    background: #e7eff8;
}
/* Pastel - confetti. One element, several shadows, so a scatter costs two
   pseudo-elements rather than a dozen. */
[data-theme="pastel"] .slide::before {
    left: 8%; top: 16%; width: 14px; height: 14px; border-radius: 50%;
    background: #f0c8ea;
    box-shadow: 190px -60px 0 4px #cfe3f7, 470px 40px 0 -2px #f5d9b0,
                760px -30px 0 6px #e2cdf5, 300px 300px 0 2px #f6cfe6,
                640px 350px 0 -3px #cfe8dd, 60px 380px 0 5px #f2dcc0;
}
[data-theme="pastel"] .slide::after {
    left: 88%; top: 62%; width: 22px; height: 22px; border-radius: 50%;
    background: #e6d4f7;
}

/* Slate - keeps its stripes, and squares off one corner. */
[data-theme="slate"] .slide::before {
    inset: 0;
    background: #dbe4ee;
    clip-path: polygon(100% 0, 100% 46%, 62% 0);
}
[data-theme="slate"] .slide::after {
    left: 0; bottom: 0; width: 190px; height: 10px;
    background: #2563eb;
}

/* Autumn - a fallen ring and a solid disc, off opposite corners. */
[data-theme="autumn"] .slide::before {
    left: 72%; top: -90px; width: 300px; height: 300px;
    border: 26px solid #f3dcbb; border-radius: 50%;
}
[data-theme="autumn"] .slide::after {
    left: -60px; top: 68%; width: 220px; height: 220px; border-radius: 50%;
    background: #f0dcc4;
}

/* Mono - keeps its dot screen, and cuts one hard corner. */
[data-theme="mono"] .slide::before {
    inset: 0;
    background: #111111;
    clip-path: polygon(100% 0, 100% 20%, 76% 0);
}
[data-theme="mono"] .slide::after {
    left: 0; bottom: 0; width: 260px; height: 6px;
    background: #111111;
}

/* Primary - the two circles this system started from. */
[data-theme="primary"] .slide::before {
    left: calc(96% - 1px); top: calc(4% - 1px);
    width: 2px; height: 2px; border-radius: 50%;
    box-shadow: 0 0 0 209px #fdf0b5;
}
[data-theme="primary"] .slide::after {
    left: calc(2% - 1px); top: calc(96% - 1px);
    width: 2px; height: 2px; border-radius: 50%;
    box-shadow: 0 0 0 249px #d6e9fb;
}

/* Templates that paint their own full-bleed background have no room for them -
   the art would land on top of the photo or the gradient, not behind it.
   .slide--title belongs here as much as the rest: it paints --s-title-bg, and
   leaving it out put a pale block and a blue spine across every title slide. */
.slide--title::before, .slide--title::after,
.slide--title-image::before, .slide--title-image::after,
.slide--quote::before, .slide--quote::after,
.slide--section::before, .slide--section::after {
    content: none;
}

/* A row of cards - but only up to four of them.
   The selector is a quantity query: an item is styled only when it is among the
   first four AND among the last four, which is true of every item exactly when
   there are four or fewer. At eight the cards stop helping and start hurting -
   the columns go narrow, every caption breaks onto six lines, and the slide
   reads as a wall of boxes. A wide row of plain captions is better. */
.slide--term-grid .slide__term-item:nth-child(-n+4):nth-last-child(-n+4) {
    padding: 14px;
    border: 1px solid var(--s-border);
    border-radius: 16px;
    background: var(--s-surface);
}

/* ── Photo mount ───────────────────────────────────────────
   Applied to every image that sits directly on the slide canvas. Off unless a
   theme sets the variables, because a white mount on a white ground is just an
   invisible 6px of padding.

   Not term-grid thumbnails: those already sit in a row of their own, and where
   the row is carded as well a mount makes it a box inside a box. */
.slide__image,
.slide__pstep-image,
.slide__hook-image,
.slide__recap-image {
    border: var(--s-image-frame);
    border-radius: var(--s-image-frame-radius);
    box-shadow: var(--s-image-shadow);
}

/* Except a bleed image, which is meant to run off the edge of the slide - a
   mount would draw a white line down the middle of it and stop it bleeding. */
.slide--image-text:not(.slide--image-text--circle) .slide__image {
    border: 0;
    border-radius: 0;
    box-shadow: none;
}

/* ── Hook: the question the deck answers ──────────────────
   A deliberately sparse slide. One question, given room, beside one picture -
   the point is that the class reads it and wonders, not that it teaches. */
.slide--hook {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    gap: 0 48px;
    padding: 48px 56px;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide--hook .slide__heading {
    font-family: var(--s-font-display);
    font-size: 2.4rem;
    font-weight: 700;
    color: var(--s-heading);
    line-height: 1.15;
    margin-bottom: 1rem;
}

.slide__hook-question {
    font-size: 1.35rem;
    line-height: 1.5;
    color: var(--s-text);
}

.slide__hook-image-wrap {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    overflow: hidden;
}

.slide__hook-image {
    max-width: 100%;
    max-height: 100%;
    border-radius: 16px;
    object-fit: cover;
}

/* ── Recap: what to leave with ────────────────────────────
   Picture left, takeaways right. The callout reuses the concept slide's box so
   a "Remember" reads the same wherever a deck puts one. */
.slide--recap {
    display: grid;
    grid-template-columns: 0.85fr 1.15fr;
    align-items: center;
    gap: 0 44px;
    padding: 44px 56px;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide__recap-image-wrap {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    overflow: hidden;
}

.slide__recap-image {
    max-width: 100%;
    max-height: 100%;
    border-radius: 16px;
    object-fit: cover;
}

.slide--recap .slide__heading {
    font-family: var(--s-font-display);
    font-size: 1.9rem;
    font-weight: 700;
    color: var(--s-heading);
    line-height: 1.2;
}

.slide__recap-intro {
    font-size: 1.05rem;
    color: var(--s-text-muted);
    margin-top: 0.3rem;
}

.slide__recap-list {
    list-style: none;
    margin: 0.9rem 0 0.9rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.slide__recap-list li {
    font-size: 1.1rem;
    line-height: 1.45;
    padding-left: 1.6rem;
    position: relative;
    color: var(--s-text);
}

/* A tick, not a bullet: these are things the class has now done. */
.slide__recap-list li::before {
    content: '\2713';
    position: absolute;
    left: 0;
    top: 0;
    font-size: 1rem;
    font-weight: 700;
    color: var(--s-accent);
}

.slide--recap .slide__example-box {
    margin-top: 0.2rem;
}

/* ── Photo process: a sequence you can see ────────────────
   process-flow in pictures. The arrow sits between the image and the label so
   it reads along the row without needing a column of its own. */
.slide--photo-process {
    display: flex;
    flex-direction: column;
    padding: 44px 56px;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide--photo-process .slide__heading {
    font-family: var(--s-font-display);
    font-size: 2rem;
    font-weight: 700;
    color: var(--s-heading);
    line-height: 1.2;
    margin-bottom: 1.1rem;
}

.slide__pstep-row {
    display: flex;
    flex: 1;
    gap: 20px;
    align-items: stretch;
}

.slide__pstep {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    text-align: center;
}

/* Grows into whatever height the row has left, so the pictures - which are the
   reason to use this template over process-flow - get the space rather than
   leaving a band of empty slide under the captions. */
.slide__pstep-image-wrap {
    position: relative;
    /* A fixed share of the column rather than flex:1. Captions vary in length,
       and letting the picture absorb the difference gave each stage a different
       image height and knocked the three labels out of line with each other. */
    flex: 0 0 62%;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.slide__pstep-image {
    max-width: 100%;
    max-height: 100%;
    border-radius: 12px;
    object-fit: cover;
}

/* Sits in the gap between two pictures and vertically centred on them, so the
   row reads as one journey rather than three separate cards. Anchored to the
   image wrapper rather than the column because the captions vary in height. */
.slide__pstep-arrow {
    position: absolute;
    top: 50%;
    right: -22px;
    transform: translateY(-50%);
    font-size: 1.5rem;
    line-height: 1;
    color: var(--s-accent);
}

.slide__pstep-label {
    margin-top: 0.7rem;
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--s-text);
    line-height: 1.3;
}

.slide__pstep-detail {
    font-size: 0.95rem;
    line-height: 1.45;
    color: var(--s-text-muted);
    margin-top: 0.25rem;
}

/* ── Icon badge ───────────────────────────────────────────
   Some cards illustrate an abstract idea - Drinking, Washing, Growing - which
   has no photograph and no diagram. A symbol in a tinted disc is what those
   want, and because the set is bundled, every icon in a row matches every
   other: the one thing a web image search can never promise.

   The glyph is inline SVG with stroke="currentColor", so it takes the theme's
   accent like any other text and needs no per-theme rule. */
.slide__icon-badge {
    flex: 0 0 auto;
    width: 88px;
    height: 88px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    /* A solid tint, not a translucent one. Both halves of that matter for the
       PDF export: color-mix() is newer CSS than the export path is worth
       betting on, and mixing toward `transparent` fades toward black in a
       renderer that does not premultiply alpha - the same fault that turned
       this theme's background discs into shaded spheres. */
    background: var(--s-icon-badge-bg);
    color: var(--s-accent);
}

.slide__icon-badge .slide__icon {
    width: 44px;
    height: 44px;
}

/* A process step is narrower and its badge sits in a fixed-height band. */
.slide--photo-process .slide__icon-badge {
    width: 72px;
    height: 72px;
}

.slide--photo-process .slide__icon-badge .slide__icon {
    width: 36px;
    height: 36px;
}

/* ── image-text variants ──────────────────────────────────
   Same content, two shapes. Alternating them - and which side the picture sits
   on - is most of what stops a run of picture-and-text slides reading as one
   slide shown four times. */
.slide--image-text--left .slide__image-wrap { order: -1; }

/* A disc inside a ring, floated in the column rather than filling it. The ring
   is the whole point: it is what turns a crop into a deliberate shape. */
.slide--image-text--circle .slide__image-wrap {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 40px;
}

.slide--image-text--circle .slide__image,
.slide--image-text--circle .slide__image-placeholder {
    width: 100%;
    max-width: 340px;
    height: auto;
    aspect-ratio: 1 / 1;
    border-radius: 50%;
    border: 10px solid var(--s-image-ring);
    box-shadow: var(--s-image-shadow);
    object-fit: cover;
}

/* ── Bookends ─────────────────────────────────────────────
   The deck opens and closes on the same shape: a panel around the words, drawn
   in the accent on the title and in a second colour on the recap. Cheap, and it
   is what makes a deck feel deliberately topped and tailed rather than just
   started and stopped. */
.slide__title-panel {
    padding: var(--s-panel-padding);
    border: var(--s-title-panel-border);
    border-radius: var(--s-panel-radius);
    background: var(--s-title-panel-bg);
}

.slide--recap .slide__recap-text {
    padding: var(--s-panel-padding);
    border: var(--s-panel-alt-border);
    border-radius: var(--s-panel-radius);
    background: var(--s-panel-bg);
}

/* ── Icon cards ───────────────────────────────────────────
   Three ideas that no photograph shows. The badge is the whole point, so it is
   larger here than the one a term-grid cell gets, and the card is always drawn -
   there is no quantity query, because this template caps at four by construction
   where a term-grid can legitimately carry eight. */
.slide--icon-cards {
    display: flex;
    flex-direction: column;
    padding: 44px 56px;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
}

.slide--icon-cards .slide__heading {
    font-family: var(--s-font-display);
    font-size: 2.15rem;
    font-weight: 700;
    color: var(--s-heading);
    line-height: 1.2;
    margin-bottom: 1.2rem;
}

.slide__icon-card-row {
    display: flex;
    flex: 1;
    gap: 26px;
    align-items: stretch;
}

.slide__icon-card {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* Top-aligned, not centred: each card centring its own content put the
       badges and labels on different lines whenever the sentences differed in
       length, and a row of labels that does not line up is the first thing the
       eye catches. Uneven space at the FOOT of a card is not noticed. */
    justify-content: flex-start;
    gap: 0.7rem;
    padding: 30px 26px 24px;
    border: 1px solid var(--s-border);
    border-radius: 18px;
    background: var(--s-surface);
    text-align: center;
}

.slide--icon-cards .slide__icon-badge {
    width: 104px;
    height: 104px;
}

.slide--icon-cards .slide__icon-badge .slide__icon {
    width: 52px;
    height: 52px;
}

/* Sized against a reference deck rather than by eye: its card labels measure
   ~29px and its body ~19px on a 960-wide slide. The first pass at 1.35rem/1.02rem
   left the type looking timid and the card half empty. */
.slide__icon-card-label {
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--s-heading-alt);
    line-height: 1.2;
    /* Two lines' worth whether it needs them or not. "Drinking Water" wraps and
       "Boats" does not, and without this the sentences beneath them start on
       different lines - the same misalignment the cards are top-aligned to
       avoid, reintroduced one element lower down. */
    min-height: 2.4em;
    display: flex;
    align-items: center;
    justify-content: center;
}

.slide__icon-card-text {
    font-size: 1.15rem;
    line-height: 1.6;
    color: var(--s-text-muted);
}


/* ══ Elements renderer (elements_json + contents_json) ═══════════════════
   Geometry (position/size) is inline per element from box – these rules
   only carry typography/colour, reusing the same theme variables as the
   template renderer above so a slide looks the same either way. */
.slide--elements {
    position: relative;
    width: 960px;
    height: 540px;
    overflow: hidden;
    box-sizing: border-box;
    background-color: var(--s-bg);
    background-image: var(--s-bg-image);
    background-size: var(--s-bg-size);
    color: var(--s-text);
    font-family: var(--s-font);
}

.slide--elements .el {
    box-sizing: border-box;
    overflow: hidden;
}

/* A background colour the teacher chose for this slide: a full-canvas shape
   under everything else. Clicks go through it to the slide, so it can never be
   picked up and dragged like the shapes drawn on top of it. */
.slide--elements .el[data-slide-bg] {
    pointer-events: none;
}

.slide--elements .el--heading,
.slide--elements .el--chapter_title {
    font-family: var(--s-font-display);
    font-size: 2rem;
    font-weight: 700;
    color: var(--s-heading);
    line-height: 1.2;
}

.slide--elements .el--subtitle,
.slide--elements .el--chapter_subtitle {
    font-size: 1.15rem;
    font-weight: 400;
    color: var(--s-text-muted);
    line-height: 1.4;
}

.slide--elements .el--column_heading {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--s-col-heading);
}

.slide--elements .el--body {
    font-size: 1.1rem;
    line-height: 1.5;
    color: var(--s-text);
}

.slide--elements p {
    margin: 0;
}

.slide--elements .el--bullet_list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    font-size: 1.15rem;
    line-height: 1.5;
    color: var(--s-text);
}

.slide--elements .el--bullet_list li {
    padding-left: 1.3rem;
    position: relative;
}

.slide--elements .el--bullet_list li::before {
    content: '';
    position: absolute;
    left: 0.1rem;
    top: 0.55em;
    width: 0;
    height: 0;
    border-top: 0.32em solid transparent;
    border-bottom: 0.32em solid transparent;
    border-left: 0.4em solid var(--s-bullet);
}

/* Per-template markers (the model's bulletStyle, rendered as data-bullet):
   "main" is a content slide's list, "dot" a comparison column's. */
.slide--elements .el--bullet_list[data-bullet="main"] li {
    padding-left: 1.4rem;
}

.slide--elements .el--bullet_list[data-bullet="dot"] li {
    padding-left: 1rem;
}

.slide--elements .el--bullet_list[data-bullet="dot"] li::before {
    left: 0;
    top: 0.6em;
    width: 5px;
    height: 5px;
    border: 0;
    border-radius: 50%;
    background: var(--s-bullet);
}

[data-theme="primary"] .slide--elements .el--bullet_list[data-bullet="main"] li::before {
    content: '★';
    width: auto;
    height: auto;
    border: 0;
    top: 0.1em;
    left: 0;
    color: #fbbf24;
    font-size: 0.95rem;
}

/* Composite boxes (step, event, example, term): the parts are sized in em of
   the box's own font-size, so the one size stored on the element scales the
   whole box – which is how generation shrinks a slide that does not fit. */
.slide--elements .el--term_copy { font-size: 1.15rem; }

.slide--elements .el--flow_step {
    font-size: 0.85rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 0 8px;
    box-sizing: border-box;
}

/* The numbered circle is a real shape + text element pair in the model
   (generated next to the step's text box, anchored above it) – no CSS
   pseudo-element, so a single element can't double-draw it. */

.slide--elements .el--flow_step .el__label {
    font-weight: 700;
    font-size: 1.1765em;
    color: var(--s-heading);
    margin-bottom: 0.35em;
}

.slide--elements .el--flow_step .el__text {
    font-size: 1em;
    color: var(--s-text-muted);
    line-height: 1.45;
}

.slide--elements .el--timeline_event {
    font-size: 1rem;
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.slide--elements .el--timeline_event .el__label {
    font-size: 0.85em;
    font-weight: 700;
    color: var(--s-accent);
    white-space: nowrap;
}

.slide--elements .el--timeline_event .el__text {
    font-size: 1em;
    color: var(--s-text);
    line-height: 1.4;
}

.slide--elements .el--quote_text {
    font-family: var(--s-font-display);
    font-size: 1.7rem;
    font-weight: 600;
    color: var(--s-heading);
    line-height: 1.4;
}

.slide--elements .el--attribution {
    font-size: 1.05rem;
    color: var(--s-text-muted);
}

.slide--elements .el--chapter_number {
    font-family: var(--s-font-display);
    font-size: 3.5rem;
    font-weight: 800;
    color: var(--s-accent);
    opacity: 0.7;
}

.slide--elements .el--term {
    font-family: var(--s-font-display);
    font-size: 2rem;
    font-weight: 700;
    color: var(--s-heading);
    line-height: 1.2;
}

.slide--elements .el--definition {
    font-size: 1.15rem;
    line-height: 1.6;
    color: var(--s-text);
}

.slide--elements .el--definition_label {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    color: var(--s-accent);
}

/* Tints per callout kind, the same set as .slide__example-box--*. */
.slide--elements .el--example_box {
    font-size: 0.9rem;
    --callout-tint: 16, 163, 74;
    --callout-label: #0f9d58;
    border-radius: 10px;
    background: rgba(var(--callout-tint), 0.08);
    border: 1px solid rgba(var(--callout-tint), 0.18);
}

.slide--elements .el--example_box[data-callout="fun-fact"] {
    --callout-tint: 99, 102, 241;
    --callout-label: #4f46e5;
}

.slide--elements .el--example_box[data-callout="remember"] {
    --callout-tint: 236, 72, 153;
    --callout-label: #db2777;
}

.slide--elements .el--example_box[data-callout="try-this"] {
    --callout-tint: 245, 158, 11;
    --callout-label: #d97706;
}

.slide--elements .el--example_box .el__example-label {
    font-size: 0.9444em;
    font-weight: 700;
    color: var(--callout-label);
    margin-bottom: 0.353em;
}

.slide--elements .el--example_box .el__example-text {
    font-size: 1em;
    line-height: 1.55;
    color: var(--s-text);
}

.slide--elements .el--example {
    font-size: 1rem;
    color: var(--s-text-muted);
    font-style: italic;
    line-height: 1.5;
}

.slide--elements .el--category {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    color: var(--s-accent);
    /* A one-line pill. Its box width is estimated without knowing the theme's
       font, and a wide one (Verdana) wrapped the label onto a second line that
       fell out of the bottom of the pill – so it never wraps, and is never
       narrower than its text whatever width the box was given. */
    white-space: nowrap;
    min-width: max-content;
}

.slide--elements .el--key_fact {
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--s-heading);
    line-height: 1.4;
}

.slide--elements .el--example_text {
    font-size: 0.95rem;
    color: var(--s-text-muted);
    line-height: 1.5;
}

.slide--elements .el--term_copy .el__term {
    font-size: 1em;
    font-weight: 700;
    color: var(--s-heading-alt);
    margin-bottom: 0.2609em;
}

.slide--elements .el--term_copy .el__definition {
    font-size: 0.7652em;
    font-weight: 400;
    line-height: 1.5;
    color: var(--s-text-muted);
}

.slide--elements .el--image,
.slide--elements .el--image-placeholder {
    width: 100%;
    height: 100%;
}

.slide--elements .el--image-placeholder {
    background: linear-gradient(135deg, var(--s-surface) 0%, var(--s-border) 100%);
    border-radius: 8px;
}

.slide--elements .el--shape {
    display: flex;
    align-items: center;
    justify-content: center;
}
