/* ============================================================
   AGUANTE — aguante.app
   The interface runs cold at hour 0 and heats as the fast
   deepens. --heat is set from JS off the measured metabolic
   curve; it encodes state rather than decorating it.

   Design pass informed by Mobbin: pill CTAs (Locket, Manus),
   slim top progress + chip options (Visible, Life Reset),
   TLDR summary cards and divider-separated sections for
   long-form reading (Binance, Moonly).
   ============================================================ */
:root{
  color-scheme:dark;
  --bg:#08090B; --panel:#101317; --panel-2:#161A20; --panel-3:#1C222A;
  --line:#232931; --line-2:#2E3640;
  /* --txt-3 was #5D6975, which measured 3.1–3.5:1 against the panels — under
     the 4.5:1 minimum. That matters more in this app than most: it's used at
     night by people who are deliberately lightheaded. Raised once to #7C8693,
     which cleared every panel in use but sat at 4.34 on --panel-3; nothing
     puts small text there today, so it was a trap rather than a live bug.
     Now #818B97, clearing 4.5 on all four panels. */
  --txt:#F2F5F8; --txt-2:#A2AEBA; --txt-3:#818B97;
  /* Must match RAMP[0] in app.js — this is what shows before applyHeat runs. */
  --heat:#728DA7; --glow:rgba(114,141,167,.30);
  /* --heat as TEXT. Identical to --heat in the dark theme, where the ramp was
     already tuned to clear 4.5:1 on the panels. The light theme cannot reuse
     --heat for text — see the block below — so every heat-coloured LABEL reads
     this token and every heat-coloured FILL reads --heat. */
  --heat-ink:#728DA7;
  /* The accent SURFACE, as opposed to --heat the hue. In the dark theme a
     primary button is a light fill on dark ground and it carries a near-black
     label. The light theme has to invert that or the CTA is a mid-tone slab on
     pale paper — legible by the numbers, and visibly not the thing to press. */
  --fill:var(--heat);
  --good:#3FCF8E; --warn:#FFB020; --bad:#FF4D5E;
  /* Surfaces that were hardcoded before the light theme existed. */
  --track:#1A1F26;              /* the dial's unfilled ring */
  --txt-hot:#C6D0DA;            /* body copy inside a heat-tinted .card.hot */
  --ink:#07080A;                /* the label on --fill — see .btn */
  --redflag:#FFA0A8;
  --scrim:rgba(4,5,7,.62);
  --sq-a:#2A3138; --sq-b:#171B20;
  --shadow:rgba(0,0,0,.8);
  --press:rgba(255,255,255,.07); /* the flash under a finger */
  --sans:-apple-system,BlinkMacSystemFont,"SF Pro Display","Segoe UI","Helvetica Neue",Arial,sans-serif;
  --mono:ui-monospace,"SF Mono",SFMono-Regular,Menlo,Consolas,monospace;
  --safe-b:env(safe-area-inset-bottom,0px);
  --safe-t:env(safe-area-inset-top,0px);
  --r-pill:999px; --r-card:18px; --r-row:15px;
  --ease:cubic-bezier(.32,.72,0,1);
  /* Release curve. Slight overshoot, nothing playful — a button that
     bounces would be at war with everything this app says. */
  --spring:cubic-bezier(.2,1.32,.44,1);
  /* The one de-emphasis level for unit suffixes — the "h" on the timer, the
     "mg" on a dose, the "/28" under a count. It used to be seven inline
     values between .40 and .55, none of them checked, and every one of them
     put a MEANINGFUL character under the contrast floor: 2.05:1 for the "mg"
     on the electrolyte screen, in an app whose worst near-miss to date was a
     units bug that would have under-dosed sodium by a third.
     .78 is the lowest value that clears 3:1 for every one of them across both
     themes and the whole heat ramp, with margin. The hierarchy was never
     carried by the fade anyway — it is carried by size and weight, which is
     why raising it costs nothing. */
  --dim:.78;
}

/* ============================================================
   LIGHT
   ============================================================
   Daylight in the workshop, not a clinical white. The bone tint is
   deliberate: this app is opened at 3am by people who are deliberately
   lightheaded, and #FFFFFF at full field is hostile in that state. Cards
   go pure white so the elevation hierarchy inverts cleanly — in the dark
   theme panels are LIGHTER than the ground, here they are brighter than a
   warmer ground, and "raised" still reads as "raised".

   The semantic three had to be rebuilt, not reused. --good #3FCF8E
   measures 1.99:1 on white — it is a colour designed to glow on near-black
   and it is illegible here. Same for --warn and --bad. The light values
   are darkened to clear 4.5:1 against --panel-3, the darkest surface any
   of them sits on.

   --heat is the one token that cannot simply be re-picked, because it is
   both a fill and a label. See applyHeat() in app.js. */
