/* Base layer behind every page — same technique as game/css/layout.css's
   body rule (a soft wash layered under the illustration via background-image
   so it stays legible under every opaque card on top of it, fixed so it
   doesn't scroll with content), but the wash color comes from THIS app's
   own --bg-page token instead of importing v1's slightly different pink. */
html, body {
  min-height: 100%;
  background-color: var(--bg-page);
  background-image: linear-gradient(
      180deg,
      color-mix(in srgb, var(--bg-page) 92%, transparent),
      color-mix(in srgb, var(--bg-page) 96%, transparent)
    ),
    url("../assets/bg/stage-01-restore.webp");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-attachment: fixed;
  color: var(--text-main);
  font-family: var(--font-base);
}

#app-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* ---------- Top nav ---------- */

#topnav {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  padding: var(--space-3) var(--space-6);
  background: var(--surface);
  border-bottom: 1px solid var(--border-soft);
  position: sticky;
  top: 0;
  z-index: 20;
}

.topnav-brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: 800;
  font-size: 1.05rem;
  color: var(--primary);
  white-space: nowrap;
}

.topnav-brand .version-tag {
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--surface);
  background: var(--git-branch);
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  letter-spacing: 0.04em;
}

#topnav-tabs {
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  flex: 1;
}

/* ---------- Main content ---------- */

#app-main {
  flex: 1;
  padding: var(--space-5) var(--space-6) var(--space-7);
}

.tab-panel {
  display: none;
}

.tab-panel.is-active {
  display: block;
  animation: panel-in 220ms var(--ease-standard);
}

@keyframes panel-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .tab-panel.is-active { animation: none; }
}

/* ---------- Studio layout: main workspace | character sidebar ---------- */
/* 2 columns: everything except 櫻's card lives in the wide left column —
   the timeline editor on top, then the two Demo cards side by side below
   it (.studio-main / .studio-demo-row) — and 櫻's character card is a
   narrow-ish sidebar on the far right (260-320px). Column ORDER here must
   match the DOM order arrangement-studio.js's render() builds (main column
   first, character column second) — swapping one without the other would
   put the sidebar back on the wrong side. See responsive.css for how this
   collapses to a single stacked column at <=1279px. */

.studio-grid {
  display: grid;
  grid-template-columns: 1fr minmax(260px, 320px);
  gap: var(--space-5);
  align-items: start;
}

.studio-main {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  /* Without this, the grid item's automatic min-width defaults to the
     min-content width of everything inside it — including the 32-step
     timeline editor. That's the same bug the old 3-column layout hit
     (see git history): it blew .studio-grid out past the viewport and
     clipped a whole column off-screen, invisible behind html/body's
     overflow-x:hidden. min-width: 0 lets the grid track's actual size
     win instead, so the timeline editor's own flexible columns (not a
     scroll container, at this width) can shrink to fit. */
  min-width: 0;
}

/* 本次 Demo card + 最新 Demo 時光軸 card, side by side under the timeline
   editor — both still inside .studio-main, not spanning the character
   sidebar. */
.studio-demo-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
  align-items: start;
}

.studio-demo-row > .card {
  /* Same min-width:0 story as .studio-main above: a long demo name or
     git-style message could otherwise force a card wider than its 1fr
     share and reintroduce the same overflow bug. */
  min-width: 0;
}

/* ---------- Project status bar ---------- */

.status-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
}

/* Title + 櫻's hint bubble sit together as one group on the left, so the
   auto-margin that pushes the 方塊變更/Demo 節點/遠端 pills to the right
   edge lives on the GROUP, not on .status-bar__title alone — otherwise the
   hint bubble (inserted after the title) would get shoved out to the right
   edge along with the pills instead of sitting right next to the title. */
.status-bar__title-group {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-5);
  margin-right: auto;
}

.status-bar__title {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.status-bar__title h1 {
  font-size: 1.5rem;
  font-weight: 800;
  margin: 0;
}

.status-bar__branch {
  font-size: 0.85rem;
  color: var(--git-branch);
  font-weight: 700;
  display: flex;
  align-items: center;
  gap: 6px;
}

/* ---------- Rhythm test overlay ---------- */

#rhythm-modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(67, 39, 56, 0.45);
  display: none;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  z-index: 100;
}

#rhythm-modal-backdrop.is-open {
  display: flex;
}

/* ---------- Nickname gate ---------- */
/* Same overlay treatment as the rhythm-test modal above, but a plain
   always-flex fixed element removed from the DOM on submit (js/nickname-gate.js)
   instead of an is-open toggle — there's nothing to reopen. z-index sits
   ABOVE the rhythm modal's 100, since this gate has to block absolutely
   everything (including that modal) until a nickname is submitted. */
#nickname-gate-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(67, 39, 56, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  z-index: 300;
}

.nickname-gate-card {
  background: var(--surface);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-card-hover);
  width: min(420px, 100%);
  padding: var(--space-6) var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  text-align: center;
}

.nickname-gate-card h1 {
  font-size: 1.4rem;
  font-weight: 800;
  margin: 0;
}

.nickname-gate-card .demo-name-field {
  text-align: left;
}

.rhythm-modal {
  background: var(--surface);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-card-hover);
  width: min(880px, 100%);
  max-height: min(760px, 92vh);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.rhythm-modal__header {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border-soft);
}

.rhythm-modal__header-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Without this, the flex row's default min-width:auto lets this column
     refuse to shrink, which instead squeezed the "返回編曲工作台" button
     next to it down to a 3-line-wrapped sliver on narrow screens. */
  min-width: 0;
}

.rhythm-modal__header .btn-tertiary {
  flex-shrink: 0;
}

.rhythm-modal__body {
  padding: var(--space-4) var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  overflow-y: auto;
}

.rhythm-canvas-wrap {
  position: relative;
  aspect-ratio: 16 / 9;
  width: 100%;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: radial-gradient(circle at 50% 0%, #2c1f45 0%, #1a1330 60%, #120c22 100%);
  border: 1px solid var(--border-soft);
}

.rhythm-canvas-wrap canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.rhythm-modal__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--border-soft);
  flex-wrap: wrap;
}
