
/* Material 3 design tokens (light + dark), matching the Pramaan mobile app:
   tonal surfaces, an indigo primary, M3 shape (rounded cards, pill buttons,
   outlined fields) and the M3 type/elevation scale. Fonts are SELF-HOSTED at
   /static/*.woff2 (same-origin, so the strict default-src 'self' CSP allows
   them — no Google Fonts / external fetch): Inter for UI, Space Grotesk for
   display, mirroring the mobile app. */
@font-face{font-family:'Inter';font-style:normal;font-weight:100 900;font-display:swap;
  src:url(/static/inter-var.woff2) format('woff2')}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:300 700;font-display:swap;
  src:url(/static/space-grotesk-var.woff2) format('woff2')}
:root{
  color-scheme:light dark;
  --font-sans:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;
  --font-display:'Space Grotesk',var(--font-sans);
  --bg:#ffffff;--surface:#ffffff;--surface-2:#f1edf9;--surface-3:#eae6f6;
  --ink:#1b1b21;--ink-2:#46464f;--ink-3:#74737d;
  --outline:#c6c5d0;--outline-2:#e4e1ec;
  --brand:#4f46e5;--on-brand:#ffffff;--brand-cont:#e3e0ff;--on-brand-cont:#15136b;
  --ok:#146c2e;--err:#ba1a1a;
  --r-sm:8px;--r-md:12px;--r-lg:16px;--r-xl:28px;--r-pill:999px;
  --s1:4px;--s2:8px;--s3:12px;--s4:16px;--s5:20px;--s6:24px;--s7:32px;--s8:40px;
  --fs-eyebrow:.72rem;--fs-sm:.82rem;--fs-base:.97rem;
  --fs-title:clamp(1.45rem,1.22rem + 1.1vw,1.8rem);
  --fs-num:clamp(3.1rem,2.4rem + 3.2vw,4rem);
  --d1:120ms;--d2:200ms;--d3:300ms;--d4:480ms;
  --ease:cubic-bezier(.2,0,0,1);--ease-out:cubic-bezier(.05,.7,.1,1);
  --elev1:0 1px 2px rgba(0,0,0,.10),0 1px 3px 1px rgba(0,0,0,.06);
  --elev2:0 1px 2px rgba(0,0,0,.10),0 2px 6px 2px rgba(0,0,0,.08);
  --ring:0 0 0 3px rgba(79,70,229,.5);
  /* bg.ibelick 'Gradient 2' family — a soft violet (#7877c6) ellipse glow rising
     from above the fold. Same pattern on the authentik login page so broker <->
     authentik read as one product; light & dark correspond (white vs near-black
     base). */
  --page:radial-gradient(ellipse 80% 80% at 50% -20%,rgba(120,119,198,.28),rgba(255,255,255,0));
}
@media (prefers-color-scheme:dark){:root{
  --bg:#0a0a0a;--surface:#1e1f25;--surface-2:#272832;--surface-3:#2f3039;
  /* --ink-3 lightened from #928f9a so muted/helper text clears WCAG AA on the
     dark surface (was ~3.8:1, now ~5.4:1). */
  --ink:#e4e1e9;--ink-2:#c7c5d0;--ink-3:#a8a5b0;
  --outline:#48474f;--outline-2:#33333b;
  --brand:#c0c1ff;--on-brand:#23228f;--brand-cont:#3b3aa6;--on-brand-cont:#e3e0ff;
  --ok:#7bda8f;--err:#ffb4ab;
  --elev1:0 1px 2px rgba(0,0,0,.5),0 1px 3px 1px rgba(0,0,0,.3);
  --elev2:0 1px 2px rgba(0,0,0,.5),0 2px 6px 2px rgba(0,0,0,.35);
  --ring:0 0 0 3px rgba(192,193,255,.6);
  /* Dark = bg.ibelick 'Dark Gradient 2': a soft violet ellipse glow rising from
     above the fold over near-black (--bg #0a0a0a). Premium & minimal. */
  --page:radial-gradient(ellipse 80% 80% at 50% -20%,rgba(120,119,198,.30),rgba(255,255,255,0));
}}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
/* Smooth cross-document (MPA) navigation on supporting browsers — a gentle
   fade between the method picker, code entry and waiting pages. Progressive
   enhancement (ignored where unsupported) and fully disabled under
   reduced-motion. */
