/* GENERATED by scripts/build_css_bundle.py — DO NOT EDIT.
   Edit the numbered source files in web/static/css/, then rerun the script and
   COMMIT this bundle (the Docker image ships it, it does NOT rebuild it).
   Order matches web/templates/base.html so the cascade is identical. */

/* ===== 00-tailwind.css ===== */
*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:Outfit,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-tap-highlight-color:transparent}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-size:1em;font-variation-settings:normal}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-feature-settings:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.sr-only{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0,0,0,0);border-width:0;white-space:nowrap}.pointer-events-none{pointer-events:none}.\!visible{visibility:visible!important}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-x-0{left:0;right:0}.bottom-3{bottom:.75rem}.right-3{right:.75rem}.top-0{top:0}.top-20{top:5rem}.z-10{z-index:10}.z-20{z-index:20}.mx-auto{margin-left:auto;margin-right:auto}.my-2{margin-bottom:.5rem;margin-top:.5rem}.-mt-4{margin-top:-1rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-7{margin-bottom:1.75rem}.mb-8{margin-bottom:2rem}.mb-9{margin-bottom:2.25rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-auto{margin-left:auto}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-10{margin-top:2.5rem}.mt-14{margin-top:3.5rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-3\.5{margin-top:.875rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mt-9{margin-top:2.25rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.aspect-square{aspect-ratio:1/1}.size-1{width:.25rem}.h-1,.size-1{height:.25rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\[1\.35rem\]{height:1.35rem}.h-\[3\.1rem\]{height:3.1rem}.h-full{height:100%}.h-px{height:1px}.max-h-\[28rem\]{max-height:28rem}.min-h-\[4\.25rem\]{min-height:4.25rem}.min-h-\[8\.5rem\]{min-height:8.5rem}.min-h-full{min-height:100%}.min-h-screen{min-height:100vh}.w-0{width:0}.w-10{width:2.5rem}.w-11{width:2.75rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-2{width:.5rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-56{width:14rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-\[1\.35rem\]{width:1.35rem}.w-\[3\.1rem\]{width:3.1rem}.w-auto{width:auto}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0}.min-w-\[1\.15rem\]{min-width:1.15rem}.min-w-\[1\.75rem\]{min-width:1.75rem}.min-w-\[2\.5rem\]{min-width:2.5rem}.min-w-\[26rem\]{min-width:26rem}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-5xl{max-width:64rem}.max-w-6xl{max-width:72rem}.max-w-7xl{max-width:80rem}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.flex-grow,.grow{flex-grow:1}.translate-y-6{--tw-translate-y:1.5rem}.transform,.translate-y-6{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.select-all{-webkit-user-select:all;-moz-user-select:all;user-select:all}.resize-y{resize:vertical}.resize{resize:both}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-3\.5{gap:.875rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-x-6{-moz-column-gap:1.5rem;column-gap:1.5rem}.gap-y-1{row-gap:.25rem}.gap-y-3{row-gap:.75rem}.gap-y-8{row-gap:2rem}.space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.75rem*var(--tw-space-x-reverse))}.space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(0px*var(--tw-space-y-reverse));margin-top:calc(0px*(1 - var(--tw-space-y-reverse)))}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.125rem*var(--tw-space-y-reverse));margin-top:calc(.125rem*(1 - var(--tw-space-y-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.375rem*var(--tw-space-y-reverse));margin-top:calc(.375rem*(1 - var(--tw-space-y-reverse)))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.75rem*var(--tw-space-y-reverse));margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-bottom-width:calc(1px*var(--tw-divide-y-reverse));border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)))}.divide-white\/10>:not([hidden])~:not([hidden]){border-color:hsla(0,0%,100%,.1)}.divide-white\/\[0\.04\]>:not([hidden])~:not([hidden]){border-color:hsla(0,0%,100%,.04)}.self-end{align-self:flex-end}.self-center{align-self:center}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-wrap{text-wrap:wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-3xl{border-radius:1.5rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.rounded-t-2xl{border-top-left-radius:1rem;border-top-right-radius:1rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-amber-300\/25{border-color:rgba(252,211,77,.25)}.border-amber-400\/25{border-color:rgba(251,191,36,.25)}.border-amber-400\/40{border-color:rgba(251,191,36,.4)}.border-amber-500\/20{border-color:rgba(245,158,11,.2)}.border-amber-500\/25{border-color:rgba(245,158,11,.25)}.border-amber-500\/40{border-color:rgba(245,158,11,.4)}.border-blue-500\/25{border-color:rgba(59,130,246,.25)}.border-blue-500\/40{border-color:rgba(59,130,246,.4)}.border-commerce-500\/25{border-color:rgba(94,122,166,.25)}.border-commerce-500\/40{border-color:rgba(94,122,166,.4)}.border-cyan-300\/25{border-color:rgba(103,232,249,.25)}.border-cyan-400\/25{border-color:rgba(34,211,238,.25)}.border-cyan-400\/30{border-color:rgba(34,211,238,.3)}.border-cyan-400\/60{border-color:rgba(34,211,238,.6)}.border-cyan-500\/20{border-color:rgba(6,182,212,.2)}.border-cyan-500\/25{border-color:rgba(6,182,212,.25)}.border-cyan-500\/40{border-color:rgba(6,182,212,.4)}.border-emerald-300\/25{border-color:rgba(110,231,183,.25)}.border-emerald-400\/20{border-color:rgba(52,211,153,.2)}.border-emerald-400\/25{border-color:rgba(52,211,153,.25)}.border-emerald-400\/60{border-color:rgba(52,211,153,.6)}.border-emerald-500\/20{border-color:rgba(16,185,129,.2)}.border-emerald-500\/25{border-color:rgba(16,185,129,.25)}.border-emerald-500\/40{border-color:rgba(16,185,129,.4)}.border-fuchsia-500\/25{border-color:rgba(217,70,239,.25)}.border-fuchsia-500\/40{border-color:rgba(217,70,239,.4)}.border-gray-500\/25{border-color:hsla(220,9%,46%,.25)}.border-gray-500\/40{border-color:hsla(220,9%,46%,.4)}.border-green-500\/25{border-color:rgba(34,197,94,.25)}.border-green-500\/40{border-color:rgba(34,197,94,.4)}.border-indigo-500\/25{border-color:rgba(99,102,241,.25)}.border-indigo-500\/40{border-color:rgba(99,102,241,.4)}.border-lime-500\/25{border-color:rgba(132,204,22,.25)}.border-lime-500\/40{border-color:rgba(132,204,22,.4)}.border-neutral-500\/25{border-color:hsla(0,0%,45%,.25)}.border-neutral-500\/40{border-color:hsla(0,0%,45%,.4)}.border-orange-400\/25{border-color:rgba(251,146,60,.25)}.border-orange-500\/25{border-color:rgba(249,115,22,.25)}.border-orange-500\/40{border-color:rgba(249,115,22,.4)}.border-pink-500\/25{border-color:rgba(236,72,153,.25)}.border-pink-500\/40{border-color:rgba(236,72,153,.4)}.border-purple-500\/25{border-color:rgba(168,85,247,.25)}.border-purple-500\/40{border-color:rgba(168,85,247,.4)}.border-red-500\/20{border-color:rgba(239,68,68,.2)}.border-red-500\/25{border-color:rgba(239,68,68,.25)}.border-red-500\/40{border-color:rgba(239,68,68,.4)}.border-rose-400\/40{border-color:rgba(251,113,133,.4)}.border-rose-500\/20{border-color:rgba(244,63,94,.2)}.border-rose-500\/25{border-color:rgba(244,63,94,.25)}.border-rose-500\/40{border-color:rgba(244,63,94,.4)}.border-sky-500\/20{border-color:rgba(14,165,233,.2)}.border-sky-500\/25{border-color:rgba(14,165,233,.25)}.border-sky-500\/40{border-color:rgba(14,165,233,.4)}.border-slate-500\/25{border-color:rgba(100,116,139,.25)}.border-slate-500\/40{border-color:rgba(100,116,139,.4)}.border-slate-600{--tw-border-opacity:1;border-color:rgb(71 85 105/var(--tw-border-opacity,1))}.border-slate-700{--tw-border-opacity:1;border-color:rgb(51 65 85/var(--tw-border-opacity,1))}.border-slate-800\/60{border-color:rgba(30,41,59,.6)}.border-stone-500\/25{border-color:hsla(25,5%,45%,.25)}.border-stone-500\/40{border-color:hsla(25,5%,45%,.4)}.border-teal-500\/25{border-color:rgba(20,184,166,.25)}.border-teal-500\/40{border-color:rgba(20,184,166,.4)}.border-violet-300\/25{border-color:rgba(196,181,253,.25)}.border-violet-400\/25{border-color:rgba(167,139,250,.25)}.border-violet-500\/20{border-color:rgba(139,92,246,.2)}.border-violet-500\/25{border-color:rgba(139,92,246,.25)}.border-violet-500\/40{border-color:rgba(139,92,246,.4)}.border-white\/10{border-color:hsla(0,0%,100%,.1)}.border-white\/\[0\.04\]{border-color:hsla(0,0%,100%,.04)}.border-white\/\[0\.05\]{border-color:hsla(0,0%,100%,.05)}.border-white\/\[0\.06\]{border-color:hsla(0,0%,100%,.06)}.border-white\/\[0\.08\]{border-color:hsla(0,0%,100%,.08)}.border-white\/\[0\.09\]{border-color:hsla(0,0%,100%,.09)}.border-white\/\[0\.10\]{border-color:hsla(0,0%,100%,.1)}.border-white\/\[0\.12\]{border-color:hsla(0,0%,100%,.12)}.border-white\/\[0\.13\]{border-color:hsla(0,0%,100%,.13)}.border-white\/\[0\.15\]{border-color:hsla(0,0%,100%,.15)}.border-yellow-500\/25{border-color:rgba(234,179,8,.25)}.border-yellow-500\/40{border-color:rgba(234,179,8,.4)}.border-zinc-500\/25{border-color:hsla(240,4%,46%,.25)}.border-zinc-500\/40{border-color:hsla(240,4%,46%,.4)}.border-t-amber-300{--tw-border-opacity:1;border-top-color:rgb(252 211 77/var(--tw-border-opacity,1))}.border-t-amber-400{--tw-border-opacity:1;border-top-color:rgb(251 191 36/var(--tw-border-opacity,1))}.border-t-cyan-300{--tw-border-opacity:1;border-top-color:rgb(103 232 249/var(--tw-border-opacity,1))}.border-t-cyan-400{--tw-border-opacity:1;border-top-color:rgb(34 211 238/var(--tw-border-opacity,1))}.border-t-emerald-300{--tw-border-opacity:1;border-top-color:rgb(110 231 183/var(--tw-border-opacity,1))}.border-t-emerald-400{--tw-border-opacity:1;border-top-color:rgb(52 211 153/var(--tw-border-opacity,1))}.border-t-orange-400{--tw-border-opacity:1;border-top-color:rgb(251 146 60/var(--tw-border-opacity,1))}.border-t-violet-300{--tw-border-opacity:1;border-top-color:rgb(196 181 253/var(--tw-border-opacity,1))}.border-t-violet-400{--tw-border-opacity:1;border-top-color:rgb(167 139 250/var(--tw-border-opacity,1))}.bg-amber-400{--tw-bg-opacity:1;background-color:rgb(251 191 36/var(--tw-bg-opacity,1))}.bg-amber-400\/10{background-color:rgba(251,191,36,.1)}.bg-amber-400\/15{background-color:rgba(251,191,36,.15)}.bg-amber-500\/10{background-color:rgba(245,158,11,.1)}.bg-amber-500\/15{background-color:rgba(245,158,11,.15)}.bg-amber-500\/20{background-color:rgba(245,158,11,.2)}.bg-amber-500\/\[0\.04\]{background-color:rgba(245,158,11,.04)}.bg-black\/30{background-color:rgba(0,0,0,.3)}.bg-blue-400{--tw-bg-opacity:1;background-color:rgb(96 165 250/var(--tw-bg-opacity,1))}.bg-blue-500\/10{background-color:rgba(59,130,246,.1)}.bg-blue-500\/15{background-color:rgba(59,130,246,.15)}.bg-blue-500\/20{background-color:rgba(59,130,246,.2)}.bg-commerce-400{--tw-bg-opacity:1;background-color:rgb(125 151 194/var(--tw-bg-opacity,1))}.bg-commerce-500\/10{background-color:rgba(94,122,166,.1)}.bg-commerce-500\/15{background-color:rgba(94,122,166,.15)}.bg-commerce-500\/20{background-color:rgba(94,122,166,.2)}.bg-cyan-400{--tw-bg-opacity:1;background-color:rgb(34 211 238/var(--tw-bg-opacity,1))}.bg-cyan-400\/10{background-color:rgba(34,211,238,.1)}.bg-cyan-400\/15{background-color:rgba(34,211,238,.15)}.bg-cyan-400\/\[0\.08\]{background-color:rgba(34,211,238,.08)}.bg-cyan-500\/10{background-color:rgba(6,182,212,.1)}.bg-cyan-500\/15{background-color:rgba(6,182,212,.15)}.bg-cyan-500\/20{background-color:rgba(6,182,212,.2)}.bg-cyan-500\/\[0\.04\]{background-color:rgba(6,182,212,.04)}.bg-emerald-200\/30{background-color:rgba(167,243,208,.3)}.bg-emerald-400{--tw-bg-opacity:1;background-color:rgb(52 211 153/var(--tw-bg-opacity,1))}.bg-emerald-400\/10{background-color:rgba(52,211,153,.1)}.bg-emerald-400\/\[0\.06\]{background-color:rgba(52,211,153,.06)}.bg-emerald-500\/10{background-color:rgba(16,185,129,.1)}.bg-emerald-500\/15{background-color:rgba(16,185,129,.15)}.bg-emerald-500\/20{background-color:rgba(16,185,129,.2)}.bg-emerald-500\/60{background-color:rgba(16,185,129,.6)}.bg-emerald-500\/\[0\.04\]{background-color:rgba(16,185,129,.04)}.bg-emerald-500\/\[0\.07\]{background-color:rgba(16,185,129,.07)}.bg-fuchsia-400{--tw-bg-opacity:1;background-color:rgb(232 121 249/var(--tw-bg-opacity,1))}.bg-fuchsia-500\/10{background-color:rgba(217,70,239,.1)}.bg-fuchsia-500\/15{background-color:rgba(217,70,239,.15)}.bg-fuchsia-500\/20{background-color:rgba(217,70,239,.2)}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity,1))}.bg-gray-500\/10{background-color:hsla(220,9%,46%,.1)}.bg-gray-500\/15{background-color:hsla(220,9%,46%,.15)}.bg-gray-500\/20{background-color:hsla(220,9%,46%,.2)}.bg-green-400{--tw-bg-opacity:1;background-color:rgb(74 222 128/var(--tw-bg-opacity,1))}.bg-green-500\/10{background-color:rgba(34,197,94,.1)}.bg-green-500\/15{background-color:rgba(34,197,94,.15)}.bg-green-500\/20{background-color:rgba(34,197,94,.2)}.bg-indigo-400{--tw-bg-opacity:1;background-color:rgb(129 140 248/var(--tw-bg-opacity,1))}.bg-indigo-500\/10{background-color:rgba(99,102,241,.1)}.bg-indigo-500\/15{background-color:rgba(99,102,241,.15)}.bg-indigo-500\/20{background-color:rgba(99,102,241,.2)}.bg-lime-400{--tw-bg-opacity:1;background-color:rgb(163 230 53/var(--tw-bg-opacity,1))}.bg-lime-500\/10{background-color:rgba(132,204,22,.1)}.bg-lime-500\/15{background-color:rgba(132,204,22,.15)}.bg-lime-500\/20{background-color:rgba(132,204,22,.2)}.bg-neutral-400{--tw-bg-opacity:1;background-color:rgb(163 163 163/var(--tw-bg-opacity,1))}.bg-neutral-500\/10{background-color:hsla(0,0%,45%,.1)}.bg-neutral-500\/15{background-color:hsla(0,0%,45%,.15)}.bg-neutral-500\/20{background-color:hsla(0,0%,45%,.2)}.bg-orange-400{--tw-bg-opacity:1;background-color:rgb(251 146 60/var(--tw-bg-opacity,1))}.bg-orange-500\/10{background-color:rgba(249,115,22,.1)}.bg-orange-500\/15{background-color:rgba(249,115,22,.15)}.bg-orange-500\/20{background-color:rgba(249,115,22,.2)}.bg-pink-400{--tw-bg-opacity:1;background-color:rgb(244 114 182/var(--tw-bg-opacity,1))}.bg-pink-500\/10{background-color:rgba(236,72,153,.1)}.bg-pink-500\/15{background-color:rgba(236,72,153,.15)}.bg-pink-500\/20{background-color:rgba(236,72,153,.2)}.bg-purple-400{--tw-bg-opacity:1;background-color:rgb(192 132 252/var(--tw-bg-opacity,1))}.bg-purple-500\/10{background-color:rgba(168,85,247,.1)}.bg-purple-500\/15{background-color:rgba(168,85,247,.15)}.bg-purple-500\/20{background-color:rgba(168,85,247,.2)}.bg-red-400{--tw-bg-opacity:1;background-color:rgb(248 113 113/var(--tw-bg-opacity,1))}.bg-red-500\/10{background-color:rgba(239,68,68,.1)}.bg-red-500\/15{background-color:rgba(239,68,68,.15)}.bg-red-500\/20{background-color:rgba(239,68,68,.2)}.bg-rose-400{--tw-bg-opacity:1;background-color:rgb(251 113 133/var(--tw-bg-opacity,1))}.bg-rose-500\/10{background-color:rgba(244,63,94,.1)}.bg-rose-500\/15{background-color:rgba(244,63,94,.15)}.bg-rose-500\/20{background-color:rgba(244,63,94,.2)}.bg-rose-500\/\[0\.04\]{background-color:rgba(244,63,94,.04)}.bg-rose-500\/\[0\.12\]{background-color:rgba(244,63,94,.12)}.bg-sky-400{--tw-bg-opacity:1;background-color:rgb(56 189 248/var(--tw-bg-opacity,1))}.bg-sky-500\/10{background-color:rgba(14,165,233,.1)}.bg-sky-500\/15{background-color:rgba(14,165,233,.15)}.bg-sky-500\/20{background-color:rgba(14,165,233,.2)}.bg-sky-500\/\[0\.04\]{background-color:rgba(14,165,233,.04)}.bg-slate-400{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity,1))}.bg-slate-500\/10{background-color:rgba(100,116,139,.1)}.bg-slate-500\/15{background-color:rgba(100,116,139,.15)}.bg-slate-500\/20{background-color:rgba(100,116,139,.2)}.bg-slate-700{--tw-bg-opacity:1;background-color:rgb(51 65 85/var(--tw-bg-opacity,1))}.bg-slate-700\/60{background-color:rgba(51,65,85,.6)}.bg-slate-900\/60{background-color:rgba(15,23,42,.6)}.bg-slate-950\/40{background-color:rgba(2,6,23,.4)}.bg-slate-950\/50{background-color:rgba(2,6,23,.5)}.bg-slate-950\/55{background-color:rgba(2,6,23,.55)}.bg-slate-950\/60{background-color:rgba(2,6,23,.6)}.bg-slate-950\/80{background-color:rgba(2,6,23,.8)}.bg-slate-950\/85{background-color:rgba(2,6,23,.85)}.bg-slate-950\/90{background-color:rgba(2,6,23,.9)}.bg-slate-950\/95{background-color:rgba(2,6,23,.95)}.bg-stone-400{--tw-bg-opacity:1;background-color:rgb(168 162 158/var(--tw-bg-opacity,1))}.bg-stone-500\/10{background-color:hsla(25,5%,45%,.1)}.bg-stone-500\/15{background-color:hsla(25,5%,45%,.15)}.bg-stone-500\/20{background-color:hsla(25,5%,45%,.2)}.bg-teal-400{--tw-bg-opacity:1;background-color:rgb(45 212 191/var(--tw-bg-opacity,1))}.bg-teal-500\/10{background-color:rgba(20,184,166,.1)}.bg-teal-500\/15{background-color:rgba(20,184,166,.15)}.bg-teal-500\/20{background-color:rgba(20,184,166,.2)}.bg-transparent{background-color:transparent}.bg-violet-400{--tw-bg-opacity:1;background-color:rgb(167 139 250/var(--tw-bg-opacity,1))}.bg-violet-500\/10{background-color:rgba(139,92,246,.1)}.bg-violet-500\/15{background-color:rgba(139,92,246,.15)}.bg-violet-500\/20{background-color:rgba(139,92,246,.2)}.bg-violet-500\/\[0\.04\]{background-color:rgba(139,92,246,.04)}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/10{background-color:hsla(0,0%,100%,.1)}.bg-white\/95{background-color:hsla(0,0%,100%,.95)}.bg-white\/\[0\.015\]{background-color:hsla(0,0%,100%,.015)}.bg-white\/\[0\.02\]{background-color:hsla(0,0%,100%,.02)}.bg-white\/\[0\.03\]{background-color:hsla(0,0%,100%,.03)}.bg-white\/\[0\.04\]{background-color:hsla(0,0%,100%,.04)}.bg-white\/\[0\.06\]{background-color:hsla(0,0%,100%,.06)}.bg-white\/\[0\.07\]{background-color:hsla(0,0%,100%,.07)}.bg-white\/\[0\.10\]{background-color:hsla(0,0%,100%,.1)}.bg-yellow-400{--tw-bg-opacity:1;background-color:rgb(250 204 21/var(--tw-bg-opacity,1))}.bg-yellow-500\/10{background-color:rgba(234,179,8,.1)}.bg-yellow-500\/15{background-color:rgba(234,179,8,.15)}.bg-yellow-500\/20{background-color:rgba(234,179,8,.2)}.bg-zinc-400{--tw-bg-opacity:1;background-color:rgb(161 161 170/var(--tw-bg-opacity,1))}.bg-zinc-500\/10{background-color:hsla(240,4%,46%,.1)}.bg-zinc-500\/15{background-color:hsla(240,4%,46%,.15)}.bg-zinc-500\/20{background-color:hsla(240,4%,46%,.2)}.bg-gradient-to-b{background-image:linear-gradient(to bottom,var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-cyan-200{--tw-gradient-from:#a5f3fc var(--tw-gradient-from-position);--tw-gradient-to:rgba(165,243,252,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-cyan-300{--tw-gradient-from:#67e8f9 var(--tw-gradient-from-position);--tw-gradient-to:rgba(103,232,249,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-cyan-400\/\[0\.10\]{--tw-gradient-from:rgba(34,211,238,.1) var(--tw-gradient-from-position);--tw-gradient-to:rgba(34,211,238,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-transparent{--tw-gradient-from:transparent var(--tw-gradient-from-position);--tw-gradient-to:transparent var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-white\/15{--tw-gradient-from:hsla(0,0%,100%,.15) var(--tw-gradient-from-position);--tw-gradient-to:hsla(0,0%,100%,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-white\/25{--tw-gradient-from:hsla(0,0%,100%,.25) var(--tw-gradient-from-position);--tw-gradient-to:hsla(0,0%,100%,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-white\/\[0\.04\]{--tw-gradient-from:hsla(0,0%,100%,.04) var(--tw-gradient-from-position);--tw-gradient-to:hsla(0,0%,100%,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-white\/\[0\.06\]{--tw-gradient-from:hsla(0,0%,100%,.06) var(--tw-gradient-from-position);--tw-gradient-to:hsla(0,0%,100%,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.via-amber-400\/45{--tw-gradient-to:rgba(251,191,36,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),rgba(251,191,36,.45) var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-blue-300{--tw-gradient-to:rgba(147,197,253,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),#93c5fd var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-cyan-400\/45{--tw-gradient-to:rgba(34,211,238,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),rgba(34,211,238,.45) var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-emerald-400\/45{--tw-gradient-to:rgba(52,211,153,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),rgba(52,211,153,.45) var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-sky-300{--tw-gradient-to:rgba(125,211,252,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),#7dd3fc var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-violet-400\/45{--tw-gradient-to:rgba(167,139,250,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),rgba(167,139,250,.45) var(--tw-gradient-via-position),var(--tw-gradient-to)}.to-blue-400{--tw-gradient-to:#60a5fa var(--tw-gradient-to-position)}.to-indigo-300{--tw-gradient-to:#a5b4fc var(--tw-gradient-to-position)}.to-indigo-500\/\[0\.05\]{--tw-gradient-to:rgba(99,102,241,.05) var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.to-white\/\[0\.01\]{--tw-gradient-to:hsla(0,0%,100%,.01) var(--tw-gradient-to-position)}.to-white\/\[0\.02\]{--tw-gradient-to:hsla(0,0%,100%,.02) var(--tw-gradient-to-position)}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.object-contain{-o-object-fit:contain;object-fit:contain}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-10{padding:2.5rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-3\.5{padding:.875rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-bottom:.125rem;padding-top:.125rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.py-16{padding-bottom:4rem;padding-top:4rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-2\.5{padding-bottom:.625rem;padding-top:.625rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-3\.5{padding-bottom:.875rem;padding-top:.875rem}.py-4{padding-bottom:1rem;padding-top:1rem}.py-6{padding-bottom:1.5rem;padding-top:1.5rem}.py-8{padding-bottom:2rem;padding-top:2rem}.py-\[1px\]{padding-bottom:1px;padding-top:1px}.py-\[3px\]{padding-bottom:3px;padding-top:3px}.pb-1{padding-bottom:.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pb-5{padding-bottom:1.25rem}.pl-0\.5{padding-left:.125rem}.pl-2{padding-left:.5rem}.pl-4{padding-left:1rem}.pl-5{padding-left:1.25rem}.pr-10{padding-right:2.5rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-5{padding-top:1.25rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-display{font-family:Sora,system-ui,sans-serif}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:Outfit,system-ui,sans-serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[0\.65rem\]{font-size:.65rem}.text-\[0\.68rem\]{font-size:.68rem}.text-\[0\.6rem\]{font-size:.6rem}.text-\[0\.72rem\]{font-size:.72rem}.text-\[0\.74rem\]{font-size:.74rem}.text-\[0\.78rem\]{font-size:.78rem}.text-\[0\.7rem\]{font-size:.7rem}.text-\[0\.8125rem\]{font-size:.8125rem}.text-\[0\.82rem\]{font-size:.82rem}.text-\[0\.88rem\]{font-size:.88rem}.text-\[0\.95rem\]{font-size:.95rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.normal-case{text-transform:none}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-6{line-height:1.5rem}.leading-7{line-height:1.75rem}.leading-8{line-height:2rem}.leading-\[1\.55\]{line-height:1.55}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-\[0\.14em\]{letter-spacing:.14em}.tracking-\[0\.16em\]{letter-spacing:.16em}.tracking-\[0\.18em\]{letter-spacing:.18em}.tracking-\[0\.20em\]{letter-spacing:.2em}.tracking-\[0\.22em\]{letter-spacing:.22em}.tracking-normal{letter-spacing:0}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-amber-200{--tw-text-opacity:1;color:rgb(253 230 138/var(--tw-text-opacity,1))}.text-amber-200\/70{color:hsla(48,97%,77%,.7)}.text-amber-200\/90{color:hsla(48,97%,77%,.9)}.text-amber-300{--tw-text-opacity:1;color:rgb(252 211 77/var(--tw-text-opacity,1))}.text-amber-300\/45{color:rgba(252,211,77,.45)}.text-amber-300\/70{color:rgba(252,211,77,.7)}.text-amber-300\/80{color:rgba(252,211,77,.8)}.text-amber-300\/85{color:rgba(252,211,77,.85)}.text-amber-400{--tw-text-opacity:1;color:rgb(251 191 36/var(--tw-text-opacity,1))}.text-amber-400\/80{color:rgba(251,191,36,.8)}.text-amber-500{--tw-text-opacity:1;color:rgb(245 158 11/var(--tw-text-opacity,1))}.text-blue-200{--tw-text-opacity:1;color:rgb(191 219 254/var(--tw-text-opacity,1))}.text-blue-300{--tw-text-opacity:1;color:rgb(147 197 253/var(--tw-text-opacity,1))}.text-blue-300\/70{color:rgba(147,197,253,.7)}.text-blue-400{--tw-text-opacity:1;color:rgb(96 165 250/var(--tw-text-opacity,1))}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-commerce-200{--tw-text-opacity:1;color:rgb(194 208 232/var(--tw-text-opacity,1))}.text-commerce-200\/70{color:rgba(194,208,232,.7)}.text-commerce-300{--tw-text-opacity:1;color:rgb(159 180 214/var(--tw-text-opacity,1))}.text-commerce-300\/70{color:rgba(159,180,214,.7)}.text-commerce-400{--tw-text-opacity:1;color:rgb(125 151 194/var(--tw-text-opacity,1))}.text-commerce-500{--tw-text-opacity:1;color:rgb(94 122 166/var(--tw-text-opacity,1))}.text-cyan-200{--tw-text-opacity:1;color:rgb(165 243 252/var(--tw-text-opacity,1))}.text-cyan-200\/70{color:rgba(165,243,252,.7)}.text-cyan-300{--tw-text-opacity:1;color:rgb(103 232 249/var(--tw-text-opacity,1))}.text-cyan-300\/45{color:rgba(103,232,249,.45)}.text-cyan-300\/70{color:rgba(103,232,249,.7)}.text-cyan-300\/80{color:rgba(103,232,249,.8)}.text-cyan-400{--tw-text-opacity:1;color:rgb(34 211 238/var(--tw-text-opacity,1))}.text-cyan-400\/75{color:rgba(34,211,238,.75)}.text-cyan-500{--tw-text-opacity:1;color:rgb(6 182 212/var(--tw-text-opacity,1))}.text-emerald-200{--tw-text-opacity:1;color:rgb(167 243 208/var(--tw-text-opacity,1))}.text-emerald-300{--tw-text-opacity:1;color:rgb(110 231 183/var(--tw-text-opacity,1))}.text-emerald-300\/45{color:rgba(110,231,183,.45)}.text-emerald-300\/70{color:rgba(110,231,183,.7)}.text-emerald-300\/80{color:rgba(110,231,183,.8)}.text-emerald-400{--tw-text-opacity:1;color:rgb(52 211 153/var(--tw-text-opacity,1))}.text-emerald-400\/75{color:rgba(52,211,153,.75)}.text-emerald-500{--tw-text-opacity:1;color:rgb(16 185 129/var(--tw-text-opacity,1))}.text-fuchsia-200{--tw-text-opacity:1;color:rgb(245 208 254/var(--tw-text-opacity,1))}.text-fuchsia-300{--tw-text-opacity:1;color:rgb(240 171 252/var(--tw-text-opacity,1))}.text-fuchsia-400{--tw-text-opacity:1;color:rgb(232 121 249/var(--tw-text-opacity,1))}.text-fuchsia-500{--tw-text-opacity:1;color:rgb(217 70 239/var(--tw-text-opacity,1))}.text-gray-200{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity,1))}.text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity,1))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-green-200{--tw-text-opacity:1;color:rgb(187 247 208/var(--tw-text-opacity,1))}.text-green-300{--tw-text-opacity:1;color:rgb(134 239 172/var(--tw-text-opacity,1))}.text-green-400{--tw-text-opacity:1;color:rgb(74 222 128/var(--tw-text-opacity,1))}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity,1))}.text-indigo-200{--tw-text-opacity:1;color:rgb(199 210 254/var(--tw-text-opacity,1))}.text-indigo-300{--tw-text-opacity:1;color:rgb(165 180 252/var(--tw-text-opacity,1))}.text-indigo-300\/70{color:rgba(165,180,252,.7)}.text-indigo-400{--tw-text-opacity:1;color:rgb(129 140 248/var(--tw-text-opacity,1))}.text-indigo-500{--tw-text-opacity:1;color:rgb(99 102 241/var(--tw-text-opacity,1))}.text-lime-200{--tw-text-opacity:1;color:rgb(217 249 157/var(--tw-text-opacity,1))}.text-lime-300{--tw-text-opacity:1;color:rgb(190 242 100/var(--tw-text-opacity,1))}.text-lime-400{--tw-text-opacity:1;color:rgb(163 230 53/var(--tw-text-opacity,1))}.text-lime-500{--tw-text-opacity:1;color:rgb(132 204 22/var(--tw-text-opacity,1))}.text-neutral-200{--tw-text-opacity:1;color:rgb(229 229 229/var(--tw-text-opacity,1))}.text-neutral-300{--tw-text-opacity:1;color:rgb(212 212 212/var(--tw-text-opacity,1))}.text-neutral-400{--tw-text-opacity:1;color:rgb(163 163 163/var(--tw-text-opacity,1))}.text-neutral-500{--tw-text-opacity:1;color:rgb(115 115 115/var(--tw-text-opacity,1))}.text-orange-200{--tw-text-opacity:1;color:rgb(254 215 170/var(--tw-text-opacity,1))}.text-orange-300{--tw-text-opacity:1;color:rgb(253 186 116/var(--tw-text-opacity,1))}.text-orange-400{--tw-text-opacity:1;color:rgb(251 146 60/var(--tw-text-opacity,1))}.text-orange-500{--tw-text-opacity:1;color:rgb(249 115 22/var(--tw-text-opacity,1))}.text-pink-200{--tw-text-opacity:1;color:rgb(251 207 232/var(--tw-text-opacity,1))}.text-pink-300{--tw-text-opacity:1;color:rgb(249 168 212/var(--tw-text-opacity,1))}.text-pink-400{--tw-text-opacity:1;color:rgb(244 114 182/var(--tw-text-opacity,1))}.text-pink-500{--tw-text-opacity:1;color:rgb(236 72 153/var(--tw-text-opacity,1))}.text-purple-200{--tw-text-opacity:1;color:rgb(233 213 255/var(--tw-text-opacity,1))}.text-purple-300{--tw-text-opacity:1;color:rgb(216 180 254/var(--tw-text-opacity,1))}.text-purple-400{--tw-text-opacity:1;color:rgb(192 132 252/var(--tw-text-opacity,1))}.text-purple-500{--tw-text-opacity:1;color:rgb(168 85 247/var(--tw-text-opacity,1))}.text-red-200{--tw-text-opacity:1;color:rgb(254 202 202/var(--tw-text-opacity,1))}.text-red-300{--tw-text-opacity:1;color:rgb(252 165 165/var(--tw-text-opacity,1))}.text-red-300\/90{color:hsla(0,94%,82%,.9)}.text-red-400{--tw-text-opacity:1;color:rgb(248 113 113/var(--tw-text-opacity,1))}.text-red-400\/80{color:hsla(0,91%,71%,.8)}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.text-rose-100{--tw-text-opacity:1;color:rgb(255 228 230/var(--tw-text-opacity,1))}.text-rose-200{--tw-text-opacity:1;color:rgb(254 205 211/var(--tw-text-opacity,1))}.text-rose-200\/80{color:rgba(254,205,211,.8)}.text-rose-300{--tw-text-opacity:1;color:rgb(253 164 175/var(--tw-text-opacity,1))}.text-rose-300\/45{color:rgba(253,164,175,.45)}.text-rose-300\/70{color:rgba(253,164,175,.7)}.text-rose-400{--tw-text-opacity:1;color:rgb(251 113 133/var(--tw-text-opacity,1))}.text-rose-500{--tw-text-opacity:1;color:rgb(244 63 94/var(--tw-text-opacity,1))}.text-sky-200{--tw-text-opacity:1;color:rgb(186 230 253/var(--tw-text-opacity,1))}.text-sky-300{--tw-text-opacity:1;color:rgb(125 211 252/var(--tw-text-opacity,1))}.text-sky-300\/45{color:rgba(125,211,252,.45)}.text-sky-300\/70{color:rgba(125,211,252,.7)}.text-sky-400{--tw-text-opacity:1;color:rgb(56 189 248/var(--tw-text-opacity,1))}.text-sky-500{--tw-text-opacity:1;color:rgb(14 165 233/var(--tw-text-opacity,1))}.text-slate-100{--tw-text-opacity:1;color:rgb(241 245 249/var(--tw-text-opacity,1))}.text-slate-200{--tw-text-opacity:1;color:rgb(226 232 240/var(--tw-text-opacity,1))}.text-slate-300{--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity,1))}.text-slate-300\/90{color:rgba(203,213,225,.9)}.text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity,1))}.text-slate-400\/55{color:rgba(148,163,184,.55)}.text-slate-400\/60{color:rgba(148,163,184,.6)}.text-slate-400\/70{color:rgba(148,163,184,.7)}.text-slate-400\/85{color:rgba(148,163,184,.85)}.text-slate-400\/90{color:rgba(148,163,184,.9)}.text-slate-500{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1))}.text-slate-500\/60{color:rgba(100,116,139,.6)}.text-slate-500\/70{color:rgba(100,116,139,.7)}.text-slate-500\/80{color:rgba(100,116,139,.8)}.text-slate-600{--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity,1))}.text-stone-200{--tw-text-opacity:1;color:rgb(231 229 228/var(--tw-text-opacity,1))}.text-stone-300{--tw-text-opacity:1;color:rgb(214 211 209/var(--tw-text-opacity,1))}.text-stone-400{--tw-text-opacity:1;color:rgb(168 162 158/var(--tw-text-opacity,1))}.text-stone-500{--tw-text-opacity:1;color:rgb(120 113 108/var(--tw-text-opacity,1))}.text-teal-200{--tw-text-opacity:1;color:rgb(153 246 228/var(--tw-text-opacity,1))}.text-teal-300{--tw-text-opacity:1;color:rgb(94 234 212/var(--tw-text-opacity,1))}.text-teal-400{--tw-text-opacity:1;color:rgb(45 212 191/var(--tw-text-opacity,1))}.text-teal-500{--tw-text-opacity:1;color:rgb(20 184 166/var(--tw-text-opacity,1))}.text-transparent{color:transparent}.text-violet-200{--tw-text-opacity:1;color:rgb(221 214 254/var(--tw-text-opacity,1))}.text-violet-200\/70{color:rgba(221,214,254,.7)}.text-violet-300{--tw-text-opacity:1;color:rgb(196 181 253/var(--tw-text-opacity,1))}.text-violet-300\/45{color:rgba(196,181,253,.45)}.text-violet-300\/70{color:rgba(196,181,253,.7)}.text-violet-300\/80{color:rgba(196,181,253,.8)}.text-violet-400{--tw-text-opacity:1;color:rgb(167 139 250/var(--tw-text-opacity,1))}.text-violet-500{--tw-text-opacity:1;color:rgb(139 92 246/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-yellow-200{--tw-text-opacity:1;color:rgb(254 240 138/var(--tw-text-opacity,1))}.text-yellow-300{--tw-text-opacity:1;color:rgb(253 224 71/var(--tw-text-opacity,1))}.text-yellow-400{--tw-text-opacity:1;color:rgb(250 204 21/var(--tw-text-opacity,1))}.text-yellow-500{--tw-text-opacity:1;color:rgb(234 179 8/var(--tw-text-opacity,1))}.text-zinc-200{--tw-text-opacity:1;color:rgb(228 228 231/var(--tw-text-opacity,1))}.text-zinc-300{--tw-text-opacity:1;color:rgb(212 212 216/var(--tw-text-opacity,1))}.text-zinc-400{--tw-text-opacity:1;color:rgb(161 161 170/var(--tw-text-opacity,1))}.text-zinc-500{--tw-text-opacity:1;color:rgb(113 113 122/var(--tw-text-opacity,1))}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.accent-cyan-400{accent-color:#22d3ee}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-inner{--tw-shadow:inset 0 2px 4px 0 rgba(0,0,0,.05);--tw-shadow-colored:inset 0 2px 4px 0 var(--tw-shadow-color)}.shadow-inner,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-black\/20{--tw-shadow-color:rgba(0,0,0,.2);--tw-shadow:var(--tw-shadow-colored)}.shadow-black\/30{--tw-shadow-color:rgba(0,0,0,.3);--tw-shadow:var(--tw-shadow-colored)}.shadow-black\/40{--tw-shadow-color:rgba(0,0,0,.4);--tw-shadow:var(--tw-shadow-colored)}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-1{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-amber-400\/20{--tw-ring-color:rgba(251,191,36,.2)}.ring-amber-400\/50{--tw-ring-color:rgba(251,191,36,.5)}.ring-amber-400\/60{--tw-ring-color:rgba(251,191,36,.6)}.ring-amber-500\/10{--tw-ring-color:rgba(245,158,11,.1)}.ring-amber-500\/20{--tw-ring-color:rgba(245,158,11,.2)}.ring-amber-500\/25{--tw-ring-color:rgba(245,158,11,.25)}.ring-blue-400\/50{--tw-ring-color:rgba(96,165,250,.5)}.ring-blue-400\/60{--tw-ring-color:rgba(96,165,250,.6)}.ring-blue-500\/10{--tw-ring-color:rgba(59,130,246,.1)}.ring-commerce-400\/50{--tw-ring-color:rgba(125,151,194,.5)}.ring-commerce-400\/60{--tw-ring-color:rgba(125,151,194,.6)}.ring-commerce-500\/10{--tw-ring-color:rgba(94,122,166,.1)}.ring-cyan-400\/50{--tw-ring-color:rgba(34,211,238,.5)}.ring-cyan-400\/60{--tw-ring-color:rgba(34,211,238,.6)}.ring-cyan-500\/10{--tw-ring-color:rgba(6,182,212,.1)}.ring-cyan-500\/20{--tw-ring-color:rgba(6,182,212,.2)}.ring-emerald-400\/15{--tw-ring-color:rgba(52,211,153,.15)}.ring-emerald-400\/20{--tw-ring-color:rgba(52,211,153,.2)}.ring-emerald-400\/50{--tw-ring-color:rgba(52,211,153,.5)}.ring-emerald-400\/60{--tw-ring-color:rgba(52,211,153,.6)}.ring-emerald-500\/10{--tw-ring-color:rgba(16,185,129,.1)}.ring-emerald-500\/20{--tw-ring-color:rgba(16,185,129,.2)}.ring-emerald-500\/25{--tw-ring-color:rgba(16,185,129,.25)}.ring-fuchsia-400\/50{--tw-ring-color:rgba(232,121,249,.5)}.ring-fuchsia-400\/60{--tw-ring-color:rgba(232,121,249,.6)}.ring-fuchsia-500\/10{--tw-ring-color:rgba(217,70,239,.1)}.ring-gray-400\/50{--tw-ring-color:rgba(156,163,175,.5)}.ring-gray-400\/60{--tw-ring-color:rgba(156,163,175,.6)}.ring-gray-500\/10{--tw-ring-color:hsla(220,9%,46%,.1)}.ring-green-400\/50{--tw-ring-color:rgba(74,222,128,.5)}.ring-green-400\/60{--tw-ring-color:rgba(74,222,128,.6)}.ring-green-500\/10{--tw-ring-color:rgba(34,197,94,.1)}.ring-indigo-400\/50{--tw-ring-color:rgba(129,140,248,.5)}.ring-indigo-400\/60{--tw-ring-color:rgba(129,140,248,.6)}.ring-indigo-500\/10{--tw-ring-color:rgba(99,102,241,.1)}.ring-lime-400\/50{--tw-ring-color:rgba(163,230,53,.5)}.ring-lime-400\/60{--tw-ring-color:rgba(163,230,53,.6)}.ring-lime-500\/10{--tw-ring-color:rgba(132,204,22,.1)}.ring-neutral-400\/50{--tw-ring-color:hsla(0,0%,64%,.5)}.ring-neutral-400\/60{--tw-ring-color:hsla(0,0%,64%,.6)}.ring-neutral-500\/10{--tw-ring-color:hsla(0,0%,45%,.1)}.ring-orange-400\/50{--tw-ring-color:rgba(251,146,60,.5)}.ring-orange-400\/60{--tw-ring-color:rgba(251,146,60,.6)}.ring-orange-500\/10{--tw-ring-color:rgba(249,115,22,.1)}.ring-pink-400\/50{--tw-ring-color:rgba(244,114,182,.5)}.ring-pink-400\/60{--tw-ring-color:rgba(244,114,182,.6)}.ring-pink-500\/10{--tw-ring-color:rgba(236,72,153,.1)}.ring-purple-400\/50{--tw-ring-color:rgba(192,132,252,.5)}.ring-purple-400\/60{--tw-ring-color:rgba(192,132,252,.6)}.ring-purple-500\/10{--tw-ring-color:rgba(168,85,247,.1)}.ring-red-400\/50{--tw-ring-color:hsla(0,91%,71%,.5)}.ring-red-400\/60{--tw-ring-color:hsla(0,91%,71%,.6)}.ring-red-500\/10{--tw-ring-color:rgba(239,68,68,.1)}.ring-rose-400\/50{--tw-ring-color:rgba(251,113,133,.5)}.ring-rose-400\/60{--tw-ring-color:rgba(251,113,133,.6)}.ring-rose-500\/10{--tw-ring-color:rgba(244,63,94,.1)}.ring-sky-400\/50{--tw-ring-color:rgba(56,189,248,.5)}.ring-sky-400\/60{--tw-ring-color:rgba(56,189,248,.6)}.ring-sky-500\/10{--tw-ring-color:rgba(14,165,233,.1)}.ring-slate-400\/50{--tw-ring-color:rgba(148,163,184,.5)}.ring-slate-400\/60{--tw-ring-color:rgba(148,163,184,.6)}.ring-slate-500\/10{--tw-ring-color:rgba(100,116,139,.1)}.ring-slate-500\/25{--tw-ring-color:rgba(100,116,139,.25)}.ring-stone-400\/50{--tw-ring-color:hsla(24,5%,64%,.5)}.ring-stone-400\/60{--tw-ring-color:hsla(24,5%,64%,.6)}.ring-stone-500\/10{--tw-ring-color:hsla(25,5%,45%,.1)}.ring-teal-400\/50{--tw-ring-color:rgba(45,212,191,.5)}.ring-teal-400\/60{--tw-ring-color:rgba(45,212,191,.6)}.ring-teal-500\/10{--tw-ring-color:rgba(20,184,166,.1)}.ring-violet-400\/50{--tw-ring-color:rgba(167,139,250,.5)}.ring-violet-400\/60{--tw-ring-color:rgba(167,139,250,.6)}.ring-violet-500\/10{--tw-ring-color:rgba(139,92,246,.1)}.ring-violet-500\/20{--tw-ring-color:rgba(139,92,246,.2)}.ring-white\/\[0\.06\]{--tw-ring-color:hsla(0,0%,100%,.06)}.ring-white\/\[0\.08\]{--tw-ring-color:hsla(0,0%,100%,.08)}.ring-yellow-400\/50{--tw-ring-color:rgba(250,204,21,.5)}.ring-yellow-400\/60{--tw-ring-color:rgba(250,204,21,.6)}.ring-yellow-500\/10{--tw-ring-color:rgba(234,179,8,.1)}.ring-zinc-400\/50{--tw-ring-color:hsla(240,5%,65%,.5)}.ring-zinc-400\/60{--tw-ring-color:hsla(240,5%,65%,.6)}.ring-zinc-500\/10{--tw-ring-color:hsla(240,4%,46%,.1)}.blur{--tw-blur:blur(8px)}.blur,.drop-shadow{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.drop-shadow{--tw-drop-shadow:drop-shadow(0 1px 2px rgba(0,0,0,.1)) drop-shadow(0 1px 1px rgba(0,0,0,.06))}.invert{--tw-invert:invert(100%)}.filter,.invert{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(12px)}.backdrop-blur-md,.backdrop-blur-sm{-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-\[width\]{transition-duration:.15s;transition-property:width;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-all{transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-opacity{transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-transform{transition-duration:.15s;transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-200{transition-duration:.2s}.duration-500{transition-duration:.5s}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[start\:end\]{start:end}.marker\:text-slate-500 ::marker{color:#64748b}.marker\:text-slate-500::marker{color:#64748b}.file\:mr-3::file-selector-button{margin-right:.75rem}.file\:rounded-lg::file-selector-button{border-radius:.5rem}.file\:border-0::file-selector-button{border-width:0}.file\:bg-cyan-500\/20::file-selector-button{background-color:rgba(6,182,212,.2)}.file\:px-3::file-selector-button{padding-left:.75rem;padding-right:.75rem}.file\:py-1\.5::file-selector-button{padding-bottom:.375rem;padding-top:.375rem}.file\:text-cyan-200::file-selector-button{--tw-text-opacity:1;color:rgb(165 243 252/var(--tw-text-opacity,1))}.placeholder\:text-slate-400\/85::-moz-placeholder{color:rgba(148,163,184,.85)}.placeholder\:text-slate-400\/85::placeholder{color:rgba(148,163,184,.85)}.placeholder\:text-slate-500::-moz-placeholder{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1))}.placeholder\:text-slate-500::placeholder{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1))}.placeholder\:text-slate-500\/70::-moz-placeholder{color:rgba(100,116,139,.7)}.placeholder\:text-slate-500\/70::placeholder{color:rgba(100,116,139,.7)}.placeholder\:text-slate-500\/80::-moz-placeholder{color:rgba(100,116,139,.8)}.placeholder\:text-slate-500\/80::placeholder{color:rgba(100,116,139,.8)}.first\:mt-0:first-child{margin-top:0}.last\:mb-0:last-child{margin-bottom:0}.last\:border-b-0:last-child{border-bottom-width:0}.focus-within\:border-cyan-500\/30:focus-within{border-color:rgba(6,182,212,.3)}.focus-within\:ring-1:focus-within{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus-within\:ring-cyan-500\/20:focus-within{--tw-ring-color:rgba(6,182,212,.2)}.hover\:-translate-y-0\.5:hover{--tw-translate-y:-0.125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:border-amber-400\/40:hover{border-color:rgba(251,191,36,.4)}.hover\:border-amber-400\/50:hover{border-color:rgba(251,191,36,.5)}.hover\:border-cyan-400\/40:hover{border-color:rgba(34,211,238,.4)}.hover\:border-cyan-400\/50:hover{border-color:rgba(34,211,238,.5)}.hover\:border-cyan-400\/60:hover{border-color:rgba(34,211,238,.6)}.hover\:border-cyan-500\/30:hover{border-color:rgba(6,182,212,.3)}.hover\:border-emerald-400\/40:hover{border-color:rgba(52,211,153,.4)}.hover\:border-emerald-400\/50:hover{border-color:rgba(52,211,153,.5)}.hover\:border-rose-400\/40:hover{border-color:rgba(251,113,133,.4)}.hover\:border-sky-400\/40:hover{border-color:rgba(56,189,248,.4)}.hover\:border-violet-400\/40:hover{border-color:rgba(167,139,250,.4)}.hover\:border-violet-400\/50:hover{border-color:rgba(167,139,250,.5)}.hover\:border-white\/20:hover{border-color:hsla(0,0%,100%,.2)}.hover\:border-white\/\[0\.10\]:hover{border-color:hsla(0,0%,100%,.1)}.hover\:bg-amber-500\/25:hover{background-color:rgba(245,158,11,.25)}.hover\:bg-amber-500\/\[0\.08\]:hover{background-color:rgba(245,158,11,.08)}.hover\:bg-amber-950\/20:hover{background-color:rgba(69,26,3,.2)}.hover\:bg-cyan-400\/15:hover{background-color:rgba(34,211,238,.15)}.hover\:bg-cyan-400\/20:hover{background-color:rgba(34,211,238,.2)}.hover\:bg-cyan-500\/\[0\.08\]:hover{background-color:rgba(6,182,212,.08)}.hover\:bg-cyan-950\/20:hover{background-color:rgba(8,51,68,.2)}.hover\:bg-emerald-400\/20:hover{background-color:rgba(52,211,153,.2)}.hover\:bg-emerald-500\/25:hover{background-color:rgba(16,185,129,.25)}.hover\:bg-emerald-500\/\[0\.08\]:hover{background-color:rgba(16,185,129,.08)}.hover\:bg-emerald-950\/20:hover{background-color:rgba(2,44,34,.2)}.hover\:bg-rose-500\/10:hover{background-color:rgba(244,63,94,.1)}.hover\:bg-rose-500\/\[0\.08\]:hover{background-color:rgba(244,63,94,.08)}.hover\:bg-sky-500\/\[0\.08\]:hover{background-color:rgba(14,165,233,.08)}.hover\:bg-slate-500\/25:hover{background-color:rgba(100,116,139,.25)}.hover\:bg-violet-500\/\[0\.08\]:hover{background-color:rgba(139,92,246,.08)}.hover\:bg-violet-950\/20:hover{background-color:rgba(46,16,101,.2)}.hover\:bg-white\/10:hover{background-color:hsla(0,0%,100%,.1)}.hover\:bg-white\/\[0\.02\]:hover{background-color:hsla(0,0%,100%,.02)}.hover\:bg-white\/\[0\.03\]:hover{background-color:hsla(0,0%,100%,.03)}.hover\:bg-white\/\[0\.05\]:hover{background-color:hsla(0,0%,100%,.05)}.hover\:bg-white\/\[0\.06\]:hover{background-color:hsla(0,0%,100%,.06)}.hover\:bg-white\/\[0\.08\]:hover{background-color:hsla(0,0%,100%,.08)}.hover\:bg-white\/\[0\.10\]:hover{background-color:hsla(0,0%,100%,.1)}.hover\:text-cyan-200:hover{--tw-text-opacity:1;color:rgb(165 243 252/var(--tw-text-opacity,1))}.hover\:text-cyan-300:hover{--tw-text-opacity:1;color:rgb(103 232 249/var(--tw-text-opacity,1))}.hover\:text-rose-300:hover{--tw-text-opacity:1;color:rgb(253 164 175/var(--tw-text-opacity,1))}.hover\:text-slate-100:hover{--tw-text-opacity:1;color:rgb(241 245 249/var(--tw-text-opacity,1))}.hover\:text-slate-200:hover{--tw-text-opacity:1;color:rgb(226 232 240/var(--tw-text-opacity,1))}.hover\:text-slate-300:hover{--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity,1))}.hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:shadow-\[0_10px_28px_-10px_rgba\(139\2c 92\2c 246\2c 0\.40\)\]:hover{--tw-shadow:0 10px 28px -10px rgba(139,92,246,.4);--tw-shadow-colored:0 10px 28px -10px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:shadow-\[0_10px_28px_-10px_rgba\(14\2c 165\2c 233\2c 0\.40\)\]:hover{--tw-shadow:0 10px 28px -10px rgba(14,165,233,.4);--tw-shadow-colored:0 10px 28px -10px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:shadow-\[0_10px_28px_-10px_rgba\(16\2c 185\2c 129\2c 0\.40\)\]:hover{--tw-shadow:0 10px 28px -10px rgba(16,185,129,.4);--tw-shadow-colored:0 10px 28px -10px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:shadow-\[0_10px_28px_-10px_rgba\(244\2c 63\2c 94\2c 0\.40\)\]:hover{--tw-shadow:0 10px 28px -10px rgba(244,63,94,.4);--tw-shadow-colored:0 10px 28px -10px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:shadow-\[0_10px_28px_-10px_rgba\(245\2c 158\2c 11\2c 0\.40\)\]:hover{--tw-shadow:0 10px 28px -10px rgba(245,158,11,.4);--tw-shadow-colored:0 10px 28px -10px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:shadow-\[0_10px_28px_-10px_rgba\(6\2c 182\2c 212\2c 0\.40\)\]:hover{--tw-shadow:0 10px 28px -10px rgba(6,182,212,.4);--tw-shadow-colored:0 10px 28px -10px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:ring-rose-500\/30:hover{--tw-ring-color:rgba(244,63,94,.3)}.hover\:file\:bg-cyan-500\/30::file-selector-button:hover{background-color:rgba(6,182,212,.3)}.focus\:border-cyan-400:focus{--tw-border-opacity:1;border-color:rgb(34 211 238/var(--tw-border-opacity,1))}.focus\:border-cyan-500\/35:focus{border-color:rgba(6,182,212,.35)}.focus\:border-cyan-500\/40:focus{border-color:rgba(6,182,212,.4)}.focus\:border-emerald-500\/40:focus{border-color:rgba(16,185,129,.4)}.focus\:text-slate-300:focus{--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity,1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-amber-400\/40:focus{--tw-ring-color:rgba(251,191,36,.4)}.focus\:ring-cyan-400\/40:focus{--tw-ring-color:rgba(34,211,238,.4)}.focus\:ring-cyan-500\/15:focus{--tw-ring-color:rgba(6,182,212,.15)}.focus\:ring-cyan-500\/20:focus{--tw-ring-color:rgba(6,182,212,.2)}.focus\:ring-emerald-400\/40:focus{--tw-ring-color:rgba(52,211,153,.4)}.focus\:ring-emerald-500\/15:focus{--tw-ring-color:rgba(16,185,129,.15)}.focus\:ring-emerald-500\/40:focus{--tw-ring-color:rgba(16,185,129,.4)}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus-visible\:ring-cyan-400:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgb(34 211 238/var(--tw-ring-opacity,1))}.focus-visible\:ring-cyan-400\/40:focus-visible{--tw-ring-color:rgba(34,211,238,.4)}.focus-visible\:ring-cyan-400\/60:focus-visible{--tw-ring-color:rgba(34,211,238,.6)}.focus-visible\:ring-cyan-400\/80:focus-visible{--tw-ring-color:rgba(34,211,238,.8)}.focus-visible\:ring-emerald-400:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgb(52 211 153/var(--tw-ring-opacity,1))}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px}.focus-visible\:ring-offset-space-deep:focus-visible{--tw-ring-offset-color:#080e1e}.focus-visible\:ring-offset-space-void:focus-visible{--tw-ring-offset-color:#01040e}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.group[open] .group-open\:rotate-90,.group\/course[open] .group-open\/course\:rotate-90,.group\/subj[open] .group-open\/subj\:rotate-90,.group\/topic[open] .group-open\/topic\:rotate-90{--tw-rotate:90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:translate-x-0\.5{--tw-translate-x:0.125rem}.group:hover .group-hover\:scale-\[1\.10\],.group:hover .group-hover\:translate-x-0\.5{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:scale-\[1\.10\]{--tw-scale-x:1.10;--tw-scale-y:1.10}.group:hover .group-hover\:bg-amber-500\/20{background-color:rgba(245,158,11,.2)}.group:hover .group-hover\:bg-cyan-500\/20{background-color:rgba(6,182,212,.2)}.group:hover .group-hover\:bg-emerald-500\/20{background-color:rgba(16,185,129,.2)}.group:hover .group-hover\:bg-violet-500\/20{background-color:rgba(139,92,246,.2)}.group:hover .group-hover\:bg-white\/\[0\.10\]{background-color:hsla(0,0%,100%,.1)}.group:hover .group-hover\:text-amber-200{--tw-text-opacity:1;color:rgb(253 230 138/var(--tw-text-opacity,1))}.group:hover .group-hover\:text-amber-300{--tw-text-opacity:1;color:rgb(252 211 77/var(--tw-text-opacity,1))}.group:hover .group-hover\:text-cyan-200{--tw-text-opacity:1;color:rgb(165 243 252/var(--tw-text-opacity,1))}.group:hover .group-hover\:text-cyan-300{--tw-text-opacity:1;color:rgb(103 232 249/var(--tw-text-opacity,1))}.group:hover .group-hover\:text-emerald-300{--tw-text-opacity:1;color:rgb(110 231 183/var(--tw-text-opacity,1))}.group:hover .group-hover\:text-violet-200{--tw-text-opacity:1;color:rgb(221 214 254/var(--tw-text-opacity,1))}.group:hover .group-hover\:text-violet-300{--tw-text-opacity:1;color:rgb(196 181 253/var(--tw-text-opacity,1))}.group:hover .group-hover\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.group:hover .group-hover\:opacity-100{opacity:1}.group:hover .group-hover\:shadow-\[0_0_22px_-4px_rgba\(139\2c 92\2c 246\2c 0\.45\)\]{--tw-shadow:0 0 22px -4px rgba(139,92,246,.45);--tw-shadow-colored:0 0 22px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.group:hover .group-hover\:shadow-\[0_0_22px_-4px_rgba\(16\2c 185\2c 129\2c 0\.45\)\]{--tw-shadow:0 0 22px -4px rgba(16,185,129,.45);--tw-shadow-colored:0 0 22px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.group:hover .group-hover\:shadow-\[0_0_22px_-4px_rgba\(245\2c 158\2c 11\2c 0\.4\)\]{--tw-shadow:0 0 22px -4px rgba(245,158,11,.4);--tw-shadow-colored:0 0 22px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.group:hover .group-hover\:shadow-\[0_0_22px_-4px_rgba\(6\2c 182\2c 212\2c 0\.45\)\]{--tw-shadow:0 0 22px -4px rgba(6,182,212,.45);--tw-shadow-colored:0 0 22px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.group:hover .group-hover\:ring-amber-400\/40{--tw-ring-color:rgba(251,191,36,.4)}.group:hover .group-hover\:ring-amber-500\/25{--tw-ring-color:rgba(245,158,11,.25)}.group:hover .group-hover\:ring-cyan-400\/40{--tw-ring-color:rgba(34,211,238,.4)}.group:hover .group-hover\:ring-cyan-500\/25{--tw-ring-color:rgba(6,182,212,.25)}.group:hover .group-hover\:ring-emerald-400\/40{--tw-ring-color:rgba(52,211,153,.4)}.group:hover .group-hover\:ring-emerald-500\/25{--tw-ring-color:rgba(16,185,129,.25)}.group:hover .group-hover\:ring-violet-400\/40{--tw-ring-color:rgba(167,139,250,.4)}.group:hover .group-hover\:ring-violet-500\/25{--tw-ring-color:rgba(139,92,246,.25)}@media (min-width:640px){.sm\:col-span-2{grid-column:span 2/span 2}.sm\:mt-10{margin-top:2.5rem}.sm\:mt-14{margin-top:3.5rem}.sm\:block{display:block}.sm\:h-10{height:2.5rem}.sm\:h-14{height:3.5rem}.sm\:h-20{height:5rem}.sm\:h-7{height:1.75rem}.sm\:min-h-\[13rem\]{min-height:13rem}.sm\:w-10{width:2.5rem}.sm\:w-14{width:3.5rem}.sm\:w-20{width:5rem}.sm\:w-7{width:1.75rem}.sm\:max-w-xs{max-width:20rem}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:flex-wrap{flex-wrap:wrap}.sm\:p-4{padding:1rem}.sm\:p-5{padding:1.25rem}.sm\:p-6{padding:1.5rem}.sm\:p-7{padding:1.75rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:py-12{padding-bottom:3rem;padding-top:3rem}.sm\:text-2xl{font-size:1.5rem;line-height:2rem}.sm\:text-3xl{font-size:1.875rem;line-height:2.25rem}.sm\:text-4xl{font-size:2.25rem;line-height:2.5rem}.sm\:text-base{font-size:1rem;line-height:1.5rem}.sm\:text-lg{font-size:1.125rem;line-height:1.75rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}.sm\:text-xl{font-size:1.25rem;line-height:1.75rem}}@media (min-width:768px){.md\:h-\[2\.125rem\]{height:2.125rem}.md\:h-\[3\.75rem\]{height:3.75rem}.md\:w-\[2\.125rem\]{width:2.125rem}.md\:w-\[3\.75rem\]{width:3.75rem}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:order-1{order:1}.lg\:order-2{order:2}.lg\:order-3{order:3}.lg\:col-span-1{grid-column:span 1/span 1}.lg\:col-span-3{grid-column:span 3/span 3}.lg\:col-span-4{grid-column:span 4/span 4}.lg\:col-span-8{grid-column:span 8/span 8}.lg\:h-10{height:2.5rem}.lg\:h-\[4\.5rem\]{height:4.5rem}.lg\:w-10{width:2.5rem}.lg\:w-52{width:13rem}.lg\:w-\[4\.5rem\]{width:4.5rem}.lg\:min-w-0{min-width:0}.lg\:flex-1{flex:1 1 0%}.lg\:shrink-0{flex-shrink:0}.lg\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.lg\:grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.lg\:text-5xl{font-size:3rem;line-height:1}.lg\:text-base{font-size:1rem;line-height:1.5rem}}@media (min-width:1280px){.xl\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}.\[\&\:\:-webkit-details-marker\]\:hidden::-webkit-details-marker{display:none}
/* ===== 01-shell.css ===== */
/* ─── Space shell ────────────────────────────────────────────────────────── */

.space-root {
  --space-void: #01040e;
  --space-deep: #080e1e;
  --glow-cyan:   rgba(34, 211, 238, 0.45);
  --glow-indigo: rgba(99, 102, 241, 0.35);
  /* Header height the Library/PDF/overview panes subtract from 100vh/100dvh and
     the practice take-page sticks below. Includes the iOS top safe-area inset so
     it tracks the taller header under the Dynamic Island (07-…chrome.css adds the
     same inset as header padding). env() = 0 on non-notched/desktop, so this
     stays 4.5rem there. The lone JS reader (practice_take.html) can't parse the
     calc() and falls back to 72px — fine, that path is desktop-only. */
  --preview-sticky-top: calc(4.5rem + env(safe-area-inset-top, 0px));

  /* ─── Layout tokens ─────────────────────────────────────────────────────── */
  /* Left column width in the preview grid (desktop). */
  --left-col-width: 19rem;

  /* Pill layout-track padding and gap (0.14rem pad × 2 = 0.28rem total gap). */
  --pill-pad: 0.14rem;
  --pill-gap: 0.28rem;  /* = --pill-pad * 2 */

  /* Opaque background shared by .pdf-tab-panels and .pdf-tab-panel
     so the page background never bleeds through during tab switches. */
  --pane-bg: rgb(4, 12, 28);

  /* Result/download panel widths. */
  --dl-panel-width: 20rem;        /* #result-panel max-width */
  --dl-panel-inner-width: 17rem;  /* .result-download-inner max-width */
}

.space-bg {
  background-color: var(--space-void);
}
/* The gradient wash painted on a fixed *element* layer (z-index:-1, below the noise/
   aurora/stars) rather than a `background-attachment: fixed` background. A fixed
   background repaints the whole viewport on every scroll frame — janking JS-driven
   smooth-scroll; a fixed element is composited and never repaints while scrolling. */
.space-bg::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(ellipse 110% 60% at 50%  -20%, rgba(30, 90, 200, 0.18), transparent 55%),
    radial-gradient(ellipse  70% 50% at 105%  20%, rgba(79, 70, 229, 0.10), transparent 50%),
    radial-gradient(ellipse  55% 45% at  -5%  65%, rgba(14, 165, 233, 0.08), transparent 48%),
    radial-gradient(ellipse  80% 60% at  80% 105%, rgba(59, 130, 246, 0.06), transparent 50%),
    linear-gradient(180deg, #01040e 0%, #080e1e 45%, #01040e 100%);
}

/* Noise dither overlay to eliminate colour banding in dark gradients.
   Uses an inline SVG turbulence filter — no external images needed. */
.space-bg::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-repeat: repeat;
  mix-blend-mode: overlay;
}

/* ─── Aurora overlay (slow drift) ────────────────────────────────────────── */
.space-aurora {
  pointer-events: none;
  position: fixed;
  inset: 0;
  z-index: 0;
  will-change: transform;
  background:
    radial-gradient(ellipse 80% 40% at 20%  15%, rgba(34, 211, 238, 0.055), transparent 55%),
    radial-gradient(ellipse 65% 35% at 80%  70%, rgba(99, 102, 241, 0.06),  transparent 50%),
    radial-gradient(ellipse 50% 30% at 55% 100%, rgba(59, 130, 246, 0.05),  transparent 50%);
  animation: aurora-drift 28s ease-in-out infinite alternate;
}

@keyframes aurora-drift {
  0%   { transform: translate3d(  0px,  0px, 0) scale(1);   }
  33%  { transform: translate3d( 18px, 10px, 0) scale(1.02); }
  66%  { transform: translate3d(-12px, 18px, 0) scale(0.98); }
  100% { transform: translate3d( 10px, -8px, 0) scale(1.01); }
}

/* ─── Stars ──────────────────────────────────────────────────────────────── */
/* Note: do not animate this layer’s opacity in keyframes — it capped visibility
   near ~0.5 and made updates look like “no change”. Glow uses filter only. */
.space-stars {
  pointer-events: none;
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
}

/* Individual stars generated by JS — random position, size and timing per load */
.star {
  position: absolute;
  border-radius: 50%;
  background: var(--star-color, white);
  will-change: opacity, filter;
  animation: star-twinkle var(--star-dur, 4s) ease-in-out infinite var(--star-delay, 0s);
}

@keyframes star-twinkle {
  0%, 100% {
    opacity: var(--star-dim, 0.06);
    filter: brightness(0.9);
  }
  50% {
    opacity: var(--star-bright, 0.85);
    filter: brightness(1.7) drop-shadow(0 0 var(--star-glow, 1px) var(--star-glow-color, rgba(210, 235, 255, 0.8)));
  }
}

/* ─── Z-stack (above aurora/stars) ──────────────────────────────────────── */
.z-content {
  position: relative;
  z-index: 2;
}

/* ─── Cross-document page transition ────────────────────────────────────── */
/* Two layers, picked by browser capability:
   1. Where cross-document View Transitions are supported (Chromium, Safari 18+),
      `@view-transition` below cross-fades the outgoing page snapshot into the
      incoming one — no white flash. When a VT drives the nav, base.html adds
      `page-entered` on the `pagereveal` event BEFORE first paint, which
      suppresses this per-load fade so the two don't stack.
   2. Everywhere else → the original per-load fade-in of the content layer. */
body:not(.page-entered) .z-content {
  animation: page-slide-in 0.28s ease-out both;
}

@keyframes page-slide-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  body:not(.page-entered) .z-content { animation: none; }
}

/* Opt every same-origin navigation into a real cross-document View Transition.
   Progressive enhancement: unsupported browsers ignore this and fall back to the
   fade above. The sticky header gets its own transition name so it stays put
   instead of cross-fading against itself; the fixed background layers sit behind
   everything and blend fine as part of the root snapshot. Reduced-motion turns
   the cross-fade into an instant cut (see 10-accessibility-motion.css). */
@view-transition { navigation: auto; }

.site-header { view-transition-name: site-header; }

/* ─── Landscape phones: reduce vertical padding (viewport ≤ 500 px tall) ─── */
/* Tablets in landscape are ≥ 768 px tall so this rule never fires for them.   */
@media (orientation: landscape) and (max-height: 500px) {
  #site-main {
    padding-top: 1.25rem;
    padding-bottom: 1.25rem;
  }
}

/* ─── Dark-theme scrollbars (site-wide default) ──────────────────────────────
 * The default OS scrollbar is bright/light and clashes with the dark shell on
 * Windows/Linux (where scrollbars are always visible). Theme it once here:
 *   - scrollbar-width/-color are INHERITED, so setting them on the root cascades
 *     to every scroll box (Firefox).
 *   - WebKit pseudo-elements aren't inherited, so the ``*`` selector covers
 *     descendant scroll containers (code console, helper drawers, lists, …).
 * Specific accent scrollbars (.pdf-viewport-scroll, .lib-subject-tab-scroll)
 * win by higher selector specificity, so this never overrides them.        */
.space-root {
  scrollbar-width: thin;
  scrollbar-color: rgba(148, 163, 184, 0.28) transparent;  /* slate-400 thumb / transparent track */
}

*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: rgba(148, 163, 184, 0.26);
  border-radius: 5px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover {
  background: rgba(148, 163, 184, 0.42);
  background-clip: padding-box;
}
*::-webkit-scrollbar-corner { background: transparent; }

/* Footer clears the iOS home indicator at rest (viewport-fit=cover); env() = 0
   on non-notched/desktop, so the footer's py-6 (1.5rem) is unchanged there. */
.z-content > footer {
  padding-bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
}

/* ─── Skip-to-content link (keyboard / screen-reader a11y) ───────────────────
 * First focusable element on the page. Off-screen until focused, then slides in
 * as a branded pill so keyboard users can jump past the sticky nav.            */
.skip-to-content {
  position: fixed;
  top: calc(0.5rem + env(safe-area-inset-top, 0px));   /* clear the notch when focused */
  left: 0.5rem;
  z-index: 60;                     /* above the sticky header (z-20) */
  transform: translateY(-150%);
  opacity: 0;
  padding: 0.55rem 1rem;
  border-radius: 0.6rem;
  background: linear-gradient(135deg, #22d3ee 0%, #3b82f6 58%, #6366f1 100%);
  color: #fff;
  font-size: 0.85rem;
  font-weight: 600;
  box-shadow: 0 8px 24px -6px rgba(0, 0, 0, 0.6);
  transition: transform 0.15s ease, opacity 0.15s ease;
}
.skip-to-content:focus {
  transform: translateY(0);
  opacity: 1;
  outline: 2px solid #fff;
  outline-offset: 2px;
}
/* The skip target receives programmatic focus on activation — no focus ring. */
#site-main:focus { outline: none; }

@media (prefers-reduced-motion: reduce) {
  .skip-to-content { transition: none; }
}

/* ─── Language mode: inline-gloss visibility ───────────────────────────────── */
/* Authored learning content is English with inline `term 中文` glosses, wrapped at
   render time in <span class="zh-gloss"> by web/gloss_wrap.py. "English" mode hides
   them; "Chinese / English" (gloss, default) and "Chinese" (zh) modes show them. The
   wrapper is emitted in every mode, so this single rule is the only difference — which
   is why the gloss↔English switch is instant (no reload) and the render cache is
   mode-independent. Vocab tables (.learn-vocab-table) are separate markup, never hidden. */
html.mode-en .zh-gloss { display: none; }

/* ─── Language-mode switcher (header flag) ─────────────────────────────────── */
/* Flag images are SVG (web/static/img/flag-{cn,split,uk}.svg); squares rounded here so
   the diagonal split flag needs only a triangle clip. Markup in base.html, behaviour in
   web/static/js/lang-switch.js. */
.lang-flag {
  display: inline-block;
  width: 1.15rem;
  height: 1.15rem;
  border-radius: 5px;
  background-size: cover;
  background-position: center;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18);
}
.lang-flag--cn { background-image: url(../img/flag-cn.svg); }
.lang-flag--split { background-image: url(../img/flag-split.svg); }
.lang-flag--uk { background-image: url(../img/flag-uk.svg); }
/* The trigger flag follows the current mode. */
.lang-switch[data-mode="zh"]    .lang-flag--current { background-image: url(../img/flag-cn.svg); }
.lang-switch[data-mode="gloss"] .lang-flag--current { background-image: url(../img/flag-split.svg); }
.lang-switch[data-mode="en"]    .lang-flag--current { background-image: url(../img/flag-uk.svg); }

.lang-switch { position: relative; flex-shrink: 0; }
.lang-switch-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border: 0;
  border-radius: 0.375rem;
  background: transparent;
  cursor: pointer;
  transition: background-color 0.15s ease;
}
.lang-switch-trigger:hover { background: rgba(255, 255, 255, 0.1); }
.lang-switch-trigger:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px rgba(34, 211, 238, 0.6);
}
.lang-switch-menu {
  position: absolute;
  top: calc(100% + 0.4rem);
  left: 0;
  z-index: 50;
  min-width: 11rem;
  max-width: calc(100vw - 2rem);   /* never overflow a narrow phone viewport */
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.35rem;
  border-radius: 0.7rem;
  background: rgba(6, 14, 30, 0.97);
  border: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: 0 18px 40px -12px rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(10px);
}
.lang-switch-menu[hidden] { display: none; }
.lang-switch-opt {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  padding: 0.4rem 0.55rem;
  border: 0;
  border-radius: 0.45rem;
  background: transparent;
  color: rgb(203, 213, 225);
  font-size: 0.9rem;
  text-align: left;
  cursor: pointer;
  transition: background-color 0.12s ease;
}
.lang-switch-opt:hover,
.lang-switch-opt:focus-visible {
  outline: none;
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
}
.lang-switch-label { white-space: nowrap; }
/* Show only the two OTHER flags — hide the current mode's option from the menu. */
.lang-switch[data-mode="zh"]    .lang-switch-opt[data-mode="zh"],
.lang-switch[data-mode="gloss"] .lang-switch-opt[data-mode="gloss"],
.lang-switch[data-mode="en"]    .lang-switch-opt[data-mode="en"] { display: none; }


