/* AETHER HYDRO — pitch deck.
   Loaded only on /deck, after style.css and pages.css. It borrows the site's
   tokens and adds a fixed 16:9 stage; it never redefines a colour.

   SCALING, WITHOUT SCRIPT
   The rest of the site is fluid; a deck is not. Each slide is a 16:9 stage
   sized to whatever the viewport can give it, and the stage's font-size is
   set to 1% of its own width. Everything inside is then expressed in em, so
   one rule scales the whole deck from a phone to a projector with no JS and
   no resize listener. 1em = one percent of the slide's width. */

.deck{
  height:100svh;overflow-y:auto;overflow-x:hidden;
  scroll-snap-type:y mandatory;scroll-behavior:smooth;
  background:var(--abyss-3)}
@media (prefers-reduced-motion:reduce){.deck{scroll-behavior:auto}}

.slide{height:100svh;width:100%;display:grid;place-items:center;
  scroll-snap-align:start;scroll-snap-stop:always;position:relative}

/* The stage box, named so the fixed rail and counter can sit inside it
   rather than out in the letterbox gutter. */
:root{--stage-w:min(100vw, 177.7778svh);--stage-h:min(56.25vw, 100svh)}
.stage{position:relative;overflow:hidden;
  width:var(--stage-w);height:var(--stage-h);
  font-size:calc(var(--stage-w) / 100);
  padding:7em 7em;display:flex;flex-direction:column;justify-content:center;
  background:var(--abyss);color:var(--surface)}

/* --- depth: the deck descends, then surfaces for the close --------------- */
.stage--air{background:var(--surface);color:var(--abyss)}
.stage--shallow{background:var(--abyss)}
.stage--mid{background:var(--abyss-2)}
.stage--deep{background:var(--abyss-3)}

/* The site's own gear tessellation, sized to the stage so it holds at any
   projection size. Outlined gears at 7.5%, the same as THE SYSTEM. */
