/* Zhuhao 的空间 — canvas-faithful app
   All geometry / colour / radius / spacing values come from the canvas nodes
   and are emitted inline in index.html. This file only adds resets, motion,
   hover affordances and reduced-motion handling. */

*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: #050606;
  color: #ededed;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body { overflow-x: hidden; }

.viewport {
  position: relative;
  width: 100%;
  overflow: hidden;
}

.canvas {
  position: absolute;
  top: 0;
  width: 1440px;
  background: #080909;
  transform-origin: top left;
}

/* Every node establishes a containing block, so canvas-absolute children
   (aurora layer, cylinder cards, slider detents) resolve against their own
   parent frame rather than the page root. Inline `position:absolute` on the
   children still wins over this rule. */
.n {
  box-sizing: border-box;
  position: relative;
  /* Canvas "hug_contents" items keep their natural width; shrinking them
     folds two-character labels onto a second line. */
  flex-shrink: 0;
}

/* Interactive primitives ------------------------------------------------ */
a.n, button.n {
  cursor: pointer;
  text-decoration: none;
  color: inherit;
  font: inherit;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  min-width: 0;
  -webkit-tap-highlight-color: transparent;
}

a.n:hover, button.n:hover { filter: brightness(1.35); }
a.n:focus-visible, button.n:focus-visible,
.cyl-card:focus-visible, .cyl-exit:focus-visible {
  outline: 1px solid #9a9c9b;
  outline-offset: 3px;
}

[data-role="dot"] { transition: background .3s ease, width .3s ease, height .3s ease; }
[data-role="detent"] { transition: background .3s ease, box-shadow .3s ease; }
[data-role="detent"]:hover { box-shadow: 0 0 0 3px rgba(237, 237, 237, .07); }

/* Navigation current state (text-decoration avoids fighting inline colour) */
a.n[data-current="true"] { text-decoration: underline; text-underline-offset: 7px; }

/* Hero ------------------------------------------------------------------- */
@keyframes welcomeIn {
  from { opacity: 0; transform: translateY(-24px); }
  to   { opacity: 1; transform: translateY(0); }
}
[data-id="2:4"] { animation: welcomeIn .6s ease-out both; }

.aurora {
  will-change: transform, opacity, filter;
  animation:
    auroraDrift 24s ease-in-out infinite alternate,
    auroraBreath 36s ease-in-out infinite;
  transition: filter 1.2s ease-in-out;
  pointer-events: none;
}
@keyframes auroraDrift {
  from { transform: translateX(-3%); }
  to   { transform: translateX(3%); }
}
@keyframes auroraBreath {
  0%, 100% { opacity: 1; }
  50%      { opacity: .87; }
}