:root[data-theme="light"]{
  color-scheme:light;
  --bg:#F5F2ED; --panel:#FFFFFF; --panel-2:#FBF8F3; --panel-3:#EFEAE2;
  --line:#E4DED4; --line-2:#CFC7BA;
  /* Verified against --panel-3, the worst case for dark ink: 4.61:1. */
  --txt:#14171C; --txt-2:#4C545F; --txt-3:#636B77;
  --heat:#728DA7; --glow:rgba(114,141,167,.16);
  /* Pre-JS default only: RAMP[0] scaled toward black. applyHeat replaces it
     with a value solved against the live ramp on the first tick. */
  --heat-ink:#3E4D5C;
  --fill:var(--heat-ink);
  --good:#0B6E43; --warn:#8A5A00; --bad:#C4243A;
  --track:#E4E0D9;
  --txt-hot:#3C444F;
  /* Flips with --fill. Also lands on --good and --bad, whose light values are
     dark enough that a near-black glyph would disappear into them. */
  --ink:#FBFAF8;
  --redflag:#B01F30;
  --scrim:rgba(20,23,28,.45);
  --sq-a:#E8E3DA; --sq-b:#D8D2C7;
  --shadow:rgba(38,32,24,.18);
  --press:rgba(0,0,0,.055);
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{height:100%}
body{margin:0;background:var(--bg);color:var(--txt);font-family:var(--sans);
  -webkit-font-smoothing:antialiased;overflow:hidden;
  text-rendering:optimizeLegibility}
button{font-family:inherit;cursor:pointer;border:0;background:none;color:inherit}
a{color:var(--heat-ink)}

#app{position:relative;width:100%;height:100%;max-width:520px;margin:0 auto;overflow:hidden}
.aura{position:fixed;inset:0;pointer-events:none;z-index:0;transition:background 1s var(--ease);
  background:radial-gradient(110% 55% at 50% 20%, var(--glow) 0%, transparent 68%)}

.view{position:absolute;inset:0;overflow-y:auto;overflow-x:hidden;z-index:1;
  padding:calc(var(--safe-t) + 18px) 20px calc(104px + var(--safe-b));
  display:none;flex-direction:column;gap:16px;-webkit-overflow-scrolling:touch}
.view.on{display:flex;animation:viewIn .34s var(--ease)}
.view::-webkit-scrollbar{width:0}
.view.full{padding-bottom:calc(32px + var(--safe-b))}
/* programmatic focus target for view changes — never a visible outline */
.view:focus{outline:none}
@keyframes viewIn{from{opacity:0;transform:translateY(9px)}to{opacity:1;transform:none}}

/* ---------- type ---------- */
h1{margin:0;font-size:32px;font-weight:800;letter-spacing:-.034em;line-height:1.08;text-wrap:balance}
h2{margin:0;font-size:24px;font-weight:800;letter-spacing:-.028em;line-height:1.13;text-wrap:balance}
h3{margin:0;font-size:18px;font-weight:800;letter-spacing:-.018em;text-wrap:balance}
p{margin:0;line-height:1.55}
.sub{color:var(--txt-2);font-size:14px;line-height:1.58}
.eyebrow{font:700 9.5px/1 var(--mono);letter-spacing:.2em;text-transform:uppercase;color:var(--txt-3)}
.num{font-family:var(--mono);font-weight:800;color:var(--heat-ink)}
.muted{color:var(--txt-3)}


/* ---------- brand ---------- */
.brandbar{display:flex;justify-content:space-between;align-items:center;flex:none;min-height:22px}
.wordmark{font:900 15px/1 var(--sans);letter-spacing:.32em;color:var(--heat-ink);
  text-shadow:0 0 22px var(--glow)}
.tagchip{font:700 10px/1 var(--mono);letter-spacing:.1em;color:var(--txt-3)}

/* ---------- welcome hero ----------
   A forged bar cooling: cold steel above, molten below. It is the heat ramp
   the whole app runs on, stated once at the door. Bled to the top edges and
   faded to black at the bottom so the headline sits on flat ground. */
.hero{position:relative;margin:calc(-1 * (var(--safe-t) + 18px)) -20px 4px;height:38vh;min-height:230px;
  max-height:330px;flex:none;overflow:hidden}
/* the molten edge is the whole point — frame it low and keep the fade off it */
.hero img{width:100%;height:100%;object-fit:cover;object-position:50% 84%;display:block}
.hero::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(8,9,11,.70) 0%,rgba(8,9,11,.10) 40%,
    color-mix(in srgb,var(--bg) 30%,transparent) 82%,var(--bg) 100%)}
