/* Base: reset, typography and the components every dashboard page shares. Colours and sizes come from tokens.css. */
*,*::before,*::after{box-sizing:border-box}
[hidden]{display:none!important}
html{font-size:16px;-webkit-text-size-adjust:100%;scrollbar-color:var(--surface-4) transparent}
body{position:relative;margin:0;background:var(--bg-0);color:var(--ink-1);font:420 var(--text-base)/1.55 var(--font-ui);font-optical-sizing:auto;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
/* Grain scrolls with the page. A fixed full-screen layer stops iOS Safari extending the tab bar's colour under its toolbar. */
body::after{content:"";position:absolute;inset:0;z-index:100;pointer-events:none;background:var(--grain);opacity:.05}
button,input,select{font:inherit;color:inherit}
button,a{-webkit-tap-highlight-color:transparent;touch-action:manipulation}
button{cursor:pointer}button:disabled{opacity:.45;cursor:default}
a{color:inherit;text-decoration:none}
:focus-visible{outline:2px solid var(--focus);outline-offset:3px}
::selection{background:color-mix(in srgb,var(--ember) 42%,var(--bg-0));color:var(--ink-0)}
h1,h2,h3,h4,p{margin:0}

/* Type. Fraunces is for page and section titles (20px and up) and dial numerals; everything else is Geist. */
h1,h2{font-family:var(--font-display);font-weight:480;color:var(--ink-0);text-wrap:balance}
h1{font-size:var(--text-3xl);line-height:1.06;letter-spacing:-.022em}
h2{font-size:var(--text-xl);line-height:1.2;letter-spacing:-.012em}
h1 em,h2 em{font-style:italic;font-weight:420;color:var(--tone)}
h3,h4{font-family:var(--font-ui);font-weight:620;color:var(--ink-0);line-height:1.3;letter-spacing:-.012em}
h3{font-size:1.0625rem}h4{font-size:var(--text-base)}
.eyebrow{display:flex;align-items:center;gap:10px;margin-bottom:14px;font:620 var(--text-xs)/1.2 var(--font-ui);letter-spacing:.14em;text-transform:uppercase;color:var(--tone)}
.eyebrow::before{content:"";width:20px;height:2px;border-radius:2px;background:currentColor;opacity:.85}
.sub{margin-top:14px;max-width:62ch;font-size:var(--text-md);line-height:1.6;color:var(--ink-2);text-wrap:pretty}
.meta{font-size:var(--text-sm);color:var(--ink-3)}
.meta.mono,.num{font-family:var(--font-mono);font-variant-numeric:tabular-nums;letter-spacing:0}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
svg.icon{display:block;width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}
kbd{display:inline-block;min-width:22px;text-align:center;font:500 var(--text-xs)/1.7 var(--font-mono);border:1px solid var(--line-2);border-bottom-width:2px;border-radius:var(--r-xs);padding:0 5px;background:var(--surface-2);color:var(--ink-1)}
mark{background:color-mix(in srgb,var(--brass) 30%,transparent);color:inherit;border-radius:3px;padding:0 1px}

/* A screen is one routed view. Its tone lights the top of the page like a firebox door left ajar. */
.screen{position:relative;animation:screen-in var(--t-slow) var(--ease)}
.screen::before{content:"";position:absolute;z-index:-1;inset:-60px calc(var(--gutter)*-1) auto;height:460px;pointer-events:none;background:radial-gradient(52% 78% at 16% 0,color-mix(in srgb,var(--tone) 13%,transparent),transparent 72%);mask-image:linear-gradient(90deg,transparent,black 160px)}
@keyframes screen-in{from{opacity:0;transform:translateY(6px)}}
@keyframes fade-in{from{opacity:0}}

/* Page header, written by title() */
.page-top{display:flex;justify-content:space-between;align-items:end;gap:20px 28px;flex-wrap:wrap;margin-bottom:30px}
.page-top>div{min-width:0;flex:1 1 420px}
.page-top>.meta{flex:none;max-width:100%;padding:7px 13px;border:1px solid var(--line-2);border-radius:var(--r-pill);background:var(--surface-1);color:var(--ink-2);font-size:var(--text-xs);box-shadow:var(--top-light)}
.section-title{display:flex;align-items:baseline;justify-content:space-between;gap:8px 16px;flex-wrap:wrap;margin-bottom:16px}
.section-title a{display:inline-flex;align-items:center;gap:7px;font-size:var(--text-sm);font-weight:560;color:var(--tone);transition:gap var(--t) var(--ease)}
.section-title a:hover{gap:11px}.section-title a svg.icon{width:15px;height:15px}

/* Buttons. .btn alone is the quiet default; one .primary per view. */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:10px;min-height:44px;padding:0 17px;border:1px solid var(--line-2);border-radius:var(--r-md);background:var(--surface-2);color:var(--ink-1);font-size:.875rem;font-weight:580;line-height:1.2;box-shadow:var(--top-light);transition:background var(--t),border-color var(--t),color var(--t),box-shadow var(--t),transform var(--t-fast),filter var(--t)}
.btn:hover:not(:disabled){background:var(--surface-3);border-color:var(--line-3);color:var(--ink-0)}
.btn:active:not(:disabled){transform:translateY(1px)}
.btn svg.icon{width:17px;height:17px}
.btn.primary{background:var(--ember-fill);border-color:transparent;color:var(--ember-ink);font-weight:650;box-shadow:var(--ember-lift)}
.btn.primary:hover:not(:disabled){background:var(--ember-fill);border-color:transparent;color:var(--ember-ink);filter:brightness(1.08);box-shadow:var(--ember-glow)}
.btn.tone{background:var(--tone-bg);border-color:var(--tone-line);color:var(--tone)}
.btn.tone:hover:not(:disabled){background:var(--tone-bg-2);border-color:var(--tone);color:var(--tone)}
.btn.ghost{background:transparent;border-color:transparent;box-shadow:none;color:var(--ink-2)}
.btn.danger{color:var(--fire)}
.btn.danger:hover:not(:disabled){background:color-mix(in srgb,var(--fire) 12%,transparent);border-color:color-mix(in srgb,var(--fire) 40%,transparent);color:var(--fire)}
.btn[aria-pressed=true],.btn[aria-expanded=true]{background:var(--tone-bg-2);border-color:var(--tone-line);color:var(--ink-0)}
.btn.lg{min-height:52px;padding:0 26px;font-size:var(--text-base);border-radius:16px}
.btn.square{width:44px;padding:0}.btn.square-sm{min-width:44px;padding:0 13px;gap:8px}
.lesson-actions{display:flex;gap:12px;align-items:center;flex-wrap:wrap}

