/* The template gallery at /editor/templates - EditorTemplates.vue.
 *
 * WHAT THE PAGE IS (owner decision F7): all NINETEEN slide layouts and all five
 * skins, drawn at TRUE slide scale from `src/data/slideTemplates.ts`, beside the
 * machine-readable definition Claude Code writes against, so the two are
 * provably one artefact. Read-only in the browser. (The eight `tier: 'extended'`
 * templates are real and shipped; `slide-templates.md` documents eleven and is
 * stale by the other eight. Tier orders this page; it never gates it.)
 *
 * ── WHICH STYLESHEETS DRAW A SLIDE HERE, AND WHY
 *
 * The template VOCABULARY is not in this file and must never be copied into it.
 * It comes from `public/css/deck-slide-templates.css`, which this repo already
 * carries and already ships in the public bundle for the student's copy of the
 * deck, and which is a mirror of the authoritative
 * `class-app/public/css/slide-templates.css`. A second 66 KB copy would be a
 * second thing to drift, and that mirror has already drifted three times -
 * `tests/editorTemplatesCssMirror.spec.ts` now pins it. Reaching across into
 * `class-app/public/` at runtime is not an option either: that is a separate fly
 * app and this one does not serve its assets.
 *
 * What is NOT mirrored, and therefore is ported below, is the projector CHROME
 * from `class-app/public/css/slides.css`: the slide box, its title, its body and
 * the `[data-step]` reveal. That file is deliberately not mirrored because none
 * of it belongs on a page a student reads in a column - but a gallery that draws
 * a slide at true scale needs exactly the box the projector uses. About sixty
 * lines of it are reproduced here VERBATIM, and the same spec pins every
 * declaration against the class-app file so this port cannot drift either.
 *
 * The `/editor` shell links the public bundle and then the admin bundle
 * (scripts/bundle-css.mjs, ADMIN_SHELL_HEAD), so both halves are present in
 * production exactly as they are in development.
 *
 * ── THE TWO THINGS THAT MAKE THIS HARD
 *
 * 1. `cqw` RESOLVES AGAINST THE NEAREST `container-type` ANCESTOR. A slide is a
 *    fixed 1920x1080 box carrying `container-type: inline-size`, and every rule
 *    in the vocabulary sizes itself in cqw against it (1cqw = 19.2px). Let a
 *    slide fill a 480px card instead and every size re-bases silently: the card
 *    looks plausible and is wrong at every width, which is the exact failure the
 *    template system exists to prevent. So `.edt-canvas__inner` is literally
 *    1920x1080, carries the ONLY `container-type` on this page, and is
 *    transform-scaled to fit. Never add `container-type` to a card, a grid or
 *    the page body.
 *
 * 2. THE PORT MUST NOT OUTWEIGH THE VOCABULARY. The admin bundle loads AFTER the
 *    public one, so a ported `.slide { background: ... }` written normally would
 *    beat `.slide--display:has(.tpl--dark)` from the mirror at equal specificity
 *    and quietly kill every skin. Every ported rule is therefore wrapped in
 *    `:where(.edt-canvas__inner)`, which contributes ZERO specificity: the
 *    selectors keep the exact weight they have in the room, and the scoping also
 *    keeps them off the student deck in development, where index.html links
 *    every stylesheet on every page.
 *
 * `.slide__body` keeps `overflow-y: auto` here, exactly as on the projector.
 * That is what makes an over-budget slide invisible on a screen with no
 * scrollbar, and this gallery must reproduce it rather than paper over it: a
 * sample that scrolls here is a sample that is over budget in the room.
 *
 * Read public/css/admin-editor.css first - it declares the `--edt-*` tokens this
 * file uses, establishes the LTR island and owns the scroll container
 * (`.edt-body`).
 *
 * The `admin-editor` filename prefix is load-bearing: scripts/bundle-css.mjs
 * partitions the public and admin CSS bundles on `/css/admin` and nothing else,
 * so any other name ships this file to every marketing visitor.
 */

.edt-templates {
  max-width: 2200px;
  margin-inline: auto;
}

