/**
 * Design tokens for coaching.toys.
 *
 * This is the single place where colour, type and spacing are defined. Nothing
 * else in the codebase may hardcode a colour or a font.
 *
 * Every colour here is verified against WCAG 2.2 AA by scripts/contrast.ts.
 * If you change a value, run `deno task palette` — a failing ratio is a bug.
 */

:root {
  /* --- Surfaces -------------------------------------------------------- */

  /* Middle grey. Deliberately inside the narrow band where BOTH white (4.61:1)
     and pure black (4.56:1) text stay AA-readable. Moving it in either
     direction breaks one of the two. */
  --c-canvas: #757575;

  /* The "sheet of paper" every tool and content block sits on. */
  --c-paper: #ffffff;
  --c-line: #e0e0e0;

  /* --- Text ------------------------------------------------------------ */

  --c-ink: #1a1a1a; /* on paper: 17.4:1 */
  --c-ink-muted: #595959; /* on paper: 7.0:1  — secondary text, captions */
  --c-ink-strong: #000000; /* required for dark text ON CANVAS (4.56:1) */
  --c-ink-inverse: #ffffff; /* text on canvas or on a solid fill */

  /* --- Focus ----------------------------------------------------------- */

  /* A dual ring: blue core plus white halo. The halo is what keeps focus
     visible on the grey canvas as well as on white paper. */
  --c-focus: #1a5fb4;
  --c-focus-halo: #ffffff;
  --focus-ring: 0 0 0 2px var(--c-focus-halo), 0 0 0 4px var(--c-focus);

  /* --- Semantic actions ------------------------------------------------ */

  /* Colour is never the only signal: confirm/abort always carry a label or
     icon as well, per the accessibility rules. */
  --c-confirm: #2c6e49;
  --c-confirm-hover: #235a3b;
  --c-abort: #b3261e;
  --c-abort-hover: #8f1e18;

  /* --- The muted rainbow ----------------------------------------------- */

  /* One hue per tool category. Each hue has two roles:
       -solid  load-bearing. Clears 4.5:1 on paper and carries white labels,
               so it is safe for text, icons and filled buttons.
       -tint   decorative. Card headers, chips, backgrounds. Keeps ink readable
               on top of it. Not for text on paper, where it would all but
               vanish — the one exception is the wordmark on the grey canvas,
               where the tints are the readable end of the palette and the
               solids are not. scripts/contrast.ts checks both directions. */

  --c-rose: #b0374a;
  --c-rose-tint: #f6dde1;

  --c-orange: #9e5026;
  --c-orange-tint: #f9e8db;

  --c-amber: #7a6011;
  --c-amber-tint: #f3e8c9;

  --c-green: #3c6e32;
  --c-green-tint: #e0edd8;

  --c-teal: #1e6e6b;
  --c-teal-tint: #d9ebea;

  --c-blue: #2a5fa5;
  --c-blue-tint: #dce6f4;

  --c-indigo: #5b4e9e;
  --c-indigo-tint: #e4e1f3;

  --c-plum: #8b3f7e;
  --c-plum-tint: #f1ddee;

  /* --- Elevation ------------------------------------------------------- */

  /* The paper-on-grey lift. Subtle: a sheet, not a floating panel. */
  --shadow-paper: 0 1px 2px rgb(0 0 0 / 12%), 0 4px 12px rgb(0 0 0 / 10%);
  --shadow-raised: 0 2px 4px rgb(0 0 0 / 14%), 0 8px 24px rgb(0 0 0 / 12%);
  --radius: 6px;

  /* --- Type ------------------------------------------------------------ */

  /* Self-hosted, openly licensed. Never a font CDN — that would leak visitor
     IPs and break the no-third-party rule. The stack falls back to system
     fonts so nothing depends on the webfont loading. */
  --font-sans: "Atkinson Hyperlegible", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, monospace;

  /* Fluid, mobile-first. Scales with the viewport without a media query. */
  --text-sm: clamp(0.83rem, 0.8rem + 0.2vw, 0.9rem);
  --text-base: clamp(1rem, 0.95rem + 0.25vw, 1.1rem);
  --text-lg: clamp(1.2rem, 1.1rem + 0.5vw, 1.45rem);
  --text-xl: clamp(1.5rem, 1.3rem + 1vw, 2rem);
  --text-2xl: clamp(1.9rem, 1.5rem + 2vw, 3rem);

  /* --- Space ----------------------------------------------------------- */

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-12: 3rem;

  /* Minimum hit target for touch, per WCAG 2.2 target size. */
  --tap-target: 44px;
}

