/* ==========================================================================
   components.css — sound cards, motif buttons, journal interlude,
   anatomy widget, compass visualisation, roll player, credits
   ========================================================================== */

/* Inline-SVG labels: .mono's em-based sizing would blow past the viewBox,
   so pin labels to viewBox units here. */
svg .mono,
svg.mono text {
  font-size: 10px;
  letter-spacing: 0.06em;
}

/* --------------------------------------------------------------------------
   Sound profile card
   -------------------------------------------------------------------------- */
.sound-card {
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 4px;
  background: color-mix(in srgb, var(--bg-soft) 66%, transparent);
  padding: clamp(1.2rem, 3vw, 1.8rem) clamp(1.2rem, 3vw, 2.2rem);
  transition: border-color 1.4s ease, background-color 1.4s ease;
}

.sound-card-title {
  color: var(--ink-dim);
  font-size: 0.66rem;
  letter-spacing: 0.28em;
  margin-bottom: 1.1rem;
}

.sound-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.9rem 2rem;
  margin: 0 0 1.4rem;
}

.sound-card-grid dt {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  color: var(--accent);
  margin-bottom: 0.25rem;
}

.sound-card-grid dd {
  margin: 0;
  font-size: 0.88rem;
  line-height: 1.7;
  color: var(--ink);
}

/* --------------------------------------------------------------------------
   Motif button ("聆听这个时代")
   -------------------------------------------------------------------------- */
.motif-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--font-body);
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--accent);
  padding: 0.65rem 1.5rem;
  border: 1px solid var(--accent);
  border-radius: 999px;
  transition: background-color 0.3s ease, color 0.3s ease, box-shadow 0.3s ease;
}

.motif-btn:hover {
  background: var(--accent);
  color: var(--ebony);
  box-shadow: 0 8px 30px -8px var(--accent-soft);
}

.motif-btn.is-playing {
  background: var(--accent);
  color: var(--ebony);
}

.motif-icon {
  position: relative;
  width: 14px;
  height: 12px;
  display: inline-flex;
  align-items: flex-end;
  gap: 2px;
}

.motif-icon::before,
.motif-icon::after,
.motif-btn .motif-icon i {
  content: '';
  width: 3px;
  height: 100%;
  background: currentColor;
  transform-origin: bottom;
  transform: scaleY(0.4);
}

.motif-icon::after { transform: scaleY(0.8); }

.motif-btn.is-playing .motif-icon::before { animation: eq 0.7s ease-in-out infinite; }
.motif-btn.is-playing .motif-icon::after { animation: eq 0.9s 0.15s ease-in-out infinite; }

@keyframes eq {
  0%, 100% { transform: scaleY(0.3); }
  50% { transform: scaleY(1); }
}

.motif-btn-lg { font-size: 1.02rem; padding: 0.9rem 2.2rem; }

/* --------------------------------------------------------------------------
   "观察机构" button + sound-card actions row
   -------------------------------------------------------------------------- */
.sound-card-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.8rem;
}

.gallery-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-body);
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--ink-dim);
  padding: 0.65rem 1.5rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  transition: color 0.3s ease, border-color 0.3s ease, background-color 0.3s ease;
}

.gallery-btn:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-soft);
}

/* --------------------------------------------------------------------------
   Gallery modal — a museum plate
   -------------------------------------------------------------------------- */
.gallery-modal {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  padding: clamp(1rem, 4vw, 3rem);
}

/* `display: grid` above would defeat the hidden attribute's UA style,
   leaving an invisible full-screen overlay that eats every click. */
.gallery-modal[hidden] { display: none; }

.gallery-backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--ebony) 78%, transparent);
  backdrop-filter: blur(10px);
  opacity: 0;
  transition: opacity 0.32s ease;
}

.gallery-panel {
  position: relative;
  margin: 0;
  max-width: min(60rem, 94vw);
  max-height: calc(100vh - 4rem);
  overflow-y: auto;
  background: color-mix(in srgb, var(--bg-soft) 96%, transparent);
  border: 1px solid var(--line);
  border-top: 3px solid var(--accent);
  border-radius: 6px;
  box-shadow: 0 60px 120px -30px rgba(0, 0, 0, 0.9);
  opacity: 0;
  transform: translateY(22px) scale(0.985);
  transition: opacity 0.32s ease, transform 0.32s cubic-bezier(0.22, 0.9, 0.3, 1);
}

.gallery-modal.is-open .gallery-backdrop { opacity: 1; }
.gallery-modal.is-open .gallery-panel { opacity: 1; transform: none; }