/* ===== 02-auth-gate.css ===== */
/* ─── Site access gate (login modal) ─────────────────────────────────────── */
body.site-auth-locked {
  overflow: hidden;
}

.site-auth-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(1, 4, 14, 0.72);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

/* The grade gate shows/hides itself by toggling the `hidden` class. Tailwind's
   `.hidden { display: none }` is lower-priority than this unlayered `display: flex`
   (it sits in @layer utilities / earlier in app.bundle.css), so a bare `.hidden`
   can NOT override the rule above — the overlay would render on page load and
   `hideGate()` couldn't dismiss it. This higher-specificity rule (matched in this
   same file, so cascade-order-independent) guarantees `hidden` wins. */
.site-auth-overlay.hidden {
  display: none;
}

.site-auth-panel {
  width: 100%;
  max-width: 22rem;
  border-color: rgba(56, 189, 248, 0.18) !important;
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.05) inset,
    0 1px 0 rgba(255, 255, 255, 0.06) inset,
    0 28px 64px -12px rgba(0, 0, 0, 0.55),
    0 0 48px -10px rgba(34, 211, 238, 0.14) !important;
}

/* Exam library: compact year / session rails */
.lib-year-group {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.lib-session-group {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

/* minmax(0, …) on EVERY breakpoint, including this single-column base. A bare `1fr` is
   minmax(auto, 1fr), whose auto floor is the widest card's min-content — and a card is a
   nowrap flex row, so Chrome folds its `flex: 1 1 0%` title's full text width into that
   intrinsic size even though the title carries min-w-0 + truncate. One long name
   ("Complete pack — exercise sheets …") therefore inflated the track to 410px inside a
   347px column and gave /library 126px of sideways scroll on a phone; the title never
   truncated because it was handed all the room it asked for. The multi-column rules below
   already had minmax(0, …) — the phone default was the one that missed it. */
.lib-session-cards {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.5rem;
}

@media (min-width: 640px) {
  .lib-session-cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .lib-session-cards {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 1280px) {
  .lib-session-cards {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* ANY run of consecutive single-document categories
   of consecutive single-document categories shares ONE row. Each such category
   otherwise costs a header
   line (icon + label + divider) plus one card, so a subject stacked six of them —
   Syllabus, Revision, Checklist, Scheme of work, Exam technique, Course companion — down
   the page for six files.

   Same three rules the pair needed, for the same reasons:
     * `display` sits on :not(.hidden) so a search that empties the row still collapses it;
       a plain `.lib-year-row{display:grid}` would outrank Tailwind's `.hidden` (the
       documented .hidden-vs-component-rule trap).
     * grid-template-columns stays OFF that :not() selector, so the phone default below
       wins by source order instead of losing to the :not() specificity bump.
     * the lone card overrides the 1→4-col card grid, else it shrinks into a quarter cell.
   Column counts track .lib-session-cards so a row of singles lines up with the card grid
   above and below it. */
.lib-year-row {
  grid-template-columns: minmax(0, 1fr);
  gap: 1.5rem;
  align-items: start;
}
.lib-year-row:not(.hidden) { display: grid; }
.lib-year-row > .lib-year-group { min-width: 0; }
.lib-year-row .lib-session-cards { grid-template-columns: minmax(0, 1fr); }

@media (min-width: 640px) {
  .lib-year-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
  .lib-year-row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 1280px) {
  .lib-year-row { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
/* Subject-picker rows: pills wrap onto extra lines so every subject stays
   visible at all times (no horizontal scroll). */
.lib-subject-tab-scroll {
  min-width: 0;
}

/* .lib-subject-tab-row-label lives in 03-core-ui.css with the rest of the
   subject-picker design (it is part of the picker's --tab-rgb category
   system: lane wash + label column + pill tints together). */


/* ===== 03-core-ui.css ===== */
/* ─── Glass panel ────────────────────────────────────────────────────────── */
.glass-panel {
  border: 1px solid rgba(255,255,255,0.07);
  background: linear-gradient(148deg,
    rgba(15, 28, 52, 0.82) 0%,
    rgba(10, 18, 38, 0.58) 100%
  );
  backdrop-filter: blur(28px);
  -webkit-backdrop-filter: blur(28px);
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.04) inset,
    0 1px 0   rgba(255,255,255,0.06) inset,
    0 24px 48px -12px rgba(0,0,0,0.55),
    0  0px 80px -20px rgba(34,211,238,0.10);
}

/* ─── Animated gradient border on form ──────────────────────────────────── */
.form-glow {
  position: relative;
}

.form-glow::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  background: linear-gradient(135deg,
    rgba(34, 211, 238, 0.35),
    rgba(59, 130, 246, 0.22),
    rgba(139, 92, 246, 0.18),
    rgba(34, 211, 238, 0.35)
  );
  background-size: 300% 300%;
  animation: gradient-shift 9s ease infinite;
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
          mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: 0.6;
  pointer-events: none;
}

@keyframes gradient-shift {
  0%, 100% { background-position:   0% 50%; }
  50%       { background-position: 100% 50%; }
}

/* ─── Primary button ─────────────────────────────────────────────────────── */
.btn-space-primary {
  background: linear-gradient(135deg, #22d3ee 0%, #3b82f6 58%, #6366f1 100%);
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.12) inset,
    0 4px 20px -4px rgba(34,211,238,0.45),
    0 10px 28px -6px rgba(59,130,246,0.30);
  transition: transform 0.18s ease, box-shadow 0.18s ease, filter 0.18s ease;
}

.btn-space-primary:hover:not(:disabled) {
  filter: brightness(1.12) saturate(1.1);
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.15) inset,
    0 8px 32px -6px rgba(34,211,238,0.55),
    0 18px 44px -10px rgba(99,102,241,0.38);
  transform: translateY(-2px);
}

.btn-space-primary:active:not(:disabled) {
  transform: translateY(0);
  filter: brightness(1.05);
}

.btn-space-primary:disabled {
  opacity: 0.55;
  filter: grayscale(0.7);
  cursor: not-allowed;
  pointer-events: none;
}

/* ─── Site header nav — pill bar (all non-preview pages) ────────────────── */
body:not(.preview-mode-active) .site-header-nav {
  border-color: rgba(56, 189, 248, 0.12);
  background: linear-gradient(
    180deg,
    rgba(12, 22, 42, 0.5) 0%,
    rgba(8, 14, 32, 0.56) 100%
  );
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.05),
    0 0 0 1px rgba(56, 189, 248, 0.03) inset,
    0 3px 18px -8px rgba(0, 0, 0, 0.38),
    0 0 28px -14px rgba(56, 189, 248, 0.06);
  backdrop-filter: blur(12px) saturate(1.06);
  -webkit-backdrop-filter: blur(12px) saturate(1.06);
}

body:not(.preview-mode-active) .site-header-nav a {
  color: rgb(132 165 196);
  transition: color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
}

/* A nav label is one line, always. English gets this for free — every label is a single
   word, so the flex items cannot shrink below it — but Chinese breaks between ANY two
   characters, so a squeezed pill bar wrapped 编程 into 编/程 and doubled the header's
   height (reported 2026-08-10; the squeeze itself is fixed where the nav is centred, in
   07-header-preview-chrome.css). Stating it here means a label's min-content IS its full
   width, so no future container can break one mid-word again. Also picked up by the
   account pill's label + the login button, which tag themselves .nav-pill-label to
   inherit 12-mobile.css's ≤1200px collapse — both want nowrap too. */
.nav-pill-label {
  white-space: nowrap;
}

body:not(.preview-mode-active) .site-header-nav a:hover {
  color: rgb(203 230 248);
  background: rgba(56, 189, 248, 0.07);
  box-shadow: 0 0 12px -4px rgba(56, 189, 248, 0.12);
}

/* The per-destination nav icon palette lives in 12-mobile.css — it is scoped to the same
   ≤1200px block that reveals the icons, because above it the labels carry the meaning and
   only /english renders a glyph. */

.nav-link-active {
  background: rgba(255,255,255,0.10);
  color: #fff;
}

body:not(.preview-mode-active) .site-header-nav a.nav-link-active {
  color: rgb(226 246 255);
  background: linear-gradient(
    135deg,
    rgba(34, 211, 238, 0.15) 0%,
    rgba(59, 130, 246, 0.11) 100%
  );
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    0 0 0 1px rgba(34, 211, 238, 0.11) inset,
    0 0 14px -4px rgba(34, 211, 238, 0.12);
}

/* ─── Tab pills (dashboard + library subject picker) ─────────────────────────
   .tab-active is the ONE active-pill class. The dashboard renders it as-is
   (site-accent cyan). In the library picker the #lib-controls rules further
   down override its background/text/shadow with values derived from the row's
   --tab-rgb category hue — the per-colour .tab-active-<name> variants left
   with the old per-subject colour scheme. */
.tab-active {
  background: linear-gradient(135deg, rgba(34,211,238,0.22), rgba(59,130,246,0.28));
  color: rgb(207 250 254);
  box-shadow: 0 0 0 1px rgba(34,211,238,0.28) inset;
  transition: all 0.2s ease;
}


.tab-btn {
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(34, 211, 238, 0.15);
}

.tab-inactive {
  color: rgb(148 163 184);
  transition: all 0.2s ease;
}

.tab-inactive:hover {
  color: rgb(226 232 240);
  background: rgba(255,255,255,0.07);
}

/* ─── Library subject picker (library.html #lib-controls) ─────────────────
   Four qualification-level rows (IGCSE / A-Level / AP / Morning Reading),
   each a colour-coded "lane": the row div sets --tab-rgb (its category hue)
   and everything inside inherits it — lane wash, label, dot, pill tint,
   active glow, focus ring. Scoped to #lib-controls so the dashboard / PDF
   tab bars, which share .tab-btn/.tab-inactive, keep their neutral look. */

/* Give the picker room: on wide screens extend it rightward out of the centred
   max-w-5xl (64rem) reading column into the page's right gutter — the left edge
   stays aligned with the rest of the page, only the right grows — so more pills
   fit per line before wrapping. The extension is clamped to the available gutter
   (up to 16rem) and always leaves ≥2.5rem, so the page never scrolls sideways. */
@media (min-width: 1024px) {
  #lib-controls {
    width: calc(100% + max(0rem, min(16rem, (100vw - 64rem) / 2 - 1rem)));
  }
}

#lib-controls .lib-subject-tab-row {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.3rem 0.4rem;
  border-radius: 0.75rem;
  background: linear-gradient(90deg,
      rgba(var(--tab-rgb, 148, 163, 184), 0.10),
      rgba(var(--tab-rgb, 148, 163, 184), 0.032) 30%,
      rgba(var(--tab-rgb, 148, 163, 184), 0.013) 55%,
      transparent 80%);
}