@view-transition{navigation:auto}
@media (prefers-reduced-motion:reduce){
  ::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){animation:none!important}
}
body{margin:0;min-height:100svh;display:grid;place-items:safe center;padding:var(--s6);
  /* Always fit the viewport width — never a horizontal scrollbar (the card is
     centered + max-width capped, so nothing legitimately needs to scroll sideways). */
  overflow-x:hidden;
  font-family:var(--font-sans);
  font-size:var(--fs-base);line-height:1.55;color:var(--ink);
  background-color:var(--bg);
  background-image:var(--page);
  background-attachment:fixed;background-repeat:no-repeat;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
/* On a card taller than the viewport (short/landscape phones), `safe center`
   keeps the top reachable and lets the page scroll instead of clipping it. */
@media (max-width:400px){
  body{padding:var(--s4)}
  .card{padding:var(--s6) var(--s5) var(--s5)}
}
/* Premium 'glass' login card, tuned per theme so it sits in the violet glow
   (mirrors the authentik login card). Light: frosted-white with a violet-tinted
   hairline + soft halo. Dark: translucent near-black so the glow reads through. */
.card{width:100%;max-width:412px;text-align:center;padding:var(--s8) var(--s7) var(--s7);
  background:rgba(255,255,255,.80);border-radius:var(--r-xl);
  -webkit-backdrop-filter:blur(18px) saturate(130%);
  backdrop-filter:blur(18px) saturate(130%);
  border:1px solid rgba(120,119,198,.18);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.65),
    0 24px 60px -28px rgba(31,27,74,.35),
    0 0 80px -50px rgba(120,119,198,.60);
  animation:card-in var(--d4) var(--ease-out) both}
@keyframes card-in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
@media (prefers-color-scheme:dark){
  .card{
    background:rgba(18,18,23,.72);
    border:1px solid rgba(255,255,255,.08);
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,.06),
      0 24px 70px -24px rgba(0,0,0,.85),
      0 0 90px -45px rgba(120,119,198,.55)}
}
.flow>*{margin-block:0}.flow>*+*{margin-top:var(--flow,var(--s5))}
.reveal>*{animation:rise var(--d3) var(--ease-out) both}
.reveal>*:nth-child(2){animation-delay:50ms}.reveal>*:nth-child(3){animation-delay:.1s}
.reveal>*:nth-child(4){animation-delay:.15s}.reveal>*:nth-child(5){animation-delay:.2s}
.reveal>*:nth-child(6){animation-delay:.25s}.reveal>*:nth-child(7){animation-delay:.3s}
@keyframes rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
/* The mark only — no tile/border/fill — with a premium 'sheen': a soft light
   glides diagonally across the logo every few seconds, masked to the mark's own
   silhouette (the logo PNG) so the shine follows the logo shape. Pure CSS, so it
   animates reliably everywhere. */
.logo{position:relative;width:72px;height:72px;margin:0 auto;display:grid;place-items:center}
.logo img{width:60px;height:60px;display:block;object-fit:contain;
  filter:drop-shadow(0 0 12px rgba(120,119,198,.40))}
.logo::after{content:'';position:absolute;inset:0;pointer-events:none;opacity:0;
  -webkit-mask:url(/static/pramaan-logo.png) center/60px 60px no-repeat;
  mask:url(/static/pramaan-logo.png) center/60px 60px no-repeat;
  background:linear-gradient(100deg,transparent 34%,rgba(255,255,255,.9) 50%,transparent 66%) no-repeat;
  background-size:320% 100%;background-position:175% 0;mix-blend-mode:screen}
@media (prefers-reduced-motion:no-preference){
  .logo::after{opacity:1;animation:logo-sheen 5s ease-in-out infinite}
}
/* Slow, lingering glide (sweep ~4.3s) then a long pause; wide soft band. */
@keyframes logo-sheen{0%{background-position:175% 0}62%,100%{background-position:-75% 0}}
.eyebrow{font-size:var(--fs-eyebrow);font-weight:600;letter-spacing:.18em;text-transform:uppercase;color:var(--brand)}
.title{font-size:var(--fs-title);font-weight:600;line-height:1.2;font-family:var(--font-display);letter-spacing:-.01em}
.subtitle{color:var(--ink-2);max-width:34ch;margin-inline:auto}
.fineprint{color:var(--ink-2);font-size:var(--fs-sm);max-width:34ch;margin:var(--s3) auto 0}
.fineprint a{color:inherit;text-decoration:underline;text-underline-offset:2px}
.context{display:inline-flex;align-items:center;gap:var(--s2);max-width:100%;
  padding:var(--s2) var(--s3);border:1px solid var(--outline);border-radius:var(--r-sm);
  background:var(--surface-2);color:var(--ink-2);font-size:var(--fs-sm);overflow:hidden}
