/* Podivm app stylesheet.
 *
 * Shared by auth.html and app.html. The landing page keeps its own inlined
 * styles because it is driven by a 3D story that has nothing to do with the app;
 * this file starts from the same tokens so the two always look like one product.
 *
 * Layout: a top bar plus a left rail on wide screens, and a bottom tab bar on
 * phones. Every screen is a <section class="view"> rendered by app.js.
 */

:root{
  color-scheme: dark;
  --ink:#0E1428;
  --navy:#171F3A;
  --navy-2:#1F2949;
  --navy-3:#2A3560;
  --paper:#F3F1EC;
  --dim:#AEB4CC;
  --orange:#FF5A1F;
  --orange-soft:#FF8557;
  --gold:#E9B44C;
  --gold-deep:#A9752A;
  --ok:#43D19E;
  --warn:#FFB020;
  --bad:#FF6B6B;
  /* Semantic colours, one meaning each, so nothing has to be guessed from a shade:
       premium  gold is Podivm Pro and nothing else - a paid tier that shares a
                colour with medals or tips reads as a paywall everywhere
       flame    the orange guy, your streak, and the primary action
       info     a label or an explanation (eyebrows, the engine note, the numbers
                panel): information, not a warning
       ok       measured, done, improved
       warn     needs attention, or an approximate reading
       bad      a measurement that failed
     Green and amber already meant the last two; the first three are what stopped
     gold from meaning six things at once. */
  --premium:var(--gold);
  --premium-soft:#F2C562;
  --premium-ink:#2A1F08;
  --info:#7FB2FF;
  --info-soft:rgba(127,178,255,.14);
  --flame:#FF7A2F;
  --display:"Bricolage Grotesque","Avenir Next","Helvetica Neue",Arial,sans-serif;
  --body:"Instrument Sans","Helvetica Neue",Arial,sans-serif;
  --r-lg:28px; --r-md:20px; --r-sm:12px; --r-xs:9px;
  --line:rgba(255,255,255,.12);
  --line-strong:rgba(255,255,255,.2);
  --shadow:0 24px 60px -32px rgba(0,0,0,.85);
  --bar-h:72px;
  --rail-w:236px;
  --ease:cubic-bezier(.2,.8,.2,1);
}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{
  margin:0;background:var(--ink);color:var(--paper);font-family:var(--body);
  font-size:1rem;line-height:1.6;-webkit-font-smoothing:antialiased;
  overflow-x:clip;min-height:100vh;
  padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px);
}
a{color:inherit}
h1,h2,h3,h4{font-family:var(--display);font-weight:800;letter-spacing:-.03em;line-height:1.04;margin:0}
p{margin:0}
:focus-visible{outline:3px solid var(--orange);outline-offset:3px;border-radius:8px}
button{font:inherit}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
[hidden]{display:none!important}
.skip{position:absolute;left:12px;top:-64px;background:var(--orange);color:var(--navy);padding:10px 16px;border-radius:8px;z-index:200;font-weight:600;text-decoration:none}
.skip:focus{top:12px}

/* the same film grain as the landing page, so the app feels like the same room */
body::after{content:"";position:fixed;inset:0;pointer-events:none;z-index:90;opacity:.07;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}