/* Motion is opt-out, per WCAG 2.2 AA. */
@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;
  }
}

/**
 * The frame and the shared components.
 *
 * Every value here comes from tokens.css. No colour, font or spacing is
 * hardcoded — changing the palette must never mean editing this file.
 */

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

/* The UA rule for [hidden] is display:none at the lowest possible weight, so
   any component rule setting display beats it and the element stays visible.
   Toys hide elements by setting .hidden — it has to actually hide them. */
[hidden] {
  display: none !important;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--c-canvas);
  color: var(--c-ink-inverse);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: 1.55;
}

:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: 3px;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: var(--space-4);
  z-index: 10;
  padding: var(--space-2) var(--space-4);
  background: var(--c-paper);
  color: var(--c-ink);
  border-radius: var(--radius);
  box-shadow: var(--shadow-raised);
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: none;
}

/* --- Frame ------------------------------------------------------------- */

.frame {
  max-width: 68rem;
  margin: 0 auto;
  padding: var(--space-6) var(--space-4) var(--space-12);
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  min-height: 100dvh;
}

.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-6);
}

.brand {
  font-weight: 700;
  font-size: var(--text-lg);
  letter-spacing: -0.01em;
}

/* The wordmark's rainbow: the eight category hues in their palette order, then
   back down through the tints, drifting right to left. A logotype, which WCAG
   1.4.3 exempts from the contrast rule — the solids sit at about 1.3:1 on the
   grey canvas, where they are built for paper. See scripts/contrast.ts.

   background-size is what makes this work and must stay in step with the last
   colour stop. A gradient has no intrinsic size, so the default `auto` sizes
   the image to the element — here the word, about 4.2em — and every stop past
   that edge is outside the image and never painted. Sizing the tile to the
   full 8em period is what lets all sixteen colours through. The animation
   travels exactly that period, which is what keeps the loop seamless.

   All of it in em, so the rainbow holds its proportions at every font size the
   header takes. */
.brand-hue {
  background-size: 8em 100%;
  background-image: repeating-linear-gradient(
    90deg,
    var(--c-rose) 0,
    var(--c-orange) 0.5em,
    var(--c-amber) 1em,
    var(--c-green) 1.5em,
    var(--c-teal) 2em,
    var(--c-blue) 2.5em,
    var(--c-indigo) 3em,
    var(--c-plum) 3.5em,
    var(--c-plum-tint) 4em,
    var(--c-indigo-tint) 4.5em,
    var(--c-blue-tint) 5em,
    var(--c-teal-tint) 5.5em,
    var(--c-green-tint) 6em,
    var(--c-amber-tint) 6.5em,
    var(--c-orange-tint) 7em,
    var(--c-rose-tint) 7.5em,
    var(--c-rose) 8em
  );
  animation: brand-drift 12s linear infinite;
}

/* Only paint the text with it where clipping to the glyphs is supported.
   Without the guard an unsupporting browser would show a transparent word. */
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .brand-hue {
    background-clip: text;
    -webkit-background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
  }
}

@keyframes brand-drift {
  from {
    background-position: 0 0;
  }

  to {
    background-position: -8em 0;
  }
}

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

/* Forced colours drop background images, which would leave the word invisible.
   Hand it back to the system's own text colour. */
@media (forced-colors: active) {
  .brand-hue {
    background: none;
    color: CanvasText;
    -webkit-text-fill-color: currentcolor;
  }
}

.site-nav {
  display: flex;
  gap: var(--space-4);
  flex: 1;
}

.lang-nav {
  display: flex;
  gap: var(--space-2);
  font-size: var(--text-sm);
}

/* Text on the canvas must be white or true black — the soft ink fails AA here. */
.site-header a,
.site-footer a,
.site-footer p {
  color: var(--c-ink-inverse);
}

.site-header a {
  text-decoration: none;
}

.site-header a:hover,
.site-footer a:hover {
  text-decoration: underline;
}

.site-nav [aria-current="page"] {
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 2px;
}

.lang-nav .current {
  color: var(--c-ink-strong);
  font-weight: 600;
}

