#!/usr/bin/env python3
"""Build the self-contained Literate AI HTML5 conference deck."""

from __future__ import annotations

import base64
import hashlib
import html
import json
import re
from pathlib import Path

HERE = Path(__file__).resolve().parent
OUT = HERE / "index.html"
VALIDATION = HERE / "html-validation.json"
ASSETS = HERE / "assets"


def data_uri(name: str) -> str:
    path = ASSETS / name
    encoded = base64.b64encode(path.read_bytes()).decode("ascii")
    return f"data:image/png;base64,{encoded}"


def slide(number: int, title: str, eyebrow: str, body: str, notes: str, *, dark: bool = False) -> str:
    theme = " dark" if dark else ""
    return f"""
      <section class="slide{theme}" id="slide-{number}" data-slide="{number}" aria-roledescription="slide" aria-label="Slide {number} of 14: {html.escape(title)}">
        <div class="slide-head"><span class="brand">LITERATE-AI</span><span class="edition">CONFERENCE 2026</span><span class="number">{number:02}</span></div>
        <p class="eyebrow">{eyebrow}</p>
        <h2>{title}</h2>
        <div class="rule"></div>
        <div class="slide-body">{body}</div>
        <div class="source">source-notes.md</div>
        <div class="slide-progress"><i style="width:{number / 14 * 100:.4f}%"></i></div>
        <aside class="speaker-note" aria-label="Speaker notes">{notes}</aside>
      </section>"""