/* ══════════════════════════════════════════════════════════════════════════
   1. THE CANVAS

   `.edt-canvas` is the visible frame; `.edt-canvas__inner` is the slide's real
   coordinate system, always 1920x1080, scaled by a factor SlideCanvas.vue
   measures. CSS cannot divide a measured parent width by 1920 and hand back a
   unitless number, which is why that one value is a computed `:style` binding.

   `transform-origin: top left` is PHYSICAL on purpose. The inner element is
   `dir="rtl"`, and in an RTL box the logical start edge is the right one -
   anchoring the scale there would push the canvas off its own frame. This is a
   coordinate system, not a text flow, and class-app/public/css/app.css says the
   same thing about `.cl-stage__canvas` for the same reason.
   ══════════════════════════════════════════════════════════════════════════ */

.edt-canvas {
  position: relative;
  inline-size: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 10px;
  background: #ffffff;
  box-shadow: inset 0 0 0 1px var(--edt-line);
}

.edt-canvas__inner {
  position: absolute;
  top: 0;
  left: 0;
  inline-size: 1920px;
  block-size: 1080px;
  transform-origin: top left;
  /* THE only container-type on this page. See the header. */
  container-type: inline-size;

  /* The RTL island. `dir="rtl"` on the element drives bidi and `:dir()`; these
     two declarations stop `.edt-shell`'s `direction: ltr` / `text-align: left`
     leaking in by inheritance. Nothing English is ever placed inside here. */
  direction: rtl;
  text-align: start;
}

/* ══════════════════════════════════════════════════════════════════════════
   2. THE SLIDE BOX - a VERBATIM port of class-app/public/css/slides.css.

   Do not edit a value here to change how a slide looks. Change it in the room's
   own stylesheet; tests/editorTemplatesCssMirror.spec.ts fails when the two
   disagree. Every selector is wrapped in `:where(.edt-canvas__inner)`, which
   adds no specificity, so each keeps the exact weight it has in the room.
   ══════════════════════════════════════════════════════════════════════════ */

:where(.edt-canvas__inner) .slide {
  position: relative;
  block-size: 100%;
  display: flex;
  flex-direction: column;
  gap: 2cqw;
  background: var(--bg-surface);
  color: var(--text-color);
  overflow: hidden;
}

:where(.edt-canvas__inner) .slide--display {
  padding: 6cqw 7cqw;
  justify-content: center;
}

:where(.edt-canvas__inner) .slide__title {
  font-family: var(--font-display);
  font-size: clamp(26px, 4.2cqw, 84px);
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--text-color);
  text-align: center;
  text-wrap: balance;
}

/* `overflow-y: auto` is kept, not removed. See the header: it is what makes an
   over-budget slide invisible on a projector, and a gallery that hid it would be
   telling the owner a slide fits when it does not. */
:where(.edt-canvas__inner) .slide__body {
  font-size: clamp(15px, 2cqw, 40px);
  line-height: 1.6;
  color: var(--text-secondary);
  overflow-y: auto;
}

:where(.edt-canvas__inner) .slide__body p + p {
  margin-block-start: 0.8em;
}

:where(.edt-canvas__inner) .slide__body ul,
:where(.edt-canvas__inner) .slide__body ol {
  /* RTL list indentation is padding-RIGHT, per the repo convention. */
  padding-right: 1.1em;
  display: flex;
  flex-direction: column;
  gap: 0.4em;
}

:where(.edt-canvas__inner) .slide__body strong {
  font-weight: 500;
  color: var(--text-color);
}

:where(.edt-canvas__inner) .slide__body code,
:where(.edt-canvas__inner) .slide__body pre {
  font-family: var(--font-mono);
  font-size: 0.9em;
  direction: ltr;
  unicode-bidi: isolate;
}

:where(.edt-canvas__inner) .slide__body pre {
  display: block;
  padding: 0.8em 1em;
  background: var(--bg-secondary);
  border-radius: var(--radius-md);
  overflow-x: auto;
  text-align: left;
}

:where(.edt-canvas__inner) .slide__body a {
  color: var(--primary-color);
}

/* ── The build-step reveal ────────────────────────────────────────────────
   THE DEFAULT IS VISIBLE AND THE RULES HIDE. A missing step class shows too
   much, which a lecturer can talk over; the inverse paints a blank projector.

   Every selector below is exactly `.slide--step-N [data-step="M"]` - one class
   plus one attribute, identical weight throughout, and `:where()` keeps it that
   way. Never add a rule at a different weight touching opacity, transform or
   visibility on a `[data-step]` element: an uneven cascade here hides a line
   with no error and no symptom until the moment it should have appeared. */