/* Fixed right-aligned label column, so all four tab strips start on one
   vertical line ("Morning Reading" wraps to two balanced lines by design). */
#lib-controls .lib-subject-tab-row-label {
  flex-shrink: 0;
  width: 6.5rem;
  text-align: right;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-wrap: balance;
  /* Category hue (inherited --tab-rgb), softened toward slate so it reads as
     a refined tint rather than a vivid colour. Falls back to slate. */
  color: rgb(148 163 184);
  color: color-mix(in srgb, rgb(var(--tab-rgb, 148 163 184)) 85%, rgb(148 163 184));
}

/* Inactive pills: a whisper of the category hue + a hairline ring; the active
   pill still dominates via its stronger .tab-active-* gradient. */
#lib-controls .tab-inactive {
  color: rgb(203 213 225);
  color: color-mix(in srgb, rgb(var(--tab-rgb, 148 163 184)) 14%, rgb(203 213 225));
  background: rgba(var(--tab-rgb, 148, 163, 184), 0.06);
  box-shadow: inset 0 0 0 1px rgba(var(--tab-rgb, 148, 163, 184), 0.17);
}

#lib-controls .tab-inactive:hover {
  color: rgb(241 245 249);
  color: color-mix(in srgb, rgb(var(--tab-rgb, 148 163 184)) 10%, rgb(241 245 249));
  background: rgba(var(--tab-rgb, 148, 163, 184), 0.13);
  box-shadow: inset 0 0 0 1px rgba(var(--tab-rgb, 148, 163, 184), 0.30);
}