def build() -> None:
    grumpy = data_uri("00-grumpy-counter.png")
    furniture = data_uri("03-impossible-furniture.png")
    cathedral = data_uri("05-component-cathedral.png")

    slides = [
        """
      <section class="slide cover dark active" id="slide-1" data-slide="1" aria-roledescription="slide" aria-label="Slide 1 of 14: From readable intent to executable evidence">
        <div class="slide-head"><span class="brand">LITERATE-AI</span><span class="edition">CONFERENCE 2026</span><span class="number">01</span></div>
        <div class="cover-copy"><p class="eyebrow">28 OCTOBER 2026 · BROWSER-NATIVE EDITION</p><h1>From readable intent<br>to executable evidence</h1><p>How a specification-led harness grew into a component system for governed software creation.</p></div>
        <div class="hero-dag" aria-label="Abstract component graph"><b class="n1">intent</b><b class="n2">build</b><b class="n3">verify</b><b class="n4">music</b><b class="n5">3D</b><b class="n6">evidence</b></div>
        <div class="source">PROJECT.md · README.md</div><div class="slide-progress"><i style="width:7.1429%"></i></div>
        <aside class="speaker-note" aria-label="Speaker notes">Open with the distinction between generation and confidence. Literate AI makes readable intent durable and requires generated implementation to earn acceptance.</aside>
      </section>""",
        slide(2, "Code generation made code abundant. Confidence stayed scarce.", "THE BOTTLENECK MOVED", """
          <div class="flow"><article><strong>PROMPT</strong><span>plausible intent</span></article><em>→</em><article><strong>SOURCE</strong><span>plausible implementation</span></article><em>→</em><article><strong>TESTS</strong><span>plausible self-assessment</span></article><em>→</em><article class="question"><strong>?</strong><span>release confidence</span></article></div>
          <p class="thesis">A candidate can be coherent, tested, and still be wrong about the authority it was meant to implement.</p>""", "Do not frame models as the problem. The missing piece is an independently checkable custody and acceptance boundary."),
        slide(3, "Invert the product: intent is durable; implementation is renewable.", "THREE THINGS MUST REMAIN DIFFERENT", """
          <div class="triad"><article><small>AUTHORITY</small><h3>INTENT</h3><p>Readable behavior<br>and constraints</p></article><article><small>CANDIDATE</small><h3>IMPLEMENTATION</h3><p>Replaceable source<br>and native artifacts</p></article><article><small>ADMISSION</small><h3>EVIDENCE</h3><p>Independent checks<br>and current receipts</p></article></div>""", "This is the core thesis. A model can help regenerate implementation, but cannot grant itself authority or acceptance.", dark=True),
        slide(4, "A Component DAG keeps authority factored—and still makes art.", "COMPOSITION WITHOUT COPY-AND-PASTE", """
          <div class="dag" role="img" aria-label="Component connected to math, physics, 3D, music, and video"><div class="edge e1"></div><div class="edge e2"></div><div class="edge e3"></div><div class="edge e4"></div><div class="edge e5"></div><b class="root">Component</b><b class="math">math</b><b class="physics">physics</b><b class="three-d">3D</b><b class="music">music</b><b class="video">video</b></div>
          <p class="thesis left">Each node owns a readable boundary. Edges express composition, not copy-and-paste.</p>""", "The DAG is both a technical boundary and a creative palette. Components can be small enough to review and rich enough to collaborate."),
        slide(5, "The lifecycle is a chain of custody, not a single generate button.", "EVERY TRANSITION CAN REFUSE", """
          <div class="stages"><article><b>RESOLVE</b><span>exact DAG</span></article><article><b>GENERATE</b><span>bounded context</span></article><article><b>BUILD</b><span>native tools</span></article><article><b>VERIFY</b><span>independent oracle</span></article><article><b>RECEIPT</b><span>current evidence</span></article><article><b>RELEASE</b><span>exact commit</span></article></div>
          <p class="thesis">A changed specification, Flavor, skill, route, dependency, toolchain, or artifact changes what must be proved.</p>""", "The exact recipe is broader than source. Reuse is allowed only when the relevant identities remain current."),
        slide(6, "Evolution I · make readable authority executable.", "THE 0.X LINE", """
          <div class="timeline"><article><b>0.1–0.4</b><span>Components + readable specs</span></article><article><b>0.5–0.8</b><span>locks, receipts + release protocol</span></article><article><b>0.9</b><span>evidence-gated framework</span></article><article><b>0.10</b><span>create + adopt journey</span></article><article><b>1.0</b><span>stable product boundary</span></article></div>""", "This is a capability narrative, not a claim that every present feature existed at each tag."),
        slide(7, "Evolution II · make evidence compose at production scale.", "THE 1.X LINE", """
          <div class="eras"><article><b>1.1</b><span>native + multi-language</span></article><article><b>1.2</b><span>integration + document pairs</span></article><article><b>1.3</b><span>action DAG + HTML explorer</span></article><article><b>1.3.1</b><span>separate patch closure</span></article><article><b>1.4 dev</b><span>retained native + public paths</span></article></div>
          <div class="legend"><span>published</span><span>patch program</span><span>development</span></div>""", "Be explicit: v1.3.0 is the latest published tag. 1.3.1 is a separate patch program. main carries 1.4.0 development authority.", dark=True),
        slide(8, "Exact identities turn explanation into an executable contract.", "THE RECIPE IS INSPECTABLE", """
          <div class="recipe"><ul><li>Component revision</li><li>selected Flavors</li><li>pinned skills</li><li>workflow + routing</li><li>repository sources</li></ul><strong>EXACT<br>RECIPE</strong><article><b>candidate + evidence</b><span>source · build · tests<br>acceptance · receipt</span></article></div>""", "The receipt is compact because it binds larger retained evidence by exact identity. It does not replace that evidence."),
        slide(9, "Failure is evidence, too—if ownership stays explicit.", "SIDE EFFECTS CHANGE RETRY POLICY", """
          <div class="cards"><article><h3>MODEL OUTPUT</h3><p>Useful proposal<br>No acceptance authority</p></article><article class="danger"><h3>FAILED ATTEMPT</h3><p>Retain diagnostics<br>Preserve ownership uncertainty</p></article><article class="success"><h3>TRUSTED RESOLUTION</h3><p>Owned terminal evidence<br>or admitted fenced lease</p></article></div>
          <p class="thesis">Retry policy must follow side effects—not optimism.</p>""", "This is why the action DAG distinguishes immutable production from mutable package or signing operations."),
        slide(10, "Observability became a product surface, not a debug afterthought.", "ONE PORTABLE HTML FILE", """
          <div class="explorer"><div class="mini-graph"><span>repositories</span><span>Components</span><span>Flavors</span><span>skills</span><i></i><i></i><i></i><i></i><i></i><i></i></div><div><article><b>IT IS</b><p>A provenance-bound authority graph with filters, focus, and source excerpts.</p></article><article class="no"><b>IT IS NOT</b><p>A general IDE, symbol index, or go-to-definition engine.</p></article></div></div>""", "The boundary matters: calling it a source browser would overstate the implementation.", dark=True),
        slide(11, "Six labs teach composition by making increasingly questionable life choices.", "NO KPI DASHBOARDS WERE HARMED", f"""
          <div class="gallery"><figure><img src="{grumpy}" alt="Grumpy counter lab"><figcaption><b>00</b> grumpy math</figcaption></figure><figure><img src="{furniture}" alt="Impossible furniture 3D lab"><figcaption><b>03</b> impossible 3D</figcaption></figure><figure><img src="{cathedral}" alt="Component cathedral lab"><figcaption><b>05</b> multimedia cathedral</figcaption></figure></div>
          <p class="thesis">math → physics → audio/music → 3D → video → composed component art</p>""", "The source is DRY, but each generated index.html is free-standing and works without a server or network."),
        slide(12, "The cathedral is the argument: rigor can wear better clothes.", "YES, IT HAS A PIPE ORGAN · NO, FINANCE DID NOT ASK FOR IT", f"""
          <div class="feature"><img src="{cathedral}" alt="Component cathedral interactive visual lab"><div><article><b>READABLE</b><p>Select a node and inspect the authority it owns.</p></article><article><b>REPLACEABLE</b><p>Change one capability without rewriting the whole artifact.</p></article><article><b>PROVABLE</b><p>Capture bounded video; keep audio opt-in.</p></article></div></div>""", "This is intentionally cheeky. Component boundaries can support expressive work, not only business workflows.", dark=True),
        slide(13, "Release posture is part of the feature—not a footnote.", "CLAIMS FOLLOW EVIDENCE", """
          <div class="bands"><article><b>PUBLISHED</b><span>1.3.0 exact tag</span></article><article><b>PATCH</b><span>1.3.1 explicit goal ledger</span></article><article><b>DEVELOPMENT</b><span>1.4.0 on main</span></article><article><b>OPEN</b><span>FreeBSD + complete retained/public paths</span></article></div>
          <p class="thesis">An unchecked roadmap item is not a release claim. A catalog entry is not universal native qualification.</p>""", "This is the credibility slide. It prevents the evolution story from erasing current boundaries."),
        """
      <section class="slide close dark" id="slide-14" data-slide="14" aria-roledescription="slide" aria-label="Slide 14 of 14: Readable systems can be rigorous renewable and fun">
        <div class="slide-head"><span class="brand">LITERATE-AI</span><span class="edition">CONFERENCE 2026</span><span class="number">14</span></div>
        <div class="close-copy"><p class="eyebrow">SERIOUS EVIDENCE · LESS SERIOUS DEMOS</p><h2>Readable systems can be<br>rigorous, renewable—and fun.</h2><p>Keep intent human-readable.<br>Keep implementation replaceable.<br>Make evidence earn the release.</p><strong>Start with the visual labs. The grumpy counter has opinions.</strong></div>
        <div class="close-art"><i></i><i></i><i></i><i></i><i></i></div>
        <div class="source">github.com/jordanhubbard/literate-ai</div><div class="slide-progress"><i style="width:100%"></i></div>
        <aside class="speaker-note" aria-label="Speaker notes">Close on the three imperatives: readable intent, renewable implementation, earned evidence. Then invite attendees to meet the grumpy counter and inspect the generated HTML authority graph.</aside>
      </section>""",
    ]

    document = TEMPLATE.replace("{{SLIDES}}", "\n".join(slides))
    document = document.replace(
        ".slide{position:absolute;width:min(100vw,177.7778vh);height:min(100vh,56.25vw);aspect-ratio:16/9;",
        ".slide{position:fixed;left:50%;top:50%;width:1600px;height:900px;aspect-ratio:16/9;container-type:size;",
    ).replace(
        "transform:translateX(2%);transition:opacity .22s ease,transform .22s ease",
        "transform:translate(-50%,-50%) scale(var(--deck-scale,1));transform-origin:center;transition:opacity .22s ease",
    ).replace(
        ".slide.active{opacity:1;visibility:visible;transform:none;z-index:2}",
        ".slide.active{opacity:1;visibility:visible;z-index:2}",
    ).replace(
        ".feature{display:grid;grid-template-columns:2.4fr 1fr;gap:3%;height:78%}",
        ".feature{display:grid;grid-template-columns:2.4fr 1fr;grid-template-rows:minmax(0,1fr);gap:3%;height:88%;min-height:0;overflow:hidden}",
    ).replace(
        ".feature>div{display:grid;gap:4%}",
        ".feature>div{display:grid;grid-template-rows:repeat(3,minmax(0,1fr));gap:4%;min-height:0}",
    ).replace(
        "position:relative!important;display:block!important;opacity:1!important;visibility:visible!important;transform:none!important;",
        "position:relative!important;left:auto!important;top:auto!important;display:block!important;opacity:1!important;visibility:visible!important;transform:none!important;",
    )
    document = re.sub(r"(clamp\([^,]+,[\d.]+)vw", r"\1cqw", document)
    document = document.replace("font-size:1.6vw", "font-size:1.6cqw")
    OUT.write_text(document, encoding="utf-8")
    digest = hashlib.sha256(OUT.read_bytes()).hexdigest()
    report = {
        "schema": "literate-ai/html5-conference-deck-validation@1",
        "status": "built",
        "slide_count": len(slides),
        "expected_slide_count": 14,
        "speaker_notes_count": document.count('class="speaker-note"'),
        "embedded_image_count": document.count("data:image/png;base64,"),
        "sha256": digest,
        "byte_count": OUT.stat().st_size,
        "browser_review": "pending",
    }
    VALIDATION.write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8")
    print(f"built {OUT} ({len(slides)} slides, {digest})")


