/* The board: one transformed world inside a fixed viewport. */
.viewport {
  position: fixed;
  inset: 0;
  overflow: hidden;
  touch-action: none;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  background-color: var(--bg);
}
.grid {
  position: absolute;
  inset: -96px;
  background-image: radial-gradient(circle at center, var(--grid) 0.9px, transparent 1.3px);
  background-size: 28px 28px;
  will-change: transform;
  pointer-events: none;
}
.viewport:not([data-bg="dots"]) .grid { display: none; }
.viewport.is-panning { cursor: grabbing; }

/* Ripple background: screen space cells, faded out from the top centre. */
:root[data-theme="dark"] {
  --rp-border: rgba(255, 255, 255, 0.11);
  --rp-fill: #141416;
  --rp-shadow: #1e1e21;
}
:root[data-theme="light"] {
  --rp-border: rgba(20, 20, 18, 0.16);
  --rp-fill: #e9e8e3;
  --rp-shadow: transparent;
}
.ripple {
  position: absolute;
  top: 0;
  display: none;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(ellipse 72% 100% at 50% 0%, #000 20%, transparent 100%);
  mask-image: radial-gradient(ellipse 72% 100% at 50% 0%, #000 20%, transparent 100%);
}
.viewport[data-bg="ripple"] .ripple { display: grid; }
.ripple i {
  position: relative;
  display: block;
  width: 56px;
  height: 56px;
  border: 0.5px solid var(--rp-border);
  background: var(--rp-fill);
  opacity: 0.4;
  transition: opacity 150ms ease;
}
:root[data-theme="dark"] .ripple i { box-shadow: inset 0 0 40px 1px var(--rp-shadow); }
.ripple i.is-hover { opacity: 0.8; }
.ripple i::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--accent);
  opacity: 0;
}
.ripple.is-rippling i { animation: rp-pulse var(--duration, 200ms) var(--ease-out) var(--delay, 0ms) 1 none; }
.ripple.is-rippling i::after { animation: rp-tint var(--duration, 200ms) var(--ease-out) var(--delay, 0ms) 1 none; }
@keyframes rp-pulse {
  0% { opacity: 0.4; }
  30% { opacity: 0.68; }
  100% { opacity: 0.4; }
}
@keyframes rp-tint {
  0% { opacity: 0; }
  30% { opacity: 0.025; }
  100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .ripple.is-rippling i, .ripple.is-rippling i::after { animation: none; }
}

.world {
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  height: 1px;
  transform-origin: 0 0;
}
.world.is-moving { will-change: transform; }

.edges {
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  height: 1px;
  overflow: visible;
  pointer-events: none;
}
.edges path {
  fill: none;
  stroke: var(--edge);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  transition: stroke 180ms ease;
}
.edges path.is-hot { stroke: var(--edge-hot); }

/* Cards. The button holds position; .node-card takes every reaction. */
.node {
  position: absolute;
  display: block;
  padding: 0;
  border: 0;
  background: none;
  text-align: left;
  left: 0;
  top: 0;
  width: max-content;
  cursor: pointer;
  transform: translate(-50%, -50%);
  -webkit-tap-highlight-color: transparent;
}
.node:focus-visible { outline: none; }
.node:focus-visible .node-card { box-shadow: var(--card-shadow), 0 0 0 2px var(--accent); }

.node-card {
  position: relative;
  display: block;
  width: 100%;
  padding: 26px 28px 28px;
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surface);
  box-shadow: var(--card-shadow);
  transform-origin: 50% 50%;
  backface-visibility: hidden;
}
.node.is-live .node-card { will-change: transform; }

.node-glow {
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  box-shadow: var(--glow);
  opacity: 0;
  pointer-events: none;
}
.node-sheen {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 0%), rgba(255, 255, 255, 0.07), transparent 46%);
  opacity: 0;
  pointer-events: none;
}
:root[data-theme="light"] .node-sheen {
  background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 0%), rgba(255, 255, 255, 0.85), transparent 46%);
}

.node-body { position: relative; display: block; }