/* Chips: filters and segmented choices */
.filters{display:flex;flex-wrap:wrap;gap:8px;margin:24px 0}
.filter{display:inline-flex;align-items:center;gap:9px;min-height:40px;padding:0 15px;border:1px solid var(--line-2);border-radius:var(--r-pill);background:var(--surface-1);color:var(--ink-2);font-size:.875rem;font-weight:520;transition:background var(--t),border-color var(--t),color var(--t)}
.filter:hover{border-color:var(--line-3);color:var(--ink-0)}
.filter span{font:500 var(--text-xs) var(--font-mono);color:var(--ink-3)}
.filter svg.icon{width:15px;height:15px}
.filter[aria-current=true],.filter[aria-pressed=true]{background:var(--tone-bg-2);border-color:var(--tone-line);color:var(--ink-0)}
.filter[aria-current=true] span,.filter[aria-pressed=true] span{color:var(--tone)}
@media(pointer:coarse){.filter{min-height:44px}}

/* Tags */
.badge{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;border:1px solid var(--line-2);border-radius:var(--r-xs);font:600 var(--text-xs)/1 var(--font-mono);letter-spacing:.06em;text-transform:uppercase;color:var(--ink-2);white-space:nowrap}
.badge.tone{color:var(--tone);border-color:var(--tone-line);background:var(--tone-bg)}
.badge.ok{color:var(--moss);border-color:color-mix(in srgb,var(--moss) 38%,transparent);background:color-mix(in srgb,var(--moss) 12%,transparent)}
.badge.bad{color:var(--fire);border-color:color-mix(in srgb,var(--fire) 40%,transparent);background:color-mix(in srgb,var(--fire) 12%,transparent)}
.badge.warm{color:var(--brass);border-color:color-mix(in srgb,var(--brass) 38%,transparent);background:color-mix(in srgb,var(--brass) 12%,transparent)}