TEMPLATE = '''<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><meta name="color-scheme" content="dark light"><link rel="icon" href="data:,">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src data:; style-src 'unsafe-inline'; script-src 'unsafe-inline'; font-src data:">
<title>Literate AI · From readable intent to executable evidence</title>
<style>
:root{--ink:#101317;--night:#07111f;--panel:#23282f;--fog:#eef1f3;--white:#fff;--orange:#ff6b35;--orange2:#ff9b66;--blue:#72b7d6;--green:#76b900;--green2:#7bc6a4;--red:#f47c7c;--line:#d8dee3;--steel:#65707c;--muted:#aab3bc;color-scheme:dark}*{box-sizing:border-box}html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#05080c;font-family:Inter,"Helvetica Neue",Arial,sans-serif}.deck{width:100%;height:100%;display:grid;place-items:center}.slide{position:absolute;width:min(100vw,177.7778vh);height:min(100vh,56.25vw);aspect-ratio:16/9;background:var(--fog);color:var(--ink);overflow:hidden;padding:3.8% 5.4% 3.2%;opacity:0;visibility:hidden;transform:translateX(2%);transition:opacity .22s ease,transform .22s ease}.slide.active{opacity:1;visibility:visible;transform:none;z-index:2}.slide.dark{background:var(--ink);color:var(--white)}.slide-head{position:absolute;top:3.4%;left:5.4%;right:5.4%;display:flex;gap:.8%;align-items:center;font-size:clamp(7px,1vw,15px);font-weight:800;letter-spacing:.08em}.brand,.edition{padding:.45em .85em;border-radius:999px}.brand{background:var(--ink);color:#fff}.dark .brand{background:#fff;color:var(--ink)}.edition{background:var(--orange);color:var(--ink)}.number{margin-left:auto}.eyebrow{margin:7.5% 0 1%;color:var(--steel);font-size:clamp(8px,1.05vw,16px);font-weight:800;letter-spacing:.16em}.dark .eyebrow{color:var(--orange2)}h1,h2,h3,p{margin-top:0}h1{font-size:clamp(30px,5vw,76px);line-height:1.02;letter-spacing:-.045em}h2{max-width:92%;font-size:clamp(23px,3.1vw,47px);line-height:1.04;letter-spacing:-.035em;margin-bottom:1.2%}.rule{width:7%;height:.6%;min-height:3px;background:var(--orange);margin:0 0 2.6%}.slide-body{height:62%;position:relative}.source{position:absolute;bottom:2.2%;left:5.4%;font:clamp(6px,.62vw,10px)/1 monospace;color:var(--steel)}.dark .source{color:var(--muted)}.slide-progress{position:absolute;right:5.4%;bottom:2.4%;width:13%;height:3px;background:var(--line)}.dark .slide-progress{background:var(--panel)}.slide-progress i{display:block;height:100%;background:var(--orange)}.speaker-note{display:none}.thesis{font-size:clamp(13px,1.65vw,25px);line-height:1.25;font-weight:750;text-align:center;margin:3% auto 0;max-width:92%}.thesis.left{text-align:left}.flow,.triad,.stages,.eras,.cards{display:flex;align-items:stretch;gap:2%;height:55%}.flow{align-items:center}.flow article,.cards article{flex:1;background:#fff;border:1px solid var(--line);border-left:7px solid var(--red);border-radius:14px;padding:3%;display:flex;flex-direction:column;justify-content:center}.flow em{font-size:clamp(16px,2vw,30px);color:var(--steel);font-style:normal}.flow strong,.cards h3{font-size:clamp(10px,1.15vw,18px)}.flow span,.cards p{color:var(--steel);font-size:clamp(9px,1vw,16px)}.flow .question{background:var(--ink);color:#fff;text-align:center;border:0}.flow .question strong{font-size:clamp(28px,4vw,60px);color:var(--orange)}.flow .question span{color:#fff}.triad article{flex:1;border-radius:16px;padding:3%;background:var(--panel);border-top:10px solid var(--orange)}.triad article:nth-child(2){border-color:var(--blue)}.triad article:nth-child(3){border-color:var(--green2)}.triad small{color:var(--orange2);font-weight:800}.triad h3{font-size:clamp(13px,1.55vw,24px);margin:9% 0}.triad p{color:var(--muted);font-size:clamp(11px,1.25vw,19px);line-height:1.35}.dag{position:relative;width:88%;height:70%;margin:auto}.dag b{position:absolute;width:13%;padding:1.4% 1%;border-radius:999px;text-align:center;background:var(--blue);z-index:2;font-size:clamp(9px,1vw,16px)}.dag .root{left:43.5%;top:8%;background:var(--orange)}.dag .math{left:4%;top:56%}.dag .physics{left:25%;top:70%;background:var(--green2)}.dag .three-d{left:46%;top:64%;background:var(--orange2)}.dag .music{left:68%;top:50%}.dag .video{left:84%;top:72%;background:var(--green)}.edge{position:absolute;left:49%;top:24%;height:3px;background:var(--steel);transform-origin:left center}.e1{width:47%;transform:rotate(157deg)}.e2{width:29%;transform:rotate(137deg)}.e3{width:33%;transform:rotate(94deg)}.e4{width:28%;transform:rotate(39deg)}.e5{width:48%;transform:rotate(40deg)}.stages{height:42%;gap:1%}.stages article{flex:1;position:relative;background:#fff;border:1px solid var(--line);border-radius:14px;padding:2%;display:flex;flex-direction:column;justify-content:center;text-align:center}.stages article:after{content:"→";position:absolute;right:-10%;top:40%;z-index:3;color:var(--steel);font-size:1.6vw}.stages article:last-child:after{content:""}.stages article:first-child{background:var(--orange)}.stages article:nth-last-child(-n+2){background:var(--green2)}.stages b{font-size:clamp(8px,1vw,15px)}.stages span{margin-top:12%;font-size:clamp(7px,.85vw,13px);color:var(--steel)}.timeline{display:flex;height:65%;align-items:center;position:relative}.timeline:before{content:"";position:absolute;left:4%;right:4%;top:48%;height:5px;background:var(--line)}.timeline article{flex:1;position:relative;height:100%;text-align:center;z-index:1}.timeline article:after{content:"";position:absolute;left:calc(50% - 10px);top:calc(48% - 8px);width:20px;height:20px;background:var(--orange);border-radius:50%}.timeline article:last-child:after{background:var(--green)}.timeline b{display:block;margin-top:10%;font-size:clamp(12px,1.5vw,23px)}.timeline span{display:block;margin:37% auto 0;max-width:75%;color:var(--steel);font-size:clamp(8px,.95vw,15px)}.eras{height:64%}.eras article{flex:1;background:var(--panel);border-radius:14px;padding:4% 2%;border-top:8px solid var(--blue)}.eras article:nth-child(2){border-color:var(--orange2)}.eras article:nth-child(3){border-color:var(--green2)}.eras article:nth-child(4){border-color:var(--orange)}.eras article:nth-child(5){border-color:var(--green)}.eras b{display:block;font-size:clamp(16px,2vw,31px);margin-bottom:16%}.eras span{color:var(--muted);font-size:clamp(9px,1.05vw,16px);line-height:1.35}.legend{display:flex;justify-content:space-between;margin-top:2%;font-size:clamp(7px,.8vw,12px);text-transform:uppercase;letter-spacing:.1em;color:var(--muted)}.recipe{height:70%;display:grid;grid-template-columns:1.3fr .8fr 1.3fr;align-items:center;gap:6%}.recipe ul{list-style:none;padding:0;margin:0;display:grid;gap:4%}.recipe li{padding:3% 5%;margin:2% 0;background:#fff;border:1px solid var(--line);border-radius:999px;font-weight:700;font-size:clamp(8px,1vw,15px)}.recipe>strong{background:var(--ink);color:#fff;border-radius:18px;padding:20% 8%;text-align:center;font-size:clamp(14px,1.7vw,26px)}.recipe article{background:var(--green2);border-radius:18px;padding:10%;text-align:center}.recipe article b{display:block;font-size:clamp(12px,1.45vw,22px);margin-bottom:10%}.recipe article span{font-size:clamp(8px,1vw,15px)}.cards{height:56%}.cards article{border-left-color:var(--blue)}.cards .danger{border-left-color:var(--red)}.cards .success{border-left-color:var(--green)}.explorer{display:grid;grid-template-columns:1.8fr 1fr;gap:4%;height:75%}.mini-graph{position:relative;background:var(--panel);border:1px solid var(--steel);border-radius:18px;padding:6%;display:grid;grid-template-columns:repeat(4,1fr);gap:4%}.mini-graph span{height:min-content;padding:10%;border-radius:999px;background:var(--orange);color:var(--ink);font-size:clamp(7px,.8vw,12px);text-align:center;font-weight:800}.mini-graph span:nth-child(2){background:var(--blue)}.mini-graph span:nth-child(3){background:var(--green2)}.mini-graph span:nth-child(4){background:var(--orange2)}.mini-graph i{display:block;background:var(--night);border:1px solid var(--steel);border-radius:10px}.explorer>div:last-child{display:grid;gap:6%}.explorer article{border-left:7px solid var(--green2);background:var(--panel);border-radius:14px;padding:7%}.explorer article.no{border-color:var(--red)}.explorer b{font-size:clamp(10px,1.15vw,18px)}.explorer p{font-size:clamp(8px,.95vw,15px);color:var(--muted);margin:7% 0 0}.gallery{display:flex;gap:3%;height:65%}.gallery figure{margin:0;flex:1;display:flex;flex-direction:column;min-width:0}.gallery img{width:100%;height:82%;object-fit:cover;border-radius:14px;border:1px solid var(--line)}.gallery figcaption{font-size:clamp(8px,1vw,15px);font-weight:700;margin-top:3%}.gallery figcaption b{background:var(--orange);padding:.35em .55em;border-radius:999px;margin-right:4%}.feature{display:grid;grid-template-columns:2.4fr 1fr;gap:3%;height:78%}.feature>img{width:100%;height:100%;object-fit:cover;border:1px solid var(--steel);border-radius:16px}.feature>div{display:grid;gap:4%}.feature article{background:var(--panel);border-left:7px solid var(--orange);border-radius:12px;padding:6%}.feature article:nth-child(2){border-color:var(--blue)}.feature article:nth-child(3){border-color:var(--green2)}.feature b{font-size:clamp(9px,1vw,16px)}.feature p{font-size:clamp(7px,.82vw,13px);color:var(--muted);margin:5% 0 0}.bands{display:grid;gap:6%;height:60%}.bands article{display:grid;grid-template-columns:22% 1fr;align-items:center}.bands b{padding:5%;border-radius:999px;background:var(--green2);text-align:center;font-size:clamp(8px,.9vw,14px)}.bands article:nth-child(2) b{background:var(--orange)}.bands article:nth-child(3) b{background:var(--blue)}.bands article:nth-child(4) b{background:var(--red)}.bands span{padding-left:5%;font-size:clamp(12px,1.5vw,23px);font-weight:700}.cover,.close{padding:5.5% 6%}.cover-copy{width:57%;margin-top:8%}.cover-copy>p:last-child{font-size:clamp(12px,1.5vw,23px);line-height:1.4;color:var(--fog);max-width:90%}.hero-dag{position:absolute;right:0;top:0;width:39%;height:100%;background:var(--night)}.hero-dag b{position:absolute;padding:2.5% 4%;border-radius:999px;background:var(--orange);color:var(--ink);font-size:clamp(8px,.9vw,14px)}.hero-dag .n1{left:13%;top:15%}.hero-dag .n2{left:49%;top:12%;background:var(--blue)}.hero-dag .n3{left:65%;top:31%;background:var(--green)}.hero-dag .n4{left:25%;top:44%;background:var(--orange2)}.hero-dag .n5{left:57%;top:58%;background:var(--blue)}.hero-dag .n6{left:22%;top:76%;background:var(--green2)}.close-copy{margin-top:8%;width:68%}.close h2{font-size:clamp(28px,4.2vw,64px)}.close-copy>p{font-size:clamp(13px,1.6vw,24px);line-height:1.45;color:var(--fog)}.close-copy>strong{display:block;color:var(--orange2);font-size:clamp(11px,1.3vw,20px);margin-top:3%}.close-art{position:absolute;right:8%;top:14%;width:23%;height:70%}.close-art i{display:block;width:48%;height:9%;margin:12% 0;border-radius:999px;background:var(--orange)}.close-art i:nth-child(2){margin-left:43%;background:var(--blue)}.close-art i:nth-child(3){margin-left:8%;background:var(--green2)}.close-art i:nth-child(4){margin-left:48%;background:var(--orange2)}.close-art i:nth-child(5){margin-left:18%;background:var(--green)}.controls{position:fixed;right:max(12px,env(safe-area-inset-right));bottom:max(12px,env(safe-area-inset-bottom));z-index:20;display:flex;align-items:center;gap:6px;padding:7px;background:rgba(5,8,12,.84);border:1px solid #4a535e;border-radius:999px;backdrop-filter:blur(10px)}button{appearance:none;border:0;border-radius:999px;background:#252c34;color:#fff;padding:.55em .8em;font:700 13px/1 system-ui;cursor:pointer}button:hover,button:focus-visible{background:var(--orange);color:var(--ink);outline:2px solid #fff;outline-offset:2px}.counter{min-width:52px;text-align:center;color:#fff;font:700 12px/1 monospace}.notes-panel{position:fixed;left:50%;bottom:18px;z-index:15;width:min(760px,85vw);padding:18px 22px;transform:translate(-50%,120%);opacity:0;background:rgba(16,19,23,.96);color:#fff;border:1px solid var(--steel);border-radius:16px;transition:.2s;box-shadow:0 12px 50px #0008;font:16px/1.45 system-ui}.notes-open .notes-panel{transform:translate(-50%,0);opacity:1}.help{position:fixed;left:12px;bottom:12px;z-index:20;color:#aab3bc;font:11px/1.2 system-ui}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media(max-aspect-ratio:4/3){.help{display:none}.controls{transform:scale(.88);transform-origin:right bottom}}@media(prefers-reduced-motion:reduce){.slide,.notes-panel{transition:none}}@media print{html,body{height:auto;overflow:visible;background:#fff}.deck{display:block}.slide{position:relative!important;display:block!important;opacity:1!important;visibility:visible!important;transform:none!important;width:13.333in;height:7.5in;page-break-after:always;break-after:page}.controls,.help,.notes-panel{display:none!important}@page{size:13.333in 7.5in;margin:0}}
</style></head><body><main class="deck" aria-live="polite">{{SLIDES}}</main>
<div class="help" aria-hidden="true">← → navigate · N notes · F fullscreen</div><nav class="controls" aria-label="Presentation controls"><button type="button" id="prev" aria-label="Previous slide">←</button><span class="counter" aria-live="polite">1 / 14</span><button type="button" id="next" aria-label="Next slide">→</button><button type="button" id="notes" aria-label="Toggle speaker notes">N</button><button type="button" id="fullscreen" aria-label="Toggle fullscreen">⛶</button></nav><aside class="notes-panel" aria-live="polite"></aside><p class="sr-only" id="instructions">Use left and right arrow keys to navigate. Press N for notes and F for fullscreen.</p>
<script>
(()=>{'use strict';const slides=[...document.querySelectorAll('.slide')],counter=document.querySelector('.counter'),panel=document.querySelector('.notes-panel');let current=0;function fit(){document.documentElement.style.setProperty('--deck-scale',Math.min(innerWidth/1600,innerHeight/900))}function clamp(n){return Math.max(0,Math.min(slides.length-1,n))}function show(n,{hash=true}={}){n=clamp(n);slides[current].classList.remove('active');slides[current].setAttribute('aria-hidden','true');current=n;slides[current].classList.add('active');slides[current].removeAttribute('aria-hidden');counter.textContent=`${current+1} / ${slides.length}`;panel.textContent=slides[current].querySelector('.speaker-note').textContent.trim();if(hash)history.replaceState(null,'',`#${current+1}`)}function move(delta){show(current+delta)}document.querySelector('#prev').addEventListener('click',()=>move(-1));document.querySelector('#next').addEventListener('click',()=>move(1));document.querySelector('#notes').addEventListener('click',()=>document.body.classList.toggle('notes-open'));document.querySelector('#fullscreen').addEventListener('click',()=>document.fullscreenElement?document.exitFullscreen():document.documentElement.requestFullscreen());document.addEventListener('keydown',e=>{if(['ArrowRight','PageDown',' '].includes(e.key)){e.preventDefault();move(1)}else if(['ArrowLeft','PageUp','Backspace'].includes(e.key)){e.preventDefault();move(-1)}else if(e.key==='Home')show(0);else if(e.key==='End')show(slides.length-1);else if(e.key.toLowerCase()==='n')document.body.classList.toggle('notes-open');else if(e.key.toLowerCase()==='f')document.querySelector('#fullscreen').click()});let startX=0;document.addEventListener('touchstart',e=>startX=e.changedTouches[0].clientX,{passive:true});document.addEventListener('touchend',e=>{const d=e.changedTouches[0].clientX-startX;if(Math.abs(d)>50)move(d<0?1:-1)},{passive:true});window.addEventListener('hashchange',()=>show(Number(location.hash.slice(1)||1)-1,{hash:false}));window.addEventListener('resize',fit);fit();slides.forEach((s,i)=>{if(i)s.setAttribute('aria-hidden','true')});show(Number(location.hash.slice(1)||1)-1,{hash:false});})();
</script></body></html>'''


if __name__ == "__main__":
    build()
