/* Riso paper + spot inks */
:root {
  --paper:        #e6f5ee;
  --paper-white:  #f4faf6;
  --ink:          #1a3a2a;
  --ink-dim:      #4a6859;
  --ink-faint:    #8aa599;

  --riso-pink:        #ff7eb6;
  --riso-pink-deep:   #e3589c;
  --riso-green:       #2db876;
  --riso-green-deep:  #1a8a55;
  --riso-coral:       #ff8a6b;
  --riso-yellow:      #f0c33d;

  --line:         rgba(26, 58, 42, 0.16);
  --line-strong:  rgba(26, 58, 42, 0.32);

  --font-display: "Bricolage Grotesque", "Inter Tight", system-ui, sans-serif;
  --font-mono:    "Geist Mono", ui-monospace, "JetBrains Mono", monospace;
  --font-serif:   "Instrument Serif", "Times New Roman", serif;
}

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

html, body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-display);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
  min-height: 100vh;
}

/* Per-element grain.
   The site-wide paper grain is applied to topbar, footer, and `main`
   (the wrapper used on every tab page). The home page's cell stage is
   NOT a `main` -- it's a <section class="stage"> -- so the grain skips
   the cell canvas entirely, keeping the candy plastic look untouched. */
main {
  position: relative;
  z-index: 1;
}
main::after {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image: url("/img/grain.svg");
  background-repeat: repeat;
  mix-blend-mode: multiply;
  opacity: 0.32;
}
main > * { position: relative; z-index: 1; }

a { color: inherit; text-decoration: none; }
::selection { background: var(--riso-pink); color: var(--paper); }

img, svg { display: block; max-width: 100%; }
button { font: inherit; cursor: pointer; }

/* ── First-paint paper settle ─────────────────────────────────
   Light entrance for the page: main fades in briefly, like a freshly-
   printed sheet landing. The illos do a separate, more detailed riso
   print-pass inside their own SVGs.
   Opacity-only on purpose: a transform on <main> would turn it into
   a containing block for fixed descendants and break the apps-page
   lightbox during the animation window. */
@keyframes paper-settle {
  from { opacity: 0; }
  to   { opacity: 1; }
}
main { animation: paper-settle 0.5s ease-out both; }
@media (prefers-reduced-motion: reduce) {
  main { animation: none; }
}

/* ── Cursor push on the illos ─────────────────────────────────
   Cursor-driven exaggeration of riso misregistration: as the mouse
   moves over an inlined illo, the pink colour layer drifts toward the
   cursor and the green layer drifts away. The ink outline stays put
   so the shape holds together.
   /js/illos.js sets --px / --py on the <svg> from -1 to 1.
   Mouse-only (no transform on touch). */
svg.illo .riso-pink,
svg.illo .riso-green {
  transition: transform 0.28s cubic-bezier(0.2, 0.7, 0.2, 1);
  will-change: transform;
}
@media (hover: hover) and (pointer: fine) {
  svg.illo .riso-pink {
    transform: translate(calc(var(--px, 0) * 6px), calc(var(--py, 0) * 6px));
  }
  svg.illo .riso-green {
    transform: translate(calc(var(--px, 0) * -6px), calc(var(--py, 0) * -6px));
  }
}
@media (prefers-reduced-motion: reduce) {
  svg.illo .riso-pink,
  svg.illo .riso-green {
    transform: none !important;
    transition: none !important;
  }
}

/* ── Selection: riso-misregistered swipe ─────────────────────── */
::selection {
  background: var(--riso-pink);
  color: var(--ink);
  text-shadow: 1px 0.5px 0 var(--riso-green);
}

/* ── Cross-document View Transitions: mitosis tab swap ───────
   Chrome 126+ uses this for cross-page navigations (when same-origin
   and same View Transition root). The outgoing main pinches and
   slides one way; the new main buds in from the other side. Falls
   back to instant nav in browsers without support. */
@view-transition { navigation: auto; }
main { view-transition-name: page-content; }
::view-transition-old(page-content) {
  animation: 0.42s cubic-bezier(0.4, 0, 0.6, 1) both bb-mitosis-out;
}
::view-transition-new(page-content) {
  animation: 0.48s cubic-bezier(0.2, 0.7, 0.2, 1) both bb-mitosis-in;
}
@keyframes bb-mitosis-out {
  0%   { transform: scale(1) translateX(0); opacity: 1; }
  30%  { transform: scaleX(1.06) scaleY(0.96) translateX(0); }
  100% { transform: scaleX(0.55) scaleY(0.86) translateX(-22%); opacity: 0; }
}
@keyframes bb-mitosis-in {
  0%   { transform: scaleX(0.55) scaleY(0.86) translateX(22%); opacity: 0; }
  100% { transform: scale(1) translateX(0); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(page-content),
  ::view-transition-new(page-content) { animation: none; }
}

/* ── Etymology tooltip ──────────────────────────────────────── */
/* Terms wrapped by /js/etymology.js with the Greek/Latin roots in
   data-roots. Hover -> tooltip; the dotted underline signals it's
   interactive without shouting. */
.bio-term {
  border-bottom: 1px dotted var(--riso-pink-deep);
  cursor: help;
  position: relative;
}
.bio-term:hover::after,
.bio-term:focus::after {
  content: attr(data-roots);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  background: var(--ink);
  color: var(--paper-white);
  padding: 7px 12px;
  border-radius: 6px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.02em;
  line-height: 1.4;
  white-space: nowrap;
  z-index: 200;
  pointer-events: none;
  box-shadow: 2px 2px 0 var(--riso-pink);
}
.bio-term:hover::before,
.bio-term:focus::before {
  content: "";
  position: absolute;
  bottom: calc(100% + 2px);
  left: 50%;
  transform: translateX(-50%);
  border: 6px solid transparent;
  border-top-color: var(--ink);
  z-index: 200;
  pointer-events: none;
}

/* ── Ribosome scroll marker (every page with a <main>, injected by JS) ─ */
.scroll-ribosome {
  position: fixed;
  right: 14px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--paper-white);
  border: 1.5px solid var(--ink);
  box-shadow: 2px 2px 0 var(--riso-pink);
  z-index: 80;
  pointer-events: none;
  transition: top 0.08s linear;
}
.scroll-ribosome::after {
  /* Halftone dot pattern inside the ribosome */
  content: "";
  position: absolute; inset: 2px;
  border-radius: 50%;
  background-image: radial-gradient(var(--riso-pink) 1px, transparent 1.6px);
  background-size: 4px 4px;
}
@media (max-width: 760px) {
  .scroll-ribosome { display: none; }
}