/* Field: a label, an .input well holding the input and any trailing .input-btn, then a note and an error. Mark the field data-invalid with the error's text. */
.field{display:grid;gap:8px;min-width:0}
.field-top{display:flex;align-items:baseline;justify-content:space-between;gap:12px;min-height:22px}
.field label{font-size:var(--text-sm);font-weight:580;color:var(--ink-1)}
.input{display:flex;align-items:center;min-width:0;border:1px solid var(--line-2);border-radius:var(--r-md);background:var(--bg-1);box-shadow:inset 0 1px 3px color-mix(in srgb,var(--bg-0) 60%,transparent);transition:border-color var(--t),box-shadow var(--t-slow) var(--ease)}
.input:hover{border-color:var(--line-3)}
.input:focus-within{border-color:color-mix(in srgb,var(--tone) 75%,var(--brass));box-shadow:0 0 0 3px var(--tone-bg),0 0 26px -8px color-mix(in srgb,var(--tone) 70%,transparent)}
.input input{flex:1;width:0;min-width:0;height:50px;padding:0 15px;border:0;border-radius:inherit;background:none;color:var(--ink-0);font-size:var(--text-md);outline:none;text-overflow:ellipsis}
.input input::placeholder{color:var(--ink-3)}
.input input:is(:autofill,:-webkit-autofill){-webkit-text-fill-color:var(--ink-0);caret-color:var(--ink-0);box-shadow:inset 0 0 0 40px var(--bg-1);transition:background-color 1e5s}
.input:has(input:disabled){opacity:.55}
.input-btn{display:grid;place-items:center;flex-shrink:0;width:42px;height:42px;margin-right:4px;border:0;border-radius:var(--r-sm);background:none;color:var(--ink-3);transition:color var(--t),background var(--t)}
.input-btn:hover{color:var(--ink-0);background:var(--surface-2)}
.input-btn svg.icon{width:19px;height:19px}
.field-note,.field-error{font-size:var(--text-sm);line-height:1.45;color:var(--ink-3);overflow-wrap:anywhere;text-wrap:pretty}
.field-error{color:var(--fire)}
.field-error:empty{display:none}
.field[data-invalid] .input{border-color:color-mix(in srgb,var(--fire) 65%,transparent)}
.field[data-invalid] .input:focus-within{box-shadow:0 0 0 3px color-mix(in srgb,var(--fire) 16%,transparent)}
.field[data-invalid] .field-note{display:none}

/* Surfaces. .panel is the one card surface; area files add layout and override single properties. .panel.link is a card that is a link or button; .panel.hero is a page's lead card. */
.panel{background:var(--surface-1);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-1)}
.panel.link{transition:background-color var(--t),border-color var(--t),box-shadow var(--t) var(--ease),transform var(--t) var(--ease)}
.panel.link:is(:hover,:focus-visible){background-color:var(--surface-2);border-color:var(--tone-line);box-shadow:var(--shadow-2)}
@media(hover:hover) and (pointer:fine){.panel.link:hover{transform:translateY(-2px)}.panel.link:hover:active{transform:translateY(-1px)}}
.panel.hero{border-radius:var(--r-xl);box-shadow:var(--shadow-2)}
@media(max-width:680px){.panel.hero{border-radius:var(--r-lg)}}
.collection{padding:6px 22px}
.icon-block{display:grid;place-items:center;flex-shrink:0;width:44px;height:44px;border-radius:13px;background:var(--tone-bg-2);color:var(--tone);box-shadow:inset 0 0 0 1px var(--tone-line)}
.note-strip{display:flex;align-items:flex-start;gap:10px;margin-top:28px;font-size:var(--text-sm);line-height:1.6;color:var(--ink-3)}
.note-strip svg.icon{width:16px;height:16px;margin-top:2px}
.note-strip a{color:var(--ink-2);text-decoration:underline;text-underline-offset:3px;text-decoration-color:var(--line-3)}
.note-strip a:hover{color:var(--ink-0)}
.empty-state{max-width:520px;margin:24px auto;padding:40px 28px;text-align:center}
.empty-state .icon-block{margin:0 auto 18px}.empty-state p{margin-top:8px;color:var(--ink-2)}.empty-state .lesson-actions{justify-content:center;margin-top:24px}
.loading{display:grid;gap:12px;max-width:820px;animation:fade-in .3s .25s both}
.loading span{height:76px;border-radius:var(--r-lg);background:linear-gradient(90deg,var(--surface-1) 30%,var(--surface-2) 50%,var(--surface-1) 70%) 0 0/250% 100%;animation:shimmer 1.6s linear infinite}
.loading span:first-child{height:150px}
@keyframes shimmer{to{background-position:-250% 0}}