.gallery-close {
  position: absolute;
  top: 0.9rem;
  right: 0.9rem;
  z-index: 2;
  font-size: 0.62rem;
  letter-spacing: 0.2em;
  color: var(--ink-dim);
  padding: 0.35rem 0.8rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: color-mix(in srgb, var(--ebony) 72%, transparent);
  transition: color 0.3s ease, border-color 0.3s ease;
}

.gallery-close:hover { color: var(--accent); border-color: var(--accent); }

.gallery-media {
  display: grid;
  place-items: center;
  min-height: 14rem;
  background:
    radial-gradient(ellipse at 50% 0%, var(--accent-soft), transparent 70%),
    #100d0c;
  padding: clamp(1rem, 3vw, 2rem);
}

.gallery-media img {
  max-width: 100%;
  max-height: 56vh;
  border-radius: 3px;
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.8);
  transition: opacity 0.4s ease;
}

.gallery-modal.is-loading .gallery-media img { opacity: 0; }

.gallery-caption {
  padding: 1.4rem clamp(1.2rem, 3vw, 2.2rem) 1.6rem;
}

.gallery-title {
  font-size: 1.15rem;
  letter-spacing: 0.08em;
  margin-bottom: 0.7rem;
  color: var(--accent);
}

.gallery-note {
  font-size: 0.92rem;
  line-height: 2;
  color: var(--ink);
  max-width: 46rem;
  margin-bottom: 0.9rem;
}

.gallery-credit {
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  color: var(--ink-dim);
}

/* --------------------------------------------------------------------------
   时代乐单 playlist
   -------------------------------------------------------------------------- */
.playlist {
  margin-top: 1.5rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--line);
}

.playlist-title {
  font-size: 0.62rem;
  letter-spacing: 0.26em;
  color: var(--ink-dim);
  margin: 0 0 0.6rem;
}

.playlist-list {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: track;
}

.playlist-list li { border-bottom: 1px dashed var(--line); }
.playlist-list li:last-child { border-bottom: none; }

.playlist-list a {
  counter-increment: track;
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 0.55rem 0.2rem;
  border-bottom: none;
  transition: background-color 0.25s ease, padding-left 0.25s ease;
}

.playlist-list a::before {
  content: counter(track, decimal-leading-zero);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  color: var(--ink-dim);
  flex-shrink: 0;
}

.playlist-list a:hover {
  background: var(--accent-soft);
  padding-left: 0.6rem;
}

.pl-work {
  flex: 1;
  font-size: 0.88rem;
  color: var(--ink);
  transition: color 0.25s ease;
}

.playlist-list a:hover .pl-work { color: var(--accent); }

.pl-meta {
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  color: var(--ink-dim);
  white-space: nowrap;
}

/* External-link arrow, drawn only on hover */
.playlist-list a::after {
  content: '↗';
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--accent);
  opacity: 0;
  transition: opacity 0.25s ease;
}

.playlist-list a:hover::after { opacity: 1; }

@media (max-width: 640px) {
  .pl-meta { display: none; }
}

/* --------------------------------------------------------------------------
   1711 journal interlude — set like a printed page
   -------------------------------------------------------------------------- */
.chapter-journal { display: grid; place-items: center; }