:where(.edt-canvas__inner) .slide [data-step] {
  transition:
    opacity 0.25s ease,
    transform 0.25s ease;
}

:where(.edt-canvas__inner) .slide--step-0 [data-step='1'],
:where(.edt-canvas__inner) .slide--step-0 [data-step='2'],
:where(.edt-canvas__inner) .slide--step-0 [data-step='3'],
:where(.edt-canvas__inner) .slide--step-0 [data-step='4'],
:where(.edt-canvas__inner) .slide--step-0 [data-step='5'],
:where(.edt-canvas__inner) .slide--step-0 [data-step='6'],
:where(.edt-canvas__inner) .slide--step-0 [data-step='7'],
:where(.edt-canvas__inner) .slide--step-1 [data-step='2'],
:where(.edt-canvas__inner) .slide--step-1 [data-step='3'],
:where(.edt-canvas__inner) .slide--step-1 [data-step='4'],
:where(.edt-canvas__inner) .slide--step-1 [data-step='5'],
:where(.edt-canvas__inner) .slide--step-1 [data-step='6'],
:where(.edt-canvas__inner) .slide--step-1 [data-step='7'],
:where(.edt-canvas__inner) .slide--step-2 [data-step='3'],
:where(.edt-canvas__inner) .slide--step-2 [data-step='4'],
:where(.edt-canvas__inner) .slide--step-2 [data-step='5'],
:where(.edt-canvas__inner) .slide--step-2 [data-step='6'],
:where(.edt-canvas__inner) .slide--step-2 [data-step='7'],
:where(.edt-canvas__inner) .slide--step-3 [data-step='4'],
:where(.edt-canvas__inner) .slide--step-3 [data-step='5'],
:where(.edt-canvas__inner) .slide--step-3 [data-step='6'],
:where(.edt-canvas__inner) .slide--step-3 [data-step='7'],
:where(.edt-canvas__inner) .slide--step-4 [data-step='5'],
:where(.edt-canvas__inner) .slide--step-4 [data-step='6'],
:where(.edt-canvas__inner) .slide--step-4 [data-step='7'],
:where(.edt-canvas__inner) .slide--step-5 [data-step='6'],
:where(.edt-canvas__inner) .slide--step-5 [data-step='7'],
:where(.edt-canvas__inner) .slide--step-6 [data-step='7'] {
  opacity: 0;
  transform: translateY(0.6cqw);
  /* Not display:none - the reveal must not reflow the lines already on screen. */
  pointer-events: none;
}

/* ══════════════════════════════════════════════════════════════════════════
   3. THE PAGE AROUND THE SLIDES - English, LTR, Glass Campus.
   ══════════════════════════════════════════════════════════════════════════ */

.edt-tpl-head {
  margin-bottom: 2rem;
}

.edt-tpl-head__lede {
  max-width: 74ch;
  margin: 0 0 1.25rem;
  color: var(--edt-ink-2);
  font-size: 0.95rem;
  line-height: 1.6;
}

/* The read-only claim, made once and made prominent. F7 is not a preference:
   templates change through Claude Code and never through this screen, and a
   staff member who cannot tell has to guess. */
.edt-readonly {
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
  max-width: 90ch;
  padding: 0.9rem 1rem;
  border-radius: 10px;
  background: var(--edt-surface-solid);
  box-shadow: inset 0 0 0 1px var(--edt-line);
  color: var(--edt-ink-2);
  font-size: 0.86rem;
  line-height: 1.6;
}

.edt-readonly i {
  color: var(--edt-accent);
  margin-top: 0.15rem;
}

.edt-readonly p {
  margin: 0;
}

.edt-readonly .edt-readonly__title {
  margin: 0 0 0.15rem;
  font-weight: 600;
  color: var(--edt-ink);
}

.edt-tally {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 1rem 0 0;
}

.edt-tally__item {
  padding: 0.5rem 0.85rem;
  border-radius: 8px;
  background: var(--edt-glass-strong);
  box-shadow: inset 0 0 0 1px var(--edt-line);
}

.edt-tally dt {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--edt-ink-3);
}