/* The dot on each tab: solid category hue with a soft glow. */
#lib-controls .tab-dot {
  background: rgb(var(--tab-rgb, 148, 163, 184));
  box-shadow: 0 0 7px rgba(var(--tab-rgb, 148, 163, 184), 0.55);
}

/* Active pill: the full look — glassy category-hue gradient, near-white text
   tinted toward the hue, hairline ring, top highlight, soft lift glow — all
   from --tab-rgb. Out-specifies the base .tab-active, which stays cyan for
   the dashboard. */
#lib-controls .tab-btn[class*="tab-active"] {
  background: linear-gradient(160deg,
      rgba(var(--tab-rgb, 148, 163, 184), 0.32),
      rgba(var(--tab-rgb, 148, 163, 184), 0.16) 58%,
      rgba(var(--tab-rgb, 148, 163, 184), 0.24));
  color: rgb(241 245 249);
  color: color-mix(in srgb, rgb(var(--tab-rgb, 148 163 184)) 22%, white);
  box-shadow: inset 0 0 0 1px rgba(var(--tab-rgb, 148, 163, 184), 0.35),
      inset 0 1px 0 rgba(255, 255, 255, 0.10),
      0 4px 16px -8px rgba(var(--tab-rgb, 148, 163, 184), 0.60);
}

