/* ============================================================
   TOSR Wayfinding — 器物色谱
   铁釉黑作底 / 羊脂白留气 / 鎏金点睛 / 朱砂发声
   iron-glaze lacquer ground · mutton-fat jade linework ·
   matte gilt rules · cinnabar reserved for the human voice

   (Restored from the lacquer build the user chose, carrying two
   things forward from the later light-table build: the huge
   translucent plate code behind each drawing, and the short
   two-line masthead note.)
   ============================================================ */

:root {
  --lacquer: #16120c;          /* 铁釉黑 — iron-glaze ground */
  --lacquer-2: #1d1810;
  --jade: #ede3d0;             /* 羊脂白 — warm nephrite white */
  --jade-60: rgba(237, 227, 208, 0.6);
  --jade-35: rgba(237, 227, 208, 0.35);
  --gold: #a8874f;             /* 鎏金 — matte gilt */
  --gold-bright: #cfae72;
  --gold-28: rgba(168, 135, 79, 0.28);
  --gold-12: rgba(168, 135, 79, 0.14);
  --cinnabar: #b0452c;         /* 朱砂 — seal-paste red, the motion color */
  --cinnabar-bright: #c9563a;
  /* EXPERIMENTAL — the plate's solid body. Page background is
     untouched; only the drawings' opaque mass takes this color.
     Revert by deleting .stage-mass (styles.css + app.js).
     Now 黑白: a near-neutral black base, lifted just far enough off
     the warm ground to read as a plate, under jade-white linework
     (see .stage-layer). Earlier trials, if you want one back:
       朱砂  color-mix(in oklab, #b0452c 82%, #16120c)
       黑金  color-mix(in oklab, #a8874f 9%, #0e0b07)  + gilt filter */
  --plate-mass: color-mix(in oklab, #ede3d0 4%, #0a0806);
  --display: "Marcellus", "Times New Roman", serif;
  --body: "Cormorant Garamond", "Georgia", serif;
  --mono: "IBM Plex Mono", "Consolas", monospace;
  --pad: clamp(1.25rem, 4vw, 4rem);
}

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

html { scroll-behavior: smooth; }

body {
  background:
    radial-gradient(120% 90% at 20% 0%, rgba(64, 50, 30, 0.18), transparent 55%),
    radial-gradient(100% 80% at 85% 100%, rgba(43, 32, 18, 0.22), transparent 60%),
    var(--lacquer);
  color: var(--jade);
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* 格纸 — the drafting grid from the very first build, sunk under
   the glaze: dim gilt lines instead of ink, faded top and bottom */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(168, 135, 79, 0.07) 1px, transparent 1px),
    linear-gradient(90deg, rgba(168, 135, 79, 0.07) 1px, transparent 1px);
  background-size: 108px 108px;
  mask-image: linear-gradient(180deg, transparent 0%, #000 12%, #000 88%, transparent 100%);
  z-index: 0;
}

/* 窑变肌理 — faint kiln-fired grain over the lacquer ground */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  opacity: 0.05;
  mix-blend-mode: screen;
  z-index: 0;
}

.mono-tag {
  font-family: var(--mono);
  font-size: 0.66rem;
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.mono-tag--dim { color: var(--gold); opacity: 0.75; }

/* 白文印 — the one colour that answers to no measurement */
.seal {
  display: inline-block;
  padding: 0.42em 0.55em 0.36em;
  background: var(--cinnabar);
  color: var(--jade);
  font-family: var(--mono);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-indent: 0.22em; /* optically recenter the tracked text */
  text-transform: uppercase;
  box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.25);
}

/* ---------------- masthead ---------------- */

.masthead {
  position: relative;
  z-index: 1;
  border-bottom: 1px solid var(--gold-28);
}

/* gilt thread under the masthead — a slow warm sheen drifts across */
.masthead::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%, var(--gold) 35%, var(--gold-bright) 50%,
    var(--gold) 65%, transparent 100%);
  background-size: 220% 100%;
  animation: gilt-drift 9s ease-in-out infinite alternate;
  opacity: 0.9;
}

@keyframes gilt-drift {
  from { background-position: 0% 0; }
  to { background-position: 100% 0; }
}

.masthead-inner {
  padding: clamp(2.5rem, 6vw, 5rem) var(--pad) clamp(1.75rem, 3.5vw, 3rem);
}

.masthead-id {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  margin-bottom: clamp(1.5rem, 3vw, 2.5rem);
}

.masthead-title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.3rem, 5.6vw, 4.7rem);
  line-height: 1.12;
  letter-spacing: 0.01em;
  max-width: 22ch; /* breaks the title into its two lines */
  text-wrap: balance;
}

.masthead-note {
  margin-top: 1.5rem;
  max-width: 40ch;
  color: var(--jade-60);
  font-size: 1.02rem;
  font-style: italic;
}

/* ---------------- terminal tabs ---------------- */

.tabs {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  background: rgba(22, 18, 12, 0.92);
  backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--gold-28);
}