.hero .mark{position:absolute;left:20px;bottom:16px;z-index:2;
  font:900 15px/1 var(--sans);letter-spacing:.32em;color:#F2F5F8;text-shadow:0 2px 18px rgba(0,0,0,.9)}

/* ---------- progress bar (onboarding) ---------- */
.pbar{height:3px;border-radius:2px;background:var(--line);overflow:hidden;flex:none}
.pbar i{display:block;height:100%;background:var(--heat-ink);border-radius:2px;
  transition:width .45s var(--ease);box-shadow:0 0 12px var(--glow)}

/* ---------- cards ---------- */
.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);padding:17px;flex:none}
.card.hot{border-color:color-mix(in srgb,var(--heat) 62%,transparent);
  background:linear-gradient(158deg,color-mix(in srgb,var(--heat) 14%,var(--panel)) 0%,var(--panel) 64%);
  box-shadow:0 0 34px -12px var(--glow)}
.card .top{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;gap:8px}

.chip{display:inline-flex;align-items:center;font:700 9px/1 var(--mono);letter-spacing:.11em;
  text-transform:uppercase;padding:6px 9px;border-radius:var(--r-pill);
  border:1px solid currentColor;white-space:nowrap}
.c-solid{color:var(--good)} .c-likely{color:var(--warn)} .c-myth{color:var(--bad)}

/* ---------- dial ---------- */
.dial{position:relative;width:248px;height:248px;margin:4px auto;flex:none}
.dial svg{position:absolute;inset:0;transform:rotate(-90deg)}

/* The arc carries a gradient built from three live CSS variables, so it keeps
   following the ramp on every tick rather than only on a full re-render. */
.dial .arc{transition:stroke-dashoffset .6s linear;filter:drop-shadow(0 0 11px var(--glow))}
.dial .sheen,.dial .pulse{opacity:0;transform-box:fill-box;transform-origin:center}

/* 48h+ — molten. The glow BREATHES; it does not flicker. A strobing timer
   would be ugly, and at these frequencies it is a genuine seizure risk. */
@keyframes ember{
  0%,100%{filter:drop-shadow(0 0 10px var(--glow))}
  50%{filter:drop-shadow(0 0 24px var(--glow)) drop-shadow(0 0 46px var(--glow))}
}
.dial.ember .arc{animation:ember 3.6s ease-in-out infinite}
.dial.ember .sheen{opacity:.34;animation:crawl 34s linear infinite}

/* 72h — tempered. Facets crawl the ring slowly enough to read as material
   rather than as motion. This is the finished state, so it is calm. */
.dial.tempered .arc{animation:ember 6s ease-in-out infinite}
.dial.tempered .sheen{opacity:.72;animation:crawl 22s linear infinite}
@keyframes crawl{to{transform:rotate(360deg)}}

/* Crossing into a new stage — one bloom, then gone. */
@keyframes bloomring{
  0%{opacity:.7;transform:scale(1)}
  100%{opacity:0;transform:scale(1.17)}
}
.dial.bloom .pulse{animation:bloomring 1.6s ease-out}

/* Someone who asked the OS not to animate gets the colour, not the motion.
   Every state stays visually distinct — nothing is carried by movement alone. */
@media (prefers-reduced-motion: reduce){
  .dial .arc,.dial .sheen,.dial .pulse{animation:none!important}
  .dial.ember .sheen{opacity:.3}
  .dial.tempered .sheen{opacity:.7}
}
.dial .core{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px}
.elapsed{font:800 47px/1 var(--mono);letter-spacing:-.04em;font-variant-numeric:tabular-nums;
  text-shadow:0 0 38px var(--glow)}
.elapsed small{font-size:18px;opacity:var(--dim);font-weight:600}
/* seconds are the proof of life — quiet, but always moving */
.elapsed em{font-style:normal;font-size:19px;opacity:var(--dim);font-weight:700;margin-left:7px;
  letter-spacing:0;vertical-align:2px}
.since{font:600 9.5px/1 var(--mono);letter-spacing:.14em;color:var(--txt-3);text-transform:uppercase}
.heatlabel{margin-top:8px;font:800 10px/1 var(--mono);letter-spacing:.17em;text-transform:uppercase;color:var(--heat-ink)}

