/* Midnight Walk — slide engine (v01)
 *
 * ONE renderer, two hosts: admin/preview.php (live DB) and the packed
 * player.html (offline). Neither host may contain rendering rules of its own —
 * if they diverge, the preview starts lying about what will play.
 *
 * DESIGN SPACE IS ALWAYS 1920x1080. The stage is laid out at that exact size
 * and then scaled with a transform to fit whatever it sits in. So a preview in
 * a browser window is a true representation of the screen, and on the Pi at
 * 1080p the scale is simply 1.
 *
 * PERFORMANCE RULES (the Pi 4 has to sustain this at 1080p):
 *   - Animate ONLY transform and opacity. Both are GPU-composited.
 *   - No filter/backdrop-filter at runtime. The blurred backdrop is baked into
 *     a second JPEG by the photo worker precisely so nothing is filtered here.
 */

.mw-stage-wrap{position:relative;width:100%;overflow:hidden;background:#000}
.mw-stage{
  position:absolute;top:0;left:0;
  width:1920px;height:1080px;
  transform-origin:0 0;
  background:var(--mw-bg-mid,#0B1026);
  overflow:hidden;
  font-family:'Inter',system-ui,sans-serif;
  color:#fff;
}

/* ---------- slide layers (two, cross-faded) ---------- */
.mw-slide{position:absolute;inset:0;opacity:0;will-change:opacity}
.mw-slide.is-on{opacity:1}

.mw-backdrop{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  will-change:transform;transform-origin:center}
/* The scrim carries the whole legibility burden: a bright patch in someone's
 * photo lands directly behind the name otherwise. It is deliberately stronger
 * on the text side (right) and lighter over the photo side, and its overall
 * strength is tunable via --mw-dim so it can be matched to the real screen.
 * Opacity on the element scales both gradients together — no calc() inside
 * rgba(), which keeps it safe on the Pi's Chromium. */
.mw-scrim{position:absolute;inset:0;opacity:var(--mw-dim,.85);
  background:
    linear-gradient(90deg, var(--mw-scrim-a,rgba(6,9,22,.30)) 0%,
                           var(--mw-scrim-b,rgba(6,9,22,.78)) 46%,
                           var(--mw-scrim-c,rgba(6,9,22,.95)) 100%),
    radial-gradient(130% 110% at 22% 35%, transparent 0%, var(--mw-scrim-r,rgba(6,9,22,.80)) 100%)}
.mw-scrim.mw-plain{opacity:1;
  background:radial-gradient(120% 80% at 50% 8%,
    var(--mw-bg-top,#1A2350) 0%, var(--mw-bg-mid,#0B1026) 55%, var(--mw-bg-edge,#070A1A) 100%)}

/* ---------- content ---------- */
.mw-body{position:absolute;inset:0;display:flex;align-items:center;gap:96px;padding:0 130px}
.mw-body.mw-solo{justify-content:center;text-align:center;padding:0 200px}

.mw-shot{flex:0 0 auto;width:740px;height:880px;display:flex;align-items:center;justify-content:center}
/* The photo edge picks up the accent, so that control has real presence on a
 * photo slide rather than only tinting two small lines of text. */
.mw-shot img{max-width:100%;max-height:100%;object-fit:contain;border-radius:18px;
  box-shadow:0 40px 90px -30px rgba(0,0,0,.9),
             0 0 0 2px var(--mw-ring,rgba(244,199,123,.30)),
             0 0 60px -10px var(--mw-glow,rgba(244,199,123,.16));
  will-change:transform;transform-origin:center}

.mw-text{flex:1;min-width:0}
.mw-body.mw-solo .mw-text{max-width:1360px}

.mw-eyebrow{font-size:calc(26px * var(--mw-type,1));letter-spacing:.24em;text-transform:uppercase;
  color:var(--mw-accent2,#8FA3E8);margin-bottom:22px;display:block}
.mw-name{font-family:'Fraunces',Georgia,serif;font-weight:500;line-height:1.02;
  font-size:calc(104px * var(--mw-type,1));color:#fff;letter-spacing:-.01em;overflow-wrap:anywhere;
  text-shadow:0 4px 40px rgba(0,0,0,.6)}
.mw-body.mw-solo .mw-name{font-size:calc(140px * var(--mw-type,1))}
.mw-msg{font-size:calc(38px * var(--mw-type,1));line-height:1.45;color:#E8ECF8;margin-top:30px;
  overflow-wrap:anywhere;text-shadow:0 2px 22px rgba(0,0,0,.7)}
.mw-body.mw-solo .mw-msg{font-size:calc(46px * var(--mw-type,1));margin-top:38px}
.mw-from{font-size:calc(30px * var(--mw-type,1));color:var(--mw-accent,#F4C77B);margin-top:38px;
  font-style:italic;font-family:'Fraunces',Georgia,serif}

/* Entrance: transform + opacity only. */
.mw-anim{opacity:0;transform:translateY(28px)}
.mw-slide.is-on .mw-anim{opacity:1;transform:none;
  transition:opacity var(--mw-textms,700ms) ease, transform var(--mw-textms,700ms) cubic-bezier(.2,.7,.3,1)}
.mw-slide.is-on .mw-anim.d1{transition-delay:calc(var(--mw-textdelay,300ms))}
.mw-slide.is-on .mw-anim.d2{transition-delay:calc(var(--mw-textdelay,300ms) + 120ms)}
.mw-slide.is-on .mw-anim.d3{transition-delay:calc(var(--mw-textdelay,300ms) + 240ms)}
.mw-slide.is-on .mw-anim.d4{transition-delay:calc(var(--mw-textdelay,300ms) + 360ms)}

/* Ken Burns — pure transform, GPU-composited. */
@keyframes mw-kb-in  { from{transform:scale(1) translate3d(0,0,0)}
                       to{transform:scale(var(--mw-kb,1.08)) translate3d(-1.6%,-1.1%,0)} }
@keyframes mw-kb-out { from{transform:scale(var(--mw-kb,1.08)) translate3d(1.6%,1.1%,0)}
                       to{transform:scale(1) translate3d(0,0,0)} }
.mw-kb-in  { animation:mw-kb-in  var(--mw-kbms,12000ms) linear both }
.mw-kb-out { animation:mw-kb-out var(--mw-kbms,12000ms) linear both }

/* ---------- empty state ---------- */
.mw-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  text-align:center;padding:0 200px}
.mw-empty p{font-family:'Fraunces',Georgia,serif;font-size:64px;color:var(--mw-accent,#F4C77B);line-height:1.3}

@media (prefers-reduced-motion:reduce){
  .mw-kb-in,.mw-kb-out{animation:none}
  .mw-slide.is-on .mw-anim{transition:none}
}

/* ---------- text styles (per-preset typographic treatments) ----------
 * Applied as a class on the SLIDE LAYER, not the stage, so two slides with
 * different presets can cross-fade without either snapping to the other's look.
 * `classic` is the base defined above; these three vary from it.
 */

/* airy — wider tracking, lighter weight, more breathing room */
.mw-ts-airy .mw-eyebrow{letter-spacing:.38em;font-size:calc(23px * var(--mw-type,1));margin-bottom:28px}
.mw-ts-airy .mw-name{font-weight:400;letter-spacing:.004em}
.mw-ts-airy .mw-msg{font-weight:300;line-height:1.62;margin-top:36px}
.mw-ts-airy .mw-from{margin-top:46px}

/* modern — sans-serif name, tight and contemporary */
.mw-ts-modern .mw-eyebrow{letter-spacing:.16em;font-weight:600}
.mw-ts-modern .mw-name{font-family:'Inter',system-ui,sans-serif;font-weight:700;
  letter-spacing:-.03em;font-size:calc(92px * var(--mw-type,1))}
.mw-ts-modern .mw-body.mw-solo .mw-name{font-size:calc(122px * var(--mw-type,1))}
.mw-ts-modern .mw-msg{font-weight:400}
.mw-ts-modern .mw-from{font-family:'Inter',system-ui,sans-serif;font-style:normal;
  font-weight:600;font-size:calc(26px * var(--mw-type,1))}

/* quiet — small tracked-out capitals, understated */
.mw-ts-quiet .mw-eyebrow{font-size:calc(20px * var(--mw-type,1));letter-spacing:.3em;margin-bottom:30px}
.mw-ts-quiet .mw-name{font-size:calc(62px * var(--mw-type,1));text-transform:uppercase;
  letter-spacing:.13em;font-weight:500}
.mw-ts-quiet .mw-body.mw-solo .mw-name{font-size:calc(80px * var(--mw-type,1))}
.mw-ts-quiet .mw-msg{font-size:calc(34px * var(--mw-type,1));line-height:1.65}
.mw-ts-quiet .mw-body.mw-solo .mw-msg{font-size:calc(40px * var(--mw-type,1))}
.mw-ts-quiet .mw-from{margin-top:44px;font-size:calc(26px * var(--mw-type,1))}

/* ---------- ambient aura ----------
 * A single large soft radial gradient drifting very slowly. It gives the
 * text-only slides — most of the rotation — some life without any per-frame
 * work: one composited layer moved by transform, nothing repainted.
 * Deliberately slow (40s+) and low contrast; this is a memorial, not a screensaver.
 */
.mw-aura{position:absolute;left:50%;top:50%;width:150%;height:150%;margin:-75% 0 0 -75%;
  pointer-events:none;
  background:radial-gradient(closest-side, var(--mw-aura,rgba(143,163,232,.18)), transparent 72%);
  animation:mw-drift var(--mw-aurams,42000ms) ease-in-out infinite alternate;
  will-change:transform}
@keyframes mw-drift{
  from{transform:translate3d(-5%,-3.5%,0) scale(1)}
  to  {transform:translate3d(5%,4%,0)     scale(1.14)}
}

/* ---------- slide transition styles ----------
 * How the incoming slide arrives. All three are opacity (+ transform), so the
 * cost is identical — it is purely a change of character.
 */
.mw-tr-drift{transform:translate3d(2.2%,0,0)}
.mw-tr-rise {transform:translate3d(0,2.6%,0)}
.mw-slide.is-on.mw-tr-drift,
.mw-slide.is-on.mw-tr-rise{transform:none}

@media (prefers-reduced-motion:reduce){
  .mw-aura{animation:none}
  .mw-tr-drift,.mw-tr-rise{transform:none}
}