.context svg{width:14px;height:14px;flex:none;color:var(--ink-3)}
.context b{color:var(--ink);font-weight:600}
.context span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.context .dot{width:3px;height:3px;border-radius:50%;background:var(--ink-3);flex:none}
.qr{width:240px;max-width:78%;margin-inline:auto;padding:var(--s4);background:#fff;border-radius:var(--r-lg);
  border:1px solid var(--outline-2);box-shadow:var(--elev1)}
.qr svg{display:block;width:100%;height:auto;aspect-ratio:1}
.field>*+*{margin-top:var(--s3)}
.input{width:100%;height:52px;padding:0 var(--s4);border-radius:var(--r-md);border:1px solid var(--outline);
  background:var(--surface);color:var(--ink);font-size:1rem;font-family:inherit;outline:none;
  transition:border-color var(--d1) var(--ease),box-shadow var(--d1) var(--ease)}
.input::placeholder{color:var(--ink-3)}
.input:focus-visible{border-color:var(--brand);box-shadow:var(--ring)}
/* method picker: Material choice chips (radios styled as pills, no JS) */
.pills{display:flex;flex-wrap:wrap;gap:var(--s2);justify-content:center}
.pill-in{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.pill{display:inline-flex;align-items:center;gap:7px;min-height:44px;padding:0 var(--s4);
  border:1px solid var(--outline);border-radius:var(--r-pill);font-size:var(--fs-sm);font-weight:600;
  color:var(--ink-2);cursor:pointer;user-select:none;
  transition:background var(--d1),color var(--d1),border-color var(--d1)}
.pill svg{width:16px;height:16px;flex:none}
.pill:hover{background:var(--surface-2)}
.pill-in:checked + .pill{background:var(--brand);color:var(--on-brand);border-color:var(--brand)}
.pill-in:focus-visible + .pill{outline:none;box-shadow:var(--ring)}
/* Recommended badge on the primary (push) method */
.badge{font-size:.6rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  padding:2px 6px;border-radius:var(--r-pill);background:var(--brand-cont);color:var(--on-brand-cont)}
.pill-in:checked + .pill .badge{background:rgba(255,255,255,.22);color:#fff}
/* Self-explanatory idle motion per method: the push phone buzzes, SMS pops, the
   WhatsApp bubble pulses, the Telegram plane darts, the envelope bobs. Gentle &
   staggered so the row stays calm; reduce-motion disables it entirely. */
.pill svg{transform-origin:center}
@media (prefers-reduced-motion:no-preference){
  .pill[data-m=push] svg{animation:m-buzz 2s ease-in-out infinite}
  .pill[data-m=sms] svg{animation:m-pop 2.1s ease-in-out .15s infinite}
  .pill[data-m=whatsapp] svg{animation:m-pulse 2s ease-in-out .3s infinite}
  .pill[data-m=telegram] svg{animation:m-fly 2.2s ease-in-out .45s infinite}
  .pill[data-m=email] svg{animation:m-bob 2s ease-in-out .6s infinite}
}
@keyframes m-buzz{0%,80%,100%{transform:rotate(0)}83%{transform:rotate(-9deg)}86%{transform:rotate(8deg)}89%{transform:rotate(-6deg)}92%{transform:rotate(5deg)}95%{transform:rotate(-2deg)}}
@keyframes m-pop{0%,72%,100%{transform:scale(1)}84%{transform:scale(1.16)}}
@keyframes m-pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.12)}}
@keyframes m-fly{0%,72%,100%{transform:translate(0,0) rotate(0)}84%{transform:translate(3px,-2px) rotate(10deg)}}
@keyframes m-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-2px)}}
/* brand tagline under the eyebrow + the trust row */
.brand-tag{font-size:var(--fs-sm);color:var(--ink-3);margin-top:-2px;letter-spacing:.01em}
.trust{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--s2) var(--s5);
  margin-top:var(--s1);color:var(--ink-3);font-size:var(--fs-sm)}
.trust span{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.trust svg{width:14px;height:14px;color:var(--brand);flex:none}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);width:100%;min-height:48px;
  padding:0 var(--s5);border:1px solid transparent;border-radius:var(--r-pill);font:inherit;font-weight:600;
  cursor:pointer;text-decoration:none;
  transition:box-shadow var(--d1),background var(--d1),border-color var(--d1),filter var(--d1)}
