/* ============================================================
   Demo page — ink-and-paper aesthetic
   Warm cream palette, gold tianzige, bamboo & mountains scenery,
   floating ink-green play control.
   ============================================================ */

/* ── Base page ────────────────────────────────────────────── */
.demo-page {
  margin: 0;
  min-height: 100vh;
  display: flex; flex-direction: column;
  font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
  color: #2f2a25;
  background:
    radial-gradient(circle at 15% 75%, rgba(196, 168, 115, 0.18), transparent 28%),
    radial-gradient(circle at 85% 18%, rgba(148, 168, 134, 0.20), transparent 30%),
    linear-gradient(135deg, #fbf8f0 0%, #f8f2e7 44%, #fbfaf6 100%);
  overflow-x: hidden;
  transition: background-color 0.25s ease;
}

/* ── Decorative scenery (purely cosmetic; sits behind content) ── */
.scene-bamboo {
  position: fixed;
  right: -40px; top: 80px;
  width: 360px; height: 360px;
  opacity: 0.18;
  pointer-events: none;
  z-index: 0;
}
.scene-bamboo::before,
.scene-bamboo::after {
  content: ""; position: absolute;
  width: 260px; height: 2px;
  background: #6f795f;
  transform: rotate(-38deg);
  top: 90px; right: 20px;
}
.scene-bamboo::after { top: 145px; right: 80px; width: 230px; }
.scene-leaf {
  position: absolute;
  width: 80px; height: 18px;
  border-radius: 100% 0 100% 0;
  background: #6f795f;
  transform: rotate(-18deg);
}
.scene-leaf.l1 { top: 55px;  right: 170px; }
.scene-leaf.l2 { top: 82px;  right: 105px; transform: rotate(8deg);   }
.scene-leaf.l3 { top: 130px; right: 190px; transform: rotate(16deg);  }
.scene-leaf.l4 { top: 162px; right: 128px; transform: rotate(-24deg); }

.scene-mountains {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  height: 250px;
  opacity: 0.13;
  pointer-events: none;
  z-index: 0;
  background:
    linear-gradient(135deg, transparent 0 28%, #7d7569 29% 31%, transparent 32%) 3% 78% / 380px 170px no-repeat,
    linear-gradient(45deg,  transparent 0 36%, #7d7569 37% 39%, transparent 40%) 22% 76% / 420px 190px no-repeat,
    linear-gradient(135deg, transparent 0 30%, #7d7569 31% 33%, transparent 34%) 72% 86% / 420px 180px no-repeat,
    linear-gradient(45deg,  transparent 0 34%, #7d7569 35% 37%, transparent 38%) 92% 80% / 360px 150px no-repeat;
}

.scene-poem {
  position: fixed;
  right: 10.5%; top: 36%;
  writing-mode: vertical-rl;
  letter-spacing: 0.45em;
  color: rgba(76, 65, 54, 0.28);
  font-family: 'Kaiti SC', 'STKaiti', 'KaiTi', '楷体', serif;
  font-size: 17px;
  z-index: 0;
  pointer-events: none;
}
.scene-seal {
  display: inline-flex;
  margin-top: 16px;
  padding: 4px 6px;
  border: 1px solid rgba(166, 70, 48, 0.45);
  color: rgba(166, 70, 48, 0.5);
  font-size: 14px;
  letter-spacing: 0;
  writing-mode: horizontal-tb;
}

/* ── Header ────────────────────────────────────────────────── */
.demo-header {
  position: relative;
  z-index: 10;
  background: rgba(255, 252, 246, 0.78);
  backdrop-filter: saturate(180%) blur(18px);
  -webkit-backdrop-filter: saturate(180%) blur(18px);
  border-bottom: 1px solid rgba(118, 96, 70, 0.08);
  flex-shrink: 0;
  transition: opacity 0.2s ease;
}
.demo-header-inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: 0.7rem 1.5rem;
  display: flex; align-items: center; gap: 1.5rem;
}
.demo-header-inner .brand { margin-right: auto; }

/* Nav-link pill — match the dark-green active pill used on index
   (Worksheet) and builder (Hanzi Builder). Without this override the
   page picks up style.css's default blue-tinted .nav-link.active. */
.demo-page .nav-link {
  padding: 0.55rem 1.1rem;
  border-radius: 999px;
  font-size: 0.86rem; font-weight: 500;
  color: #4c4138;
  letter-spacing: 0.005em;
  transition: background 0.18s ease, color 0.18s ease;
}
.demo-page .nav-link:hover { background: rgba(118, 96, 70, 0.06); color: #2d2823; }
.demo-page .nav-link.active {
  background: #143c2a;
  color: #f7f1e8;
  box-shadow: 0 6px 16px -4px rgba(20, 60, 42, 0.30);
}

/* ── Stage layout ──────────────────────────────────────────── */
.demo-stage {
  position: relative;
  z-index: 2;
  flex: 1;
  display: flex; flex-direction: column;
  align-items: center; justify-content: flex-start;
  padding: 2.5rem 1.5rem 1.5rem;
  width: 100%;
  max-width: 920px;
  margin: 0 auto;
}

/* ── Mode tabs (汉字书写 / 汉字拆解) ───────────────────────── */
.demo-mode-tabs {
  display: inline-flex;
  align-items: stretch;
  gap: 0.45rem;
  padding: 5px;
  margin: 0 auto 2rem;
  background: rgba(255, 252, 246, 0.78);
  border: 1px solid rgba(136, 112, 75, 0.16);
  border-radius: 18px;
  box-shadow:
    0 1px 2px rgba(76, 61, 38, 0.03),
    0 16px 40px -10px rgba(76, 61, 38, 0.10);
}
.demo-mode-tab {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.7rem 1.4rem;
  border-radius: 14px;
  border: none;
  background: transparent;
  color: #6e6359;
  text-decoration: none;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.2s ease, color 0.2s ease, transform 0.08s ease, box-shadow 0.2s ease;
}
.demo-mode-tab:hover  { color: #2d2823; background: rgba(255, 255, 255, 0.6); }
.demo-mode-tab:active { transform: scale(0.97); }
.demo-mode-tab.active,
.demo-mode-tab[aria-selected="true"] {
  background: #143c2a;
  color: #f7f1e8;
  box-shadow: 0 8px 22px -6px rgba(20, 60, 42, 0.34);
}
.demo-mode-tab.active:hover,
.demo-mode-tab[aria-selected="true"]:hover {
  background: #1d5238;
  color: #f7f1e8;
}
.demo-mode-icon {
  font-size: 1.15rem;
  line-height: 1;
  opacity: 0.92;
}
.demo-mode-text {
  display: flex; flex-direction: column; align-items: flex-start;
  line-height: 1.15;
}
.demo-mode-cn {
  font-family: 'Kaiti SC', 'STKaiti', 'KaiTi', '楷体', serif;
  font-size: 1.02rem; font-weight: 600;
  letter-spacing: 0.06em;
}
.demo-mode-en {
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.72;
  margin-top: 0.05rem;
}

/* Hide the tabs in fullscreen for a clean stage */
.demo-page.is-fullscreen .demo-mode-tabs { display: none !important; }

@media (max-width: 680px) {
  .demo-mode-tabs { gap: 0.3rem; padding: 4px; margin-bottom: 1.4rem; }
  .demo-mode-tab  { padding: 0.55rem 0.95rem; gap: 0.5rem; border-radius: 12px; }
  .demo-mode-cn   { font-size: 0.95rem; }
  .demo-mode-en   { display: none; }
}

/* ── Welcome state ─────────────────────────────────────────── */
.stage-welcome {
  text-align: center;
  padding: 0.5rem 1.5rem 2rem;
  max-width: 620px;
  color: #7b7167;
  order: -1;  /* show above the input bar */
}
.stage-welcome-mark {
  width: 64px; height: 64px;
  margin: 0 auto 1.1rem;
  border-radius: 18px;
  background: rgba(255, 255, 255, 0.72);
  box-shadow:
    0 10px 30px rgba(77, 61, 35, 0.12),
    inset 0 0 0 1px rgba(112, 92, 61, 0.08);
  display: grid; place-items: center;
  font-size: 30px;
}
.stage-welcome-title {
  font-family: Georgia, 'Times New Roman', 'STSong', serif;
  font-size: clamp(2rem, 4.4vw, 3.4rem);
  line-height: 1.05;
  letter-spacing: -0.04em;
  color: #2d2823;
  margin: 0 0 0.75rem;
  font-weight: 600;
}
.stage-welcome-sub {
  margin: 0 0 1rem;
  font-size: 1rem; line-height: 1.7;
  color: #7b7167;
}
.stage-welcome-tip { font-size: 0.9rem; color: #9a8e82; margin: 0; }
.stage-welcome-tip a {
  color: #8a6b3a; font-weight: 500; text-decoration: none;
  border-bottom: 1px dashed currentColor;
  transition: color 0.18s ease;
}
.stage-welcome-tip a:hover { color: #5f481f; }

/* ── Input bar ─────────────────────────────────────────────── */
.stage-inputbar {
  display: flex; align-items: center; gap: 0.6rem;
  width: 100%; max-width: 560px;
  margin: 0 auto 2rem;
  padding: 0.35rem 0.45rem 0.35rem 1rem;
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid rgba(136, 112, 75, 0.16);
  border-radius: 16px;
  box-shadow:
    0 1px 2px rgba(76, 61, 38, 0.03),
    0 16px 40px -8px rgba(76, 61, 38, 0.10);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.stage-inputbar:focus-within {
  border-color: rgba(136, 112, 75, 0.35);
  box-shadow:
    0 1px 2px rgba(76, 61, 38, 0.04),
    0 20px 50px -10px rgba(76, 61, 38, 0.14);
}
.stage-input-icon {
  color: #8b8075;
  font-size: 1.15rem; line-height: 1;
  flex-shrink: 0;
}
.stage-input {
  flex: 1; min-width: 0;
  padding: 0.7rem 0.4rem;
  font-size: 1rem;
  font-family: inherit;
  background: transparent;
  border: none;
  outline: none;
  color: #2d2823;
}
.stage-input::placeholder { color: #a8a09a; }
.stage-clear-btn {
  flex-shrink: 0;
  border: none;
  background: #f3eee3;
  color: #83766a;
  border-radius: 999px;
  padding: 0.4rem 0.85rem;
  font-size: 0.82rem; font-weight: 500;
  cursor: pointer;
  font-family: inherit;
  letter-spacing: 0.02em;
  transition: background 0.18s ease, color 0.18s ease, transform 0.08s ease;
}
.stage-clear-btn:hover  { background: #ebe3d2; color: #5e4f3b; }
.stage-clear-btn:active { transform: scale(0.95); }
.stage-go-btn {
  flex-shrink: 0;
  padding: 0.5rem 1.15rem;
  border: none; border-radius: 12px;
  background: #143c2a;
  color: #f7f1e8;
  font-weight: 600; font-size: 0.88rem;
  letter-spacing: 0.01em;
  cursor: pointer;
  font-family: inherit;
  box-shadow: 0 8px 18px -4px rgba(20, 60, 42, 0.30);
  transition: background 0.18s ease, transform 0.08s ease, box-shadow 0.18s ease;
}
.stage-go-btn:hover  {
  background: #1d5238;
  box-shadow: 0 10px 22px -4px rgba(20, 60, 42, 0.36);
}
.stage-go-btn:active { transform: translateY(1px); }

/* ── Active stage ──────────────────────────────────────────── */
.stage-active {
  display: flex; flex-direction: column; align-items: center;
  width: 100%;
  animation: fade-up 0.3s ease both;
}
@keyframes fade-up {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ── Tianzige (米字格) grid card ───────────────────────────── */
.grid-frame {
  position: relative;
  width: 100%;
  max-width: 520px;
  aspect-ratio: 1;
  background: rgba(255, 255, 255, 0.76);
  border: 1px solid rgba(179, 138, 76, 0.30);
  border-radius: 24px;
  box-shadow:
    0 1px 3px rgba(74, 56, 28, 0.03),
    0 24px 70px -16px rgba(74, 56, 28, 0.14);
  overflow: hidden;
  transition: max-width 0.3s ease, background-color 0.25s ease, box-shadow 0.25s ease;
}
.tianzige {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  color: rgba(179, 138, 76, 0.50);    /* warm gold lines */
  pointer-events: none;
}
.tianzige .tz-diag { color: rgba(179, 138, 76, 0.40); }
.char-target {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  transition: opacity 0.25s ease;
}
.char-target svg {
  width: 100% !important; height: 100% !important;
  display: block;
}
.char-target-error {
  color: #7b7167; font-size: 0.9rem; text-align: center; padding: 1rem;
}

/* ── Stats cards ──────────────────────────────────────────── */
.stage-meta {
  width: 100%; max-width: 570px;
  margin: 1.4rem auto 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.85rem;
  background: transparent;
  border: none;
  box-shadow: none;
  border-radius: 0;
  overflow: visible;
}
.stage-meta-block {
  height: 76px;
  display: flex; align-items: center; gap: 0.85rem;
  padding: 0.85rem 1rem;
  background: rgba(255, 255, 255, 0.74);
  border: 1px solid rgba(130, 105, 70, 0.10);
  border-radius: 18px;
  box-shadow:
    0 1px 2px rgba(73, 54, 28, 0.02),
    0 14px 36px -8px rgba(73, 54, 28, 0.10);
  transition: background 0.2s ease, border-color 0.2s ease, transform 0.18s ease;
}
.stage-meta-block:hover { transform: translateY(-1px); }
.stage-meta-icon {
  width: 36px; height: 36px;
  flex-shrink: 0;
  border-radius: 12px;
  background: #f5ebd9;
  color: #ad7d37;
  display: grid; place-items: center;
  font-size: 1.05rem;
}
.stage-meta-icon-glyph {
  font-family: 'Kaiti SC', 'STKaiti', 'KaiTi', '楷体', serif;
  font-weight: 600; font-size: 1.05rem;
}
.stage-meta-text {
  display: flex; flex-direction: column; gap: 0.18rem;
  min-width: 0;
  text-align: left;
}
.stage-meta-key {
  font-weight: 700;
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #9a8e82;
  line-height: 1;
}
.stage-meta-val {
  font-variant-numeric: tabular-nums;
  font-weight: 800; font-size: 1.05rem;
  color: #342c25;
  line-height: 1.1;
}
.stage-meta-val-big { font-size: 1.3rem; }
.stage-meta-char-glyph {
  font-family: 'Kaiti SC', 'STKaiti', '楷体', serif;
  font-weight: 600;
  font-size: 1.3rem;
  color: #342c25;
  letter-spacing: 0.04em;
  line-height: 1;
}

/* ── Char nav (round prev/next + 1/1) ─────────────────────── */
.char-nav {
  display: flex; align-items: center; gap: 1rem;
  margin: 1.25rem 0 0;
  color: #746b62;
}
.char-nav-btn {
  width: 38px; height: 38px;
  border-radius: 999px;
  border: 1px solid rgba(120, 99, 73, 0.12);
  background: rgba(255, 255, 255, 0.55);
  color: #746b62;
  font-size: 1.2rem; line-height: 1;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 8px 20px -4px rgba(72, 56, 34, 0.08);
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease, transform 0.08s ease;
}
.char-nav-btn:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.85);
  border-color: rgba(120, 99, 73, 0.22);
  color: #2f2a25;
}
.char-nav-btn:active:not(:disabled) { transform: scale(0.94); }
.char-nav-btn:disabled              { opacity: 0.3; cursor: not-allowed; }
.char-nav-counter {
  font-variant-numeric: tabular-nums;
  font-size: 0.95rem; color: #5f5651;
  min-width: 50px; text-align: center;
  font-weight: 500;
}
.char-nav-sep { color: #b8aea4; margin: 0 0.25em; }

/* ── Floating control dock (ink-paper aesthetic) ──────────── */
.dock {
  position: fixed;
  bottom: 1.25rem;
  left: 50%;
  transform: translateX(-50%);
  width: min(760px, calc(100vw - 2rem));
  z-index: 40;
  padding: 1.05rem 1.4rem 1rem;
  background: rgba(255, 252, 246, 0.82);
  backdrop-filter: saturate(180%) blur(18px);
  -webkit-backdrop-filter: saturate(180%) blur(18px);
  border: 1px solid rgba(118, 96, 70, 0.12);
  border-radius: 24px;
  box-shadow:
    0 1px 3px rgba(72, 54, 31, 0.03),
    0 28px 80px -16px rgba(72, 54, 31, 0.18);
  display: flex; flex-direction: column; gap: 0.85rem;
}

.dock-row { display: flex; align-items: center; gap: 0.7rem; }
.dock-row-playback { justify-content: center; gap: 0.7rem; }
.dock-row-options  { gap: 1rem; flex-wrap: wrap; justify-content: center; color: #746b62; font-size: 0.84rem; }

/* Playback buttons */
.pb-btn {
  width: 44px; height: 44px;
  border-radius: 999px;
  border: 1px solid rgba(115, 96, 73, 0.10);
  background: #f7f1e8;
  color: #2f2a25;
  font-size: 1rem;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  box-shadow: 0 8px 20px -4px rgba(70, 52, 30, 0.08);
  transition: background 0.18s ease, color 0.18s ease, transform 0.08s ease, box-shadow 0.18s ease;
}
.pb-btn:hover  {
  background: #f0e7d6;
  box-shadow: 0 10px 24px -4px rgba(70, 52, 30, 0.14);
}
.pb-btn:active { transform: scale(0.94); }
.pb-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.pb-btn.pb-main {
  width: 60px; height: 60px;
  background: #143c2a;
  color: #fff;
  border-color: transparent;
  box-shadow: 0 14px 34px -6px rgba(20, 60, 42, 0.32);
}
.pb-btn.pb-main:hover {
  background: #1d5238;
  box-shadow: 0 16px 38px -6px rgba(20, 60, 42, 0.40);
}

/* Color dots */
.dock-colors {
  display: flex; align-items: center; gap: 0.45rem;
}
.dock-color-swatch {
  width: 18px; height: 18px;
  border-radius: 50%;
  border: none;
  cursor: pointer;
  padding: 0;
  box-shadow:
    0 0 0 2px #fff,
    0 0 0 3px rgba(34, 31, 29, 0.10);
  transition: transform 0.15s cubic-bezier(.2,.8,.2,1), box-shadow 0.18s ease;
}
.dock-color-swatch:hover {
  transform: scale(1.15) translateY(-1px);
  box-shadow:
    0 0 0 2px #fff,
    0 0 0 3px rgba(20, 60, 42, 0.6);
}
.dock-color-swatch:active { transform: scale(0.95); }
.dock-color-swatch.active {
  box-shadow:
    0 0 0 3px #fff,
    0 0 0 5px #211f1d;
}

/* Speed control */
.dock-control { display: flex; align-items: center; gap: 0.55rem; }
.dock-control-key { letter-spacing: 0.02em; color: #746b62; font-weight: 500; }
.dock-control-val { font-variant-numeric: tabular-nums; min-width: 2.4em; color: #2f2a25; font-weight: 700; }
.dock-slider {
  width: 130px;
  appearance: none; -webkit-appearance: none;
  height: 3px; background: rgba(20, 60, 42, 0.18); border-radius: 3px; cursor: pointer;
  accent-color: #143c2a;
}
.dock-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 14px; height: 14px; border-radius: 50%;
  background: #143c2a; cursor: pointer;
  box-shadow: 0 2px 6px rgba(20, 60, 42, 0.30);
}
.dock-slider::-moz-range-thumb {
  width: 14px; height: 14px; border: none; border-radius: 50%;
  background: #143c2a; cursor: pointer;
  box-shadow: 0 2px 6px rgba(20, 60, 42, 0.30);
}

/* Checkbox toggles */
.dock-toggle {
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-size: 0.84rem; color: #746b62;
  cursor: pointer; user-select: none;
  white-space: nowrap;
}
.dock-toggle input {
  width: 15px; height: 15px;
  accent-color: #143c2a;
  cursor: pointer;
}

/* Pill buttons + Fullscreen */
.dock-pill,
.dock-fullscreen {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.5rem 1rem;
  border-radius: 12px;
  border: 1px solid rgba(104, 84, 61, 0.14);
  background: rgba(250, 247, 239, 0.92);
  color: #342c25;
  font-size: 0.82rem; font-weight: 600;
  letter-spacing: 0.01em;
  cursor: pointer;
  font-family: inherit;
  box-shadow: 0 1px 2px rgba(72, 54, 31, 0.03);
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease,
              transform 0.08s ease, box-shadow 0.18s ease;
}
.dock-pill:hover,
.dock-fullscreen:hover {
  background: #fffaf0;
  border-color: rgba(104, 84, 61, 0.26);
  box-shadow:
    0 1px 2px rgba(72, 54, 31, 0.04),
    0 6px 16px -4px rgba(72, 54, 31, 0.10);
}
.dock-pill:active,
.dock-fullscreen:active { transform: scale(0.97); }
.dock-pill.active {
  background: #143c2a; color: #f7f1e8; border-color: transparent;
  box-shadow: 0 8px 20px -4px rgba(20, 60, 42, 0.30);
}

/* ── Components panel ──────────────────────────────────────── */
.components-panel {
  width: 100%; max-width: 560px;
  margin-top: 1.3rem;
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid rgba(130, 105, 70, 0.12);
  border-radius: 18px;
  padding: 0.95rem 1.1rem 1.05rem;
  box-shadow:
    0 1px 2px rgba(73, 54, 28, 0.02),
    0 14px 36px -10px rgba(73, 54, 28, 0.10);
  animation: fade-up 0.22s ease both;
}
.components-panel-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 0.75rem;
}
.components-panel-title { font-size: 0.82rem; color: #7b7167; font-weight: 500; }
.components-panel-title span {
  color: #2d2823; font-weight: 700; font-size: 1rem; margin-left: 0.25em;
  font-family: 'Kaiti SC', 'STKaiti', 'KaiTi', '楷体', serif;
}
.components-panel-close {
  background: none; border: none; cursor: pointer;
  color: #a8a09a; font-size: 1rem;
  padding: 0.25rem 0.5rem; border-radius: 8px;
  transition: background 0.15s, color 0.15s;
}
.components-panel-close:hover { background: rgba(118, 96, 70, 0.08); color: #2d2823; }

.components-list { display: flex; flex-direction: column; gap: 0.55rem; }
.component-legend-row {
  display: flex; align-items: center; gap: 0.85rem;
  padding: 0.55rem 0.7rem;
  background: rgba(255, 252, 246, 0.92);
  border: 1px solid rgba(130, 105, 70, 0.10);
  border-radius: 12px;
}
.component-swatch {
  width: 14px; height: 14px;
  border-radius: 50%;
  flex-shrink: 0;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.08);
}
.component-legend-char {
  font-family: 'Kaiti SC', 'STKaiti', '楷体', serif;
  font-size: 1.7rem; line-height: 1; color: #2d2823;
  min-width: 1.4em; text-align: center;
}
.component-legend-meta { display: flex; flex-direction: column; gap: 0.1rem; line-height: 1.2; }
.component-legend-name { font-size: 0.86rem; color: #342c25; font-weight: 600; }
.component-legend-en   { font-size: 0.72rem; color: #7b7167; }

.components-empty {
  margin: 0.5rem 0 0;
  font-size: 0.88rem; color: #7b7167;
  text-align: center;
}

/* ── Footer ──────────────────────────────────────────────── */
.demo-footer {
  position: relative;
  z-index: 2;
  background: transparent;
  border-top: none;
  margin-bottom: 10rem;  /* push the entire footer ABOVE the fixed dock */
  padding: 0.5rem 1rem;
  color: #9a8e82;
  text-align: center;
}
.demo-footer a {
  color: #8a6b3a;
  text-decoration: none;
  border-bottom: 1px dashed currentColor;
  transition: color 0.18s ease;
}
.demo-footer a:hover { color: #5f481f; }
.site-footer-sep { color: #c5b6a4; margin: 0 0.5em; }

/* (Previous padding-bottom hack to clear a fixed dock has been removed —
   the single-viewport rules below put the dock in flow, so no reservation
   is needed.) */

/* ── Fullscreen mode ───────────────────────────────────────── */
.demo-page.is-fullscreen {
  display: flex; flex-direction: column;
  align-items: stretch;
  height: 100dvh; overflow: hidden;
}
.demo-page.is-fullscreen .demo-header,
.demo-page.is-fullscreen .stage-welcome,
.demo-page.is-fullscreen .demo-mode-tabs,
.demo-page.is-fullscreen .demo-footer,
.demo-page.is-fullscreen .scene-bamboo,
.demo-page.is-fullscreen .scene-mountains,
.demo-page.is-fullscreen .scene-poem {
  display: none !important;
}
/* Keep the input bar visible in fullscreen so the user can type a new
   character without exiting. Sits at the top of the stage. */
.demo-page.is-fullscreen .stage-inputbar {
  flex-shrink: 0;
  margin: 0 auto 0.6rem;
  max-width: 560px;
  width: 100%;
}
/* Stage takes all space above the dock and centers its content
   vertically — so the grid + stats + nav cluster sits in the middle
   instead of clinging to the top with a giant empty band below. */
.demo-page.is-fullscreen .demo-stage {
  padding: 0.5rem 1.5rem;
  flex: 1 1 auto;
  min-height: 0;
  justify-content: center;
  align-items: center;
  display: flex; flex-direction: column;
  gap: 0;
  overflow: hidden;
  max-width: none;
}
.demo-page.is-fullscreen .stage-active {
  flex: 0 0 auto;             /* content-sized so centering works */
  display: flex; flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
}
.demo-page.is-fullscreen .grid-frame {
  /* Fullscreen keeps the input bar visible (for re-typing) but hides
     header/welcome/tabs/footer. The grid side is the smaller of:
     70% of viewport width, leftover vertical space (chrome ~420px for
     input + stats + nav + dock + paddings), or a hard 720px cap so the
     grid never dominates very high-DPI monitors. */
  --grid-side: min(70vw, calc(100dvh - 420px), 720px);
  width:  var(--grid-side);
  height: var(--grid-side);
  max-width:  var(--grid-side);
  max-height: var(--grid-side);
  margin: 0 auto;
}
.demo-page.is-fullscreen .stage-meta { margin: 0; }
.demo-page.is-fullscreen .char-nav   { margin: 0; }
/* Dock stays in flow as a sibling of demo-stage, sits below it
   naturally. The earlier `bottom: 1.5rem` only worked when position
   was fixed; with the single-viewport rules above the dock is static
   in flow. A small bottom margin keeps it off the screen edge. */
.demo-page.is-fullscreen .dock {
  margin: 0 auto 0.75rem;
  position: static;
}
.demo-page.is-fullscreen .dock-row-options .dock-toggle,
.demo-page.is-fullscreen .dock-row-options .dock-control-slider {
  display: none;
}

/* ── Night mode ────────────────────────────────────────────── */
.demo-page.night-mode {
  background:
    radial-gradient(circle at 15% 75%, rgba(40, 60, 80, 0.18), transparent 30%),
    radial-gradient(circle at 85% 18%, rgba(60, 80, 60, 0.18), transparent 32%),
    linear-gradient(135deg, #0e0d0b 0%, #14120e 50%, #0c0b09 100%);
  color: #e7e2d6;
}
.demo-page.night-mode .scene-bamboo,
.demo-page.night-mode .scene-mountains,
.demo-page.night-mode .scene-poem { opacity: 0.08; }
.demo-page.night-mode .demo-header {
  background: rgba(20, 18, 14, 0.85);
  border-bottom-color: rgba(255, 248, 230, 0.06);
}
.demo-page.night-mode .brand-name,
.demo-page.night-mode .nav-link  { color: #e7e2d6; }
.demo-page.night-mode .nav-link.active { color: #fff; }

.demo-page.night-mode .stage-welcome-mark {
  background: rgba(40, 36, 28, 0.7);
  box-shadow:
    0 10px 30px rgba(0, 0, 0, 0.35),
    inset 0 0 0 1px rgba(255, 235, 200, 0.08);
}
.demo-page.night-mode .stage-welcome-title { color: #f5efde; }
.demo-page.night-mode .stage-welcome-sub,
.demo-page.night-mode .stage-welcome-tip   { color: #a39a87; }
.demo-page.night-mode .stage-welcome-tip a { color: #d4b87a; }

.demo-page.night-mode .stage-inputbar {
  background: rgba(28, 25, 20, 0.78);
  border-color: rgba(255, 235, 200, 0.10);
}
.demo-page.night-mode .stage-input        { color: #f5efde; }
.demo-page.night-mode .stage-input-icon   { color: #a39a87; }
.demo-page.night-mode .stage-clear-btn    { background: #2a2620; color: #c5b9a0; }
.demo-page.night-mode .stage-clear-btn:hover { background: #36302a; color: #f5efde; }
.demo-page.night-mode .stage-go-btn       { background: #2a6e4c; }
.demo-page.night-mode .stage-go-btn:hover { background: #348959; }

.demo-page.night-mode .grid-frame {
  background: rgba(20, 18, 14, 0.82);
  border-color: rgba(179, 138, 76, 0.30);
}
.demo-page.night-mode .tianzige        { color: rgba(179, 138, 76, 0.38); }
.demo-page.night-mode .tianzige .tz-diag { color: rgba(179, 138, 76, 0.28); }

.demo-page.night-mode .stage-meta-block {
  background: rgba(28, 25, 20, 0.74);
  border-color: rgba(255, 235, 200, 0.08);
}
.demo-page.night-mode .stage-meta-icon {
  background: rgba(173, 125, 55, 0.18);
  color: #e0b86b;
}
.demo-page.night-mode .stage-meta-key  { color: #8a8073; }
.demo-page.night-mode .stage-meta-val,
.demo-page.night-mode .stage-meta-char-glyph { color: #f5efde; }

.demo-page.night-mode .char-nav-btn {
  background: rgba(28, 25, 20, 0.6);
  color: #c5b9a0;
  border-color: rgba(255, 235, 200, 0.10);
}
.demo-page.night-mode .char-nav-btn:hover:not(:disabled) {
  background: rgba(40, 36, 28, 0.85); color: #f5efde;
  border-color: rgba(255, 235, 200, 0.20);
}
.demo-page.night-mode .char-nav-counter { color: #a39a87; }
.demo-page.night-mode .char-nav-sep     { color: #4a4338; }

.demo-page.night-mode .dock {
  background: rgba(20, 18, 14, 0.85);
  border-color: rgba(255, 235, 200, 0.08);
}
.demo-page.night-mode .pb-btn {
  background: #2a2620; color: #f5efde;
  border-color: rgba(255, 235, 200, 0.06);
}
.demo-page.night-mode .pb-btn:hover { background: #36302a; }
.demo-page.night-mode .pb-btn.pb-main { background: #2a6e4c; color: #fff; }
.demo-page.night-mode .pb-btn.pb-main:hover { background: #348959; }

.demo-page.night-mode .dock-slider { background: rgba(255, 235, 200, 0.12); }
.demo-page.night-mode .dock-slider::-webkit-slider-thumb { background: #2a6e4c; }
.demo-page.night-mode .dock-slider::-moz-range-thumb     { background: #2a6e4c; }
.demo-page.night-mode .dock-control     { color: #a39a87; }
.demo-page.night-mode .dock-control-key { color: #a39a87; }
.demo-page.night-mode .dock-control-val { color: #f5efde; }
.demo-page.night-mode .dock-toggle      { color: #a39a87; }

.demo-page.night-mode .dock-pill,
.demo-page.night-mode .dock-fullscreen {
  background: rgba(28, 25, 20, 0.78);
  color: #f5efde;
  border-color: rgba(255, 235, 200, 0.08);
}
.demo-page.night-mode .dock-pill:hover,
.demo-page.night-mode .dock-fullscreen:hover { background: #36302a; }
.demo-page.night-mode .dock-pill.active {
  background: #2a6e4c; color: #fff;
}

.demo-page.night-mode .dock-color-swatch {
  box-shadow:
    0 0 0 2px #20180c,
    0 0 0 3px rgba(255, 235, 200, 0.10);
}
.demo-page.night-mode .dock-color-swatch.active {
  box-shadow:
    0 0 0 3px #20180c,
    0 0 0 5px #f5efde;
}

.demo-page.night-mode .components-panel {
  background: rgba(20, 18, 14, 0.82); border-color: rgba(255, 235, 200, 0.08);
}
.demo-page.night-mode .components-panel-title  { color: #a39a87; }
.demo-page.night-mode .components-panel-title span { color: #f5efde; }
.demo-page.night-mode .components-panel-close      { color: #8a8073; }
.demo-page.night-mode .components-panel-close:hover {
  background: rgba(255, 235, 200, 0.08); color: #f5efde;
}
.demo-page.night-mode .component-legend-row {
  background: rgba(28, 25, 20, 0.74); border-color: rgba(255, 235, 200, 0.08);
}
.demo-page.night-mode .component-legend-char,
.demo-page.night-mode .component-legend-name { color: #f5efde; }
.demo-page.night-mode .component-legend-en   { color: #a39a87; }
.demo-page.night-mode .components-empty      { color: #8a8073; }

.demo-page.night-mode .demo-footer    { color: #8a8073; }
.demo-page.night-mode .demo-footer a  { color: #d4b87a; }
.demo-page.night-mode .demo-footer a:hover { color: #ead29a; }

/* ── Mobile ────────────────────────────────────────────────── */
@media (max-width: 680px) {
  .demo-stage      { padding: 1.5rem 1rem 13rem; }
  .stage-welcome   { padding: 0 1rem 1.4rem; }
  .stage-welcome-mark { width: 56px; height: 56px; font-size: 26px; }
  .stage-inputbar  { padding: 0.3rem 0.4rem 0.3rem 0.8rem; }
  .stage-go-btn    { padding: 0.45rem 0.85rem; }
  .grid-frame      { max-width: 92vw; }
  .stage-meta      { grid-template-columns: 1fr; gap: 0.6rem; }
  .stage-meta-block { height: 64px; padding: 0.7rem 0.85rem; }
  .dock            { padding: 0.85rem 0.85rem 0.8rem; width: calc(100vw - 1.5rem); bottom: 0.75rem; }
  .pb-btn          { width: 38px; height: 38px; font-size: 0.9rem; }
  .pb-btn.pb-main  { width: 48px; height: 48px; }
  .dock-row-options { gap: 0.6rem; }
  .dock-slider     { width: 90px; }
  .dock-fullscreen span { display: none; }
  .scene-poem,
  .scene-bamboo    { display: none; }
}

/* ============================================================
   Single-viewport (100dvh) layout — Stroke Animation page
   Keep header / inputs / grid / stats / dock all visible inside
   the viewport without a page-level scrollbar. The grid scales
   to whatever vertical space is left after the fixed-height
   pieces. Tested down to ~700px tall viewports.
   ------------------------------------------------------------ */

/* Lock the page to viewport height (use 100dvh — survives mobile
   address-bar collapse — and kill any page-level scrolling). */
.demo-page {
  height: 100dvh;
  overflow: hidden;
}

/* .demo-stage takes the remaining vertical space and lays its
   children out in a flex column. min-height:0 lets it shrink
   below content size if needed; overflow:hidden keeps the page
   from gaining a scrollbar when content overflows. */
.demo-stage {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  padding: 0.5rem 1.5rem 0.4rem;
  gap: 0.4rem;
}

/* Tighten the welcome block so it doesn't crowd the grid on
   short laptop screens. */
.stage-welcome {
  padding: 0.25rem 1.25rem 0.4rem;
  flex-shrink: 0;
  max-width: 620px;
}
.stage-welcome-mark  { width: 44px; height: 44px; margin: 0 auto 0.4rem; font-size: 1.2rem; }
.stage-welcome-title { font-size: clamp(1.35rem, 2.6vw, 2rem); margin-bottom: 0.3rem; }
.stage-welcome-sub   { margin: 0 0 0.35rem; font-size: 0.88rem; line-height: 1.45; }
.stage-welcome-tip   { font-size: 0.82rem; margin: 0; }

/* Mode tabs + input bar: fixed-height items, don't flex. */
.demo-mode-tabs   { flex-shrink: 0; }
.stage-inputbar   { flex-shrink: 0; margin: 0; }

/* Active state owns the remaining space; grid fills it. */
.stage-active {
  flex: 1 1 auto;
  min-height: 0;
  display: flex; flex-direction: column; align-items: center;
  width: 100%;
  gap: 0.4rem;
}

/* Grid: square that fits BOTH the available width AND the leftover
   vertical space. We set width AND height to the same min() so the
   frame is square regardless of which axis is the binding constraint.
   aspect-ratio alone is unreliable here because flex-column shrink
   was overriding the height calculation.
   ~440px reserves room for: header (~103) + mode-tabs (~66) + input-bar
   (~56) + stats (~65) + dock (~179) + paddings/gaps. If the header /
   dock chrome shifts noticeably, tune the 440px subtrahend. */
.grid-frame {
  flex: 0 0 auto;
  --grid-side: min(100%, calc(100dvh - 540px));
  width:  var(--grid-side);
  height: var(--grid-side);
  max-width:  var(--grid-side);
  max-height: var(--grid-side);
  aspect-ratio: 1 / 1;
  margin: 0 auto;
}

/* Stats row: compact fixed-height card row, tight gap above. */
.stage-meta       { flex-shrink: 0; margin: 0.5rem 0 0; }
.stage-meta-block { height: auto; padding: 0.55rem 0.85rem; }

/* Dock: in flow at the bottom of the body — NOT fixed anymore.
   Header / stage / dock all stack inside the 100dvh body. */
.dock {
  position: static;
  transform: none;
  left: auto; bottom: auto;
  margin: 0 auto 0.4rem;
  flex-shrink: 0;
}

/* Active container: keep children tightly stacked. */
.stage-active {
  gap: 0.35rem;
  justify-content: flex-start;
}

/* Hide the small site footer on this page — out of viewport budget. */
.demo-footer { display: none; }