[data-role^="poem-"] {
  transition: opacity .8s ease-in-out, transform .8s ease-in-out;
  transform-origin: left center;
}
[data-role^="poem-"].is-out {
  opacity: 0 !important;
  transform: translateY(-12px) !important;
}
[data-role^="poem-"].is-in { animation: poemIn .8s ease-in-out both; }
@keyframes poemIn {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

[data-role="module-label"] { transition: opacity .5s ease; }

/* Cylinder --------------------------------------------------------------- */
.cyl-card {
  padding: 0;
  margin: 0;
  border: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  transform-origin: center center;
  -webkit-tap-highlight-color: transparent;
}
.cyl-card:hover { box-shadow: 0 0 0 1px #5c5e5d, 0 22px 54px rgba(0, 0, 0, .55); }
.cyl-num { opacity: 0; transition: opacity .45s ease; }
.cyl-card.is-front .cyl-num { opacity: 1; }

/* Transitions are switched on only after the first layout frame. Otherwise
   the browser may coalesce the initial inline styles with the first update,
   so the very first rotation silently renders without any animation. */
.is-ready .cyl-card {
  transition:
    left .6s cubic-bezier(.22, 1, .36, 1), top .6s cubic-bezier(.22, 1, .36, 1),
    transform .6s cubic-bezier(.22, 1, .36, 1), opacity .6s cubic-bezier(.22, 1, .36, 1),
    filter .6s cubic-bezier(.22, 1, .36, 1), background .6s, border-color .6s,
    box-shadow .3s ease-out;
}
@keyframes focusIn {
  0%   { box-shadow: 0 0 0 0 rgba(127, 168, 147, 0), 0 0 0 rgba(127, 168, 147, 0); }
  38%  { box-shadow: 0 0 0 3px rgba(127, 168, 147, .32), 0 0 52px rgba(127, 168, 147, .24); }
  100% { box-shadow: 0 0 0 0 rgba(127, 168, 147, 0), 0 0 0 rgba(127, 168, 147, 0); }
}
.cyl-card.is-focus-in { animation: focusIn .82s cubic-bezier(.22, 1, .36, 1); }

.cyl-exit { font-family: 'Noto Sans SC', sans-serif; }
.cyl-exit[hidden] { display: none; }
.cyl-exit:hover { background: #232423; color: #fff; }

[data-role="knob"], [data-role="knob-glow"], [data-role="knob-readout"] {
  transition: top .6s cubic-bezier(.22, 1, .36, 1);
  pointer-events: none;
}
[data-id="4:60"] { touch-action: none; cursor: ns-resize; }
[data-role="detent"] { cursor: pointer; }
/* The rotated side cards overlap the ‹ › hit areas; keep the arrows on top. */
[data-role="cyl-prev"], [data-role="cyl-next"] { z-index: 20 !important; }

/* Function sub-page opened by clicking the focused card ------------------- */
.cyl-subpage {
  position: fixed; inset: 0; z-index: 90;
  display: flex; align-items: center; justify-content: center;
  background: rgba(4, 6, 5, .8);
  opacity: 0;
  transition: opacity .26s ease-out;
  backdrop-filter: blur(9px);
  font-family: 'Noto Sans SC', sans-serif;
}
.cyl-subpage[hidden] { display: none; }
.cyl-subpage.is-open { opacity: 1; }
.cyl-subpage-inner {
  position: relative;
  width: min(560px, calc(100vw - 48px));
  padding: 50px 52px 46px;
  border: 1px solid #2a2d2b;
  border-radius: 16px;
  background: #0e100f;
  transform: translateY(18px) scale(.98);
  transition: transform .34s cubic-bezier(.22, 1, .36, 1);
}
.cyl-subpage.is-open .cyl-subpage-inner { transform: none; }
.cyl-subpage-close {
  position: absolute; right: 18px; top: 16px;
  width: 32px; height: 32px; border: 1px solid #2f3230;
  border-radius: 8px; background: #141715; color: #ced0ce;
  font-size: 18px; line-height: 1; cursor: pointer;
}
.cyl-subpage-close:hover { background: #232623; color: #fff; }
.cyl-subpage-code { font-size: 11px; letter-spacing: 2px; color: #7fa893; }
.cyl-subpage-inner h2 {
  margin: 16px 0 12px; font-size: 38px; font-weight: 500; color: #ededed;
}
.cyl-subpage-desc { margin: 0 0 34px; font-size: 14px; line-height: 1.85; color: #8c8e8d; }
.cyl-subpage-links { display: flex; gap: 10px; }
.cyl-subpage-link {
  padding: 10px 18px; border: 1px solid #2f3230; border-radius: 8px;
  background: #141715; color: #ced0ce; font-size: 13px;
  font-family: inherit; cursor: pointer;
}
.cyl-subpage-link:hover { background: #1c201e; color: #fff; }

/* 06 成果控制台 — scroll-triggered digital dragon reveal ------------------ */
.console-section { position: relative; }
/* The console is wiped into existence left-to-right, as if the dragon's
   dispersing lines were drawing it, rather than fading in as a ready block. */
.console-window {
  transition: opacity .4s ease-out, clip-path 1.05s cubic-bezier(.22,1,.36,1);
}
.console-section.is-animating .console-window {
  opacity: 0;
  clip-path: inset(0 100% 0 0);
}
.console-section.is-revealed .console-window {
  opacity: 1;
  clip-path: inset(0 0 0 0);
}
/* Each text node is written explicitly by JS (is-written). Keyframes with a
   long animation-delay used to leave some rows invisible when many nodes
   shared one animation name — this state-driven version cannot skip a node. */
.console-ink {
  transition: opacity .42s ease-out,
              clip-path .52s cubic-bezier(.22, 1, .36, 1),
              transform .42s ease-out;
}
.console-section.is-animating .console-ink {
  opacity: 0;
  clip-path: inset(0 100% 0 0);
  transform: translateY(6px);
}
.console-section.is-animating .console-ink.is-written {
  opacity: 1;
  clip-path: inset(0 0 0 0);
  transform: none;
}
.dragon-canvas { pointer-events: none; }

/* 06 is a file browser: categories filter, rows select for quick access. */
.file-row[hidden] { display: none !important; }
.file-row, .side-item { cursor: pointer; }
.file-row {
  transition: background .22s ease-out, top .38s cubic-bezier(.22, 1, .36, 1);
}
.file-row:hover { background: rgba(255, 255, 255, .03); }
.file-row.is-selected { background: rgba(127, 168, 147, .085); }
.file-row.is-previewing { background: rgba(127, 168, 147, .12); }
.side-item { transition: color .2s ease-out; }
.side-item:hover, .side-item.is-active { color: #ededed !important; }
.active-bar { transition: top .38s cubic-bezier(.22, 1, .36, 1); }

.row-action {
  cursor: pointer;
  transition: background .2s ease-out, border-color .2s ease-out;
}
.row-action:hover {
  background: #191c1a !important;
  border-color: #4a4e4b !important;
}
.row-action:hover .console-ink { color: #ededed !important; }
.row-action.is-pressed { background: rgba(127, 168, 147, .2) !important; }

.is-static .console-window,
.is-static .console-ink {
  opacity: 1 !important;
  clip-path: none !important;
  transform: none !important;
  animation: none !important;
}

/* ?static freezes motion so the rendered frame can be compared to the canvas */
.is-static [data-id="2:4"],
.is-static .aurora { animation: none !important; }
.is-static .cyl-card,
.is-static [data-role="knob"],
.is-static [data-role="knob-glow"],
.is-static [data-role="knob-readout"] { transition: none !important; }

/* Keep the cylinder crisp when the user prefers less motion --------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}