main {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

.site-footer {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
  font-size: var(--text-sm);
}

.site-footer p {
  margin: 0;
}

.section-heading {
  margin: 0;
  font-size: var(--text-xl);
  color: var(--c-ink-inverse);
}

/* --- Paper --------------------------------------------------------------
   The core metaphor: content sits on a white sheet on the grey canvas. */

.paper {
  background: var(--c-paper);
  color: var(--c-ink);
  border-radius: var(--radius);
  box-shadow: var(--shadow-paper);
  padding: clamp(var(--space-6), 4vw, var(--space-12));
}

.hero h1 {
  margin: 0 0 var(--space-3);
  font-size: var(--text-2xl);
  line-height: 1.15;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.lede {
  margin: 0;
  color: var(--c-ink-muted);
  font-size: var(--text-lg);
  max-width: 60ch;
}

.prose {
  max-width: 68ch;
}

.prose h1 {
  margin: 0 0 var(--space-3);
  font-size: var(--text-2xl);
  line-height: 1.15;
  letter-spacing: -0.02em;
}

.prose h2 {
  margin: var(--space-8) 0 var(--space-2);
  font-size: var(--text-lg);
}

.prose p,
.prose ul {
  margin: 0 0 var(--space-4);
}

.prose .lede {
  margin-bottom: var(--space-6);
}

/* The documentation runs to twenty-five tools, so the third level has to carry
   its own weight: h2 opens a category, h3 names a tool. The rule above each h2
   is what makes the categories findable when scrolling. */
.prose h3 {
  margin: var(--space-6) 0 var(--space-2);
  font-size: var(--text-base);
  color: var(--hue, var(--c-ink));
}

.prose h2 + h3 {
  margin-top: var(--space-4);
}

.prose hr {
  margin: var(--space-8) 0;
  border: 0;
  border-top: 1px solid var(--c-line);
}

.prose ul {
  padding-left: var(--space-5);
}

.prose li {
  margin-bottom: var(--space-2);
}

/* A nested list is the contents list; it should read as a group, not as a
   second helping of bullets. */
.prose li > ul {
  margin: var(--space-2) 0 0;
}

/* The documentation is the first page with links in its body. --c-blue is the
   palette's verified 4.5:1-on-paper hue; the underline stays, so the link is
   never signalled by colour alone. */
.prose a {
  color: var(--c-blue);
  font-weight: 600;
}

.prose a:hover {
  text-decoration-thickness: 2px;
}

.prose code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--c-line);
  border-radius: 3px;
  padding: 0.1em 0.35em;
}

.prose pre {
  margin: 0 0 var(--space-4);
  padding: var(--space-4);
  background: var(--c-line);
  border-radius: var(--radius);
  overflow-x: auto;
}

/* The block already has the background; the span inside must not repeat it. */
.prose pre code {
  background: none;
  padding: 0;
}

/* --- Catalogue ---------------------------------------------------------- */

.catalogue {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

.category-name {
  margin: 0 0 var(--space-3);
  font-size: var(--text-lg);
  color: var(--c-ink-inverse);
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

/* The hue tags the category without carrying meaning on its own — the name is
   always right next to it. */
.category-name::before {
  content: "";
  width: 0.85rem;
  height: 0.85rem;
  border-radius: 3px;
  background: var(--hue);
  border: 2px solid var(--hue-tint);
  flex: none;
}

.toy-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
  gap: var(--space-4);
}

.toy-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  height: 100%;
  padding: var(--space-6);
  background: var(--c-paper);
  color: var(--c-ink);
  text-decoration: none;
  border-radius: var(--radius);
  border-top: 4px solid var(--hue);
  box-shadow: var(--shadow-paper);
  transition: transform 140ms ease, box-shadow 140ms ease;
}

.toy-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-raised);
}

.toy-title {
  font-weight: 700;
  font-size: var(--text-lg);
}

.toy-summary {
  color: var(--c-ink-muted);
  font-size: var(--text-sm);
  flex: 1;
}

.toy-cta {
  color: var(--hue);
  font-weight: 600;
  font-size: var(--text-sm);
}

.toy-card:hover .toy-cta {
  text-decoration: underline;
}

.empty {
  color: var(--c-ink-inverse);
}

/* --- Toy shell ---------------------------------------------------------- */

