/* NQAAE's own site face (nqaae.uz serves it as alex.ttf; the file reports itself
   as Alexandria, a variable weight 100-900). It carries no Cyrillic, so Geist
   stays behind it in the stack for the Russian and Cyrillic-Uzbek copy. */
@font-face{
  font-family:'Alex';
  src:url('fonts/alex.ttf') format('truetype');
  font-weight:100 900;
  font-style:normal;
  font-display:swap;
}

/* ===========================================================================
   NQAAE Atlas 2.0 — Dark / Blue cinematic edition
   theme.css · design tokens, stage geometry, the earth backdrop, deck chrome
   Canvas is a fixed 1920 x 1080 surface scaled uniformly to the viewport.
   =========================================================================== */

:root{
  /* --- surface ---------------------------------------------------------- */
  --void:#01040c;
  --deep:#040a18;
  --panel:rgb(10 22 46 / .58);
  --panel-solid:#08142c;
  --panel-hi:rgb(16 34 68 / .72);
  --line:rgb(120 172 255 / .16);
  --line-2:rgb(120 172 255 / .30);
  --line-3:rgb(140 190 255 / .48);

  /* --- ink -------------------------------------------------------------- */
  --ink:#eaf2ff;
  --ink-2:#a6c1e6;
  --ink-3:#6f89b3;
  --ink-4:#40567a;

  /* --- accents ---------------------------------------------------------- */
  --blue:#2f7bff;
  --blue-2:#5da4ff;
  --blue-3:#9cc8ff;
  --sky:#38bdf8;
  --cyan:#22d3ee;
  --teal:#2fd1a5;
  --amber:#f5b544;
  --rose:#ff6b81;
  --violet:#a78bfa;

  --glow-blue:rgb(47 123 255 / .55);
  --glow-cyan:rgb(34 211 238 / .40);

  /* --- motion ----------------------------------------------------------- */
  --ease:cubic-bezier(.16,1,.30,1);          /* expo out — the house curve  */
  --ease-soft:cubic-bezier(.33,1,.68,1);
  --ease-io:cubic-bezier(.65,0,.35,1);
  --t-slide:1100ms;

  --font:'Alex','Geist',-apple-system,'Segoe UI',sans-serif;
  --scale:1;
}

*{box-sizing:border-box}
html,body{margin:0;height:100%;width:100%;overflow:hidden;background:#01040c}
body{font-family:var(--font);color:var(--ink);-webkit-font-smoothing:antialiased;font-synthesis:none}
button{font:inherit;cursor:pointer;color:inherit}
img{user-select:none;-webkit-user-drag:none}
::selection{background:rgb(47 123 255 / .35)}

/* --- the 1920x1080 stage ------------------------------------------------- */
#deck{
  /* fixed, not absolute. The canvas is 1920px wide and shrunk with a transform;
     while it took part in the document's scrollable overflow, a phone grew its
     layout viewport to fit that 1920px box, fit() then measured the grown
     viewport and scaled to it, which overflowed again — innerWidth chased
     itself down 775 -> 584 -> 490 and the deck sat off-screen at x=-95 the whole
     way. Out of flow, there is nothing for the viewport to grow to. */
  position:fixed;left:50%;top:50%;width:1920px;height:1080px;
  transform:translate(-50%,-50%) scale(var(--scale));transform-origin:center;
  overflow:hidden;isolation:isolate;background:var(--void);
}

/* ===========================================================================
   BACKDROP — one continuous earth/space field behind every slide.
   Slides only re-frame the camera, so cuts read as a single moving shot.
   =========================================================================== */
.stagefield{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden;background:var(--void)}