.tab {
  position: relative;
  flex: 1;
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  padding: 0.9rem var(--pad) 0.85rem;
  border: 0;
  border-right: 1px solid var(--gold-12);
  background: transparent;
  color: var(--jade-35);
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.25s ease, color 0.25s ease;
  transition: color 0.25s ease, background 0.25s ease;
}
.tab:last-child { border-right: 0; }

.tab-code {
  font-family: var(--display);
  font-size: 1.15rem;
  letter-spacing: 0.04em;
  color: inherit;
}

.tab:hover { color: var(--jade); background: rgba(237, 227, 208, 0.04); }

/* The current tab is a filled block, same idea as the reference's
   inverted bar — but struck as a 白文印: the cinnabar field, jade
   letterforms and inset bite are lifted straight from the TOSR seal
   in the masthead, so the marker comes out of this page's own
   vocabulary instead of reading as a borrowed black bar. */
.tab.is-active,
.tab.is-active:hover {
  color: var(--jade);
  background: var(--cinnabar);
  /* the outer 1px carries the cinnabar down over .tabs' own bottom
     rule, so the seal meets the sheet below it with no seam — a
     separate ::after strip left a hairline of the rule showing
     through at fractional device-pixel ratios */
  box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.28),
              0 1px 0 var(--cinnabar);
}

.tab.is-active .tab-code { color: var(--jade); }

/* ---------------- sheets ---------------- */

.sheet {
  position: relative;
  z-index: 1;
  overflow: hidden;
  border-bottom: 1px solid var(--gold-12);
  padding: clamp(1.75rem, 3.5vw, 3rem) var(--pad) clamp(2.5rem, 5vw, 4.5rem);
  scroll-margin-top: 4.4rem; /* clears the sticky tabs */
}

/* carried over from the light-table build: the plate code set huge
   and translucent behind the drawing, bled off the left edge */
.sheet-numeral {
  position: absolute;
  left: var(--bleed, -0.05em);
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--display);
  font-size: clamp(9rem, 26vw, 24rem);
  line-height: 0.74;
  letter-spacing: -0.045em;
  color: rgba(237, 227, 208, 0.045);
  pointer-events: none;
  user-select: none;
  z-index: 0;
}

.sheet-head {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: clamp(1.5rem, 3vw, 2.5rem);
}

.sheet-title-block { display: flex; align-items: baseline; gap: 1.25rem; }

.sheet-title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.5rem, 2.8vw, 2.2rem);
  letter-spacing: 0.02em;
  color: var(--jade);
}

.level-chips { display: flex; gap: 0.5rem; flex-wrap: wrap; }

.level-chip {
  border: 1px solid var(--gold-28);
  background: transparent;
  padding: 0.32rem 0.75rem;
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold);
  cursor: default;
  transition: border-color 0.2s ease, color 0.2s ease;
}
.level-chip:hover { border-color: var(--gold-bright); color: var(--gold-bright); }

/* sheet body: axo stage + route panel — one uniform layout for all */

.sheet-body {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(240px, 24vw, 340px);
  gap: clamp(1.5rem, 3vw, 3rem);
  align-items: center;
}

/* a slightly narrower reserved panel column, so a wide plate's
   drawing can spill a bit further into that space */
.sheet-body--wide {
  grid-template-columns: minmax(0, 1fr) clamp(200px, 18vw, 270px);
}

/* ---------------- axo stage ---------------- */

/* frame carries the size; stage clips the oversized canvas so its
   transparent PNGs cannot swallow clicks meant for other elements */
.stage-frame {
  position: relative;
  min-width: 0;
  margin-inline: auto;
  /* aspect-ratio + width set per-terminal from crop data in app.js */
}