.toy-header {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: var(--space-8);
}

.toy-category {
  margin: 0 0 var(--space-1);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--hue);
}

.toy-header h1 {
  margin: 0 0 var(--space-2);
  font-size: var(--text-xl);
  letter-spacing: -0.01em;
}

.toy-summary {
  margin: 0;
  color: var(--c-ink-muted);
}

/* When the stage is fullscreen it becomes the whole screen, so it has to bring
   its own background and padding — the page around it is gone. Keyed off the
   class, not :fullscreen, because the same look has to work on the CSS
   fallback we use where the Fullscreen API is missing (Safari on iPhone). */
.toy.is-fullscreen {
  background: var(--c-paper);
  padding: var(--space-8);
  display: flex;
  flex-direction: column;
  border-radius: 0;
}

.toy.is-fullscreen .toy-stage {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* The fallback: no real fullscreen, so cover the viewport ourselves. dvh
   rather than vh so Safari's collapsing URL bar can't cut off the bottom, and
   the safe-area insets keep content clear of the notch and home indicator. */
.toy.is-faux-fullscreen {
  position: fixed;
  inset: 0;
  z-index: 50;
  width: 100%;
  height: 100dvh;
  margin: 0;
  overflow: auto;
  box-shadow: none;
  padding: max(var(--space-8), env(safe-area-inset-top))
    max(var(--space-8), env(safe-area-inset-right))
    max(var(--space-8), env(safe-area-inset-bottom))
    max(var(--space-8), env(safe-area-inset-left));
}

/* The page behind the overlay must not scroll under it. */
body.has-faux-fullscreen {
  overflow: hidden;
}

/* Source credit for a toy based on a named method. Quiet, but always present:
   the idea it is built on is named and linked, per the project's rules. */
.toy-credit {
  margin-top: var(--space-8);
  padding-top: var(--space-4);
  border-top: 1px solid var(--c-line);
}

.toy-credit p {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--c-ink-muted);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.toy-credit a {
  color: var(--hue);
  font-weight: 600;
}

.toy.is-fullscreen .toy-credit {
  margin-top: var(--space-4);
}

/* --- Controls ----------------------------------------------------------- */

.btn {
  font: inherit;
  font-weight: 600;
  color: var(--c-ink-inverse);
  background: var(--c-ink);
  border: 0;
  border-radius: var(--radius);
  padding: 0 var(--space-6);
  min-height: var(--tap-target);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  cursor: pointer;
  transition: background-color 120ms ease;
}

.btn-lg {
  font-size: var(--text-lg);
  min-height: 56px;
  padding: 0 var(--space-8);
}

.btn-confirm {
  background: var(--c-confirm);
}

.btn-confirm:hover {
  background: var(--c-confirm-hover);
}

.btn-abort {
  background: var(--c-abort);
}

.btn-abort:hover {
  background: var(--c-abort-hover);
}

/* Disabled controls stay visible and labelled so the layout never jumps — they
   just read as inert. WCAG exempts inactive controls from the contrast rule. */
.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.btn:disabled:hover {
  background: var(--c-ink);
}

.btn-confirm:disabled:hover {
  background: var(--c-confirm);
}

.btn-abort:disabled:hover {
  background: var(--c-abort);
}

.btn-quiet {
  font: inherit;
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--c-ink-muted);
  background: transparent;
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  padding: 0 var(--space-4);
  min-height: var(--tap-target);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
}

.btn-quiet:hover {
  background: var(--hue-tint, var(--c-line));
  color: var(--c-ink);
}

.btn-quiet svg {
  width: 1.1em;
  height: 1.1em;
  flex: none;
}

.chip {
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--c-ink);
  background: var(--hue-tint);
  border: 1px solid transparent;
  border-radius: 999px;
  min-height: 36px;
  min-width: 44px;
  padding: 0 var(--space-3);
  cursor: pointer;
}

.chip:hover {
  border-color: var(--hue);
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--c-ink-muted);
}

.field input,
.field select {
  font: inherit;
  font-size: var(--text-base);
  font-weight: 400;
  color: var(--c-ink);
  background: var(--c-paper);
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  min-height: var(--tap-target);
  padding: 0 var(--space-3);
  min-width: 6rem;
}

.field input:disabled {
  background: #f3f3f3;
  color: var(--c-ink-muted);
}