/* ── Print stylesheet ────────────────────────────────────────
   Strip the riso furniture so handouts come out as plain readable
   text. Everything interactive disappears; links get their URL
   appended after them for paper trail. */
@media print {
  .topbar, footer,
  .joke-strip-wrap, .roots-strip-wrap, .joke-deck, .joke-actions,
  .joke-card-wrap, .staffroom-download, .roots-download,
  .notfound-actions, .stage, .scroll-ribosome, .ribosome-trail,
  iframe, video, audio, .video-section { display: none !important; }

  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
    box-shadow: none !important;
    text-shadow: none !important;
  }
  body, main {
    background: white !important;
    color: black !important;
    padding: 0 !important;
  }
  main::after { display: none !important; }
  h1, h2, h3, h4 { color: black !important; }
  em { color: #333 !important; font-style: italic; }
  a { color: black; text-decoration: underline; }
  a[href^="http"]::after,
  a[href^="mailto"]::after { content: " (" attr(href) ")"; font-size: 0.85em; color: #555; }
  a[href^="/"]::after { content: ""; }
  .bio-term { border-bottom: none; }
  .post-card, .article-body, .legal-page { break-inside: avoid; }
}

/* ── Ribosome cursor trail ──────────────────────────────────── */
/* Mounted by /js/ribosome-trail.js. Real cursor is untouched; this
   small pink dot follows it with an ~80ms ease, like the cell is
   keeping pace. Skipped on touch/coarse-pointer and reduced motion. */
.ribosome-trail {
  position: fixed;
  top: 0; left: 0;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--riso-pink);
  border: 1.5px solid var(--ink);
  box-shadow: 1.5px 1.5px 0 var(--riso-green);
  pointer-events: none;
  z-index: 9999;
  opacity: 0;
  transition: opacity 0.15s;
  will-change: transform;
}
.ribosome-trail::after {
  /* Halftone dot pattern matches the scroll-ribosome */
  content: "";
  position: absolute; inset: 2px;
  border-radius: 50%;
  background-image: radial-gradient(rgba(26, 58, 42, 0.5) 0.5px, transparent 1.1px);
  background-size: 3px 3px;
}
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .ribosome-trail { display: none !important; }
}

/* ── Accessibility: visible focus rings ──────────────────────
   Keyboard users need a clear hit-state. :focus-visible fires for
   keyboard nav but not mouse clicks, so visual chrome stays clean. */
:focus-visible {
  outline: 2px solid var(--riso-pink-deep);
  outline-offset: 3px;
  border-radius: 4px;
}
/* Buttons / pills already have their own rounding -- tighter offset */
button:focus-visible,
.tab:focus-visible,
.cb:focus-visible, .lchip:focus-visible, .tc:focus-visible,
.joke-pill:focus-visible, .joke-deal:focus-visible,
.roots-strip-deal:focus-visible, .joke-strip-deal:focus-visible {
  outline-offset: 2px;
}

/* ── Skip-to-content link ────────────────────────────────────
   Always the first focusable element on the page. Visually hidden
   until a keyboard user tabs into it, then it slides into view. */
.skip-link {
  position: absolute;
  top: 8px; left: 8px;
  padding: 10px 16px;
  background: var(--ink);
  color: var(--paper-white);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.05em;
  border-radius: 999px;
  box-shadow: 2px 2px 0 var(--riso-pink);
  z-index: 1000;
  transform: translateY(-200%);
  transition: transform 0.18s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.skip-link:focus {
  transform: translateY(0);
  outline: none;
}

/* ── Mobile niceties ─────────────────────────────────────────
   Drop the iOS Safari gray tap-flash, replace it with a quick
   opacity dim on press. Subtler, on-brand, less startling. */
* { -webkit-tap-highlight-color: transparent; }
@media (hover: none) {
  a:active, button:active {
    opacity: 0.65;
    transition: opacity 0.05s;
  }
}

/* ── Konami easter egg flash (home page) ────────────────────
   Small overlay confirming the sequence registered. Pairs with
   the cell explode-and-reassemble triggered by /js/konami.js.  */
.konami-flash {
  position: fixed;
  left: 50%;
  bottom: 40px;
  transform: translateX(-50%) translateY(8px);
  z-index: 200;
  padding: 14px 22px;
  background: var(--paper-white);
  border: 1.5px solid var(--ink);
  border-radius: 12px;
  box-shadow: 3px 3px 0 var(--riso-pink);
  text-align: center;
  opacity: 0;
  transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.2,0.7,0.2,1);
  pointer-events: none;
}
.konami-flash.is-in { opacity: 1; transform: translateX(-50%) translateY(0); }
.konami-flash.is-out { opacity: 0; transform: translateX(-50%) translateY(-8px); }
.konami-seq {
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: 0.1em;
  color: var(--ink);
}
.konami-note {
  margin-top: 4px;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 15px;
  color: var(--riso-pink);
}