/* ---------- buttons: pill, with real press feedback ---------- */
.btn{background:var(--fill);color:var(--ink);border-radius:var(--r-pill);padding:17px 22px;
  font:800 15px/1 var(--sans);letter-spacing:-.012em;width:100%;flex:none;
  display:flex;align-items:center;justify-content:center;gap:8px;
  transition:transform .3s var(--spring),box-shadow .3s var(--ease),filter .2s,opacity .2s;
  box-shadow:0 6px 22px -8px var(--glow)}
/* Down fast, back slow. A physical key falls under the finger in almost no time
   and takes its own time returning; matching the two speeds is most of why
   software buttons feel dead. The shadow collapses with it, so the button reads
   as pressed TOWARD the surface rather than merely shrinking. */
.btn:active{transform:scale(.958);filter:brightness(1.07);
  box-shadow:0 2px 9px -7px var(--glow);
  transition-duration:.06s,.06s,.06s,.2s}
.btn[disabled]{opacity:.32;box-shadow:none;transform:none}
.btn.ghost{background:transparent;color:var(--txt-2);border:1px solid var(--line-2);box-shadow:none}
.btn.ghost:active{background:var(--press);border-color:var(--fill)}
/* End fast lives at the bottom of a long view — it needs presence without
   competing with primary CTAs. Outlined in the live heat color. */
.btn.end{background:transparent;color:var(--txt);box-shadow:none;
  border:1.5px solid color-mix(in srgb,var(--fill) 60%,transparent)}
.btn.end:active{background:color-mix(in srgb,var(--heat) 12%,transparent)}
.btn.danger{background:transparent;color:var(--bad);
  border:1px solid color-mix(in srgb,var(--bad) 42%,transparent);box-shadow:none}
.btn.sm{padding:11px 17px;font-size:13px;width:auto}

/* sticky footer CTA with a fade, so content scrolls under it */
.sticky{position:sticky;bottom:0;padding:18px 0 4px;flex:none;
  background:linear-gradient(180deg,transparent,var(--bg) 34%);margin-top:auto}

/* ---------- rows ---------- */
.row{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r-row);padding:15px 16px;
  color:var(--txt);text-align:left;transition:border-color .18s,background .18s,transform .12s var(--ease)}
.row:active{transform:scale(.978);background:var(--press);transition-duration:.06s}
.row.sel{border-color:var(--fill);background:color-mix(in srgb,var(--heat) 9%,var(--panel))}
.row b{display:block;font-size:15px;font-weight:700;margin-bottom:3px;letter-spacing:-.012em}
.row span{font-size:12px;color:var(--txt-3);line-height:1.42;display:block}
.row .arw{font-size:17px;color:var(--txt-3);flex:none;transition:color .18s}
.row.sel .arw,.row:active .arw{color:var(--heat-ink)}
.rowstack{display:flex;flex-direction:column;gap:10px;flex:none}

/* selection check — Visible's pattern */
.tick{width:23px;height:23px;border-radius:50%;border:1.5px solid var(--line-2);flex:none;
  display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--ink);transition:.18s}
.row.sel .tick{background:var(--fill);border-color:var(--fill)}

/* pill chips for short options */
.chips{display:flex;flex-wrap:wrap;gap:9px;flex:none}
.chipbtn{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-pill);
  padding:13px 19px;font:700 14px/1 var(--sans);color:var(--txt);letter-spacing:-.01em;
  transition:transform .3s var(--spring),background .18s,border-color .18s,color .18s}
.chipbtn:active{transform:scale(.94);transition-duration:.06s}
.chipbtn.sel{background:var(--fill);border-color:var(--fill);color:var(--ink)}

/* ---------- inputs ---------- */
label.fld{display:flex;flex-direction:column;gap:7px;flex:none}
label.fld > span{font:700 9.5px/1 var(--mono);letter-spacing:.15em;text-transform:uppercase;color:var(--txt-3)}
input[type=text],input[type=number],input[type=datetime-local],select{
  background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:16px;
  color:var(--txt);font:600 16px/1 var(--sans);width:100%;appearance:none;transition:border-color .18s}
input:focus,select:focus{outline:none;border-color:var(--fill);box-shadow:0 0 0 3px var(--glow)}
.pair{display:grid;grid-template-columns:1fr 1fr;gap:11px;flex:none}