.journal-page {
  max-width: 46rem;
  background: var(--journal-paper, #e9dfc6);
  color: #33291c;
  padding: clamp(2rem, 6vw, 4rem) clamp(1.6rem, 6vw, 4rem);
  border-radius: 2px;
  box-shadow:
    0 40px 90px -30px rgba(0, 0, 0, 0.85),
    inset 0 0 80px rgba(120, 90, 40, 0.18);
  position: relative;
}

/* Deckled top & bottom edges, like cut rag paper */
.journal-page::before,
.journal-page::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  height: 7px;
  background-image: radial-gradient(circle at 6px 0, transparent 5px, var(--journal-paper, #e9dfc6) 5px);
  background-size: 13px 7px;
}

.journal-page::before { top: -6px; transform: rotate(180deg); }
.journal-page::after { bottom: -6px; }

.journal-masthead {
  text-align: center;
  color: #7a6647;
  border-bottom: 1px solid #b9a67f;
  padding-bottom: 0.9rem;
  margin-bottom: 1.6rem;
}

.journal-page .chapter-year {
  -webkit-text-stroke: 0;
  color: #2e2417;
  font-size: clamp(3.6rem, 9vw, 6.5rem);
}

.journal-page .chapter-title {
  color: #2e2417;
  margin-bottom: 1.6rem;
}

.journal-columns {
  columns: 2;
  column-gap: 2.4rem;
  column-rule: 1px solid #c9b88f;
  font-size: 0.94rem;
  line-height: 2;
  text-align: justify;
  margin-bottom: 1.8rem;
}

.journal-columns em { color: #8a5a22; }

.journal-diagram {
  border-top: 1px solid #b9a67f;
  border-bottom: 1px solid #b9a67f;
  padding: 1rem 0;
  margin-bottom: 1.6rem;
  color: #4a3a22;
}

.journal-diagram svg { width: 100%; height: auto; }

.journal-page .motif-btn {
  color: #6d4d1e;
  border-color: #6d4d1e;
}

.journal-page .motif-btn:hover,
.journal-page .motif-btn.is-playing {
  background: #6d4d1e;
  color: var(--journal-paper, #e9dfc6);
}

@media (max-width: 640px) {
  .journal-columns { columns: 1; }
}

/* --------------------------------------------------------------------------
   Anatomy widget（击弦机解剖室）
   -------------------------------------------------------------------------- */
.anatomy {
  max-width: 56rem;
  margin: 0 auto;
}

.anatomy-tabs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.6rem;
  margin-bottom: 2rem;
}

.anatomy-tab {
  font-family: var(--font-body);
  font-size: 0.86rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--ink-dim);
  padding: 0.55rem 1.3rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  transition: color 0.3s ease, border-color 0.3s ease, background-color 0.3s ease;
}

.anatomy-tab:hover { color: var(--accent); border-color: var(--accent); }

.anatomy-tab.is-active {
  color: var(--ebony);
  background: var(--accent);
  border-color: var(--accent);
}

.anatomy-stage {
  border: 1px solid var(--line);
  border-radius: 6px;
  background:
    radial-gradient(ellipse at 50% 0%, var(--accent-soft), transparent 68%),
    color-mix(in srgb, var(--bg-soft) 80%, transparent);
  padding: clamp(1rem, 4vw, 2.4rem);
}

.anatomy-stage svg {
  width: 100%;
  height: auto;
  color: var(--ink);
  display: block;
}

.anatomy-svg .part-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  fill: var(--ink-dim);
}

.anatomy-svg .part-line { stroke: var(--ink-dim); stroke-width: 0.6; stroke-dasharray: 2 3; }
.anatomy-svg .string-line { stroke: var(--ink); }
.anatomy-svg .frame-part { stroke: var(--ink-dim); }
.anatomy-svg .moving-part { stroke: var(--accent); }
.anatomy-svg .hammer-head { fill: var(--accent); }

/* String vibration after the hammer strikes */
.anatomy-svg .string-line { transition: none; }
.anatomy-svg.is-striking .string-line { animation: string-shiver 0.5s 0.24s ease-out; }

@keyframes string-shiver {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(1.6px); }
  40% { transform: translateX(-1.4px); }
  60% { transform: translateX(1px); }
  80% { transform: translateX(-0.6px); }
}

/* Key / hammer / jack movement is driven by CSS classes toggled in JS.
   transform-box: view-box lets transform-origin use viewBox coordinates. */
.anatomy-svg .g-key,
.anatomy-svg .g-hammer,
.anatomy-svg .g-jack,
.anatomy-svg .g-lever {
  transform-box: view-box;
  transition: transform 0.22s cubic-bezier(0.34, 1.3, 0.5, 1);
}

.anatomy-svg.is-striking .g-key { transform: rotate(-2.6deg); }
.anatomy-svg.is-striking .g-hammer { transform: rotate(var(--hammer-throw, -24deg)); }
.anatomy-svg.is-striking .g-jack { transform: rotate(6deg); }
.anatomy-svg.is-striking .g-lever { transform: rotate(-3deg); }

/* Second, half-height strike for the Érard double escapement demo */
.anatomy-svg.is-repeating .g-hammer { transform: rotate(calc(var(--hammer-throw, -24deg) * 0.45)); }

.anatomy-caption {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1.6rem;
}

.anatomy-note {
  max-width: 34rem;
  font-size: 0.9rem;
  line-height: 1.9;
  color: var(--ink-dim);
}

.anatomy-note strong { color: var(--accent); }

/* --------------------------------------------------------------------------
   Compass visualisation（音域的三百年）
   -------------------------------------------------------------------------- */
.compass-viz {
  max-width: 62rem;
  margin: 0 auto;
}

