
/* ==== base/tokens.css ==== */
/* Studora design tokens — sourced from studora-blueprint.html */
:root{
  --paper:#faf8f1;
  --paper-2:#f3efe2;
  --ink:#17181c;
  --ink-2:#3c3d44;
  --ink-3:#646570;
  --rule:#e6e0cd;
  --rule-ink:#d6cfb6;

  --yellow:#ffe680;
  --yellow-2:#fff2b5;
  --mint:#c9ecd0;
  --blush:#fbd2c5;
  --sky:#c9dffc;
  --lilac:#dfd3f3;

  --green:#1f7a3d;
  --red:#b94632;
  --blue:#1e528f;

  --sans:'Inter',ui-sans-serif,system-ui,sans-serif;
  --serif:'Fraunces',ui-serif,Georgia,serif;
  --mono:'JetBrains Mono',ui-monospace,monospace;

  --rule-step:32px;
  --shadow-pop:2px 2px 0 var(--ink);
  --radius-sm:3px;
  --radius:4px;
  --radius-lg:6px;
}

/* ==== base/reset.css ==== */
*{box-sizing:border-box}
html,body{margin:0;padding:0}
body.nb{
  background:var(--paper);
  color:var(--ink);
  font-family:var(--sans);
  font-size:15.5px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  background-image:linear-gradient(transparent 31px,var(--rule) 31px,var(--rule) 32px,transparent 32px);
  background-size:100% 32px;
  background-position:0 60px;
  min-height:100vh;
}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;cursor:pointer;border:0;background:none;padding:0}
p{margin:0 0 12px}
h1,h2,h3,h4,h5{margin:0}
img,svg{display:block;max-width:100%}

mark.hl{background:var(--yellow);padding:0 .12em;border-radius:2px;box-decoration-break:clone;-webkit-box-decoration-break:clone;color:inherit}
mark.hl.g{background:var(--mint)}
mark.hl.p{background:var(--blush)}
mark.hl.b{background:var(--sky)}

.serif{font-family:var(--serif);font-style:italic;font-weight:500}
.mono{font-family:var(--mono)}
.muted{color:var(--ink-3)}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}