#lib-controls .tab-btn:focus-visible {
  outline: 2px solid rgba(var(--tab-rgb, 148, 163, 184), 0.65);
  outline-offset: 1px;
}

/* Small screens: stack the label above its tab strip so pills get the full
   row width (the inline label column would eat a third of a phone screen). */
@media (max-width: 639.98px) {
  #lib-controls .lib-subject-tab-row {
    flex-direction: column;
    align-items: stretch;
    gap: 0.35rem;
    padding: 0.4rem;
  }

  #lib-controls .lib-subject-tab-row-label {
    width: auto;
    text-align: left;
    padding-left: 0.35rem;
  }
}

/* ─── Library cards ──────────────────────────────────────────────────────── */
.lib-card {
  cursor: pointer;
  touch-action: manipulation;   /* eliminates 300 ms tap delay on iOS/Android */
  transition: transform 0.18s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}

.lib-card:hover {
  transform: translateY(-2px);
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.07) inset,
    0 12px 24px -6px rgba(0,0,0,0.35),
    0  0px 40px -10px rgba(34,211,238,0.09);
}

/* ─── "Continue where you left off" card (partials/resume.html) ──────────────
   The macro renders the card with the `hidden` attribute and resume.js removes it only
   once GET /api/resume actually returns something. But the card carries Tailwind's
   `flex` utility, whose `display: flex` BEATS the UA sheet's `[hidden] { display: none }`
   — so a visitor with no history saw an empty 78px "CONTINUE WHERE YOU LEFT OFF" row on
   /learn and /code (and now / , which reuses the macro). Make `hidden` authoritative,
   exactly as 13-account.css has to for the header chips, guest score and feedback badge.
   Bundled (not page-scoped) so it covers every current and future user of the macro. */
[data-resume-card][hidden] { display: none; }

/* ─── Shared page hero (.site-hero) ──────────────────────────────────────────
   ONE source of truth for the Learn / Practice / Code / Library heroes (Jinja
   macro: web/templates/partials/hero.html). Structure + animation are shared;
   colour is driven by per-accent CSS vars. The cyan defaults reproduce the
   original .learn-hero exactly (incl. the two-hue cyan→blue icon tile). This block
   lives in the bundle so EVERY page — including ones that don't load 06-landing.css
   (Library, Code) — gets the styling AND the keyframes below (the keyframes used to
   live only in the page-scoped 06-landing.css, which is why Library's shimmer/
   entrance were silently dead). */
@keyframes float {
  0%, 100% { transform: translateY(  0px); }
  50%      { transform: translateY( -7px); }
}
@keyframes title-shimmer {
  0%   { background-position: 0% 50%; }
  100% { background-position: 100% 50%; }
}
@keyframes hero-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes hero-in-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Per-accent palette. --hero: primary (-400); --hero2: icon-tile 2nd hue (-500);
   --glyph: icon glyph (-200); --ht1/2/3: the three -300 title-gradient stops.
   --ht4/5 extend the same -300 ramp for CHIP DOTS only (the title still uses 1-3), so a
   hero with four or five bullets gives each its own colour instead of repeating. Each
   ramp stays inside its own cool family — see the landing-page palette rule. */
.site-hero          { --hero: 34,211,238;  --hero2: 59,130,246;  --glyph: 165,243,252;
                      --ht1: 103,232,249;  --ht2: 147,197,253;   --ht3: 165,180,252;
                      --ht4: 196,181,253;  --ht5: 240,171,252;   --ht6: 110,231,183;
                      --ht7: 249,168,212;  --ht8:  94,234,212; }                          /* cyan (Learn) */
.site-hero--emerald { --hero: 52,211,153;  --hero2: 20,184,166;  --glyph: 167,243,208;
                      --ht1: 110,231,183;  --ht2: 94,234,212;    --ht3: 103,232,249;
                      --ht4: 147,197,253;  --ht5: 165,180,252;   --ht6: 196,181,253;
                      --ht7: 240,171,252;  --ht8: 249,168,212; }
.site-hero--sky     { --hero: 56,189,248;  --hero2: 59,130,246;  --glyph: 186,230,253;
                      --ht1: 125,211,252;  --ht2: 147,197,253;   --ht3: 165,180,252;
                      --ht4: 196,181,253;  --ht5: 240,171,252;   --ht6: 110,231,183;
                      --ht7: 249,168,212;  --ht8:  94,234,212; }
.site-hero--violet  { --hero: 167,139,250; --hero2: 168,85,247;  --glyph: 221,214,254;
                      --ht1: 196,181,253;  --ht2: 216,180,254;   --ht3: 165,180,252;
                      --ht4: 147,197,253;  --ht5: 103,232,249;   --ht6: 110,231,183;
                      --ht7: 249,168,212;  --ht8:  94,234,212; }

.site-hero-icon {
  background: linear-gradient(135deg, rgba(var(--hero), 0.22), rgba(var(--hero2), 0.22));
  box-shadow: 0 0 0 1px rgba(var(--hero), 0.30), 0 0 14px -2px rgba(var(--hero), 0.42);
  animation: float 7s ease-in-out infinite;
}
.site-hero-icon svg { color: rgb(var(--glyph)); }

.site-hero-eyebrow {
  color: rgba(var(--hero), 0.75);
  text-shadow: 0 0 18px rgba(var(--hero), 0.45), 0 0 36px rgba(var(--hero), 0.20);
}

.site-hero-title {
  background: linear-gradient(to right, rgb(var(--ht1)), rgb(var(--ht2)), rgb(var(--ht3)));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  background-size: 200% 200%;
  filter: drop-shadow(0 0 22px rgba(var(--hero), 0.20));
  animation: title-shimmer 8s ease-in-out infinite alternate;
}

.site-hero-subtitle { text-shadow: 0 0 28px rgba(var(--hero), 0.12); }

/* Balanced title wrap: a two-line hero title breaks evenly ("Learn IGCSE, A-Level /
   and AP subjects") instead of orphaning its last word. Progressive — browsers without
   text-wrap support simply keep today's greedy wrap. `pretty` on the subtitle likewise
   only prevents single-word orphans. */
.site-hero h1 { text-wrap: balance; }
.site-hero-subtitle { text-wrap: pretty; }

/* One colour per chip, up to five; a sixth and beyond cycle back. Dots used to reuse the
   title gradient's three stops, so a hero passing a fourth chip rendered a dot with NO
   background — invisible, silent, and noticeable only as one bullet in a list missing its
   marker (the landing page hit exactly this). */
/* One colour per chip, up to eight. The BASE rule matters as much as the overrides: dots
   used to be enumerated 1-3 only, so a hero passing a fourth chip rendered a dot with no
   background at all — invisible, silent, and noticeable only as one bullet in a list
   missing its marker. Now any index gets a colour and the numbered rules just refine it.
   `color` as well as `background`, so a dot can glow in its own hue via currentColor. */
.site-hero-chips [class^="site-hero-dot-"] { background: rgb(var(--ht1)); color: rgb(var(--ht1)); }
.site-hero-chips .site-hero-dot-2 { background: rgb(var(--ht2)); color: rgb(var(--ht2)); }
.site-hero-chips .site-hero-dot-3 { background: rgb(var(--ht3)); color: rgb(var(--ht3)); }
.site-hero-chips .site-hero-dot-4 { background: rgb(var(--ht4)); color: rgb(var(--ht4)); }
.site-hero-chips .site-hero-dot-5 { background: rgb(var(--ht5)); color: rgb(var(--ht5)); }
.site-hero-chips .site-hero-dot-6 { background: rgb(var(--ht6)); color: rgb(var(--ht6)); }
.site-hero-chips .site-hero-dot-7 { background: rgb(var(--ht7)); color: rgb(var(--ht7)); }
.site-hero-chips .site-hero-dot-8 { background: rgb(var(--ht8)); color: rgb(var(--ht8)); }

/* Pause shimmer + float in a backgrounded tab. */
html.doc-background-paused .site-hero-icon,
html.doc-background-paused .site-hero-title { animation-play-state: paused; }

/* Staggered page-load entrance. Shimmer is on .site-hero-title (the span); the
   entrance translates the parent <h1> — different elements, so they never collide. */
body:not(.page-entered) .site-hero-icon,
body:not(.page-entered) .site-hero-eyebrow  { animation: hero-in 0.28s ease   0ms both; }
body:not(.page-entered) .site-hero h1       { animation: hero-in 0.28s ease  80ms both; }
body:not(.page-entered) .site-hero-subtitle { animation: hero-in 0.28s ease 160ms both; }
body:not(.page-entered) .site-hero-chips    { animation: hero-in 0.28s ease 240ms both; }

/* Library only: the controls + first subject grid sit below the hero and continue
   the same cascade (the hero itself is .site-hero, handled above). */
body:not(.page-entered) #lib-controls { animation: hero-in 0.28s ease 300ms both; }
body:not(.page-entered) #grid-physics { animation: hero-in 0.28s ease 360ms both; }

/* ─── Helper drawer rendered markdown content ───────────────────────────── */
/* Server renders cached <kind>.md to HTML; this block styles the result.
   Use em (not rem) so headings/lists scale with the drawer's base font size
   (practice page = text-base, test page = text-sm). */
.ex-helper-body {
  padding: 0.85rem 1rem;
}
.ex-helper-body > :first-child { margin-top: 0; }
.ex-helper-body > :last-child  { margin-bottom: 0; }

/* H1 included for backward-compat with cached "# Topic" helpers that pre-date
   the prompt update; visually identical to H2. */
.ex-helper-body h1,
.ex-helper-body h2 {
  font-family: 'Sora', 'Outfit', system-ui, sans-serif;
  font-size: 1.05em;
  font-weight: 600;
  color: rgb(241, 245, 249);   /* slate-100 */
  margin: 1em 0 0.4em;
}
.ex-helper-body h3 {
  font-size: 0.78em;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgb(148, 163, 184);   /* slate-400 */
  margin: 0.9em 0 0.3em;
}
.ex-helper-body p {
  margin: 0.45rem 0;
  line-height: 1.65;
}
.ex-helper-body ul,
.ex-helper-body ol {
  margin: 0.4rem 0;
  padding-left: 1.25rem;
}
.ex-helper-body ul { list-style: disc; }
.ex-helper-body ol { list-style: decimal; font-variant-numeric: tabular-nums; }
.ex-helper-body li { margin: 0.18rem 0; line-height: 1.5; }
.ex-helper-body strong {
  color: rgb(248, 250, 252);   /* slate-50 — lift from body slate-200 */
  font-weight: 600;
}
.ex-helper-body em {
  color: rgb(226, 232, 240);   /* slate-200 */
  font-style: italic;
}
.ex-helper-body code {
  background: rgba(255, 255, 255, 0.05);
  padding: 0.05rem 0.3rem;
  border-radius: 0.25rem;
  color: rgb(165, 243, 252);   /* cyan-200 */
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85em;
}
.ex-helper-body pre {
  background: rgba(2, 6, 23, 0.6);
  border-radius: 0.5rem;
  padding: 0.7rem 0.9rem;
  overflow-x: auto;
  margin: 0.6rem 0;
}
.ex-helper-body pre code {
  background: transparent;
  padding: 0;
  color: inherit;
  font-size: 0.85em;
}
.ex-helper-body blockquote {
  border-left: 2px solid rgba(34, 211, 238, 0.4);
  padding-left: 0.7rem;
  margin: 0.5rem 0;
  color: rgb(203, 213, 225);   /* slate-300 */
}
.ex-helper-body hr {
  border: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  margin: 0.9rem 0;
}
/* Display math (KaTeX renders inside this wrapper from dollarmath) */
.ex-helper-body .math.block {
  margin: 0.7rem 0;
  overflow-x: auto;
}