/* ---------- safety checks ---------- */
.check{display:flex;gap:13px;align-items:flex-start;background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r-row);padding:15px;width:100%;text-align:left;color:var(--txt);flex:none;
  transition:.18s var(--ease)}
.check:active{transform:scale(.982);background:var(--press);transition-duration:.06s}
.check.on{border-color:var(--bad);background:color-mix(in srgb,var(--bad) 9%,var(--panel))}
.check .box{width:22px;height:22px;border-radius:7px;border:1.5px solid var(--line-2);flex:none;margin-top:1px;
  display:flex;align-items:center;justify-content:center;font-size:13px;color:var(--ink);transition:.18s}
.check.on .box{background:var(--bad);border-color:var(--bad)}
.check.on.safe{border-color:var(--good);background:color-mix(in srgb,var(--good) 9%,var(--panel))}
.check.on.safe .box{background:var(--good);border-color:var(--good)}
.check b{display:block;font-size:14.5px;font-weight:700;margin-bottom:3px}
.check span{font-size:11.5px;color:var(--txt-3);line-height:1.42;display:block}

/* ---------- verdict ---------- */
.verdict{border-left:3px solid var(--heat);background:var(--panel-2);
  border-radius:0 var(--r-card) var(--r-card) 0;padding:16px;flex:none}
.verdict .lbl{font:700 9.5px/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;
  color:var(--heat-ink);margin-bottom:9px}
.verdict .act{font-size:17px;font-weight:800;margin-bottom:8px;letter-spacing:-.018em;text-wrap:balance;line-height:1.24}
.verdict .why{font-size:13px;color:var(--txt-2);line-height:1.6}
.redflag,.softnote{margin-top:13px;padding-top:13px;border-top:1px solid var(--line);font-size:12px;line-height:1.5}
.redflag{color:var(--redflag)} .redflag b{color:var(--bad)}
.softnote{color:var(--txt-2)} .softnote b{color:var(--good)}

.grid2{display:grid;grid-template-columns:1fr 1fr;gap:10px;flex:none}
.sym{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-row);padding:14px 13px;
  color:var(--txt);text-align:left;transition:.18s var(--ease)}
.sym:active{transform:scale(.955);transition-duration:.06s}
.sym.sel{border-color:var(--fill);background:color-mix(in srgb,var(--heat) 9%,var(--panel))}
/* A selected surface is tinted with the live heat, and past 60h that heat is
   nearly white — enough to lift the panel and drop --txt-3 to 4.44:1 on the
   sub-label. Selected items have earned more emphasis anyway, so they take
   --txt-2, which clears it at every point on the ramp. */
.sym.sel span,.row.sel span{color:var(--txt-2)}
.sym b{display:block;font-size:14px;font-weight:700;margin-bottom:4px;letter-spacing:-.01em}
.sym span{font-size:11px;color:var(--txt-3);line-height:1.38;display:block}

/* the brand word doing its warm job */
.holdon{border:1px solid color-mix(in srgb,var(--heat) 55%,transparent);border-radius:var(--r-card);
  padding:20px 17px;text-align:center;flex:none;
  background:linear-gradient(168deg,color-mix(in srgb,var(--heat) 16%,var(--panel)),var(--panel));
  box-shadow:0 0 40px -14px var(--glow)}
.holdon .word{font:900 26px/1 var(--sans);letter-spacing:.18em;color:var(--heat-ink);
  text-shadow:0 0 30px var(--glow);margin-bottom:10px}
.holdon .gloss{font-size:13px;color:var(--txt-2);line-height:1.6}

/* ---------- breathing ----------
   The orb is driven from JS with an explicit transition duration per phase
   rather than a CSS keyframe loop, because the phase lengths differ per
   protocol and a keyframe can't retime itself mid-cycle. */
.breathwrap{position:relative;height:300px;display:flex;align-items:center;justify-content:center;flex:none}
.orb{width:220px;height:220px;border-radius:50%;position:relative;
  background:radial-gradient(circle at 50% 45%,
    color-mix(in srgb,var(--heat) 42%,transparent) 0%,
    color-mix(in srgb,var(--heat) 12%,transparent) 55%, transparent 72%);
  border:1.5px solid color-mix(in srgb,var(--heat) 55%,transparent);
  transform:scale(.44);
  transition:transform linear;
  box-shadow:0 0 60px -12px var(--glow)}
.orb::after{content:"";position:absolute;inset:14px;border-radius:50%;
  border:1px solid color-mix(in srgb,var(--heat) 26%,transparent)}
