/**
 * Stable deck framework injected into the system prompt when the active skill
 * mode is `deck`. The whole point: stop regenerating the scale-to-fit JS, the
 * keyboard handler, the slide visibility toggle, the counter, and the print
 * rules each turn — every regeneration has subtly different bugs (focus is
 * wrong, scaling drifts inside the iframe wrapper, arrow keys swallowed).
 *
 * Two pieces ship together:
 *   - DECK_SKELETON_HTML : the literal scaffold the model copies verbatim.
 *   - DECK_FRAMEWORK_DIRECTIVE : the prompt fragment that tells the model
 *     what is fixed and what they're allowed to change.
 *
 * Pattern: 1920×1080 fixed canvas centered in the viewport via `display:grid;
 * place-items:center`, scaled with `transform: scale()` whose factor is
 * recomputed on every resize. Slides are `<section class="slide">` inside
 * the stage, only `.slide.active` is visible. Prev/next + counter live
 * OUTSIDE the scaled stage so they don't shrink with it.
 *
 * Why this pattern (not horizontal scroll-snap):
 *   - It matches what the model has the strongest prior on, so the framework
 *     gets adopted verbatim instead of being "blended" with the model's own
 *     instincts (which is what produced the drift in the first place).
 *   - 1920×1080 is the canonical slide canvas. Designs scale predictably.
 *   - Print becomes trivial: render every slide as block, page-break between.
 *
 * Drift fixes baked in:
 *   - `transform-origin: top left` and the stage is positioned by grid +
 *     place-items, so scaling never shifts content sideways inside the
 *     OD viewer's nested transform wrapper.
 *   - Capture-phase keydown on BOTH window and document so iframe focus
 *     quirks can't swallow arrow keys.
 *   - Auto-focus body on load and on every click.
 *   - localStorage position restored on load.
 *   - Print stylesheet shows every slide as a 1920×1080 page-broken block,
 *     producing a multi-page vertical PDF on Save-as-PDF.
 */
