/* Learnify — design system.
 *
 * Read off the 17 screenshots of the old app, then tightened. The rules the
 * operator set: minimal, more icons and fewer words, smaller buttons and cards
 * (small, not tiny), nothing overlapping, and as little scrolling as possible.
 *
 * Structure:
 *   1. tokens        2. shell + phone frame     3. header + balances
 *   4. stage          5. icon buttons            6. cards + lists
 *   7. buttons        8. sheets (modals)         9. motion
 */

/* ── 1. tokens ───────────────────────────────────────────────────────────── */
:root{
  --bg:#070B14;            /* app ground, matches the screenshots            */
  --bg-2:#0B1220;
  --surface:#131B2E;       /* cards                                          */
  --surface-2:#18223A;     /* raised / hover                                 */
  --line:rgba(148,168,200,.14);
  --line-2:rgba(148,168,200,.24);
  --text:#E8EEFB;
  --muted:#8FA0BD;
  --subtle:#64748B;

  --blue:#3B82F6;  --blue-2:#2563EB;   /* primary action                     */
  --green:#22C55E; --green-2:#16A34A;  /* cash                               */
  --gold:#F5B301;  --gold-2:#D99A00;   /* points                             */
  --red:#EF4444;                        /* live / danger                      */
  --teal:#2DD4BF;
  --violet:#7B4DFF;

  --r-sm:10px; --r-md:14px; --r-lg:18px; --r-xl:24px; --r-pill:999px;

  /* One spacing scale. Every gap in the app is one of these five. */
  --s1:6px; --s2:10px; --s3:14px; --s4:18px; --s5:26px;

  --shadow:0 10px 30px rgba(0,0,0,.45);
  --shadow-lg:0 24px 64px rgba(0,0,0,.6);
  --ring:0 0 0 1px var(--line);

  /* Motion. One easing for everything so the app feels like one object. */
  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-out:cubic-bezier(.16,1,.3,1);
  --fast:140ms; --base:240ms; --slow:420ms;
}

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{height:100%}
body{
  margin:0;background:var(--bg);color:var(--text);
  font:14px/1.5 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  -webkit-font-smoothing:antialiased;overscroll-behavior:none;
}
img{max-width:100%;display:block}
button{font:inherit;color:inherit}

/* ── 2. shell + phone frame ──────────────────────────────────────────────────
   The app is a 9:16 phone. On a desktop it is centred at its real width rather
   than stretched, so the layout the screenshots describe is what everyone sees. */
#app{
  position:relative;width:100%;max-width:430px;margin:0 auto;min-height:100dvh;
  display:flex;flex-direction:column;
  /* The operator's own artwork (941x1672, a 9:16 plate) is the ground; the two
     radial washes sit over it so the beams and particles still read on top.
     `learnifybg` has no file extension on purpose — it is served by content
     type, so the url() is written exactly as the file is named. */
  background:
    radial-gradient(120% 60% at 50% -10%,rgba(59,130,246,.16),transparent 60%),
    radial-gradient(90% 50% at 50% 100%,rgba(123,77,255,.12),transparent 60%),
    /* .png, not the extensionless original: Apache serves a file with no
       extension with an EMPTY Content-Type, and a browser refuses to paint that
       as a background. Same bytes, correct type. */
    url("../learnifybg.png") center top / cover no-repeat,
    var(--bg);
  /* Same art as WebP: 23 KB instead of 1.28 MB on the first paint. A WebView
     without image-set() drops this declaration and keeps the PNG above. */
  background:
    radial-gradient(120% 60% at 50% -10%,rgba(59,130,246,.16),transparent 60%),
    radial-gradient(90% 50% at 50% 100%,rgba(123,77,255,.12),transparent 60%),
    image-set(url("../learnifybg.webp") type("image/webp"), url("../learnifybg.png") type("image/png")) center top / cover no-repeat,
    var(--bg);
  overflow:hidden;
}
/* A sheet pushed down the stack stays mounted but hidden, so returning to it
   restores its scroll position and its already-loaded data instead of
   refetching. .open and .stacked are mutually exclusive. */