/* Solid ink, never the brand ramp: the house rule forbids the gradient through
   letterforms at weight 500 and above, numerals included. */
.edt-tally dd {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--edt-ink);
}

.edt-caveats {
  max-width: 88ch;
  margin: 1rem 0 0;
  padding: 0 0 0 1.1rem;
  color: var(--edt-ink-2);
  font-size: 0.84rem;
  line-height: 1.65;
}

.edt-caveats li + li {
  margin-top: 0.35rem;
}

/* ── Sections ─────────────────────────────────────────────────────────────
   The 3-stop brand ramp on a 2px bar: a hairline is the one place the house
   rules allow it. Never on a fill, never through a letterform. */
.edt-sec {
  margin: 2.5rem 0 0;
  padding-top: 1.5rem;
  border-top: 1px solid var(--edt-line);
}

.edt-sec__title {
  position: relative;
  margin: 0 0 0.5rem;
  padding-bottom: 0.5rem;
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--edt-ink);
}

.edt-sec__title::after {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  bottom: 0;
  inline-size: 72px;
  block-size: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, #0894ff 0%, #bd32d6 50%, #ffa304 100%);
}

.edt-sec__lede {
  max-width: 86ch;
  margin: 0 0 1rem;
  color: var(--edt-ink-2);
  font-size: 0.88rem;
  line-height: 1.65;
}

.edt-sec__lede--warn {
  padding: 0.75rem 0.9rem;
  border-radius: 8px;
  background: rgba(255, 163, 4, 0.08);
  box-shadow: inset 0 0 0 1px rgba(255, 163, 4, 0.28);
  color: var(--edt-ink);
}

.edt-sub {
  margin: 1.75rem 0 0.6rem;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--edt-ink);
}

/* ── One template card ───────────────────────────────────────────────────── */

.edt-tpl-list {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.edt-tpl {
  padding: 1.1rem 1.2rem 1.2rem;
  border-radius: 12px;
  background: var(--edt-glass);
  -webkit-backdrop-filter: var(--edt-glass-blur);
  backdrop-filter: var(--edt-glass-blur);
  box-shadow:
    inset 0 0 0 1px var(--edt-line),
    var(--edt-glass-shadow);
}

.edt-tpl__head {
  margin-bottom: 0.9rem;
}

.edt-tpl__name {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0 0 0.25rem;
  font-size: 1rem;
  font-weight: 600;
  color: var(--edt-ink);
}

.edt-tpl__class {
  padding: 0.1rem 0.4rem;
  border-radius: 4px;
  background: rgba(0, 113, 227, 0.07);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--edt-accent-ink);
}

.edt-tpl__purpose {
  max-width: 90ch;
  margin: 0 0 0.5rem;
  color: var(--edt-ink-2);
  font-size: 0.86rem;
  line-height: 1.55;
}

.edt-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.edt-chip {
  padding: 0.2rem 0.5rem;
  border-radius: 5px;
  background: var(--edt-surface-solid);
  box-shadow: inset 0 0 0 1px var(--edt-line);
  font-size: 0.72rem;
  color: var(--edt-ink-3);
}

/* An inert root class is a trap, not a footnote: `tpl--terminal` and
   `tpl--table` match no rule, so the next person to grep for one, find nothing
   and tidy it away would silently unstyle every such slide in the deck. */
.edt-chip--warn {
  max-width: 62ch;
  background: rgba(255, 163, 4, 0.1);
  box-shadow: inset 0 0 0 1px rgba(255, 163, 4, 0.35);
  color: #8a5200;
  line-height: 1.5;
}

.edt-chip--warn i {
  margin-inline-end: 0.3rem;
}

.edt-chip code {
  font-family: var(--font-mono);
  font-size: 0.95em;
}

/* Render left, definition right. Below 1100px they stack: a definition list
   squeezed beside a slide is unreadable, and a slide squeezed beside a
   definition list is useless. */
.edt-tpl__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: 1.25rem;
  align-items: start;
}

.edt-tpl__render,
.edt-tpl__def {
  min-width: 0;
}

.edt-tpl__def {
  font-size: 0.82rem;
  line-height: 1.55;
  color: var(--edt-ink-2);
}

.edt-def__h {
  margin: 1rem 0 0.4rem;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--edt-ink-3);
}

.edt-def__h:first-child {
  margin-top: 0;
}

