/* ==========================================================================
   Ycotes — Design Tokens
   Palette derived from the mascot: yellow ground, black outline, red mouth.
   Governing rule: DARK CANVAS, YELLOW AS LIGHT SOURCE, RED FOR ACTION ONLY.
   Yellow at large surface area reads cheap; yellow as emitted light reads premium.
   ========================================================================== */

:root {
  /* --- Brand, straight from the logo ---------------------------------- */
  --y-yellow:        #F0C64A;   /* primary  — background yellow           */
  --y-yellow-soft:   #F6DC8F;   /* banana body — secondary surfaces       */
  --y-black:         #1C1C1C;   /* outline/sunglasses black               */
  --y-red:           #E8544A;   /* mouth red — CTAs and alerts ONLY       */
  --y-white:         #FFFFFF;   /* glove white                            */

  /* Tints/shades. Generated, not eyeballed, so hover states stay on-hue. */
  --y-yellow-900:    #4A3C10;
  --y-yellow-700:    #8A6F1E;
  --y-yellow-500:    #F0C64A;
  --y-yellow-300:    #F5D887;
  --y-red-700:       #B23A32;
  --y-red-300:       #F08A83;

  /* Correct/pass green. Not a brand colour and never used as one — it exists
     only where "right vs wrong" has to be legible at a glance (quiz review,
     lecture ticks). Desaturated so it never competes with the yellow. */
  --y-green:         #3E9E5F;

  /* --- Canvas --------------------------------------------------------- */
  /* Not pure black. #0D0D0F carries a hint of blue so yellow reads warm
     against it; pure #000 makes yellow look dirty.                       */
  --surface-0:       #0D0D0F;   /* page ground                            */
  --surface-1:       #16161A;   /* raised card                            */
  --surface-2:       #212127;   /* hover / input                          */
  --surface-line:    #2E2E36;   /* hairline borders                       */

  --text-hi:         #F7F7F8;   /* headings                               */
  --text-mid:        #B4B4BE;   /* body                                   */
  --text-lo:         #7C7C88;   /* captions, meta                         */

  /* --- Type ------------------------------------------------------------
     Research finding: template sites run hero:body at ~2.5:1 on system-ui
     and read generic. Committed sites run >= 3.5:1 and vary WEIGHT rather
     than shouting. Vercel sets its 64px H1 at font-normal. We do the same:
     large and calm beats medium and bold.                                */
  --font-display: "Clash Display", "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
  --font-body:    "Inter", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono:    "JetBrains Mono", ui-monospace, "SF Mono", monospace;

  /* Fluid scale. clamp() so the 4:1 hero:body ratio holds at every width
     without a single media query.                                        */
  --fs-hero:    clamp(2.75rem, 1.6rem + 5.6vw, 4.5rem);   /* 44 -> 72px   */
  --fs-h2:      clamp(2rem,    1.4rem + 2.8vw, 3rem);     /* 32 -> 48px   */
  --fs-h3:      clamp(1.375rem, 1.15rem + 1.1vw, 1.75rem);
  --fs-body-lg: clamp(1.0625rem, 1rem + 0.3vw, 1.125rem); /* 17 -> 18px   */
  --fs-body:    1rem;
  --fs-sm:      0.875rem;
  --fs-xs:      0.75rem;

  --lh-tight:   1.04;   /* hero — tight enough to read as one mass        */
  --lh-snug:    1.22;
  --lh-body:    1.65;   /* long-form notes pages need real leading        */

  --tracking-hero: -0.03em;
  --tracking-body:  0;
  --tracking-eyebrow: 0.14em;

  /* --- Space: 4px base ------------------------------------------------
     The scale must contain EVERY step any stylesheet references. An undefined
     custom property does not fall back — it invalidates the whole declaration
     at computed-value time, so `padding: var(--s-5) var(--s-6)` silently
     becomes no padding at all. That is invisible in review and only shows up
     as text jammed against a border. --s-5 was missing and cost 17 broken
     declarations across six files. */
  --s-1: 0.25rem;  --s-2: 0.5rem;   --s-3: 0.75rem;  --s-4: 1rem;
  --s-5: 1.25rem;  --s-6: 1.5rem;   --s-7: 1.75rem;  --s-8: 2rem;
  --s-10: 2.5rem;  --s-12: 3rem;    --s-16: 4rem;    --s-20: 5rem;
  --s-24: 6rem;    --s-32: 8rem;    --s-40: 10rem;

  /* Applied to BOTH sides of every section, so this value is doubled at every
     seam. At the old 10rem two consecutive sections put ~300px of empty canvas
     between them on every page of the site — measured, not guessed. 4.5rem
     gives a ~145px seam, which still reads as a deliberate pause without the
     reader wondering whether something failed to load. */
  --section-y: clamp(2rem, 1rem + 3.4vw, 4.5rem);

  /* --- Layout --------------------------------------------------------- */
  --measure:      68ch;    /* max line length for readable body copy      */
  --container:    1200px;
  --container-wide: 1440px;
  --gutter:       clamp(1rem, 0.5rem + 2vw, 2.5rem);
  --radius-sm: 6px;  --radius: 12px;  --radius-lg: 20px;  --radius-pill: 999px;

  /* --- Elevation ------------------------------------------------------
     On a dark canvas, shadow alone is invisible. Depth comes from a
     lifted top hairline plus a yellow glow used sparingly.               */
  --shadow-card:  0 1px 0 0 rgb(255 255 255 / 0.06) inset,
                  0 12px 32px -12px rgb(0 0 0 / 0.7);
  --glow-yellow:  0 0 0 1px rgb(240 198 74 / 0.32),
                  0 8px 40px -8px rgb(240 198 74 / 0.28);
  --glow-red:     0 8px 32px -8px rgb(232 84 74 / 0.42);

  /* --- Motion ---------------------------------------------------------
     Eases lifted from production bundles (Anthropic, Linear). power3.out
     is the house curve: fast departure, long settle — it carries momentum
     instead of the uniform ease-out that makes templates feel dead.      */
  --ease-out:    cubic-bezier(0.16, 1, 0.3, 1);      /* ~ power3.out      */
  --ease-out-2:  cubic-bezier(0.33, 1, 0.68, 1);     /* ~ power2.out      */
  --ease-inout:  cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);  /* overshoot — CTAs  */

  --dur-fast: 160ms;  --dur: 320ms;  --dur-slow: 640ms;  --dur-reveal: 800ms;

  --stagger: 80ms;    /* Linear's phrase-reveal cadence                   */

  --z-nav: 100;  --z-dropdown: 200;  --z-modal: 300;  --z-toast: 400;
}