/* Sheet: below its width a side panel rises from the bottom over a scrim, which follows it in the markup. The script adds .sheet while the panel's width query matches (SHEET_AT) and data-open while it is open; the area file keeps the wide layout and the panel's own surface. */
.sheet{position:fixed;z-index:70;inset:auto 0 0;padding-bottom:max(16px,env(safe-area-inset-bottom));border-bottom:0;border-radius:var(--r-xl) var(--r-xl) 0 0;box-shadow:var(--shadow-3);transform:translateY(100%);visibility:hidden;transition:transform var(--t-slow) var(--ease),visibility 0s var(--t-slow)}
.sheet::before{content:"";flex-shrink:0;width:40px;height:4px;margin:0 auto 12px;border-radius:2px;background:var(--line-3)}
.sheet[data-open]{transform:none;visibility:visible;transition:transform var(--t-slow) var(--ease)}
.sheet-scrim{position:fixed;inset:0;z-index:69;background:color-mix(in srgb,var(--bg-0) 72%,transparent);opacity:0;visibility:hidden;transition:opacity var(--t),visibility 0s var(--t)}
.sheet[data-open]+.sheet-scrim{opacity:1;visibility:visible;transition:opacity var(--t)}
html:has(.sheet[data-open]){overflow:hidden}

/* Meter: a level bar with the pass mark as a tick. Set --pass on the element. */
.meter{display:block;position:relative;height:6px;border-radius:3px;background:var(--surface-3)}
.meter i{position:absolute;inset:0 auto 0 0;border-radius:3px;background:var(--moss);transform-origin:left}
.weak .meter i{background:var(--fire)}
.meter::after{content:"";position:absolute;left:var(--pass);top:-4px;bottom:-4px;width:2px;margin-left:-1px;border-radius:1px;background:color-mix(in srgb,var(--ink-0) 55%,transparent)}
.animate .meter i{animation:grow .6s .1s var(--ease) both}
@keyframes grow{from{transform:scaleX(0)}}

/* Gauge: the dial drawn by gauge(). Size it with --gauge; colour it with a tone, or .pass / .fail. */
.gauge{position:relative;flex-shrink:0;width:var(--gauge,176px);aspect-ratio:200/160;container-type:inline-size;--g:var(--tone)}
.gauge.pass{--g:var(--moss)}.gauge.fail{--g:var(--ember)}
.gauge svg{display:block;width:100%;height:100%;overflow:visible}
.gauge path,.gauge circle{fill:none;stroke-linecap:round}
.g-track{stroke:var(--surface-3);stroke-width:10}
.g-fill{stroke:var(--g);stroke-width:10;filter:drop-shadow(0 0 7px color-mix(in srgb,var(--g) 40%,transparent))}
.g-band{stroke:var(--moss);stroke-width:3;opacity:.75}
.g-tick{stroke:var(--ink-4);stroke-width:1.5}
.g-pass{stroke:var(--ink-0);stroke-width:2;opacity:.9}
.g-needle{transform-box:view-box;transform-origin:100px 100px;transform:rotate(calc(-120deg + var(--p)*2.4deg))}
.g-needle path{stroke:var(--ink-0);stroke-width:3}
.gauge .g-needle circle{fill:var(--surface-1);stroke:var(--ink-0);stroke-width:3}
.gauge strong{position:absolute;inset:auto 0 0;text-align:center;font:520 19cqw/1 var(--font-display);letter-spacing:-.03em;color:var(--ink-0);font-variant-numeric:lining-nums tabular-nums}
.gauge strong small{margin-left:.06em;font-size:max(.48em,var(--text-xs));font-weight:480;color:var(--ink-3)}
.animate .g-needle{animation:g-needle .9s var(--ease) both}
.animate .g-fill{animation:g-fill .9s var(--ease) both}
@keyframes g-needle{from{transform:rotate(-120deg)}}
@keyframes g-fill{from{stroke-dasharray:0 100}}

/* Nothing transitions until the saved layout is applied, so a page load never animates. */
html:not([data-motion]) *{transition:none!important}
@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}

/* Layout measures other files position against. The shell owns the bars themselves; --stack-h is what sticks under the top bar (the exam bar), measured by the script.
   Every scroll into view and focus scroll lands clear of all of them. */
:root{--topbar-h:60px;--tabbar-h:0px;--stack-h:0px}
@media(max-width:680px){:root{--topbar-h:52px;--tabbar-h:calc(64px + env(safe-area-inset-bottom))}}
html{scroll-padding:calc(var(--topbar-h) + var(--stack-h) + 16px) 0 calc(var(--tabbar-h) + 16px)}