/* Skip-to-content link — visible on focus only. WCAG 2.4.1 */
.skip-link{
  position:absolute;left:-9999px;top:0;
  background:var(--ink,#17181c);color:var(--paper,#faf8f1);
  padding:10px 16px;font-family:var(--mono);font-size:13px;font-weight:600;
  border-radius:0 0 6px 0;z-index:9999;text-decoration:none;
}
.skip-link:focus{left:0;outline:2px solid var(--yellow,#ffe680);outline-offset:-2px}

/* Respect reduced-motion users */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important;scroll-behavior:auto!important}
}

/* Visible focus indicators for keyboard users */
:focus-visible{outline:2px solid var(--ink-3,#3a3a3a);outline-offset:2px;border-radius:2px}
button:focus-visible,a:focus-visible,input:focus-visible{outline:2px solid var(--ink-3,#3a3a3a);outline-offset:2px}

.nb-wrap{max-width:1240px;margin:0 auto;padding:0 24px}
@media(max-width:600px){.nb-wrap{padding:0 16px}}

/* Hand-drawn red squiggle underline on hover for body links — signature #4.
   The SVG lives in /assets/img/squiggle.svg so the bytes are cached
   immutably (per the long-lived Cache-Control rule on /assets/img/*) and
   removed from every CSS bundle. The previous inline data URL added ~280 B
   to every CSS render — small per-byte, but it was inside the critical
   bundle and shipped on every page load. */
.sq{display:inline;position:relative;background-image:none}
.sq::after{
  content:"";position:absolute;left:-2%;right:-2%;bottom:-2px;height:6px;
  background:url("/assets/img/squiggle.svg") no-repeat bottom;
  background-size:100% 100%;opacity:0;transition:opacity .15s;
  pointer-events:none;
}
.sq:hover::after,a.sq:focus-visible::after{opacity:1}

/* ==== base/animations.css ==== */
@keyframes nbPulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.45;transform:scale(.8)}}
@keyframes nbSpring{0%{transform:scale(1)}45%{transform:scale(1.03)}100%{transform:scale(1)}}
@keyframes nbShake{0%,100%{transform:translateX(0)}25%{transform:translateX(-5px)}75%{transform:translateX(5px)}}
@keyframes nbFade{from{opacity:0}to{opacity:1}}
@keyframes nbRise{from{opacity:0;transform:translateY(14px) rotate(-1deg)}to{opacity:1;transform:none}}
@keyframes nbFall{to{transform:translate(var(--drift,0),100vh) rotate(720deg);opacity:0}}
@keyframes nbWobble{0%,100%{transform:rotate(0)}25%{transform:rotate(-3deg)}75%{transform:rotate(3deg)}}
@keyframes nbSkel{from{background-position:200% 0}to{background-position:-200% 0}}
@keyframes nbPageIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
@keyframes nbSlideIn{from{opacity:0;transform:translateX(-12px)}to{opacity:1;transform:none}}

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

/* ==== fonts.css ==== */
/* Studora — self-hosted fonts (woff2 only, latin subset, variable axes).
 * Replaces the third-party Google Fonts stylesheet that was costing us a
 * ~1.2s FCP gap and contributing to a 0.42 CLS on the hero.
 *
 * Strategy:
 *   - One variable woff2 per family (Inter, Fraunces italic, JetBrains Mono).
 *     Each is declared with a font-weight range so a single file covers all
 *     weights we use.
 *   - Hero h1 uses Inter 800 + a Fraunces-italic <em>. Both files are
 *     <link rel="preload"> in index.html so they arrive in the first round trip.
 *
 * font-display choices (CLS-driven):
 *   - Fraunces italic uses `font-display: optional`. The hero h1 has a single
 *     italic word ("quieter") whose swap from Georgia -> Fraunces was the
 *     dominant source of the 0.4201 CLS. `optional` tells the browser to use
 *     the fallback if Fraunces hasn't arrived in ~100ms and *not* swap later,
 *     guaranteeing zero shift. Since we also preload the file, on warm and
 *     reasonably-fast connections it arrives in time and renders in Fraunces;
 *     on slow connections we keep Georgia and skip the shift entirely.
 *   - Inter and JetBrains Mono use `font-display: swap`. Inter 800 is
 *     preloaded; the size-adjust/ascent-override on the @font-face below
 *     keeps fallback metrics close enough that any swap is sub-pixel.
 */

/* Inter — variable, weights 400..800. Used everywhere. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('/assets/fonts/inter-var.woff2') format('woff2-variations'),
       url('/assets/fonts/inter-var.woff2') format('woff2');
  /* Metric overrides for the ui-sans-serif / system-ui fallback to minimise
   * layout shift on swap. Numbers derived from Inter's vs system-ui's vertical
   * metrics; same approximation that next/font ships. */
  size-adjust: 107.4%;
  ascent-override: 90%;
  descent-override: 22.43%;
  line-gap-override: 0%;
}

/* Fraunces italic — variable opsz 9..144, weight 500..700. Hero emphasis +
 * stats. font-display: optional eliminates the worst-case CLS on the hero. */
@font-face {
  font-family: 'Fraunces';
  font-style: italic;
  font-weight: 500 700;
  font-display: optional;
  src: url('/assets/fonts/fraunces-italic-var.woff2') format('woff2-variations'),
       url('/assets/fonts/fraunces-italic-var.woff2') format('woff2');
  /* Metric overrides tuned for Georgia / ui-serif fallback so that if Fraunces
   * never arrives, the hero typography still has roughly the right vertical
   * rhythm. */
  size-adjust: 107%;
  ascent-override: 95%;
  descent-override: 25%;
  line-gap-override: 0%;
}

/* JetBrains Mono — variable, weights 400..500. Small monospace UI text only. */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url('/assets/fonts/jetbrains-mono-var.woff2') format('woff2-variations'),
       url('/assets/fonts/jetbrains-mono-var.woff2') format('woff2');
  size-adjust: 100%;
  ascent-override: 90%;
  descent-override: 20%;
  line-gap-override: 0%;
}

/* ==== components/topbar.css ==== */
.nb-top{position:sticky;top:0;z-index:50;background:var(--paper);border-bottom:1.5px solid var(--ink)}
.nb-top-in{max-width:1240px;margin:0 auto;padding:14px 24px;display:flex;align-items:center;gap:18px}

.nb-logo{
  display:inline-flex;align-items:center;gap:2px;text-decoration:none;
  color:var(--ink);font-weight:800;letter-spacing:-.025em;cursor:pointer;
  font-size:22px;line-height:1;
}
.nb-logo .mark{
  width:46px;height:46px;flex-shrink:0;background:transparent;
  /* The SVG carries its own colours and yellow accent — no border / no bg here. */
}
.nb-logo .word{margin-left:-2px;color:var(--ink)}
.nb-logo em,
.nb-logo .nb-logo-tag{
  font-family:var(--serif);font-style:italic;font-weight:500;
  color:var(--ink-3);font-size:14px;margin-left:8px;letter-spacing:0;
}
@media(max-width:1039px){
  .nb-logo .nb-logo-tag{display:none}
}
.nb-logo:hover .mark{transform:rotate(-3deg);transition:transform .18s ease}

.nb-nav{display:none;gap:20px;margin-left:18px;font-family:var(--mono);font-size:12.5px;color:var(--ink-2);white-space:nowrap}
.nb-nav a{text-decoration:none;padding:6px 0;border-bottom:2px solid transparent;cursor:pointer;transition:border-color .15s, color .15s}
.nb-nav a:hover,.nb-nav a.active{border-bottom-color:var(--ink);color:var(--ink)}
@media(min-width:1040px){.nb-nav{display:flex}}

/* Hamburger button — visible below the 1040px breakpoint where the inline
   nav collapses. Matches the brand: paper background, ink rules, square-ish
   corners via --radius. The two lines are pure CSS, no SVG needed. */
.nb-burger{
  display:none;width:44px;height:44px;flex-shrink:0;
  background:var(--paper);border:1.5px solid var(--ink);border-radius:var(--radius);
  cursor:pointer;align-items:center;justify-content:center;flex-direction:column;gap:5px;
  margin-left:auto;padding:0;
}
.nb-burger .nb-burger-line{display:block;width:20px;height:1.5px;background:var(--ink);border-radius:1px}
.nb-burger:hover{background:var(--paper-2)}
.nb-burger:focus-visible{outline:2px solid var(--ink);outline-offset:2px}

@media(max-width:1039px){
  .nb-burger{display:inline-flex}
  .nb-top-cta{margin-left:8px}
  .nb-top-in{position:relative}
  .nb-nav{
    display:none;flex-direction:column;align-items:flex-start;gap:0;
    position:absolute;top:100%;left:0;right:0;margin:0;
    background:var(--paper);border-top:1.5px solid var(--ink);border-bottom:1.5px solid var(--ink);
    padding:6px 24px;z-index:49;
  }
  .nb-nav.open{display:flex}
  .nb-nav a{display:block;width:100%;padding:12px 0;border-bottom:1px solid var(--rule)}
  .nb-nav a:last-child{border-bottom:0}
  .nb-nav a:hover,.nb-nav a.active{border-bottom-color:var(--ink);color:var(--ink)}
}

.nb-top-cta{margin-left:auto;display:flex;gap:8px;flex-shrink:0;align-items:center}
.nb-streak-mini{display:none;font-family:var(--mono);font-size:12px;color:var(--ink-2);align-items:center;gap:6px;padding:6px 10px;border:1.5px solid var(--ink);border-radius:6px;background:var(--paper)}
.nb-streak-mini b{font-family:var(--sans);color:var(--red);font-weight:800}
.nb-streak-mini.bump{animation:nbWobble .25s}
@media(min-width:720px){.nb-streak-mini{display:inline-flex}}

/* Mistake-count badge in the nav. Small, monospace, brand-red. */
.nb-nav-badge{display:inline-block;margin-left:4px;padding:1px 6px;font-family:var(--mono);font-size:10.5px;font-weight:700;color:#fff;background:var(--red,#b94632);border-radius:999px;line-height:1.4;vertical-align:1px}

/* ==== components/buttons.css ==== */
.nb-btn{
  padding:9px 16px;border:1.5px solid var(--ink);background:var(--paper);
  font-family:var(--mono);font-size:12.5px;font-weight:600;
  text-decoration:none;color:var(--ink);border-radius:6px;
  white-space:nowrap;display:inline-flex;align-items:center;gap:8px;cursor:pointer;
  transition:transform .12s, box-shadow .12s;
}
.nb-btn:hover{transform:translate(-1px,-1px);box-shadow:var(--shadow-pop)}
.nb-btn:active{transform:translate(0,0);box-shadow:none}
.nb-btn.primary{background:var(--ink);color:var(--paper)}
.nb-btn.primary:hover{box-shadow:2px 2px 0 var(--ink-3)}
.nb-btn.y{background:var(--yellow)}
.nb-btn.sm{padding:7px 12px;font-size:12px}

.nb-sticker{display:inline-block;padding:3px 10px;font-family:var(--mono);font-size:10.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;border:1.5px solid var(--ink);border-radius:3px;background:var(--paper)}
.nb-sticker.y{background:var(--yellow)}
.nb-sticker.g{background:var(--mint);color:var(--green)}
.nb-sticker.p{background:var(--blush);color:var(--red)}
.nb-sticker.b{background:var(--sky);color:var(--blue)}
.nb-sticker.d{background:var(--ink);color:var(--paper)}

.nb-pin{position:absolute;top:-10px;right:-8px;background:var(--yellow);border:1.5px solid var(--ink);padding:4px 9px;font-family:var(--mono);font-size:10.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;transform:rotate(4deg);box-shadow:var(--shadow-pop);z-index:2}
.nb-pin.g{background:var(--mint)}
.nb-pin.p{background:var(--blush)}
.nb-pin.b{background:var(--sky)}

/* ==== components/cards.css ==== */
/* Paper cards with ruled-line backgrounds — match blueprint exactly */
.nb-card{
  border:1.5px solid var(--ink);background:var(--paper);
  padding:22px 24px;margin-bottom:14px;position:relative;
  background-image:linear-gradient(transparent 31px,var(--rule) 31px,var(--rule) 32px,transparent 32px);
  background-size:100% 32px;background-position:0 0;
}
.nb-card.flat{background-image:none}
.nb-card.yellow{background-color:#fff8d8;background-image:linear-gradient(transparent 31px,#ecd88a 31px,#ecd88a 32px,transparent 32px)}
.nb-card.mint{background-color:#dff4e2;background-image:linear-gradient(transparent 31px,#a9d6b2 31px,#a9d6b2 32px,transparent 32px)}
.nb-card.blush{background-color:#fcdfd4;background-image:linear-gradient(transparent 31px,#dfb0a0 31px,#dfb0a0 32px,transparent 32px)}
.nb-card.sky{background-color:#d9e8fb;background-image:linear-gradient(transparent 31px,#a9c0dd 31px,#a9c0dd 32px,transparent 32px)}
.nb-card.dark{background:var(--ink);color:var(--paper);background-image:none;border-color:var(--ink)}
.nb-card.dark .mono{color:var(--yellow)}

.nb-card h3,.nb-card h4{font-family:var(--sans);font-weight:800;letter-spacing:-.015em;margin:0 0 6px}
.nb-card h3{font-size:21px}
.nb-card h4{font-size:18px}
.nb-card p{margin:0 0 10px;font-size:14.5px;color:var(--ink-2)}
.nb-card p:last-child{margin-bottom:0}

.nb-cols-2,.nb-cols-3,.nb-cols-4{display:grid;gap:14px}
.nb-cols-2{grid-template-columns:repeat(2,1fr)}
.nb-cols-3{grid-template-columns:repeat(3,1fr)}
.nb-cols-4{grid-template-columns:repeat(4,1fr)}
@media(max-width:900px){.nb-cols-2,.nb-cols-3,.nb-cols-4{grid-template-columns:1fr}}
@media(min-width:600px) and (max-width:900px){.nb-cols-3,.nb-cols-4{grid-template-columns:repeat(2,1fr)}}

/* callout */
.nb-callout{
  border:1.5px solid var(--ink);padding:16px 20px;margin:18px 0;
  background:var(--paper);display:grid;grid-template-columns:40px 1fr;gap:14px;align-items:start;
}
.nb-callout.tip{background:var(--mint)}
.nb-callout.warn{background:var(--blush)}
.nb-callout.info{background:var(--sky)}
.nb-callout .ic{
  width:30px;height:30px;border:1.5px solid var(--ink);background:var(--paper);
  border-radius:50%;display:grid;place-items:center;
  font-family:var(--serif);font-weight:700;font-style:italic;font-size:17px;
}
.nb-callout h5{margin:0 0 3px;font-size:14px;font-weight:800;letter-spacing:.02em;text-transform:uppercase;font-family:var(--mono)}
.nb-callout p{margin:0;font-size:14.5px;line-height:1.5;color:var(--ink)}

/* section heading */
.nb-sh{
  margin:64px 0 22px;display:flex;align-items:baseline;gap:18px;
  border-bottom:1.5px solid var(--ink);padding-bottom:14px;flex-wrap:wrap;
}
.nb-sh .num{font-family:var(--mono);font-size:13px;color:var(--red);font-weight:600;letter-spacing:.08em}
.nb-sh h2{margin:0;font-size:clamp(26px,3.4vw,38px);font-weight:800;letter-spacing:-.025em;line-height:1}
.nb-sh h2 em{font-family:var(--serif);font-style:italic;font-weight:500;color:var(--ink-2)}
.nb-sh .caption{font-family:var(--serif);font-style:italic;color:var(--ink-3);font-size:16px;margin-left:auto}
.nb-sh .more{font-family:var(--mono);font-size:12px;color:var(--ink-2);border-bottom:1px dashed var(--rule-ink);cursor:pointer;text-decoration:none;margin-left:auto}
.nb-sh .more:hover{color:var(--ink);border-color:var(--ink)}
.nb-sh .more+.caption{margin-left:0}
@media(max-width:560px){.nb-sh{margin-top:48px}.nb-sh .caption,.nb-sh .more{margin-left:0}}

.nb-lede{
  font-family:var(--serif);font-style:italic;font-size:21px;line-height:1.5;
  color:var(--ink-2);max-width:820px;margin:0 0 30px;
  border-left:3px solid var(--yellow);padding-left:20px;
}

/* ==== components/breadcrumbs.css ==== */
.nb-crumbs{font-family:var(--mono);font-size:12px;color:var(--ink-3);padding:18px 0;display:flex;gap:8px;text-transform:uppercase;letter-spacing:.1em;flex-wrap:wrap}
.nb-crumbs a{text-decoration:none;color:var(--ink-2);cursor:pointer}
.nb-crumbs a:hover{color:var(--ink)}
.nb-crumbs span.sep{color:var(--rule-ink)}

/* ==== components/footer.css ==== */
.nb-foot{margin-top:80px;border-top:1.5px solid var(--ink);padding:36px 24px;font-family:var(--mono);font-size:11.5px;color:var(--ink-3);background:var(--paper)}
.nb-foot-in{max-width:1240px;margin:0 auto;display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap}
.nb-foot a{color:var(--ink-2);text-decoration:none;margin-right:14px;cursor:pointer}
.nb-foot a:hover{color:var(--ink)}
.nb-foot .stamp2{border:1.5px solid var(--ink);padding:8px 14px;background:var(--yellow);color:var(--ink);font-weight:700;letter-spacing:.14em;border-radius:4px}

/* ==== pages/home.css ==== */
.nb-hero{padding:56px 0 40px;position:relative;max-width:1240px;margin:0 auto;padding-left:24px;padding-right:24px}
.nb-hero h1{font-weight:800;letter-spacing:-.035em;line-height:1.02;margin:0 0 28px;font-size:clamp(40px,7vw,90px);max-width:1100px}
.nb-hero h1 em{font-family:var(--serif);font-style:italic;font-weight:500;color:var(--ink-2)}
.nb-hero h1 .hl{background:var(--yellow);padding:0 .08em;border-radius:4px}
.nb-hero h1 .hl.g{background:var(--mint)}
.nb-hero h1 .hl.p{background:var(--blush)}
.nb-hero h1 .hl.b{background:var(--sky)}

.nb-hero-cta{display:flex;gap:12px;flex-wrap:wrap;margin-top:8px}

.nb-stats{display:grid;grid-template-columns:repeat(4,1fr);gap:0;border:1.5px solid var(--ink);background:var(--paper);margin-top:24px}
.nb-stats>div{padding:20px 24px;border-right:1.5px solid var(--ink);font-family:var(--mono);font-size:10.5px;color:var(--ink-3);text-transform:uppercase;letter-spacing:.12em}
.nb-stats>div:last-child{border-right:0}
.nb-stats strong{display:block;font-family:var(--sans);font-size:36px;font-weight:800;letter-spacing:-.025em;color:var(--ink);margin-top:6px;line-height:1;text-transform:none}
.nb-stats strong em{font-family:var(--serif);font-style:italic;color:var(--blue);font-weight:500}
@media(max-width:780px){
  .nb-stats{grid-template-columns:repeat(2,1fr)}
  .nb-stats>div:nth-child(2){border-right:0}
  .nb-stats>div:nth-child(1),.nb-stats>div:nth-child(2){border-bottom:1.5px solid var(--ink)}
  .nb-stats strong{font-size:28px}
}

.nb-steps{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:8px}
@media(max-width:900px){.nb-steps{grid-template-columns:1fr}}
.nb-step{border:1.5px solid var(--ink);padding:22px 24px;background:var(--paper);position:relative}
.nb-step .n{font-family:var(--mono);font-size:11px;color:var(--red);font-weight:700;letter-spacing:.1em;margin-bottom:10px}
.nb-step h4{font-size:18px;font-weight:800;margin:0 0 8px;letter-spacing:-.015em}
.nb-step p{margin:0;font-size:14px;color:var(--ink-2);line-height:1.5}

.nb-feature-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px}
@media(max-width:700px){.nb-feature-grid{grid-template-columns:1fr}}

.nb-usage-pill{
  display:inline-flex;align-items:center;gap:8px;
  font-family:var(--mono);font-size:12px;color:var(--ink-2);
  padding:6px 12px;border:1.5px solid var(--ink);border-radius:999px;background:var(--paper-2);
}
.nb-usage-pill b{color:var(--ink);font-weight:700}
