/* base.css — the reset and the shared states every module expects. Needs tokens.css first.
   Interface: .visually-hidden; .slot (data-label, --slot-ar); [data-reveal] + .in (reveal.js);
   .flip > .flip__face / .flip__face--back + .is-flipped (flip.js); .cursor + .is-over/.is-hidden and
   html.has-cursor (cursor.js); prefers-reduced-motion kills motion and shows every reveal. */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body { margin: 0; overflow-x: clip; min-height: 100svh; }
img, video, canvas, svg { max-width: 100%; height: auto; display: block; }
[hidden] { display: none !important; }
button { font: inherit; color: inherit; }

.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* A labelled placeholder for a picture code cannot draw, at its final size. */
.slot {
  position: relative; margin: 0; display: grid; place-items: center; overflow: hidden;
  aspect-ratio: var(--slot-ar, 16 / 9);
  outline: 1px dashed color-mix(in srgb, currentColor 30%, transparent); outline-offset: -1px;
  background: linear-gradient(135deg, color-mix(in srgb, currentColor 5%, transparent),
    color-mix(in srgb, currentColor 14%, transparent));
}
.slot::after {
  content: attr(data-label); padding: .5em .9em; text-align: center; opacity: .55;
  font: 500 11px/1.3 system-ui, sans-serif; letter-spacing: .08em; text-transform: uppercase;
}
.slot > img, .slot > video, .slot > canvas { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* reveal.js */
[data-reveal] {
  opacity: 0; transform: translateY(16px); filter: blur(6px);
  transition: opacity var(--dur-m) var(--ease), transform var(--dur-m) var(--ease), filter var(--dur-m) var(--ease);
}
[data-reveal].in { opacity: 1; transform: none; filter: none; }

/* flip.js: <div class="flip"><div class="flip__face">front</div><div class="flip__face flip__face--back">back</div></div> */
.flip { position: relative; perspective: 1200px; transform-style: preserve-3d; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.flip__face {
  position: relative; backface-visibility: hidden; -webkit-backface-visibility: hidden;
  transition: transform var(--dur-l) var(--ease); transform: rotateY(0);
}
.flip__face--back { position: absolute; inset: 0; transform: rotateY(180deg); }
.flip.is-flipped .flip__face { transform: rotateY(-180deg); }
.flip.is-flipped .flip__face--back { transform: rotateY(0); }
.flip:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; }

/* cursor.js: white on difference blend inverts whatever is under it, so it needs no colour of its own. */
html.has-cursor, html.has-cursor * { cursor: none; }
.cursor {
  position: fixed; left: 0; top: 0; z-index: var(--z-cursor); pointer-events: none;
  width: var(--cursor-size, 10px); height: var(--cursor-size, 10px); border-radius: 50%;
  background: var(--cursor-color, #fff); mix-blend-mode: difference; will-change: transform;
  transition: width var(--dur-s) var(--ease), height var(--dur-s) var(--ease), background-color var(--dur-s), opacity var(--dur-s);
}
.cursor.is-over { width: var(--cursor-ring, 36px); height: var(--cursor-ring, 36px); background: transparent; border: 1.5px solid var(--cursor-color, #fff); }
.cursor.is-hidden { opacity: 0; }

/* The kill switch: nothing moves on its own, and every reveal is already shown. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
  html { scroll-behavior: auto; }
  [data-reveal] { opacity: 1; transform: none; filter: none; }
}