/* KaTeX auto-render display math (learn / know / reference / practice). A long
   equation must scroll within its column, not widen the whole page on a phone —
   the classic mobile horizontal-scroll bug. Global (bundled) so every math page
   is covered; KaTeX's own .katex-display sets no overflow, so there's no
   conflict. overflow-y stays hidden so the scrollbar can't clip tall fractions. */
.katex-display {
  overflow-x: auto;
  overflow-y: hidden;
  padding-block: 0.25rem;   /* keep the scrollbar off the glyphs */
}


/* ═══ Collapsed page copy (partials/prose_fold.html) ═══════════════════════════════
   MOVED HERE from the page-scoped 06-landing.css (2026-08-27). It is a SHARED
   component — /know subject+topic pages, /library/<subject>, and now the /library and
   /code subject/course indexes all render it — but 06-landing.css is loaded only via
   {% block extra_head %} on the landing-ish pages, so on /library and /code the markup
   arrived completely unstyled (a raw browser disclosure triangle). 03-core-ui.css is
   bundled into app.bundle.css, which every page loads, so the component now follows its
   markup everywhere. Keep it here; do not copy it back into a page sheet.
   ══════════════════════════════════════════════════════════════════════════════════ */
/* ─── Collapsed page copy (partials/prose_fold.html) ──────────────────────────────
   One near-invisible line instead of two-to-three paragraphs in the reading flow. Used by
   the /know and /learn landings and every /know/<subject> page.

   NO box, border, fill or icon (user steer, 2026-08-02): the copy is there for search and
   for the rare reader who wants it, so its handle should cost the page nothing. It is a
   small muted line the eye skips, which brightens on hover and takes a visible focus ring
   on keyboard focus — unobtrusive, not undiscoverable.

   ⚠️ COLLAPSED, never CSS-hidden. Text hidden from readers but served to crawlers is
   named in Google's spam policies as "hidden text" and risks a site-wide demotion; a
   <details> is the sanctioned pattern and is indexed at full weight under mobile-first
   indexing. Do not "simplify" this to display:none, visibility:hidden, or an off-screen
   position — the visual result would look the same and the consequence would not. */
.prose-fold {
  margin: -0.25rem 0 1.25rem;
  max-width: 42rem;
}
.prose-fold-summary {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  cursor: pointer;
  padding: 0.125rem 0;
  list-style: none;
  user-select: none;
  font-size: 0.75rem;
  font-weight: 400;
  color: rgb(71, 85, 105);
  transition: color 0.15s ease;
}
.prose-fold-summary::-webkit-details-marker { display: none; }
.prose-fold-summary:hover { color: rgb(148, 163, 184); }
.prose-fold-summary:focus-visible {
  outline: 2px solid rgba(56, 189, 248, 0.7);
  outline-offset: 3px;
  border-radius: 0.25rem;
  color: rgb(203, 213, 225);
}
.prose-fold-chevron {
  width: 0.75rem; height: 0.75rem;
  flex: none;
  opacity: 0.7;
  transition: transform 0.18s ease;
}
.prose-fold[open] > .prose-fold-summary .prose-fold-chevron { transform: rotate(90deg); }
/* The HANDLE is near-invisible; the CONTENT is not. Once a reader has chosen to open it
   they are reading, so this is body copy at the site's normal reading size, not the 13px
   footnote it was. `**key term**` in the source becomes <strong> (web/templating.py:
   bold_marks) so the paragraphs can be skimmed rather than only read.

   Opened, the copy sits in the SAME dark content box the handout body uses further down
   this very page (.learn-content-body above: rgb(3,9,26) + rounded-xl + a hairline
   border, `p-4 sm:p-5`). The page background is a textured aurora, so paragraphs laid
   straight onto it read worse than every other block of content here; reusing that box
   makes the panel look native rather than like a one-off inset. Typography stays sans —
   only the surface is borrowed, not .learn-content-body's serif. */
.prose-fold-body {
  margin-top: 0.5rem;
  padding: 1rem;
  border-radius: 0.75rem;
  border: 1px solid rgba(255, 255, 255, 0.06);
  background-color: rgb(3, 9, 26);
}
@media (min-width: 640px) { .prose-fold-body { padding: 1.25rem; } }
.prose-fold-body p {
  max-width: 62ch;
  font-size: 0.9375rem;
  line-height: 1.75;
  color: rgb(203, 213, 225);
}
.prose-fold-body p + p { margin-top: 0.75rem; }

/* The /library subject index (library.html) — a link list inside a prose-fold rather
   than the macro's paragraphs, so it needs its own list reset. Multi-column so 36
   subjects stay one glance rather than a long scroll. */
.lib-subject-index-list {
  columns: 2;
  column-gap: 2rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
@media (min-width: 640px) { .lib-subject-index-list { columns: 3; } }
.lib-subject-index-list li { break-inside: avoid; margin-bottom: 0.35rem; }
.lib-subject-index-list a {
  font-size: 0.9375rem;
  line-height: 1.6;
  color: rgb(203, 213, 225);
  text-decoration: none;
}
.lib-subject-index-list a:hover { color: #fff; text-decoration: underline; }
.prose-fold-body strong {
  font-weight: 600;
  color: #fff;
}

@media (prefers-reduced-motion: reduce) {
  .prose-fold-summary, .prose-fold-chevron { transition: none; }
}

/* ===== 07-header-preview-chrome.css ===== */
/* ─── Site header (glass); PDF tabs share 2-col grid with main preview layout ─ */
/* --header-glass-fill: 1 at PDF scroll top, lower while scrolling (set from index.html) */
.site-header {
  position: relative;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  background: transparent;
  backdrop-filter: blur(10px) saturate(1.1);
  -webkit-backdrop-filter: blur(10px) saturate(1.1);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.04);
  /* Safe area (iOS viewport-fit=cover): the frosted bar extends up under the
     Dynamic Island / notch and clears the rounded corners in landscape. Resolves
     to 0 on non-notched / desktop. Keep in sync with --preview-sticky-top, which
     adds the same top inset so the Library/PDF/overview panes stay aligned. */
  padding-top: env(safe-area-inset-top, 0px);
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
}

.site-header::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(8, 14, 30, 0.58) 0%,
    rgba(8, 14, 30, 0.42) 55%,
    rgba(8, 14, 30, 0.35) 100%
  );
  opacity: var(--header-glass-fill, 1);
  transition: opacity 0.35s ease;
}

.site-header-inner {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 1rem;
}

/* Wraps the brand link + language flag so the grid sees one cell, not two */
.site-header-brand-area {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  min-width: 0;
}

/* Header wordmark: single line by default; stacked eyebrow + title in PDF preview */
.site-header-brand-stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15rem;
  line-height: 1.15;
}

.site-header-brand-eyebrow {
  display: none;
  font-size: 0.52rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(125, 211, 252, 0.78);
  line-height: 1;
  text-shadow: 0 0 20px rgba(56, 189, 248, 0.35);
}

.site-header-brand-titles {
  display: block;
}

.site-header-brand-title {
  font-weight: 700;
  letter-spacing: -0.02em;
}

.site-header-brand-title--default {
  display: inline-block;
}

/* The wordmark is authored as two spans ("IGCSE, A-Level" + "& AP") so phones can
   stack it at a CHOSEN break (they go display:block down there) instead of wrapping
   wherever the gutter happens to run out. Inline everywhere else — the newline
   between them in base.html is the space that joins them into one line. */
.site-header-brand-line {
  white-space: nowrap;
}

.site-header-brand-title--preview {
  display: none;
  font-size: 1.0625rem;
  filter: drop-shadow(0 0 16px rgba(56, 189, 248, 0.28));
}

@media (min-width: 640px) {
  .site-header-brand-title--preview {
    font-size: 1.1875rem;
  }
}

body.preview-mode-active:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-brand-eyebrow {
  display: block;
}

body.preview-mode-active:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-brand-title--default {
  display: none;
}

body.preview-mode-active:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-brand-title--preview {
  display: inline-block;
}

/* Wordmark block centered over the left column; text left-aligned inside the block */
body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-brand-area {
  display: flex;
  justify-content: center;
  align-items: center;
  justify-self: stretch;
  width: 100%;
  min-width: 0;
}

body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-brand-stack {
  align-items: flex-start;
  text-align: left;
  width: max-content;
  max-width: 100%;
}

/* ─── Pinned brand wordmark (non-preview) ──────────────────────────────── */
/* Outside preview mode, the brand link lives twice in the DOM (see base.html):
   once here inside <header>, once as a body-level `.site-header-brand--pinned`
   duplicate fixed to the viewport's top-left corner (mirrors the account
   pill's top-right treatment in 13-account.css — same insets, opposite edge).
   Each copy is shown in exactly one mode, so only one wordmark ever renders:
   preview mode needs the in-header copy for its own grid-column layout
   (rules above), so hide the pinned copy there; everywhere else, hide the
   in-header copy so its sibling .lang-switch — the only flex child left in
   .site-header-brand-area — slides to the start of that area, i.e. roughly
   the spot the brand link used to occupy. */
body.preview-mode-active .site-header-brand--pinned {
  display: none;
}

body:not(.preview-mode-active) .site-header-inner .site-header-brand {
  display: none;
}

.site-header-brand--pinned {
  position: fixed;
  top: calc(1rem + env(safe-area-inset-top, 0px));
  left: calc(1rem + env(safe-area-inset-left, 0px));
  z-index: 60;
}

/* Two-row header band (the reflow lower down): row 1 carries only the language flag
   and the search button, both 2.5rem touch targets. The pinned brand is
   `position: fixed`, so the flex row it visually belongs to cannot centre it —
   align it by hand instead: start at that row's own content-box top (the header's
   safe-area padding + .site-header-inner's 0.625rem) and give the brand the same
   2.5rem height with its text centred inside. Both centres then land on the same y,
   whether the wordmark is one line or the two it stacks into on phones. */
@media (max-width: 767px) {
  .site-header-brand--pinned {
    /* `absolute`, not `fixed`, on phones. The wordmark is pinned to a VIEWPORT corner so
       it survives the header's layout changes — which is right on desktop, where it floats
       over the wide centring gutters. A phone has no gutters: the reading column runs edge
       to edge, and .site-header is `position: relative` (the rule at the top of this file
       beats the template's `sticky` utility, which loads earlier), so the header scrolls
       away and left the wordmark sitting on top of the content — measured 70px across the
       first card's title on /eXam/practice. Anchoring to the document instead makes it
       scroll away WITH the header it visually belongs to; body is `position: static`, so
       these offsets resolve against the initial containing block and the at-rest position
       is pixel-identical. The account chip gets the same treatment in 13-account.css. */
    position: absolute;
    top: calc(0.625rem + env(safe-area-inset-top, 0px));
    min-height: 2.5rem;
    display: flex;
    align-items: center;
  }
}

@media (max-width: 640px) {
  .site-header-brand--pinned {
    left: calc(0.85rem + env(safe-area-inset-left, 0px));
  }
}

/* Stack the wordmark rather than shrink it, everywhere the header is laid out
   against reserved gutters rather than the centred content column. Measured at
   this font size: "IGCSE, A-Level & AP" is 178px on one line, which runs past
   the 10.5rem the gutter reserves (see below) and out over the language flag;
   stacked onto its two authored lines it is 133px, which that reservation
   clears with room to spare. ≥1024px the gutter is widened instead so desktop
   keeps a single-line wordmark. */
@media (max-width: 1023px) {
  .site-header-brand--pinned .site-header-brand-line {
    display: block;
  }
}

/* ─── Reserving the two fixed corners ────────────────────────────────────────
   The pinned brand (left) and the account slot (right, 13-account.css) are
   `position: fixed` to the VIEWPORT corners, while the header's own content sits in a
   centred `max-w-5xl` column. That only works while the centring gutters are wider than
   the widgets — and measured, they are not below **1315px**: at 1280 the brand covered
   the language switcher by 9px and the account slot covered the search button by 9px, and
   it got worse as the viewport narrowed (40px / 36px by 1023px, where the account slot
   also sat on top of 42px of the icon nav — i.e. the search button was unclickable
   anywhere from 640px to 1314px).

   Fix: below that width stop centring the header (it no longer needs to line up with the
   content column once the gutters are gone) and reserve the corners as padding instead, so
   flex lays the header's own children out inside what's left. The reserved widths are
   measured, not guessed: the brand is 149px at its 16px inset (→ 10.5rem clears it) and
   the account slot is 145px logged out but up to 272px with a long @username, so the name
   cap is tightened to 4rem in 13-account.css to keep it inside 12rem.

   Scoped to :not(.preview-mode-active) throughout: preview mode shows the IN-HEADER brand
   (the pinned copy is hidden there) and lays the header out as its own grid, so it needs
   neither the left reservation nor the un-capping. */
@media (max-width: 1650px) {
  body:not(.preview-mode-active) .site-header-inner {
    max-width: none;
    padding-left: 10.5rem;   /* stacked brand ends at 165px; +3px breathing room */
    padding-right: 12rem;
  }
}

/* ≥1024px the wordmark is a single line (the stacking rule above stops at 1023px), which
   measures 178px → 194px from the viewport edge, i.e. past the 10.5rem above and over the
   language flag. Widen the reservation for that band only: the flag is the sole header
   child the left padding moves here (the nav is absolutely centred and the search button
   is pinned to the header's top-right — see the "Centered nav" block at the end of this
   file), so there is nothing to squeeze. Below 1024px the row IS packed — at 768px it
   already has no slack — which is why that band stacks the wordmark instead. */
@media (min-width: 1024px) and (max-width: 1650px) {
  body:not(.preview-mode-active) .site-header-inner {
    padding-left: 12.75rem;   /* pinned brand ends at 194px; +10px breathing room */
  }
}

/* NB: ≥1024px the nav and the search button are absolutely positioned against
   .site-header-inner (the "Centered nav" block at the end of this file), so the padding
   above does NOT move them — an abspos box is laid out against the padding box. Their
   offsets are corrected for this band down there, where the rules they override live. */

.site-header-preview-col {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  margin-left: auto;
  flex: 1 1 auto;
  min-width: 0;
  position: relative;
  gap: 0.75rem;
}

/* Just above the mobile breakpoint the row is 3px SHORT, and because the column is
   justify-content: flex-end that deficit overflows LEFTWARDS — the nav pill's rounded
   left edge lands on top of the language flag's 40px touch target and eats its rightmost
   3px (measured at 768px, i.e. iPad portrait; the flag's centre still clicks, but its
   right edge hit-tests to the nav). Flex overflow is silent, which is why the band read
   as "no slack" rather than as a collision. Reclaim the deficit in that band only by
   tightening the nav↔search gap; ≥1024px the nav is absolutely centred and unaffected. */
@media (min-width: 768px) and (max-width: 1023px) {
  body:not(.preview-mode-active) .site-header-preview-col {
    gap: 0.5rem;
  }
}

.site-header-middle {
  display: none;
  flex: 1 1 auto;
  min-width: 0;
  align-items: center;
  justify-content: center;
}

.site-header-middle:has(#pdf-tab-bar-wrap:not([hidden])) {
  display: flex;
}

/* ─── Sheet preview: the header carries the PDF tabs, not the site chrome ─────
   The generated-sheet preview hands the header's right-hand side to the PDF tab bar
   (back · Ranking · sheet/layout/mark-scheme), which leaves no room for the controls
   that live there on every other page — so they are hidden for the duration.

   The nav pill bar is the one that was REPORTED (2026-08-10): below 1024px it shares
   row 1 with the account pill, and that pill is a VIEWPORT corner widget (fixed, z-60,
   13-account.css) — measured at 1014px it sat 44px INTO the nav, i.e. Generate/Grade
   were unclickable; ≥1024px the nav instead floats over the right end of the tab-bar
   row. Hiding it rather than re-fitting it is the user's call and the right one: the
   preview is a focused document view you enter from /generate and leave with the ←
   button (or Backspace), so it doesn't need eight links to other sections mid-render.
   The header drops a whole row this way — 182px → 131px at 1014px — which the PDF gets.

   The search button and the admin feedback badge go with it, because they are already
   in the same trap and hiding them is what keeps the fix from just moving the collision:
   they sit AFTER the nav in the flex/grid flow, so ≥1024px they end up underneath the
   account pill (invisible and unclickable today), and below it they were pushed onto a
   third header row — the stray magnifier under the ← button. Pinning them instead needs
   a measured gutter that tracks the pill's four widths AND still clears the centred tab
   track; probed at 1201px that leaves ~15px, i.e. the next header change re-opens this
   bug. Ctrl/⌘-K still opens search here (search.js binds it on document).

   The nav's own preview-mode styling in 08-workspace-pdf-preview.css is now inert; it is
   left in place so re-enabling the nav wouldn't have to re-derive the look. */
body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-nav,
body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) .site-search-btn,
body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-feedback-badge {
  display: none;
}

@media (min-width: 1024px) {
  body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) {
    display: grid;
    grid-template-columns: minmax(0, 19rem) minmax(0, 1fr);
    gap: 1rem;
    align-items: center;
  }

  body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-brand-area {
    grid-column: 1;
  }

  body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-preview-col {
    grid-column: 2;
    position: relative;   /* containing block for anything pinned inside the column */
    margin-left: 0;
    flex: unset;
    width: 100%;
    min-width: 0;
    min-height: 2.75rem;
    display: flex;
    align-items: center;
  }

  /* Middle stretches across the full preview column so the tab track centres
     over the PDF pane, not just the space left after the nav. */
  body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-middle {
    flex: 1 1 0;
    display: flex;
    align-items: center;
    min-width: 0;
    width: 100%;
  }
}

@media (max-width: 1023px) {
  /* One column, two rows: wordmark + flag, then the tab bar. It was `1fr auto`, the
     second column being the nav's — now that nothing is placed there it would only
     charge row 1 the column gap for an empty track. */
  body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) {
    display: grid;
    grid-template-columns: 1fr;
    grid-template-rows: auto auto;
    gap: 0.5rem 1rem;
    align-items: center;
  }

  body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-brand-area {
    grid-column: 1;
    grid-row: 1;
  }

  body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-preview-col {
    display: contents;
  }

  /* `display: contents` above dissolves the preview column, so its children become grid
     items in their own right. With the nav hidden that leaves only .site-header-middle,
     placed explicitly below — the search button and the feedback badge would otherwise
     AUTO-place into the cell the nav used to hold, i.e. straight under the fixed account
     pill (measured: search at 943-979 against the pill at 935-987), which is exactly the
     collision being fixed; they are hidden here for that reason (see the block above). */
  body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-middle {
    grid-column: 1 / -1;
    grid-row: 2;
    flex: unset;
    justify-content: stretch;
    width: 100%;
    min-width: 0;
  }
}

/* ─── Mobile header: 2-row layout below 640 px ───
 * The icon-only nav (12-mobile.css, ≤1023px) stays on a single row with the
 * brand from 640–1023px; below 640px the brand and nav start to collide
 * (measured: brand↔nav gap goes negative ~600px), so here we reflow.
 * Row 1: brand + language flag. Row 2: the nav pill bar on its own.
 * (The account slot is `position: fixed` — see 13-account.css — so it's
 * already out of this flow entirely, pinned to the viewport corner.)
 * `.site-header-preview-col` is dissolved with `display: contents` (same trick
 * as the <1024px preview layout above) so its remaining children — the nav —
 * become DIRECT flex items of `.site-header-inner` and can be ordered
 * independently: nav forced to row 2 via a 100% flex-basis. Without this, the
 * centered nav row overflowed past the viewport and clipped the leftmost nav
 * icons.
 * Scoped to non-preview so the preview-mode grid layout is unaffected.   */
/* Raised from 639px to 767px (2026-07-30): with the two fixed corner widgets now reserved
   as gutters (block above), a single-row header no longer has room for the 312px icon nav
   below ~768px — it overflowed leftwards, back under the pinned brand. Dropping the nav to
   its own row is the mechanism this header already used on phones, so it just starts one
   breakpoint earlier. */