/* ---------------------------------------------------------------- buttons -- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:9px;
  background:var(--orange);color:var(--navy);font-weight:600;text-decoration:none;
  padding:14px 24px;border-radius:999px;border:0;font-size:1rem;cursor:pointer;
  transition:background .2s,transform .12s;text-align:center}
.btn:hover{background:var(--orange-soft)}
.btn:active{transform:translateY(1px)}
.btn[disabled],.btn[aria-disabled="true"]{opacity:.55;cursor:progress;transform:none}
.btn.ghost{background:transparent;color:var(--paper);border:1px solid var(--line-strong)}
.btn.ghost:hover{background:rgba(255,255,255,.08)}
.btn.gold{background:var(--gold);color:#2A1F08}
.btn.gold:hover{background:#F2C562}
.btn.quiet{background:transparent;color:var(--dim);border:0;padding:8px 4px;text-decoration:underline;text-underline-offset:4px}
.btn.quiet:hover{color:var(--paper);background:none}
.btn.small{padding:10px 18px;font-size:.95rem}
.btn.block{width:100%}
.btn.google{background:#fff;color:#1F1F1F;border:1px solid rgba(0,0,0,.08)}
.btn.google:hover{background:#F1F1F1}
.btn.google svg{width:20px;height:20px;flex:none}
.btn.danger{background:transparent;color:var(--bad);border:1px solid rgba(255,107,107,.5)}
.btn.danger:hover{background:rgba(255,107,107,.12)}
.btn-row{display:flex;flex-wrap:wrap;gap:12px}
.btn-row .btn{flex:1 1 auto}

/* ------------------------------------------------------------------ shell -- */
.bar{position:sticky;top:0;z-index:60;background:rgba(14,20,40,.92);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
.bar .inner{display:flex;align-items:center;justify-content:space-between;gap:20px;height:var(--bar-h);
  width:min(1240px,100% - 40px);margin-inline:auto}
.wordmark{display:inline-flex;align-items:center;gap:10px;text-decoration:none}
.wordmark img{height:38px;width:auto;display:block}
/* The header deliberately has no navigation: the rail owns it on a wide screen and
   the tab bar owns it on a phone. A third copy of the same four links was noise. */
.who{display:flex;align-items:center;gap:12px}
/* The streak is a flame, not a star, and it is orange: the same colour as the guy
   who counts it. Gold now belongs to Pro alone, and a gold star next to a gold Pro
   badge asked people to tell two premium things apart that were never related. */
.who .streak{display:inline-flex;align-items:center;gap:6px;font-weight:600;font-size:.9rem;
  background:rgba(255,90,31,.14);color:var(--flame);border:1px solid rgba(255,90,31,.35);
  padding:5px 12px 5px 10px;border-radius:999px}
.who .streak svg{width:14px;height:14px;flex:none;fill:currentColor}
.who .streak .flame{transform-origin:50% 90%;animation:flicker 2.4s ease-in-out infinite alternate}
@keyframes flicker{from{transform:scale(1) rotate(-1deg)}to{transform:scale(1.08) rotate(2deg)}}
.avatar{width:38px;height:38px;border-radius:50%;display:grid;place-items:center;background:var(--navy-3);
  color:var(--paper);font-weight:600;font-size:.9rem;border:1px solid var(--line-strong);text-decoration:none;
  cursor:pointer;padding:0}
.avatar:hover{border-color:var(--orange)}
/* The account menu, hanging off the avatar. It is where the profile, the progress
   page, the tier and the motion switch are listed together, so the circle stops
   being a door that only goes one place. */
.who-menu{position:relative}
.who-panel{position:absolute;right:0;top:calc(100% + 10px);z-index:80;min-width:236px;
  display:grid;gap:2px;padding:8px;border-radius:var(--r-sm);background:var(--navy-2);
  border:1px solid var(--line-strong);box-shadow:var(--shadow)}
.who-panel[hidden]{display:none}
.who-panel-head{display:grid;gap:1px;padding:8px 11px 11px;border-bottom:1px solid var(--line);margin-bottom:6px}
.who-panel-head strong{font-family:var(--display);font-size:1rem;letter-spacing:-.01em}
.who-panel-head span{color:var(--dim);font-size:.82rem;overflow-wrap:anywhere}
.who-panel a,.who-panel button{display:block;width:100%;text-align:left;padding:10px 12px;
  border-radius:var(--r-xs);background:none;border:0;color:var(--paper);text-decoration:none;
  font:inherit;font-weight:500;cursor:pointer}
.who-panel a:hover,.who-panel button:hover{background:var(--navy-3)}

/* The streak is a button now, because behind it is the thing it is counting: today's
   goals, this week, and the longest run. The ring is the day - it closes when the day's
   practice has happened - and it is the only score a streak screen needs, because
   turning up is not a measurement of anything except turning up. */
.who .streak{cursor:pointer;font:inherit;font-weight:600;font-size:.9rem;gap:7px}
.who .streak b{font-variant-numeric:tabular-nums}
.who .streak:hover{border-color:rgba(255,90,31,.6);background:rgba(255,90,31,.2)}
.ring.small circle{stroke-width:3}
.streak-menu .who-panel{min-width:290px;max-width:min(336px,calc(100vw - 28px));gap:13px}
.streak-top{display:flex;align-items:center;gap:14px}
.streak-top .ring{flex:none}
.streak-goals{display:grid;gap:7px;min-width:0}
.streak-goals>strong{font-family:var(--display);font-size:.98rem;letter-spacing:-.01em}
/* A goal row: an empty circle, and a green tick inside it once it has happened. The
   same shape on the streak panel and on Today, because they are the same two facts. */
.goal{display:flex;align-items:center;gap:9px;font-size:.88rem;color:var(--dim);min-width:0}
.goal i{flex:none;width:16px;height:16px;border-radius:50%;border:2px solid var(--line-strong);
  display:grid;place-items:center}
.goal.on{color:var(--paper)}
.goal.on i{background:var(--ok);border-color:var(--ok)}
.goal.on i::after{content:"";width:6px;height:3px;border-left:2px solid #06301F;
  border-bottom:2px solid #06301F;transform:rotate(-45deg) translate(1px,-1px)}
.goal strong{font-weight:600}
.goal em{font-style:normal;font-size:.8rem;color:var(--dim)}
.streak-week{display:flex;gap:5px}
.streak-week .wd{flex:1 1 0;display:grid;place-items:center;height:32px;border-radius:var(--r-xs);
  background:var(--navy-3);color:var(--dim);font-size:.76rem;font-weight:600}
.streak-week .wd.on{background:var(--ok);color:#06301F}
.streak-week .wd.now{box-shadow:inset 0 0 0 2px var(--orange)}
.streak-count{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  padding-top:11px;border-top:1px solid var(--line)}
.streak-count strong{font-family:var(--display);font-size:1.05rem}
.streak-count span{color:var(--dim);font-size:.8rem;text-align:right}
.streak-panel p{margin:0}
.who-panel a.streak-go{display:flex;align-items:center;justify-content:center;gap:8px;
  padding:11px 12px;border-radius:var(--r-xs);background:var(--orange);color:var(--navy);
  font-weight:700;text-align:center}
.who-panel a.streak-go:hover{background:var(--orange-soft)}
/* The state of a switch is a label, so it is blue, the same as any other label. */
.who-panel button b{color:var(--info);font-weight:700}

.shell{display:grid;grid-template-columns:var(--rail-w) minmax(0,1fr);gap:36px;
  width:min(1240px,100% - 40px);margin:0 auto;padding:34px 0 96px;align-items:start}
.rail{position:sticky;top:calc(var(--bar-h) + 22px);display:grid;gap:6px}
.rail a{display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:var(--r-sm);
  color:var(--dim);text-decoration:none;font-weight:500;transition:background .18s,color .18s}
.rail a:hover{background:var(--navy-2);color:var(--paper)}
.rail a[aria-current="page"]{background:var(--navy-2);color:var(--paper);box-shadow:inset 3px 0 0 var(--orange)}
.rail a svg{width:20px;height:20px;flex:none;opacity:.9}
/* The Pro offer, in the rail under the navigation. Gold because it is the paid
   tier; it is the only gold thing on an ordinary screen. */
.rail-pro{display:grid;gap:2px;margin-top:16px;padding:13px 15px;border-radius:var(--r-sm);
  text-decoration:none;background:linear-gradient(150deg,rgba(233,180,76,.16),rgba(233,180,76,.04));
  border:1px solid rgba(233,180,76,.34);transition:border-color .18s,transform .12s}
.rail-pro:hover{border-color:rgba(233,180,76,.6);transform:translateY(-1px)}
.rail-pro strong{font-family:var(--display);font-size:.95rem;color:var(--premium);letter-spacing:-.01em}
.rail-pro span{font-size:.78rem;color:var(--dim);line-height:1.35}
.rail .rail-foot{margin-top:18px;padding-top:18px;border-top:1px solid var(--line);color:var(--dim);font-size:.86rem}
.rail .rail-foot strong{color:var(--paper);display:block;font-family:var(--display);font-size:1rem;letter-spacing:-.01em}
main{min-width:0}
main:focus{outline:none}

.tabs{position:fixed;left:0;right:0;bottom:0;z-index:70;display:none;
  background:rgba(14,20,40,.96);backdrop-filter:blur(10px);border-top:1px solid var(--line);
  padding-bottom:env(safe-area-inset-bottom,0px)}
.tabs a{flex:1;display:grid;justify-items:center;gap:3px;padding:9px 4px 8px;color:var(--dim);
  text-decoration:none;font-size:.7rem;font-weight:500;min-height:56px}
.tabs a svg{width:22px;height:22px}
.tabs a[aria-current="page"]{color:var(--orange)}

/* ------------------------------------------------------------------- text -- */
/* The demo note, one line with the detail folded away: it is the first thing on
   every screen of a local demo, and five lines of small print above the thing you
   came to look at is the wrong trade. */
.demo-note{margin:14px auto 0;width:min(1240px,100% - 40px)}
.demo-note p{margin:10px 0 0;font-size:.9rem}
.demo-note summary{cursor:pointer;color:var(--info);font-weight:600;display:inline}
.demo-note summary:hover{text-decoration:underline;text-underline-offset:3px}
.demo-note code{background:rgba(255,255,255,.07);border-radius:5px;padding:1px 5px;font-size:.9em}
@media (max-width:560px){.demo-note{width:calc(100% - 28px)}}

/* A section label is information, so it is blue. It used to be gold, which made
   every screen look like it was advertising something. */
.eyebrow{font-size:.78rem;letter-spacing:.14em;text-transform:uppercase;color:var(--info);font-weight:600;margin-bottom:10px}
h1.view-title{font-size:clamp(1.7rem,3.4vw,2.5rem)}
.lede{color:var(--dim);font-size:1.05rem;max-width:58ch}
.muted{color:var(--dim)}
.tiny{font-size:.85rem}
.center{text-align:center}
.stack{display:grid;gap:22px}
.stack-sm{display:grid;gap:12px}
.row-between{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}
.grid-2{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:18px}
.grid-3{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:14px}

/* ------------------------------------------------------------------- card -- */
.card{background:var(--navy);border:1px solid var(--line);border-radius:var(--r-md);padding:24px}
.card.pad-lg{padding:30px}
.card.hero{background:linear-gradient(150deg,var(--navy-2),var(--navy) 62%);border-color:var(--line-strong);box-shadow:var(--shadow)}
.card.gold{background:linear-gradient(150deg,rgba(233,180,76,.16),rgba(233,180,76,.04));border-color:rgba(233,180,76,.4)}
.card.focus{background:linear-gradient(150deg,rgba(255,90,31,.15),rgba(255,90,31,.03));border-color:rgba(255,90,31,.4)}
.card.info{background:linear-gradient(150deg,var(--info-soft),rgba(127,178,255,.02));border-color:rgba(127,178,255,.3)}
.card.flat{background:var(--navy-2)}
.card h2{font-size:1.35rem;margin-bottom:8px}
.card h3{font-size:1.1rem;margin-bottom:6px}
.card .card-top{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;margin-bottom:14px}
.pill{display:inline-flex;align-items:center;gap:7px;padding:6px 12px;border-radius:999px;
  background:var(--navy-2);border:1px solid var(--line);font-size:.82rem;font-weight:600;color:var(--dim)}
.pill i{width:7px;height:7px;border-radius:50%;background:var(--orange);flex:none}
.pill svg{width:13px;height:13px;flex:none;fill:currentColor}
/* Gold is premium and blue is information. `.focus` is the brand tint, used for the
   thing to do next (the one fix, a drill, the current lesson) so the eye lands on
   advice rather than on marketing. */
.pill.gold,.pill.premium{background:rgba(233,180,76,.14);border-color:rgba(233,180,76,.35);color:var(--premium)}
.pill.focus{background:rgba(255,90,31,.14);border-color:rgba(255,90,31,.38);color:var(--orange-soft)}
.pill.info{background:var(--info-soft);border-color:rgba(127,178,255,.35);color:var(--info)}
.pill.ok{background:rgba(67,209,158,.13);border-color:rgba(67,209,158,.35);color:var(--ok)}
.pill.warn{background:rgba(255,176,32,.13);border-color:rgba(255,176,32,.35);color:var(--warn)}
/* `overflow-wrap:anywhere` and the zero min-width on the child are load-bearing: an
   engine failure can carry a URL or a stack fragment with no space in it, and a banner
   is a flex row, so without these the unbreakable token sets the min-content width of
   every column above it and the whole page scrolls sideways on a phone. The text still
   breaks at spaces first - `anywhere` only comes into play when a word cannot fit. */
.banner{display:flex;gap:14px;align-items:flex-start;padding:16px 18px;border-radius:var(--r-sm);
  background:var(--navy-2);border:1px solid var(--line);font-size:.95rem;overflow-wrap:anywhere}
.banner>div{min-width:0}

/* The same guard for the whole practicing area, because engine strings reach more than
   the banners: a raw error, a CDN path, a file name. A word that cannot fit is broken
   rather than allowed to push the column wider than the screen. */
#view{overflow-wrap:anywhere}
.banner.gold{background:rgba(233,180,76,.1);border-color:rgba(233,180,76,.32)}
.banner.info{background:var(--info-soft);border-color:rgba(127,178,255,.32)}
.banner.warn{background:rgba(255,176,32,.1);border-color:rgba(255,176,32,.34)}
.banner.bad{background:rgba(255,107,107,.1);border-color:rgba(255,107,107,.34)}
.banner strong{display:block;font-family:var(--display);letter-spacing:-.01em}

/* -------------------------------------------------------------- score bars -- */
/* Deliberately the same shape as the landing page's breakdown: a band that shows
   the healthy range, a fill that lands in it, and a knob on the end. */
.scores{display:grid;gap:16px}
.sli .row{display:flex;justify-content:space-between;align-items:baseline;gap:10px;margin-bottom:8px;font-size:.92rem}
.sli .lab{font-weight:600}
.sli .lab em{font-style:normal;color:var(--dim);margin-left:8px;font-weight:500}
.sli.off .lab em{color:var(--bad)}
.sli .val{font-variant-numeric:tabular-nums;font-weight:600}
.sli.off .val{color:var(--orange)}
/* A bar with nothing behind it is drawn empty and dashed rather than as a middling
   score: an unmeasured metric is not an average one. */
.sli.blank{opacity:.6}
.sli.blank .fill,.sli.blank .knob{display:none}
.sli.blank .track{background:repeating-linear-gradient(90deg,rgba(255,255,255,.16) 0 6px,transparent 6px 12px)}
.sli .bar-note{margin-top:7px;max-width:74ch}
.track{position:relative;height:9px;border-radius:5px;background:rgba(255,255,255,.12)}
.fill{position:absolute;left:0;top:0;bottom:0;border-radius:5px;background:var(--paper);
  transition:width 1.1s var(--ease)}
.sli.off .fill{background:var(--orange)}
.knob{position:absolute;top:50%;width:16px;height:16px;border-radius:50%;background:var(--paper);
  border:3px solid var(--ink);transform:translate(-50%,-50%);transition:left 1.1s var(--ease)}
.sli.off .knob{background:var(--orange)}

/* ------------------------------------------------------------------ forms -- */
.field{display:grid;gap:7px;margin-bottom:16px}
.field label{font-weight:600;font-size:.94rem}
.field .hint{color:var(--dim);font-size:.85rem}
input[type=text],input[type=email],input[type=password],input[type=tel],select,textarea{
  width:100%;padding:14px 16px;border-radius:var(--r-sm);border:1px solid var(--line-strong);
  background:var(--ink);color:var(--paper);font:inherit}
input::placeholder{color:#7C839F}
input:focus,select:focus,textarea:focus{border-color:var(--orange);outline:none;box-shadow:0 0 0 3px rgba(255,90,31,.22)}
.field.bad input{border-color:var(--bad)}
.field .err{color:var(--bad);font-size:.86rem;font-weight:500}
.checkline{display:flex;gap:10px;align-items:flex-start;font-size:.9rem;color:var(--dim)}
.checkline input{margin-top:4px}
.msg{min-height:1.4em;font-weight:600;font-size:.94rem}
.msg.err{color:var(--bad)}
.msg.ok{color:var(--ok)}
/* Something the person has to act on that is not a mistake they made: the account
   behind a session no longer exists, so no amount of retyping the password fixes it.
   Green would read as "that worked"; red would blame them. */
.msg.warn{color:var(--warn)}

/* ------------------------------------------------------------------- auth -- */
/* The auth page is one screen, and it is built to be read as one.
   100svh rather than 100vh, because a phone's collapsing URL bar otherwise pushes the
   button below a fold nobody knows to scroll. The aside is centred rather than spread
   against the form, and its paragraph is gone: what it said - that recordings stay on
   the device - is said once, at the bottom of the form, where somebody is agreeing to
   it. */
.auth-wrap{min-height:100vh;min-height:100svh;display:grid;grid-template-columns:1.02fr .98fr}
.auth-aside{position:relative;overflow:hidden;background:linear-gradient(160deg,var(--navy-3),var(--navy) 55%,var(--ink));
  padding:38px;display:flex;flex-direction:column;justify-content:center;gap:28px}
.auth-aside h2{font-size:clamp(1.7rem,3vw,2.4rem);max-width:20ch}
.auth-aside .lede{max-width:36ch}
.auth-form-col{padding:20px 24px;display:grid;place-items:center;background:var(--ink)}
.auth-card{width:min(440px,100%)}
.auth-card .view-title{font-size:clamp(1.35rem,2.4vw,1.75rem)}
.auth-card .field{margin-bottom:11px}
/* Name and email share a row, so the form is a row shorter on every screen wider than
   a phone. Two inputs of 210 pixels each is still a comfortable target. */
.auth-card .field-row{display:grid;grid-template-columns:1fr 1fr;gap:0 12px}
.auth-card .divider{margin:14px 0}
.auth-card .tabs-switch{display:flex;gap:6px;background:var(--navy-2);padding:5px;border-radius:999px;margin-bottom:16px;border:1px solid var(--line)}
/* The demo sentence is a note, not a banner: the box around it was 132 pixels of a
   screen whose whole job is to be one screen. */
.demo-line{margin-bottom:16px}
.demo-line code{background:rgba(255,255,255,.07);border-radius:5px;padding:1px 5px;font-size:.92em}
.auth-card .tabs-switch button{flex:1;background:none;border:0;color:var(--dim);padding:10px;border-radius:999px;cursor:pointer;font-weight:600}
.auth-card .tabs-switch button[aria-selected="true"]{background:var(--paper);color:var(--ink)}
.divider{display:flex;align-items:center;gap:14px;color:var(--dim);font-size:.85rem;margin:20px 0}
.divider::before,.divider::after{content:"";height:1px;background:var(--line);flex:1}

/* ----------------------------------------------------------------- mascot -- */
/* The orange guy. One inline SVG, posed by a class, with an optional bubble.
   He is decorative by default: aria-hidden unless he is carrying a message. */
.guy{--guy-h:120px;display:block;height:var(--guy-h);width:auto;overflow:visible}
.guy .head{fill:var(--orange)}
.guy .limb{stroke:var(--orange);stroke-width:9;stroke-linecap:round;stroke-linejoin:round;fill:none}
.guy .limb-soft{stroke:var(--orange-soft);stroke-width:6;stroke-linecap:round;fill:none}
.guy .head,.guy .limb{-webkit-transform-box:fill-box}
.guy .bob{transform-origin:100px 170px;animation:guy-bob 2.6s ease-in-out infinite alternate}
.guy .armL{transform-origin:100px 106px}
.guy .armR{transform-origin:100px 106px}
.guy[data-pose="wave"] .armR{animation:guy-wave 1s ease-in-out infinite alternate}
.guy[data-pose="cheer"] .armL{animation:guy-up 1.4s ease-in-out infinite alternate}
.guy[data-pose="cheer"] .armR{animation:guy-up 1.4s ease-in-out infinite alternate-reverse}
.guy[data-pose="think"] .armR{transform:rotate(-46deg) translateY(-6px)}
.guy[data-pose="think"] .bob{animation-duration:4.2s}
.guy[data-pose="point"] .armR{transform:rotate(28deg)}
.guy[data-pose="peek"] .bob{animation-duration:3.4s}
.guy[data-pose="sleep"] .bob{animation-duration:7s}
.guy .zzz{opacity:0}
.guy[data-pose="sleep"] .zzz{opacity:1;animation:guy-float 3s ease-in-out infinite}
@keyframes guy-bob{from{transform:translateY(0)}to{transform:translateY(-7px)}}
@keyframes guy-wave{from{transform:rotate(8deg)}to{transform:rotate(-52deg)}}
@keyframes guy-up{from{transform:rotate(20deg)}to{transform:rotate(-26deg)}}
@keyframes guy-float{from{transform:translateY(4px);opacity:.4}to{transform:translateY(-6px);opacity:1}}
/* Walking. The legs swing from the hip while his box is moving, which is the whole
   difference between strolling and teleporting for a figure this simple: two strokes
   and a rotation, and the second leg half a beat behind the first. */
.guy .legs path{transform-origin:100px 172px}
.guy[data-walk="true"] .legs path{animation:guy-step .46s ease-in-out infinite alternate}
.guy[data-walk="true"] .legs path:last-child{animation-delay:-.23s}
.guy[data-walk="true"] .bob{animation-duration:1.2s}
@keyframes guy-step{from{transform:rotate(-13deg)}to{transform:rotate(13deg)}}
/* Two more poses, so an idle cycle is not the same four shapes in the same order. */
.guy[data-pose="hop"] .bob{animation:guy-hop 1.15s var(--ease) infinite}
@keyframes guy-hop{0%,58%,100%{transform:translateY(0)}30%{transform:translateY(-22px)}}
.guy[data-pose="stretch"] .armL{transform:rotate(38deg)}
.guy[data-pose="stretch"] .armR{transform:rotate(-38deg)}
.guy[data-pose="stretch"] .bob{animation-duration:4.6s}

.guy-bubble{position:relative;display:inline-block;max-width:34ch;padding:13px 17px;border-radius:16px;
  background:var(--paper);color:var(--ink);font-weight:600;font-size:.95rem;line-height:1.45;
  box-shadow:0 14px 30px -18px rgba(0,0,0,.9)}
.guy-bubble::after{content:"";position:absolute;left:22px;bottom:-9px;width:16px;height:16px;background:var(--paper);transform:rotate(45deg)}
.guy-bubble.gold{background:var(--gold);color:#2A1F08}
.guy-bubble.gold::after{background:var(--gold)}

/* He used to float.
   The companion was fixed to the viewport and hit-tested the paint to find a gutter
   in it, and all of that is gone with the fixed companion itself. It was the wrong
   shape for this product: a figure in the corner is one you have to decide to look
   at, he has to be argued out of the way on every screen and every scroll, and when
   the window moved his lane he travelled across the page to get there - which, with
   transitions off, was a teleport. He now stands where the layout puts him with his
   line in a real text box beside him, so the page cannot be covered by him at all. */
.guy-stage{display:flex;align-items:flex-end;gap:20px;justify-content:center}

/* confetti for the small wins */
.confetti{position:fixed;inset:0;pointer-events:none;z-index:80;overflow:hidden}
.confetti i{position:absolute;width:9px;height:14px;border-radius:2px;animation:conf-fall linear forwards}
@keyframes conf-fall{from{transform:translateY(-10vh) rotate(0)}to{transform:translateY(105vh) rotate(540deg)}}

/* ------------------------------------------------------------------ toast -- */
/* Sized from the layout viewport rather than 100vw: vw includes the scrollbar,
   which made this box hang a few pixels off the left edge of the screen. */
.toasts{position:fixed;right:20px;bottom:20px;z-index:95;display:grid;gap:10px;max-width:min(380px,calc(100% - 40px))}
.toast{background:var(--navy-2);border:1px solid var(--line-strong);border-left:4px solid var(--orange);
  border-radius:var(--r-sm);padding:14px 16px;box-shadow:var(--shadow);animation:toast-in .3s var(--ease) both}
.toast.ok{border-left-color:var(--ok)}
.toast.bad{border-left-color:var(--bad)}
.toast strong{display:block;font-family:var(--display);margin-bottom:2px}
.toast span{color:var(--dim);font-size:.9rem}
@keyframes toast-in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}

/* ------------------------------------------------------------------- quiz -- */
.quiz-progress{display:flex;gap:6px;margin-bottom:26px}
.quiz-progress i{height:5px;border-radius:3px;background:rgba(255,255,255,.16);flex:1}
.quiz-progress i.on{background:var(--orange)}
.choices{display:grid;gap:12px;margin:24px 0 8px}
.choice{display:flex;align-items:center;gap:14px;text-align:left;width:100%;padding:17px 20px;border-radius:var(--r-sm);
  background:var(--navy-2);border:1px solid var(--line);color:var(--paper);cursor:pointer;
  font-weight:500;transition:border-color .18s,background .18s,transform .12s}
.choice:hover{border-color:var(--orange);background:var(--navy-3)}
.choice:active{transform:translateY(1px)}
.choice .k{width:26px;height:26px;border-radius:50%;border:1px solid var(--line-strong);display:grid;place-items:center;
  font-size:.8rem;font-weight:700;color:var(--dim);flex:none}
.choice.sel{border-color:var(--orange);background:var(--navy-3)}
.choice.sel .k{background:var(--orange);color:var(--navy);border-color:var(--orange)}

/* --------------------------------------------------------------- recording -- */
.stage-wrap{position:relative;border-radius:var(--r-md);overflow:hidden;background:#050813;border:1px solid var(--line-strong);
  aspect-ratio:16/10;max-height:58vh;margin-inline:auto;width:100%}
.stage-wrap video{width:100%;height:100%;object-fit:cover;display:block;transform:scaleX(-1);background:#050813}
.stage-wrap.no-mirror video{transform:none}
.stage-overlay{position:absolute;inset:0;pointer-events:none;display:flex;flex-direction:column;justify-content:space-between;padding:16px}
.stage-top{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}
.rec{display:inline-flex;align-items:center;gap:8px;padding:6px 12px;border-radius:9px;background:rgba(14,20,40,.86);font-weight:600;font-variant-numeric:tabular-nums;font-size:.9rem}
.rec i{width:11px;height:11px;border-radius:50%;background:#FF3B30;animation:blink 1s steps(1,end) infinite}
@keyframes blink{50%{opacity:0}}
.meter{display:flex;gap:3px;align-items:flex-end;height:26px;padding:6px;border-radius:9px;background:rgba(14,20,40,.7)}
.meter i{width:4px;height:100%;border-radius:2px;background:var(--paper);transform:scaleY(.12);transform-origin:bottom}
.stage-top-left{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
/* "In frame" beside the timer, not over the picture: the one piece of good news the
   camera has to give is a green dot, and a green dot does not need to be drawn across
   somebody's face. */
.head-ok{display:inline-flex;align-items:center;gap:7px;padding:6px 12px;border-radius:9px;
  background:rgba(67,209,158,.14);border:1px solid rgba(67,209,158,.4);color:var(--ok);
  font-weight:600;font-size:.86rem}
.head-ok::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--ok)}
.teleprompter{margin:0 auto;max-width:46ch;padding:14px 18px;border-radius:var(--r-sm);background:rgba(14,20,40,.86);
  border:1px solid var(--line-strong);font-size:1.02rem;line-height:1.5}
.teleprompter strong{color:var(--orange-soft);display:block;font-family:var(--display);margin-bottom:5px;font-size:.95rem}
/* The head guide: where to sit, drawn on the picture.
   "Keep your head in frame" is advice nobody can act on, so four corner brackets mark
   where the models want a face and a pair of shoulders. It used to be a dashed oval
   that snapped to a solid green ring the moment a face was found, which read as a grade
   awarded for sitting still and drew a bright circle over the middle of the very thing
   the person is standing in front of trying to look natural. The guide is on screen
   only while the reading is bad: when the face is readable the whole thing fades out of
   the picture and the good news moves to a chip beside the timer, where it belongs. */
.head-guide{position:absolute;inset:0;display:grid;justify-items:center;align-content:center;
  gap:13px;pointer-events:none;padding:16px 16px 26%;
  transition:opacity .5s var(--ease),visibility .5s var(--ease)}
.head-guide[hidden]{display:none}
.head-guide[data-state="on"]{opacity:0;visibility:hidden}
.head-guide[data-state="waiting"]{opacity:.8}
/* The frame is brackets rather than a closed outline: nothing is drawn over the face,
   and a shape that is only corners cannot be mistaken for a reading. */
.head-guide .head-frame{position:relative;display:block;width:min(46%,230px);aspect-ratio:3/4;
  background:radial-gradient(120% 85% at 50% 40%,rgba(255,255,255,.06),transparent 72%)}
.head-guide .head-cap{position:absolute;width:32px;height:32px;border:2px solid rgba(174,180,204,.62);
  transition:border-color .35s var(--ease)}
.head-guide .head-cap:nth-child(1){top:0;left:0;border-right:0;border-bottom:0;border-radius:14px 0 0 0}
.head-guide .head-cap:nth-child(2){top:0;right:0;border-left:0;border-bottom:0;border-radius:0 14px 0 0}
.head-guide .head-cap:nth-child(3){bottom:0;left:0;border-right:0;border-top:0;border-radius:0 0 0 14px}
.head-guide .head-cap:nth-child(4){bottom:0;right:0;border-left:0;border-top:0;border-radius:0 0 14px 0}
.head-guide[data-state="watch"] .head-cap{border-color:rgba(255,176,32,.85)}
.head-guide[data-state="off"] .head-cap{border-color:rgba(255,107,107,.85)}
.head-guide .head-caption{display:grid;gap:2px;justify-items:center;text-align:center;
  padding:7px 12px;border-radius:var(--r-xs);background:rgba(14,20,40,.86);max-width:min(92%,36ch)}
.head-guide .head-caption b{font-size:.86rem;font-weight:600}
.head-guide .head-caption i{font-style:normal;font-size:.76rem;color:var(--dim)}
.head-guide[data-state="watch"] .head-caption i{color:var(--warn)}
.stage-empty{position:absolute;inset:0;display:grid;place-items:center;text-align:center;padding:24px;background:var(--navy)}
.stage-actions{display:flex;gap:12px;justify-content:center;margin-top:18px;flex-wrap:wrap}
.countdown{position:absolute;inset:0;display:grid;place-items:center;background:rgba(14,20,40,.72);
  font-family:var(--display);font-size:clamp(4rem,14vw,9rem);font-weight:800;color:var(--paper)}

/* ------------------------------------------------------------- live guide -- */
/* Reads along under the video while a take is running. Every tile is a reading
   the offline pass will also make, at a lower sample rate, so the states here use
   the same words the report does: a tile goes amber exactly when the equivalent
   bar would come back as a problem. A tile with nothing behind it is dashed and
   says why, rather than showing a zero. */
.live{margin-top:18px;padding:16px 18px;border-radius:var(--r-md);background:var(--navy-2);border:1px solid var(--line)}
.live-head{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin-bottom:14px}
.live-pill{background:rgba(255,90,31,.14);border-color:rgba(255,90,31,.4);color:var(--orange)}
.live-pill i{background:var(--orange);animation:blink 1.8s steps(1,end) infinite}
.live-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(128px,1fr));gap:10px}
.live-tile{display:grid;gap:3px;padding:11px 13px;border-radius:var(--r-sm);background:var(--ink);
  border:1px solid var(--line);transition:border-color .3s var(--ease),background .3s var(--ease)}
.live-lab{font-size:.74rem;letter-spacing:.09em;text-transform:uppercase;color:var(--dim);font-weight:600}
.live-val{font-family:var(--display);font-size:1.45rem;font-weight:800;letter-spacing:-.03em;
  line-height:1.1;font-variant-numeric:tabular-nums}
.live-track{display:block;height:5px;border-radius:3px;background:rgba(255,255,255,.12);overflow:hidden}
.live-track i{display:block;height:100%;width:0;border-radius:3px;background:var(--ok);transition:width .3s linear,background .3s}
.live-note{font-size:.76rem;line-height:1.35;color:var(--dim)}
.live-tile[data-state="watch"]{border-color:rgba(255,176,32,.55);background:rgba(255,176,32,.08)}
.live-tile[data-state="watch"] .live-val{color:var(--warn)}
.live-tile[data-state="watch"] .live-track i{background:var(--warn)}
.live-tile[data-state="unknown"]{border-style:dashed;opacity:.75}
.live-tile[data-state="unknown"] .live-track{background:repeating-linear-gradient(90deg,rgba(255,255,255,.14) 0 5px,transparent 5px 10px)}
.live-tile[data-state="unknown"] .live-track i{display:none}
.live-tile[data-state="done"] .live-track i{background:var(--dim)}
.live-caption{margin-top:12px;padding:11px 14px;border-radius:var(--r-sm);background:var(--ink);
  border:1px solid var(--line);font-size:.95rem;min-height:2.7em}
.live-caption-lab{display:inline-block;margin-right:8px;font-size:.72rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--dim);font-weight:600}
.live-caption-text .filler{color:var(--orange);font-weight:600;text-decoration:underline dotted;text-underline-offset:3px}
/* Hedging is amber and fillers are orange, in the live caption and in the transcript,
   so the two marks are the same two colours in both places. They used to be orange and
   gold, and gold is the paid tier now. */
.live-caption-text .hedge{color:var(--warn)}
.live-nudge{margin:12px 0 0;padding:11px 14px;border-radius:var(--r-sm);font-weight:600;
  background:rgba(255,90,31,.12);border:1px solid rgba(255,90,31,.35);animation:bubble-in .28s var(--ease) both}
/* Which microphone. A row under the picture rather than a dialog: it appears only
   when the machine actually has more than one input, and it never covers the video. */
.mic-row{display:flex;gap:10px;align-items:center;margin:14px 0 0;flex-wrap:wrap}
.mic-row .micro{font-size:.76rem;letter-spacing:.09em;text-transform:uppercase;color:var(--dim);font-weight:600}
.mic-row .mic-select{width:auto;flex:1 1 240px;max-width:100%;padding:9px 12px;font-size:.92rem}
/* Amber, not red: a flat input is something to fix, not a failure of the person. */
.mic-why{margin:10px 0 0;padding:11px 14px;border-radius:var(--r-sm);font-weight:600;font-size:.92rem;
  background:rgba(255,176,32,.12);border:1px solid rgba(255,176,32,.4);color:var(--paper)}

/* The three inputs, which is all the record screen shows by default. A row of
   chips rather than a grid of tiles: there is nothing to compare against and no
   percentage worth reading on a take that is still starting, and a number that
   looks like a measurement but is not yet one is the failure mode this whole
   section exists to avoid. */
.live-state{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 12px}
.live-chip{display:inline-flex;align-items:center;padding:7px 13px;border-radius:999px;
  font-size:.86rem;font-weight:600;background:var(--ink);border:1px solid var(--line);
  color:var(--dim);transition:border-color .25s var(--ease),color .25s var(--ease)}
.live-chip[data-state="ok"]{border-color:rgba(67,209,158,.45);color:var(--paper)}
.live-chip[data-state="ok"]::before{content:"";width:8px;height:8px;border-radius:50%;
  background:var(--ok);margin-right:9px}
.live-chip[data-state="watch"]{border-color:rgba(255,176,32,.55);background:rgba(255,176,32,.1);color:var(--warn)}
.live-chip[data-state="watch"]::before{content:"";width:8px;height:8px;border-radius:50%;
  background:var(--warn);margin-right:9px;animation:blink 1.6s steps(1,end) infinite}
.live-chip[data-state="unknown"]::before{content:"";width:8px;height:8px;border-radius:50%;
  background:var(--dim);margin-right:9px;opacity:.6}
.live-more{margin-top:4px;padding:4px 0;background:none;border:0;color:var(--dim);cursor:pointer;
  font-size:.86rem;text-decoration:underline;text-underline-offset:4px}
.live-more:hover{color:var(--paper)}
.live-grid[hidden]{display:none}

/* One line on the record screen: which engine is going to read this take. */
.engine-note{margin:12px 0 0;padding:11px 14px;border-radius:var(--r-sm);font-size:.88rem;
  color:var(--dim);background:var(--ink);border:1px solid var(--line)}
.engine-note.on{border-color:rgba(67,209,158,.35);color:var(--paper)}

/* Which engine read the take, said once at the top of the report. */
.engine-line{margin-top:18px;padding:12px 15px;border-radius:var(--r-sm);font-size:.88rem;
  color:var(--dim);background:rgba(255,255,255,.04);border:1px solid var(--line)}
.engine-line b{display:block;color:var(--paper);margin-bottom:3px}
.engine-line.deep{border-color:rgba(67,209,158,.3);background:rgba(67,209,158,.07)}
.engine-line.deep b{color:var(--ok)}

/* The pipeline's own report: strengths, what to improve, and the caveats, per
   half of the take. It is the same three-way split the offline tool prints. */
.deep-block{margin-top:16px}
/* Sentence case, like every other heading in the report. The pipeline's own labels
   are already words a person reads ("Areas to improve"); shouting them in caps made
   the most useful part of the page the least readable. */
.deep-block h4{margin:0 0 7px;font-size:.98rem;color:var(--ok);font-weight:700}
.deep-block h4.warn{color:var(--warn)}
.deep-list{list-style:none;margin:0;padding:0;display:grid;gap:9px}
.deep-list li{display:flex;gap:12px;align-items:flex-start;font-size:.94rem;color:var(--paper)}
.deep-list li::before{content:"";flex:none;width:6px;height:6px;border-radius:50%;margin-top:9px;
  background:var(--line-strong)}
.contrib{flex:none;min-width:52px;font-family:var(--display);font-weight:800;font-variant-numeric:tabular-nums;
  font-size:.95rem}
.contrib.up{color:var(--ok)}
.contrib.down{color:var(--warn)}

/* -------------------------------------------------------------- analysing -- */
.analysing{display:grid;gap:20px;justify-items:center;text-align:center;padding:34px 0}
.analysing .bar-track{width:min(420px,100%);height:8px;border-radius:4px;background:rgba(255,255,255,.14);overflow:hidden}
.analysing .bar-track i{display:block;height:100%;width:0;background:var(--orange);transition:width .4s linear}
.analysing .steps{color:var(--dim);font-size:.95rem;min-height:1.6em}

/* Today's two things. Blue, because it is a label about the day rather than a reading of
   a person; green only once both have happened, which is the same green as every other
   done in the product, and no third colour for a score that would not exist. */
.card.quests.done{background:linear-gradient(150deg,rgba(67,209,158,.12),rgba(67,209,158,.02));
  border-color:rgba(67,209,158,.32)}
.goals{display:grid;gap:11px}
.goals .goal{flex-wrap:wrap;font-size:.95rem}
.goals .goal i{width:18px;height:18px}
.goals .goal strong{font-family:var(--display);font-weight:600}

/* ----------------------------------------------------------------- lessons -- */
.path{display:grid;gap:14px;counter-reset:step}
.lesson{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:18px;align-items:center;
  padding:18px 20px;border-radius:var(--r-md);background:var(--navy);border:1px solid var(--line);text-decoration:none;
  transition:border-color .18s,background .18s,transform .12s}
.lesson:hover{border-color:var(--line-strong);background:var(--navy-2);transform:translateY(-1px)}
.lesson .no{width:44px;height:44px;border-radius:50%;display:grid;place-items:center;font-family:var(--display);
  font-weight:800;font-size:1.2rem;background:var(--navy-3);color:var(--dim)}
.lesson[data-state="done"] .no{background:var(--ok);color:#06301F}
.lesson[data-state="current"]{border-color:var(--orange);background:var(--navy-2)}
.lesson[data-state="current"] .no{background:var(--orange);color:var(--navy)}
.lesson[data-state="locked"]{opacity:.62}
.lesson h3{font-size:1.06rem;margin-bottom:3px}
.lesson .meta{color:var(--dim);font-size:.86rem;display:flex;gap:14px;flex-wrap:wrap}
.lesson .chev{color:var(--dim)}
/* The path.
   One spine down the left, the drills as stops on it, and the one you are up to wearing a
   Start marker: the drills are an order rather than a set, and what somebody wants to know
   on this page is where along that order they are. The line is green behind every stop
   already reached and dim above every stop not yet, so the progress is read without being
   told. Each row draws its own incoming segment - from the row above's bottom edge down to
   its own centre - which is why nothing has to be measured at build time and the spine
   survives a title that wraps to three lines. */
.path{position:relative;--gap:14px}
.path .lesson{position:relative}
.path .lesson::before{content:"";position:absolute;left:41px;top:calc(-1 * var(--gap));
  bottom:50%;width:2px;border-radius:2px;background:var(--line);pointer-events:none}
.path .lesson:first-child::before{display:none}
.path .lesson[data-state="done"]::before,
.path .lesson[data-state="current"]::before,
.path .lesson[data-state="due"]::before{background:rgba(67,209,158,.8)}
/* A check-in that is due: a live action, so it is orange like the stop you are up to,
   but an outlined one - it is a second reading rather than the next drill. */
.path .lesson[data-state="due"]{border-color:rgba(255,90,31,.45);background:var(--navy-2)}
.path .lesson[data-state="due"] .no{color:var(--orange);border-color:rgba(255,90,31,.5);
  background:rgba(255,90,31,.12)}
.path .lesson .no{border:2px solid var(--navy-3);background:var(--navy-2);color:var(--dim)}
.path .lesson[data-state="done"] .no{border-color:var(--ok)}
.path .lesson[data-state="current"] .no{transform:scale(1.12);
  box-shadow:0 0 22px -6px rgba(255,90,31,.7)}
.path .lesson[data-state="pro"] .no{border-color:rgba(233,180,76,.4)}
.start-tag{display:inline-flex;align-items:center;margin-left:9px;padding:2px 9px;border-radius:999px;
  background:var(--orange);color:var(--navy);font-family:var(--body);font-size:.68rem;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;vertical-align:middle}
/* The unit bar: one segment per drill, filled behind the ones that are done. Two colours
   and a shape, no number - the number is printed beside it anyway. */
.unit-bar{display:flex;gap:5px;margin:12px 0 16px}
.unit-bar i{flex:1 1 0;height:6px;border-radius:3px;background:rgba(255,255,255,.09)}
.unit-bar i.on{background:var(--ok)}
.unit-bar i.now{background:rgba(255,90,31,.55)}
/* The stops arrive in order, once, on mount - and only under `html.motion-on`, because the
   switch in the account menu covers everything that moves and a person who turned it off
   should not be shown a cascade of cards. `backwards` rather than `both`: a filling
   animation would go on overriding the row's own hover lift for the life of the page. */
html.motion-on .path .lesson{animation:step-in .46s var(--ease) backwards;
  animation-delay:calc(var(--step,0) * 60ms)}
@keyframes step-in{from{opacity:0;transform:translateY(10px) scale(.98)}to{opacity:1;transform:none}}
html.motion-on .path .lesson[data-state="current"] .no{animation:node-pulse 2.6s var(--ease) infinite}
@keyframes node-pulse{
  0%,100%{box-shadow:0 0 0 0 rgba(255,90,31,.4),0 0 22px -6px rgba(255,90,31,.7)}
  60%{box-shadow:0 0 0 12px rgba(255,90,31,0),0 0 22px -6px rgba(255,90,31,.7)}}
.lesson-body{display:grid;gap:20px;max-width:70ch}
.lesson-body h2{font-size:1.6rem}
.lesson-body .block{background:var(--navy);border:1px solid var(--line);border-left:3px solid var(--orange);border-radius:var(--r-sm);padding:18px 20px}
.lesson-body .block h3{font-size:.95rem;text-transform:uppercase;letter-spacing:.1em;color:var(--info);margin-bottom:8px;font-weight:700}
.drill-timer{display:flex;align-items:center;gap:16px;flex-wrap:wrap}
.drill-timer .clock{font-family:var(--display);font-size:2.2rem;font-weight:800;font-variant-numeric:tabular-nums}
.ring{transform:rotate(-90deg)}
.ring circle{fill:none;stroke-width:9;stroke-linecap:round}
.ring .bg{stroke:rgba(255,255,255,.14)}
.ring .fg{stroke:var(--orange);transition:stroke-dashoffset .6s var(--ease)}
.checkin-row{display:grid;grid-template-columns:auto minmax(0,1fr);gap:20px;align-items:center;
  padding:18px;border-radius:var(--r-md);background:var(--navy);border:1px solid var(--line)}

/* --------------------------------------------------------- the model score -- */
/* The dial used to be here: the take's score out of ten, as the largest thing on the
   report, Today and the check-in. It went with the rest of the front-facing score. A
   good score was green rather than gold, because gold is the paid tier now - that part
   of the reasoning still holds and is why nothing new is allowed to be gold. */

/* Folded detail.
   The statistics and the evidence both used to be panels on the open page, which made
   the report a page of evidence rather than a page of feedback. Nothing was removed to
   make room: it is the same numbers, the same notes and the same transcript, one tap
   down, below the two cards that answer "how did it go" and "what do I do". */
.stats-more{margin-top:22px;padding-top:18px;border-top:1px solid var(--line)}
.evidence{margin-top:0}
.stats-more>summary,.evidence>summary{cursor:pointer;font-weight:600;font-size:.95rem;
  color:var(--info);list-style-position:outside}
.stats-more>summary:hover,.evidence>summary:hover{text-decoration:underline;text-underline-offset:3px}
.stats-more[open]>summary,.evidence[open]>summary{margin-bottom:2px}
.stats-more .fix-line span:first-child{color:var(--paper)}

/* Where the numbers came from, per report. Three states, and the third is a
   promise not to pretend: a value the take did not produce is named. */
.prov{display:grid;gap:10px;margin:14px 0 0;padding:0;list-style:none;font-size:.92rem;color:var(--dim)}
.prov li{padding-left:16px;position:relative}
.prov li::before{content:"";position:absolute;left:0;top:.55em;width:7px;height:7px;border-radius:50%;background:var(--dim)}
.prov li.ok::before{background:var(--ok)}
.prov li.mid::before{background:var(--warn)}
.prov li.miss::before{background:var(--bad)}
.prov strong{display:block;color:var(--paper);font-family:var(--display);letter-spacing:-.01em}

/* ------------------------------------------------- the words you said ----- */
/* The transcript is evidence: the fillers and hedges are marked in the same
   colour the live caption used, so the numbers above and the words below are
   visibly the same measurement. */
.transcript{margin-top:4px;padding:14px 16px;border-radius:var(--r-sm);background:var(--ink);
  border:1px solid var(--line);line-height:1.75;font-size:.97rem;color:var(--paper);max-height:340px;overflow:auto}
.transcript .filler{color:var(--orange);font-weight:600;text-decoration:underline dotted;text-underline-offset:3px}
.transcript .hedge{color:var(--warn)}
.filler-mark{color:var(--orange);font-weight:600}
.hedge-mark{color:var(--warn);font-weight:600}
.fix-line{display:grid;gap:4px;padding:10px 0;border-bottom:1px solid var(--line)}
.fix-line:last-child{border-bottom:0}
.lesson-link{color:var(--orange);text-decoration:none;font-weight:600}
.lesson-link:hover{text-decoration:underline}

/* ---------------------------------------------------------------- profile -- */
.profile-head{display:flex;align-items:center;gap:18px;flex-wrap:wrap}
/* The crest: the avatar in a ring, with the streak as a flame riding its corner.
   The streak used to be a third pill on this page saying the same number the tiles
   said; a flame on the crest is where the number belongs, and it is the one orange
   thing about the person themselves. */
.crest{position:relative;display:inline-flex;flex:none;padding:5px;border-radius:50%;
  border:1px solid var(--line-strong);background:radial-gradient(circle at 30% 20%,rgba(255,90,31,.18),transparent 70%)}
.crest-flame{position:absolute;right:-6px;bottom:-4px;display:inline-flex;align-items:center;gap:3px;
  padding:3px 8px;border-radius:999px;background:var(--ink);border:1px solid rgba(255,90,31,.5);
  color:var(--flame);font-family:var(--display);font-weight:800;font-size:.82rem;
  font-variant-numeric:tabular-nums}
.crest-flame svg{fill:currentColor}
.stat .tiny{margin-top:2px}
.grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:14px}
.chart svg{width:100%;height:auto;display:block;margin-bottom:10px}
.chart-line{fill:none;stroke:var(--orange);stroke-width:3;stroke-linejoin:round;stroke-linecap:round}
.chart-band{fill:rgba(255,90,31,.14);stroke:none}
.chart-dot{fill:var(--paper);stroke:var(--ink);stroke-width:3}
.chart-val{fill:var(--dim);font-size:13px;font-family:var(--body);font-weight:600}
.chart-axis{stroke:rgba(255,255,255,.18);stroke-width:1}
/* Five columns, and every one of them a size rather than "as wide as the content". Each
   row is its own grid, so content-sized columns made the dates, the counts and the detail
   line land at different points down the list - and once the detail column carried a chip
   and a pair of numbers it took the width it wanted and squeezed the take's own label down
   to one word a line. The two flexible columns share the space in a fixed ratio, so the
   rows line up with each other and long text wraps instead of shoving. */
.rec-row{display:grid;grid-template-columns:100px minmax(0,1.25fr) 84px minmax(0,1fr) 14px;gap:14px;align-items:center;
  padding:13px 16px;border-radius:var(--r-sm);background:var(--navy-2);border:1px solid var(--line);
  text-decoration:none;transition:border-color .18s,transform .12s}
.rec-row:hover{border-color:var(--line-strong);transform:translateY(-1px)}
.rec-row .when{font-size:.86rem;color:var(--dim);white-space:nowrap}
.rec-row .kind{font-weight:600}
.rec-row .meta .move-chip{margin-left:2px}
.rec-row .score{font-family:var(--display);font-size:1.2rem;font-weight:800;font-variant-numeric:tabular-nums}
.rec-row .score em{font-style:normal;font-size:.8rem;color:var(--dim);font-weight:600}
.rec-row .meta{font-size:.82rem;color:var(--dim)}
.rec-row .chev{color:var(--dim)}
/* ---------------------------------------------------------------- medals -- */
/* The board of medals, and it is a board rather than a wall of cards: earned ones
   are a filled disc with the brand glow, the ones still to come are an outline, and
   the guy stands beside it. Nothing here is gold except a medal that was actually
   earned, and even then the glow is the brand colour - the point of this screen is
   progress through the product, not a paid tier. */
.medal-board{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin-top:14px}
.medal{display:grid;gap:6px;justify-items:start;padding:16px;border-radius:var(--r-md);
  background:var(--navy-2);border:1px dashed var(--line-strong);transition:border-color .2s var(--ease),transform .2s var(--ease)}
.medal:hover{transform:translateY(-2px)}
.medal .medal-mark{display:grid;place-items:center;width:44px;height:44px;border-radius:50%;
  background:rgba(255,255,255,.05);border:1px solid var(--line-strong);font-size:1.3rem;line-height:1}
.medal .medal-mark .guy{height:26px;width:auto}
.medal[data-got="true"]{border-style:solid;border-color:rgba(255,90,31,.45);
  background:linear-gradient(150deg,rgba(255,90,31,.12),transparent)}
/* The earned disc is dark with an orange ring, not solid orange: the medal is the
   figure standing on it, and an orange guy on an orange disc is invisible. */
.medal[data-got="true"] .medal-mark{background:var(--ink);border-color:var(--orange);
  box-shadow:0 8px 22px -10px rgba(255,90,31,.9)}
.medal[data-got="true"] .medal-mark svg{fill:none}
.medal h3{font-size:1rem}
.medal .when{font-size:.78rem;color:var(--dim);font-variant-numeric:tabular-nums}
.medal-progress{display:flex;align-items:center;gap:14px;flex-wrap:wrap}

/* ------------------------------------------------------------ the guy, big -- */
/* The one place he appears: standing in the layout, beside a box that holds what he
   is saying. That is the whole design now - no fixed position, no lane, no
   hit-testing - because the answer to "where can a cartoon stand without being in
   the way" is "in the page, next to the thing he is talking about". */
.mascot-spot{display:flex;align-items:flex-end;gap:18px;flex-wrap:wrap}
.mascot-spot .mascot-tap{background:none;border:0;padding:0;cursor:pointer;line-height:0;
  border-radius:16px;transition:transform .2s var(--ease)}
.mascot-spot .mascot-tap:hover{transform:translateY(-4px)}
.mascot-spot .mascot-tap:focus-visible{outline:2px solid var(--orange);outline-offset:5px}
.mascot-says{flex:1 1 260px;min-width:min(260px,100%)}
.mascot-says .guy-bubble{margin-bottom:0;max-width:none}
.mascot-says .prompt-line{color:var(--dim);font-size:.86rem;margin-top:9px}
/* The muted pose: he is beside the question rather than commenting on it, so his
   bubble is a quiet box with a border instead of a white speech balloon. A balloon
   is for something he says by himself; a box is for the page speaking through him. */
.mascot-spot[data-tone="quiet"] .mascot-says .guy-bubble{background:var(--navy-2);color:var(--paper);
  border:1px solid var(--line-strong);font-weight:500;box-shadow:none}
.mascot-spot[data-tone="quiet"] .mascot-says .guy-bubble::after{background:var(--navy-2);
  border-right:1px solid var(--line-strong);border-bottom:1px solid var(--line-strong)}
.mascot-spot[data-size="small"] .guy{height:76px}
.mascot-note{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}
.mascot-note .mascot-tap{align-self:flex-end}
@keyframes bubble-in{from{opacity:0;transform:translateY(6px) scale(.96)}to{opacity:1;transform:none}}
.mascot-says .guy-bubble{animation:bubble-in .28s var(--ease) both}

/* --------------------------------------------------------------- pro tier -- */
/* The paid tier, said plainly: what it adds, what it costs, and that it is not
   switched on. Gold appears only here and on the Pro pills. */
.pro-hero{background:linear-gradient(150deg,rgba(233,180,76,.14),rgba(233,180,76,.03));
  border-color:rgba(233,180,76,.4)}
.pro-price{display:flex;align-items:baseline;gap:8px;margin:6px 0 2px}
.pro-price b{font-family:var(--display);font-size:2.4rem;font-weight:800;letter-spacing:-.04em;line-height:1}
.pro-price span{color:var(--dim);font-size:.92rem}
.pro-list{list-style:none;margin:16px 0 0;padding:0;display:grid;gap:11px}
.pro-list li{display:flex;gap:11px;align-items:flex-start;font-size:.95rem}
.pro-list li::before{content:"";flex:none;width:17px;height:17px;margin-top:4px;border-radius:50%;
  background:rgba(233,180,76,.18);border:1px solid rgba(233,180,76,.5);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23E9B44C' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7'/%3E%3C/svg%3E");
  background-size:11px 11px;background-position:center;background-repeat:no-repeat}
.pro-list li.muted::before{border-color:var(--line-strong);background-color:rgba(255,255,255,.05);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23AEB4CC' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6L6 18'/%3E%3C/svg%3E")}
.pro-list li.muted{color:var(--dim)}

/* The gate itself: one card, on the screen that would otherwise have opened the
   camera, explaining what the trial covered and what Pro adds. It is a card and not
   a modal on purpose - nothing is taken away from the page behind it. */
.gate{display:grid;gap:14px;justify-items:start;padding:26px;border-radius:var(--r-md);
  background:linear-gradient(150deg,rgba(233,180,76,.1),var(--navy));border:1px solid rgba(233,180,76,.38)}
.gate .gate-top{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.gate h3{font-size:1.2rem}
.gate p{color:var(--dim);font-size:.94rem;max-width:62ch}
.gate .gate-note{font-size:.84rem;color:var(--dim)}
/* A lesson that belongs to another track: readable on Pro, named as Pro here. */
.lesson[data-state="pro"]{opacity:.8}
.lesson[data-state="pro"] .no{background:rgba(233,180,76,.16);color:var(--premium);border:1px solid rgba(233,180,76,.4)}
.lesson[data-state="pro"]:hover{border-color:rgba(233,180,76,.45)}
.track-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:8px 0 2px}

/* --------------------------------------------------------------- the stats -- */
/* A page that answers "how am I doing" without one number that needs a paragraph of
   explanation. Every row is a bar, a plain-language verdict, and - once there is a
   second take - a sentence saying which way it moved. The chip is the same five-point
   threshold the check-in uses, said in English rather than as a delta. */
.stat-move{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:5px 14px;align-items:baseline;
  padding:13px 0;border-bottom:1px solid var(--line)}
.stat-move:last-child{border-bottom:0}
.stat-move .sm-label{font-weight:600}
.stat-move .sm-label em{font-style:normal;color:var(--dim);margin-left:8px;font-weight:500;font-size:.88rem}
.stat-move .sm-val{font-variant-numeric:tabular-nums;font-weight:600}
.stat-move .sm-plain{grid-column:1 / -1;font-size:.88rem;color:var(--dim);max-width:74ch}
.tr-label em{font-style:normal;color:var(--dim);font-size:.86rem;font-weight:500}
.tr-count{font-size:.82rem;color:var(--dim);font-variant-numeric:tabular-nums;white-space:nowrap}
.tr-flat{font-size:.84rem;color:var(--dim)}
.spark{width:200px;height:44px;max-width:44vw}
.spark-line{fill:none;stroke:var(--orange);stroke-width:2.5;stroke-linejoin:round;stroke-linecap:round}
.spark-dot{fill:var(--paper)}
/* A filled-in value is drawn hollow and amber - the same colour the bars use for an
   approximate reading, so the two screens cannot disagree about what one looks like. */
.spark-dot.filled{fill:var(--ink);stroke:var(--warn);stroke-width:2}
.spark-miss{fill:none;stroke:var(--dim);stroke-width:1.5}
.move-chip.same,.move-chip.none{color:var(--dim)}
code{background:var(--navy-2);border-radius:5px;padding:1px 6px;font-size:.9em}
.stat-move .sm-track{grid-column:1 / -1;display:block;margin-top:5px}
.move-chip{display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:999px;
  font-size:.78rem;font-weight:600;border:1px solid var(--line);color:var(--dim)}
.move-chip.up{color:var(--ok);border-color:rgba(67,209,158,.4);background:rgba(67,209,158,.1)}
.move-chip.down{color:var(--warn);border-color:rgba(255,176,32,.4);background:rgba(255,176,32,.1)}
.stat-head{display:grid;gap:6px;justify-items:start}

/* The four weeks above the six bars, one square a day. Green because a filled square is
   a thing that happened - a drill finished or a take recorded - and not a grade. */
.act-days{display:grid;grid-template-columns:repeat(14,minmax(0,1fr));gap:6px;margin-top:14px}
.act{aspect-ratio:1;border-radius:5px;background:rgba(255,255,255,.05);border:1px solid var(--line)}
.act[data-on="true"]{background:rgba(67,209,158,.28);border-color:rgba(67,209,158,.5)}

/* ------------------------------------------------------------ the library -- */
/* The search box and the four counts.
   A filter is a place you are, and the five colours are already spoken for - orange is
   the next thing to do, blue is a label, green is measured - so the selected chip is
   paper rather than a hue. Any of them will do on a phone, where four chips and a
   search field are the whole of the page above the first drill. */
.filterbar{display:grid;gap:14px}
.search{display:flex;align-items:center;gap:10px;padding:10px 16px;border-radius:999px;
  border:1px solid var(--line);background:rgba(255,255,255,.03);transition:border-color .18s var(--ease)}
.search:focus-within{border-color:var(--orange);box-shadow:0 0 0 3px rgba(255,90,31,.22)}
.search svg{width:17px;height:17px;flex:none;color:var(--dim)}
.search input{flex:1;min-width:0;border:0;background:transparent;padding:0;font:inherit;
  font-size:.98rem;color:var(--paper)}
.search input:focus{outline:none;border:0;box-shadow:none}
.chips{display:flex;flex-wrap:wrap;gap:8px}
.chip{display:inline-flex;align-items:center;gap:8px;padding:7px 14px;border-radius:999px;
  border:1px solid var(--line);background:transparent;color:var(--dim);font:inherit;font-size:.88rem;
  font-weight:600;cursor:pointer;transition:color .18s var(--ease),border-color .18s var(--ease),background .18s var(--ease)}
.chip:hover{border-color:var(--line-strong);color:var(--paper)}
.chip b{font-variant-numeric:tabular-nums;opacity:.7;font-weight:600}
.chip[aria-pressed="true"]{border-color:var(--paper);color:var(--paper);background:rgba(255,255,255,.09)}
.chip[aria-pressed="true"] b{opacity:.9}
.saved-tag,.note-tag{color:var(--info)}

/* The note under a drill. It is the one box in the app that holds words the person
   wrote rather than numbers we measured, so it is deliberately plain. */
.note{width:100%;min-height:112px;resize:vertical;line-height:1.6;font-size:.96rem}

/* Reading a lesson with the furniture out of the way. The rail and the tab bar go while
   a drill is open and come back on any other route, so nothing has to be explained and
   nothing is unreachable for longer than the lesson takes to read. */
html.reading .rail,html.reading .tabs{display:none}
/* The rail is the shell's first grid column, so simply hiding it would slide the lesson
   into a 236px-wide column and wrap every line of the drill. Reading mode collapses the
   grid to one column instead, which is what the phone layout does for the same reason. */
html.reading .shell{grid-template-columns:minmax(0,1fr);gap:0;max-width:900px}

/* ----------------------------------------------- every take on one bar -- */
/* Take by take rather than first against latest, for the bar that went up and came back
   down in between. The line is drawn only between readings that exist: a take where a
   bar was not measured leaves a dashed mark and breaks the line, because a segment
   across a gap is a measurement nobody made. */
.trend-row{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:14px;align-items:center;
  padding:12px 0;border-bottom:1px solid var(--line)}
.trend-row:last-child{border-bottom:0}
.tr-label{display:grid;font-weight:600}

/* -------------------------------------------------------------- documents -- */
/* Privacy and terms: the same room as the product, one column of prose. They are
   static pages with no scripts, because a page about what we do with your data
   should not need an app to boot before it can be read. */
.doc-wrap{width:min(760px,100% - 40px);margin:0 auto;padding:44px 0 80px}
.doc h1{font-size:clamp(1.7rem,3.4vw,2.4rem);margin-bottom:12px}
.doc h2{font-size:1.2rem;margin:34px 0 6px}
.doc p,.doc li{color:var(--dim);line-height:1.7}
.doc p{margin:10px 0}
.doc ul{margin:10px 0;padding-left:22px;display:grid;gap:6px}
.doc strong{color:var(--paper)}
.doc a{color:var(--orange);text-decoration:none}
.doc a:hover{text-decoration:underline}
.doc .updated{color:var(--dim);font-size:.86rem}
.doc code{background:var(--navy-2);border-radius:5px;padding:1px 6px;font-size:.9em}
.doc-foot{margin-top:44px;padding-top:20px;border-top:1px solid var(--line);display:flex;gap:22px;
  flex-wrap:wrap;font-size:.9rem}
.doc-foot a{color:var(--dim);text-decoration:none}
.doc-foot a:hover{color:var(--paper)}

/* ------------------------------------------------------------------- misc -- */
.empty{display:grid;gap:16px;justify-items:center;text-align:center;padding:40px 20px;color:var(--dim)}
.kv{display:grid;grid-template-columns:auto 1fr;gap:8px 18px;font-size:.95rem}
.kv dt{color:var(--dim)}
.kv dd{margin:0;font-weight:600}
.stat{display:grid;gap:2px}
.stat b{font-family:var(--display);font-size:1.9rem;letter-spacing:-.03em;line-height:1}
.stat span{color:var(--dim);font-size:.85rem}
.spinner{width:20px;height:20px;border-radius:50%;border:3px solid rgba(255,255,255,.25);border-top-color:var(--paper);animation:spin .8s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.loading-screen{min-height:100vh;display:grid;place-items:center;gap:18px;text-align:center;padding:24px}

/* A short window is the common case - a laptop with its browser chrome, a phone lying
   sideways - and it is the one where a sign-up form grows a scrollbar for no reason but
   its own padding. The spare spacing goes first, before the button is allowed below the
   fold. */
@media (max-height:820px){
  .auth-form-col{padding:12px 24px}
  .auth-aside{padding:26px}
  .auth-card .tabs-switch{margin-bottom:12px}
  .auth-card .field{margin-bottom:9px}
  .auth-card .divider{margin:11px 0}
  .demo-line{margin-bottom:12px}
}

@media (max-width:980px){
  .shell{grid-template-columns:minmax(0,1fr);gap:22px;padding-bottom:120px}
  .rail{display:none}
  .tabs{display:flex}
  .bar nav{display:none}
  /* Stacked, the aside has to stop being half a screen: two short lines and the guy,
     so the form underneath it is still whole on the first screen. */
  .auth-wrap{grid-template-columns:minmax(0,1fr);min-height:auto}
  .auth-aside{padding:20px;gap:14px;min-height:auto}
  .auth-aside h2{font-size:clamp(1.35rem,5.4vw,1.75rem);max-width:26ch}
  .auth-aside .lede{display:none}
  .auth-aside .guy-stage{margin-top:0!important;gap:14px}
  .auth-aside .guy-stage .guy{height:70px}
  .auth-form-col{padding:18px}
}
@media (max-width:560px){
  /* Toasts move to the top on a phone: the bottom band holds the tab bar and the
     orange guy, and a toast landing on top of either one was the other half of
     "it covers important information". */
  .bar .inner{width:calc(100% - 28px);height:64px}
  .bar .wordmark img{height:30px}
  .shell{width:calc(100% - 28px);padding-top:22px}
  .card{padding:18px}
  .card.pad-lg{padding:20px}
  .stage-wrap{aspect-ratio:3/4;max-height:none}
  .lesson{grid-template-columns:auto minmax(0,1fr);gap:14px}
  .lesson .chev{display:none}
  /* A recording row has five columns of detail; on a phone the two that matter -
     which take it was and what it scored - keep a line of their own. */
  .rec-row{grid-template-columns:auto auto;grid-template-areas:"when score" "kind kind" "meta meta";gap:6px 12px}
  .rec-row .when{grid-area:when}
  .rec-row .score{grid-area:score;justify-self:end}
  .rec-row .kind{grid-area:kind}
  .rec-row .meta{grid-area:meta}
  .rec-row .chev{display:none}
  .btn-row .btn{flex:1 1 100%}
  .toasts{left:14px;right:14px;top:calc(var(--bar-h) + 10px);bottom:auto;max-width:none}
}
/* A phone, on the one screen whose entire job is to be one screen. The bubble goes and
   the headline narrows: at 844 pixels of height, a name, an email, a password, a
   checkbox, a divider, a Google button and the legal line do not leave room for a
   cartoon as well - and the button below the fold is the thing that costs a sign-up.
   He is on the landing page before this and inside the app after it. */
@media (max-width:640px){
  .auth-aside{padding:16px 18px;gap:8px}
  .auth-aside h2{font-size:1.28rem;max-width:none}
  .auth-aside .guy-stage{display:none}
  .auth-aside .wordmark img{height:30px}
}
/* Reduced motion, honoured only when somebody asked for it.
   The device setting is read from the document class rather than from the media
   query alone, because on Windows this query is driven by "Show animations in
   Windows" - a display setting that is off on plenty of machines nobody ever chose
   it on. With it off, every animation in this product was dead and the guy did not
   walk anywhere, he arrived. The class is set in <head> (and from the profile's
   switch); ?motion=off hands full control back to the device setting. */
@media (prefers-reduced-motion:reduce){
  html:not(.motion-on) .guy .bob,html:not(.motion-on) .guy .armL,html:not(.motion-on) .guy .armR,
  html:not(.motion-on) .guy .zzz,html:not(.motion-on) .guy .legs path{animation:none!important}
  html:not(.motion-on) .confetti{display:none}
  html:not(.motion-on) .sli .fill,html:not(.motion-on) .sli .knob,html:not(.motion-on) .chart *{transition:none}
  html:not(.motion-on){scroll-behavior:auto}
}