.stage {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

.stage-canvas {
  /* full 5100x2400 canvas, oversized + shifted to show the crop */
  position: absolute;
  /* keeps the linework's screen blend inside the plate — it must mix
     with the red mass beneath it, never with the page ground */
  isolation: isolate;
}

/* EXPERIMENTAL — 朱砂坯. One per level, sitting directly under that
   level's linework: the PNG's own alpha is used as a mask, so the
   drawing's opaque body (and only that) is filled with red while the
   transparent surround stays lacquer. Because each mass is inserted
   right beneath its own layer, an upper floor still occludes the one
   below exactly as before. */
.stage-mass {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  background: var(--plate-mass);
  -webkit-mask-image: var(--plate);
  mask-image: var(--plate);
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  transition: opacity 0.35s ease;
  pointer-events: none;
}

.stage-mass,
.stage-layer,
.stage-overlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* ink linework inverted to mutton-fat white on the lacquer ground.
   The trailing drop-shadow bolds every stroke — outer silhouette and
   interior line alike — by a fraction of a pixel; needed because the
   source PNGs' 3px outline renders sub-pixel thin once scaled down
   for the page (see MAX_SCALE in app.js), which otherwise reads as
   a hairline rather than a drawn edge. */
.stage-layer {
  user-select: none;
  -webkit-user-drag: none;
  transition: opacity 0.35s ease;
  /* invert turns ink into mutton-fat white linework. Gilt version,
     if you want it back:
       invert(0.92) sepia(1) saturate(2.3) brightness(0.82)
       drop-shadow(0 0 0.55px rgba(207, 174, 114, 0.85)); */
  /* sepia(0.45) lands the inverted linework on ~#ede0c7, i.e. the same
     warm cream as --jade, so the drawing and the plate titles read as
     one family rather than white-on-warm */
  filter: invert(0.92) sepia(0.45) brightness(1.0)
          drop-shadow(0 0 0.55px rgba(237, 227, 208, 0.85));
  /* the inverted image is near-black where the plate is solid and
     bright on every drawn line, so screening it over the mass leaves
     the body dark and paints only the linework */
  mix-blend-mode: screen;
}

/* level-chip hover isolates one layer */
.stage.is-isolating .stage-layer,
.stage.is-isolating .stage-mass { opacity: 0.14; }
.stage.is-isolating .stage-layer.is-isolated,
.stage.is-isolating .stage-mass.is-isolated { opacity: 1; }

/* injected route SVGs */
.stage-overlay { pointer-events: none; }
.stage-overlay svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.stage-overlay .route-line {
  cursor: pointer;
  pointer-events: visibleStroke;
  transition: opacity 0.3s ease, filter 0.3s ease;
}

/* when a route is chosen, the rest of the page holds its breath */
.sheet.has-focus .route-line { opacity: 0.12; }
.sheet.has-focus .route-line.is-focus { opacity: 1; }

.route-line.is-focus { filter: drop-shadow(0 0 10px rgba(176, 69, 44, 0.45)); }

/* ---------------- route panel ---------------- */

.panel { border-top: 1px solid var(--gold); }

.panel-head {
  display: flex;
  justify-content: space-between;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--gold-28);
}

.route-list { list-style: none; }

.route-item { border-bottom: 1px solid var(--gold-12); }

.route-btn {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 0.9rem;
  width: 100%;
  min-height: 3.1rem;
  padding: 0.7rem 0.25rem;
  border: 0;
  background: transparent;
  font-family: var(--body);
  font-size: 1.04rem;
  font-weight: 500;
  color: var(--jade);
  text-align: left;
  cursor: pointer;
  transition: background 0.2s ease, padding-left 0.25s ease;
}

.route-btn:hover {
  background: rgba(176, 69, 44, 0.1);
  padding-left: 0.6rem;
}

/* color swatch drawn as a short route stroke with arrowhead */
.route-swatch {
  position: relative;
  width: 26px;
  height: 2px;
  background: currentColor;
  flex-shrink: 0;
}
.route-swatch::after {
  content: "";
  position: absolute;
  right: -1px;
  top: -3px;
  border-left: 6px solid currentColor;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
}

.route-name { min-width: 0; line-height: 1.3; }

.route-status {
  font-family: var(--mono);
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold);
  opacity: 0;
  transition: opacity 0.2s ease;
}

/* status only surfaces on hover — quiet by default */
.route-btn:hover .route-status { opacity: 1; }

.route-btn.is-wip { cursor: default; }
.route-btn.is-wip .route-swatch { opacity: 0.35; }
.route-btn.is-wip .route-name { color: var(--jade-35); font-weight: 400; }
.route-btn.is-wip .route-status { opacity: 0.7; }
.route-btn.is-wip:hover { background: transparent; padding-left: 0.25rem; }

/* ---------------- fullscreen player ---------------- */

.player {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  background: #0d0a06;
  animation: player-in 0.35s ease both;
}

@keyframes player-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

.player[hidden] { display: none; }

.player-chrome {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem var(--pad);
}

.player-caption {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  min-width: 0;
}

.player-swatch { width: 22px; height: 3px; flex-shrink: 0; }

.player-terminal { color: var(--gold); opacity: 0.8; }

.player-route {
  color: var(--jade);
  font-family: var(--body);
  font-size: 1.05rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.player-close {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  border: 1px solid var(--gold-28);
  background: transparent;
  color: var(--gold-bright);
  padding: 0.45rem 0.9rem;
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.16em;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.player-close:hover {
  background: var(--cinnabar);
  border-color: var(--cinnabar);
  color: var(--jade);
}
.player-close-x { font-size: 0.95rem; line-height: 1; }

/* the padding lives on the stage, not the video itself, so a click
   in the gutter around the video hits .player-stage (background)
   rather than the <video> box — that's what lets "click outside the
   video" close the player without swallowing clicks meant for it */
.player-stage {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 var(--pad) var(--pad);
}

#player-video {
  max-width: 100%;
  max-height: 100%;
  outline: none;
}

/* ---------------- responsive ---------------- */

@media (max-width: 900px) {
  .sheet-body { grid-template-columns: 1fr; }
  .stage-frame { width: 100% !important; }
  .tab { padding-left: 1rem; padding-right: 1rem; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