.sheet.stacked{display:none}
/* Empty/no-fill banner slots occupy no space. Keep the provider's image
   proportional inside the phone frame, away from fixed navigation. */
.richads-banner{flex:none;min-width:0}
.richads-banner:empty{display:none}
.richads-banner:not(:empty){margin:12px 16px 0}
.richads-banner .banner-block-tg{display:block;width:100%}
.richads-banner img{display:block;width:100%;height:auto;max-width:100%;border-radius:12px}
.popup-points-card{display:grid;grid-template-columns:30px minmax(0,1fr) auto;align-items:center;gap:10px;flex:none;margin:12px 0;padding:12px;border:1px solid rgba(148,163,184,.25);border-radius:14px;background:linear-gradient(120deg,rgba(59,130,246,.12),rgba(123,77,255,.1));color:var(--text)}
#learnify-popup-points-home:empty{display:none}
#learnify-popup-points-home .popup-points-card{margin:12px 16px 0}
.popup-points-icon{display:grid;place-items:center;width:30px;height:30px;border-radius:10px;background:rgba(96,165,250,.15);color:#93c5fd;font-size:22px}
.popup-points-copy{min-width:0}
.popup-points-copy small{display:block;font-size:8px;letter-spacing:.08em;color:#93c5fd}
.popup-points-copy b{display:block;font-size:12px}
.popup-points-copy p{margin:2px 0 0;font-size:10px;line-height:1.4;opacity:.7}
.popup-points-card button{padding:9px 10px;border:1px solid rgba(96,165,250,.35);border-radius:10px;background:rgba(59,130,246,.16);color:#dbeafe;font-size:10px;font-weight:700;cursor:pointer}
.popup-points-card button:disabled{opacity:.6;cursor:wait}
.popup-points-message{grid-column:1/-1;margin:0;font-size:11px;line-height:1.4}
.popup-points-message:empty{display:none}
@media(max-width:359px){.popup-points-card{grid-template-columns:24px minmax(0,1fr);gap:8px}.popup-points-card button{grid-column:2;justify-self:start}.popup-points-icon{width:24px;height:24px}}
@media (min-width:481px){
  body{background:#05070D}
  #app{box-shadow:0 0 0 1px var(--line),var(--shadow-lg)}
}

/* The empty top nav bar, kept deliberately: Telegram draws its own controls
   over this strip, and the old app reserved it. Removing it makes the header
   collide with the platform UI. */
.topbar{height:env(safe-area-inset-top,0px);min-height:8px;flex:none}

/* The two floating controls that sit on every full page. */
.float-controls{display:flex;justify-content:center;gap:var(--s2);padding:var(--s2) 0 var(--s1)}
.fc-btn{
  width:38px;height:38px;display:grid;place-items:center;flex:none;
  border:1px solid var(--line);border-radius:12px;background:var(--surface);
  cursor:pointer;transition:transform var(--fast) var(--ease),background var(--fast);
}
.fc-btn:active{transform:scale(.92)}
.fc-btn.is-sound{background:rgba(239,68,68,.12);border-color:rgba(239,68,68,.28)}
.fc-btn svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:2}

/* ── 3. header + balances ────────────────────────────────────────────────── */
.idbar{
  display:flex;align-items:center;gap:var(--s2);
  margin:0 var(--s3);padding:var(--s2);
  border:1px solid var(--line);border-radius:var(--r-lg);
  background:linear-gradient(180deg,var(--surface-2),var(--surface));
}
.idbar-avatar{width:42px;height:42px;border-radius:50%;flex:none;object-fit:cover;
  border:1px solid var(--line-2);background:var(--bg-2)}
.idbar-who{min-width:0;flex:1}
.idbar-who b{display:block;font-size:14px;font-weight:800;letter-spacing:-.01em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.idbar-who small{color:var(--subtle);font-size:11px}

/* Balance pills. Points are gold, cash is green — the two never share a colour,
   because that is the one thing a player must not misread. */
.pill{
  display:inline-flex;align-items:center;gap:6px;flex:none;
  padding:7px 11px;border-radius:var(--r-pill);
  border:1px solid var(--line);background:rgba(255,255,255,.03);
  font-size:13px;font-weight:800;font-variant-numeric:tabular-nums;
}
.pill img{width:16px;height:16px}
.pill.is-points{border-color:rgba(245,179,1,.26);color:#FFD166}
.pill.is-cash{border-color:rgba(34,197,94,.26);color:#5EE9A0}

/* ── live withdrawals ticker ─────────────────────────────────────────────── */
.ticker{
  display:flex;align-items:center;gap:var(--s2);overflow:hidden;
  margin:var(--s2) var(--s3) 0;padding:8px var(--s2);
  border:1px solid var(--line);border-radius:var(--r-md);
  background:rgba(255,255,255,.02);
}
.ticker-live{display:inline-flex;align-items:center;gap:5px;flex:none;
  font-size:10px;font-weight:900;letter-spacing:.08em;color:#7CF0A8}
.ticker-live i{width:6px;height:6px;border-radius:50%;background:#22C55E;
  box-shadow:0 0 0 0 rgba(34,197,94,.6);animation:pulse 1.8s infinite}
@keyframes pulse{70%{box-shadow:0 0 0 7px rgba(34,197,94,0)}100%{box-shadow:0 0 0 0 rgba(34,197,94,0)}}
.ticker-track{display:flex;align-items:center;gap:var(--s2);width:max-content;white-space:nowrap;animation:slide 36s linear infinite}
.ticker-track:hover{animation-play-state:paused}
@keyframes slide{from{transform:translateX(0)}to{transform:translateX(-50%)}}
.ticker-item{display:inline-flex;align-items:center;gap:5px;min-height:26px;padding:2px 8px 2px 3px;border:1px solid rgba(255,255,255,.09);border-radius:999px;background:rgba(255,255,255,.045);font-size:11px;color:var(--muted)}
.ticker-item b{color:var(--text);font-weight:700}
.ticker-item em{color:#5EE9A0;font-style:normal;font-weight:800}
.ticker-avatar{position:relative;display:grid;place-items:center;flex:none;width:21px;height:21px;overflow:hidden;border-radius:50%;border:1px solid rgba(255,255,255,.23);background:linear-gradient(135deg,#334b86,#7750aa);color:#fff;font-size:9px;font-weight:800}
.ticker-avatar img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.ticker-person{display:inline-flex;align-items:baseline;gap:4px}
.ticker-person small{font-size:9px;color:var(--muted)}
.ticker-method{padding-left:5px;border-left:1px solid var(--line);font-size:9px;color:var(--muted)}
@media(prefers-reduced-motion:reduce){.ticker-track{animation:none}}

/* ── 4. stage ────────────────────────────────────────────────────────────────
   The signature screen: light beams and drifting particles behind a ring of
   icon buttons, with EARN at the centre. Positions match the old app exactly —
   the operator asked for the same placements, and muscle memory is real. */
.stage{position:relative;flex:1;min-height:430px;margin-top:var(--s2)}
.stage-bg{position:absolute;inset:0;overflow:hidden;pointer-events:none}
.beam{position:absolute;top:-12%;width:56%;height:130%;opacity:.5;
  background:linear-gradient(180deg,rgba(59,130,246,.34),transparent 72%);
  filter:blur(14px);transform-origin:50% 0}
.beam.b1{left:-10%;transform:rotate(14deg)}
.beam.b2{right:-12%;transform:rotate(-16deg);background:linear-gradient(180deg,rgba(123,77,255,.3),transparent 72%)}
.beam.b3{left:32%;width:34%;transform:rotate(2deg);background:linear-gradient(180deg,rgba(45,212,191,.2),transparent 70%)}
#particles{position:absolute;inset:0;width:100%;height:100%}

/* ── 5. icon buttons ─────────────────────────────────────────────────────── */
.stage-col{position:absolute;top:5%;display:flex;flex-direction:column;gap:var(--s5);z-index:2}
.stage-col.left{left:var(--s3)}
.stage-col.right{right:var(--s3)}
.stage-row{position:absolute;left:0;right:0;bottom:var(--s4);z-index:2;
  display:flex;justify-content:space-around;padding:0 var(--s3)}

.ibtn{
  position:relative;display:flex;flex-direction:column;align-items:center;gap:5px;
  width:64px;background:none;border:0;padding:0;cursor:pointer;
  transition:transform var(--fast) var(--ease);
}
.ibtn:active{transform:scale(.9)}
.ibtn-art{
  width:52px;height:52px;display:grid;place-items:center;border-radius:15px;
  background:linear-gradient(180deg,rgba(255,255,255,.07),rgba(255,255,255,.02));
  border:1px solid var(--line);box-shadow:var(--shadow);
  transition:border-color var(--base),box-shadow var(--base),transform var(--base) var(--ease-out);
}
.ibtn:hover .ibtn-art{border-color:var(--line-2);transform:translateY(-2px)}
.ibtn-art img{width:36px;height:36px;object-fit:contain;filter:drop-shadow(0 3px 8px rgba(0,0,0,.5))}
.ibtn-label{font-size:11px;font-weight:700;color:#CBD5E1;text-shadow:0 1px 4px rgba(0,0,0,.7)}
/* The unread mark. One dot, always the same place, never a number. */
.ibtn-dot{position:absolute;top:-3px;right:8px;width:11px;height:11px;border-radius:50%;
  background:var(--red);border:2px solid var(--bg);box-shadow:0 0 10px rgba(239,68,68,.8)}

/* EARN — the one thing on the screen that is allowed to be loud. */
.earn{
  position:absolute;left:50%;top:52%;transform:translate(-50%,-50%);z-index:3;
  display:flex;flex-direction:column;align-items:center;gap:var(--s1);
  background:none;border:0;cursor:pointer;
}
.earn-art{
  width:84px;height:84px;border-radius:50%;display:grid;place-items:center;
  background:radial-gradient(circle at 38% 32%,#FFE28A,#F5B301 46%,#B8770A);
  box-shadow:0 0 0 6px rgba(245,179,1,.12),0 0 34px rgba(245,179,1,.45),var(--shadow);
  animation:breathe 3.4s var(--ease) infinite;
}
.earn-art img{width:52px;height:52px}
@keyframes breathe{0%,100%{transform:scale(1)}50%{transform:scale(1.045)}}
.earn:active .earn-art{transform:scale(.94)}
.earn-label{font-size:13px;font-weight:900;letter-spacing:.09em;color:#FFD166;
  text-shadow:0 2px 10px rgba(0,0,0,.8)}

/* The two arrows that point into EARN, exactly as the old home screen drew. */
.arrow{position:absolute;top:44%;width:74px;height:44px;z-index:2;pointer-events:none;opacity:.9}
.arrow.a-left{left:19%}
.arrow.a-right{right:19%;transform:scaleX(-1)}
.arrow path{fill:none;stroke:#F5B301;stroke-width:3.4;stroke-linecap:round;
  stroke-dasharray:120;stroke-dashoffset:120;animation:draw 2.4s var(--ease) infinite}
@keyframes draw{0%{stroke-dashoffset:120;opacity:0}25%{opacity:1}70%{stroke-dashoffset:0;opacity:1}100%{stroke-dashoffset:0;opacity:0}}

/* ── 6. cards + lists ────────────────────────────────────────────────────── */
.card{border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface);padding:var(--s3)}
.card+.card{margin-top:var(--s2)}
.card-head{display:flex;align-items:center;gap:var(--s2);margin-bottom:var(--s2)}
.card-head b{font-size:14px;font-weight:800}
.eyebrow{font-size:10px;font-weight:900;letter-spacing:.12em;text-transform:uppercase;color:var(--violet)}

/* One row shape for every list in the app: art, copy, trailing control. */
.row{
  display:flex;align-items:center;gap:var(--s2);width:100%;text-align:left;
  padding:var(--s2);border:1px solid var(--line);border-radius:var(--r-md);
  background:rgba(255,255,255,.02);cursor:pointer;
  transition:background var(--fast),border-color var(--fast),transform var(--fast) var(--ease);
}
.row:active{transform:scale(.985)}
.row:hover{background:rgba(255,255,255,.045);border-color:var(--line-2)}
.row+.row{margin-top:var(--s1)}
.row-art{width:40px;height:40px;border-radius:11px;flex:none;display:grid;place-items:center;
  background:rgba(255,255,255,.05);border:1px solid var(--line)}
.row-art img{width:26px;height:26px;object-fit:contain}
.row-copy{min-width:0;flex:1}
.row-copy b{display:block;font-size:13.5px;font-weight:700}
.row-copy small{display:block;color:var(--muted);font-size:11.5px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.row-go{color:var(--subtle);flex:none}

/* Reward chips — small, tabular, never wrapping mid-number. */
.chip{display:inline-flex;align-items:center;gap:4px;padding:4px 9px;border-radius:var(--r-pill);
  font-size:11.5px;font-weight:800;font-variant-numeric:tabular-nums;
  background:rgba(255,255,255,.05);border:1px solid var(--line)}
.chip img{width:13px;height:13px}
.chip.is-points{color:#FFD166;border-color:rgba(245,179,1,.24)}
.chip.is-cash{color:#5EE9A0;border-color:rgba(34,197,94,.24)}

/* Progress */
.bar{height:6px;border-radius:var(--r-pill);background:rgba(255,255,255,.07);overflow:hidden}
.bar i{display:block;height:100%;border-radius:inherit;
  background:linear-gradient(90deg,var(--blue),var(--teal));
  transition:width var(--slow) var(--ease-out)}

/* ── 7. buttons ──────────────────────────────────────────────────────────── */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:7px;
  padding:11px 16px;border:1px solid transparent;border-radius:var(--r-md);
  font-size:13.5px;font-weight:800;cursor:pointer;position:relative;overflow:hidden;
  transition:transform var(--fast) var(--ease),filter var(--fast),box-shadow var(--base);
}
.btn:active{transform:translateY(1px) scale(.99)}
.btn-block{display:flex;width:100%}
.btn-primary{background:linear-gradient(135deg,var(--blue),var(--blue-2));color:#fff;
  box-shadow:0 8px 22px rgba(37,99,235,.36)}
.btn-primary:hover{filter:brightness(1.07)}
.btn-gold{background:linear-gradient(135deg,#FFD166,var(--gold-2));color:#2A1B00;
  box-shadow:0 8px 22px rgba(245,179,1,.34)}
.btn-ghost{background:rgba(255,255,255,.05);border-color:var(--line);color:var(--text)}
.btn:disabled{opacity:.5;cursor:not-allowed;transform:none}

/* The specialised button: a light sweeps across it once on press. Costs one
   pseudo-element, reads as "premium", and never blocks the tap. */
.btn-shine::after{
  content:"";position:absolute;inset:0;pointer-events:none;transform:translateX(-120%);
  background:linear-gradient(100deg,transparent 20%,rgba(255,255,255,.38),transparent 80%);
}
.btn-shine:active::after{animation:shine .6s var(--ease-out)}
@keyframes shine{to{transform:translateX(120%)}}

/* ── 8. sheets (modals) ──────────────────────────────────────────────────────
   Every secondary screen is a bottom sheet: it rises over the home screen,
   which stays visible and blurred behind. Back is a boxed arrow top-left and
   the title is centred — the shape the old app used on all 13 of its screens. */
.scrim{
  position:fixed;inset:0;z-index:60;display:none;
  background:rgba(4,7,14,.62);backdrop-filter:blur(7px);-webkit-backdrop-filter:blur(7px);
}
.scrim.open{display:block;animation:fade var(--base) var(--ease) both}
@keyframes fade{from{opacity:0}to{opacity:1}}

.sheet{
  position:fixed;left:50%;bottom:0;transform:translateX(-50%);z-index:61;
  width:100%;max-width:430px;max-height:92dvh;display:none;flex-direction:column;
  border-radius:var(--r-xl) var(--r-xl) 0 0;border:1px solid var(--line);border-bottom:0;
  background:linear-gradient(180deg,var(--surface-2),var(--bg-2) 42%);
  box-shadow:var(--shadow-lg);
}
.sheet.open{display:flex;animation:rise var(--slow) var(--ease-out) both}
@keyframes rise{from{transform:translate(-50%,7%);opacity:0}to{transform:translate(-50%,0);opacity:1}}
.sheet-head{
  display:flex;align-items:center;gap:var(--s2);flex:none;
  padding:var(--s3);border-bottom:1px solid var(--line);
}
.sheet-back{width:36px;height:36px;flex:none;display:grid;place-items:center;cursor:pointer;
  border:1px solid var(--line);border-radius:11px;background:rgba(255,255,255,.05)}
.sheet-back svg{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:2.2}
.sheet-title{flex:1;text-align:center;font-size:15px;font-weight:800;
  /* The back button is 36px, so the title is padded by the same on the right —
     otherwise "centred" is off by half a button and every screen looks crooked. */
  padding-right:36px}
.sheet-body{padding:var(--s3);overflow-y:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch}
.sheet-body>*+*{margin-top:var(--s2)}

/* ── 8b. sheet pieces ─────────────────────────────────────────────────────
   Used by the balance sheets. Kept with the design system rather than inlined
   in the partial, so a spacing change lands everywhere at once. */

/* The rank crest. A real hexagon via clip-path — a rotated square leaves the
   icon inside it rotated too, which is why the old build used an image. */
.badge-hex{
  width:92px;height:92px;margin:0 auto;display:grid;place-items:center;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
  background:linear-gradient(160deg,#A8B6CC,#5A6982 55%,#39445A);
  box-shadow:0 12px 30px rgba(0,0,0,.5);
}
.badge-hex img{width:38px;height:38px;filter:drop-shadow(0 2px 6px rgba(0,0,0,.55))}

/* Two-up action tiles (My Points). Square-ish, icon-led, one word plus a hint. */
.grid-2{display:grid;grid-template-columns:1fr 1fr;gap:var(--s2)}
.tile{
  display:flex;flex-direction:column;align-items:center;gap:3px;
  padding:var(--s3) var(--s2);cursor:pointer;
  border:1px solid var(--line);border-radius:var(--r-md);
  background:rgba(255,255,255,.03);
  transition:transform var(--fast) var(--ease),background var(--fast),border-color var(--fast);
}
.tile:active{transform:scale(.97)}
.tile:hover{background:rgba(255,255,255,.055);border-color:var(--line-2)}
.tile b{font-size:13px;font-weight:800}
.tile small{color:var(--muted);font-size:11px}
.tile-art{
  width:40px;height:40px;margin-bottom:3px;display:grid;place-items:center;
  border-radius:12px;background:rgba(255,255,255,.05);border:1px solid var(--line);
}
.tile-art img{width:24px;height:24px;object-fit:contain}

/* ── 8c. tabs, countdown, notes ───────────────────────────────────────────
   Used by the social sheets. Two tabs sit side by side rather than stacking,
   because a board you cannot see is a board nobody switches to. */
.tabs{display:grid;grid-template-columns:1fr 1fr;gap:var(--s2)}
.tab{
  display:flex;flex-direction:column;gap:2px;padding:var(--s2) var(--s3);text-align:left;cursor:pointer;
  border:1px solid var(--line);border-radius:var(--r-md);background:rgba(255,255,255,.03);
  transition:background var(--fast),border-color var(--fast),transform var(--fast) var(--ease);
}
.tab:active{transform:scale(.98)}
.tab b{font-size:13.5px;font-weight:800}
.tab small{color:var(--muted);font-size:11px}
.tab.on{background:rgba(45,212,191,.1);border-color:rgba(45,212,191,.4)}
.tab.on b{color:#7FE8DC}

/* Four fixed cells so the numbers never reflow as they tick down. */
.countdown{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s1);margin-top:var(--s3)}
.countdown span{
  display:flex;flex-direction:column;align-items:center;gap:1px;padding:8px 4px;
  border:1px solid var(--line);border-radius:var(--r-sm);background:rgba(255,255,255,.03);
}
.countdown b{font-size:17px;font-weight:900;font-variant-numeric:tabular-nums}
.countdown small{font-size:9px;font-weight:800;letter-spacing:.08em;color:var(--muted)}

/* One inline message line under a form. Empty by default so it takes no space
   until there is something to say. */
.form-note{margin-top:var(--s2);font-size:12px;line-height:1.5;color:var(--muted);min-height:0}
.form-note:empty{margin:0}
.form-note.is-bad{color:#FCA5A5}
.form-note.is-ok{color:#5EE9A0}

.duel-hero{text-align:center;border-color:rgba(244,63,94,.28);
  background:linear-gradient(170deg,rgba(244,63,94,.14),var(--surface) 62%)}
.duel-hero img{margin:0 auto}

/* ── 8d. form fields ──────────────────────────────────────────────────────
   One input treatment for the whole app. Font-size is 16px on purpose: any
   smaller and iOS Safari zooms the page when the field is focused, which on a
   fixed 9:16 layout looks like the app breaking. */
.field-label{
  display:block;margin-bottom:6px;font-size:10.5px;font-weight:900;
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted);
}
.field{
  width:100%;padding:11px var(--s3);border:1px solid var(--line);border-radius:var(--r-md);
  background:rgba(255,255,255,.04);color:var(--text);font:600 16px/1.2 inherit;
  transition:border-color var(--fast),background var(--fast);
}
.field:focus{outline:none;border-color:rgba(59,130,246,.55);background:rgba(59,130,246,.07)}
.field::placeholder{color:var(--subtle);font-weight:500}
.field:disabled{opacity:.55;cursor:not-allowed}
select.field{appearance:none;cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,var(--muted) 50%),
                   linear-gradient(135deg,var(--muted) 50%,transparent 50%);
  background-position:calc(100% - 17px) 52%,calc(100% - 12px) 52%;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:34px}
/* An unstyled <option> renders white-on-white on some Android WebViews. */
select.field option{background:#131B2E;color:#E8EEFB}

/* ── 8e. quiz ─────────────────────────────────────────────────────────────
   The playing screen: counter, timer ring, earned chip, then the question. */
.qz-top{display:flex;align-items:center;justify-content:space-between;gap:var(--s2)}

/* The per-question ring. One conic-gradient driven by --p (100 → 0), so the
   countdown costs no layout and no SVG. Turns amber then red as it runs out. */
.qz-ring{
  position:relative;width:46px;height:46px;flex:none;display:grid;place-items:center;
  border-radius:50%;
  background:conic-gradient(var(--ring-c,var(--blue)) calc(var(--p,100)*1%),rgba(255,255,255,.09) 0);
  transition:--p .95s linear;
}
.qz-ring::before{content:"";position:absolute;inset:4px;border-radius:50%;background:var(--surface)}
.qz-ring b{position:relative;font-size:15px;font-weight:900;font-variant-numeric:tabular-nums}
.qz-ring.warn{--ring-c:var(--gold)}
.qz-ring.danger{--ring-c:var(--red)}
@property --p{syntax:'<number>';inherits:true;initial-value:100}

/* Choices. Letter tile + text, and the result colours the whole row so the
   answer is readable at a glance rather than by a small icon. */
.qz-choice{
  display:flex;align-items:center;gap:var(--s2);width:100%;text-align:left;cursor:pointer;
  padding:var(--s2) var(--s3);border:1px solid var(--line);border-radius:var(--r-md);
  background:rgba(255,255,255,.03);font-size:13.5px;font-weight:600;
  transition:transform var(--fast) var(--ease),background var(--fast),border-color var(--fast);
}
.qz-choice:active{transform:scale(.985)}
.qz-choice:disabled{cursor:default}
.qz-choice-letter{
  width:28px;height:28px;flex:none;display:grid;place-items:center;border-radius:9px;
  background:linear-gradient(180deg,rgba(255,255,255,.1),rgba(255,255,255,.03));
  border:1px solid var(--line);font-size:12.5px;font-weight:900;
}
.qz-choice.correct{border-color:rgba(34,197,94,.55);background:rgba(34,197,94,.12)}
.qz-choice.correct .qz-choice-letter{background:rgba(34,197,94,.25);border-color:transparent}
.qz-choice.wrong{border-color:rgba(239,68,68,.55);background:rgba(239,68,68,.12)}
.qz-choice.wrong .qz-choice-letter{background:rgba(239,68,68,.25);border-color:transparent}

/* ── 9. motion ───────────────────────────────────────────────────────────── */
.rise-in{animation:riseIn var(--base) var(--ease-out) both}
.rise-in:nth-child(2){animation-delay:40ms}
.rise-in:nth-child(3){animation-delay:80ms}
.rise-in:nth-child(4){animation-delay:120ms}
@keyframes riseIn{from{opacity:0;transform:translateY(9px)}to{opacity:1;transform:none}}

/* Boot screen: the logo, and nothing else to read. */
#boot{position:fixed;inset:0;z-index:90;display:grid;place-items:center;background:var(--bg);
  transition:opacity var(--slow) var(--ease),visibility var(--slow)}
#boot.gone{opacity:0;visibility:hidden}
.boot-mark{width:92px;height:92px;border-radius:26px;display:grid;place-items:center;
  background:linear-gradient(180deg,rgba(255,255,255,.08),rgba(255,255,255,.02));
  border:1px solid var(--line);box-shadow:0 0 46px rgba(59,130,246,.3);
  animation:bootPulse 1.6s var(--ease) infinite}
.boot-mark img{width:62px;height:62px}
@keyframes bootPulse{0%,100%{transform:scale(1);box-shadow:0 0 40px rgba(59,130,246,.26)}
  50%{transform:scale(1.06);box-shadow:0 0 62px rgba(59,130,246,.46)}}
.boot-bar{width:120px;height:3px;margin-top:var(--s4);border-radius:var(--r-pill);
  background:rgba(255,255,255,.1);overflow:hidden;position:relative}
.boot-bar i{position:absolute;inset:0;width:40%;border-radius:inherit;
  background:linear-gradient(90deg,transparent,var(--blue),transparent);
  animation:bootSweep 1.2s var(--ease) infinite}
@keyframes bootSweep{from{transform:translateX(-110%)}to{transform:translateX(300%)}}

/* The runtime never started (index.php watchdog): a message and a Reload button, not an endless logo. */
.boot-fail{display:grid;justify-items:center;gap:10px;max-width:290px;padding:24px;text-align:center;
  color:#94A3B8;font-size:13.5px;line-height:1.5}
.boot-fail img{border-radius:16px;opacity:.9}
.boot-fail b{color:#F1F5F9;font-size:16px}
.boot-fail button{margin-top:6px;padding:11px 26px;border:0;border-radius:999px;cursor:pointer;
  background:linear-gradient(135deg,#3B82F6,#7B4DFF);color:#fff;font:800 14px/1 inherit}

/* A sheet that could not load: one card, one Retry (screens.js onLoad). */
.nl-load-error{display:flex;align-items:center;gap:10px;justify-content:space-between;
  border-color:rgba(239,68,68,.32)!important;color:#FCA5A5;font-size:13px;line-height:1.45}
.nl-load-error .btn{flex:none;padding:8px 14px;font-size:12.5px}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important}
}