.btn:focus-visible{outline:none;box-shadow:var(--ring)}
.btn-primary{color:var(--on-brand);background:var(--brand)}
.btn-primary:hover{box-shadow:var(--elev2);filter:brightness(1.08)}
.btn-ghost{color:var(--brand);background:transparent;border-color:var(--outline)}
.btn-ghost:hover{background:var(--surface-2)}
.btn-link{min-height:auto;width:auto;margin-inline:auto;padding:var(--s2) var(--s3);color:var(--brand);
  background:none;border:none;font-weight:600;font-size:var(--fs-sm)}
.btn-link:hover{text-decoration:underline}
.divider{display:flex;align-items:center;gap:var(--s3);color:var(--ink-3);font-size:var(--fs-sm)}
.divider::before,.divider::after{content:'';flex:1;height:1px;background:var(--outline-2)}
.match{margin-inline:auto;padding:var(--s5) var(--s8);border-radius:var(--r-lg);
  background:var(--brand-cont);color:var(--on-brand-cont)}
.num{font-size:var(--fs-num);font-weight:600;line-height:1;letter-spacing:.06em;font-variant-numeric:tabular-nums;
  color:var(--on-brand-cont);animation:num-in var(--d3) var(--ease-out) both}
@keyframes num-in{from{opacity:0;transform:scale(.92)}to{opacity:1;transform:none}}
.status{display:inline-flex;align-items:center;gap:var(--s2);color:var(--ink-2);font-size:var(--fs-sm)}
.status.is-ok{color:var(--ok);font-weight:600}
.status.is-err{color:var(--err);font-weight:600}
.spinner{width:15px;height:15px;border-radius:50%;flex:none;
  border:2px solid var(--outline);border-top-color:var(--brand);animation:spin .8s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
/* Shimmer skeleton — theme-aware loading placeholder, matching the app. The
   global prefers-reduced-motion rule below freezes the sweep automatically. */
.skeleton{position:relative;overflow:hidden;border-radius:var(--r-md);
  background:var(--surface-2)}
.skeleton::after{content:'';position:absolute;inset:0;transform:translateX(-100%);
  background:linear-gradient(90deg,transparent,var(--surface-3),transparent);
  animation:shimmer 1.2s ease-in-out infinite}
@keyframes shimmer{100%{transform:translateX(100%)}}
.sk-bar{height:12px;width:70%;margin:var(--s3) auto 0}
.offline{width:100%;text-align:left;border:1px solid var(--outline-2);border-radius:var(--r-md);
  background:var(--surface-2);padding:0 var(--s4)}
.offline>summary{cursor:pointer;list-style:none;padding:var(--s3) 0;color:var(--ink-2);
  font-size:var(--fs-sm);font-weight:600;text-align:center}
.offline>summary::-webkit-details-marker{display:none}
.offline[open]{padding-bottom:var(--s4)}
.offline .muted{color:var(--ink-3);font-size:var(--fs-sm);margin:var(--s2) 0}
.offline .input{margin-bottom:var(--s3);font-variant-numeric:tabular-nums;letter-spacing:.12em}
.foot{margin-top:var(--s7);padding-top:var(--s6);border-top:1px solid var(--outline-2);
  color:var(--ink-3);font-size:var(--fs-sm);line-height:1.5}
/* Frontier Labs co-brand. Two variants — dark (blue + #1f1a18) for light surfaces and
   white (blue + white) for dark surfaces — swapped by prefers-color-scheme so
   the mark is never washed out. No chip needed. */
.cobrand{height:32px;width:auto;display:block;margin:0 auto var(--s4)}
.cobrand-dark{display:none}
@media (prefers-color-scheme:dark){
  .cobrand-light{display:none}
  .cobrand-dark{display:block}
}
.trust{display:inline-flex;align-items:center;gap:var(--s2);justify-content:center}
.trust svg{width:13px;height:13px;flex:none}
/* Match-Glyphs: the user confirms this emoji row matches the one on their phone,
   a tripwire that the origin shown on the phone is the one driving this login. */
.glyph-check{margin-top:var(--s5);text-align:center}
.glyph-check-label{font-size:var(--fs-sm);color:var(--ink-3);margin:0 0 var(--s2);font-weight:600}
.glyphs{font-size:1.9rem;line-height:1.1;display:flex;justify-content:center;gap:.16em;
  font-variant-emoji:emoji}
@media (prefers-contrast:more){:root{--outline:#000;--ink-2:#000;--ink-3:#3a3a42}}
@media (prefers-reduced-motion:reduce){*{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}}
