@property --accent {
  syntax: "<color>";
  inherits: true;
  initial-value: #e8742a;
}

:root {
  --desk: #1a1612;
  --paper: #f3ecdd;
  --ink: #2a241e;
  --graphite: #4b453e;
  --muted: #847968;
  --accent: #e8742a;

  --hand: "Caveat", cursive;
  --mono: "DM Mono", ui-monospace, monospace;
  --display: "Shrikhand", Georgia, serif;

  /* set from JS on resize */
  --pw: 360px;
  --ph: 400px;
  --cy: 45%;

  --inset: 18px;

  /* paper tooth: multiplied into the page background and into each piece */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.45 0 0 0 0 0.38 0 0 0 0 0.3 0 0 0 0.275 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  background: var(--desk);
  color: var(--ink);
  font-family: var(--mono);
}

body {
  background:
    radial-gradient(ellipse at 50% 0%, #2a231c 0%, transparent 70%),
    var(--desk);
}

.defs { position: absolute; }

/* ---------- the page ---------- */

.page {
  position: fixed;
  inset: var(--inset);
  overflow: hidden;
  border-radius: 6px 6px 14px 14px;
  background:
    var(--grain),
    radial-gradient(ellipse at 50% 45%, transparent 55%, rgba(120, 88, 48, 0.16) 100%),
    var(--paper);
  background-blend-mode: multiply, normal;
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.5),
    0 40px 90px rgba(0, 0, 0, 0.6),
    inset 0 -2px 0 rgba(0, 0, 0, 0.08);
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  transition: transform 1.2s cubic-bezier(.2, .8, .2, 1), opacity 1s ease;
}

.loading .page { opacity: 0; transform: translateY(24px) rotate(-0.6deg); }

/* spiral binding, sits over the top edge of the page */
.spiral {
  position: fixed;
  z-index: 10;
  top: calc(var(--inset) - 14px);
  left: calc(var(--inset) + 40px);
  right: calc(var(--inset) + 40px);
  height: 36px;
  pointer-events: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='36'%3E%3Cellipse cx='15' cy='27' rx='4' ry='3.6' fill='%23251f19'/%3E%3Cpath d='M13 28 C 8 18, 8 6, 15 3.5 C 21 1.5, 23 9, 19 15' fill='none' stroke='%23181512' stroke-width='3.6' stroke-linecap='round'/%3E%3Cpath d='M13 28 C 8 18, 8 6, 15 3.5 C 21 1.5, 23 9, 19 15' fill='none' stroke='%23a29d95' stroke-width='2' stroke-linecap='round'/%3E%3Cpath d='M10.5 18 C 10 12, 11 7, 14 5' fill='none' stroke='%23e6e2db' stroke-width='0.8' stroke-linecap='round'/%3E%3C/svg%3E") repeat-x center / 30px 36px;
}

/* ---------- hand-drawn line boil ---------- */

.boil { animation: boil 0.42s steps(1) infinite; }