@media (max-width: 767px) {
  body:not(.preview-mode-active) .site-header-inner {
    flex-wrap: wrap;
    align-items: center;
    padding-top: 0.625rem;
    padding-bottom: 0.625rem;
    row-gap: 0.5rem;
  }
  body:not(.preview-mode-active) .site-header-inner .site-header-preview-col {
    display: contents;
  }
  body:not(.preview-mode-active) .site-header-inner .site-header-brand-area {
    order: 0;
    min-width: 0;
  }
  body:not(.preview-mode-active) .site-header-inner .site-header-nav {
    order: 2;
    flex-basis: 100%;           /* full width → wraps to its own row */
    justify-content: center;
    flex-wrap: wrap;            /* never-clip fallback on <360px phones */
  }
}

/* Once the nav has its own row, only the language flag and the search button share row 1
   with the two fixed corner widgets — so the right gutter can shrink to the compact
   account pill, and the nav's row should reclaim BOTH gutters rather than sit indented
   inside them (a phone would otherwise wrap 8 icons onto two rows).
   Grow `flex-basis` by exactly the gutters, so the nav's OUTER (margin-box) size stays a
   full line: that is what flexbox wraps on, so it still drops to its own row, and the
   negative margins then pull its border box out to both viewport edges. A plain
   `flex-basis: 100%` plus negative margins makes the outer size SMALLER, so the nav fits
   back on row 1 under the pinned brand — the bug this replaced. (`width` can't do the job:
   flex-basis wins over width for the main size.)
   MUST stay after the reflow block above — same specificity, so source order decides. */
@media (max-width: 767px) {
  body:not(.preview-mode-active) .site-header-inner { padding-right: 8.5rem; }
  body:not(.preview-mode-active) .site-header-inner .site-header-nav {
    margin-left: -10.5rem;
    margin-right: -8.5rem;
    flex-basis: calc(100% + 19rem);   /* 10.5rem + 8.5rem */
  }
}

/* Phones proper: the pinned brand drops to a 0.85rem inset and is 142px wide. */
@media (max-width: 639px) {
  body:not(.preview-mode-active) .site-header-inner { padding-left: 9.25rem; }
  body:not(.preview-mode-active) .site-header-inner .site-header-nav {
    margin-left: -9.25rem;
    flex-basis: calc(100% + 17.75rem);  /* 9.25rem + 8.5rem */
  }
}

/* ─── Preview mode header on portrait phones: wordmark hidden, tabs on row 2 ───
   The wordmark is dropped here (it is the widest thing in the header and the ← button
   already says where you are), leaving row 1 to the language flag alone. The nav used to
   own this row's right end — and at 375px its 302px pill bar ran straight through the
   centred flag — so with it hidden the ≤1023px grid above already lays this row out;
   only the wordmark and the flag's alignment still differ. */
@media (max-width: 479px) {
  body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-brand {
    display: none;
  }
  /* Brand link is hidden above; the wrapper still occupies row 1 so the flag stays
     visible — but that wrapper CENTRES its content (preview brand-area rule near the top
     of this file), which left the lone flag floating mid-row. `justify-self` alone could
     not fix that: the same rule sets `width: 100%`, and a definite width makes a grid
     item fill its area whatever the alignment says — measured, the flag stayed at x=482
     of a 1014px row and only moved to the 24px gutter once the width went back to auto. */
  body.preview-mode-active .site-header-inner:has(#pdf-tab-bar-wrap:not([hidden])) .site-header-brand-area {
    justify-self: start;
    width: auto;
  }
}

/* ─── Centered nav (non-preview, desktop) ──────────────────────────────── */
/* Absolutely positions .site-header-nav at the horizontal center of
   .site-header-inner. Scoped to non-preview pages + lg-and-up so that:
     - preview mode keeps its existing grid (see lines ~134, ~178);
     - <1024 px keeps the right-aligned flex layout (no room to centre
       without brand / nav / account overlapping).
   .site-header-inner is already position: relative (line 28). Overriding
   .site-header-preview-col to position: static lets the absolutely-positioned
   nav anchor to .site-header-inner instead of preview-col, so it centres on
   the full header width — not just the right-hand column. */
@media (min-width: 1024px) {
  body:not(.preview-mode-active) .site-header-preview-col {
    position: static;
  }
  body:not(.preview-mode-active) .site-header-nav {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    /* `width` is NOT decoration here. An abspos box with `left` and no `right`/`width`
       is shrink-to-fit, and shrink-to-fit is clamped to the space left of that offset —
       i.e. HALF the header — so the pill bar was handed 512px of a 1024px container and
       flex-shrank its items to fit. English survives that only by accident: every label
       is one unbreakable word, so min-content ≈ max-content and the box is forced back
       out to the full 657px (measured — the fix moves it 0px). Chinese labels break
       between any two characters, so min-content is ONE character per pill: the box
       stayed at 512, every item shrank, and 编程 wrapped to 编/程 with the header
       doubling to 62px. Teacher/admin only, because the 9th pill (Grade 批改) is what
       pushes zh past the clamp — 556px needed against 512 available. `max-content` sizes
       the box to the bar itself, so the clamp can never squeeze it. */
    width: max-content;
  }

  /* The search button used to sit inline before the account slot, packed by
     .site-header-preview-col's justify-content:flex-end. That group's width is
     dynamic (long @username + score badge + admin feedback badge all widen
     it), and since it's flush-right while the nav above is independently
     centered, a wide account cluster shifts the whole group left into the
     centered nav's rightmost pill ("Grade") — an overlap bug. Pin the search
     button to the header's own top-right corner instead (anchored on
     .site-header-inner, same trick as the centered nav above) so its position
     never depends on account-slot width, and reserve its footprint as padding
     on the preview column so the account slot can't grow into it either. */
  body:not(.preview-mode-active) .site-header-preview-col {
    padding-right: 4.5rem;
  }
  body:not(.preview-mode-active) .site-search-btn {
    position: absolute;
    right: 1.5rem;
    top: 50%;
    transform: translateY(-50%);
  }
}

/* `right: 1.5rem` above anchors the search button to .site-header-inner's padding box —
   which, below 1315px, is the whole viewport (the header stops being centred so it can
   reserve the two fixed corners; see the corner-reservation block earlier in this file).
   That put the button hard against the viewport edge, i.e. underneath the account slot,
   making search unclickable on every laptop narrower than 1315px. Pull it inside the
   reserved 12rem gutter. MUST stay after the rule it overrides — same specificity, so
   source order is what decides. */
@media (min-width: 1024px) and (max-width: 1650px) {
  body:not(.preview-mode-active) .site-search-btn { right: 13rem; }
}

/* ===== 10-accessibility-motion.css ===== */
/* ─── Reduced-motion overrides ───────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .hero-icon,
  .form-glow::before,
  .space-aurora,
  .star,
  .site-header-score.is-bumping {
    animation: none;
  }

  .result-panel-reveal {
    transition-duration: 0.01ms;
    transition-timing-function: step-end;
  }

  .generate-workspace,
  .gen-left-col,
  .hero-collapse {
    transition-duration: 0.01ms;
  }

  .preview-mode #pdf-preview-pane,
  body.preview-mode-active #pdf-tab-bar-wrap:not([hidden]) {
    transition-duration: 0.01ms;
    opacity: 1;
    transform: none;
  }

  .site-header::before {
    transition-duration: 0.01ms;
  }

  .dl-hero:hover,
  .dl-hero:active,
  .dl-icon-btn:hover,
  .dl-icon-btn:active {
    transform: none;
  }

  /* Page-load entrance: fade only, no translate */
  body:not(.page-entered) #generate-workspace:not(.preview-mode)
    #gen-left-col > .hero-collapse:first-child p.uppercase,
  body:not(.page-entered) #generate-workspace:not(.preview-mode)
    #gen-left-col > .hero-collapse:first-child h1,
  body:not(.page-entered) #generate-workspace:not(.preview-mode)
    #gen-left-col > .hero-collapse:first-child > p.text-slate-400,
  body:not(.page-entered) #generate-workspace:not(.preview-mode) #gen-form.glass-panel,
  body:not(.page-entered) #generate-workspace:not(.preview-mode)
    .hero-collapse.mt-14 .feature-card:nth-child(1),
  body:not(.page-entered) #generate-workspace:not(.preview-mode)
    .hero-collapse.mt-14 .feature-card:nth-child(2),
  body:not(.page-entered) #generate-workspace:not(.preview-mode)
    .hero-collapse.mt-14 .feature-card:nth-child(3) {
    animation-name: hero-in-fade;
  }

  /* Title shimmer: disable */
  #generate-workspace:not(.preview-mode) #gen-left-col > .hero-collapse:first-child h1.font-display {
    animation: none;
  }

  /* Shared hero (.site-hero, used by Learn/Practice/Code/Library): kill float +
     shimmer, and make the entrance fade-only (keep the stagger delays, drop translate). */
  .site-hero-icon,
  .site-hero-title { animation: none; }
  body:not(.page-entered) .site-hero-icon,
  body:not(.page-entered) .site-hero-eyebrow,
  body:not(.page-entered) .site-hero h1,
  body:not(.page-entered) .site-hero-subtitle,
  body:not(.page-entered) .site-hero-chips,
  body:not(.page-entered) #lib-controls,
  body:not(.page-entered) #grid-physics {
    animation-name: hero-in-fade;
  }

  /* Icon settle: disable spring overshoot, keep icon at final scale */
  body:not(.page-entered) #generate-workspace:not(.preview-mode)
    .hero-collapse.mt-14 .feature-card > div:first-child,
  body:not(.page-entered) #grade-page .mt-10 .feature-card > div:first-child {
    animation: none;
  }

  /* PDF tab panel switch: jump instantly instead of fading */
  .pdf-tab-panel,
  .pdf-tab-panel.is-active {
    transition-duration: 0.01ms;
  }

  /* Cross-document View Transitions: cut instantly instead of cross-fading the
     whole page (and the named header). The live DOM shows immediately. */
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* ===== 12-mobile.css ===== */
/* ─── Mobile / tablet overrides ───────────────────────────────────────────────
 * Loaded last in base.html so it overrides earlier files.
 * Breakpoints:
 *   ≤1023px — below the desktop nav: icon-only nav bar + 44px touch controls
 *   ≤767px  — phones incl. landscape (sticky table columns)
 *   ≤639px  — header reflows account/score to row 1, nav to row 2 (see 07-…chrome)
 *   ≤479px  — small-phone card helper text; ≤359px hides the brand eyebrow
 * Desktop (≥1024px) is untouched.
 * ────────────────────────────────────────────────────────────────────────── */

/* ─── Navigation: icon-only nav bar below the desktop breakpoint ──────────────
 * The LABELLED nav only fits "at full width" at ≥1024px; below that we show the
 * icon-only nav bar. Two sub-zones (the 2-row reflow itself lives in
 * 07-header-preview-chrome.css):
 *   640–1023px — icon nav, single row (brand · icons · account)
 *   ≤639px     — icon nav + account/score lifted to header row 1, nav on row 2
 */
.nav-pill-icon { display: none; }

/* Raised from 1023px to 1200px (2026-07-30): below 1315px the header reserves gutters for
   the two fixed corner widgets (07-header-preview-chrome.css), and the centred label nav
   is 585px wide — at 1024–1200 its right-hand pills ran into the search button. The icon
   nav is 312px, which clears everything with room to spare. */
@media (max-width: 1200px) {
  .site-header-nav { gap: 0.125rem; padding: 0.25rem; }
  /* 8px around a 20px icon = 36px pills. The single-row icon nav fits cleanly
     from 640px up (brand↔nav gap stays positive ≥620px, measured). Below 640px
     the nav drops to its own row (07-…chrome.css reflow), where 8·36 + gaps
     ≈ 302px fits down to ~360px; narrower phones wrap to two icon rows via
     .site-header-nav{flex-wrap} rather than clip. 36px is a hair under the 44px
     touch ideal — the cost of a dense 8-icon bar; the row-1 controls keep 44px. */
  .site-header-nav a { padding: 0.5rem; }
  .nav-pill-label {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }
  .nav-pill-icon { display: inline-block; }

  /* ── Per-destination icon hue ──────────────────────────────────────────────
   * Scoped to this block on purpose: here the labels are visually hidden, so the glyph
   * is the ONLY thing naming a destination, and a colour makes the target findable by
   * muscle memory instead of by re-reading nine similar line drawings. Above 1200px the
   * labels do that job and only /english renders a glyph at all — one coloured icon in a
   * row of grey labels reads as a mistake, so the palette stops at the same breakpoint
   * the icons start at.
   *
   * Keyed on data-nav (base.html), NOT on href, so this reads as a palette table and a
   * renamed route loses its colour visibly rather than silently.
   *
   * Only the SVG is tinted — pill chrome and labels stay neutral, so it reads as nine
   * icons and not nine coloured buttons. Muted at rest, full on hover/active: this bar is
   * on every page of the site, so it has to stay calm, not just look colourful once.
   *
   * Hues are picked for MEANING first (lit bulb = amber, tick = emerald, AI sparkles =
   * fuchsia, code = the cyan /code already uses) and separation second. If a tenth link
   * is added, check it against its ROW NEIGHBOURS — those are the only pairs a reader
   * ever compares — not against the hue wheel.
   */
  body:not(.preview-mode-active) .site-header-nav a[data-nav] svg {
    color: rgb(var(--nav-rgb));
    opacity: 0.75;
    transition: opacity 0.18s ease;
  }
  body:not(.preview-mode-active) .site-header-nav a[data-nav]:hover svg,
  body:not(.preview-mode-active) .site-header-nav a[data-nav].nav-link-active svg { opacity: 1; }

  .site-header-nav a[data-nav="english"]  { --nav-rgb: 251 113 133; }  /* rose-400    — the daily feed */
  .site-header-nav a[data-nav="code"]     { --nav-rgb: 34 211 238; }   /* cyan-400    — /code's own accent */
  /* pink-400 — the clapperboard. Its row NEIGHBOURS are code (cyan) and learn
     (violet), which is the pair a reader compares; the other pink-family hue,
     english's rose-400, is separated from it by code. */
  .site-header-nav a[data-nav="videos"]   { --nav-rgb: 244 114 182; }  /* pink-400    — the clapperboard */
  .site-header-nav a[data-nav="learn"]    { --nav-rgb: 167 139 250; }  /* violet-400  — lessons */
  .site-header-nav a[data-nav="vocab"]    { --nav-rgb: 190 242 100; }  /* lime-300    — language */
  .site-header-nav a[data-nav="practice"] { --nav-rgb: 251 146 60; }   /* orange-400  — exam practice */
  .site-header-nav a[data-nav="know"]     { --nav-rgb: 252 211 77; }   /* amber-300   — the lit bulb */
  .site-header-nav a[data-nav="library"]  { --nav-rgb: 96 165 250; }   /* blue-400    — the archive */
  .site-header-nav a[data-nav="generate"] { --nav-rgb: 232 121 249; }  /* fuchsia-400 — AI sparkles */
  .site-header-nav a[data-nav="grade"]    { --nav-rgb: 52 211 153; }   /* emerald-400 — a tick is green */

  /* Account button / chip + language flag: full ~44px touch target (they have the
     room — single row at 640–1023px, header row 1 at ≤639px). */
  .site-header-account-btn,
  .site-header-account-chip,
  .lang-switch-trigger {
    min-height: 2.5rem;
    min-width: 2.5rem;
  }
  .lang-switch-trigger { display: inline-flex; align-items: center; justify-content: center; }
}

/* Forced-colours mode paints its own palette; a decorative hue fights it. */
@media (forced-colors: active) {
  body:not(.preview-mode-active) .site-header-nav a[data-nav] svg { color: CanvasText; opacity: 1; }
}

@media (max-width: 359px) {
  .site-header-brand-eyebrow { display: none !important; }
}

/* ─── iOS: stop the auto-zoom when focusing a sub-16px field ──────────────────
 * Mobile Safari zooms the page in whenever a focused input/textarea/select has a
 * font-size < 16px — jarring on the practice/test answer textareas (Tailwind
 * `text-sm` = 14px) and any other small field. Force 16px on phones.
 * `!important` is REQUIRED: the 14px comes from the `.text-sm` utility
 * (specificity 0,1,0), which a bare `input{}` (0,0,1) would lose to. Only fields
 * already < 16px are visibly affected. */
@media (max-width: 640px) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  textarea,
  select {
    font-size: 16px !important;
  }
}

/* Admin-stats tables: the sticky first-column rule now lives in 14-dashboard.css
   alongside the rest of the .admin-stats-table styling (loaded on both /dashboard
   and /admin/stats), so it can sit after the zebra/hover rules and stay opaque. */

/* ─── Teacher grade table: sticky student column when wide ───────────────── */
@media (max-width: 767px) {
  .ex-grade-table th:first-child,
  .ex-grade-table td:first-child {
    position: sticky;
    left: 0;
    background: rgba(8, 14, 30, 0.95);
    z-index: 1;
    box-shadow: 1px 0 0 rgba(255, 255, 255, 0.04);
  }
}

/* ─── Admin overview cards: shrink the multi-segment helper line ─────────── */
@media (max-width: 479px) {
  .admin-card-helper {
    font-size: 0.65rem;
    line-height: 1.2;
  }
}

/* ─── Starfield: hide on phones ──────────────────────────────────────────────
 * .space-stars is position:fixed (01-shell.css), so the 75 twinkling dots stay
 * frozen while the page scrolls — visibly "stuck" on a phone, and 75 animated
 * drop-shadow filters are a needless battery/scroll cost on mobile. display:none
 * drops them from the render tree (stops every twinkle animation) and is fully
 * responsive across the breakpoint. The aurora + gradient still carry the space
 * look; tablet/desktop keep the full starfield. */
@media (max-width: 767px) {
  .space-stars { display: none; }
}

/* ===== 13-account.css ===== */
/* ─── Account widget (header Account pill / chip / popover) ─────────────── */
/*
 * Logged-out: a cyan-glow pill that sits in its own slot to the right of
 * .site-header-nav (sibling, not child) — reads as a separate control.
 * Logged-in: a compact chip with a gradient avatar dot + @username, plus a
 * glass popover with a single Log out item.
 */

/* Pinned to the viewport's top-right corner, independent of the header's own
   layout (flex/grid mode, preview mode, breakpoint) — stacked directly above
   the floating feedback launcher (23-feedback.css .feedback-launcher), same
   `right` inset, so the two corner controls read as a vertically-aligned
   pair. Fixed positioning takes the slot out of the header's flex flow
   entirely, so it can never be squeezed or overlapped by the nav pill bar
   the way an in-flow flex sibling could be. */
.site-header-account-slot {
  position: fixed;
  top: calc(1rem + env(safe-area-inset-top, 0px));
  right: calc(1rem + env(safe-area-inset-right, 0px));
  z-index: 60;
  margin: 0;
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}

/* On phones, scroll away with the header instead of floating over the article. Same
   reasoning as the pinned wordmark in 07-header-preview-chrome.css: viewport-fixed corner
   controls work while wide centring gutters exist to float over, but a phone's reading
   column is edge-to-edge and the header is not sticky, so the chip stayed parked on top of
   the content. `absolute` against the (static) body keeps the at-rest position identical.
   Breakpoint matches the wordmark's (767px), not the 640px inset tweak below it. */
@media (max-width: 767px) {
  .site-header-account-slot { position: absolute; }
}

@media (max-width: 640px) {
  .site-header-account-slot {
    top: calc(0.85rem + env(safe-area-inset-top, 0px));
    right: calc(0.85rem + env(safe-area-inset-right, 0px));
  }
}

.site-header-account-btn {
  position: relative;
  background: linear-gradient(135deg,
    rgba(34, 211, 238, 0.06) 0%,
    rgba(99, 102, 241, 0.06) 100%);
  /* Inset border via box-shadow keeps the pill on the same grid as the
     surrounding nav links (which have no border). The shadow alpha is what
     animates via @keyframes login-pulse below. */
  box-shadow: inset 0 0 0 1px rgba(34, 211, 238, var(--login-ring, 0.40));
  --login-ring: 0.40;
  animation: login-pulse 3.5s ease-in-out infinite;
  transition: transform 0.18s ease, box-shadow 0.18s ease, filter 0.18s ease;
}