.sf-earth{
  position:absolute;left:-8%;top:-8%;width:116%;height:116%;
  background:url('img/earth-wide.jpg') 50% 62% / cover no-repeat;
  transform:scale(var(--e-scale,1.06)) translate3d(var(--e-x,0px),var(--e-y,0px),0);
  opacity:var(--e-op,1);
  filter:saturate(var(--e-sat,1.05)) brightness(var(--e-br,1));
  transition:transform 2200ms var(--ease),opacity 1400ms var(--ease),filter 1600ms var(--ease);
  will-change:transform,opacity;
}
/* slow continuous drift so the frame is never completely still */
.stagefield.is-live .sf-earth{animation:kenburns 68s var(--ease-soft) infinite alternate}
@keyframes kenburns{
  from{background-position:47% 63%}
  to{background-position:57% 57%}
}

/* extra parallax stars in front of the plate, for depth on dark framings */
.sf-stars{
  position:absolute;inset:-12%;opacity:var(--s-op,.5);
  background-repeat:repeat;background-size:820px 820px;
  background-image:
    radial-gradient(1.7px 1.7px at 12% 18%,rgb(255 255 255 / 1),transparent 62%),
    radial-gradient(1.4px 1.4px at 68% 7%,rgb(205 230 255 / .95),transparent 62%),
    radial-gradient(1.9px 1.9px at 82% 34%,rgb(255 255 255 / .92),transparent 62%),
    radial-gradient(1.3px 1.3px at 33% 52%,rgb(180 214 255 / .90),transparent 62%),
    radial-gradient(1.6px 1.6px at 55% 78%,rgb(255 255 255 / .84),transparent 62%),
    radial-gradient(1.3px 1.3px at 90% 66%,rgb(196 226 255 / .82),transparent 62%),
    radial-gradient(1.8px 1.8px at 5% 74%,rgb(255 255 255 / .78),transparent 62%),
    radial-gradient(1.3px 1.3px at 44% 26%,rgb(212 233 255 / .76),transparent 62%),
    radial-gradient(1.2px 1.2px at 24% 88%,rgb(255 255 255 / .70),transparent 62%),
    radial-gradient(1.1px 1.1px at 76% 92%,rgb(190 220 255 / .66),transparent 62%);
  transition:opacity 1400ms var(--ease);
}
.stagefield.is-live .sf-stars{animation:drift-a 150s linear infinite}
.sf-stars-2{background-size:560px 560px;opacity:var(--s2-op,.46);filter:blur(.4px)}
.stagefield.is-live .sf-stars-2{animation:drift-b 96s linear infinite}
@keyframes drift-a{to{transform:translate3d(-900px,-260px,0)}}
@keyframes drift-b{to{transform:translate3d(620px,-180px,0)}}

/* twinkle pass — a handful of brighter points breathing out of phase */
.sf-twinkle{position:absolute;inset:0;opacity:var(--s-op,.6)}
.sf-twinkle i{position:absolute;width:4px;height:4px;border-radius:50%;background:#fff;
  box-shadow:0 0 15px 3px rgb(168 208 255 / .92);opacity:0}
.stagefield.is-live .sf-twinkle i{animation:twinkle 6.2s var(--ease-soft) infinite}
@keyframes twinkle{0%,100%{opacity:0;transform:scale(.4)}45%{opacity:.9;transform:scale(1.04)}}

/* aurora — the deep blue volumetric glows */
.sf-aurora{position:absolute;inset:0;opacity:var(--a-op,1);transition:opacity 1400ms var(--ease)}
.sf-aurora span{position:absolute;border-radius:50%;filter:blur(90px);opacity:.5}
.sf-a1{left:-14%;top:-22%;width:940px;height:940px;background:radial-gradient(circle,rgb(29 78 216 / .85),transparent 66%)}
.sf-a2{right:-16%;top:-10%;width:820px;height:820px;background:radial-gradient(circle,rgb(14 116 190 / .7),transparent 66%)}
.sf-a3{left:34%;bottom:-36%;width:1180px;height:1180px;background:radial-gradient(circle,rgb(34 130 220 / .55),transparent 64%)}
.stagefield.is-live .sf-a1{animation:breathe 22s var(--ease-soft) infinite alternate}
.stagefield.is-live .sf-a2{animation:breathe 27s var(--ease-soft) -6s infinite alternate-reverse}
.stagefield.is-live .sf-a3{animation:breathe 31s var(--ease-soft) -12s infinite alternate}
@keyframes breathe{from{transform:translate3d(0,0,0) scale(1);opacity:.34}to{transform:translate3d(60px,-46px,0) scale(1.16);opacity:.6}}

