/*
  notex.us home page: the chalkboard under the headline. An equation is
  written by hand in chalk; then, glyph by glyph, the chalk straightens into
  typeset math while its LaTeX source is typed out underneath.

  GENERATED by tools/site/hero-board/build.mjs from hero.template.css. Edit the
  template (or the strokes and timings in build.mjs), then run
    node tools/site/hero-board/build.mjs
  which rewrites this file and the board in index.html.

  Linked by index.html only, after style.css. CSS and SVG only: no script, no
  style attributes (the CSP in infra/envs/site/cloudfront.tf). The board is
  decorative (aria-hidden); the caption says in words what it shows.

  The finished picture is the resting state: typeset glyphs visible, chalk
  hidden. Motion is added only under prefers-reduced-motion: no-preference,
  so reduced motion, or no animation support, shows the result and nothing
  moves. Only stroke-dashoffset, transform and opacity animate. It plays once
  and holds; every animation, the chalk dust included, ends before 5 s, so
  WCAG 2.2.2 needs no pause control. The durations are constants in build.mjs,
  which refuses a longer timeline.
*/

.hero-chalk {
  --board: #1f2a25;
  --board-edge: rgb(255 255 255 / 0.05);
  --board-lift: 0 1px 1px rgb(24 35 63 / 0.18), 0 12px 22px -16px rgb(24 35 63 / 0.6);
  --ledge: #b9c0c9;
  --ledge-lip: #d9dee4;
  --chalk: #eeece2;
  --chalk-type: #f8f7f2;

  position: relative;
  margin: 0 0 1.75rem;
}

/* On the blackboard page: a darker board with a faint chalk edge. */
@media (prefers-color-scheme: dark) {
  .hero-chalk {
    --board: #131a17;
    --board-edge: rgb(230 236 231 / 0.11);
    --board-lift: none;
    --ledge: #34413b;
    --ledge-lip: #46544d;
  }
}

.hero-board {
  position: relative;
  aspect-ratio: 720 / 260;
  border-radius: 8px 8px 3px 3px;
  background-color: var(--board);
  /* Slate: eraser smears (long, flat ellipses), a wiped patch or two, a
     diagonal sweep and a vignette. Gradients, not SVG strokes: at 1-3%
     alpha, strokes render differently from browser to browser. */
  background-image:
    radial-gradient(ellipse 27% 6% at 25% 15%, rgb(255 255 255 / 0.04), transparent),
    radial-gradient(ellipse 21% 5% at 75% 20%, rgb(255 255 255 / 0.035), transparent),
    radial-gradient(ellipse 42% 8% at 46% 84%, rgb(255 255 255 / 0.03), transparent),
    radial-gradient(ellipse 34% 26% at 30% 36%, rgb(255 255 255 / 0.05), transparent),
    radial-gradient(ellipse 30% 22% at 72% 70%, rgb(255 255 255 / 0.035), transparent),
    linear-gradient(172deg, transparent 30%, rgb(255 255 255 / 0.03) 48%, transparent 66%),
    radial-gradient(130% 110% at 50% 45%, transparent 55%, rgb(0 0 0 / 0.36));
  box-shadow: inset 0 0 0 1px var(--board-edge), var(--board-lift);
}