.site-header-account-btn:hover {
  --login-ring: 0.85;
  filter: brightness(1.08);
  transform: translateY(-1px);
  /* The pulse is paused on hover so the hover ring sits at full strength. */
  animation-play-state: paused;
  box-shadow:
    inset 0 0 0 1px rgba(34, 211, 238, 0.85),
    0 8px 24px -8px rgba(34, 211, 238, 0.45);
}

.site-header-account-btn:active {
  transform: translateY(0);
}

@keyframes login-pulse {
  0%, 100% { box-shadow: inset 0 0 0 1px rgba(34, 211, 238, 0.40); }
  50%      { box-shadow: inset 0 0 0 1px rgba(34, 211, 238, 0.55); }
}

@media (prefers-reduced-motion: reduce) {
  .site-header-account-btn { animation: none; }
  .site-header-account-btn { box-shadow: inset 0 0 0 1px rgba(34, 211, 238, 0.45); }
}

/* The user-icon SVG inherits the existing .nav-pill-icon sizing — no override
   needed. The label inherits .nav-pill-label so it collapses to icon-only on
   phones via the rule in 12-mobile.css. */


/* ─── Logged-in chip + avatar dot ────────────────────────────────────────── */
.site-header-account-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
}

.site-header-account-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  border-radius: 9999px;
  padding: 0.375rem 0.875rem;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.10);
  font-size: 0.875rem;
  font-weight: 500;
  color: rgba(226, 232, 240, 0.95);
  transition: background 0.16s ease, border-color 0.16s ease;
}

.site-header-account-chip:hover {
  background: rgba(255, 255, 255, 0.10);
  border-color: rgba(34, 211, 238, 0.35);
}

/* The chip and the login button are now rendered TOGETHER in the header and
   toggled by the `hidden` attribute (server-side, or client-side during identity
   hydration in cache_html mode — see base.html). Both carry `display: inline-flex`
   from their class, which would otherwise beat the UA `[hidden] { display: none }`;
   this higher-specificity rule makes `hidden` authoritative (same pattern as the
   account-dialog fields below). */
.site-header-account-chip[hidden],
.site-header-account-btn[hidden] {
  display: none;
}

.site-header-account-dot {
  display: inline-block;
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 9999px;
  background: linear-gradient(135deg, #67e8f9 0%, #818cf8 100%);
  box-shadow: 0 0 6px rgba(34, 211, 238, 0.45);
  flex-shrink: 0;
}

.site-header-account-name {
  max-width: 9rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Below 1315px the header reserves a fixed 12rem gutter for this slot (see the
   corner-reservation block in 07-header-preview-chrome.css). A 9rem name lets the chip
   reach 272px, which would spill back over the search button that now sits just inside
   that gutter — so cap the name to a width the reservation actually covers (4rem keeps
   the whole slot under ~170px, leaving a ~22px gap to the button at every width in the
   band). */
@media (max-width: 1650px) {
  .site-header-account-name { max-width: 4rem; }
}


/* ─── Site-wide score pill (inside the chip, beside @username) ───────────── */
/* Gold/amber so it reads as "score", distinct from the cyan account dot.
   Deliberately NOT tagged .nav-pill-label, so it stays visible on phones where
   the username text collapses (the chip then shows dot + ⭐score). */
.site-header-score {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  margin-left: 0.125rem;
  padding: 0.12rem 0.45rem;
  border-radius: 9999px;
  background: linear-gradient(135deg, rgba(250, 204, 21, 0.16) 0%, rgba(245, 158, 11, 0.12) 100%);
  border: 1px solid rgba(250, 204, 21, 0.30);
  color: #fde68a;
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1;
}

.site-header-score-icon {
  width: 0.8rem;
  height: 0.8rem;
  color: #fbbf24;
  filter: drop-shadow(0 0 3px rgba(251, 191, 36, 0.5));
  flex-shrink: 0;
}

.site-header-score-value {
  font-variant-numeric: tabular-nums;  /* digits don't reflow the row as it ticks */
  min-width: 0.6ch;
}

/* JS adds .is-bumping for one animation cycle whenever the total increases. */
.site-header-score.is-bumping,
.site-header-guest-score.is-bumping {
  animation: score-pop 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes score-pop {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.28); }
  100% { transform: scale(1); }
}


/* ─── Guest score chip (logged out, but has actually scored) ─────────────── */
/* Same amber vocabulary as the in-chip score pill, so "points" looks the same
   whether or not you have an account — but this one is a <button>, because for a
   guest the score *is* the call to action: clicking opens the account dialog, and
   link_open_session then carries the points onto the new account for real.
   Stays hidden until /api/me reports a non-zero total (account.js) or the visitor
   scores live (user-score.js) — a "0 points" badge would be an anti-hook. */
.site-header-guest-score {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.2rem 0.55rem;
  border-radius: 9999px;
  background: linear-gradient(135deg, rgba(250, 204, 21, 0.16) 0%, rgba(245, 158, 11, 0.12) 100%);
  border: 1px solid rgba(250, 204, 21, 0.30);
  color: #fde68a;
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.site-header-guest-score:hover {
  background: linear-gradient(135deg, rgba(250, 204, 21, 0.28) 0%, rgba(245, 158, 11, 0.20) 100%);
  border-color: rgba(250, 204, 21, 0.55);
}

.site-header-guest-score:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px rgba(251, 191, 36, 0.60);
}

/* Same reason as the chip/button pair above: inline-flex would otherwise beat
   the UA's `[hidden] { display: none }`, so make `hidden` authoritative. */
.site-header-guest-score[hidden] {
  display: none;
}

.site-header-guest-score-value {
  font-variant-numeric: tabular-nums;  /* digits don't reflow the row as it ticks */
  min-width: 0.6ch;
}


/* ─── Admin unread-feedback notification badge (header, every page) ────────
   Mirrors .site-header-score but red, to read as "needs attention". Admin-only;
   links to the dashboard feedback panel. Shown only when there is unread feedback
   (toggled via [hidden] — server-render or account.js in cache_html mode). */
.site-header-feedback-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  margin-left: 0.25rem;
  padding: 0.12rem 0.5rem;
  border-radius: 9999px;
  background: linear-gradient(135deg, rgba(239, 68, 68, 0.22) 0%, rgba(220, 38, 38, 0.16) 100%);
  border: 1px solid rgba(248, 113, 113, 0.45);
  color: #fecaca;
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  animation: feedback-pulse 2s ease-in-out infinite;
}
.site-header-feedback-badge:hover {
  background: linear-gradient(135deg, rgba(239, 68, 68, 0.32) 0%, rgba(220, 38, 38, 0.24) 100%);
  border-color: rgba(248, 113, 113, 0.65);
}
/* `display: inline-flex` above would beat the UA `[hidden] { display: none }`;
   this higher-specificity rule makes `hidden` authoritative (same pattern as the
   account chip/button above). */
.site-header-feedback-badge[hidden] { display: none; }
.site-header-feedback-icon {
  width: 0.95rem;
  height: 0.95rem;
  color: #f87171;
  filter: drop-shadow(0 0 3px rgba(248, 113, 113, 0.5));
  flex-shrink: 0;
}
.site-header-feedback-count {
  font-variant-numeric: tabular-nums;  /* digits don't reflow the row as it ticks */
  min-width: 0.6ch;
}
@keyframes feedback-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
  50%      { box-shadow: 0 0 10px -1px rgba(239, 68, 68, 0.55); }
}
@media (prefers-reduced-motion: reduce) {
  .site-header-feedback-badge { animation: none; }
}


/* ─── Popover (anchored beneath chip) ───────────────────────────────────── */
.site-header-account-popover {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  min-width: 10rem;
  padding: 0.375rem;
  border-radius: 0.75rem;
  z-index: 30;
  /* glass-panel-like surface; not reusing the class so we control padding. */
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: linear-gradient(148deg,
    rgba(15, 28, 52, 0.92) 0%,
    rgba(10, 18, 38, 0.78) 100%);
  backdrop-filter: blur(28px);
  -webkit-backdrop-filter: blur(28px);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.04) inset,
    0 18px 36px -12px rgba(0, 0, 0, 0.6);
  /* Hidden via [hidden] attribute by default; toggled by JS. */
}

.site-header-account-popover button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.5rem 0.75rem;
  border-radius: 0.5rem;
  font-size: 0.875rem;
  color: rgba(226, 232, 240, 0.9);
  background: transparent;
  transition: background 0.12s ease, color 0.12s ease;
}

.site-header-account-popover button:hover {
  background: rgba(34, 211, 238, 0.10);
  color: white;
}


/* ─── Modal dialog ──────────────────────────────────────────────────────── */
.account-dialog {
  /* Native <dialog> reset: strip the UA border. Inner padding is owned by THIS
     rule (not the `p-6 sm:p-7` utilities the element used to carry): 13-account
     is bundled after 00-tailwind.css, so at equal specificity
     `.account-dialog { padding }` wins over `.p-6`/`.sm:p-7`. The old
     `padding: 0` reset therefore silently zeroed the dialog's padding on every
     side — content sat flush to the edges and the rounded top corner clipped
     the title. Keep padding here so it can't be re-broken that way. */
  border: none;
  padding: 1.5rem;
  /* On a notched phone where the centered dialog grows near full height, keep the
     submit button above the home indicator. env() = 0 elsewhere (and the ≥640px
     padding override below also lands on non-notched widths), so this is inert
     except on a small notched device. */
  padding-bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
  background: transparent;
  color: inherit;
  /* Slight bump from 24rem so the password requirements row doesn't wrap on
     narrower phones. */
  max-width: 26rem;
  width: calc(100% - 2rem);
  /* Must stay `fixed`, matching the UA's dialog:modal rule. The old
     `position: relative` here silently overrode it (author rules beat UA rules
     whatever the specificity) and top-layer coercion turned it into `absolute`
     — anchoring the dialog to the DOCUMENT, not the viewport. Net effect:
     showModal()'s focusing steps scrolled the page to the top every time the
     dialog opened. Any positioned value keeps anchoring the close (×) button
     and the ::before glow, so nothing else changes. */
  position: fixed;
  /* The UA sheet gives <dialog> `overflow: auto`, and the .form-glow::before
     halo sits at inset -1px — 1px of "scrollable" overflow on every side. That
     phantom pixel engaged BOTH classic scrollbars (macOS-with-mouse, Windows):
     a vertical bar eating 15px of the right padding and a horizontal bar
     cutting across the bottom corners. The dialog itself must never scroll —
     the form below is the scroll container — so keep its overflow visible
     (this also un-clips the halo's right/bottom edge). */
  overflow: visible;
}

/* Mirror the intended p-6 → sm:p-7 step-up on wider screens (those utilities
   were dead — see the padding note above). */
@media (min-width: 640px) {
  .account-dialog { padding: 1.75rem; }
}

.account-dialog::backdrop {
  background: rgba(1, 4, 14, 0.72);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.account-dialog[open] {
  /* Center via dialog's default position; flex centering is also fine but
     would double up with the user-agent stylesheet on some engines. */
  margin: auto;
  /* Phones / short windows: cap the dialog at the viewport (minus the same
     1rem inset used horizontally) and scroll the form inside it. Without this,
     tall states (the Teacher path reveals the access-code field) — and, on
     every phone, the soft keyboard shrinking the usable area when a field is
     focused — push the submit button off a centered native <dialog>, which has
     no page scroll behind it and no internal scroll, leaving Continue
     unreachable. Desktop windows are taller than the form, so max-height never
     binds and nothing changes there. dvh tracks the mobile URL bar; the plain
     vh declaration is the fallback for engines without dvh. */
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 2rem);
  max-height: calc(100dvh - 2rem);
}

/* The form — not the dialog — is the scroll container. Two reasons: the close
   (×) is an absolutely-positioned sibling, so it stays pinned at the corner
   instead of scrolling away with the content; and the dialog's -1px gradient
   glow border (.form-glow::before) isn't clipped the way dialog-level overflow
   would clip it. min-height:0 lets the flex child shrink below its content so
   overflow-y actually engages. */
.account-dialog > form {
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  /* Being a scroll container, the form clips at its padding box — which used
     to coincide exactly with the fields' border box, shaving the inputs' 2px
     focus ring and gluing the (short-window) scrollbar flush against the
     fields. Extend the scrollport into the dialog's padding and pad the same
     amount back: pixel-identical when nothing scrolls, and when the form does
     scroll the bar parks in the gutter with the rings left intact. */
  margin: -0.5rem -1rem;
  padding: 0.5rem 1rem;
}

/* A native <dialog> doesn't lock the page behind it — wheel/touch over the
   backdrop scrolled the page under the blur. Freeze it while the modal is up
   (:has misses = old engines keep today's behaviour, nothing breaks). */
html:has(.account-dialog[open]) {
  overflow: hidden;
}

/* Close (×) button anchored to the dialog's top-right corner so the user
   has an explicit way out beyond ESC / backdrop click. */
.account-dialog-close {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 0.5rem;
  color: rgba(148, 163, 184, 0.85);
  background: transparent;
  transition: background 0.12s ease, color 0.12s ease;
}

.account-dialog-close:hover { background: rgba(255, 255, 255, 0.06); color: white; }
.account-dialog-close:focus-visible {
  outline: 2px solid rgba(34, 211, 238, 0.6);
  outline-offset: 2px;
}

/* Per-field grouping: input + optional inline-hint or check-list.
   Tighter vertical rhythm than the form's outer gap, so an input and its
   feedback row read as one unit instead of two free-floating elements.
   Labels are sr-only — placeholders carry the visible field-purpose hint. */
.account-field-group {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

/* account.js shows/hides these blocks by toggling the `hidden` attribute (the
   role picker + password checklist hide on the login path; the teacher-code
   field hides unless Teacher is selected). The UA `[hidden] { display: none }`
   is lower-priority than the `display: flex` declarations on these classes, so
   without this higher-specificity rule the attribute has no effect and the
   elements stay visible. */
.account-field-group[hidden],
.account-role-fieldset[hidden],
.account-password-checks[hidden] {
  display: none;
}

/* Static helper under a field (the teacher-code gate). Muted to match the
   password-checklist tone. */
.account-field-hint {
  font-size: 0.75rem;
  color: rgba(148, 163, 184, 0.72);
  padding-left: 0.125rem;
}

/* Teacher-code field reads as a distinct "gate": a faint cyan callout that
   frames the input + helper, with a gentle reveal when Teacher is picked. The
   rule sets no `display`, so the `[hidden] { display: none }` rule above still
   wins while the field is hidden. */
.account-field-group[data-account-teacher-code] {
  padding: 0.625rem 0.75rem;
  border-radius: 0.75rem;
  background: rgba(34, 211, 238, 0.05);
  border: 1px solid rgba(34, 211, 238, 0.16);
}

.account-field-group[data-account-teacher-code]:not([hidden]) {
  animation: account-field-in 0.18s ease;
}

@keyframes account-field-in {
  from { opacity: 0; transform: translateY(-0.25rem); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .account-field-group[data-account-teacher-code]:not([hidden]) { animation: none; }
}


/* ─── Live-check hint row (below username field in the modal) ───────────── */
.account-hint-row {
  font-size: 0.8125rem;
  display: flex;
  align-items: center;
  gap: 0.375rem;
  padding-left: 0.125rem;
}

/* Collapse the row when JS hasn't populated it yet so there's no awkward
   reserved vertical space above the role picker. */
.account-hint-row:empty {
  display: none;
}

.account-hint--found { color: rgb(103, 232, 249); }  /* cyan-300 */
.account-hint--new   { color: rgb(165, 180, 252); }  /* indigo-300 */

.account-hint-icon {
  display: inline-flex;
  width: 0.875rem;
  height: 0.875rem;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 0.75rem;
}


/* ─── Role selector (segmented radio in the create-account dialog) ─────── */
.account-role-fieldset {
  border: 0;
  padding: 0;
  margin: 0;
  /* Match the flex/gap structure of .account-field-group so legend → group
     spacing is the same 0.375rem used elsewhere.
     align-items: flex-start keeps the inline-flex .account-role-group from
     being stretched to the dialog's full width (default flex-container
     behaviour is align-items: stretch). */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.375rem;
}

.account-role-group {
  position: relative;
  display: inline-flex;
  gap: 0.25rem;
  padding: 0.25rem;
  border-radius: 9999px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.08);
}

.account-role-group input[type="radio"] {
  /* Visually hide but keep focusable for keyboard + screen readers. */
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: 1px;
  height: 1px;
}

.account-role-group label {
  padding: 0.375rem 0.875rem;
  border-radius: 9999px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: rgba(203, 213, 225, 0.85);
  cursor: pointer;
  transition: background 0.14s ease, color 0.14s ease, box-shadow 0.14s ease;
}

.account-role-group label:hover {
  color: white;
  background: rgba(255, 255, 255, 0.06);
}

.account-role-group input[type="radio"]:checked + label {
  background: linear-gradient(135deg, #67e8f9 0%, #818cf8 100%);
  color: white;
  box-shadow: 0 0 12px -2px rgba(34, 211, 238, 0.45);
}

.account-role-group input[type="radio"]:focus-visible + label {
  outline: 2px solid rgba(34, 211, 238, 0.6);
  outline-offset: 2px;
}


/* ─── Password strength checklist (create / neutral mode only) ──────────── */
.account-password-checks {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.75rem;
  color: rgba(148, 163, 184, 0.75);
  padding-left: 0.125rem;
}

.account-password-checks li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  transition: color 0.16s ease;
}

.account-check-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 0.875rem;
  height: 0.875rem;
  border-radius: 9999px;
  border: 1px solid rgba(148, 163, 184, 0.45);
  background: rgba(255, 255, 255, 0.02);
  font-size: 0.625rem;
  line-height: 1;
  color: transparent;
  flex-shrink: 0;
  transition: background 0.16s ease, border-color 0.16s ease, color 0.16s ease;
}

/* Use a CSS-only checkmark glyph that appears once .met is set. */
.account-check-icon::before {
  content: "✓";
  font-weight: 700;
  color: inherit;
}

.account-password-checks li.met {
  color: rgb(165, 243, 252);  /* cyan-200 */
}

.account-password-checks li.met .account-check-icon {
  background: linear-gradient(135deg, #22d3ee 0%, #6366f1 100%);
  border-color: rgba(34, 211, 238, 0.85);
  color: white;
  box-shadow: 0 0 8px -1px rgba(34, 211, 238, 0.45);
}


/* ─── Password eye toggle ───────────────────────────────────────────────── */
.account-password-wrap {
  position: relative;
}

.account-password-toggle {
  position: absolute;
  top: 50%;
  right: 0.625rem;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 0.375rem;
  color: rgba(148, 163, 184, 0.85);
  background: transparent;
  transition: background 0.12s ease, color 0.12s ease;
}

.account-password-toggle:hover { background: rgba(255, 255, 255, 0.06); color: white; }


/* ─── Toast (post-reload flash) ─────────────────────────────────────────── */
.account-toast {
  position: fixed;
  top: 1.25rem;
  right: 1.25rem;
  z-index: 60;
  min-width: 14rem;
  padding: 0.75rem 1rem;
  border-radius: 0.75rem;
  background: linear-gradient(148deg,
    rgba(15, 28, 52, 0.95) 0%,
    rgba(10, 18, 38, 0.85) 100%);
  border: 1px solid rgba(34, 211, 238, 0.30);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  box-shadow:
    0 18px 36px -12px rgba(0, 0, 0, 0.55),
    0 0 24px -6px rgba(34, 211, 238, 0.25);
  font-size: 0.875rem;
  color: rgba(241, 245, 249, 0.95);
  animation: account-toast-in 0.32s cubic-bezier(0.22, 1, 0.36, 1);
}

@keyframes account-toast-in {
  from { opacity: 0; transform: translateY(-0.5rem); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .account-toast { animation: none; }
}


/* ─── Mobile: collapse pill label, shrink chip ──────────────────────────── */
@media (max-width: 479px) {
  /* The nav-pill-label rule in 12-mobile.css hides the inner span. We tag
     our pill with .nav-pill-label too so the same rule applies; no
     additional declaration needed here for the pill. */
  .site-header-account-chip {
    padding: 0.375rem 0.5rem;
  }
  .site-header-account-name {
    max-width: 6rem;
  }
}