export declare const DECK_SKELETON_HTML = "<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <title><!-- SLOT: deck title --></title>\n  <style>\n    /* ===========================================================\n       Deck framework \u2014 DO NOT EDIT the rules in this <style> block.\n       Edit only inside the second <style> block below (per-deck\n       styles) and inside <section class=\"slide\"> bodies.\n\n       Contract this framework provides:\n         - 1920\u00D71080 fixed canvas, scaled to fit the viewport\n         - Only .slide.active is visible at a time\n         - Prev/next + counter rendered outside the scaled stage\n         - Keyboard (\u2190 \u2192 space PgUp PgDn Home End), click, and stored\n           position survive iframe focus quirks\n         - \"Save as PDF\" produces a multi-page vertical PDF, one slide\n           per page, by toggling every slide visible under @media print\n       =========================================================== */\n    :root {\n      /* SLOT: theme tokens \u2014 the only top-level CSS the agent edits.\n         Add or override --bg / --fg / --accent / etc. here. */\n      --bg: #ffffff;\n      --fg: #1c1b1a;\n      --muted: #6b6964;\n      --accent: #c96442;\n      --surface: #ffffff;\n      --shell: #08090d;\n    }\n    * { box-sizing: border-box; margin: 0; padding: 0; }\n    html, body {\n      width: 100%;\n      height: 100%;\n      overflow: hidden;\n      background: var(--shell);\n      color: var(--fg);\n      font: 18px/1.5 -apple-system, system-ui, sans-serif;\n      -webkit-font-smoothing: antialiased;\n      -moz-osx-font-smoothing: grayscale;\n    }\n    .deck-shell {\n      position: fixed;\n      inset: 0;\n      display: grid;\n      place-items: center;\n      overflow: hidden;\n    }\n    .deck-stage {\n      width: 1920px;\n      height: 1080px;\n      background: var(--bg);\n      position: relative;\n      transform-origin: top left;\n      box-shadow: 0 30px 80px rgba(0, 0, 0, 0.35);\n      flex-shrink: 0;\n    }\n    .slide {\n      position: absolute;\n      inset: 0;\n      display: none;\n      flex-direction: column;\n      overflow: hidden;\n    }\n    .slide.active { display: flex; }\n\n    /* Chrome \u2014 counter + prev/next live outside the scaled stage so they\n       don't shrink with it. Do not relocate them inside .deck-stage. */\n    .deck-counter {\n      position: fixed;\n      bottom: 22px;\n      left: 50%;\n      transform: translateX(-50%);\n      display: inline-flex;\n      align-items: center;\n      gap: 4px;\n      background: rgba(10, 14, 26, 0.92);\n      backdrop-filter: blur(10px);\n      -webkit-backdrop-filter: blur(10px);\n      padding: 6px;\n      border-radius: 999px;\n      border: 1px solid rgba(255, 255, 255, 0.08);\n      color: #fff;\n      font: 12px/1 ui-monospace, SFMono-Regular, Menlo, monospace;\n      letter-spacing: 0.18em;\n      z-index: 1000;\n    }\n    .deck-counter button {\n      width: 36px; height: 36px;\n      background: transparent;\n      color: #fff;\n      border: 0;\n      border-radius: 50%;\n      font-size: 18px;\n      line-height: 1;\n      cursor: pointer;\n      display: grid;\n      place-items: center;\n      transition: background 0.15s;\n    }\n    .deck-counter button:hover { background: rgba(255, 255, 255, 0.12); }\n    .deck-counter button[disabled] { opacity: 0.3; cursor: default; }\n    .deck-counter .deck-count {\n      padding: 0 14px;\n      letter-spacing: 0.22em;\n    }\n    .deck-counter .deck-count .total { color: rgba(255, 255, 255, 0.5); }\n    .deck-hint {\n      position: fixed;\n      bottom: 26px;\n      right: 28px;\n      color: rgba(255, 255, 255, 0.4);\n      font: 11px/1 ui-monospace, SFMono-Regular, Menlo, monospace;\n      letter-spacing: 0.2em;\n      text-transform: uppercase;\n      z-index: 999;\n      pointer-events: none;\n    }\n\n    /* Print / PDF stitching \u2014 every slide stacks top-to-bottom, one per\n       page. The viewer's \"Share \u2192 PDF\" relies on this; do not remove. */\n    @media print {\n      @page { size: 1920px 1080px; margin: 0; }\n      html, body {\n        width: 1920px !important;\n        height: auto !important;\n        overflow: visible !important;\n        background: #fff !important;\n      }\n      .deck-shell {\n        position: static !important;\n        display: block !important;\n        inset: auto !important;\n      }\n      .deck-stage {\n        width: 1920px !important;\n        height: auto !important;\n        transform: none !important;\n        box-shadow: none !important;\n        position: static !important;\n      }\n      .slide {\n        display: flex !important;\n        position: relative !important;\n        inset: auto !important;\n        width: 1920px !important;\n        height: 1080px !important;\n        page-break-after: always;\n        break-after: page;\n      }\n      .slide:last-child { page-break-after: auto; break-after: auto; }\n      .deck-counter, .deck-hint { display: none !important; }\n    }\n  </style>\n  <style>\n    /* SLOT: per-deck styles \u2014 typography, layout helpers, slide variants.\n       Add classes used by the slide content below, e.g. .title, .big-stat,\n       .grid-3. Do not redefine .deck-shell / .deck-stage / .slide /\n       .deck-counter / .deck-hint or anything inside @media print. */\n  </style>\n</head>\n<body>\n  <div class=\"deck-shell\">\n    <div class=\"deck-stage\" id=\"deck-stage\">\n\n      <!-- SLOT: slides \u2014 one <section class=\"slide\"> per slide. The first\n           slide must have class=\"slide active\". The framework auto-counts\n           them and toggles .active as the user navigates. -->\n\n      <section class=\"slide active\" data-screen-label=\"01 Title\">\n        <!-- SLOT: slide 1 content -->\n      </section>\n\n      <section class=\"slide\" data-screen-label=\"02\">\n        <!-- SLOT: slide 2 content -->\n      </section>\n\n      <!-- ... add as many <section class=\"slide\"> blocks as the brief asks\n           for. The first one is .active; the rest are not. -->\n\n    </div>\n  </div>\n\n  <!-- Framework chrome \u2014 DO NOT EDIT below this line. -->\n  <nav class=\"deck-counter\" role=\"navigation\" aria-label=\"Deck navigation\">\n    <button type=\"button\" id=\"deck-prev\" aria-label=\"Previous slide\">\u2039</button>\n    <span class=\"deck-count\"><span id=\"deck-cur\">01</span> <span class=\"total\">/ <span id=\"deck-total\">01</span></span></span>\n    <button type=\"button\" id=\"deck-next\" aria-label=\"Next slide\">\u203A</button>\n  </nav>\n  <div class=\"deck-hint\">\u2190 / \u2192 \u00B7 space</div>\n\n  <script>\n    (function () {\n      var stage = document.getElementById('deck-stage');\n      var slides = Array.prototype.slice.call(document.querySelectorAll('.slide'));\n      var prev = document.getElementById('deck-prev');\n      var next = document.getElementById('deck-next');\n      var cur = document.getElementById('deck-cur');\n      var total = document.getElementById('deck-total');\n      var STORE = 'deck:idx:' + (location.pathname || '/');\n      var idx = 0;\n\n      // ---- scale-to-fit ---------------------------------------------------\n      // The stage is 1920\u00D71080 and positioned by .deck-shell's\n      // `display:grid;place-items:center`. We scale via transform with\n      // transform-origin:top-left, then re-center by translating to the\n      // remainder. This survives nested transforms (e.g. when the OD viewer\n      // wraps the iframe in its own scale wrapper at zoom != 100%).\n      function fit() {\n        var sw = window.innerWidth;\n        var sh = window.innerHeight;\n        var pad = 32;\n        var s = Math.min((sw - pad) / 1920, (sh - pad) / 1080);\n        if (!isFinite(s) || s <= 0) s = 1;\n        var tx = (sw - 1920 * s) / 2;\n        var ty = (sh - 1080 * s) / 2;\n        stage.style.transform = 'translate(' + tx + 'px,' + ty + 'px) scale(' + s + ')';\n      }\n\n      // ---- navigation -----------------------------------------------------\n      function pad2(n) { return (n < 10 ? '0' : '') + n; }\n      function paint() {\n        slides.forEach(function (el, i) { el.classList.toggle('active', i === idx); });\n        if (cur) cur.textContent = pad2(idx + 1);\n        if (total) total.textContent = pad2(slides.length);\n        if (prev) prev.toggleAttribute('disabled', idx <= 0);\n        if (next) next.toggleAttribute('disabled', idx >= slides.length - 1);\n      }\n      function go(i) {\n        idx = Math.max(0, Math.min(slides.length - 1, i));\n        paint();\n        try { localStorage.setItem(STORE, String(idx)); } catch (_) {}\n      }\n      function onKey(e) {\n        var t = e.target;\n        if (t && (t.tagName === 'INPUT' || t.tagName === 'TEXTAREA' || t.isContentEditable)) return;\n        if (e.key === 'ArrowRight' || e.key === 'PageDown' || e.key === ' ') { e.preventDefault(); go(idx + 1); }\n        else if (e.key === 'ArrowLeft' || e.key === 'PageUp') { e.preventDefault(); go(idx - 1); }\n        else if (e.key === 'Home') { e.preventDefault(); go(0); }\n        else if (e.key === 'End') { e.preventDefault(); go(slides.length - 1); }\n      }\n      // Capture phase + listen on both targets \u2014 inside the OD iframe,\n      // focus may be on window OR document; a single non-capture listener\n      // silently misses presses.\n      window.addEventListener('keydown', onKey, true);\n      document.addEventListener('keydown', onKey, true);\n      if (prev) prev.addEventListener('click', function () { go(idx - 1); });\n      if (next) next.addEventListener('click', function () { go(idx + 1); });\n\n      // Auto-focus body so arrow keys work without an initial click.\n      document.body.setAttribute('tabindex', '-1');\n      document.body.style.outline = 'none';\n      function focusDeck() { try { window.focus(); document.body.focus({ preventScroll: true }); } catch (_) {} }\n      document.addEventListener('mousedown', focusDeck);\n      window.addEventListener('load', focusDeck);\n\n      // Restore last position.\n      try {\n        var saved = parseInt(localStorage.getItem(STORE) || '0', 10);\n        if (!isNaN(saved) && saved >= 0 && saved < slides.length) idx = saved;\n      } catch (_) {}\n\n      window.addEventListener('resize', fit);\n      fit();\n      paint();\n      focusDeck();\n    })();\n  </script>\n</body>\n</html>";
export declare const DECK_FRAMEWORK_DIRECTIVE = "# Slide deck \u2014 fixed framework (this is non-negotiable for deck mode)\n\nDecks regress when each turn re-authors the scale-to-fit logic, the keyboard handler, the slide visibility toggle, the counter, and the print rules. The user has hit this enough times that we now ship a **fixed framework**: 1920\u00D71080 canvas, scale-to-fit, prev/next + counter, capture-phase keyboard, click-anywhere focus, localStorage position restore, and a print stylesheet that emits a multi-page vertical PDF on Save-as-PDF \u2014 all baked in.\n\n**You do not write any of that. You do not modify any of that.** Your job is to fill content slots only.\n\n## Workflow \u2014 copy framework first, then fill content\n\nWhen the user asks for slides, your TodoWrite plan **must** start with \"copy the deck framework verbatim\" before any content step. The intended order is:\n\n```\n1.  Bind the active direction's palette + fonts to :root in the framework\n2.  Copy the canonical skeleton below as index.html (nothing else first)\n3.  Plan the slide arc and theme rhythm (state aloud before writing)\n4.  Add per-deck classes inside the second <style> block\n5.  Replace each <section class=\"slide\"> SLOT with real content\n6.  Self-check (no rewriting framework chrome / @media print / nav script)\n7.  Emit single <artifact> if a new canonical deck HTML was written this turn; otherwise summarize the edits (see \"Artifact emission is conditional\" in the discovery layer)\n```\n\nIf you find yourself writing `<style>` rules for `.deck-shell`, `.deck-stage`, `.slide`, `.canvas`, `fit()`, `@media print`, or a keyboard handler \u2014 STOP. The framework already has them. Re-read this directive, then keep going from \"fill SLOT content\".\n\n## The contract\n\nWhen you start a new deck, your output is a single HTML file built from the canonical skeleton below. **Copy the skeleton verbatim**, including its first `<style>` block, the `.deck-shell` / `.deck-stage` / `.deck-counter` / `.deck-hint` chrome, and the entire trailing `<script>`.\n\nYou may edit only inside slots marked `SLOT:`:\n- `SLOT: deck title` \u2014 the `<title>` element.\n- `SLOT: theme tokens` \u2014 the `:root` CSS custom properties (`--bg`, `--fg`, `--accent`, `--shell`, \u2026). Add new tokens here if needed.\n- `SLOT: per-deck styles` \u2014 the second `<style>` block. Define classes used by your slide content (e.g. `.title`, `.big-stat`, `.grid-3`, custom typography). **Never redefine** `.deck-shell`, `.deck-stage`, `.slide`, `.deck-counter`, `.deck-hint`, or anything inside `@media print`.\n- `SLOT: slides` \u2014 the `<section class=\"slide\">` blocks. Add as many as the brief calls for. The first slide MUST be `<section class=\"slide active\" \u2026>`; the rest are `<section class=\"slide\" \u2026>` (no `active`). The script auto-counts them.\n- `SLOT: slide N content` \u2014 content inside each `<section>`.\n\n## Common drift modes \u2014 DO NOT DO THESE\n\nThese are the failure patterns we just spent days debugging. Each one looks \"equivalent\" but breaks something specific:\n\n- \u274C Don't write your own `fit()` function or `transform: scale()` script. The framework already does it, and ad-hoc versions drift inside the OD viewer's nested transform wrapper.\n- \u274C Don't use `transform-origin: center center` on the stage. The framework uses `top left` plus an explicit translate so scaled content lands at the same place every render.\n- \u274C Don't use `document.addEventListener('keydown', \u2026)` alone. Inside an iframe, focus is sometimes on window. The framework adds capture-phase listeners on **both** targets \u2014 replacing this with a single listener silently swallows arrow keys.\n- \u274C Don't replace the localStorage key, the slide-visibility toggle (`.slide.active`), or the counter element IDs (`#deck-cur`, `#deck-total`, `#deck-prev`, `#deck-next`). The framework reads them by ID.\n- \u274C Don't put the prev/next buttons or the counter **inside** `.deck-stage`. They must live outside the scaled element so they stay legible at any viewport size.\n- \u274C Don't redefine `.slide { display: ... }` in your per-deck styles. The framework uses `display: none` / `display: flex` to toggle slides; overriding it breaks navigation.\n- \u274C Don't strip or \"tidy\" the `@media print` block. It is how Share \u2192 PDF stitches every slide into a multi-page document. Without it, PDF export collapses to a single screenshot.\n\n## Why this matters (so you can judge edge cases)\n\nThe framework is a contract with the host viewer. The OD iframe sits inside a transformed wrapper (the zoom control); the keyboard handler needs capture phase + dual targets; \"Share \u2192 PDF\" reads the print stylesheet; the position survives reloads via localStorage. If a turn rewrites any of these \u2014 even with \"equivalent\" code \u2014 the next turn diverges, and three turns in the deck has subtly broken nav and a one-page PDF. Treat the framework as load-bearing infrastructure.\n\nIf the user asks for something the framework genuinely doesn't support (vertical decks, custom slide transitions, multi-column simultaneous slides), say so and ask before forking. **Default answer: keep the framework, change the slide content.**\n\n## Each slide\n\nEach `<section class=\"slide\" data-screen-label=\"NN Title\">` is one slide rendered onto the 1920\u00D71080 canvas. Inside the section, lay out content with your own `SLOT: per-deck styles` classes. Slide labels are 1-indexed (`01 Title`, `02 Problem`\u2026). The first slide gets `class=\"slide active\"`; the others just `class=\"slide\"`.\n\nReal copy only \u2014 no lorem ipsum, no invented metrics, no generic emoji icon rows. If you don't have a value, leave a short honest placeholder.\n\n## Canonical skeleton (this is exactly what the file you write looks like)\n\n```html\n<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <title><!-- SLOT: deck title --></title>\n  <style>\n    /* ===========================================================\n       Deck framework \u2014 DO NOT EDIT the rules in this <style> block.\n       Edit only inside the second <style> block below (per-deck\n       styles) and inside <section class=\"slide\"> bodies.\n\n       Contract this framework provides:\n         - 1920\u00D71080 fixed canvas, scaled to fit the viewport\n         - Only .slide.active is visible at a time\n         - Prev/next + counter rendered outside the scaled stage\n         - Keyboard (\u2190 \u2192 space PgUp PgDn Home End), click, and stored\n           position survive iframe focus quirks\n         - \"Save as PDF\" produces a multi-page vertical PDF, one slide\n           per page, by toggling every slide visible under @media print\n       =========================================================== */\n    :root {\n      /* SLOT: theme tokens \u2014 the only top-level CSS the agent edits.\n         Add or override --bg / --fg / --accent / etc. here. */\n      --bg: #ffffff;\n      --fg: #1c1b1a;\n      --muted: #6b6964;\n      --accent: #c96442;\n      --surface: #ffffff;\n      --shell: #08090d;\n    }\n    * { box-sizing: border-box; margin: 0; padding: 0; }\n    html, body {\n      width: 100%;\n      height: 100%;\n      overflow: hidden;\n      background: var(--shell);\n      color: var(--fg);\n      font: 18px/1.5 -apple-system, system-ui, sans-serif;\n      -webkit-font-smoothing: antialiased;\n      -moz-osx-font-smoothing: grayscale;\n    }\n    .deck-shell {\n      position: fixed;\n      inset: 0;\n      display: grid;\n      place-items: center;\n      overflow: hidden;\n    }\n    .deck-stage {\n      width: 1920px;\n      height: 1080px;\n      background: var(--bg);\n      position: relative;\n      transform-origin: top left;\n      box-shadow: 0 30px 80px rgba(0, 0, 0, 0.35);\n      flex-shrink: 0;\n    }\n    .slide {\n      position: absolute;\n      inset: 0;\n      display: none;\n      flex-direction: column;\n      overflow: hidden;\n    }\n    .slide.active { display: flex; }\n\n    /* Chrome \u2014 counter + prev/next live outside the scaled stage so they\n       don't shrink with it. Do not relocate them inside .deck-stage. */\n    .deck-counter {\n      position: fixed;\n      bottom: 22px;\n      left: 50%;\n      transform: translateX(-50%);\n      display: inline-flex;\n      align-items: center;\n      gap: 4px;\n      background: rgba(10, 14, 26, 0.92);\n      backdrop-filter: blur(10px);\n      -webkit-backdrop-filter: blur(10px);\n      padding: 6px;\n      border-radius: 999px;\n      border: 1px solid rgba(255, 255, 255, 0.08);\n      color: #fff;\n      font: 12px/1 ui-monospace, SFMono-Regular, Menlo, monospace;\n      letter-spacing: 0.18em;\n      z-index: 1000;\n    }\n    .deck-counter button {\n      width: 36px; height: 36px;\n      background: transparent;\n      color: #fff;\n      border: 0;\n      border-radius: 50%;\n      font-size: 18px;\n      line-height: 1;\n      cursor: pointer;\n      display: grid;\n      place-items: center;\n      transition: background 0.15s;\n    }\n    .deck-counter button:hover { background: rgba(255, 255, 255, 0.12); }\n    .deck-counter button[disabled] { opacity: 0.3; cursor: default; }\n    .deck-counter .deck-count {\n      padding: 0 14px;\n      letter-spacing: 0.22em;\n    }\n    .deck-counter .deck-count .total { color: rgba(255, 255, 255, 0.5); }\n    .deck-hint {\n      position: fixed;\n      bottom: 26px;\n      right: 28px;\n      color: rgba(255, 255, 255, 0.4);\n      font: 11px/1 ui-monospace, SFMono-Regular, Menlo, monospace;\n      letter-spacing: 0.2em;\n      text-transform: uppercase;\n      z-index: 999;\n      pointer-events: none;\n    }\n\n    /* Print / PDF stitching \u2014 every slide stacks top-to-bottom, one per\n       page. The viewer's \"Share \u2192 PDF\" relies on this; do not remove. */\n    @media print {\n      @page { size: 1920px 1080px; margin: 0; }\n      html, body {\n        width: 1920px !important;\n        height: auto !important;\n        overflow: visible !important;\n        background: #fff !important;\n      }\n      .deck-shell {\n        position: static !important;\n        display: block !important;\n        inset: auto !important;\n      }\n      .deck-stage {\n        width: 1920px !important;\n        height: auto !important;\n        transform: none !important;\n        box-shadow: none !important;\n        position: static !important;\n      }\n      .slide {\n        display: flex !important;\n        position: relative !important;\n        inset: auto !important;\n        width: 1920px !important;\n        height: 1080px !important;\n        page-break-after: always;\n        break-after: page;\n      }\n      .slide:last-child { page-break-after: auto; break-after: auto; }\n      .deck-counter, .deck-hint { display: none !important; }\n    }\n  </style>\n  <style>\n    /* SLOT: per-deck styles \u2014 typography, layout helpers, slide variants.\n       Add classes used by the slide content below, e.g. .title, .big-stat,\n       .grid-3. Do not redefine .deck-shell / .deck-stage / .slide /\n       .deck-counter / .deck-hint or anything inside @media print. */\n  </style>\n</head>\n<body>\n  <div class=\"deck-shell\">\n    <div class=\"deck-stage\" id=\"deck-stage\">\n\n      <!-- SLOT: slides \u2014 one <section class=\"slide\"> per slide. The first\n           slide must have class=\"slide active\". The framework auto-counts\n           them and toggles .active as the user navigates. -->\n\n      <section class=\"slide active\" data-screen-label=\"01 Title\">\n        <!-- SLOT: slide 1 content -->\n      </section>\n\n      <section class=\"slide\" data-screen-label=\"02\">\n        <!-- SLOT: slide 2 content -->\n      </section>\n\n      <!-- ... add as many <section class=\"slide\"> blocks as the brief asks\n           for. The first one is .active; the rest are not. -->\n\n    </div>\n  </div>\n\n  <!-- Framework chrome \u2014 DO NOT EDIT below this line. -->\n  <nav class=\"deck-counter\" role=\"navigation\" aria-label=\"Deck navigation\">\n    <button type=\"button\" id=\"deck-prev\" aria-label=\"Previous slide\">\u2039</button>\n    <span class=\"deck-count\"><span id=\"deck-cur\">01</span> <span class=\"total\">/ <span id=\"deck-total\">01</span></span></span>\n    <button type=\"button\" id=\"deck-next\" aria-label=\"Next slide\">\u203A</button>\n  </nav>\n  <div class=\"deck-hint\">\u2190 / \u2192 \u00B7 space</div>\n\n  <script>\n    (function () {\n      var stage = document.getElementById('deck-stage');\n      var slides = Array.prototype.slice.call(document.querySelectorAll('.slide'));\n      var prev = document.getElementById('deck-prev');\n      var next = document.getElementById('deck-next');\n      var cur = document.getElementById('deck-cur');\n      var total = document.getElementById('deck-total');\n      var STORE = 'deck:idx:' + (location.pathname || '/');\n      var idx = 0;\n\n      // ---- scale-to-fit ---------------------------------------------------\n      // The stage is 1920\u00D71080 and positioned by .deck-shell's\n      // `display:grid;place-items:center`. We scale via transform with\n      // transform-origin:top-left, then re-center by translating to the\n      // remainder. This survives nested transforms (e.g. when the OD viewer\n      // wraps the iframe in its own scale wrapper at zoom != 100%).\n      function fit() {\n        var sw = window.innerWidth;\n        var sh = window.innerHeight;\n        var pad = 32;\n        var s = Math.min((sw - pad) / 1920, (sh - pad) / 1080);\n        if (!isFinite(s) || s <= 0) s = 1;\n        var tx = (sw - 1920 * s) / 2;\n        var ty = (sh - 1080 * s) / 2;\n        stage.style.transform = 'translate(' + tx + 'px,' + ty + 'px) scale(' + s + ')';\n      }\n\n      // ---- navigation -----------------------------------------------------\n      function pad2(n) { return (n < 10 ? '0' : '') + n; }\n      function paint() {\n        slides.forEach(function (el, i) { el.classList.toggle('active', i === idx); });\n        if (cur) cur.textContent = pad2(idx + 1);\n        if (total) total.textContent = pad2(slides.length);\n        if (prev) prev.toggleAttribute('disabled', idx <= 0);\n        if (next) next.toggleAttribute('disabled', idx >= slides.length - 1);\n      }\n      function go(i) {\n        idx = Math.max(0, Math.min(slides.length - 1, i));\n        paint();\n        try { localStorage.setItem(STORE, String(idx)); } catch (_) {}\n      }\n      function onKey(e) {\n        var t = e.target;\n        if (t && (t.tagName === 'INPUT' || t.tagName === 'TEXTAREA' || t.isContentEditable)) return;\n        if (e.key === 'ArrowRight' || e.key === 'PageDown' || e.key === ' ') { e.preventDefault(); go(idx + 1); }\n        else if (e.key === 'ArrowLeft' || e.key === 'PageUp') { e.preventDefault(); go(idx - 1); }\n        else if (e.key === 'Home') { e.preventDefault(); go(0); }\n        else if (e.key === 'End') { e.preventDefault(); go(slides.length - 1); }\n      }\n      // Capture phase + listen on both targets \u2014 inside the OD iframe,\n      // focus may be on window OR document; a single non-capture listener\n      // silently misses presses.\n      window.addEventListener('keydown', onKey, true);\n      document.addEventListener('keydown', onKey, true);\n      if (prev) prev.addEventListener('click', function () { go(idx - 1); });\n      if (next) next.addEventListener('click', function () { go(idx + 1); });\n\n      // Auto-focus body so arrow keys work without an initial click.\n      document.body.setAttribute('tabindex', '-1');\n      document.body.style.outline = 'none';\n      function focusDeck() { try { window.focus(); document.body.focus({ preventScroll: true }); } catch (_) {} }\n      document.addEventListener('mousedown', focusDeck);\n      window.addEventListener('load', focusDeck);\n\n      // Restore last position.\n      try {\n        var saved = parseInt(localStorage.getItem(STORE) || '0', 10);\n        if (!isNaN(saved) && saved >= 0 && saved < slides.length) idx = saved;\n      } catch (_) {}\n\n      window.addEventListener('resize', fit);\n      fit();\n      paint();\n      focusDeck();\n    })();\n  </script>\n</body>\n</html>\n```\n\nWhen the brief is \"make me a deck\", your output is this skeleton with theme tokens tuned, per-deck classes added, and `<section class=\"slide\">` blocks filled in \u2014 nothing more, nothing less. Skill-specific guidance (typography, theme presets, layout vocabulary) layers *on top of* this framework, not in place of it.\n";