/* The chalk tray, and a stick of chalk lying on it. */
.hero-board::after {
  content: "";
  position: absolute;
  left: -0.375rem;
  right: -0.375rem;
  bottom: -0.5rem;
  height: 0.5rem;
  border-radius: 1px 1px 3px 3px;
  background: linear-gradient(var(--ledge-lip), var(--ledge) 45%);
}
.hero-board::before {
  content: "";
  position: absolute;
  z-index: 1;
  right: 9%;
  bottom: -0.25rem;
  width: 1.75rem;
  height: 0.4375rem;
  border-radius: 0.25rem 0.1875rem 0.1875rem 0.25rem;
  background: linear-gradient(#fbfaf5, #dcd9cd);
  transform: rotate(-2deg);
}

.hero-board svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* Phones: a taller board, the SVGs scaled to cover it (preserveAspectRatio
   slice), so the empty sides are cropped and the equation is bigger. */
@media (max-width: 35.99rem) {
  .hero-board { aspect-ratio: 720 / 318; }
}

/* Chalk grain: a static noise tile (grain.svg) as an alpha mask. As an image
   it is rasterized once, so no filter runs per frame. */
.hero-hand {
  -webkit-mask: url(grain.svg) 0 0 / 180px 180px repeat;
  mask: url(grain.svg) 0 0 / 180px 180px repeat;
}
@media (max-width: 35.99rem) {
  .hero-hand {
    -webkit-mask-size: 120px 120px;
    mask-size: 120px 120px;
  }
}
.hero-hand path {
  fill: none;
  stroke: var(--chalk);
  stroke-opacity: 0.92;
  stroke-width: 4.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.hero-type { fill: var(--chalk-type); }
.hero-board .dust { fill: var(--chalk); }

/* Each glyph scales about its own centre when it morphs. */
.hero-board .hw,
.hero-board .ts {
  transform-box: fill-box;
  transform-origin: 50% 50%;
}

.hero-board .hw,
.hero-board .dust circle { opacity: 0; }

.hero-chalk figcaption { margin-top: 1.25rem; }
.hero-chalk figcaption code {
  font-size: 0.8125rem;
  color: var(--ink);
}
.hero-chalk figcaption .c { color: var(--pen); }
.hero-chalk figcaption .w { white-space: nowrap; }

/* Per-stroke timing (--d delay, --l duration) and per-glyph morph values. */
.hero-board .s1 { --d: 0.3s; --l: 0.25s; }
.hero-board .s2 { --d: 0.6s; --l: 0.07s; }
.hero-board .s3 { --d: 0.72s; --l: 0.19s; }
.hero-board .s4 { --d: 0.96s; --l: 0.18s; }
.hero-board .s5 { --d: 1.19s; --l: 0.18s; }
.hero-board .s6 { --d: 1.42s; --l: 0.07s; }
.hero-board .s7 { --d: 1.54s; --l: 0.1s; }
.hero-board .s8 { --d: 1.67s; --l: 0.1s; }
.hero-board .s9 { --d: 1.82s; --l: 0.14s; }
.hero-board .s10 { --d: 2s; --l: 0.15s; }
.hero-board .s11 { --d: 2.18s; --l: 0.12s; }
.hero-board .s12 { --d: 2.35s; --l: 0.11s; }
.hero-board .s13 { --d: 2.49s; --l: 0.11s; }
.hero-board .s14 { --d: 2.65s; --l: 0.1s; }
.hero-board .s15 { --d: 2.77s; --l: 0.1s; }
.hero-board .s16 { --d: 2.92s; --l: 0.23s; }
.hero-board .s17 { --d: 3.2s; --l: 0.11s; }
.hero-board .s18 { --d: 3.34s; --l: 0.08s; }
.hero-board .s19 { --d: 3.44s; --l: 0.09s; }
.hero-board .k1 { --t: 3.84s; --mx: 0.16px; --my: -2.41px; --sx: 0.754; --sy: 0.967; --ix: 1.325; --iy: 1.034; }
.hero-board .k2 { --t: 3.88s; --mx: 2.87px; --my: -15.17px; --sx: 1.511; --sy: 1; --ix: 0.662; --iy: 1; }
.hero-board .k3 { --t: 3.93s; --mx: -2.05px; --my: -0.39px; --sx: 1.059; --sy: 1.238; --ix: 0.945; --iy: 0.808; }
.hero-board .k4 { --t: 3.97s; --mx: 3.28px; --my: -8.24px; --sx: 0.932; --sy: 1.335; --ix: 1.073; --iy: 0.749; }
.hero-board .k5 { --t: 4.02s; --mx: -0.8px; --my: -1.42px; --sx: 0.909; --sy: 0.905; --ix: 1.101; --iy: 1.104; }
.hero-board .k6 { --t: 4.06s; --mx: 1.68px; --my: 0.36px; --sx: 1.429; --sy: 1; --ix: 0.7; --iy: 1; }
.hero-board .k7 { --t: 4.11s; --mx: 0.82px; --my: -0.51px; --sx: 0.806; --sy: 1.018; --ix: 1.24; --iy: 0.983; }
.hero-board .k8 { --t: 4.15s; --mx: -5.4px; --my: 1.72px; --sx: 0.793; --sy: 0.88; --ix: 1.261; --iy: 1.136; }
.hero-board .k9 { --t: 4.2s; --mx: -0.06px; --my: 1.81px; --sx: 0.787; --sy: 0.955; --ix: 1.271; --iy: 1.047; }
.hero-board .k10 { --t: 4.24s; --mx: -0.65px; --my: 1px; --sx: 1.01; --sy: 1.097; --ix: 0.99; --iy: 0.912; }
.hero-board .k11 { --t: 4.29s; --mx: -0.34px; --my: 1.8px; --sx: 1.084; --sy: 0.81; --ix: 0.922; --iy: 1.235; }
.hero-board .k12 { --t: 4.33s; --mx: -1.13px; --my: 5.88px; --sx: 0.898; --sy: 0.927; --ix: 1.114; --iy: 1.078; }
.hero-board .k13 { --t: 4.38s; --mx: -1.44px; --my: 3.31px; --sx: 0.809; --sy: 0.944; --ix: 1.236; --iy: 1.059; }
.hero-board .p1 { --fx: -3px; --fy: 16px; }
.hero-board .p2 { --fx: 4px; --fy: 22px; }
.hero-board .p3 { --fx: -1px; --fy: 11px; }
.hero-board .p4 { --fx: 2px; --fy: 27px; }

@media (prefers-reduced-motion: no-preference) {
  .hero-hand .hw path {
    stroke-dasharray: 1 2;
    animation: chalk-write var(--l) cubic-bezier(0.45, 0.05, 0.35, 1) var(--d) both;
  }
  .hero-board .hw {
    animation:
      chalk-lift 0.55s cubic-bezier(0.5, 0, 0.2, 1) var(--t) both,
      chalk-fade 0.45s ease-in var(--t) both;
  }
  .hero-board .ts {
    animation:
      type-settle 0.55s cubic-bezier(0.2, 0.7, 0.2, 1) var(--t) both,
      type-fade 0.3s ease-out var(--t) both;
  }
  .hero-board .dust circle { animation: dust-fall 0.5s cubic-bezier(0.3, 0.6, 0.5, 1) var(--t) both; }
  .hero-board .dust .p2,
  .hero-board .dust .p4 { animation-duration: 0.55s; }
  .hero-chalk figcaption code { animation: caption-in 0.4s ease-out 3.74s both; }
}

/* Wide enough for the source on one line: it is typed out, left to right,
   while the chalk turns into type. A cover in the page colour slides off it,
   one character per step. Narrower, where it wraps, it fades in instead. */
@media (prefers-reduced-motion: no-preference) and (min-width: 36rem) {
  .hero-chalk figcaption code {
    position: relative;
    display: inline-block;
    overflow: hidden;
    vertical-align: top;
    white-space: nowrap;
    animation: none;
  }
  .hero-chalk figcaption code::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--paper);
    animation: source-type 0.84s steps(49) 3.74s both;
  }
}

@keyframes chalk-write { from { stroke-dashoffset: 1.01; } to { stroke-dashoffset: 0; } }
@keyframes chalk-lift { to { transform: translate(var(--mx), var(--my)) scale(var(--sx), var(--sy)); } }
@keyframes chalk-fade { from { opacity: 1; } to { opacity: 0; } }
@keyframes type-settle { from { transform: translate(calc(-1 * var(--mx)), calc(-1 * var(--my))) scale(var(--ix), var(--iy)); } }
@keyframes type-fade { from { opacity: 0; } }
@keyframes dust-fall {
  0% { opacity: 0; }
  12% { opacity: 0.7; }
  100% { opacity: 0; transform: translate(var(--fx), var(--fy)); }
}
@keyframes caption-in { from { opacity: 0; } }
@keyframes source-type { to { transform: translateX(100%); } }

/* It is a picture: keep its colours in forced-colours mode, and leave it out
   of print (a dark board prints badly without backgrounds). */
@media (forced-colors: active) {
  .hero-board { forced-color-adjust: none; }
}

@media print {
  .hero-chalk { display: none; }
}