@keyframes boil {
  0%   { filter: url(#boil-0); }
  33%  { filter: url(#boil-1); }
  66%  { filter: url(#boil-2); }
}

/* ---------- atmosphere ---------- */

/* The watercolor shape (radial falloff run through the #wash displacement) is pre-rendered
   by JS into --wash-mask, so a color change only repaints a flat fill. Box is 160% of the
   pw*2.2 x ph*1.7 wash to cover the displacement filter's region. */
.wash {
  position: absolute;
  left: 50%;
  top: var(--cy);
  width: calc(var(--pw) * 2.2 * 1.6);
  height: calc(var(--ph) * 1.7 * 1.6);
  translate: -50% -50%;
  background: var(--accent);
  -webkit-mask: var(--wash-mask) center / 100% 100% no-repeat;
  mask: var(--wash-mask) center / 100% 100% no-repeat;
  opacity: 0.32;
  mix-blend-mode: multiply;
  transition: --accent 0.9s ease;
  pointer-events: none;
}

/* Pencil construction lines. JS pre-renders each of the 3 boil frames to an image; the
   frames are flipped with a compositor-only opacity animation in sync with .boil. */
.guides { position: absolute; inset: 0; pointer-events: none; }
.ticks-wheel { position: absolute; width: 0; height: 0; will-change: transform; }
.boil-frames > img {
  position: absolute;
  opacity: 0;
  will-change: opacity;
  animation: boil-frame 0.42s step-end infinite;
}
.boil-frames > img:nth-child(2) { animation-delay: -0.28s; }
.boil-frames > img:nth-child(3) { animation-delay: -0.14s; }
@keyframes boil-frame {
  0%      { opacity: 1; }
  33.333% { opacity: 0; }
  100%    { opacity: 0; }
}

.ghost-title {
  position: absolute;
  left: 50%;
  top: calc(var(--cy) - var(--ph) * 0.08);
  translate: -50% -50%;
  font-family: var(--display);
  font-size: clamp(72px, 15vw, 250px);
  line-height: 1;
  white-space: nowrap;
  color: transparent;
  -webkit-text-stroke: 1.4px var(--accent);
  opacity: 0.28;
  pointer-events: none;
  transition: opacity 0.35s ease, transform 0.6s cubic-bezier(.2, .8, .2, 1), --accent 0.9s ease;
}
.ghost-title.swap { opacity: 0; transform: translateY(18px) rotate(-1.5deg); }

/* ---------- the wheel ---------- */

.wheel { position: absolute; inset: 0; }

.piece, .piece-shade {
  position: absolute;
  left: 50%;
  top: var(--cy);
  width: var(--pw);
  height: var(--ph);
  margin-left: calc(var(--pw) / -2);
  margin-top: calc(var(--ph) / -2);
  will-change: transform, opacity;
}
.piece {
  border: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.piece-shade { pointer-events: none; }
.piece:focus-visible { outline: 2px dashed var(--graphite); outline-offset: 8px; border-radius: 12px; }

.piece > *, .piece-shade > * {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
  -webkit-user-drag: none;
}

/* off-center: graphite study of the piece */
.sketch {
  filter: grayscale(1) contrast(1.55) brightness(1.12);
  mix-blend-mode: multiply;
  opacity: 0.78;
}

/* pencil hatching clipped to the piece silhouette */
.hatch {
  background:
    repeating-linear-gradient(-38deg, rgba(42, 36, 30, 0.75) 0 1px, transparent 1px 6px),
    repeating-linear-gradient(52deg, rgba(42, 36, 30, 0.35) 0 1px, transparent 1px 11px);
  -webkit-mask: var(--src) center / contain no-repeat;
  mask: var(--src) center / contain no-repeat;
  mix-blend-mode: multiply;
  opacity: 0.32;
}

/* center: paint blooms out through a splat-shaped mask */
.paint {
  -webkit-mask-image: var(--splat);
  mask-image: var(--splat);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: 50% 46%;
  mask-position: 50% 46%;
  -webkit-mask-size: var(--bloom, 0%) var(--bloom, 0%);
  mask-size: var(--bloom, 0%) var(--bloom, 0%);
}

/* paper tooth over the piece itself, clipped to its silhouette */
.grain {
  background: var(--grain);
  -webkit-mask: var(--src) center / contain no-repeat;
  mask: var(--src) center / contain no-repeat;
  mix-blend-mode: multiply;
}

/* Shadow lives in its own layer behind the piece (drop-shadow on the masked .paint renders
   a box in Chrome), so the blur is rasterized once and only its opacity animates. */
.shade {
  filter: brightness(0) blur(16px);
  transform: translateY(26px) scale(0.95);
}

.all-paint .paint { -webkit-mask-image: none; mask-image: none; }

/* paint flicks that land when a piece settles */
.splats { position: absolute; inset: 0; z-index: 110; pointer-events: none; }
.splat {
  position: absolute;
  background: var(--c);
  border-radius: 48% 52% 44% 56% / 55% 45% 55% 45%;
  mix-blend-mode: multiply;
  opacity: 0.85;
  animation: flick 0.5s cubic-bezier(.2, 1.6, .4, 1) both;
}
.splat.out { animation: flick-out 0.4s ease forwards; }
@keyframes flick { from { transform: scale(0) rotate(var(--r)); } to { transform: scale(1) rotate(var(--r)); } }
@keyframes flick-out { to { transform: scale(0.4) rotate(var(--r)); opacity: 0; } }

/* ---------- sketchbook notes ---------- */

.note {
  position: absolute;
  z-index: 120;
  display: flex;
  align-items: center;
  gap: 4px;
  pointer-events: none;
  font-family: var(--hand);
  font-weight: 500;
  font-size: clamp(20px, 1.7vw, 36px);
  line-height: 1;
  color: var(--graphite);
}
/* notes live in the open paper above and below the center piece, arrows pointing in */
.note-l {
  right: calc(50% + var(--pw) * 0.1);
  top: calc(var(--cy) - var(--ph) * 0.5 - 70px);
  rotate: -4deg;
}
.note-r {
  left: calc(50% + var(--pw) * 0.16);
  top: calc(var(--cy) - var(--ph) * 0.5 - 30px);
  rotate: 3deg;
}
.note-text {
  white-space: nowrap;
  clip-path: inset(-20% 100% -20% 0);
  transition: clip-path 0.2s ease;
}
.note-arrow { width: 118px; height: 72px; flex: none; overflow: visible; }
.note-arrow path {
  fill: none;
  stroke: var(--graphite);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 0.2s ease;
}

.settled .note-text { clip-path: inset(-20% -5% -20% -5%); transition: clip-path 0.9s cubic-bezier(.6, 0, .3, 1) 0.15s; }
.settled .note-arrow path { stroke-dashoffset: 0; transition: stroke-dashoffset 0.6s cubic-bezier(.6, 0, .3, 1) 0.75s; }
.settled .note-arrow path + path { transition-delay: 1.25s; transition-duration: 0.2s; }
.settled .note-r .note-text { transition-delay: 0.45s; }
.settled .note-r .note-arrow path { transition-delay: 1s; }
.settled .note-r .note-arrow path + path { transition-delay: 1.5s; }

/* ---------- HUD ---------- */

.hud {
  position: absolute;
  left: 40px;
  right: 40px;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.hud-top { top: 38px; }
.hud-bottom { bottom: 26px; }
.hud-group { display: flex; align-items: center; gap: 34px; flex: 1; }
.hud-top nav { justify-content: flex-end; }

.hud-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--ink);
  text-decoration: none;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  background: none;
  border: 0;
  cursor: pointer;
  position: relative;
}
.hud-link::after {
  content: "";
  position: absolute;
  left: -4px; right: -4px; bottom: -5px;
  height: 7px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 8' preserveAspectRatio='none'%3E%3Cpath d='M2 5 C 30 1, 60 8, 98 3' fill='none' stroke='%23e8742a' stroke-width='2.4' stroke-linecap='round'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
  clip-path: inset(0 100% 0 0);
  transition: clip-path 0.35s cubic-bezier(.6, 0, .3, 1);
}
.hud-link:hover::after, .hud-link:focus-visible::after { clip-path: inset(0 0 0 0); }
.hud-link:focus-visible { outline: none; }
.sq { width: 8px; height: 8px; background: var(--ink); display: inline-block; border-radius: 1px; rotate: 8deg; }
.hud-dim { color: var(--muted); font-variant-numeric: tabular-nums; }

.logo {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-decoration: none;
  color: var(--ink);
  text-transform: none;
  letter-spacing: 0;
}
.logo-a {
  font-family: var(--hand);
  font-weight: 700;
  font-size: 22px;
  line-height: 0.6;
  color: var(--accent);
  rotate: -7deg;
  translate: -38px 2px;
  transition: --accent 0.9s ease;
}
.logo-b { font-family: var(--display); font-size: 25px; line-height: 1; }

.toggle span { color: var(--accent); transition: --accent 0.9s ease; }

/* bottom HUD items get a paper label so they stay legible over pieces that swing past */
.hud-bottom .toggle, .hud-bottom .progress > * {
  background: var(--paper);
  padding: 4px 8px;
  border-radius: 3px;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
}
.hud-bottom > * { flex: 1; }
.hud-bottom .toggle { flex: none; }

.hint {
  position: absolute;
  left: 50%;
  bottom: -6px;
  translate: -50% 0;
  display: flex;
  align-items: center;
  gap: 4px;
  font-family: var(--hand);
  font-size: 22px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--graphite);
  opacity: 0;
  transition: opacity 0.6s ease;
  pointer-events: none;
}
.hint svg { width: 26px; height: 26px; }
.hint path { fill: none; stroke: var(--graphite); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.show-hint .hint { opacity: 1; animation: nudge 1.6s ease-in-out infinite; }
@keyframes nudge { 50% { transform: translateY(4px); } }

.progress { display: flex; align-items: center; gap: 14px; flex: 1; justify-content: flex-end; }
.dots { display: flex; gap: 7px; }
.dot {
  width: 9px; height: 9px;
  border: 1.4px solid var(--ink);
  border-radius: 50% 45% 55% 48%;
  transition: background 0.3s ease, transform 0.3s ease;
}
.dot.on { background: var(--accent); border-color: var(--ink); transform: scale(1.35) rotate(20deg); }

/* ---------- caption ---------- */

.caption {
  position: absolute;
  left: 50%;
  bottom: 62px;
  z-index: 100;
  translate: -50% 0;
  width: min(520px, 90%);
  text-align: center;
  pointer-events: none;
}
.cap-meta {
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
  min-height: 1.3em;
  white-space: pre;
}
.cap-title {
  position: relative;
  display: inline-block;
  margin-top: 6px;
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(26px, 2.6vw, 38px);
  line-height: 1.1;
  color: var(--ink);
}
#capTitle { display: inline-block; clip-path: inset(-30% -4% -30% -4%); }
#capTitle.write { animation: write-on 0.7s cubic-bezier(.6, 0, .3, 1) both; }
@keyframes write-on { from { clip-path: inset(-30% 104% -30% -4%); } }

.swash {
  position: absolute;
  left: -6%;
  bottom: -9px;
  width: 112%;
  height: 16px;
  overflow: visible;
  z-index: -1;
}
.swash path {
  fill: none;
  stroke: var(--accent);
  stroke-width: 7;
  stroke-linecap: round;
  opacity: 0.75;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: --accent 0.9s ease;
}
.swash.draw path { animation: draw 0.55s cubic-bezier(.6, 0, .3, 1) 0.35s forwards; }
@keyframes draw { to { stroke-dashoffset: 0; } }

.cap-palette { display: flex; justify-content: center; gap: 6px; margin-top: 14px; min-height: 16px; }
.swatch {
  width: 16px;
  height: 16px;
  background: var(--c);
  border-radius: 52% 48% 40% 60% / 60% 40% 60% 40%;
  mix-blend-mode: multiply;
  animation: dab 0.4s cubic-bezier(.2, 1.6, .4, 1) both;
  animation-delay: calc(var(--k) * 60ms + 0.3s);
}
@keyframes dab { from { transform: scale(0) rotate(-40deg); } }

/* ---------- graphite cursor trail ---------- */

#graphite {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 300;
  pointer-events: none;
  visibility: hidden; /* shown by JS only while a trail is on screen */
}

/* ---------- small screens ---------- */

@media (max-width: 760px) {
  :root { --inset: 8px; }
  .hud { left: 16px; right: 16px; }
  .hud-top { top: 30px; }
  .hud-top .hud-group { gap: 14px; }
  .hud-top nav .hud-link:not(:last-child), .hud-top .hud-group:first-child .hud-link { display: none; }
  .logo-b { font-size: 19px; }
  .logo-a { font-size: 18px; translate: -28px 2px; }
  .note { display: none; }
  .caption { bottom: 70px; }
  .hint { bottom: 160px; white-space: nowrap; }
  .progress .hud-dim { display: none; }
  .spiral { left: 24px; right: 24px; }
}

@media (prefers-reduced-motion: reduce) {
  .boil { animation: none; filter: url(#boil-0); }
  .boil-frames > img { animation: none; }
  .boil-frames > img:first-child { opacity: 1; }
  .show-hint .hint { animation: none; }
}