.breathlabel{position:absolute;inset:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:7px;pointer-events:none}
.breathlabel b{font:800 22px/1 var(--sans);letter-spacing:-.02em}
.breathlabel span{font:700 10px/1 var(--mono);letter-spacing:.2em;text-transform:uppercase;color:var(--txt-3)}
/* Centred: in the breathing view this sits inside a flex-centred label, but
   Settle and PMR append it straight to the view, where it was stranded against
   the left edge under a centred figure. */
.breathcount{font:800 46px/1 var(--mono);letter-spacing:-.03em;font-variant-numeric:tabular-nums;text-align:center;
  text-shadow:0 0 30px var(--glow)}
/* Reduced motion: hold the orb still and let the words carry the pacing.
   Someone who asked the OS not to animate should not get a pulsing circle. */
@media (prefers-reduced-motion: reduce){
  .orb{transform:scale(.8)!important;transition:none!important}
}

/* ---------- settle ----------
   Decentering, drawn rather than decorated. The steps on screen say a thought
   arrives, you name it, and you let it leave on its own — "you can watch a
   sentence go by, you don't have to board it." So the centre holds still and
   the disturbances travel OUTWARD and dissolve. Rings that converged on the
   middle would be drawing the opposite instruction.

   Three of them on a nine-second loop, not many on a fast one. Sparse and slow
   reads as calm; dense and quick reads as agitation, which is precisely the
   state the practice is for. The centre's own drift is 11s and 4.5% — present
   if you look for it, never a pacer. This must not be mistaken for the
   breathing orb: nobody should end up matching their breath to it.

   Water is not a borrowed metaphor here. Quenching is the step between molten
   and tempered, and tempered blue is where this app's ramp ends at 72h. */
.stillwrap{position:relative;height:300px;display:flex;align-items:center;justify-content:center;flex:none}
.still{width:130px;height:130px;border-radius:50%;position:relative;z-index:1;
  background:radial-gradient(circle at 50% 46%,
    color-mix(in srgb,var(--heat) 32%,transparent) 0%,
    color-mix(in srgb,var(--heat) 9%,transparent) 58%, transparent 74%);
  border:1px solid color-mix(in srgb,var(--heat) 44%,transparent);
  box-shadow:0 0 54px -14px var(--glow);
  animation:stilldrift 11s ease-in-out infinite}
@keyframes stilldrift{0%,100%{transform:scale(1)}50%{transform:scale(1.045)}}
.ripple{position:absolute;left:50%;top:50%;width:130px;height:130px;margin:-65px 0 0 -65px;
  border-radius:50%;border:1px solid var(--heat);opacity:0;pointer-events:none;
  animation:ripple 9s linear infinite}
.ripple:nth-child(2){animation-delay:3s}
.ripple:nth-child(3){animation-delay:6s}
/* linear, with the deceleration written into the keyframe SPACING instead of a
   bezier — a real ripple slows as it spreads, and an easing curve applied to
   the whole animation was front-loading it so hard that each ring did its
   visible travelling in the first second and then crept for eight more.
   It fades well before the edge: it leaves on its own, which is the line. */
@keyframes ripple{
  0%  {transform:scale(1);    opacity:0}
  8%  {opacity:.42}
  40% {transform:scale(1.72); opacity:.20}
  70% {transform:scale(2.02); opacity:.06}
  100%{transform:scale(2.15); opacity:0}
}
/* Reduced motion: the composition still has to READ. Held at the three radii
   the loop would have passed through, so "something moved outward from here"
   survives without anything moving. The blanket rule above already stops the
   animation; without these the rings would sit at opacity 0 and vanish. */
@media (prefers-reduced-motion: reduce){
  .ripple{opacity:.22}
  .ripple:nth-child(2){transform:scale(1.4);opacity:.14}
  .ripple:nth-child(3){transform:scale(1.8);opacity:.08}
}

/* ---------- end-fast sheet ---------- */
.sheetback{position:fixed;inset:0;background:var(--scrim);backdrop-filter:blur(3px);
  z-index:80;display:flex;align-items:flex-end;
  padding:14px;padding-bottom:calc(14px + var(--safe-b));animation:sheetin .18s var(--ease)}
.sheet{background:var(--panel-2);border:1px solid var(--line-2);border-radius:22px;
  padding:22px 18px 18px;width:100%;display:flex;flex-direction:column}
@keyframes sheetin{from{opacity:0}to{opacity:1}}

/* ---------- affiliate ---------- */
.aff{display:flex;gap:12px;align-items:center;background:var(--panel-2);border:1px dashed var(--line-2);
  border-radius:var(--r-row);padding:13px;flex:none}