.node-eyebrow {
  display: block;
  margin-bottom: 6px;
  font-size: 17px;
  line-height: 1.3;
  font-weight: 500;
  letter-spacing: -0.005em;
  color: var(--text-3);
}
.node-title {
  display: block;
  font-size: 32px;
  line-height: 1.06;
  font-weight: 600;
  letter-spacing: -0.022em;
  color: var(--text);
  overflow-wrap: anywhere;
}
.node-summary {
  display: -webkit-box;
  margin-top: 12px;
  font-size: 19px;
  line-height: 1.38;
  letter-spacing: -0.004em;
  color: var(--text-2);
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.node-summary.mono {
  font-family: var(--mono);
  font-size: 17px;
  letter-spacing: 0;
}

/* Root card. */
.node[data-kind="root"] .node-card {
  padding: 32px 34px;
  text-align: center;
  background: var(--surface-hi);
}
.root-visual {
  display: block;
  width: 240px;
  height: 128px;
  margin: 0 auto 18px;
}
/* The drawings carry transparent paper around the ink (light: 42px above, 79px below at 640px;
   dark: 65px and 102px). These margins take that out, so the ink sits 32px from the top of the
   card and 22px above the name in both themes: an even box. */
.root-visual:has(.root-img) { width: 260px; height: 260px; margin: -17px auto -10px; }
html[data-theme="dark"] .root-visual:has(.root-img) { margin: -26px auto -19px; }
.root-visual img { width: 100%; height: 100%; object-fit: contain; }
/* Sketched ring: one drawing per theme, its paper blended into the card. */
html:not([data-theme="dark"]) .root-img[data-for="dark"],
html[data-theme="dark"] .root-img[data-for="light"] { display: none; }

.root-name {
  display: block;
  font-size: 46px;
  line-height: 1;
  font-weight: 600;
  font-stretch: 100%;
  letter-spacing: 0.14em;
  margin-right: -0.14em;
  color: var(--text);
}
.root-line {
  display: block;
  margin: 16px auto 0;
  max-width: 34ch;
  font-size: 17px;
  line-height: 1.42;
  color: var(--text-2);
}
.root-aha {
  display: block;
  margin: 16px auto 0;
  max-width: 24ch;
  font-size: 25px;
  line-height: 1.22;
  font-weight: 500;
  letter-spacing: -0.012em;
  color: var(--text);
}

/* Drawn ring. */
.ring-svg { width: 100%; height: 100%; overflow: visible; }
.ring-svg .ring-glow { opacity: 0.55; transition: opacity 320ms ease; }
.node[data-kind="root"].is-hover .ring-svg .ring-glow { opacity: 0.9; }

@media (prefers-reduced-motion: reduce) {
  .node-glow { transition: opacity 200ms ease; }
}

/* Ring drawings fade in once decoded; nothing waits for them. */
.root-img { opacity: 0; transition: opacity 360ms var(--ease-out); }
.root-img.is-loaded { opacity: 1; }

/* Folded cards fade as they gather into their parent; position is the spring's job. */
.node { transition: opacity 240ms var(--ease-out); }
.node.is-off {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 200ms ease, visibility 0s linear 200ms;
}
.edges path { transition: stroke 180ms ease, opacity 260ms ease; }
.edges path.is-off { opacity: 0; }

/* Category cards: the three questions, set large. */
.node[data-kind="category"] .node-title { font-size: 34px; letter-spacing: -0.024em; }
.node[aria-expanded] .node-title { padding-right: 26px; }

/* The quiet mark on cards that unfold rather than open. */
.node-unfold {
  position: absolute;
  top: 4px;
  right: -6px;
  width: 22px;
  height: 22px;
  color: var(--text-3);
  transition: transform 300ms var(--ease-out), color 160ms ease;
}
.node-unfold svg { display: block; width: 100%; height: 100%; }
.node[aria-expanded="true"] .node-unfold { transform: rotate(180deg); color: var(--accent-text); }

/* Where you are, in plain words. */
.trail {
  position: fixed;
  top: max(18px, env(safe-area-inset-top));
  left: max(22px, env(safe-area-inset-left));
  z-index: 15;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 8px;
  max-width: calc(100% - 44px);
  font-size: 15px;
  line-height: 1.35;
  color: var(--text-3);
}
.trail a { color: var(--text-3); text-decoration: none; transition: color 150ms ease; }
.trail a:hover { color: var(--text); }
.trail [aria-current] { color: var(--text-2); }
.trail .sep { opacity: 0.6; }

@media (prefers-reduced-motion: reduce) {
  .node-unfold { transition: none; }
}
.node[data-kind="category"] .node-summary { -webkit-line-clamp: unset; display: block; }
/* A soft wash of the page colour behind the top left corner, so the path always reads. */
.trail::before {
  content: "";
  position: fixed;
  left: 0;
  top: 0;
  z-index: -1;
  width: min(760px, 100vw);
  height: 120px;
  background: radial-gradient(100% 100% at 0 0, var(--bg) 42%, transparent 100%);
  pointer-events: none;
}
.node[aria-expanded] .node-summary { -webkit-line-clamp: unset; display: block; }
/* What a category holds: its cards' names, quietly, one per line. */
.node-contents { display: block; margin-top: 18px; font-size: 17px; line-height: 1.5; color: var(--text-3); }
.node-contents span { display: block; }
.node.is-open .node-contents { display: none; }
/* One path at a time: the panel carries it while open. */
.trail { transition: opacity 200ms ease; }
body.is-open .trail { opacity: 0; pointer-events: none; }

/* One tree in focus: the other two categories step back (the scale is the card's spring). */
.node.is-receded { opacity: 0.42; }
@media (hover: hover) and (pointer: fine) {
  .node.is-receded:hover { opacity: 0.85; }
}

/* First layout: no transitions, so folded cards are simply not there. */
.world.is-still .node, .world.is-still .edges path { transition: none !important; }