/* horizon light — the bright atmospheric rim that sells the "from orbit" look */
.sf-rim{position:absolute;left:-10%;right:-10%;height:2px;top:var(--rim-y,74%);opacity:var(--rim-op,0);
  background:linear-gradient(90deg,transparent,rgb(120 200 255 / .9) 22%,rgb(200 236 255 / 1) 50%,rgb(120 200 255 / .9) 78%,transparent);
  filter:blur(2px);transition:opacity 1600ms var(--ease),top 2200ms var(--ease)}
.sf-rim::after{content:'';position:absolute;left:0;right:0;top:-48px;height:100px;
  background:linear-gradient(180deg,transparent,rgb(70 160 255 / .32),transparent);filter:blur(24px)}

/* faint horizon grid, gives scale + a technical register */
.sf-grid{position:absolute;left:0;right:0;bottom:0;height:52%;opacity:var(--g-op,0);
  background-image:linear-gradient(rgb(110 180 255 / .16) 1px,transparent 1px),linear-gradient(90deg,rgb(110 180 255 / .16) 1px,transparent 1px);
  background-size:120px 120px;
  -webkit-mask-image:linear-gradient(180deg,transparent,#000 55%,transparent);
  mask-image:linear-gradient(180deg,transparent,#000 55%,transparent);
  transform:perspective(760px) rotateX(66deg) scale(1.9);transform-origin:bottom;
  transition:opacity 1400ms var(--ease)}

/* colour grade + vignette on top of everything scenic */
.sf-grade{position:absolute;inset:0;
  background:
    /* The stage is a fixed 16:9 canvas, so a window wider than 16:9 letterboxes
       it. Without this the earth and its horizon glow stop dead at the canvas
       edge and the bars read as a seam. Fading the backdrop to the same --void
       the page is painted in makes the join invisible. Content sits inside a
       96px margin, so nothing readable is touched. */
    linear-gradient(90deg,var(--void),rgb(1 4 12 / 0) 124px,
      rgb(1 4 12 / 0) calc(100% - 124px),var(--void)),
    radial-gradient(120% 82% at 50% 96%,rgb(6 26 62 / .30),transparent 62%),
    linear-gradient(180deg,rgb(1 5 14 / var(--v-top,.62)) 0%,rgb(1 6 18 / .16) 38%,rgb(1 5 16 / var(--v-bot,.55)) 100%);
  transition:background 1600ms var(--ease)}
.sf-vig{position:absolute;inset:0;box-shadow:inset 0 0 300px 90px rgb(0 2 8 / .8),inset 0 0 640px 200px rgb(0 3 12 / .5)}
/* film grain keeps large flat gradients from banding on projectors */
.sf-grain{position:absolute;inset:-50%;opacity:.05;pointer-events:none;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/></filter><rect width='140' height='140' filter='url(%23n)' opacity='.55'/></svg>")}
.stagefield.is-live .sf-grain{animation:grain 900ms steps(4) infinite}
@keyframes grain{0%{transform:translate3d(0,0,0)}25%{transform:translate3d(-6%,3%,0)}50%{transform:translate3d(4%,-5%,0)}75%{transform:translate3d(-3%,-2%,0)}}

/* --- camera framings ----------------------------------------------------- */
/* Each slide names one. Changing it glides the earth instead of cutting.     */
#deck[data-bg="hero"]   .stagefield{--e-scale:1.16;--e-y:2%;--e-br:1.06;--s-op:.78;--a-op:.9;--rim-op:0;--g-op:0;--v-top:.55;--v-bot:.42}
#deck[data-bg="rise"]   .stagefield{--e-scale:1.30;--e-y:14%;--e-br:1.12;--s-op:.92;--a-op:1;--rim-op:0;--g-op:0;--v-top:.70;--v-bot:.28}
#deck[data-bg="deep"]   .stagefield{--e-scale:1.62;--e-y:38%;--e-br:.78;--e-op:.85;--s-op:.84;--a-op:.70;--rim-op:.55;--rim-y:89%;--g-op:.20;--v-top:.82;--v-bot:.78}
#deck[data-bg="void"]   .stagefield{--e-scale:1.95;--e-y:52%;--e-br:.60;--e-op:.60;--s-op:1;--a-op:.85;--rim-op:.35;--rim-y:95%;--g-op:.30;--v-top:.88;--v-bot:.88}
#deck[data-bg="close"]  .stagefield{--e-scale:1.44;--e-x:-10%;--e-y:26%;--e-br:.90;--s-op:.74;--a-op:.85;--rim-op:0;--g-op:0;--v-top:.76;--v-bot:.62}
#deck[data-bg="finale"] .stagefield{--e-scale:1.10;--e-y:6%;--e-br:1.14;--s-op:.82;--a-op:1;--rim-op:0;--g-op:0;--v-top:.62;--v-bot:.34}

/* ===========================================================================
   SLIDES
   =========================================================================== */
.slide{position:absolute;inset:0;z-index:1;display:none;overflow:hidden}
.slide.is-active{display:block;z-index:3}
.slide.is-leaving{display:block;z-index:2;pointer-events:none}

/* the transition itself: a short dolly + defocus, never a hard cut */
.slide.is-active{animation:shot-in var(--t-slide) var(--ease) both}
.slide.is-leaving{animation:shot-out 760ms var(--ease-io) both}
@keyframes shot-in{
  from{opacity:0;transform:scale(1.035) translate3d(0,14px,0);filter:blur(14px)}
  60%{opacity:1}
  to{opacity:1;transform:none;filter:blur(0)}
}
@keyframes shot-out{
  from{opacity:1;transform:none;filter:blur(0)}
  to{opacity:0;transform:scale(.972) translate3d(0,-10px,0);filter:blur(10px)}
}
/* backwards navigation mirrors the dolly so the deck feels reversible */
#deck.is-back .slide.is-active{animation:shot-in-b var(--t-slide) var(--ease) both}
#deck.is-back .slide.is-leaving{animation:shot-out-b 760ms var(--ease-io) both}
@keyframes shot-in-b{from{opacity:0;transform:scale(.968) translate3d(0,-14px,0);filter:blur(14px)}60%{opacity:1}to{opacity:1;transform:none;filter:blur(0)}}
@keyframes shot-out-b{from{opacity:1;transform:none;filter:blur(0)}to{opacity:0;transform:scale(1.04) translate3d(0,12px,0);filter:blur(10px)}}

/* --- slide heading ------------------------------------------------------- */
.head{position:absolute;left:96px;right:96px;top:74px;z-index:4}
.kicker{display:inline-flex;align-items:center;gap:12px;margin:0 0 20px;
  font-size:17px;font-weight:600;letter-spacing:3.4px;text-transform:uppercase;color:var(--blue-3)}
.kicker::before{content:'';width:34px;height:1px;background:linear-gradient(90deg,transparent,var(--blue-2));flex:none}
.head h2{margin:0;font-size:62px;line-height:1.08;font-weight:700;letter-spacing:-1.9px;color:#fff;
  text-shadow:0 4px 40px rgb(6 18 44 / .8)}

/* --- the travelling light on titles --------------------------------------
   A band of light crosses every heading: one moving gradient clipped to the
   glyphs, so it costs a single paint and needs no extra element. The text-shadow
   above still draws, because a shadow is taken from the glyph shape rather than
   its colour.

   It is NOT applied to a title whose words are child elements — .cascade wraps
   each word in its own <i>, and .has-titlecard splits the heading into three
   spans that travel independently. Clipping the parent's background there would
   leave those children with nothing of their own to paint. */
:root{--shine:linear-gradient(100deg,
  #ffffff 20%,#ffffff 32%,#e4edf9 40%,#d3e0f2 45%,#e4edf9 50%,#ffffff 58%,#ffffff 70%);
  /* subtitles sit just under the white of the headings rather than down in the
     body-copy blue, so a scene reads as one block of type */
  --ink-sub:#e2ecfa}
.slide:not(.has-titlecard) .head h2{
  background-image:var(--shine);background-size:300% 100%;background-position:165% 0;
  -webkit-background-clip:text;background-clip:text;color:transparent}
.slide.is-in:not(.has-titlecard) .head h2{
  animation:title-shine 6.4s var(--ease-soft) infinite}
@keyframes title-shine{
  0%  {background-position:165% 0}
  50% {background-position:-75% 0}
  100%{background-position:-75% 0}}
/* A still frame shows solid type. Parking the sweep at any fixed position
   would leave the darker band sitting across the words. */
#deck.is-still .head h2,
#deck.is-still .st-cycle span{animation:none!important;
  background-image:none!important;color:#fff!important}
.sub{margin:18px 0 0;font-size:24px;line-height:1.48;color:var(--ink-sub);max-width:1180px;font-weight:400}
/* a heading that owns the full width rather than anchoring a left column */
.head.is-centered{text-align:center}
.head.is-centered .kicker{justify-content:center}
.head.is-centered .kicker::before{display:none}
.head.is-centered .sub{margin-left:auto;margin-right:auto}
/* A frame of a sequence can drop its kicker while its neighbours keep one. The
   element stays so the box is still reserved — remove it and the title would
   jump 41px between two frames of what is meant to be one continuous diagram. */
.kicker.is-quiet{visibility:hidden}
/* a hairline under the title. On a continuous sequence it is the beat that
   marks the change, so unlike the kicker it is deliberately not held. */
.head-rule{display:block;width:132px;height:2px;margin:26px auto 0;border-radius:2px;
  background:linear-gradient(90deg,transparent,var(--blue-2) 22%,#9fd0ff 50%,var(--blue-2) 78%,transparent);
  box-shadow:0 0 22px -5px var(--glow-blue)}
/* no subtitle means the scene can start higher */
.slide.has-tall-stage .stage{top:236px}

.badge{position:absolute;right:0;top:10px;display:inline-flex;align-items:center;gap:10px;
  padding:11px 20px;border-radius:999px;font-size:15px;font-weight:600;letter-spacing:.3px;
  background:rgb(47 209 165 / .10);border:1px solid rgb(47 209 165 / .34);color:#84e8c9;
  backdrop-filter:blur(10px)}
.badge i{width:7px;height:7px;border-radius:50%;background:#2fd1a5;flex:none;
  box-shadow:0 0 0 0 rgb(47 209 165 / .7);animation:ping 2.4s var(--ease-soft) infinite}
@keyframes ping{0%{box-shadow:0 0 0 0 rgb(47 209 165 / .65)}70%{box-shadow:0 0 0 12px rgb(47 209 165 / 0)}100%{box-shadow:0 0 0 0 rgb(47 209 165 / 0)}}
.badge.is-blue{background:rgb(47 123 255 / .12);border-color:rgb(93 164 255 / .38);color:var(--blue-3)}
.badge.is-blue i{background:var(--blue-2);animation-name:ping-b}
@keyframes ping-b{0%{box-shadow:0 0 0 0 rgb(93 164 255 / .6)}70%{box-shadow:0 0 0 12px rgb(93 164 255 / 0)}100%{box-shadow:0 0 0 0 rgb(93 164 255 / 0)}}

.stage{position:absolute;left:96px;right:96px;top:284px;bottom:104px;z-index:3}
.slide.no-head .stage{top:0;bottom:0;left:0;right:0}

.foot{position:absolute;left:96px;right:96px;bottom:78px;margin:0;font-size:17px;line-height:1.5;
  color:var(--ink-3);z-index:4}

/* --- glass panel primitive ---------------------------------------------- */
.glass{position:relative;border-radius:26px;background:var(--panel);border:1px solid var(--line);
  backdrop-filter:blur(26px) saturate(1.25);
  box-shadow:0 30px 90px -30px rgb(0 6 22 / .9),inset 0 1px 0 rgb(180 214 255 / .10)}
/* a single hairline of light along the top edge — reads as bevel, not border */
.glass::before{content:'';position:absolute;left:24px;right:24px;top:-1px;height:1px;
  background:linear-gradient(90deg,transparent,rgb(150 200 255 / .55),transparent);pointer-events:none}

/* ===========================================================================
   DECK CHROME
   =========================================================================== */
.chrome{position:absolute;left:0;right:0;bottom:0;height:64px;z-index:40;display:flex;align-items:center;
  padding:0 30px;gap:22px;color:var(--ink-3);font-size:13px;
  background:linear-gradient(0deg,rgb(2 7 18 / .82),transparent);
  opacity:.4;transition:opacity 420ms var(--ease)}
.chrome:hover{opacity:1}
/* The bar has no left-hand element, so the dots centre on the FRAME rather
   than on whatever space the buttons leave over. */
.dots{position:absolute;left:50%;top:0;bottom:0;transform:translateX(-50%);
  display:flex;align-items:center;gap:7px}
.acts{margin-left:auto}
.dots b{width:6px;height:6px;border-radius:50%;background:rgb(140 180 240 / .28);transition:all 420ms var(--ease)}
.dots b.on{width:24px;border-radius:3px;background:var(--blue-2);box-shadow:0 0 12px var(--glow-blue)}
.acts{display:flex;align-items:center;gap:8px}
.acts span{font-variant-numeric:tabular-nums;letter-spacing:1px;margin-right:8px;color:var(--ink-2)}
.acts button{width:34px;height:34px;border-radius:10px;border:1px solid var(--line);
  background:rgb(12 26 54 / .6);color:var(--ink-2);display:grid;place-items:center;font-size:15px;
  transition:all 260ms var(--ease)}
.acts button:hover{background:rgb(47 123 255 / .22);border-color:var(--line-3);color:#fff;transform:translateY(-2px)}
.acts button[aria-pressed="true"]{background:rgb(47 123 255 / .3);color:#fff;border-color:var(--line-3)}
.toast{position:absolute;left:50%;bottom:96px;transform:translate(-50%,14px);z-index:50;
  padding:11px 20px;border-radius:999px;font-size:14px;letter-spacing:.3px;
  background:rgb(8 18 40 / .92);border:1px solid var(--line-2);color:var(--ink);
  opacity:0;pointer-events:none;transition:all 320ms var(--ease);backdrop-filter:blur(12px)}
.toast.on{opacity:1;transform:translate(-50%,0)}

/* ===========================================================================
   VIEW-ONLY · a deck driven from the admin panel
   The chrome goes because none of it does anything here — the lock in deck.js
   is what actually closes those routes; hiding the bar just stops it lying.
   =========================================================================== */
#deck.is-viewonly .chrome,
html.is-viewonly .chrome{display:none}
#deck.is-viewonly{cursor:default}

.live-note{position:absolute;left:50%;bottom:34px;transform:translate(-50%,10px);z-index:60;
  padding:9px 20px;border-radius:999px;pointer-events:none;
  font-size:14px;font-weight:550;letter-spacing:.3px;color:var(--ink-2);
  background:rgb(6 14 32 / .82);border:1px solid var(--line);backdrop-filter:blur(14px);
  opacity:0;transition:opacity 420ms var(--ease),transform 420ms var(--ease)}
.live-note.is-on{opacity:1;transform:translate(-50%,0)}

/* the link went out from under us: say so rather than freezing silently */
#deck.is-closed::after{content:'';position:absolute;inset:0;z-index:55;
  background:rgb(1 4 12 / .72);backdrop-filter:blur(6px)}

/* ===== lite: what a phone can actually render ==============================
   Set by the inline script in index.html for coarse-pointer, small or
   low-memory devices. The audience opens the viewer link on phones, so the deck
   has to survive there — and it did not: the cover crashed the renderer, the
   browser reloaded twice and then gave up.

   Three things are removed, in order of how much they cost:

   1. The cover video. Already prevented from downloading (deck.js attaches src
      only off lite), so here we only need the plate to still look composed.
   2. backdrop-filter. Each one makes the compositor snapshot and blur whatever
      is behind it, every frame it changes. There are thirteen.
   3. Large blurs and the per-frame filter chain on the video plate.

   Nothing here changes layout, type or colour: the deck reads the same, it just
   stops asking a phone GPU for work it cannot do. The projector never sees any
   of it. */

html.lite *,
html.lite *::before,
html.lite *::after{
  -webkit-backdrop-filter:none!important;
  backdrop-filter:none!important}

/* Where the glass was carrying the separation, give the surface back some body
   so panels do not dissolve into the backdrop. */
html.lite .card,
html.lite .panel,
html.lite .glass{background-color:rgb(9 20 44 / .86)}

/* The video plate becomes a still disc: same size, same falloff, no decode. */
html.lite .cover-orb-disc{
  background:
    radial-gradient(closest-side at 42% 38%, rgb(38 74 150 / .55), transparent 70%),
    radial-gradient(closest-side, rgb(10 24 54 / .95), rgb(2 8 22 / .35) 70%, transparent 88%)}
html.lite .cover-orb-disc video{display:none}
html.lite .cover-orb-shade{filter:blur(18px)}   /* was 40px */

/* --- lite, part two: the ambient backdrop ---------------------------------
   Removing the cover video was not enough for a real iPhone. The backdrop is
   twelve full-canvas layers and eight of them animate forever: a ken-burns pan
   on the earth, two drifting star sheets, twinkling particles, three aurora
   blobs carrying filter:blur(90px) at up to 1180px across, and a grain sheet at
   inset:-50% — four times the canvas area — repainting four times a second.

   Each animated layer holds its own backing store at canvas size, and iOS caps
   memory per tab rather than per machine. Twelve of those is what kills the
   renderer once the video is gone.

   Lite keeps what carries the look and costs nothing once painted — the earth,
   the grading, the vignette — and stops everything that needs a buffer. The
   scenes' own entrance animations are untouched: they are the presentation, they
   are per-slide, and they end. */
html.lite .stagefield *{animation:none!important}
html.lite .sf-aurora,
html.lite .sf-grain,
html.lite .sf-twinkle,
html.lite .sf-stars-2{display:none!important}
html.lite .sf-stars{filter:none}

/* The 90px aurora wash gave the field its colour; a plain gradient does the same
   job for a phone and allocates nothing. */
html.lite .stagefield{
  background-image:
    radial-gradient(60% 45% at 12% 8%,  rgb(29 78 216 / .30), transparent 70%),
    radial-gradient(55% 40% at 88% 4%,  rgb(14 116 190 / .24), transparent 70%),
    radial-gradient(70% 50% at 46% 104%,rgb(34 130 220 / .20), transparent 68%)}

html.lite .cover-orb-shade{filter:none;
  background:radial-gradient(closest-side,rgb(2 8 22 / .92),transparent 74%)}

/* will-change is a promise to the compositor that costs a permanent backing
   store whether or not anything is animating. Lite has stopped the animations,
   so the promise is all cost and no benefit. */
html.lite *{will-change:auto!important}

/* ===========================================================================
   TOUCH · phones and tablets
   The canvas is a fixed 1920x1080 surface scaled to fit, so everything inside
   it shrinks with --scale. On a phone that is about 0.2: a 64px control bar
   becomes 13px and a 34px button becomes 7px. Sizes that need to stay a real
   physical size are therefore written as a real measurement divided by the
   scale, which cancels it out.
   =========================================================================== */
@media (pointer:coarse){
  /* The chrome sits outside #deck, so it is NOT scaled by the canvas and these
     are real pixels. That is the whole reason it was moved: inside the canvas a
     64px bar became 13px on a phone, and sizing it up to compensate then covered
     a quarter of an already-small slide. Out here it lands in the letterbox,
     where there is nothing but black. */
  .chrome{opacity:1;height:54px;padding:0 16px;gap:12px;
    padding-bottom:env(safe-area-inset-bottom,0px);
    height:calc(54px + env(safe-area-inset-bottom,0px))}
  .acts{gap:8px}
  .acts span{font-size:13px;margin-right:6px;letter-spacing:normal}
  .acts button{width:44px;height:44px;border-radius:12px;font-size:19px}
  /* 18 dots at 6px are a 1px target on a phone — not reachable, not legible. */
  .dots{display:none}
  /* A hover lift on a device with no hover leaves the button stuck mid-air
     after a tap. */
  .acts button:hover{transform:none}

  /* These two are still inside the canvas, so they DO need the scale cancelled
     out or they arrive at a couple of pixels tall. */
  .toast,.live-note{font-size:calc(14px / var(--scale));
    padding:calc(9px / var(--scale)) calc(20px / var(--scale));
    bottom:calc(26px / var(--scale));
    border-radius:calc(999px / var(--scale))}
}

/* --- turn the phone ------------------------------------------------------- */
/* A 16:9 slide in a 9:19.5 window can only ever use about a quarter of it —
   measured: 26% upright against 82% on its side. No amount of scaling changes
   that; the deck already fills the full width in portrait. So say so, once,
   quietly, and let the hint take itself away the moment the phone turns. */
.rotate-hint{display:none}
@media (pointer:coarse) and (orientation:portrait){
  .rotate-hint{
    display:flex;align-items:center;gap:10px;
    position:fixed;left:50%;transform:translateX(-50%);
    bottom:calc(76px + env(safe-area-inset-bottom,0px));
    z-index:70;
    /* A fixed box with only `left` set shrink-wraps into whatever remains to the
       right of that edge — here 195px, which squeezed the line to 73px. Size to
       the content and cap it instead. */
    width:max-content;max-width:min(88vw,380px);
    padding:11px 18px;border-radius:999px;
    background:rgb(8 18 40 / .92);border:1px solid var(--line-2);
    color:var(--ink-2);font-size:14px;line-height:1.35;text-align:left;
    pointer-events:none;                 /* never in the way of a tap */
    animation:rotate-hint-in 520ms var(--ease) both 900ms}
  .rotate-hint svg{width:22px;height:22px;flex:none;color:var(--blue-2)}
}
/* Nothing to say on a viewer link: the audience cannot drive it anyway, and the
   hint would sit over the slide they are trying to watch. */
html.is-viewonly .rotate-hint{display:none}

@keyframes rotate-hint-in{from{opacity:0;transform:translate(-50%,10px)}
                          to{opacity:1;transform:translate(-50%,0)}}

/* Notches and home indicators sit over the letterbox, not the slide, but the
   chrome is pinned to the very bottom of the canvas — on a phone in landscape
   that is exactly where the home indicator lives. */
@supports (padding:env(safe-area-inset-bottom)){
  @media (pointer:coarse){
    .chrome{padding-bottom:calc(env(safe-area-inset-bottom,0px) / var(--scale))}
  }
}