.aff .sq{width:42px;height:42px;border-radius:11px;flex:none;background:linear-gradient(140deg,var(--sq-a),var(--sq-b));
  border:1px solid var(--line);display:flex;align-items:center;justify-content:center;font-size:18px}
.aff .m b{display:block;font-size:13px;font-weight:700}
.aff .m span{font-size:11px;color:var(--txt-3);line-height:1.4}
/* The paid-link disclosure lives in here. It was the least legible text in the
   app at 3.26:1 on 10px, which is a poor look for the one line that has to be
   "clear and conspicuous" — and a poor look for a brand built on not hiding
   things. Now uses the audited token and a readable size. */
.disc{font:500 10.5px/1.6 var(--mono);color:var(--txt-3);margin-top:9px;flex:none}

/* ---------- stats ---------- */
.statgrid{display:grid;grid-template-columns:1fr 1fr;gap:10px;flex:none}
.stat{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);padding:15px}
.stat .k{font:700 9px/1 var(--mono);letter-spacing:.15em;text-transform:uppercase;color:var(--txt-3)}
.stat .v{font:800 27px/1 var(--mono);font-variant-numeric:tabular-nums;margin-top:9px;letter-spacing:-.03em}
.stat .v small{font-size:13px;opacity:var(--dim);font-weight:600}
.bars{display:flex;align-items:flex-end;gap:6px;height:98px;padding-top:8px;flex:none}
.bars .b{flex:1;background:var(--heat-ink);border-radius:5px 5px 2px 2px;min-height:5px;
  animation:barIn .5s var(--ease) backwards}
.bars .b.miss{background:var(--line-2)}
@keyframes barIn{from{height:4px!important;opacity:.3}}
.barlabels{display:flex;gap:6px;flex:none}
.barlabels span{flex:1;text-align:center;font:600 9px/1 var(--mono);color:var(--txt-3)}
.meter{height:8px;border-radius:5px;background:var(--line);overflow:hidden;flex:none}
.meter i{display:block;height:100%;background:var(--heat-ink);border-radius:5px;
  transition:width .7s var(--ease);box-shadow:0 0 12px var(--glow)}

/* ---------- history ---------- */
.hrow{display:flex;align-items:center;gap:13px;background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r-row);padding:14px 16px;width:100%;text-align:left;color:var(--txt);flex:none;
  transition:.18s var(--ease)}
.hrow:active{transform:scale(.978);border-color:var(--fill);transition-duration:.06s}
.hrow .h{font:800 18px/1 var(--mono);font-variant-numeric:tabular-nums;min-width:56px;letter-spacing:-.03em}
.hrow .meta b{display:block;font-size:13px;font-weight:700}
.hrow .meta span{font-size:11px;color:var(--txt-3)}
.hrow .dot{width:8px;height:8px;border-radius:50%;flex:none}

/* ---------- empty state ---------- */
.empty{display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;gap:11px;padding:46px 18px;flex:none}
.empty .glyph{width:66px;height:66px;border-radius:50%;border:1.5px dashed var(--line-2);
  display:flex;align-items:center;justify-content:center;font-size:25px;opacity:.6;margin-bottom:4px}
.empty b{font-size:17px;font-weight:800;letter-spacing:-.02em}
.empty p{font-size:13.5px;color:var(--txt-3);max-width:30ch;line-height:1.55}

/* ---------- long-form reading (Moonly / Binance patterns) ---------- */
.artmeta{display:flex;align-items:center;gap:9px;font:600 11px/1 var(--mono);color:var(--txt-3);flex:none}
.artmeta i{width:3px;height:3px;border-radius:50%;background:var(--txt-3);display:block}
.tldr{border:1px solid color-mix(in srgb,var(--heat) 40%,transparent);border-radius:var(--r-card);
  padding:16px;background:color-mix(in srgb,var(--heat) 7%,var(--panel));flex:none}
.tldr .h{display:flex;align-items:center;gap:7px;font:800 9.5px/1 var(--mono);letter-spacing:.17em;
  text-transform:uppercase;color:var(--heat-ink);margin-bottom:11px}
.tldr p{font-size:13px;line-height:1.6;color:var(--txt-2)}
.tldr b{color:var(--txt)}

.article{font-size:15px;line-height:1.68;color:var(--txt-2);flex:none}
.article p{margin:0 0 15px}
.article b{color:var(--txt);font-weight:700}
.article h4{margin:26px 0 11px;font-size:16.5px;font-weight:800;letter-spacing:-.02em;color:var(--txt);
  padding-top:22px;border-top:1px solid var(--line)}