.stage--pattern::before{content:"";position:absolute;inset:0;z-index:0;
  pointer-events:none;opacity:.075;
  background-image:var(--gear-tile);background-repeat:repeat;
  background-size:20em 20em;
  -webkit-mask-image:linear-gradient(180deg,transparent,#000 16%,#000 78%,transparent);
  mask-image:linear-gradient(180deg,transparent,#000 16%,#000 78%,transparent)}
/* Cyan strokes carry further on mineral than on abyss. */
.stage--air.stage--pattern::before{opacity:.085}
.stage > *{position:relative;z-index:1}

/* The surface, carried across the deck at the depth transitions. */
.stage--wave::after{content:"";position:absolute;left:0;right:0;top:0;
  height:4em;z-index:0;pointer-events:none;
  background:var(--wave) center bottom/100% 100% no-repeat}

/* --- type ---------------------------------------------------------------- */
.s-kicker{font-family:"Chivo Mono",monospace;font-size:1.15em;
  letter-spacing:.2em;text-transform:uppercase;color:var(--flow);
  line-height:1.5}
.stage--air .s-kicker{color:var(--flow-deep)}
.s-h{font-weight:900;text-transform:uppercase;letter-spacing:-.03em;
  line-height:.92;font-size:5.4em;margin-top:.35em;max-width:16ch}
/* 6.3em, not 7.6: the closing slide's longest word is INFRASTRUCTURE. at
   fifteen characters, which cannot wrap and overflowed the stage. Sized so
   the longest single word in the deck still fits the measure. */
.s-h--big{font-size:6.3em;max-width:15ch;line-height:.9}
.s-lead{font-size:1.9em;font-weight:500;line-height:1.5;max-width:44ch;
  margin-top:1em;opacity:.86}
.s-body{font-size:1.5em;font-weight:500;line-height:1.6;max-width:52ch;
  margin-top:.9em;opacity:.8}
.s-body strong,.s-lead strong{font-weight:900;opacity:1}
.s-fig{font-weight:900;font-size:4.6em;line-height:1;letter-spacing:-.03em;
  white-space:nowrap}
.s-fig--sm{font-size:3.2em}
.s-unit{font-size:1.3em;font-weight:500;line-height:1.45;margin-top:.7em;
  opacity:.78}
.s-rule{height:1px;background:var(--rule-d);margin:2.2em 0}
.stage--air .s-rule{background:var(--rule-l)}

/* --- layouts: no two consecutive slides share one ------------------------ */
.s-mid{justify-content:center}

.s-split{display:grid;grid-template-columns:1.05fr 1fr;gap:5em;
  align-items:start;margin-top:2em}
.s-split--wide{grid-template-columns:1fr 1.35fr}

.s-grid{display:grid;gap:2.6em;margin-top:2.4em}
.s-grid--2{grid-template-columns:repeat(2,1fr)}
.s-grid--3{grid-template-columns:repeat(3,1fr)}
.s-grid--4{grid-template-columns:repeat(4,1fr)}
.s-cell{border-top:2px solid var(--flow);padding-top:1.2em}
.stage--air .s-cell{border-top-color:var(--flow-deep)}
.s-cell__k{font-family:"Chivo Mono",monospace;font-size:1em;letter-spacing:.18em;
  text-transform:uppercase;color:var(--flow);line-height:1.5}
.stage--air .s-cell__k{color:var(--flow-deep)}
.s-cell__h{font-weight:900;text-transform:uppercase;font-size:1.85em;
  line-height:1.1;margin-top:.5em;letter-spacing:-.01em}
.s-cell__b{font-size:1.35em;font-weight:500;line-height:1.55;margin-top:.55em;
  opacity:.8}

/* rows — the site's .tbl at deck scale */
.s-rows{margin-top:2em;border-top:1px solid var(--rule-d)}
.s-row{display:grid;grid-template-columns:14em 1fr;gap:2em;
  padding:1.05em 0;border-bottom:1px solid var(--rule-d);align-items:baseline}
.s-row__k{font-family:"Chivo Mono",monospace;font-size:1.05em;
  letter-spacing:.14em;text-transform:uppercase;color:var(--flow)}
.s-row__v{font-size:1.45em;font-weight:500;opacity:.84;line-height:1.5}

/* a real table, for the five-year model */
.s-table{width:100%;border-collapse:collapse;margin-top:2em;font-size:1.35em}
.s-table th,.s-table td{padding:.72em .5em;text-align:right;
  border-bottom:1px solid var(--rule-d)}
.s-table th:first-child,.s-table td:first-child{text-align:left}
.s-table thead th{font-family:"Chivo Mono",monospace;font-size:.72em;
  letter-spacing:.16em;text-transform:uppercase;color:var(--flow);
  font-weight:500;border-bottom-color:var(--flow)}
.s-table tbody th{font-weight:500;opacity:.8}
.s-table td{font-weight:500;opacity:.86;font-variant-numeric:tabular-nums}
.s-table .is-total th,.s-table .is-total td{font-weight:900;opacity:1;
  border-bottom-color:var(--flow)}

/* the route, reused as a phase spine */
.s-route{display:grid;grid-template-columns:repeat(4,1fr);gap:2.2em;
  margin-top:3em;position:relative}
.s-route::before{content:"";position:absolute;left:0;right:0;top:.55em;
  height:1px;background:var(--rule-d)}
.s-stop{position:relative;padding-top:2.4em}
.s-stop::before{content:"";position:absolute;left:0;top:0;
  width:1.15em;height:1.15em;border-radius:50%;
  background:var(--abyss);border:2px solid var(--flow)}
.s-stop--on::before{background:var(--flow)}


/* --- progress ------------------------------------------------------------ */
/* --- where you are ------------------------------------------------------
   The rail is a map: one mark per slide, grouped into the four acts, with
   the current slide drawn long and lit. Dots at half a vh were too small to
   locate yourself by, which is the whole job of the thing. */
.deck__rail{position:fixed;top:50%;translate:0 -50%;z-index:40;
  right:calc(50vw - var(--stage-w) / 2 + var(--stage-h) * .022);
  display:flex;flex-direction:column;align-items:flex-end;
  gap:calc(var(--stage-h) * .011)}
.deck__pip{width:calc(var(--stage-h) * .018);height:calc(var(--stage-h) * .003);
  border-radius:1px;background:var(--surface);
  opacity:.28;transition:opacity .3s var(--ease),background .3s var(--ease),
    width .3s var(--ease)}
/* An act divider opens a group. */
.deck__pip--act{margin-top:calc(var(--stage-h) * .022)}
.deck__pip--act:first-child{margin-top:0}
.deck__pip.is-here{opacity:1;background:var(--flow);
  width:calc(var(--stage-h) * .046)}

/* The count and the section, in one place, low in the corner. */
.deck__where{position:fixed;z-index:40;
  right:calc(50vw - var(--stage-w) / 2 + var(--stage-h) * .055);
  bottom:calc(50svh - var(--stage-h) / 2 + var(--stage-h) * .05);
  display:flex;flex-direction:column;align-items:flex-end;
  gap:calc(var(--stage-h) * .012);
  font-family:"Chivo Mono",monospace;line-height:1;text-align:right;
  pointer-events:none}
.deck__where__n{font-size:calc(var(--stage-h) * .026);letter-spacing:.12em;
  color:var(--surface);opacity:.6}
.deck__where__n b{font-weight:700;color:var(--flow);opacity:1}
.deck__where__n i{font-style:normal;margin:0 .4em;opacity:.5}
.deck__where__t{font-size:calc(var(--stage-h) * .019);letter-spacing:.22em;
  text-transform:uppercase;color:var(--surface);opacity:.55;max-width:34vh}
/* On a light slide both the rail and the count need the darker ink.
   Set from script: .deck__where is not a sibling of .slide, so there is no
   selector that reaches it from the active slide. */
html.deck-light .deck__where__n,
html.deck-light .deck__where__t{color:var(--abyss)}
html.deck-light .deck__pip{background:var(--abyss);opacity:.3}
html.deck-light .deck__pip.is-here{background:var(--flow-deep);opacity:1}
html.deck-light .deck__where__n b{color:var(--flow-deep)}
html:not(.js) .deck__where{display:none}
@media (prefers-reduced-motion:reduce){.deck__pip{transition:none}}

/* --- motion: slow water, never slide-ins --------------------------------- */
@media (prefers-reduced-motion:no-preference){
  .stage--wave::after{animation:deck-drift 26s linear infinite}
  @keyframes deck-drift{from{background-position-x:0}
                        to{background-position-x:-100%}}
  html.js .stage > *:not(.t-mark):not(.fx){opacity:0;transform:translate3d(0,1.1em,0);
    transition:opacity .7s var(--ease),transform .7s var(--ease)}
  html.js .slide.is-here .stage > *:not(.t-mark):not(.fx){opacity:1;transform:none}
  html.js .slide.is-here .stage > *:nth-child(2){transition-delay:.07s}
  html.js .slide.is-here .stage > *:nth-child(3){transition-delay:.14s}
  html.js .slide.is-here .stage > *:nth-child(4){transition-delay:.21s}
}
/* Without the observer nothing is ever marked is-here, so the armed state
   must never apply. Same trap as the site's [data-reveal]. */
html:not(.js) .stage > *:not(.t-mark):not(.fx){opacity:1;transform:none}

/* --- print: the deck is also the PDF ------------------------------------- */
/* Explicit dimensions and an orientation keyword cannot be combined - 'size:
   1600px 900px landscape' was invalid, so the declaration was dropped and
   every slide printed onto Letter portrait, cropped on both sides.

   Inches, not px: given a px page size Chrome wrote a point-based MediaBox and
   then laid the page out in CSS px against it, so the stage came out at about
   three quarters size, centred, on a field of white. 13.333in x 7.5in is the
   standard 16:9 slide, and the stage below is pinned to exactly that. */
@page{size:13.333in 7.5in;margin:0}
@media print{
  .deck{height:auto;overflow:visible;scroll-snap-type:none;background:none}
  .deck__rail,.deck__skip{display:none}
  .slide{display:block;width:100vw;height:100vh;margin:0;padding:0;
    break-after:page;page-break-after:always}
  .slide:last-child{break-after:auto;page-break-after:auto}
  /* The stage is driven by --stage-w / --stage-h, and so are the rail and the
     counter. Overriding width on .stage alone left font-size still deriving
     from the screen variable, so the whole slide came out at about three
     quarters scale in the corner.

     Absolute units did not help either - 'in' on the element and 'in' on
     @page did not land on the same box. Deriving from the page itself does:
     @page is already 16:9, so 100vw x 100vh fills it exactly by
     construction, and font-size stays 1% of the width so every em holds. */
  :root{--stage-w:100vw;--stage-h:100vh}
  .stage{width:var(--stage-w);height:var(--stage-h);margin:0}
  .stage > *:not(.t-mark):not(.fx){opacity:1!important;transform:none!important}
  *{animation:none!important;transition:none!important}
  .deck__where{display:none}

  /* The deck is dark. Chrome leaves 'Background graphics' off by default, so
     without this every slide prints as white paper with white type on it -
     fine in headless, invisible from the print dialog. */
  html,body,.deck,.slide,.stage,.stage *,.tided__layer{
    -webkit-print-color-adjust:exact;print-color-adjust:exact}
}


/* =====================================================================
   THE TIDE, ON A DECK
   The site paints a copy of the content in submerged colours and clips it to
   whatever sits below the surface. That idea ports; its DOM-clone does not —
   the deck is a scroll-snap container, not the document. So a tided slide is
   two stacked layers of identical content, one in air and one submerged, and
   the sea layer is masked by the wave tile itself. Moving the mask
   horizontally moves the surface across the frame, and because the mask is the
   real wave the cut is genuinely wavy rather than a flat line with a wave
   drawn on it.
   ===================================================================== */
.tided{position:relative;isolation:isolate;
  /* On the parent, not on the sea layer: the surface is the sea's SIBLING, so
     anything declared there is invisible to it and the meniscus drifted to the
     top of the frame. Both read these. */
  --tide-w:150em;                 /* one wave tile wide, in stage units */
  /* The stage is 56.25em tall and the surface rests at 26em, so ~31em of fill
     is all that is ever visible. At 300em the mask rasterised to roughly
     4,000px every frame and a 1s timer took 1.5s to fire. The wave's position
     inside the tile is proportional, so shrinking it changes nothing but cost. */
  --tide-h:90em;
  --tide-at:26em;                 /* where the surface rests, from the top */
  /* Two offsets, because the two tiles carry the wave at different heights.
     The mask tile (--wave-mask-mid) has it dead centre, so the band extends
     45em either side of the waterline and both its edges fall outside the
     56.25em stage. The line tile is short and carries the wave at 62.4% of
     its height. Its wave is centred at 52.382% of that tile, not 50%: the
     path runs 17.76 to 57.67 inside a 72-unit box, and the midpoint of that
     is not the middle of the box. Using 0.0375 assumed it was, which put the
     meniscus 0.546em - about 8px - above the water it is supposed to trace.
     0.06 * 0.523819 = 0.0314292. */
  --tide-mask-y:calc(var(--tide-at) - var(--tide-h) * 0.5);
  --tide-line:calc(var(--tide-at) - var(--tide-h) * 0.0314292)}
.tided__layer{position:absolute;inset:0;display:flex;flex-direction:column;
  padding:inherit}
.tided__air{background:var(--surface);color:var(--abyss)}
/* mask-repeat is repeat-x, so the tile forms one horizontal band and its top
   edge is a hard boundary that Chrome rasterises with a row of partial alpha -
   a faint straight line across the frame, above the wave. It used to be
   clipped away, but the clip sat only 0.7em below the seam and the wave crest
   rises into that band, so it was shaving the crest as well.
   --wave-mask-mid carries the wave at the centre of the tile instead, which
   puts the band's edges 45em from the waterline: both outside the stage. No
   seam to hide, and nothing clipped. */
.tided__sea{background:var(--abyss);color:var(--surface);
  -webkit-mask-image:var(--wave-mask-mid);mask-image:var(--wave-mask-mid);
  -webkit-mask-size:var(--tide-w) var(--tide-h);
  mask-size:var(--tide-w) var(--tide-h);
  -webkit-mask-repeat:repeat-x;mask-repeat:repeat-x;
  -webkit-mask-position:0 var(--tide-mask-y);
  mask-position:0 var(--tide-mask-y)}
@media (prefers-reduced-motion:no-preference){
  .tided__sea{animation:tide-run 22s linear infinite}
}
@keyframes tide-run{
  from{-webkit-mask-position:0 var(--tide-mask-y);
       mask-position:0 var(--tide-mask-y)}
  to{-webkit-mask-position:var(--tide-w) var(--tide-mask-y);
     mask-position:var(--tide-w) var(--tide-mask-y)}
}
/* THE SURFACE ITSELF.
   A bare mask edge is just a shape change; the homepage's waterline has a
   meniscus, a crest and a lift in the water just under it. --wave-line is the
   same path as the mask, stroked, so tracing it puts the line exactly on the
   cut - and because the line tile is 72 tall where the mask tile is 1200, it
   only has to be sized to the same 6% ratio and given the same position to
   stay locked to it at any width. */
.tided__surface{position:absolute;inset:0;z-index:2;pointer-events:none;
  background-image:var(--wave-line);
  background-size:var(--tide-w) calc(var(--tide-h) * 0.06);
  background-repeat:repeat-x;
  background-position:0 var(--tide-line)}
/* No drop-shadow here: two of them on a full-stage element whose background
   position animates every frame pegged the renderer hard enough that the tab
   stopped responding. The glow comes from the lift underneath instead, which
   costs nothing to composite. */

/* Light carried just under the surface, inside the water. The sea layer is
   already masked, so this can run the full height and only the submerged part
   of it survives. */
/* The ramp is long on purpose. This gradient is a straight horizontal band,
   but the surface it lights is a wave that swings 1.5em either side of
   --tide-at. With a short ramp its brightest row read as a second, straight
   waterline sitting next to the real one - two lines that would not line up,
   because only one of them was a wave. Over six em the variation across a
   crest is a change in brightness rather than an edge. */
.tided__sea::before{content:"";position:absolute;inset:0;z-index:0;
  pointer-events:none;
  background:linear-gradient(to bottom,
    transparent calc(var(--tide-at) - 6em),
    rgba(0,216,224,.10) calc(var(--tide-at) - 1em),
    rgba(0,216,224,.16) calc(var(--tide-at) + 2.5em),
    rgba(0,216,224,.06) calc(var(--tide-at) + 9em),
    transparent calc(var(--tide-at) + 18em))}

@media (prefers-reduced-motion:no-preference){
  .tided__surface{animation:tide-run-line 22s linear infinite}
}
@keyframes tide-run-line{
  from{background-position:0 var(--tide-line)}
  to{background-position:var(--tide-w) var(--tide-line)}
}

/* The accent is legal on abyss, so it only lives in the sea layer. */
.tided__sea .t-accent{color:var(--flow)}
.tided__air .t-accent{color:var(--flow-deep)}

/* --- title slide --------------------------------------------------------- */
/* The mark at scale, cropped by the frame, with the surface running through
   it. It is a closed loop, which is the whole argument, so it gets to be the
   composition rather than a watermark in a corner. */
.stage.tided{padding:0}
.stage.tided .tided__layer{padding:7em}
.t-mark{position:absolute;z-index:0;pointer-events:none;
  left:50%;top:44%;width:132em;height:auto;
  transform:translate(-50%,-50%) rotate(-8deg)}
.tided__air .t-mark{color:var(--abyss);opacity:.13}
.tided__sea .t-mark{color:var(--flow);opacity:.34}
.t-title__body{position:relative;z-index:1;margin-top:auto;
  display:flex;flex-direction:column}
.t-logo{width:38em;height:auto;display:block}
.tided__air .t-logo .lg-ink{fill:var(--abyss)}
.tided__air .t-logo .lg-accent{fill:var(--flow-deep)}
.tided__sea .t-logo .lg-ink{fill:var(--surface)}
.tided__sea .t-logo .lg-accent{fill:var(--flow)}
.t-title__k{font-family:"Chivo Mono",monospace;font-size:1.35em;
  letter-spacing:.22em;text-transform:uppercase;line-height:1.5;
  margin-top:2.4em}
.t-title__meta{display:flex;gap:3em;margin-top:1.1em;
  font-family:"Chivo Mono",monospace;font-size:1.15em;letter-spacing:.2em;
  text-transform:uppercase;opacity:.8}

/* --- the loop as the deck's section device -------------------------------
   One mark partial, three contexts. On the title it is the composition; on
   an act divider it frames the act; on a content slide it is a watermark
   bleeding off the corner. Sizing and colour are contextual so the SVG
   itself is never duplicated with a second class. */

/* Act dividers. The loop sits fully inside the frame - no crop - and the
   act title lands on its crossing point. */
.s-act{align-items:center;justify-content:center;text-align:center}
/* The stage is exactly 100em wide and the mark's aspect (3657.4 x 2116.6)
   puts an 80em mark at 46.3em tall, so it centres on plain offsets - no
   percentage transform to resolve. It sits fully inside the frame: uncropped,
   which is the point of using it as the act device. */
.s-act .t-mark{left:10em;top:calc(50% - 23.15em);width:80em;
  transform:none;color:var(--flow);opacity:.12}
.stage--air .s-act .t-mark,.s-act.stage--air .t-mark{color:var(--flow-deep);opacity:.16}
.s-act__n{position:relative;z-index:1;font-family:"Chivo Mono",monospace;
  font-size:1.3em;letter-spacing:.42em;text-transform:uppercase;
  color:var(--flow);line-height:1.5}
.s-act__h{position:relative;z-index:1;font-weight:900;text-transform:uppercase;
  font-size:5.8em;line-height:.92;letter-spacing:-.03em;
  margin-top:.22em;max-width:17ch}
.s-act__b{position:relative;z-index:1;font-size:1.6em;font-weight:500;
  line-height:1.55;max-width:44ch;margin-top:1.15em;opacity:.82}

/* Content slides: the loop recurs quietly, off the bottom-right corner.
   Faded radially so the bleed reads as a fade, not a crop. */
.stage--loop .t-mark{left:auto;top:auto;right:-15em;bottom:-12em;
  width:64em;transform:none;color:var(--flow);opacity:.1;
  -webkit-mask-image:radial-gradient(closest-side,#000 42%,transparent 97%);
  mask-image:radial-gradient(closest-side,#000 42%,transparent 97%)}
.stage--air.stage--loop .t-mark{color:var(--flow-deep);opacity:.14}

/* --- the wire: dated headlines ------------------------------------------
   The "why now" argument is that these are news items, not projections, so
   the slide is shaped like a wire feed rather than another cell grid. */
.s-wire{margin-top:1.5em;display:flex;flex-direction:column}
.s-wire__i{display:grid;grid-template-columns:9.5em 1fr;gap:2.4em;
  padding:1.05em 0;border-top:1px solid var(--rule-d);align-items:baseline}
.s-wire__i:last-child{border-bottom:1px solid var(--rule-d)}
.s-wire__d{font-family:"Chivo Mono",monospace;font-size:1.1em;
  letter-spacing:.16em;text-transform:uppercase;color:var(--flow);
  line-height:1.6}
.s-wire__t{font-size:1.5em;font-weight:700;line-height:1.35}
.s-wire__s{font-size:1.1em;font-weight:500;line-height:1.5;
  opacity:.62;margin-top:.35em}
.stage--air .s-wire__d{color:var(--flow-deep)}
.stage--air .s-wire__i{border-color:var(--rule-l)}

/* A heading that yields the slide to what sits under it. */
.s-h--sm{font-size:3.6em;max-width:26ch}

/* Two figures reading down a column rather than squeezed side by side in
   half a split. Each one gets the column's full measure. */
.s-stack{display:flex;flex-direction:column;gap:1.7em}


/* =====================================================================
   ATMOSPHERE
   One decorative layer per slide - .fx, a direct child of .stage, excluded
   from the reveal machinery for the same reason .t-mark is. Everything is
   in em so it holds at any projection size; every animation moves only
   transform or opacity; nothing repaints a large tile per frame (the title
   tide remains the only thing in the deck that does). One-shot devices are
   keyed to .is-here so they play when the slide arrives rather than all at
   once on load, and resolve to their finished state without JS.
   ===================================================================== */
.fx{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden}

/* A droplet field, used as a mask by the glass devices. One tile, ten beads. */
.fx{--drops:
    radial-gradient(circle at 12% 18%, #000 0 .40em, transparent .46em),
    radial-gradient(circle at 63% 9%,  #000 0 .24em, transparent .29em),
    radial-gradient(circle at 86% 31%, #000 0 .52em, transparent .58em),
    radial-gradient(circle at 34% 41%, #000 0 .30em, transparent .35em),
    radial-gradient(circle at 8%  62%, #000 0 .44em, transparent .50em),
    radial-gradient(circle at 52% 71%, #000 0 .22em, transparent .27em),
    radial-gradient(circle at 77% 83%, #000 0 .36em, transparent .42em),
    radial-gradient(circle at 26% 88%, #000 0 .48em, transparent .54em),
    radial-gradient(circle at 95% 57%, #000 0 .28em, transparent .33em),
    radial-gradient(circle at 44% 26%, #000 0 .18em, transparent .23em)}

/* --- 04 why-now: rain on the glass ------------------------------------
   A drop on glass is not a bright dot - a bright core on a dark ground is
   a star, and a long fading tail behind it is a meteor. It is a lens: dark
   body, bright rim where the edge refracts, and a small specular highlight
   on the upper shoulder. The ones that let go leave a short wet track, not
   a streak. */
.fx--rain{--bead:radial-gradient(circle at 36% 29%,
    rgba(233,242,241,.50) 0 5%,
    rgba(150,205,215,.16) 16%,
    rgba(3,28,40,.60) 50%,
    rgba(0,216,224,.30) 80%,
    rgba(0,216,224,.10) 92%,
    transparent 96%)}
.fx__bead{position:absolute;background:var(--bead);
  border-radius:50% 50% 52% 48%/48% 52% 50% 50%}
/* Head, and the track it wets on the way down. */
.fx__drip{position:absolute;top:-4em;width:.8em;height:1em;
  border-radius:50% 50% 50% 50%/62% 62% 38% 38%;
  background:var(--bead);background-size:100% 100%}
.fx__drip::before{content:"";position:absolute;left:50%;bottom:60%;
  width:.34em;height:4.2em;translate:-50% 0;border-radius:.34em;
  background:linear-gradient(180deg,transparent,rgba(0,216,224,.14));
  filter:blur(.06em)}
@media (prefers-reduced-motion:no-preference){
  html.js .fx__drip{animation:fx-drip 13s cubic-bezier(.6,0,.9,.55) infinite}
}
@keyframes fx-drip{0%{transform:translateY(0) scaleY(1);opacity:0}
  10%{opacity:.95}
  85%{opacity:.95}
  100%{transform:translateY(64em) scaleY(1.5);opacity:0}}
html:not(.js) .fx__drip{display:none}

/* --- 05 water-crisis: the level recedes ---------------------------------
   No tide-mark rule: a hairline across the full frame just reads as a stray
   divider. The water's own edge is the level, and it drops away from where
   it started. */
.fx--recede{--was:30em;--fall:13em}
.fx--recede__body{position:absolute;left:0;right:0;top:var(--was);bottom:-6em;
  background:linear-gradient(180deg,rgba(0,216,224,.20),rgba(0,216,224,.04) 44%,transparent)}
@media (prefers-reduced-motion:no-preference){
  html.js .fx--recede__body{transform:translateY(0)}
  html.js .slide.is-here .fx--recede__body{
    animation:fx-recede 9s cubic-bezier(.33,0,.2,1) .4s both}
}
@keyframes fx-recede{to{transform:translateY(var(--fall))}}
html:not(.js) .fx--recede__body{transform:translateY(var(--fall))}

/* --- 06 compute-constraint: cloud banks --------------------------------
   Drawn clouds, with an outline. A blurred radial gradient can suggest haze
   but it can never read as a cloud - the silhouette is the whole thing. Four
   true circular lobes over a flat base, every radius at least half its chord
   so the bumps stay round, and one hairline weight across every cloud
   regardless of size (non-scaling-stroke). */
/* They sit back: weaker toward the bottom of the frame, where the copy and
   the table are, so the weather never competes with anything being read. */
.fx--cloud-bank{-webkit-mask-image:linear-gradient(180deg,#000 8%,rgba(0,0,0,.45) 52%,rgba(0,0,0,.12));
  mask-image:linear-gradient(180deg,#000 8%,rgba(0,0,0,.45) 52%,rgba(0,0,0,.12))}
.fx__cloud{position:absolute}
.fx__cloud svg{display:block;width:100%;height:100%;overflow:visible}
@media (prefers-reduced-motion:no-preference){
  html.js .fx__cloud{animation:fx-cloud 64s ease-in-out infinite alternate}
}
@keyframes fx-cloud{to{transform:translateX(7em)}}

/* --- 07 alternatives: every column drains -------------------------------
   Four fills, one per answer, each emptying and leaving the cell dry. */
.fx--drain{display:flex}
.fx__col{flex:1;position:relative;overflow:hidden}
/* The separator drains with the column, so four full columns read as four
   rather than as one band. */
.fx__col::before{content:"";position:absolute;left:0;right:0;top:38%;bottom:0;
  background:linear-gradient(180deg,rgba(0,216,224,.20),rgba(0,216,224,.03));
  border-top:1px solid rgba(0,216,224,.45);
  border-right:1px solid rgba(0,216,224,.22)}
.fx__col:last-child::before{border-right:0}
@media (prefers-reduced-motion:no-preference){
  html.js .slide.is-here .fx__col::before{
    animation:fx-drain 6.5s cubic-bezier(.4,0,.25,1) both}
  html.js .slide.is-here .fx__col:nth-child(2)::before{animation-delay:.5s}
  html.js .slide.is-here .fx__col:nth-child(3)::before{animation-delay:1s}
  html.js .slide.is-here .fx__col:nth-child(4)::before{animation-delay:1.5s}
}
@keyframes fx-drain{from{transform:translateY(0)}to{transform:translateY(100%)}}
html:not(.js) .fx__col::before{transform:translateY(100%)}

/* --- 02 thesis: the circuit ---------------------------------------------
   The one-liner is a closed loop, so a charge runs around it. The band is
   masked by the mark itself, which is why --loop-mask exists. */
.fx--circuit{-webkit-mask-image:var(--loop-mask);mask-image:var(--loop-mask);
  -webkit-mask-size:82em auto;mask-size:82em auto;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;opacity:.5}
.fx--circuit::before{content:"";position:absolute;top:-10em;bottom:-10em;width:30em;
  background:linear-gradient(90deg,transparent,rgba(0,216,224,.85),transparent)}
@media (prefers-reduced-motion:no-preference){
  html.js .fx--circuit::before{animation:fx-sweep 15s linear infinite}
}
@keyframes fx-sweep{from{transform:translateX(-34em)}to{transform:translateX(108em)}}

/* --- 09 scout: wind ------------------------------------------------------
   Cirrus at jet-stream height, actually moving. Each streak is a tapered
   sliver rather than a stroked line - a constant-width stroke reads as a
   drawn rule, and wind does not have square ends. The ends are masked off
   as well, so a streak arrives and leaves rather than popping.

   Travel is one full pass, left to right, at a speed that tracks weight:
   the heavier, brighter streaks run faster and the faint ones hang back,
   which is what gives the layer depth. --w is each streak's own width, so
   one keyframe pair serves every size. */
.fx--cirrus{-webkit-mask-image:linear-gradient(180deg,#000 10%,rgba(0,0,0,.5) 46%,rgba(0,0,0,.1));
  mask-image:linear-gradient(180deg,#000 10%,rgba(0,0,0,.5) 46%,rgba(0,0,0,.1))}
.fx__wisp{position:absolute;left:0;width:var(--w);
  transform:translateX(calc(-1 * var(--w)));
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 16%,#000 84%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 16%,#000 84%,transparent)}
.fx__wisp svg{display:block;width:100%;height:100%}
@media (prefers-reduced-motion:no-preference){
  html.js .fx__wisp{animation:fx-wind var(--t) linear infinite}
}
@keyframes fx-wind{
  from{transform:translateX(calc(-1 * var(--w)))}
  to{transform:translateX(100em)}}
html:not(.js) .fx__wisp{transform:translateX(14em)}

/* --- 10 hydro: rain falling --------------------------------------------
   Water coming down, which is the whole slide. Many streaks, fast and
   angled - that is what keeps it reading as rain rather than as a handful
   of drips running down a pane. */
.fx__rainline{position:absolute;top:-16em;width:.13em;height:10em;
  border-radius:.13em;rotate:9deg;
  background:linear-gradient(180deg,transparent,rgba(0,216,224,.55))}
.fx--rainfall::after{content:"";position:absolute;left:0;right:0;bottom:0;
  height:9em;pointer-events:none;
  background:linear-gradient(0deg,rgba(0,216,224,.14),transparent)}
@media (prefers-reduced-motion:no-preference){
  html.js .fx__rainline{animation:fx-downpour 2.1s linear infinite}
}
@keyframes fx-downpour{to{transform:translateY(78em)}}
html:not(.js) .fx__rainline{display:none}

/* --- 11 compute: altitude ----------------------------------------------
   Seven thousand feet is the argument, so the ground is drawn the way
   ground is drawn - contours closing on a summit, tightening as they climb.
   A datum line sits under them for the elevation to be read against. */
.fx__contour{position:absolute;border:1px solid rgba(0,216,224,.26);
  border-radius:54% 46% 44% 56%/60% 40% 60% 40%}
.fx__contour--peak{border-color:rgba(0,216,224,.62);
  background:rgba(0,216,224,.07)}
.fx__datum{position:absolute;left:0;right:0;height:1px;
  background:linear-gradient(90deg,transparent,rgba(0,216,224,.28) 20%,
    rgba(0,216,224,.28) 80%,transparent)}

/* --- 13 market: containment -------------------------------------------
   TAM holds SAM holds SOM. Corner ticks rather than full frames, so it
   reads as measurement instead of three boxes. */
.fx__ring{position:absolute;left:50%;top:50%;translate:-50% -50%}
.fx__ring span{position:absolute;width:2.4em;height:2.4em;
  border:1px solid rgba(0,216,224,.42)}
.fx__ring span:nth-child(1){left:0;top:0;border-right:0;border-bottom:0}
.fx__ring span:nth-child(2){right:0;top:0;border-left:0;border-bottom:0}
.fx__ring span:nth-child(3){left:0;bottom:0;border-right:0;border-top:0}
.fx__ring span:nth-child(4){right:0;bottom:0;border-left:0;border-top:0}
.fx__ring--1{width:90em;height:45em;opacity:.4}
.fx__ring--2{width:60em;height:32em;opacity:.7}
.fx__ring--3{width:30em;height:20em;
  background:radial-gradient(closest-side,rgba(0,216,224,.10),transparent 82%)}

/* --- 14 model: running condensation ------------------------------------
   The cold-surface state: drops that have already gathered and are tracking
   down, each leaving a wet line behind it. Mostly movement, where slide 4 is
   mostly stillness. */
.fx__track{position:absolute;top:-10em;width:.78em;height:.95em;
  border-radius:50% 50% 54% 46%/58% 58% 42% 42%;
  background:radial-gradient(circle at 36% 30%,rgba(233,242,241,.55) 0 6%,
    rgba(150,205,215,.18) 18%,rgba(3,28,40,.55) 52%,
    rgba(0,216,224,.34) 82%,transparent 94%)}
.fx__track::before{content:"";position:absolute;left:50%;bottom:40%;
  width:.3em;height:13em;translate:-50% 0;border-radius:.3em;
  background:linear-gradient(180deg,transparent,rgba(0,216,224,.26))}
@media (prefers-reduced-motion:no-preference){
  html.js .fx__track{animation:fx-track 12s cubic-bezier(.55,0,.85,.6) infinite}
}
@keyframes fx-track{0%{transform:translateY(0);opacity:0}9%{opacity:.95}
  86%{opacity:.95}100%{transform:translateY(70em);opacity:0}}
html:not(.js) .fx__track{display:none}

/* --- 15 gtm: the route runs --------------------------------------------
   Keyed to .is-here so it sets off from the first stop when you reach the
   slide. Left running, you arrive halfway through and it reads as a line
   that starts at the end. */
.fx__pulse{position:absolute;top:calc(50% + 1.6em);width:9em;height:.2em;
  transform:translateX(-10em);
  background:linear-gradient(90deg,transparent,rgba(0,216,224,.9),transparent)}
@media (prefers-reduced-motion:no-preference){
  html.js .slide.is-here .fx__pulse{
    animation:fx-route 7s cubic-bezier(.6,0,.4,1) .5s infinite}
}
@keyframes fx-route{from{transform:translateX(-10em)}to{transform:translateX(102em)}}
html:not(.js) .fx__pulse{display:none}

/* --- 16 competition: broken, and not -----------------------------------
   Three runs that stop short, against one that does not. Plain segments -
   carving the mark into arcs just read as a damaged logo. Kept in the clear
   strip under the rows; across them they looked like strikethrough. */
.fx__seg{position:absolute;height:.26em;border-radius:.26em;
  background:rgba(0,216,224,.34);transform-origin:left center}
.fx__seg--1{left:7em;top:87%;width:15em}
.fx__seg--2{left:25em;top:87%;width:9em}
.fx__seg--3{left:38em;top:87%;width:12em}
.fx__whole{position:absolute;left:7em;top:93%;width:79em;height:.34em;
  border-radius:.34em;transform-origin:left center;
  background:linear-gradient(90deg,rgba(0,216,224,.75),rgba(0,216,224,.35))}
/* Each of theirs sets off and stops. Ours keeps going. */
@media (prefers-reduced-motion:no-preference){
  html.js .slide.is-here .fx__seg{animation:fx-reach 5s cubic-bezier(.2,.8,.3,1) both}
  html.js .slide.is-here .fx__seg--2{animation-delay:.35s}
  html.js .slide.is-here .fx__seg--3{animation-delay:.7s}
  html.js .slide.is-here .fx__whole{
    animation:fx-reach 5s cubic-bezier(.2,.8,.3,1) 1.1s both}
}
@keyframes fx-reach{from{transform:scaleX(0)}to{transform:scaleX(1)}}
.fx__closed{position:absolute;right:-6em;bottom:-4em;width:44em;height:auto;
  aspect-ratio:3657.4/2116.6;opacity:.20;
  background:rgba(0,216,224,.55);
  -webkit-mask-image:var(--loop-mask);mask-image:var(--loop-mask);
  -webkit-mask-size:contain;mask-size:contain;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}

/* --- 17 financials: the shape of the row -------------------------------
   A step in a tinted band was never legible as a claim. One bar per year,
   height proportional to that year's revenue (1.5, 2.8, 11.5, 31, 68), sat
   behind its own column - the growth in the table, drawn. */
/* Sat on the table's own baseline (88% of the frame) and aligned to the
   measured column boxes - anchored to the stage floor they hung below the
   table and sat left of their columns. */
.fx__yr{position:absolute;bottom:12%;
  background:linear-gradient(0deg,rgba(0,216,224,.17),rgba(0,216,224,.02) 78%);
  border-top:1px solid rgba(0,216,224,.45)}

/* --- 18 capital: three platforms ----------------------------------------*/
/* Solid at the floor, fading up - the other way round they read as boxes
   floating rather than platforms standing. */
.fx__step{position:absolute;bottom:0;border-top:1px solid rgba(0,216,224,.42);
  background:linear-gradient(0deg,rgba(0,216,224,.15),rgba(0,216,224,.02) 72%)}
.fx__step--1{left:7em;width:28.7em;height:26%}
.fx__step--2{left:35.65em;width:28.7em;height:41%}
.fx__step--3{left:64.3em;width:28.7em;height:58%}

/* --- 19 risks: fogged, then clear ---------------------------------------
   The risk is obscured; the path through it is not. Static, one layer. */
.fx--fog{-webkit-backdrop-filter:blur(.5em);backdrop-filter:blur(.5em);
  -webkit-mask-image:linear-gradient(100deg,#000 22%,transparent 62%);
  mask-image:linear-gradient(100deg,#000 22%,transparent 62%)}

/* --- 21 window: the aperture narrows ------------------------------------
   The blades translate; they are never scaled. scaleY on a box carrying a
   1px border stretches that hairline and re-rasterises it every frame, which
   is what made the edges flash. Moving a fixed-size box keeps the edge on
   the compositor and perfectly crisp. */
.fx--gap::before,.fx--gap::after{content:"";position:absolute;left:0;right:0;
  height:30em;will-change:transform}
.fx--gap::before{top:0;transform:translateY(-16em);
  background:linear-gradient(180deg,rgba(0,0,0,.62),rgba(0,0,0,.15));
  border-bottom:1px solid rgba(0,216,224,.55)}
.fx--gap::after{bottom:0;transform:translateY(21.75em);
  background:linear-gradient(0deg,rgba(0,0,0,.62),rgba(0,0,0,.15));
  border-top:1px solid rgba(0,216,224,.55)}
.fx--gap__glow{position:absolute;left:0;right:0;top:30.19em;height:20em;
  translate:0 -50%;
  background:linear-gradient(180deg,transparent,rgba(0,216,224,.10) 46%,
    rgba(0,216,224,.10) 54%,transparent)}
@media (prefers-reduced-motion:no-preference){
  html.js .slide.is-here .fx--gap::before{animation:fx-close-top 14s ease-in-out both}
  html.js .slide.is-here .fx--gap::after{animation:fx-close-bot 14s ease-in-out both}
}
/* Closed, the gap runs 24.5em to 38em - the right-hand paragraph sits at
   25.39-34.99em with the webfonts settled, so the gap sits at 22.89-37.49em:
   2.5em of air above it and 2.5em below. Blades are 30em tall, so the top
   one's lower edge is 30 + its offset and the bottom one's upper edge is
   26.25 + its offset. Both paddings were checked against the rendered boxes,
   not the intended ones. */
@keyframes fx-close-top{from{transform:translateY(-16em)}to{transform:translateY(-7.11em)}}
@keyframes fx-close-bot{from{transform:translateY(21.75em)}to{transform:translateY(11.24em)}}
html:not(.js) .fx--gap::before{transform:translateY(-7.11em)}
html:not(.js) .fx--gap::after{transform:translateY(11.24em)}

/* --- 22 moat: the lattice locks -----------------------------------------*/
.fx--lattice::before{content:"";position:absolute;inset:0;opacity:.5;
  background:
    repeating-linear-gradient(60deg,rgba(0,216,224,.16) 0 1px,transparent 1px 4.2em),
    repeating-linear-gradient(-60deg,rgba(0,216,224,.16) 0 1px,transparent 1px 4.2em),
    repeating-linear-gradient(0deg,rgba(0,216,224,.10) 0 1px,transparent 1px 4.2em);
  -webkit-mask-image:radial-gradient(60% 70% at 26% 50%,#000 12%,transparent 82%);
  mask-image:radial-gradient(60% 70% at 26% 50%,#000 12%,transparent 82%)}

/* --- 23 highlights: ripples --------------------------------------------
   One thing dropped in, and the effects keep spreading - which is the
   argument of the slide. Rings scale and fade; transform and opacity only. */
.fx__ring2{position:absolute;left:50%;top:52%;width:26em;height:26em;
  translate:-50% -50%;border-radius:50%;
  border:1px solid rgba(0,216,224,.42);opacity:0}
@media (prefers-reduced-motion:no-preference){
  html.js .fx__ring2{animation:fx-ripple 15s cubic-bezier(.2,.6,.3,1) infinite}
}
@keyframes fx-ripple{
  0%{transform:scale(.18);opacity:0}
  12%{opacity:.75}
  100%{transform:scale(3.4);opacity:0}}
html:not(.js) .fx__ring2{opacity:.3;transform:scale(1.6)}

/* --- 24 close: the tide, again -----------------------------------------
   The deck opens on the tide running across the mark and closes the same
   way. It is the one device that repeats on purpose - a bookend, not a
   duplicate. The water sits lower here so the statement crosses it. */
.s-close{--tide-at:31em}
.s-close .tided__air .t-mark{opacity:.09}
.s-close .tided__sea .t-mark{opacity:.24}

/* --- the editor ---------------------------------------------------------
   Only /deck loads js/deck-edit.js, so none of this exists on /present. */
/* Centred and wrapping: anchored left it ran off the edge once the bar
   carried Site, Decks, Slides, Versions, Export, Import, Reset and Present. */
.edbar{position:fixed;left:50%;translate:-50% 0;bottom:1.4vh;z-index:60;
  display:flex;flex-wrap:wrap;justify-content:center;
  max-width:min(96vw,74rem);
  align-items:center;gap:.55rem;padding:.5rem .6rem;border-radius:.5rem;
  background:rgba(4,40,58,.93);border:1px solid rgba(0,216,224,.3);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  font-family:"Chivo Mono",monospace;font-size:.68rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--surface);
  box-shadow:0 .4rem 1.4rem rgba(0,0,0,.4)}
.edbar__b{font:inherit;letter-spacing:inherit;text-transform:inherit;
  color:var(--surface);background:transparent;cursor:pointer;
  border:1px solid rgba(233,242,241,.28);border-radius:.3rem;
  padding:.32rem .55rem;text-decoration:none;line-height:1;
  transition:border-color .2s var(--ease),color .2s var(--ease)}
.edbar__b:hover{border-color:var(--flow);color:var(--flow)}
.edbar__b:focus-visible{outline:2px solid var(--flow);outline-offset:2px}
.edbar__b--on[aria-pressed="true"]{border-color:var(--flow);color:var(--flow);
  background:rgba(0,216,224,.12)}
.edbar__b--go{border-color:var(--flow);color:var(--abyss);background:var(--flow)}
.edbar__b--go:hover{color:var(--abyss);background:#5ee9ef;border-color:#5ee9ef}
.edbar__s{opacity:.62;transition:opacity .3s var(--ease),color .3s var(--ease)}
.edbar__s.is-flash{opacity:1;color:var(--flow)}
.edbar__w{color:#FFB454}
.edbar__sp{width:.4rem}

/* What can be edited, and what is being edited. */
html.is-editing [data-e]{border-radius:.15em;
  transition:background .18s var(--ease),box-shadow .18s var(--ease)}
html.is-editing [data-e]:hover{background:rgba(0,216,224,.09);
  box-shadow:0 0 0 .28em rgba(0,216,224,.09)}
html.is-editing [data-e]:focus{outline:none;background:rgba(0,216,224,.14);
  box-shadow:0 0 0 .28em rgba(0,216,224,.14)}

/* The stage clips at 16:9, so copy that outgrows it just vanishes. Flag it. */
html.is-editing .stage.is-over{outline:2px solid #FFB454;outline-offset:-2px}

@media (prefers-reduced-motion:reduce){
  .edbar__b,.edbar__s,html.is-editing [data-e]{transition:none}
}
@media print{.edbar{display:none}}

/* The exit-presentation control lived here. /present is gone: /deck is the
   public deck and /admin/deck is the editable one, so there is no mode to
   leave. */


/* Publishing is the one button that changes what other people see. */
.edbar__b--pub{border-color:rgba(0,216,224,.55);color:var(--flow)}
.edbar__b--pub:hover{background:rgba(0,216,224,.14)}
.edbar__b--pub:disabled{opacity:.45;cursor:default;background:none}

/* Version history, hanging above the toolbar. */
.edver{position:absolute;left:0;bottom:calc(100% + .5rem);z-index:61;
  max-width:min(92vw,24rem);
  min-width:15rem;max-height:16rem;overflow-y:auto;
  padding:.45rem;border-radius:.5rem;
  background:rgba(4,40,58,.97);border:1px solid rgba(0,216,224,.3);
  box-shadow:0 .4rem 1.4rem rgba(0,0,0,.45)}
.edver__t{padding:.35rem .45rem;opacity:.55;font-size:.62rem}
.edver__i{display:flex;width:100%;justify-content:space-between;gap:1rem;
  align-items:center;font:inherit;letter-spacing:inherit;text-transform:inherit;
  color:var(--surface);background:transparent;border:0;border-radius:.3rem;
  padding:.42rem .45rem;cursor:pointer;text-align:left}
.edver__i:hover{background:rgba(0,216,224,.14);color:var(--flow)}
.edver__i:focus-visible{outline:2px solid var(--flow);outline-offset:-2px}
.edver__tag{opacity:.5;font-size:.58rem}
@media print{.edver{display:none}}
.edver--decks{min-width:17rem}
.edver__i.is-here{color:var(--flow);background:rgba(0,216,224,.1)}
.edver__i--new{border-top:1px solid rgba(233,242,241,.14);margin-top:.25rem;
  padding-top:.5rem}
.edver__i--del:hover{background:rgba(255,120,120,.16);color:#ff9c9c}
.edver__i--main{border-top:1px solid rgba(233,242,241,.14);margin-top:.25rem;
  padding-top:.5rem}
.edver__i--main:hover{background:rgba(0,216,224,.16);color:var(--flow)}

/* A slide a deck leaves out. .slide sets display:grid, which beats the
   browser's own [hidden] rule, so it has to be said here. */
.slide[hidden],.deck__pip[hidden]{display:none!important}
.edver--slides{min-width:21rem;max-height:22rem}
.edver__i--slide b{opacity:.5;margin-right:.5rem;font-weight:400}
.edver__i--slide.is-off{opacity:.42}
.edver__i--slide.is-off span:first-child{text-decoration:line-through}
.edver__i--slide.is-off .edver__tag{color:#FFB454;opacity:.9}

/* --- the deck inside the site -------------------------------------------
   The public deck sits under the site's own bar; the admin one does not. The
   deck is a full-viewport scroll-snap container, so the bar cannot simply be
   laid on top: every measurement below it - the scroller, the slide, the 16:9
   stage, and the fixed rail and counter that are positioned against the
   stage - has to come off the reduced height instead of the viewport.

   One variable carries that. It is 0 everywhere else, so nothing changes for
   the admin deck. */
:root{--deck-top:0px}
body[data-deck-chrome]{
  --deck-top:var(--nav-h);
  /* 177.7778svh means 1.777778 x the viewport height, not 177 x it: svh is
     already one percent. Written as a multiplication the hundred has to go. */
  --stage-w:min(100vw, calc(1.777778 * (100svh - var(--deck-top))));
  --stage-h:min(56.25vw, calc(100svh - var(--deck-top)))}

/* The midline of the deck's own box, which is no longer the midline of the
   viewport once the bar is above it. */
body[data-deck-chrome]{--deck-mid:calc(var(--deck-top) + (100svh - var(--deck-top)) / 2)}
body:not([data-deck-chrome]){--deck-mid:50svh}

body[data-deck-chrome] .deck{height:calc(100svh - var(--deck-top));
  margin-top:var(--deck-top)}
body[data-deck-chrome] .slide{height:calc(100svh - var(--deck-top))}

.deck__rail{top:var(--deck-mid)}
.deck__where{bottom:calc(100svh - var(--deck-mid) - var(--stage-h) / 2
                         + var(--stage-h) * .05)}

/* The bar belongs to the site, not to the deck: it stays in air rather than
   taking the submerged palette a slide underneath it would impose. */
body[data-deck-chrome] .nav{position:fixed;top:0;left:0;right:0;z-index:50}