/* ── Slots and shared parts ───────────────────────────────────────────────
   A stacked list, never a table. A slot has eight facts and this panel is half
   a card wide; declared column widths past the available width give every other
   column a width of 0 and the row stacks unscrolled, which is the failure mode
   the repo has already met once. */
.edt-slots,
.edt-parts {
  margin: 0;
  padding: 0;
  list-style: none;
}

.edt-slot,
.edt-part {
  padding: 0.5rem 0;
  border-top: 1px solid var(--edt-line);
}

.edt-slot:first-child,
.edt-part:first-child {
  padding-top: 0;
  border-top: none;
}

.edt-slot__head,
.edt-part__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem;
  margin: 0;
}

.edt-slot__key {
  font-weight: 600;
  color: var(--edt-ink);
}

.edt-slot__class,
.edt-part__head code {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--edt-accent-ink);
}

.edt-slot__opt {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--edt-ink-3);
}

.edt-slot__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0.15rem 0 0;
  font-size: 0.72rem;
  color: var(--edt-ink-3);
}

.edt-slot__el,
.edt-part__el {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--edt-ink-3);
}

.edt-slot__kind {
  padding: 0 0.35rem;
  border-radius: 4px;
  background: rgba(25, 26, 35, 0.05);
  font-size: 0.72rem;
  color: var(--edt-ink-3);
}

.edt-slot__extra {
  margin: 0.15rem 0 0;
  font-size: 0.72rem;
  color: var(--edt-ink-3);
}

.edt-slot__extra code {
  margin-inline-end: 0.3rem;
  font-family: var(--font-mono);
}

.edt-slot__note {
  margin: 0.25rem 0 0;
  font-size: 0.78rem;
  color: var(--edt-ink-2);
}

.edt-cap {
  margin: 0;
  color: var(--edt-ink);
}

.edt-cap__src {
  margin: 0.2rem 0 0;
  font-size: 0.72rem;
  color: var(--edt-ink-3);
}

.edt-cap__opts {
  margin: 0.35rem 0 0;
  padding-left: 1.1rem;
  font-size: 0.78rem;
  color: var(--edt-ink-3);
}

/* ── Rules and their severity ─────────────────────────────────────────────
   `error` breaks the slide, `warning` makes it worse. That distinction is a
   field of the artefact, so it is drawn rather than described. */
.edt-rules {
  margin: 0;
  padding: 0;
  list-style: none;
}

.edt-rule {
  display: flex;
  gap: 0.55rem;
  align-items: flex-start;
  max-width: 100ch;
  padding: 0.4rem 0;
  font-size: 0.8rem;
  line-height: 1.55;
  color: var(--edt-ink-2);
}

.edt-rule + .edt-rule {
  border-top: 1px solid var(--edt-line);
}

.edt-rule--standalone {
  margin-top: 0.75rem;
  padding: 0.6rem 0.75rem;
  border-radius: 8px;
  background: rgba(214, 45, 45, 0.05);
  box-shadow: inset 0 0 0 1px rgba(214, 45, 45, 0.2);
}

.edt-sev {
  flex: 0 0 auto;
  margin-top: 0.1rem;
  padding: 0.05rem 0.4rem;
  border-radius: 4px;
  font-size: 0.62rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
}

.edt-sev--error {
  background: rgba(214, 45, 45, 0.1);
  color: #a51f1f;
}

.edt-sev--warning {
  background: rgba(255, 163, 4, 0.14);
  color: #8a5200;
}

.edt-notes {
  margin: 0;
  padding-left: 1.1rem;
  font-size: 0.8rem;
  line-height: 1.55;
}

/* ── Build-step controls ──────────────────────────────────────────────────
   A VIEW control, not an edit affordance: it changes which step you are looking
   at and writes nothing. `data-view-control` in the markup is what lets the
   read-only spec tell the two apart. */
.edt-steps {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin-top: 0.6rem;
}

.edt-steps__label {
  margin-inline-end: 0.2rem;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--edt-ink-3);
}

.edt-steps__btn {
  min-inline-size: 26px;
  padding: 0.15rem 0.45rem;
  border: none;
  border-radius: 5px;
  background: var(--edt-surface-solid);
  box-shadow: inset 0 0 0 1px var(--edt-line);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--edt-ink-2);
  cursor: pointer;
}