.article h4:first-child{border-top:0;padding-top:0;margin-top:0}
.article ul{margin:0 0 15px;padding-left:20px}
.article li{margin-bottom:9px}
.article ul.flags{list-style:none;padding-left:0}
.article ul.flags li{padding-left:22px;position:relative;margin-bottom:11px}
.article ul.flags li::before{content:"";position:absolute;left:2px;top:8px;width:7px;height:7px;
  border-radius:2px;background:var(--bad)}
.article table{width:100%;border-collapse:collapse;margin:0 0 17px;font-size:12px}
/* headers must not wrap — the container scrolls instead, or "FAST LENGTH"
   breaks across two lines and collides with the row beneath it */
.article th{text-align:left;font:700 9px/1.4 var(--mono);letter-spacing:.1em;text-transform:uppercase;
  color:var(--txt-3);padding:9px 9px;border-bottom:1px solid var(--line-2);white-space:nowrap}
.article td{padding:10px 9px;border-bottom:1px solid var(--panel-2);vertical-align:top}
.article td:first-child{color:var(--txt)}
.scrollx{overflow-x:auto;flex:none}

/* ---------- block screen ---------- */
.blockwrap{border:1px solid color-mix(in srgb,var(--bad) 48%,transparent);border-radius:var(--r-card);
  padding:20px;background:color-mix(in srgb,var(--bad) 8%,var(--panel));flex:none}
.blockwrap h2{color:var(--bad)}

/* ---------- tabs ---------- */
.tabs{position:absolute;bottom:0;left:0;right:0;z-index:50;
  padding:0 8px calc(20px + var(--safe-b));height:calc(84px + var(--safe-b));
  background:linear-gradient(180deg,color-mix(in srgb,var(--bg) 0%,transparent),
    color-mix(in srgb,var(--bg) 96%,transparent) 38%);
  display:flex;align-items:flex-end;justify-content:space-around;
  border-top:1px solid color-mix(in srgb,var(--line) 45%,transparent);backdrop-filter:blur(14px)}
.tabs.hide{display:none}
.tab{color:var(--txt-3);font:700 9px/1 var(--mono);letter-spacing:.09em;
  text-transform:uppercase;display:flex;flex-direction:column;align-items:center;gap:7px;
  padding:9px 6px;flex:1;transition:color .2s}
.tab .ic{font-size:17px;opacity:.45;transition:transform .3s var(--spring),opacity .22s,filter .22s}
.tab:active .ic{transform:scale(.86);transition-duration:.06s}
.tab.on{color:var(--heat-ink)}
.tab.on .ic{opacity:1;transform:translateY(-2px);filter:drop-shadow(0 0 9px var(--glow))}

/* ---------- toast ---------- */
.toast{position:fixed;left:50%;bottom:calc(112px + var(--safe-b));transform:translateX(-50%) translateY(16px);
  background:var(--panel-3);border:1px solid color-mix(in srgb,var(--fill) 50%,transparent);
  border-radius:var(--r-pill);padding:13px 20px;font:700 13px/1 var(--sans);z-index:200;
  opacity:0;pointer-events:none;transition:.28s var(--ease);white-space:nowrap;
  box-shadow:0 10px 30px -10px var(--shadow)}
.toast.on{opacity:1;transform:translateX(-50%) translateY(0)}

/* Keyboard focus was invisible — there was no :focus-visible rule at all, so
   anyone navigating by keyboard had no idea where they were. */
:focus-visible{outline:2px solid var(--heat-ink);outline-offset:3px;border-radius:4px}
button:focus-visible,.row:focus-visible,.sym:focus-visible,.chipbtn:focus-visible,.check:focus-visible{
  outline:2px solid var(--heat-ink);outline-offset:3px}

@media (prefers-reduced-motion: reduce){*{transition:none!important;animation:none!important}}
/* The blanket rule above also kills every press state, and a control that does
   not answer the finger is a worse outcome than a 60ms scale. Reduced motion
   asks for no MOVEMENT — not for no feedback. So the transforms go and the
   colour response stays, applied instantly. */
@media (prefers-reduced-motion: reduce){
  .btn:active,.row:active,.chipbtn:active,.check:active,.sym:active,
  .hrow:active,.tab:active .ic{transform:none!important}
  .btn:active{filter:brightness(1.14)}
  .btn.ghost:active,.row:active,.check:active,.chipbtn:active,.sym:active{background:var(--press)}
}
