/* Brand surface — warm Peach canvas with the signature Ink dot grid, plus the
   brand animation set. The "student poster" backdrop.

   VENDORED DEVIATION (see components/ds/README.md): upstream styles `body`
   directly. The student engine (app/page.tsx + app/spm-ui.css) owns `body` in
   this app, so every rule that used to be global is scoped to a `.ks-app`
   wrapper. Only the @keyframes stay global — CSS animation names cannot be
   scoped, and the component CSS references them by name.

   Upstream's `@import './fonts.css'` and `@import './tokens.css'` are dropped:
   the fonts already load from the root layout's <link>, and app/teacher/layout.tsx
   imports tokens.css → base.css → components.css explicitly, in that order.

   Upstream's gallery chrome (.ks-gallery-nav, .ks-gallery-root, …) is dropped —
   it styles the design system's own demo page, not the product. */

.ks-app,
.ks-app *,
.ks-app *::before,
.ks-app *::after { box-sizing: border-box; }

/* The student engine's stylesheet (app/spm-ui.css, imported globally via
   app/globals.css) pins `html, body { height: 100%; overflow: hidden }` for its
   own internal scroll containers. The teacher surface is a normal scrolling
   document — whenever the teacher canvas is mounted, undo the lock. */
html:has(.ks-app),
body:has(.ks-app) {
  height: auto;
  overflow: visible;
}

.ks-app {
  /* The canvas. `min-height: 100dvh` replaces what `body` used to give for
     free — without it the dot grid stops at the end of the content. */
  min-height: 100dvh;
  margin: 0;
  font-family: var(--ks-font-body);
  color: var(--ks-ink);
  background:
    radial-gradient(circle at 1px 1px, rgba(16, 16, 20, 0.07) 1px, transparent 0) 0 0 / 22px 22px,
    var(--surface-base);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

.ks-app a { color: var(--ks-blue); text-decoration: none; }
/* Hover keeps Blue (4.5:1 on Haze — AA); Flame is only 3.3:1, so signal with underline, not recolour. */
.ks-app a:hover { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }

/* Brand animation set (RecordButton pulse, spinners, floating stickers, waveforms,
   shimmer). Global by necessity — @keyframes has no scope. The names are all
   `ks`-prefixed and do not collide with anything in app/spm-ui.css. */
@keyframes ksPulse  { 0% { transform: scale(1); opacity: .5; } 70% { transform: scale(2); opacity: 0; } 100% { opacity: 0; } }
@keyframes ksSpin   { to { transform: rotate(360deg); } }
@keyframes ksFloat  { 0%, 100% { transform: translateY(0) rotate(var(--r, 0deg)); } 50% { transform: translateY(-9px) rotate(var(--r, 0deg)); } }
@keyframes ksWave   { 0%, 100% { transform: scaleY(.35); } 50% { transform: scaleY(1); } }
@keyframes ksShimmer{ 0% { background-position: -260px 0; } 100% { background-position: 260px 0; } }

/* Reduced motion (FOUNDATIONS §08) — collapse all loops and transitions to a
   static state; loading is still conveyed by the label ("Analysing…").
   Scoped to `.ks-app` so it cannot alter the student engine's motion. */
@media (prefers-reduced-motion: reduce) {
  .ks-app,
  .ks-app * { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
}