.edt-steps__btn.is-on {
  background: var(--edt-accent);
  box-shadow: none;
  color: #ffffff;
}

.edt-steps__btn:focus-visible {
  outline: 2px solid var(--edt-accent);
  outline-offset: 2px;
}

/* A sample pointing at something this site does not host, or carrying a token
   the room would draw differently. Named, never hidden: a broken <img> paints
   empty and the slide renders on, which is exactly how the mascot mirror stayed
   broken for students. */
.edt-imgwarn {
  margin: 0.6rem 0 0;
  padding: 0.5rem 0.7rem;
  border-radius: 8px;
  background: rgba(255, 163, 4, 0.1);
  box-shadow: inset 0 0 0 1px rgba(255, 163, 4, 0.32);
  font-size: 0.75rem;
  line-height: 1.55;
  color: #7a4a00;
  overflow-wrap: anywhere;
}

.edt-imgwarn i {
  margin-inline-end: 0.35rem;
}

.edt-imgwarn code {
  display: inline-block;
  margin: 0 0.15rem;
  font-family: var(--font-mono);
  font-size: 0.95em;
}

/* ── Skins ────────────────────────────────────────────────────────────────── */

.edt-skins {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(383px, 1fr));
  gap: 1.25rem;
}

.edt-skin {
  padding: 1rem;
  border-radius: 12px;
  background: var(--edt-glass);
  -webkit-backdrop-filter: var(--edt-glass-blur);
  backdrop-filter: var(--edt-glass-blur);
  box-shadow:
    inset 0 0 0 1px var(--edt-line),
    var(--edt-glass-shadow);
}

.edt-skin__head {
  margin-bottom: 0.7rem;
}

.edt-skin__name {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin: 0 0 0.25rem;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--edt-ink);
}

.edt-skin__name code {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--edt-accent-ink);
}

.edt-skin__none {
  font-size: 0.7rem;
  font-weight: 400;
  color: var(--edt-ink-3);
}

.edt-skin__purpose {
  margin: 0;
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--edt-ink-2);
}

.edt-skin__ground {
  margin: 0.15rem 0 0;
  font-size: 0.74rem;
  line-height: 1.5;
  color: var(--edt-ink-3);
}

.edt-skin .edt-canvas {
  margin-top: 0.2rem;
}

/* A reserved skin, and the mascot-surface constraint that rides with it. That
   constraint is a machine field on the skin (`requiresMascotSurface`), not a
   footnote, so it is drawn as a constraint. */
.edt-reserved {
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
  margin-top: 0.75rem;
  padding: 0.6rem 0.75rem;
  border-radius: 8px;
  background: rgba(214, 45, 45, 0.05);
  box-shadow: inset 0 0 0 1px rgba(214, 45, 45, 0.22);
  font-size: 0.78rem;
  line-height: 1.55;
  color: var(--edt-ink-2);
}

.edt-reserved i {
  margin-top: 0.15rem;
  color: #a51f1f;
}

.edt-reserved p {
  margin: 0;
}

.edt-reserved .edt-reserved__title {
  margin: 0 0 0.2rem;
  font-weight: 600;
  color: var(--edt-ink);
}

.edt-reserved code {
  margin: 0 0.1rem;
  font-family: var(--font-mono);
  font-size: 0.95em;
  overflow-wrap: anywhere;
}

/* ── Density ──────────────────────────────────────────────────────────────── */

.edt-density {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 1rem;
}

.edt-density__name {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin: 0 0 0.4rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--edt-ink);
}

.edt-density__name code {
  font-family: var(--font-mono);
  font-weight: 400;
  color: var(--edt-accent-ink);
}

.edt-density__scale {
  font-size: 0.72rem;
  font-weight: 400;
  color: var(--edt-ink-3);
}

.edt-mods {
  max-width: 100ch;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.8rem;
  line-height: 1.55;
  color: var(--edt-ink-2);
}

.edt-mods li {
  padding: 0.4rem 0;
  border-top: 1px solid var(--edt-line);
}

.edt-mods li:first-child {
  border-top: none;
}

.edt-mods code {
  margin-inline-end: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--edt-accent-ink);
}

.edt-mods strong {
  margin-inline-end: 0.4rem;
  font-weight: 600;
  color: var(--edt-ink);
}

