  /* Shared card pop-in (summary + history cards) */
  @keyframes lvlPop { from { opacity:0; transform:scale(.82); } to { opacity:1; transform:scale(1); } }

  /* Session-summary overlay (durable — only the Close button dismisses it) */
  .sum-overlay {
    position:fixed; inset:0; z-index:55; display:flex; align-items:flex-start; justify-content:center; padding:20px;
    overflow-y:auto;   /* short/landscape screens: the card can exceed the viewport — keep Close reachable */
    /* transparent while the goo splat plays over the live content — the darken/blur arrives
       with the stats card via .capped .sum-scrim below */
    background:transparent;
    opacity:0; transition:opacity .5s ease;
  }
  .sum-overlay.show { opacity:1; }
  .sum-overlay[hidden] { display:none; }
  .sum-card {
    position:relative; z-index:2;            /* above the splatter so the stats stay readable */
    margin-top:8vh;                          /* bias toward the top half of the screen */
    /* near-opaque bg, NO backdrop blur: the goo sim + afterglow clip behind this never stop
       animating, so a backdrop-filter here re-blurred the card area every frame — a big part
       of the end-of-session framerate dip. The darken carries the separation instead. */
    width:100%; max-width:350px; background:rgba(20,11,36,.94); border:1px solid var(--panel-line); border-radius:18px;
    padding:26px 24px; text-align:center; box-shadow:0 26px 80px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.05);
    animation: lvlPop .4s cubic-bezier(.2,.9,.3,1.3);
  }
  .sum-card[hidden] { display:none; }
  .sum-kicker { font-family:"Chakra Petch",sans-serif; font-weight:800; letter-spacing:5px; font-size:13px;
    background:linear-gradient(95deg,var(--magenta),var(--cyan)); -webkit-background-clip:text; background-clip:text; color:transparent; }
  .sum-stats { margin:20px 0 22px; text-align:left; }
  .sum-stats .row { display:flex; align-items:center; gap:11px; position:relative; margin-top:0;
    padding:11px 2px; border-bottom:1px solid rgba(51,33,92,.6); font-size:14px; }
  .sum-stats .row:last-child { border-bottom:none; }
  .sum-stats .row .ico { width:28px; height:28px; flex:0 0 auto; border-radius:8px; display:flex; align-items:center; justify-content:center;
    background:var(--inset); border:1px solid var(--panel-line); font-size:14px; }
  .sum-stats .row .lbl { flex:1; color:var(--muted); }
  .sum-stats .row .val { font-family:"JetBrains Mono",monospace; color:var(--text); font-weight:700; font-variant-numeric:tabular-nums; }
  .sum-actions { display:flex; gap:10px; }
  .sum-close { width:100%; padding:13px; border:none; border-radius:11px; cursor:pointer;
    background:linear-gradient(95deg,var(--magenta),var(--violet)); color:#fff; font-weight:700; font-size:15px; box-shadow:0 0 24px rgba(255,45,155,.4); }
  .sum-actions .sum-close { width:auto; flex:1; }
  .sum-save { flex:1.3; padding:13px; border:none; border-radius:11px; cursor:pointer;
    background:linear-gradient(95deg,var(--cyan),var(--violet)); color:#08131a; font-weight:700; font-size:15px;
    box-shadow:0 0 24px rgba(34,224,255,.35); }
  .sum-save[hidden] { display:none; }
  .sum-save:disabled { opacity:.65; cursor:default; box-shadow:none; color:#0b2530; }
  .goo-defs { position:absolute; width:0; height:0; }
  /* backdrop layers: fixed, not absolute — the overlay scrolls (tall card on short screens)
     and these must keep covering the viewport rather than scrolling away with the content */
  /* NO filter, like .ruin-goo: a drop-shadow here is a full-screen blur pass re-run on
     every sim paint — for the whole summary + afterglow it was the single costliest part
     of the end-of-session sequence. The pearl look survives without the rim (the ruin goo
     has always run bare and reads identically). */
  .sum-goo { position:fixed; inset:0; width:100%; height:100%; pointer-events:none; }
  .sum-scrim { position:fixed; inset:0; z-index:1; pointer-events:none;     /* darken the splatter/clip once the card is up */
    /* darken only, NO backdrop blur: a full-viewport blur(7px) over the never-idle goo sim
       and the looping afterglow embed cost a whole-screen re-blur every frame through the
       entire afterglow — the main end-of-session framerate dip. A slightly deeper darken
       gives the same "pushed back" read for free. */
    background:radial-gradient(120% 90% at 50% 120%, rgba(123,45,255,.18), transparent 60%), rgba(8,7,16,.74);
    opacity:0; transition:opacity .6s ease; }
  .sum-overlay.capped .sum-scrim { opacity:1; }
  .edge-overlay {
    position:fixed; inset:0; z-index:60; display:flex; align-items:center; justify-content:center;
    /* Translucent by design: darken + tint the clip playing underneath, don't black it out.
       This costs a whole-screen recomposite per video frame while visuals are on (~120fps
       baseline dips to ~100 during a hold) — an accepted trade to keep the clip visible. No
       backdrop blur (far worse); and the heavy full-screen glow repaint is gone (see .edge-glow). */
    background:radial-gradient(55% 45% at 50% 45%, rgba(255,176,32,.14), transparent 70%), rgba(8,7,16,.74);
    overflow:hidden;
    opacity:0; transition:opacity .18s ease; cursor:pointer; text-align:center;   /* fade in quickly */
  }
  .edge-overlay.show { opacity:1; }
  .edge-overlay.ending { transition:opacity .8s ease; pointer-events:none; }   /* fade out gently — and STOP
     eating taps: the near-invisible full-screen layer otherwise swallows the next ~1s of clicks
     (tapping Ruin right after resuming an edge hit this and started a fresh edge instead) */
  .edge-overlay[hidden] { display:none; }
  /* The throbber. A BOUNDED, centered element (not inset:0): a full-screen gradient layer
     blows the browser's layer-promotion budget and gets re-rasterized every frame — a
     per-pixel radial recompute across the whole screen at the display's refresh rate, which
     crushes weak GPUs. Bounded to ~1 Mpx, it stays a cached texture, so only the beat's
     transform/opacity animate (no repaint). The static full-screen vignette below frames the
     dark corners the glow no longer reaches. */
  .edge-glow { position:absolute; inset:0; margin:auto; width:min(1000px,94vw); height:min(760px,80vh);
    pointer-events:none; transform-origin:50% 50%; will-change:transform, opacity; backface-visibility:hidden;
    background:radial-gradient(50% 50% at 50% 50%, rgba(255,176,32,.34), rgba(255,45,155,.16) 52%, transparent 76%);
    animation:edgeBeat .92s ease-out infinite; }
  @keyframes edgeBeat { 0%{transform:scale(1);opacity:.55;} 9%{transform:scale(1.06);opacity:.95;} 18%{transform:scale(1);opacity:.6;} 28%{transform:scale(1.04);opacity:.8;} 44%{transform:scale(1);opacity:.5;} 100%{transform:scale(1);opacity:.5;} }
  /* Static (like .ruin-vignette): the beat lives on .edge-glow alone, so this doesn't need to
     be a second animated full-screen layer blending over the live clip every frame. */
  .edge-vignette { position:absolute; inset:0; pointer-events:none; opacity:.85;
    background:radial-gradient(farthest-side at 50% 46%, transparent 26%, rgba(6,4,12,.72) 100%); }
  .edge-flash { position:absolute; inset:0; margin:auto; width:min(1000px,94vw); height:min(760px,80vh);
    pointer-events:none; opacity:0;
    background:radial-gradient(50% 50% at 50% 50%, rgba(255,176,32,.5), rgba(255,45,155,.16) 55%, transparent 76%); }
  .edge-inner { position:relative; z-index:2; }
  .edge-label { font-family:"Chakra Petch",sans-serif; color:var(--amber); font-weight:800; letter-spacing:8px; font-size:15px; text-shadow:0 0 26px rgba(255,176,32,.75), 0 0 50px rgba(255,45,155,.4); }
  .edge-timer { font-family:"Chakra Petch",sans-serif; font-size:92px; font-weight:800; color:var(--text); line-height:1.05; margin-top:8px;
    font-variant-numeric:tabular-nums; text-shadow:0 0 38px rgba(255,176,32,.6), 0 4px 30px rgba(255,45,155,.4); }
  .edge-unit { color:var(--muted); font-size:15px; letter-spacing:2px; text-transform:uppercase; }
  .edge-hint { margin-top:30px; color:var(--faint); font-size:13px; }
  @keyframes edgePulse { 0%{ transform:scale(1); } 26%{ transform:scale(1.14); } 100%{ transform:scale(1); } }
  .edge-timer.pulse { animation:edgePulse .42s ease; }

  .edgebtn {
    width:100%; margin-top:10px; padding:12px; border-radius:11px; border:1px solid var(--panel-line);
    cursor:pointer; font-family:"Chakra Petch",sans-serif; font-size:14px; font-weight:700; letter-spacing:.06em; color:var(--text); background:var(--inset);
    font-variant-numeric:tabular-nums; transition:.15s;
  }
  .edgebtn:disabled { cursor:not-allowed; opacity:.6; }

  .ruinbtn {
    width:100%; margin-top:10px; padding:12px; border-radius:11px; border:1px solid var(--panel-line);
    cursor:pointer; font-family:"Chakra Petch",sans-serif; font-size:14px; font-weight:700; letter-spacing:.06em; color:var(--text); background:var(--inset);
    font-variant-numeric:tabular-nums; transition:.15s;
  }
  .ruinbtn:disabled { cursor:not-allowed; opacity:.6; }

  /* Drives the live Deny control (.session-btn.deny in base.css) during the climax window. */
  @keyframes denyPulse { 0%,100%{ box-shadow:0 0 18px rgba(255,45,155,.4); transform:scale(1); } 50%{ box-shadow:0 0 34px rgba(255,45,155,.75); transform:scale(1.02); } }

  /* ---- Ruin recovery overlay (heavier edge; magenta/violet) with a goo splat that plays
         while it's up and fades out with the overlay ---- */
  .ruin-overlay {
    position:fixed; inset:0; z-index:60; display:flex; align-items:center; justify-content:center;
    /* Translucent by design (see .edge-overlay): darken + tint the clip underneath. No backdrop
       blur. The goo splat and glow render on top; goo is toggleable for weak GPUs. */
    background:radial-gradient(55% 45% at 50% 44%, rgba(255,45,155,.14), transparent 70%), rgba(8,7,16,.74);
    overflow:hidden;
    opacity:0; transition:opacity .2s ease; cursor:pointer; text-align:center;
  }
  .ruin-overlay.show { opacity:1; }
  .ruin-overlay.ending { transition:opacity .9s ease; pointer-events:none; }   /* see .edge-overlay.ending */
  .ruin-overlay[hidden] { display:none; }
  /* no filter here (unlike .sum-goo): a drop-shadow on this layer re-ran a full-screen
     blur on every sim paint, and the ruin goo plays under a live countdown — post-session
     the summary goo has the frames to spare, mid-session the ruin doesn't */
  .ruin-goo { position:absolute; inset:0; width:100%; height:100%; pointer-events:none; z-index:1; }
  /* Throbber — bounded centered element, not full-screen (see .edge-glow for why). */
  .ruin-glow { position:absolute; inset:0; margin:auto; width:min(1000px,94vw); height:min(760px,80vh);
    pointer-events:none; z-index:0; transform-origin:50% 50%;
    will-change:transform, opacity; backface-visibility:hidden;
    background:radial-gradient(50% 50% at 50% 50%, rgba(255,45,155,.34), rgba(123,45,255,.16) 52%, transparent 76%);
    animation:ruinBeat 1.0s ease-out infinite; }
  @keyframes ruinBeat { 0%{transform:scale(1);opacity:.6;} 12%{transform:scale(1.05);opacity:.95;} 30%{transform:scale(1);opacity:.65;} 100%{transform:scale(1);opacity:.6;} }
  .ruin-vignette { position:absolute; inset:0; pointer-events:none; z-index:0;
    background:radial-gradient(farthest-side at 50% 46%, transparent 26%, rgba(6,4,12,.72) 100%); }
  .ruin-flash { position:absolute; inset:0; margin:auto; width:min(1000px,94vw); height:min(760px,80vh);
    pointer-events:none; opacity:0; z-index:1;
    background:radial-gradient(50% 50% at 50% 50%, rgba(255,45,155,.5), rgba(123,45,255,.18) 55%, transparent 76%); }
  .ruin-inner { position:relative; z-index:2; }
  .ruin-label { font-family:"Chakra Petch",sans-serif; color:var(--magenta); font-weight:800; letter-spacing:6px; font-size:15px;
    text-shadow:0 0 26px rgba(255,45,155,.8), 0 0 50px rgba(123,45,255,.45); }
  .ruin-timer { font-family:"Chakra Petch",sans-serif; font-size:92px; font-weight:800; color:var(--text); line-height:1.05; margin-top:8px;
    font-variant-numeric:tabular-nums; text-shadow:0 0 38px rgba(255,45,155,.6), 0 4px 30px rgba(123,45,255,.4); }
  .ruin-timer.pulse { animation:edgePulse .42s ease; }
  .ruin-unit { color:var(--muted); font-size:15px; letter-spacing:2px; text-transform:uppercase; }
  .ruin-hint { margin-top:30px; color:var(--faint); font-size:13px; }

  /* Freeze the edge/ruin beat + timer pulses for reduced-motion users — also a free perf win. */
  @media (prefers-reduced-motion: reduce) {
    .edge-glow, .ruin-glow { animation:none; opacity:.72; }
    .edge-timer.pulse, .ruin-timer.pulse { animation:none; }
  }

  /* ---- Climax finisher overlay (A4) ---- */
  .climax-overlay {
    position:fixed; inset:0; z-index:58; display:flex; align-items:center; justify-content:center; cursor:pointer;
    background:
      radial-gradient(60% 50% at 50% 46%, rgba(255,176,32,.28), transparent 70%),
      radial-gradient(120% 90% at 50% 120%, rgba(255,45,155,.26), transparent 60%),
      rgba(8,7,16,.84);
    opacity:1; transition:opacity .5s ease;
  }
  .climax-overlay[hidden] { display:none; }
  .climax-overlay.closing { opacity:0; pointer-events:none; }   /* see .edge-overlay.ending */
  .climax-burst { position:absolute; inset:0; width:100%; height:100%; pointer-events:none; }
  .climax-shock { position:absolute; top:46%; left:50%; width:140px; height:140px; margin:-70px 0 0 -70px;
    border-radius:50%; border:3px solid rgba(255,176,32,.8); pointer-events:none; opacity:0; }
  .climax-shock.go { animation:climaxShock 1.2s cubic-bezier(.2,.7,.3,1) forwards; }
  @keyframes climaxShock { 0%{ transform:scale(.2); opacity:1; border-color:rgba(255,255,255,.95); } 100%{ transform:scale(7); opacity:0; border-color:rgba(255,45,155,0); } }
  .climax-card { position:relative; z-index:2; text-align:center; padding:30px; }
  .climax-card.pop { animation:climaxPop .55s cubic-bezier(.2,.9,.3,1.4); }
  @keyframes climaxPop { from{ opacity:0; transform:scale(.8); } to{ opacity:1; transform:scale(1); } }
  .climax-kicker { font-family:"Chakra Petch",sans-serif; font-weight:800; letter-spacing:.5em; font-size:15px;
    color:var(--amber); text-shadow:0 0 24px rgba(255,176,32,.7), 0 0 50px rgba(255,45,155,.4); margin-left:.5em; }
  .climax-big { font-family:"Chakra Petch",sans-serif; font-weight:800; font-size:64px; line-height:1; letter-spacing:.04em; margin:8px 0 4px;
    background:linear-gradient(95deg,var(--amber),#ff8a3d 45%,var(--magenta)); -webkit-background-clip:text; background-clip:text; color:transparent;
    filter:drop-shadow(0 0 30px rgba(255,176,32,.55)) drop-shadow(0 0 40px rgba(255,45,155,.3)); }
  .climax-sub { font-family:"JetBrains Mono",monospace; font-size:12px; letter-spacing:.24em; text-transform:uppercase; color:var(--muted); margin-top:10px; }
  .climax-hint { margin-top:24px; color:var(--faint); font-size:12px; }

  /* ---- Denial moment: denied the climax finish — the session ends with no release ---- */
  .deny-overlay {
    position:fixed; inset:0; z-index:59; display:flex; align-items:center; justify-content:center; cursor:pointer;
    overflow-y:auto;   /* landscape: scroll instead of clipping the card top */
    background:
      radial-gradient(55% 45% at 50% 44%, rgba(255,45,155,.26), transparent 70%),
      radial-gradient(120% 90% at 50% 120%, rgba(123,45,255,.26), transparent 60%),
      rgba(8,7,16,.86);
    opacity:1; transition:opacity .5s ease;
  }
  .deny-overlay[hidden] { display:none; }
  .deny-overlay.closing { opacity:0; pointer-events:none; }   /* see .edge-overlay.ending */
  .deny-shock { position:absolute; top:44%; left:50%; width:130px; height:130px; margin:-65px 0 0 -65px;
    border-radius:50%; border:2px solid rgba(255,45,155,.8); pointer-events:none; opacity:0; }
  .deny-shock.go { animation:denyShock 1.1s cubic-bezier(.2,.7,.3,1) forwards; }
  @keyframes denyShock { 0%{ transform:scale(.2); opacity:.9; border-color:rgba(255,255,255,.9); } 100%{ transform:scale(6.5); opacity:0; border-color:rgba(123,45,255,0); } }
  .deny-card { position:relative; z-index:2; text-align:center; padding:30px; margin:auto; }
  .deny-card.pop { animation:climaxPop .55s cubic-bezier(.2,.9,.3,1.4); }
  .deny-kicker { font-family:"Chakra Petch",sans-serif; font-weight:800; letter-spacing:.5em; font-size:16px;
    color:var(--magenta); text-shadow:0 0 24px rgba(255,45,155,.8), 0 0 50px rgba(123,45,255,.4); margin-left:.5em; }
  .deny-sub { font-family:"JetBrains Mono",monospace; font-size:11px; letter-spacing:.24em; text-transform:uppercase; color:var(--muted); margin-top:10px; }
  .deny-big { font-family:"Chakra Petch",sans-serif; font-weight:800; font-size:60px; line-height:1; letter-spacing:.04em; margin:10px 0 4px;
    background:linear-gradient(95deg,var(--magenta),var(--violet) 55%,var(--cyan)); -webkit-background-clip:text; background-clip:text; color:transparent;
    filter:drop-shadow(0 0 26px rgba(255,45,155,.5)); }
  .deny-hint { margin-top:24px; color:var(--faint); font-size:12px; }

  /* ---- First-run gate / intro: 18+ self-attestation + a one-screen explainer ---- */
  .fr-overlay { position:fixed; inset:0; z-index:80; display:flex; align-items:center; justify-content:center; padding:20px; overflow:auto;
    background:radial-gradient(60% 50% at 50% 30%, rgba(123,45,255,.22), transparent 70%), rgba(8,7,16,.93);
    -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px); opacity:1; transition:opacity .4s ease; }
  .fr-overlay[hidden] { display:none; }
  .fr-overlay.closing { opacity:0; }
  .fr-card { width:100%; max-width:440px; margin:auto; padding:30px 28px;
    background:rgba(20,11,36,.9); border:1px solid var(--panel-line); border-radius:18px;
    -webkit-backdrop-filter:blur(18px); backdrop-filter:blur(18px);
    box-shadow:0 26px 80px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.05); animation:lvlPop .45s cubic-bezier(.2,.9,.3,1.3); }
  .fr-kicker { font-family:"Chakra Petch",sans-serif; font-weight:800; letter-spacing:6px; font-size:12px;
    background:linear-gradient(95deg,var(--magenta),var(--violet) 50%,var(--cyan)); -webkit-background-clip:text; background-clip:text; color:transparent; }
  .fr-title { font-family:"Chakra Petch",sans-serif; font-weight:700; font-size:22px; line-height:1.2; margin:10px 0 8px; color:var(--text); }
  .fr-lead { color:var(--muted); font-size:14px; line-height:1.55; margin:0 0 18px; }
  .fr-list { list-style:none; padding:0; margin:0 0 18px; }
  .fr-list li { padding:9px 0; border-bottom:1px solid rgba(51,33,92,.5); font-size:13.5px; line-height:1.5; }
  .fr-list li:last-child { border-bottom:none; }
  .fr-list li b { color:var(--cyan); font-weight:600; }
  .fr-list li span { color:var(--muted); }
  .fr-safety { font-size:12.5px; color:var(--amber); line-height:1.45; margin-bottom:18px; padding:10px 12px; border-radius:10px;
    background:rgba(255,176,32,.08); border:1px solid rgba(255,176,32,.3); }
  .fr-enter { width:100%; padding:14px; border:none; border-radius:11px; cursor:pointer;
    background:linear-gradient(95deg,var(--magenta),var(--violet)); color:#fff; font-weight:700; font-size:15px; box-shadow:0 0 24px rgba(255,45,155,.4); }
  .fr-enter:hover { filter:brightness(1.1); }
  .fr-legal { margin-top:14px; text-align:center; font-size:11px; color:var(--faint); line-height:1.6; }
  .fr-legal a { color:var(--muted); text-decoration:underline; }
  .fr-legal a:hover { color:var(--cyan); }