.compass-rows { display: flex; flex-direction: column; gap: 0.55rem; margin-bottom: 1.4rem; }

.compass-row {
  display: grid;
  grid-template-columns: 9.5rem 1fr;
  align-items: center;
  gap: 1.2rem;
}

.compass-row-label {
  text-align: right;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  color: var(--ink-dim);
  line-height: 1.5;
  transition: color 0.3s ease;
}

.compass-row-label b {
  display: block;
  font-family: var(--font-body);
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: 0.08em;
}

.compass-track { position: relative; height: 26px; }

.compass-bar {
  position: absolute;
  top: 4px;
  bottom: 4px;
  border-radius: 999px;
  background: linear-gradient(to right, color-mix(in srgb, var(--accent) 55%, transparent), var(--accent));
  opacity: 0.66;
  transform-origin: left;
  transform: scaleX(0);
  transition: transform 1.1s cubic-bezier(0.25, 0.9, 0.3, 1), opacity 0.3s ease;
  border: none;
  padding: 0;
}

.compass-viz.is-visible .compass-bar { transform: scaleX(1); }

.compass-row:hover .compass-bar,
.compass-row.is-hot .compass-bar { opacity: 1; box-shadow: 0 0 18px var(--accent-soft); }

.compass-row:hover .compass-row-label { color: var(--accent); }

.compass-bar .compass-count {
  position: absolute;
  right: 0.7rem;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.1em;
  color: var(--ebony);
  opacity: 0;
  transition: opacity 0.3s ease;
  white-space: nowrap;
}

.compass-row:hover .compass-count { opacity: 1; }

/* Baseline: 88-key strip */
.compass-keys {
  margin-left: 10.7rem;
  position: relative;
  height: 34px;
  border-radius: 3px;
  overflow: hidden;
  border: 1px solid var(--line);
}

.compass-keys .ck {
  position: absolute;
  top: 0;
  height: 100%;
}

.compass-keys .ck.is-white { background: var(--ivory); border-right: 1px solid rgba(0,0,0,0.35); }
.compass-keys .ck.is-black { background: #191419; height: 60%; z-index: 2; }

.compass-keys .ck.is-dim { opacity: 0.14; }

.compass-legend {
  margin-left: 10.7rem;
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  color: var(--ink-dim);
  margin-top: 0.5rem;
}

@media (max-width: 720px) {
  .compass-row { grid-template-columns: 6.4rem 1fr; gap: 0.7rem; }
  .compass-keys, .compass-legend { margin-left: 7.1rem; }
  .compass-row-label { font-size: 0.56rem; }
  .compass-row-label b { font-size: 0.7rem; }
}

/* --------------------------------------------------------------------------
   Roll player（可播放的打孔纸卷）
   -------------------------------------------------------------------------- */
.roll-player {
  max-width: 42rem;
  margin: 0 auto clamp(2.5rem, 6vh, 4rem);
}

.roll-frame {
  position: relative;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: linear-gradient(to bottom, #241c11, #1b150c);
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.9), inset 0 0 60px rgba(0, 0, 0, 0.5);
  overflow: hidden;
}

.roll-canvas { display: block; width: 100%; height: auto; }

.roll-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.4rem;
  margin-top: 1.4rem;
}

.roll-play {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.92rem;
  letter-spacing: 0.2em;
  color: var(--ebony);
  background: var(--accent);
  padding: 0.7rem 1.8rem;
  border-radius: 999px;
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}

.roll-play:hover { transform: translateY(-2px); box-shadow: 0 10px 30px -8px var(--accent-soft); }

.roll-tune { color: var(--ink-dim); font-size: 0.64rem; letter-spacing: 0.16em; }

/* --------------------------------------------------------------------------
   Credits
   -------------------------------------------------------------------------- */
.credits {
  margin-top: clamp(3rem, 8vh, 5rem);
  padding-top: 2.4rem;
  border-top: 1px solid var(--line);
  text-align: left;
  max-width: 44rem;
  margin-inline: auto;
}

.credits h3 {
  font-size: 0.66rem;
  letter-spacing: 0.3em;
  color: var(--ink-dim);
  margin-bottom: 1.2rem;
}

.credits ul {
  margin: 0 0 1.8rem;
  padding-left: 1.2rem;
  font-size: 0.86rem;
  line-height: 2.1;
  color: var(--ink-dim);
}

.credits-sig {
  text-align: center;
  color: var(--accent);
  font-size: 0.68rem;
  letter-spacing: 0.3em;
}