.edt-ladder {
  max-width: 100ch;
  margin: 0;
  padding: 0;
  list-style: none;
}

.edt-ladder li {
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
  padding: 0.4rem 0;
  font-size: 0.8rem;
  line-height: 1.55;
  color: var(--edt-ink-2);
}

.edt-ladder__n {
  flex: 0 0 auto;
  inline-size: 20px;
  block-size: 20px;
  border-radius: 50%;
  background: var(--edt-surface-solid);
  box-shadow: inset 0 0 0 1px var(--edt-line);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  line-height: 20px;
  text-align: center;
  color: var(--edt-ink-2);
}

/* ── The build-step demo ──────────────────────────────────────────────────── */

.edt-stepdemo {
  max-width: 720px;
  margin-bottom: 1.25rem;
}

.edt-stepdemo .edt-steps {
  margin: 0 0 0.6rem;
}

.edt-stepdemo__note {
  margin: 0.5rem 0 0;
  font-size: 0.75rem;
  color: var(--edt-ink-3);
}

.edt-stepdemo__note code,
.edt-sec__lede code,
.edt-tpl-foot code,
.edt-readonly code,
.edt-caveats code {
  font-family: var(--font-mono);
  font-size: 0.92em;
  color: var(--edt-accent-ink);
  overflow-wrap: anywhere;
}

/* ── Shared parts ─────────────────────────────────────────────────────────── */

.edt-parts {
  max-width: 110ch;
  font-size: 0.82rem;
  color: var(--edt-ink-2);
}

.edt-part__purpose {
  margin: 0.2rem 0 0;
  line-height: 1.55;
}

.edt-part__seen {
  margin: 0.25rem 0 0;
  font-size: 0.72rem;
  color: var(--edt-ink-3);
}

.edt-part__seen span {
  font-family: var(--font-mono);
}

/* ── Mascot poses ─────────────────────────────────────────────────────────── */

.edt-poses {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(117px, 1fr));
  gap: 0.6rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.edt-pose {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
  padding: 0.6rem 0.35rem;
  border-radius: 9px;
  background: var(--edt-surface-solid);
  box-shadow: inset 0 0 0 1px var(--edt-line);
  text-align: center;
}

.edt-pose__img {
  inline-size: 61px;
  block-size: 61px;
  object-fit: contain;
}

.edt-pose__missing {
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: 61px;
  block-size: 61px;
  border-radius: 6px;
  background: rgba(25, 26, 35, 0.05);
  font-size: 0.6rem;
  line-height: 1.2;
  color: var(--edt-ink-3);
}

.edt-pose__id {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--edt-ink-2);
  overflow-wrap: anywhere;
}

.edt-pose__meaning {
  font-size: 0.64rem;
  color: var(--edt-ink-3);
}

.edt-pose__warn {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  color: #8a5200;
}

/* The Claude Code surface, drawn rather than described: a pose with no -dark
   file paints nothing here, which is exactly what it does on a slide. */
.edt-poses--dark .edt-pose {
  background: #0b0c12;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
}

.edt-poses--dark .edt-pose__id {
  color: rgba(255, 255, 255, 0.72);
}

.edt-poses--dark .edt-pose__missing {
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.5);
}

.edt-tpl-foot {
  margin: 2.5rem 0 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--edt-line);
  font-size: 0.78rem;
  color: var(--edt-ink-3);
}

.edt-tpl-foot p {
  margin: 0;
}

/* ══════════════════════════════════════════════════════════════════════════
   4. NARROWER SCREENS

   The repo's two breakpoints. A phone never reaches this page - EditorShell
   renders the "open this on a computer" notice instead of the body on every
   route but the session list (F9) - so the rules below are the tablet's
   portrait edge, not a phone layout.
   ══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 1100px) {
  /* Below this the definition panel is narrower than its own slot names. */
  .edt-tpl__grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 1024px) {
  .edt-skins,
  .edt-density {
    grid-template-columns: minmax(0, 1fr);
  }

  .edt-poses {
    grid-template-columns: repeat(auto-fill, minmax(99px, 1fr));
  }
}

@media (prefers-reduced-motion: reduce) {
  :where(.edt-canvas__inner) .slide [data-step] {
    transition: none;
  }
}
