// Build the deck's reading surface: two views over ONE DOM.
//
// slider — one slide at a time, arrows / Space / index. The default (decided 2026-07-14).
// read — every slide stacked as a card. Ctrl+F works, text is selectable, the page
// prints, a screen reader walks it.
//
// Both views share the same nodes: the capture already gives one .print-slide-container
// per slide, which is the structural equivalent of the old carousel's . Every slide
// is ALWAYS in the DOM (so it is always indexable); the mode only changes what the reader
// reaches with Ctrl+F — 2.1k words stacked, ~30 in slider. That is the price of the
// default, and it is stated rather than buried.
export function buildBody(deckHtml, { id, count, W, H, t }) {
let n = 0
let body = deckHtml.replace(/
`
})
// Each .print-slide-container is a top-level sibling, so the figure closes right before
// the next one opens, and once at the end.
const parts = body.split(' ('').join('')
if (n !== count) throw new Error(`envolví ${n} slides pero la captura contó ${count}`)
return { html: chrome(body, { n, t }), css: css(W, H), js: js(W, H), slides: n }
}
// TWO layers, deliberately.
//
// .deck-view — the site's UI around the deck: bar, index, switcher, backdrop. It
// belongs to the PAGE, so it inherits the page's colours and follows the
// site's theme.
// .deck-read — the boundary. It wraps ONLY the captured DOM, and carries `dark`
// because the deck's own world is dark.
//
// Nesting the chrome inside .deck-read (as this first did) makes it inherit the DECK's
// palette — near-white text — while it is painted on the SITE's background: an index
// nobody can read on a light page. The boundary wraps what was captured, never the
// interface we build around it.
const chrome = (body, { n, t }) => `
1 / ${n}
${body}
`
const css = (W, H) => `
.deck-slides { display: flex; flex-direction: column; gap: 1.5rem; }
.deck-slide {
container-type: inline-size;
position: relative; width: 100%;
/* NOT aspect-ratio: 980/552. Slidev's frame is 552px tall and 12 of this deck's 16 slides
hold MORE than that — up to 672px — so a rigid 16:9 box silently cuts the bottom off
three quarters of the deck. Slidev clips them too; nobody noticed because until now the
slides were PNGs of themselves. A reading surface may not lose content: the card is as
tall as the slide's real content, measured (--deck-h) and scaled (--deck-k). */
height: calc(var(--deck-h, ${H}) * var(--deck-k, 1) * 1px);
overflow: hidden; border-radius: .75rem;
box-shadow: 0 1px 3px rgba(0,0,0,.25), 0 8px 24px rgba(0,0,0,.18);
}
/* The card is dark because THE DECK is dark, and not by accident: its source declares
colorSchema:dark, so Slidev never compiles a light palette at all. A light/dark toggle
here was tried and reverted — removing the .dark class turned the card white while the
deck's text stayed rgb(232,232,232): light on white, unreadable. Slidev's 37 .dark rules
exist in the bundle, but they are not what makes THIS deck dark; the theme's base colours
are, unconditionally. And the slides hard-code absolute utilities (text-gray-400,
bg-gray-900) that would not flip with a theme anyway. A light deck means re-authoring the
decks, not toggling a class. The chrome around it still follows the SITE's theme. */
.deck-slide { background: #0b0b0b; border: 1px solid rgba(255,255,255,.10); }
/* The slide is a , and the site's .prose gives every figure margin: 2em 0. The card
is exempt from the boundary guard on purpose (deck- classes are ours), so that margin lands
on it — and on the zoom modal it pushed the fixed element 32px down, past the bottom of the
viewport on a large screen. Specificity (0,2,0) to beat .prose figure (0,1,1). */
.deck-view .deck-slide { margin: 0; }
.deck-slide::after { color: rgba(255,255,255,.35); background: rgba(0,0,0,.35); }
/* Slidev hard-codes 980x552 inline. The slide has to be SCALED to its box, or the
content is simply clipped: on a 390px phone the box is 328px wide while the content
stays 980px — two thirds of every slide cropped away, with no error anywhere.
NOT scale(calc(100cqw / 980)): scale() demands a , and calc() cannot divide a
length by a length, so that declaration is silently DROPPED. It merely looks right
while the column happens to measure ~980px. The ratio must be computed (ResizeObserver)
and published as a custom property.
Bound to [data-js] for (0,4,0): Slidev's own