/* --------------------------------------------------------------------------
   Light surfaces. The student side (notes, long reading) is easier on the
   eyes light; the business side stays dark. Scope with .theme-light.
   -------------------------------------------------------------------------- */
/* Ink accent. On dark, the brand yellow IS the accent. On light it is close to
   unreadable — #F0C64A on #FFFDF7 is roughly 1.5:1, well under the 4.5:1 text
   minimum — so text switches to a deep amber while the yellow stays available
   for fills and borders, where contrast rules do not apply. Every eyebrow,
   inline link and accent word uses this token rather than --y-yellow. */
:root { --accent-ink: var(--y-yellow); }

.theme-light {
  --surface-0:    #FFFDF7;   /* warm white — sits under yellow correctly  */
  --surface-1:    #FFFFFF;
  --surface-2:    #FBF4E2;
  --surface-line: #E8E2D2;
  --text-hi:      #16161A;
  --text-mid:     #45454F;
  --text-lo:      #6B6B78;
  --accent-ink:   #8A6100;   /* ~5.6:1 on --surface-0. Passes AA.          */
  --shadow-card:  0 1px 2px rgb(28 28 28 / 0.04), 0 12px 28px -14px rgb(28 28 28 / 0.16);
  --glow-yellow:  0 0 0 1px rgb(240 198 74 / 0.55),
                  0 8px 30px -10px rgb(240 198 74 / 0.45);
}

/* --------------------------------------------------------------------------
   Accessibility guards. Both are things production sites ship and template
   sites skip — they are not optional.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  /* Anything staged for a GSAP reveal must be forced visible, or reduced
     motion users get a blank page. */
  [data-reveal] { opacity: 1 !important; filter: none !important; transform: none !important; }
}

/* No-JS / GSAP-failed fallback. Paired with the guard in motion.js. */
.no-js [data-reveal] { opacity: 1; filter: none; transform: none; }

:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--y-yellow);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

::selection { background: var(--y-yellow); color: var(--y-black); }
