:root {
  color-scheme: dark;
  --stone: oklch(0.13 0.018 255);
  --stone-deep: oklch(0.065 0.012 255);
  --oak: oklch(0.28 0.068 48);
  --oak-dark: oklch(0.16 0.045 38);
  --oak-light: oklch(0.39 0.086 60);
  --leather: oklch(0.2 0.055 28);
  --leather-dark: oklch(0.1 0.028 24);
  --iron: oklch(0.23 0.012 45);
  --iron-dark: oklch(0.105 0.006 45);
  --brass: oklch(0.68 0.13 78);
  --brass-bright: oklch(0.84 0.16 84);
  --brass-dark: oklch(0.42 0.1 72);
  --wax: oklch(0.46 0.17 25);
  --mimic: oklch(0.48 0.16 24);
  --tongue: oklch(0.62 0.18 18);
  --vellum: oklch(0.82 0.065 82);
  --vellum-deep: oklch(0.68 0.08 77);
  --vellum-ink: oklch(0.18 0.045 44);
  --vellum-text: oklch(0.34 0.1 40);
  --vellum-text-muted: oklch(0.34 0.055 48);
  --vellum-text-strong: oklch(0.24 0.055 44);
  --vellum-text-dim: oklch(0.32 0.06 48);
  --vellum-text-accent: oklch(0.28 0.12 28);
  --placeholder: oklch(0.3 0.05 48);
  --tooth: oklch(0.96 0.025 92);
  --ink: oklch(0.97 0.02 86);
  --muted: oklch(0.82 0.045 78);
  --dim: oklch(0.68 0.045 70);
  --danger: oklch(0.68 0.2 26);
  --raised-shadow:
    0 2px 0 oklch(1 0 0 / 0.06) inset,
    0 -12px 24px oklch(0 0 0 / 0.22) inset,
    0 12px 0 oklch(0.04 0.012 24 / 0.9),
    0 26px 36px oklch(0 0 0 / 0.42);

  /* Type scale — 8 steps, 1.125–1.2 ratio between closely-spaced steps.
     xs is micro labels only; sm covers secondary metadata and notes;
     base is body and form labels; md/lg are emphasized text and h3;
     xl is h2 and data; 2xl is mobile h1; display is desktop h1. */
  --text-xs: 0.8125rem;      /* 13px — micro labels, avatar initials only */
  --text-sm: 0.9375rem;      /* 15px — secondary metadata, notes, inputs */
  --text-base: 1rem;         /* 16px — body, form labels */
  --text-md: 1.125rem;       /* 18px — song titles, emphasized body */
  --text-lg: 1.25rem;        /* 20px — h3 */
  --text-xl: 1.5rem;         /* 24px — h2, stat numbers */
  --text-2xl: 2.625rem;      /* 42px — mobile h1 */
  --text-display: clamp(2.75rem, 5vw, 3.75rem); /* 44–60px — h1 */

  /* Font families — Cinzel for display (carved stone), Crimson Pro for body
     (old-style serif, reads like printed vellum). Both from Google Fonts. */
  --font-display: "Cinzel", "Trajan Pro", Georgia, "Times New Roman", serif;
  --font-body: "Crimson Pro", Georgia, "Times New Roman", serif;

  font-family: var(--font-body);
  font-feature-settings: "kern" 1, "liga" 1, "calt" 1, "onum" 1;
  font-kerning: normal;
  text-rendering: optimizeLegibility;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  min-height: 100vh;
  color: var(--ink);
  background:
    radial-gradient(ellipse at 48% -8%, oklch(0.72 0.15 82 / 0.18), transparent 34rem),
    radial-gradient(circle at 9% 23%, oklch(0.42 0.14 28 / 0.2), transparent 24rem),
    radial-gradient(circle at 92% 8%, oklch(0.38 0.12 304 / 0.22), transparent 28rem),
    linear-gradient(180deg, oklch(0.16 0.025 260), var(--stone) 42%, var(--stone-deep));
}

body::before {
  position: fixed;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(circle at 18% 28%, oklch(1 0 0 / 0.035) 0 0.08rem, transparent 0.12rem),
    radial-gradient(circle at 72% 38%, oklch(0 0 0 / 0.18) 0 0.1rem, transparent 0.13rem),
    radial-gradient(circle at 52% 80%, oklch(1 0 0 / 0.025) 0 0.07rem, transparent 0.1rem),
    linear-gradient(180deg, transparent, oklch(0 0 0 / 0.26));
  content: "";
}

/* Logged-out closed tavern. This branch does not use the app shell,
   hero panel, queue panel, or shared button classes. */
.lo-shell {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: minmax(20rem, 0.82fr) minmax(0, 1.18fr);
  gap: 1.45rem;
  width: min(1750px, calc(100% - 2rem));
  min-height: 100vh;
  margin: 0 auto;
  padding: 1rem 0;
  overflow: hidden;
  color: var(--ink);
}

.lo-sky,
.lo-sky::before,
.lo-sky::after {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.lo-sky {
  background:
    radial-gradient(circle at 75% 14%, oklch(0.92 0.055 96 / 0.92) 0 3.25rem, transparent 3.42rem),
    radial-gradient(circle at 71% 16%, oklch(0.8 0.12 92 / 0.2), transparent 10rem),
    radial-gradient(ellipse at 42% 10%, oklch(0.62 0.16 302 / 0.18), transparent 25rem),
    radial-gradient(ellipse at 58% -8%, oklch(0.48 0.14 218 / 0.2), transparent 30rem),
    radial-gradient(ellipse at 18% 80%, oklch(0.48 0.15 24 / 0.16), transparent 28rem),
    linear-gradient(180deg, oklch(0.18 0.06 266), oklch(0.09 0.04 258) 56%, oklch(0.035 0.018 245));
}

.lo-sky::before {
  content: "";
  background:
    radial-gradient(circle at 8% 18%, oklch(1 0 0 / 0.82) 0 1px, transparent 1.6px),
    radial-gradient(circle at 18% 43%, oklch(1 0 0 / 0.55) 0 1px, transparent 1.5px),
    radial-gradient(circle at 34% 12%, oklch(1 0 0 / 0.74) 0 1px, transparent 1.6px),
    radial-gradient(circle at 51% 31%, oklch(1 0 0 / 0.6) 0 1px, transparent 1.5px),
    radial-gradient(circle at 68% 52%, oklch(1 0 0 / 0.44) 0 1px, transparent 1.5px),
    radial-gradient(circle at 84% 27%, oklch(1 0 0 / 0.72) 0 1px, transparent 1.6px),
    radial-gradient(circle at 93% 66%, oklch(1 0 0 / 0.48) 0 1px, transparent 1.5px),
    radial-gradient(circle at 27% 72%, oklch(0.95 0.035 92 / 0.46) 0 1px, transparent 1.45px),
    radial-gradient(circle at 61% 11%, oklch(0.95 0.035 92 / 0.5) 0 1px, transparent 1.45px),
    radial-gradient(circle at 79% 78%, oklch(0.95 0.035 92 / 0.38) 0 1px, transparent 1.45px);
  animation: lo-stars 5.6s ease-in-out infinite;
}

.lo-sky::after {
  content: "";
  background:
    radial-gradient(ellipse at 25% 18%, oklch(0.58 0.12 288 / 0.16), transparent 18rem),
    radial-gradient(ellipse at 63% 32%, oklch(0.42 0.12 220 / 0.18), transparent 22rem),
    radial-gradient(ellipse at 42% 102%, oklch(0 0 0 / 0.5), transparent 35rem),
    linear-gradient(180deg, transparent 56%, oklch(0.02 0.012 248 / 0.5));
  animation: lo-sky-breathe 9s ease-in-out infinite;
}

.lo-star,
.lo-cloud,
.lo-fog {
  position: fixed;
  z-index: 0;
  pointer-events: none;
}

.lo-star {
  width: 0.18rem;
  height: 0.18rem;
  border-radius: 50%;
  background: oklch(0.96 0.02 92);
  box-shadow: 0 0 0.75rem oklch(0.86 0.1 92 / 0.42);
}

.lo-star.one {
  top: 17%;
  left: 44%;
  animation: lo-drift-a 16s linear infinite;
}

.lo-star.two {
  top: 30%;
  left: 88%;
  animation: lo-drift-b 19s linear infinite;
}

.lo-star.three {
  top: 9%;
  left: 13%;
  animation: lo-drift-a 22s linear infinite reverse;
}

.lo-cloud {
  width: 34rem;
  height: 10rem;
  border-radius: 999px;
  background:
    radial-gradient(ellipse at 35% 52%, oklch(0.24 0.06 272 / 0.22), transparent 60%),
    radial-gradient(ellipse at 62% 48%, oklch(0.16 0.05 256 / 0.2), transparent 68%);
  filter: blur(16px);
}

.lo-cloud.one {
  top: 16%;
  left: 11%;
  animation: lo-clouds 36s linear infinite;
}

.lo-cloud.two {
  right: -8rem;
  bottom: 19%;
  animation: lo-clouds 44s linear infinite reverse;
}

.lo-fog {
  height: 12rem;
  border-radius: 999px;
  opacity: 0.34;
  background:
    radial-gradient(ellipse at 18% 50%, oklch(0.74 0.05 255 / 0.18), transparent 62%),
    radial-gradient(ellipse at 58% 52%, oklch(0.64 0.06 278 / 0.16), transparent 68%),
    radial-gradient(ellipse at 88% 48%, oklch(0.5 0.05 230 / 0.12), transparent 60%);
  filter: blur(22px);
  transform: translate3d(0, 0, 0);
}

.lo-fog.one {
  right: -12rem;
  bottom: 8%;
  width: 54rem;
  animation: lo-fog-drift-a 32s linear infinite;
}

.lo-fog.two {
  left: -16rem;
  bottom: 24%;
  width: 48rem;
  animation: lo-fog-drift-b 40s linear infinite;
}

.lo-fog.three {
  left: 18%;
  top: 24%;
  width: 34rem;
  height: 8rem;
  opacity: 0.18;
  animation: lo-fog-drift-c 52s linear infinite;
}

.lo-aside {
  position: relative;
  z-index: 1;
  display: grid;
  align-content: center;
  gap: 1.5rem;
  min-height: calc(100vh - 2rem);
  padding: 0.75rem;
}

.lo-sign-wrap {
  position: relative;
  width: min(22rem, 100%);
  margin: 0 auto;
  padding-top: 4.2rem;
}

.lo-sign-wrap::before {
  position: absolute;
  top: -5.25rem;
  left: 50%;
  z-index: 3;
  width: min(31rem, calc(100vw - 4rem));
  height: 1.16rem;
  border: 1px solid oklch(0.47 0.014 58 / 0.34);
  border-radius: 0.42rem;
  background:
    radial-gradient(circle at 8% 37%, oklch(0 0 0 / 0.52) 0 0.08rem, transparent 0.1rem),
    radial-gradient(circle at 18% 67%, oklch(0.68 0.018 64 / 0.22) 0 0.05rem, transparent 0.07rem),
    radial-gradient(circle at 31% 29%, oklch(0 0 0 / 0.5) 0 0.06rem, transparent 0.08rem),
    radial-gradient(circle at 46% 73%, oklch(0.78 0.02 68 / 0.18) 0 0.055rem, transparent 0.08rem),
    radial-gradient(circle at 62% 34%, oklch(0 0 0 / 0.46) 0 0.075rem, transparent 0.1rem),
    radial-gradient(circle at 78% 64%, oklch(0 0 0 / 0.5) 0 0.065rem, transparent 0.09rem),
    radial-gradient(circle at 91% 38%, oklch(0.7 0.018 64 / 0.2) 0 0.05rem, transparent 0.075rem),
    linear-gradient(90deg, oklch(0.035 0.003 45), transparent 12% 88%, oklch(0.035 0.003 45)),
    repeating-linear-gradient(96deg, transparent 0 0.36rem, oklch(1 0 0 / 0.04) 0.37rem 0.42rem, transparent 0.43rem 0.74rem),
    linear-gradient(180deg, oklch(0.43 0.012 58), oklch(0.22 0.008 50) 34%, oklch(0.07 0.004 45) 72%, oklch(0.025 0.003 45));
  box-shadow:
    inset 0 0.12rem 0.08rem oklch(1 0 0 / 0.12),
    inset 0 0.34rem 0.2rem oklch(0.7 0.016 65 / 0.09),
    inset 0 -0.18rem 0.1rem oklch(0 0 0 / 0.82),
    inset 0 -0.42rem 0.32rem oklch(0 0 0 / 0.48),
    0 0.18rem 0 oklch(0.015 0.002 45 / 0.96),
    0 0.56rem 0.48rem oklch(0 0 0 / 0.56);
  content: "";
  transform: translateX(-50%);
}

.lo-sign-wrap::after {
  position: absolute;
  top: -5.42rem;
  left: 50%;
  z-index: 4;
  width: min(33.25rem, calc(100vw - 2.4rem));
  height: 1.5rem;
  border-radius: 0.48rem;
  background:
    radial-gradient(ellipse at 2.5% 50%, oklch(0.11 0.006 46) 0 0.72rem, transparent 0.74rem),
    radial-gradient(ellipse at 97.5% 50%, oklch(0.11 0.006 46) 0 0.72rem, transparent 0.74rem),
    radial-gradient(circle at 2.5% 31%, oklch(0.73 0.018 66 / 0.24) 0 0.08rem, transparent 0.1rem),
    radial-gradient(circle at 97.5% 31%, oklch(0.73 0.018 66 / 0.22) 0 0.08rem, transparent 0.1rem),
    linear-gradient(90deg, transparent 0 3.2%, oklch(0 0 0 / 0.42) 3.3% 3.9%, transparent 4% 96%, oklch(0 0 0 / 0.42) 96.1% 96.7%, transparent 96.8% 100%);
  box-shadow:
    inset 0 0.08rem 0.08rem oklch(1 0 0 / 0.08),
    inset 0 -0.2rem 0.22rem oklch(0 0 0 / 0.58);
  content: "";
  pointer-events: none;
  transform: translateX(-50%);
}

.lo-sign {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 14rem;
  border: 3px solid oklch(0.1 0.025 36);
  border-radius: 3px;
  background:
    linear-gradient(180deg, oklch(0.38 0.07 52 / 0.18), transparent 35%),
    repeating-linear-gradient(2deg, transparent 0 3px, oklch(0.22 0.045 45 / 0.42) 3px 4px, transparent 4px 8px),
    repeating-linear-gradient(-1deg, transparent 0 8px, oklch(0.28 0.055 48 / 0.34) 8px 9px, transparent 9px 15px),
    linear-gradient(90deg, oklch(0.05 0.015 35 / 0.72), transparent 13%, transparent 87%, oklch(0.05 0.015 35 / 0.72)),
    linear-gradient(180deg, oklch(0.23 0.055 46), oklch(0.16 0.04 40));
  box-shadow:
    0 0 0 4px oklch(0.65 0.12 78 / 0.26) inset,
    0 0 0 7px oklch(0.07 0.018 30 / 0.92) inset,
    inset 0 8px 16px oklch(0 0 0 / 0.4),
    0 8px 0 oklch(0.035 0.012 28 / 0.82),
    0 14px 8px oklch(0 0 0 / 0.32);
}

.lo-mark {
  width: min(14rem, 58%);
  height: auto;
  filter: drop-shadow(0 4px 3px oklch(0 0 0 / 0.44));
}

.lo-chain {
  --lo-iron-black: oklch(0.075 0.006 45);
  --lo-iron-shadow: oklch(0.02 0.003 45);
  --lo-iron-deep: oklch(0.12 0.008 45);
  --lo-iron-mid: oklch(0.24 0.011 50);
  --lo-iron-high: oklch(0.53 0.018 58);
  position: absolute;
  top: -4.8rem;
  z-index: 2;
  display: flex;
  width: 1.35rem;
  flex-direction: column;
  align-items: center;
  filter: drop-shadow(0.16rem 0.26rem 0.16rem oklch(0 0 0 / 0.6));
  transform-origin: top center;
}

.lo-chain::before {
  position: absolute;
  top: -0.18rem;
  left: 50%;
  width: 1.05rem;
  height: 0.68rem;
  border: 1px solid oklch(0.5 0.018 58 / 0.34);
  border-radius: 0 0 999px 999px;
  background:
    radial-gradient(circle at 35% 28%, var(--lo-iron-high) 0 0.07rem, transparent 0.08rem),
    radial-gradient(circle at 65% 28%, var(--lo-iron-high) 0 0.06rem, transparent 0.075rem),
    linear-gradient(90deg, var(--lo-iron-shadow), var(--lo-iron-mid) 38%, var(--lo-iron-high) 48%, var(--lo-iron-deep) 68%, var(--lo-iron-black));
  box-shadow:
    inset 0.1rem 0 0.12rem oklch(1 0 0 / 0.08),
    inset -0.12rem -0.16rem 0.16rem oklch(0 0 0 / 0.64),
    0 0.18rem 0.18rem oklch(0 0 0 / 0.52);
  content: "";
  transform: translateX(-50%);
}

.lo-chain-left {
  left: calc(50% - 10rem + 0.6rem);
  transform: rotate(-1.5deg);
}

.lo-chain-right {
  right: calc(50% - 10rem + 0.6rem);
  transform: rotate(1.5deg);
}

.lo-chain span {
  position: relative;
  display: block;
  flex: 0 0 auto;
}

.lo-chain span + span {
  margin-top: -0.65rem;
}

.lo-chain span:nth-child(odd) {
  z-index: 2;
  width: 1.16rem;
  height: 1.78rem;
  border-radius: 999px;
  background:
    radial-gradient(ellipse at 32% 14%, oklch(0.82 0.022 70 / 0.34) 0 0.08rem, transparent 0.18rem),
    radial-gradient(ellipse at 72% 86%, oklch(0 0 0 / 0.76) 0 0.18rem, transparent 0.34rem),
    repeating-linear-gradient(124deg, transparent 0 0.2rem, oklch(1 0 0 / 0.045) 0.21rem 0.24rem, transparent 0.25rem 0.48rem),
    linear-gradient(100deg, var(--lo-iron-black), var(--lo-iron-deep) 18%, var(--lo-iron-high) 38%, var(--lo-iron-mid) 47%, var(--lo-iron-black) 63%, var(--lo-iron-deep) 82%, var(--lo-iron-shadow));
  box-shadow:
    inset 0.18rem 0.1rem 0.15rem oklch(1 0 0 / 0.08),
    inset -0.2rem -0.24rem 0.2rem oklch(0 0 0 / 0.62),
    0.08rem 0.16rem 0.14rem oklch(0 0 0 / 0.68),
    0 0 0 1px oklch(0.66 0.022 62 / 0.2);
  -webkit-mask: radial-gradient(ellipse at 50% 50%, transparent 0 39%, #000 41% 100%);
  mask: radial-gradient(ellipse at 50% 50%, transparent 0 39%, #000 41% 100%);
}

.lo-chain span:nth-child(even) {
  z-index: 3;
  width: 0.54rem;
  height: 1.68rem;
  border-radius: 999px;
  background:
    radial-gradient(ellipse at 42% 10%, oklch(0.82 0.02 68 / 0.32), transparent 0.22rem),
    radial-gradient(ellipse at 70% 92%, oklch(0 0 0 / 0.72), transparent 0.3rem),
    repeating-linear-gradient(164deg, transparent 0 0.16rem, oklch(1 0 0 / 0.055) 0.17rem 0.19rem, transparent 0.2rem 0.42rem),
    linear-gradient(90deg, var(--lo-iron-shadow), var(--lo-iron-deep) 18%, var(--lo-iron-high) 44%, var(--lo-iron-mid) 55%, var(--lo-iron-black) 100%);
  box-shadow:
    inset 0.1rem 0 0.12rem oklch(1 0 0 / 0.1),
    inset -0.16rem 0 0.14rem oklch(0 0 0 / 0.6),
    0.12rem 0.18rem 0.16rem oklch(0 0 0 / 0.72),
    0 0 0 1px oklch(0.68 0.022 62 / 0.18);
}

.lo-inscription {
  max-width: 32rem;
  margin: 0 auto;
  text-align: center;
}

.lo-note {
  margin: 0 0 0.65rem;
  color: var(--brass-bright);
  font-size: var(--text-sm);
  font-weight: 800;
}

.lo-inscription h1 {
  max-width: 12ch;
  margin: 0 auto 1rem;
  color: var(--tooth);
  font-family: var(--font-display);
  font-size: var(--text-display);
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.05;
  text-wrap: balance;
}

.lo-inscription p:not(.lo-note) {
  max-width: 34rem;
  margin: 0 auto;
  color: oklch(0.84 0.04 78);
  font-size: var(--text-md);
  line-height: 1.55;
  text-wrap: pretty;
}

.lo-door-panel {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  min-height: calc(100vh - 2rem);
}

.lo-door {
  position: relative;
  display: grid;
  aspect-ratio: 9 / 16;
  width: auto;
  max-width: min(100%, 34rem);
  height: min(calc(100vh - 2rem), 60rem);
  min-height: 0;
  place-items: center;
  overflow: hidden;
  border: 2px solid oklch(0.07 0.016 32);
  border-radius: 4px;
  background:
    linear-gradient(90deg, oklch(0 0 0 / 0.38), transparent 8%, transparent 92%, oklch(0 0 0 / 0.44)),
    linear-gradient(180deg, oklch(0.37 0.078 55 / 0.24), transparent 24%, oklch(0 0 0 / 0.28)),
    repeating-linear-gradient(89deg, oklch(0.2 0.055 39) 0 1px, transparent 1px 17%),
    repeating-linear-gradient(3deg, transparent 0 7px, oklch(0.31 0.062 47 / 0.38) 7px 9px, transparent 9px 18px),
    repeating-linear-gradient(-2deg, transparent 0 16px, oklch(0.12 0.035 34 / 0.48) 16px 18px, transparent 18px 30px),
    linear-gradient(180deg, oklch(0.31 0.072 48), oklch(0.17 0.048 37) 58%, oklch(0.1 0.032 30));
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.08),
    inset 0 -22px 28px oklch(0 0 0 / 0.42),
    0 10px 0 oklch(0.03 0.01 24 / 0.86);
}

.lo-door::before,
.lo-door::after {
  position: absolute;
  inset: 0;
  content: "";
  pointer-events: none;
}

.lo-door::before {
  background:
    linear-gradient(90deg,
      transparent 0 15.8%,
      oklch(0.055 0.018 28 / 0.74) 16% 16.5%,
      transparent 16.8% 32.6%,
      oklch(0.055 0.018 28 / 0.66) 32.8% 33.3%,
      transparent 33.5% 49.4%,
      oklch(0.055 0.018 28 / 0.7) 49.6% 50.1%,
      transparent 50.3% 66.1%,
      oklch(0.055 0.018 28 / 0.66) 66.3% 66.8%,
      transparent 67% 82.7%,
      oklch(0.055 0.018 28 / 0.74) 82.9% 83.4%,
      transparent 83.6% 100%);
}

.lo-door::after {
  background:
    radial-gradient(ellipse at 50% 20%, oklch(0.78 0.13 82 / 0.08), transparent 24rem),
    radial-gradient(ellipse at 48% 62%, oklch(0 0 0 / 0.34), transparent 27rem);
}

.lo-door-slit {
  position: absolute;
  top: 33%;
  left: 9%;
  right: 9%;
  z-index: 2;
  height: 3.5rem;
  overflow: hidden;
  border: 1px solid oklch(0.055 0.015 30);
  background:
    linear-gradient(180deg, oklch(0.012 0.006 250), oklch(0.035 0.018 254) 48%, oklch(0.01 0.005 250));
  box-shadow:
    inset 0 0.62rem 0.72rem oklch(0 0 0 / 0.86),
    inset 0 -0.52rem 0.58rem oklch(0 0 0 / 0.86),
    inset 0.5rem 0 0.6rem oklch(0 0 0 / 0.76),
    inset -0.5rem 0 0.6rem oklch(0 0 0 / 0.76),
    0 0.45rem 0.4rem oklch(0 0 0 / 0.32);
}

.lo-slit-chamber,
.lo-slit-slide,
.lo-slit-frame {
  position: absolute;
  inset: 0;
}

.lo-slit-chamber {
  z-index: 1;
  background:
    radial-gradient(ellipse at 33% 48%, oklch(0.74 0.18 84 / 0.28), transparent 8%),
    radial-gradient(ellipse at 62% 48%, oklch(0.74 0.18 84 / 0.26), transparent 8%),
    radial-gradient(ellipse at 47% 50%, oklch(0.42 0.16 22 / 0.18), transparent 36%),
    linear-gradient(180deg, oklch(0.012 0.006 250), oklch(0.05 0.022 254) 46%, oklch(0.01 0.005 250));
}

.lo-eye {
  position: absolute;
  z-index: 2;
  top: 50%;
  width: 1.05rem;
  height: 0.62rem;
  border-radius: 999px;
  background:
    radial-gradient(circle at 50% 52%, oklch(0.12 0.06 35) 0 0.12rem, transparent 0.13rem),
    radial-gradient(ellipse at 50% 52%, oklch(0.96 0.18 82) 0 0.28rem, oklch(0.66 0.2 31) 0.3rem 0.38rem, transparent 0.4rem);
  box-shadow:
    0 0 0.6rem oklch(0.76 0.2 34 / 0.48),
    0 0 1.1rem oklch(0.82 0.16 82 / 0.28);
  transform: translateY(-50%);
  animation: lo-eye-watch 4.8s ease-in-out infinite;
}

.lo-eye-left {
  left: 34%;
}

.lo-eye-right {
  left: 58%;
  width: 1.12rem;
}

.lo-eye-small {
  left: 47%;
  top: 57%;
  width: 0.62rem;
  height: 0.38rem;
  opacity: 0.75;
}

.lo-slit-slide {
  z-index: 3;
  inset: 0 auto 0 -5%;
  width: 112%;
  background:
    linear-gradient(90deg, oklch(0 0 0 / 0.28), transparent 10%, transparent 86%, oklch(0 0 0 / 0.32)),
    repeating-linear-gradient(2deg, transparent 0 6px, oklch(0.31 0.062 47 / 0.46) 6px 8px, transparent 8px 15px),
    repeating-linear-gradient(-1deg, transparent 0 13px, oklch(0.13 0.038 34 / 0.5) 13px 15px, transparent 15px 25px),
    linear-gradient(180deg, oklch(0.28 0.064 46), oklch(0.13 0.038 34));
  box-shadow:
    inset 0 0 0 1px oklch(0 0 0 / 0.34),
    inset 0 0.16rem 0 oklch(1 0 0 / 0.06),
    inset 0 -0.24rem 0.28rem oklch(0 0 0 / 0.38);
  animation: lo-slit-slide-open 1.35s 0.45s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.lo-slit-frame {
  z-index: 4;
  background:
    linear-gradient(180deg, oklch(0 0 0 / 0.7), transparent 22%, transparent 76%, oklch(0 0 0 / 0.72)),
    linear-gradient(90deg, oklch(0 0 0 / 0.58), transparent 6%, transparent 94%, oklch(0 0 0 / 0.58));
  box-shadow:
    inset 0 0.28rem 0.2rem oklch(0.04 0.016 30),
    inset 0 -0.28rem 0.18rem oklch(0.04 0.016 30);
}

.lo-door-crossbar {
  position: absolute;
  left: 5%;
  right: 5%;
  z-index: 1;
  height: 3.2rem;
  border: 1px solid oklch(0.08 0.018 34);
  background:
    linear-gradient(180deg, oklch(0.36 0.075 52), oklch(0.18 0.047 36)),
    oklch(0.22 0.055 42);
  box-shadow:
    inset 0 0.2rem 0 oklch(1 0 0 / 0.07),
    inset 0 -0.35rem 0.4rem oklch(0 0 0 / 0.35),
    0 0.45rem 0.6rem oklch(0 0 0 / 0.42);
}

.lo-door-crossbar.top {
  top: 15%;
  transform: rotate(-1deg);
}

.lo-door-crossbar.bottom {
  bottom: 15%;
  transform: rotate(1.2deg);
}

.lo-door-knocker {
  position: absolute;
  right: 13%;
  top: 50%;
  z-index: 2;
  width: 4.7rem;
  height: 6.3rem;
  transform: translateY(-50%) rotate(5deg);
}

.lo-door-knocker::before,
.lo-door-knocker::after {
  position: absolute;
  content: "";
  pointer-events: none;
}

.lo-door-knocker::before {
  top: 0;
  left: 50%;
  width: 2.15rem;
  height: 2.15rem;
  border: 0.18rem solid oklch(0.14 0.012 52);
  border-radius: 50%;
  background:
    radial-gradient(circle at 34% 28%, oklch(0.76 0.04 72 / 0.7) 0 0.22rem, transparent 0.24rem),
    radial-gradient(circle at 50% 58%, oklch(0.13 0.012 48) 0 0.28rem, transparent 0.3rem),
    linear-gradient(135deg, oklch(0.58 0.035 68), oklch(0.22 0.014 54) 52%, oklch(0.06 0.006 45));
  box-shadow:
    inset 0.16rem 0.16rem 0.16rem oklch(1 0 0 / 0.14),
    inset -0.2rem -0.22rem 0.18rem oklch(0 0 0 / 0.52),
    0 0.22rem 0.24rem oklch(0 0 0 / 0.46);
  transform: translateX(-50%);
}

.lo-door-knocker::after {
  left: 50%;
  bottom: 0;
  width: 3.4rem;
  height: 4.25rem;
  border: 0.44rem solid oklch(0.42 0.035 62);
  border-top-color: oklch(0.58 0.04 70);
  border-right-color: oklch(0.2 0.016 52);
  border-bottom-color: oklch(0.11 0.01 48);
  border-left-color: oklch(0.34 0.025 58);
  border-radius: 50% 50% 48% 48%;
  background: radial-gradient(ellipse at 50% 50%, transparent 0 54%, oklch(0 0 0 / 0.24) 55% 64%, transparent 65%);
  box-shadow:
    inset 0.18rem 0.18rem 0.15rem oklch(1 0 0 / 0.12),
    inset -0.24rem -0.3rem 0.22rem oklch(0 0 0 / 0.48),
    0 0.46rem 0.34rem oklch(0 0 0 / 0.5);
  transform: translateX(-50%);
}

.lo-door-action {
  position: relative;
  z-index: 3;
  display: grid;
  justify-items: center;
  gap: 0.65rem;
  width: min(22rem, calc(100% - 3rem));
  padding: 1rem 1.05rem 1.1rem;
  border: 1px solid oklch(0.11 0.025 36);
  border-radius: 8px;
  background:
    linear-gradient(180deg, oklch(0.2 0.048 38 / 0.98), oklch(0.095 0.025 30 / 0.98));
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.08),
    0 6px 0 oklch(0.035 0.012 26 / 0.82);
  text-align: center;
}

.lo-door-note {
  margin: 0;
  color: oklch(0.82 0.06 78);
  font-size: var(--text-sm);
  font-weight: 700;
}

.lo-door-action h2 {
  margin: 0;
  color: var(--tooth);
  font-family: var(--font-display);
  font-size: 1.75rem;
  line-height: 1.1;
}

.lo-discord-link {
  display: inline-flex;
  min-height: 2.8rem;
  align-items: center;
  justify-content: center;
  padding: 0 1.05rem;
  border-radius: 7px;
  background:
    radial-gradient(ellipse at 50% 0, oklch(0.96 0.15 88 / 0.72), transparent 1.2rem),
    linear-gradient(180deg, var(--brass-bright), var(--brass) 48%, var(--brass-dark));
  color: var(--vellum-ink);
  font-size: var(--text-base);
  font-weight: 800;
  text-decoration: none;
  text-shadow: 0 1px 0 oklch(1 0 0 / 0.15);
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.38),
    inset 0 -4px 0 oklch(0.25 0.07 50 / 0.32),
    0 3px 0 oklch(0.1 0.02 30 / 0.68);
  transition:
    transform 170ms cubic-bezier(0.25, 1, 0.5, 1),
    filter 170ms cubic-bezier(0.25, 1, 0.5, 1);
}

.lo-discord-link:hover {
  filter: brightness(1.06);
  transform: translateY(-1px);
}

.lo-discord-link:active {
  filter: brightness(0.95);
  transform: translateY(0);
}

.lo-discord-link:focus-visible {
  outline: 3px solid oklch(0.9 0.14 84 / 0.55);
  outline-offset: 3px;
}

@keyframes lo-stars {
  0%,
  100% {
    opacity: 0.72;
  }
  50% {
    opacity: 1;
  }
}

@keyframes lo-drift-a {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(2.2rem, 0.7rem, 0);
  }
}

@keyframes lo-drift-b {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(-1.8rem, 0.9rem, 0);
  }
}

@keyframes lo-clouds {
  from {
    transform: translate3d(-1.5rem, 0, 0);
  }
  to {
    transform: translate3d(2rem, 0.6rem, 0);
  }
}

@keyframes lo-fog-drift-a {
  0% {
    opacity: 0.22;
    transform: translate3d(0, 0, 0);
  }
  50% {
    opacity: 0.4;
    transform: translate3d(-8rem, -0.8rem, 0);
  }
  100% {
    opacity: 0.22;
    transform: translate3d(-16rem, 0.35rem, 0);
  }
}

@keyframes lo-fog-drift-b {
  0% {
    opacity: 0.16;
    transform: translate3d(0, 0, 0);
  }
  50% {
    opacity: 0.32;
    transform: translate3d(7rem, 0.7rem, 0);
  }
  100% {
    opacity: 0.16;
    transform: translate3d(14rem, -0.2rem, 0);
  }
}

@keyframes lo-fog-drift-c {
  0%,
  100% {
    transform: translate3d(-2rem, 0, 0);
  }
  50% {
    transform: translate3d(2rem, 0.6rem, 0);
  }
}

@keyframes lo-sky-breathe {
  0%,
  100% {
    opacity: 0.82;
  }
  50% {
    opacity: 1;
  }
}

@keyframes lo-slit-slide-open {
  to {
    transform: translateX(78%);
  }
}

@keyframes lo-eye-watch {
  0%,
  100% {
    filter: brightness(0.9);
  }
  48% {
    filter: brightness(1.18);
  }
  53% {
    filter: brightness(0.58) scaleY(0.28);
  }
  58% {
    filter: brightness(1.12);
  }
}

@media (prefers-reduced-motion: reduce) {
  .lo-sky::after,
  .lo-sky::before,
  .lo-star,
  .lo-cloud,
  .lo-fog,
  .lo-eye {
    animation: none;
  }

  .lo-slit-slide {
    transform: translateX(78%);
    animation: none;
  }
}

@media (max-width: 900px) {
  .lo-shell {
    grid-template-columns: 1fr;
    gap: 1rem;
    width: min(100% - 1rem, 48rem);
    overflow: visible;
    min-height: 0;
  }

  .lo-aside {
    min-height: auto;
    padding: 2.8rem 0.5rem 0;
  }

  .lo-sign-wrap {
    width: min(18rem, 82vw);
    padding-top: 0;
  }

  .lo-sign-wrap::before {
    display: none;
  }

  .lo-sign-wrap::after {
    display: none;
  }

  .lo-sign {
    min-height: 11.5rem;
  }

  .lo-mark {
    width: min(11rem, 58%);
  }

  .lo-chain {
    top: -3.35rem;
  }

  .lo-chain-left {
    left: 1.65rem;
  }

  .lo-chain-right {
    right: 1.65rem;
  }

  .lo-inscription h1 {
    max-width: 13ch;
    font-size: 2.625rem;
  }

  .lo-inscription p:not(.lo-note) {
    font-size: var(--text-base);
  }

  .lo-door-panel {
    min-height: 0;
    padding: 0.5rem 0 1rem;
    place-items: start center;
  }

  .lo-door {
    height: auto;
    width: min(100%, 24rem);
  }
}

@media (max-width: 560px) {
  .lo-shell {
    width: min(100% - 0.75rem, 30rem);
    padding: 0.5rem 0;
  }

  .lo-sign-wrap {
    width: min(15.5rem, 82vw);
  }

  .lo-sign {
    min-height: 9.8rem;
  }

  .lo-chain {
    top: -3.05rem;
    width: 1rem;
    transform-origin: top center;
  }

  .lo-chain span:nth-child(odd) {
    width: 0.98rem;
    height: 1.5rem;
  }

  .lo-chain span:nth-child(even) {
    width: 0.46rem;
    height: 1.42rem;
  }

  .lo-chain span + span {
    margin-top: -0.55rem;
  }

  .lo-chain-left {
    left: 1.35rem;
  }

  .lo-chain-right {
    right: 1.35rem;
  }

  .lo-inscription {
    max-width: 25rem;
  }

  .lo-inscription h1 {
    font-size: 2.2rem;
  }

  .lo-door-panel {
    min-height: 0;
  }

  .lo-door {
    width: min(100%, 21rem);
  }

  .lo-door-slit {
    left: 7%;
    right: 7%;
    height: 3rem;
  }

  .lo-door-crossbar {
    height: 2.5rem;
  }

  .lo-door-action {
    width: min(19rem, calc(100% - 1.6rem));
  }

  .lo-door-action h2 {
    font-size: 1.45rem;
  }

  .lo-discord-link {
    width: 100%;
  }
}

button,
input {
  font: inherit;
}

a {
  color: inherit;
}

.app-shell {
  position: relative;
  display: grid;
  grid-template-columns: minmax(20rem, 0.82fr) minmax(0, 1.18fr);
  gap: 1.45rem;
  /* In idle mode we keep a comfortable reading width (max
     1750px centered) so the brand hero and ledger feel like a
     well-typeset book on a wide monitor. In playing mode the
     overrides below drop the cap and use the full viewport —
     a karaoke stage wants every pixel. */
  width: min(1750px, calc(100% - 2rem));
  min-height: 100vh;
  margin: 0 auto;
  padding: 1rem 0;
}

/* ============================================================
   Layout swap: idle (single page) vs playing (stage + sidebar).
   Hard switch — no transition. The data-layout attribute is set
   by the App() component based on session.status.

   Playing layout grid:
     row 1: top bar (auto height, full width)
     row 2: sidebar (left) | stage (right, flex-grow)
   Below the 880px breakpoint the playing layout collapses to a
   single column and the stage (video embed) is hidden — the
   queue becomes the main view. The rotation prompt is rendered
   by the component layer (Phase H).
   ============================================================ */

.app-shell[data-layout="playing"] {
  /* Single-column on small screens (queue-only, no video).
     Two-column layout kicks in via @media (min-width: 880px).
     Width is full viewport (minus a small gutter) so 4K, 2K,
     8K, foldable landscape — every landscape aspect ratio —
     uses the entire screen. No 1750px cap here. */
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "topbar"
    "queue";
  width: calc(100% - 1rem);
  margin: 0 auto;
  min-height: 100vh;
}

@media (min-width: 880px) {
  .app-shell[data-layout="playing"] {
    grid-template-columns: 320px minmax(0, 1fr);
    grid-template-rows: 56px 1fr;
    /* Two rows × two columns. The topbar spans both columns.
       The queue-panel spans row 2 col 1 + 2 — its own internal
       grid splits that row into the queue sidebar and the main
       queue content. Note the row 2 area is also named "queue"
       (matches the base mobile rule above, and matches the
       queue-panel's grid-area: queue), NOT "sidebar stage".
       The original CSS had named the areas "sidebar stage" but
       those are areas inside the queue-panel — naming them at
       the app-shell level created implicit grid tracks that
       broke the layout. */
    grid-template-areas:
      "topbar topbar"
      "queue queue";
    gap: 0.85rem;
    /* Full viewport width (minus a small gutter). 4K, 2K, 8K,
       ultrawide — every landscape ratio uses the whole screen.
       The internal max-width on .hero-panel and .queue-panel
       keeps their content centered without capping the shell.
       height: 100vh (not min-height) locks the grid to the
       viewport so the sidebar stays fixed and only its song
       list scrolls; min-height would let the grid grow when
       content pushes it. */
    width: calc(100% - 2rem);
    margin: 0 auto;
    padding: 0.85rem 0;
    height: 100vh;
  }
}

/* Tablet (880-1199px): narrower sidebar, slightly shorter top bar.
   Below the top bar collapses to 48px; the sidebar drops to 280px.
   This buys a couple inches of stage width on iPad-sized screens
   without breaking the layout. */
@media (min-width: 880px) and (max-width: 1199px) {
  .app-shell[data-layout="playing"] {
    grid-template-columns: 280px minmax(0, 1fr);
    grid-template-rows: 48px 1fr;
  }
}

/* Wide desktops: slightly wider sidebar. The 320px mark is a
   sweet spot — wide enough for the compact candle + queue rows
   to read clearly, narrow enough that a 1080p monitor still has
   1700+px of stage area for the 16:9 video. */
@media (min-width: 1600px) {
  .app-shell[data-layout="playing"] {
    grid-template-columns: 360px minmax(0, 1fr);
  }
}

/* Assign grid areas. .hero-panel becomes the top bar; .queue-panel
   becomes the main area. The sidebar is a child of the queue
   panel — not a separate grid item — so we can keep the queue
   content inside its existing container. */
.app-shell[data-layout="playing"] .hero-panel {
  grid-area: topbar;
  height: clamp(48px, 5vw, 64px);
  min-height: 0;
  padding: 0;
  overflow: hidden;
}

.app-shell[data-layout="playing"] .queue-panel {
  grid-area: queue;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "sidebar"
    "songs";
  gap: 0.6rem;
  overflow: hidden;
}

@media (min-width: 880px) {
  .app-shell[data-layout="playing"] .queue-panel {
    grid-template-columns: 320px minmax(0, 1fr);
    grid-template-rows: 1fr;
    grid-template-areas:
      "sidebar songs";
    gap: 0.85rem;
    overflow: hidden;
  }
}

/* The proposal form + mimic live inside .queue-panel today. In
   playing mode we hide them — the top bar handles proposing, and
   the mimic is decoration we don't need mid-song. */
.app-shell[data-layout="playing"] .mimic-stage,
.app-shell[data-layout="playing"] .offering-board,
.app-shell[data-layout="playing"] .toolbar {
  display: none;
}

.app-shell[data-layout="playing"] .hero-copy,
.app-shell[data-layout="playing"] .chain,
.app-shell[data-layout="playing"] .stat-board {
  display: none;
}

/* TopBar is only meaningful in playing mode. Hidden in idle. */
.app-shell[data-layout="idle"] .topbar {
  display: none;
}

/* Queue sidebar (Phase E will populate). In idle layout it's
   hidden — the sidebar only exists when the night is started.
   In playing layout it occupies the .queue-panel "sidebar" grid
   area. On mobile (<880px) it stacks above the songs area.
   The placeholder border keeps it visible during development so
   we can see the layout structure; Phase E replaces it with a
   proper sidebar. */
.queue-sidebar {
  display: none;
}

.app-shell[data-layout="playing"] .queue-sidebar {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  padding: 0.85rem;
  border: 1px solid var(--iron-dark);
  outline: 1px solid oklch(0.86 0.14 84 / 0.18);
  border-radius: 4px;
  /* Same woody/oak background as the idle-layout queue-panel —
     a leather ledger darkening to oak at the bottom, with the
     radial highlights that give it depth. The pale vellum it had
     before washed out the candle and competed with the song rows
     for contrast; the oak palette keeps the sidebar reading like
     part of the same furniture as the rest of the tavern. */
  background:
    radial-gradient(circle at 50% 0%, oklch(0.78 0.14 82 / 0.08), transparent 14rem),
    linear-gradient(180deg, oklch(0.32 0.06 42) 0%, var(--oak) 18%, var(--oak-dark) 96%),
    var(--oak);
  color: var(--ink);
  overflow-y: auto;
  grid-area: sidebar;
  min-height: 0;
}

.sidebar-candle {
  /* Compact candle: shrink the SVG and stack the meter-text
     tighter so it fits a ~280-360px sidebar comfortably. */
}

.sidebar-candle .meter-svg {
  width: 56px;
  height: 140px;
  flex: 0 0 auto;
}

/* The tankard's general rule (`.wax-candle-meter .meter-svg--tankard
   { width: 100% }`) overrides a simple `.sidebar-candle` selector,
   so we scope with the parent attribute selector to win specificity. */
.app-shell[data-layout="playing"] .sidebar-candle .meter-svg--tankard {
  width: 130px;
  height: auto;
  aspect-ratio: 5 / 2;
  flex: 0 0 auto;
}

.sidebar-candle .meter-text {
  flex: 1 1 auto;
  min-width: 0;
}

.sidebar-candle .wax-candle-meter {
  gap: 0.5rem;
}

.sidebar-candle .meter-text .meter-now {
  font-size: var(--text-base);
}

.sidebar-candle .meter-text .meter-sub {
  font-size: var(--text-xs, 0.75rem);
}

.sidebar-queue {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  flex: 1 1 auto;
  min-height: 0;
}

.sidebar-section-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding-bottom: 0.4rem;
  border-bottom: 1px solid oklch(0.84 0.12 82 / 0.28);
}

.sidebar-section-header h3 {
  margin: 0;
  font-size: var(--text-base);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--vellum);
  font-family: var(--font-display);
}

.sidebar-section-count {
  font-size: var(--text-sm);
  color: oklch(0.78 0.05 78);
}

.sidebar-song-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;
}

.sidebar-subheading {
  margin: 0.5rem 0 0.25rem;
  font-size: var(--text-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--vellum);
  font-weight: 600;
}

.sidebar-filter-bar {
  display: flex;
  gap: 0.4rem;
  margin-bottom: 0.5rem;
}

.sidebar-filter-bar .filter-input {
  flex: 1;
  padding: 0.45rem 0.7rem;
  font-size: var(--text-sm);
}

.sidebar-filter-bar .filter-select {
  padding: 0.45rem 0.7rem;
  font-size: var(--text-sm);
  min-width: 110px;
}

/* In the sidebar the SongRow needs to compress to a narrower
   width. The idle-layout SongRow is tuned for ~700px+ main
   content; in a 280-360px sidebar the 7.5rem thumbnail + 1fr
   text + auto buttons overflows. We stack the thumbnail above
   the metadata and put the action buttons inline below the
   main column so the row still reads as a single card but fits
   the column. */
.app-shell[data-layout="playing"] .song-row {
  grid-template-columns: 1fr;
  grid-template-rows: auto auto;
  padding: 0.55rem 0.7rem;
  gap: 0.45rem;
  font-size: var(--text-sm);
}

.app-shell[data-layout="playing"] .song-row .song-thumb {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  max-height: 5.5rem;
  display: block;
}

.app-shell[data-layout="playing"] .song-row .song-thumb img,
.app-shell[data-layout="playing"] .song-row .song-thumb span {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  font-size: 0; /* hide the "YT" placeholder text */
}

.app-shell[data-layout="playing"] .song-row .song-heading {
  flex-wrap: wrap;
  gap: 0.15rem 0.5rem;
}

.app-shell[data-layout="playing"] .song-row .song-heading a {
  font-size: var(--text-base);
  flex-basis: 100%;
}

.app-shell[data-layout="playing"] .song-row .song-meta {
  flex-wrap: wrap;
  gap: 0.2rem 0.4rem;
  font-size: var(--text-xs);
}

.app-shell[data-layout="playing"] .song-row .song-actions {
  align-items: flex-start;
}

.app-shell[data-layout="playing"] .song-row .delete-button,
.app-shell[data-layout="playing"] .song-row .admin-button {
  font-size: var(--text-xs);
  padding: 0.25rem 0.5rem;
  align-self: flex-start;
}

.app-shell[data-layout="playing"] .song-row .notes-add-button,
.app-shell[data-layout="playing"] .song-row .notes-edit-button {
  background: transparent;
  color: var(--dim);
  border-color: transparent;
}

.app-shell[data-layout="playing"] .song-row .notes-add-button:hover,
.app-shell[data-layout="playing"] .song-row .notes-edit-button:hover {
  background: oklch(1 0 0 / 0.04);
  color: var(--tooth);
  border-color: oklch(1 0 0 / 0.08);
}

.app-shell[data-layout="playing"] .song-row .notes-editor {
  font-size: var(--text-xs);
}

.sidebar-song-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.3rem 0.4rem;
  border-radius: 3px;
  font-size: var(--text-sm);
  background: oklch(0.98 0.01 80 / 0.6);
  border: 1px solid oklch(0.86 0.14 84 / 0.18);
}

.sidebar-song-row:hover {
  background: oklch(0.96 0.03 80);
}

.sidebar-song-title {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: 600;
  color: var(--tooth);
}

.sidebar-song-duration {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  color: var(--dim);
  font-size: var(--text-xs, 0.75rem);
}

.sidebar-empty {
  margin: 0;
  font-style: italic;
  color: var(--dim);
  font-size: var(--text-sm);
  text-align: center;
  padding: 0.5rem 0;
}

.sidebar-sung-summary {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--dim);
  font-style: italic;
  padding-top: 0.25rem;
  border-top: 1px dashed oklch(0.86 0.14 84 / 0.3);
}

.sidebar-admin {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  flex: 0 0 auto;
  padding-top: 0.5rem;
  border-top: 1px solid oklch(0.86 0.14 84 / 0.3);
}

/* Queue main: in playing mode this gets the "songs" grid area.
   In idle mode it's just a normal block; we don't apply any
   special flex/grid rules so the original layout is preserved
   (the existing CSS handles spacing for toolbar, mimic, songs,
   etc. via their own selectors). */
.app-shell[data-layout="playing"] .queue-main {
  grid-area: songs;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  min-height: 0;
}

/* ============================================================
   Phase H: rotation prompt + no-video below breakpoint
   ============================================================
   In playing mode below the 880px breakpoint the video embed is
   hidden — the queue becomes the main view. If the device's
   portrait height clears the threshold (the device is a small
   tablet or foldable that would fit landscape), show a fixed
   banner above the top bar prompting the user to rotate. Tiny
   phones don't get the prompt (rotating wouldn't help). */

.rotation-prompt {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  padding: 0.55rem 1rem;
  background: linear-gradient(180deg, oklch(0.42 0.16 65) 0%, oklch(0.36 0.14 60) 100%);
  color: oklch(0.16 0.04 50);
  font-weight: 700;
  font-size: var(--text-sm);
  text-align: center;
  border-bottom: 1px solid oklch(0.3 0.15 22);
  box-shadow: 0 2px 8px oklch(0.1 0.02 50 / 0.4);
}

.rotation-prompt[data-visible="1"] {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
}

.rotation-prompt-icon {
  font-size: 1.1em;
}

/* ============================================================
   PlayerStage — the main area in playing mode.

   The stage is a single full-bleed container holding the video
   embed (or fallback). It sits inside .queue-main, which is the
   "songs" grid area of the queue-panel at desktop, or the only
   row at mobile. The stage has no card chrome, no title, no admin
   controls — the top bar owns the song meta and admin actions,
   the sidebar owns the queue. The stage is purely a window onto
   the video. ============================================================ */

/* "Start the night" CTA. Admin-only, lives in the hero-panel
   between hero-copy and the user contribution list. In the
   current layout the user-contributions list (next sibling)
   takes all leftover vertical space via `flex: 1 1 0`, so the
   CTA just sits naturally below hero-copy. Its `min-height`
   reservation still wins over the user list's flex shrink —
   flex respects min-height as a floor. */
.hero-start {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  justify-content: center;
  gap: 0.6rem;
  padding: 0.6rem 0 0.4rem;
  min-height: 3.4rem;
  flex: 0 0 auto;
}

.hero-start .admin-button,
.hero-start .rebalance-button {
  flex: 1 1 0;
  min-width: 0;
  max-width: 12rem;
}

.rebalance-button {
  background:
    linear-gradient(180deg, oklch(0.21 0.04 36), oklch(0.13 0.025 30));
  color: oklch(0.82 0.06 65);
  border-color: oklch(0.32 0.06 50);
  padding: 0 1rem;
  min-height: 2.4rem;
  font-size: var(--text-sm);
}

.rebalance-button:hover:not(:disabled) {
  background:
    linear-gradient(180deg, oklch(0.27 0.05 36), oklch(0.18 0.03 30));
  color: oklch(0.92 0.07 70);
  border-color: oklch(0.42 0.08 50);
}

.rebalance-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.rebalance-subtitle {
  /* Removed: the subtitle line under "Balance turns" was
     dropped in favor of a tighter side-by-side button row.
     Keeping the rule (with display:none) would still match
     any stragglers; we just hide it cleanly. */
  display: none;
}

/* ============================================================
   User contributions list (hero-panel sidebar)
   ============================================================
   Sits between hero-start and HeroStats. Two layers:

     .user-contributions      → flex item that grows to fill the
                                 leftover space between hero-start
                                 and HeroStats; also the scroll
                                 container when rows exceed the
                                 allotted height. NO visual chrome
                                 of its own — it's invisible.

     .user-contributions-card → the visible card. Content-sized
                                 (rows + padding + border). Holds
                                 the oak background, border,
                                 padding, and the direction-aware
                                 scroll-shadow technique. Sits at
                                 the bottom of the outer container
                                 via margin-top: auto so the empty
                                 space above it (when the room is
                                 small) is invisible — the oak
                                 background only covers where rows
                                 actually live.

   With this split, the list still fills the available space
   (so the flex layout above it is correct) but the visible
   background only covers the rows + padding, not the empty
   space above them when the room is small. */

.user-contributions {
  /* Flex item inside hero-panel. flex: 1 1 0 absorbs leftover
     space; min-height comes from --uc-min-height, a CSS custom
     property set inline by the Rust component based on the
     contributor count:
       - 0-3 users: enough to fit all rows exactly (no scroll).
       - 4+ users:  fixed at ~4½ rows so scrollability is
                    always visible — the half-row peeks at the
                    bottom as the affordance.
     The `0` fallback is for safety when the prop isn't set.
     The container is the scroll viewport; its overflow triggers
     when the inner card is taller than the space allocated. */
  flex: 1 1 0;
  min-height: var(--uc-min-height, 0);
  margin: 0.35rem 0;
  display: flex;
  flex-direction: column;

  /* The scroll surface. scrollbar-gutter: stable keeps the
     layout from shifting when overflow appears. */
  overflow-y: auto;
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  scrollbar-color: oklch(0.42 0.06 50 / 0.7) transparent;
}

.user-contributions::-webkit-scrollbar {
  width: 0.5rem;
}

.user-contributions::-webkit-scrollbar-track {
  background: transparent;
}

.user-contributions::-webkit-scrollbar-thumb {
  background: oklch(0.42 0.06 50 / 0.6);
  border-radius: 999px;
}

.user-contributions-card {
  /* margin-top: auto absorbs the leftover vertical space above
     this card when the outer container is taller than the
     card. The card is content-sized (rows + padding), so the
     oak background below only paints the actual row area —
     the empty space above the card stays unpainted.
     When the card is taller than the container (many users),
     margin-top collapses to 0 and the card overflows the
     container downward, which the outer then scrolls. */
  margin-top: auto;
  padding: 0.5rem 0.65rem;
  border: 1px solid oklch(0.18 0.025 38 / 0.7);
  border-radius: 4px;
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.04),
    inset 0 -6px 12px oklch(0 0 0 / 0.18);

  /* ============================================================
     Direction-aware scroll shadows (Lea Verou / bramus.us)
     ============================================================
     Two pairs of background layers:
       1. COVERS (background-attachment: local)
          Move with the content. Solid oak at the very top /
          bottom of the content, fading to transparent. When
          content is flush with the top or bottom of the
          scrollport, the corresponding cover is on top of
          the shadow and hides it.
       2. SHADOWS (background-attachment: scroll)
          Glued to the scrollport edges. Stay visible until
          covered.
     Net effect:
       - At the top of the scroll: bottom shadow visible.
       - At the bottom: top shadow visible.
       - In the middle: both visible.
       - Content fits (no overflow): neither visible.
     The base solid oak + radial accent also use `scroll`
     attachment so they stay anchored to the viewport (the
     top-of-list glow reads as a header halo regardless of
     scroll position).
     Pure CSS, no JS, works in every modern browser including
     Firefox (background-attachment: local has been supported
     there since 2013).
     ============================================================ */
  background:
    /* Top cover */
    linear-gradient(
      oklch(0.1 0.022 28) 30%,
      transparent
    ) top / 100% 40px no-repeat local,
    /* Bottom cover */
    linear-gradient(
      transparent,
      oklch(0.1 0.022 28) 70%
    ) bottom / 100% 40px no-repeat local,
    /* Top shadow (small, dark, fades downward) */
    radial-gradient(
      farthest-side at 50% 0,
      rgba(0, 0, 0, 0.5),
      transparent
    ) top / 100% 12px no-repeat,
    /* Bottom shadow */
    radial-gradient(
      farthest-side at 50% 100%,
      rgba(0, 0, 0, 0.5),
      transparent
    ) bottom / 100% 12px no-repeat,
    /* Radial accent (viewport-fixed "header glow") */
    radial-gradient(
      ellipse at 50% 0%,
      oklch(0.42 0.08 52 / 0.14),
      transparent 14rem
    ),
    /* Base solid oak gradient */
    linear-gradient(
      180deg,
      oklch(0.16 0.03 32),
      oklch(0.1 0.022 28)
    );
}

.user-contributions-list {
  /* Bottom-align the rows within the card. When the rows fit
     inside the card, justify-content: flex-end pins them to
     the bottom edge of the card. When the rows overflow the
     card (only happens when the outer container's allotted
     space is less than the row stack), the list grows past
     the card and the outer container scrolls — but in that
     case there's no "bottom" to align to, so the rows just
     stack from the top. */
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin: 0;
  padding: 0;
  list-style: none;
  min-height: 100%;
  justify-content: flex-end;
}

.user-contribution-row {
  display: grid;
  /* Avatar | name | stats (songs + playtime). The name
     column is allowed to truncate so long Discord handles
     don't blow out the row. */
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.55rem;
  padding: 0.32rem 0.45rem;
  border-radius: 3px;
  background: linear-gradient(90deg, oklch(0.22 0.04 36 / 0.55), oklch(0.13 0.025 30 / 0.35));
  border: 1px solid oklch(0.32 0.06 48 / 0.45);
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.04),
    inset 0 -2px 4px oklch(0 0 0 / 0.18);
  /* Subtle vellum tint on the name so it pops against the
     oak backdrop of the row. */
  color: oklch(0.86 0.04 80);
  font-size: var(--text-sm);
}

.user-contribution-row .avatar {
  width: 1.5rem;
  height: 1.5rem;
  font-size: 0.7rem;
}

.user-contribution-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
  color: var(--vellum);
  letter-spacing: 0.005em;
}

.user-contribution-stats {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.05rem;
  min-width: 0;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.user-contribution-songs {
  font-weight: 700;
  color: var(--tooth);
  font-size: var(--text-sm);
  line-height: 1.05;
}

.user-contribution-songs-label {
  font-weight: 500;
  color: var(--dim);
  font-size: var(--text-xs);
  letter-spacing: 0.02em;
}

.user-contribution-playtime {
  font-size: var(--text-xs);
  color: oklch(0.78 0.06 70);
  line-height: 1.05;
}

.user-contributions-empty {
  margin: 0;
  padding: 0.65rem 0.4rem;
  font-size: var(--text-sm);
  font-style: italic;
  color: var(--dim);
  text-align: center;
}

/* ============================================================
   Wide-but-vertically-short viewports (e.g. 1280×720 laptops)
   ============================================================
   The sidebar (hero-panel) is now unconditionally scrollable:
   `position: sticky; height: calc(100vh - 2rem); overflow-y: auto`
   means whatever the viewport height, if content doesn't fit
   a scrollbar appears — no max-height clipping, no media-query
   gating. The vertical-breakpoint media query therefore only
   needs to handle the two cosmetic concerns that depend on
   available vertical space:

     1. h1 shrinks so the headline doesn't dominate a short
        viewport and crowd out the body copy and stats below.
     2. .brand-lockup shrinks proportionally (width, margin,
        padding, brand-mark, and the chain pins/scale all
        shrink together so the visual relationship between
        lockup and chains is preserved).

   The hero-start, stat-board, body copy, guild-note, and the
   panel's overflow behavior are NOT touched here. They keep
   their natural sizes and rely on the panel's own scrollbar
   if they collectively don't fit. */

@media (max-height: 800px) {
  /* Lockup: original was 20rem wide × 5rem top margin. We
     scale to ~14rem × 3.6rem which keeps the same aspect
     ratio (~0.28) and preserves the centered visual weight
     without crowding the h1 below it. The chain pins use a
     sibling custom property so we adjust it to keep the
     visual relationship between lockup edge and pin. */
  .brand-lockup {
    width: 14rem;
    margin: 3.6rem auto 1rem;
    padding: 0.7rem 0.35rem 0.8rem;
    --chain-pin-inset: 0.42rem;
  }

  .brand-mark {
    width: min(9rem, 60%);
  }

  /* The chains use `calc(50% - 10rem + var(--chain-pin-inset))`
     — that `10rem` is hardcoded for the 20rem-wide lockup.
     For the 14rem lockup we offset by +3rem (half the
     difference) so the chains stay parked at the lockup's
     top corners. We keep using `--chain-pin-inset` so the
     inset tweak from above still applies. The chains
     themselves also shrink via --chain-scale so they don't
     dwarf the smaller lockup. */
  .chain {
    --chain-scale: 0.84;
    top: -0.9rem;
  }

  .chain.left {
    left: calc(50% - 7rem + var(--chain-pin-inset));
  }

  .chain.right {
    right: calc(50% - 7rem + var(--chain-pin-inset));
  }

  /* H1: clamp upper bound at 2.6rem so even on 720p we have
     room for the body copy, the user list, and HeroStats.
     Still 700 / Cinzel / -0.015em letter-spacing — same
     proportions, just shorter. */
  h1 {
    font-size: clamp(1.85rem, 3.6vw, 2.6rem);
    margin-bottom: 0.7rem;
  }
}

.queue-main {
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.app-shell[data-layout="playing"] .queue-main {
  padding: 0;
  gap: 0;
}

.app-shell[data-layout="playing"] .queue-main .embed-player {
  flex: 1 1 auto;
  width: 100%;
  height: 100%;
  min-height: 0;
  /* The embed-player already has aspect-ratio 16/9 baked in
     (it's a video). For wide desktop screens the video would
     otherwise center vertically with letterbox bars — the
     queue-panel parent uses min-height: 100% on its row, so
     the embed stretches into the available vertical space and
     the browser letterboxes inside the iframe. */
}

.player-stage-empty {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 0.75rem;
  padding: 3rem 1.5rem;
  background:
    radial-gradient(ellipse at 50% 0%, oklch(0.36 0.07 42 / 0.95), oklch(0.18 0.04 30) 70%);
  border-radius: 4px;
  border: 1px solid var(--iron-dark);
  text-align: center;
  flex: 1 1 auto;
  min-height: 240px;
}

.player-stage-empty-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-xl);
  color: var(--vellum);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.player-stage-empty-body {
  margin: 0;
  font-size: var(--text-base);
  color: oklch(0.75 0.04 80);
  max-width: 38ch;
  line-height: 1.5;
}

/* ============================================================
   EmbedPlayer fallback overlay (Phase G)
   ============================================================
   When the YouTube IFrame Player API fails to load (network
   blocked, CSP wrong, etc.) the EmbedPlayer shows this overlay
   instead of the iframe. The thumbnail is preserved from the
   song's metadata; the admin gets a "Mark as sung anyway" button
   so they can still advance the queue. */

.embed-player {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: oklch(0.1 0.04 50);
  border-radius: 4px;
  overflow: hidden;
}

.embed-player-target {
  width: 100%;
  height: 100%;
}

.embed-player-target[data-state="loading"] {
  display: flex;
  align-items: center;
  justify-content: center;
  color: oklch(0.7 0.04 80);
  font-style: italic;
}

.embed-player-target[data-state="loading"]::before {
  content: "Loading the mimic's player…";
  font-size: var(--text-sm);
}

.embed-player-target[data-state="ready"] {
  /* YT replaces this with the iframe; nothing visible from our
     CSS side. The 16:9 aspect comes from the parent. */
}

.embed-player-fallback {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: linear-gradient(180deg, oklch(0.15 0.04 50) 0%, oklch(0.22 0.04 50) 100%);
  color: var(--tooth);
  padding: 1rem;
  gap: 0.75rem;
}

.embed-player-thumb {
  width: 100%;
  max-height: 60%;
  object-fit: contain;
  border-radius: 3px;
}

.embed-player-fallback-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.5rem;
}

.embed-player-fallback-reason {
  margin: 0;
  font-size: var(--text-sm);
  color: oklch(0.88 0.04 80);
  font-style: italic;
}

.embed-player-fallback-actions {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.embed-player-open,
.embed-player-mark-sung {
  background: oklch(0.3 0.05 50);
  border: 1px solid var(--iron-dark);
  color: var(--tooth);
  padding: 0.4rem 0.8rem;
  border-radius: 3px;
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
}

.embed-player-open:hover,
.embed-player-mark-sung:hover {
  background: oklch(0.36 0.06 50);
}

.embed-player-mark-sung {
  background: oklch(0.4 0.12 25);
  border-color: oklch(0.3 0.15 22);
}

.embed-player-mark-sung:hover {
  background: oklch(0.46 0.14 25);
}

/* ============================================================
   TopBar (playing mode only)
   ============================================================
   Two-zone horizontal strip:
     - topbar-left: status badge | song title | song duration
     - topbar-right: admin buttons (admin only) | user chip | logout
   On screens too narrow for the full layout the song title
   truncates and the duration hides. The bar is fixed-height
   (set by the parent .hero-panel's height), so children need
   to fit within it. */

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  width: 100%;
  height: 100%;
  padding: 0 0.9rem;
  background: linear-gradient(180deg, oklch(0.18 0.04 50) 0%, oklch(0.22 0.04 50) 100%);
  color: var(--tooth);
  border: 1px solid var(--iron-dark);
  border-radius: 4px;
  box-sizing: border-box;
  overflow: hidden;
}

.topbar-left,
.topbar-right {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  min-width: 0;
}

.topbar-left {
  flex: 1 1 auto;
}

.topbar-right {
  flex: 0 0 auto;
  flex-shrink: 0;
}

.topbar-divider {
  width: 1px;
  height: 1.4em;
  background: var(--iron-dark);
  flex: 0 0 auto;
}

.topbar-title {
  font-size: var(--text-base);
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 1 1 auto;
  color: oklch(0.92 0.04 80);
}

.topbar-progress {
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  color: var(--dim);
  flex: 0 0 auto;
}

/* Admin buttons row: icon + label. On narrow bars the label
   drops out and only the icon remains (via @media inside the
   bar). */
.topbar-admin {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex: 0 0 auto;
}

.topbar-button {
  background: oklch(0.3 0.04 50);
  border: 1px solid var(--iron-dark);
  color: var(--tooth);
  font-size: var(--text-sm);
  font-weight: 600;
  padding: 0.3rem 0.55rem;
  border-radius: 3px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  white-space: nowrap;
  transition: background 120ms ease, transform 80ms ease;
}

.topbar-button:hover:not(:disabled) {
  background: oklch(0.36 0.05 50);
}

.topbar-button:active:not(:disabled) {
  transform: translateY(1px);
}

.topbar-button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.topbar-button-stop {
  background: oklch(0.4 0.12 25);
  border-color: oklch(0.3 0.15 22);
}

.topbar-button-stop:hover:not(:disabled) {
  background: oklch(0.46 0.14 25);
}

.topbar-button-advance {
  background: oklch(0.32 0.06 145);
  border-color: oklch(0.25 0.08 145);
}

.topbar-button-advance:hover:not(:disabled) {
  background: oklch(0.38 0.07 145);
}

.topbar-button-pause,
.topbar-button-resume {
  background: oklch(0.32 0.06 240);
  border-color: oklch(0.25 0.08 240);
}

.topbar-button-pause:hover:not(:disabled),
.topbar-button-resume:hover:not(:disabled) {
  background: oklch(0.38 0.07 240);
}

.topbar-button-logout {
  background: oklch(0.26 0.03 50);
}

/* Inline stop-confirm form: replaces the Stop button when the
   admin taps it. The input expects the literal "STOP" before
   the Confirm button enables. */
.topbar-stop-confirm {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  background: oklch(0.4 0.12 25 / 0.18);
  border: 1px solid oklch(0.3 0.15 22);
  border-radius: 3px;
  padding: 0.18rem 0.3rem;
}

.topbar-stop-input {
  background: oklch(0.16 0.04 50);
  border: 1px solid oklch(0.3 0.04 50);
  color: var(--tooth);
  font-family: inherit;
  font-size: var(--text-sm);
  padding: 0.18rem 0.4rem;
  border-radius: 2px;
  width: 6.5rem;
  outline: none;
}

.topbar-stop-input:focus {
  border-color: oklch(0.5 0.14 22);
}

/* User chip: avatar + username + logout. The username hides on
   narrow bars (where the avatar alone is enough to identify). */
.topbar-user {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex: 0 0 auto;
}

.topbar-username {
  font-size: var(--text-sm);
  font-weight: 600;
  color: oklch(0.88 0.04 80);
  white-space: nowrap;
}

/* Below the 880px breakpoint the bar compresses: the song title
   collapses to a max-width and the progress badge hides. The
   admin buttons keep both icon + label so the controls are
   unambiguous on a phone. */
@media (max-width: 879px) {
  .topbar {
    padding: 0 0.5rem;
    gap: 0.4rem;
  }
  .topbar-title {
    max-width: 10rem;
  }
  .topbar-progress {
    display: none;
  }
}

@media (max-width: 540px) {
  /* Very narrow bars: drop button labels so the icons fit. */
  .topbar-button-label {
    display: none;
  }
  .topbar-button {
    padding: 0.3rem 0.45rem;
  }
  .topbar-title {
    max-width: 6rem;
  }
}

.hero-panel,
.queue-panel {
  position: relative;
  border: 2px solid var(--iron-dark);
  /* Faint gold outline drawn 0.65rem inside the panel border,
     matching production exactly. The outline traces the
     panel's box, not the content's; it's a panel-level
     decoration, not content-following. */
  outline: 1px solid oklch(0.86 0.14 84 / 0.18);
  outline-offset: -0.65rem;
  box-shadow: var(--raised-shadow);
}

/* Queue panel needs overflow:hidden to keep its decorative
   spine (the ::before leather binding) and clasp rivets from
   spilling past the carved edges. Hero-panel does NOT want
   overflow:hidden — it needs to be able to scroll on short
   viewports (the wide-but-short media query at the bottom of
   this file sets overflow-y:auto on .hero-panel). Splitting
   the overflow declaration off the shared rule above keeps
   the two panels from fighting each other in the cascade. */
.queue-panel {
  overflow: hidden;
}

/* Queue-panel keeps the production brass-dot recipe on a
   panel-pinned ::after — the queue-panel doesn't scroll
   internally in idle mode, so panel-corners and content-
   corners are the same place. */
.queue-panel::after {
  position: absolute;
  inset: 0.85rem;
  background:
    radial-gradient(circle at 0 0, var(--brass) 0 0.28rem, transparent 0.31rem),
    radial-gradient(circle at 100% 0, var(--brass) 0 0.28rem, transparent 0.31rem),
    radial-gradient(circle at 0 100%, var(--brass) 0 0.28rem, transparent 0.31rem),
    radial-gradient(circle at 100% 100%, var(--brass) 0 0.28rem, transparent 0.31rem);
  content: "";
  pointer-events: none;
}

.hero-panel {
  /* Sticky scrollable sidebar.
     - `position: sticky; top: 2rem` keeps the panel in view
       while the page scrolls (the queue-panel grows naturally
       with song-list content and pushes the page taller than
       100vh). `top: 2rem` leaves a 2rem gap above the panel
       so the hanging chains (positioned at top: -1.15rem) have
       somewhere to dangle.
     - `height: calc(100vh - 2rem)` makes the panel exactly
       the viewport height minus the chain gap, so it
       occupies the full visible area below the chains.
     - `overflow-y: auto` means the panel's own scrollbar
       appears whenever its content (hero-copy + hero-start +
       user-list + stat-board) exceeds its height. There is
       NO max-height clipping, NO conditional overflow. If it
       doesn't fit, the scrollbar appears. And that's that.
     This is independent from the user-list's own scrollbar
     (the user-list is a child flex item with its own
     overflow-y: auto). The two scroll contexts coexist. */
  position: sticky;
  top: 2rem;
  display: flex;
  flex-direction: column;
  height: calc(100vh - 2rem);
  overflow-y: auto;
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  scrollbar-color: oklch(0.42 0.06 50 / 0.7) transparent;
  padding: 1.55rem;
  border-radius: 8px 8px 4px 4px;

  /* Background stack — oak with candlelight highlights.
     No content-attached outlines here; the panel-level
     outline (4 lines tracing the panel) is drawn by the
     CSS `outline` property on the shared .hero-panel,
     .queue-panel rule above (outline-offset: -0.65rem
     puts it 0.65rem inside the panel border, matching
     production). */
  background:
    radial-gradient(ellipse at 52% 8%, oklch(0.76 0.16 82 / 0.14), transparent 16rem),
    radial-gradient(ellipse at 28% 28%, oklch(0.48 0.12 52 / 0.28), transparent 10rem),
    radial-gradient(ellipse at 78% 68%, oklch(0.09 0.02 28 / 0.74), transparent 18rem),
    linear-gradient(90deg, oklch(0.07 0.018 25 / 0.64), transparent 14%, transparent 86%, oklch(0.055 0.016 22 / 0.72)),
    linear-gradient(180deg, var(--oak-light), var(--oak) 18%, var(--oak-dark));
}

/* Panel-level lighting overlay — a subtle vignette and the
   "carved by candlelight" edges that aren't part of the
   physical oak color. */
.hero-panel::before {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(90deg, oklch(1 0 0 / 0.04), transparent 10%, oklch(0 0 0 / 0.1) 13%, transparent 18%, transparent 82%, oklch(0 0 0 / 0.1) 87%, transparent 91%),
    radial-gradient(circle at 17% 65%, oklch(0.54 0.18 24 / 0.16), transparent 12rem),
    linear-gradient(180deg, oklch(1 0 0 / 0.045), transparent 22%, oklch(0 0 0 / 0.26));
  content: "";
}

/* Subtle brass corner-dots on the SIDEBAR's content (not the
   panel). The hero-panel's content scrolls internally on
   short viewports, and on tall viewports the content may
   not fill the panel — gluing the dots to the panel's
   outer box (production's `inset: 0.85rem` recipe) makes
   them sit in empty space when content is short, and at
   the panel's bottom edge when content has been scrolled
   all the way down (visually below the stat-board rather
   than hugging it).

   Instead, two flex-child anchors ride with the content:
   `.content-corners.top` is the FIRST flex child (sits
   flush at the top of the content), `.content-corners.bottom`
   is the LAST flex child (sits flush at the bottom of the
   content). Each anchor is zero-height so it doesn't affect
   the flex column's height; its two `::before` / `::after`
   pseudo-elements paint one brass dot each, at the
   anchor's left and right corners. When content fills the
   panel, the dots sit at production's inset-0.85rem
   position; when content is shorter or has scrolled, the
   dots track the content's actual bounding box.

   The dot itself is production's exact recipe:
   radial-gradient(circle at <corner>, brass 0 0.28rem,
   transparent 0.31rem). Pseudo-elements are sized to
   0.62rem × 0.62rem so the full fade (out to 0.31rem
   from the corner center) is contained within the box. */
.content-corners {
  /* Zero-height positioning anchor. overflow:visible so the
     absolutely-positioned pseudo-elements paint outside
     the anchor's box. */
  flex: 0 0 0;
  height: 0;
  position: relative;
  overflow: visible;
  pointer-events: none;
}

.content-corners::before,
.content-corners::after {
  content: "";
  position: absolute;
  width: 0.62rem;
  height: 0.62rem;
  pointer-events: none;
}

/* TOP corners — sit at the anchor's top edge, which is the
   content's top edge. */
.content-corners.top::before {
  top: 0;
  left: 0;
  background: radial-gradient(
    circle at 0 0,
    var(--brass) 0 0.28rem,
    transparent 0.31rem
  );
}
.content-corners.top::after {
  top: 0;
  right: 0;
  background: radial-gradient(
    circle at 100% 0,
    var(--brass) 0 0.28rem,
    transparent 0.31rem
  );
}

/* BOTTOM corners — sit at the anchor's bottom edge, which
   is the content's bottom edge. */
.content-corners.bottom::before {
  bottom: 0;
  left: 0;
  background: radial-gradient(
    circle at 0 100%,
    var(--brass) 0 0.28rem,
    transparent 0.31rem
  );
}
.content-corners.bottom::after {
  bottom: 0;
  right: 0;
  background: radial-gradient(
    circle at 100% 100%,
    var(--brass) 0 0.28rem,
    transparent 0.31rem
  );
}

/* Webkit scrollbar styling — matches the carved oak aesthetic. */
.hero-panel::-webkit-scrollbar {
  width: 0.5rem;
}

.hero-panel::-webkit-scrollbar-track {
  background: transparent;
}

.hero-panel::-webkit-scrollbar-thumb {
  background: oklch(0.42 0.06 50 / 0.6);
  border-radius: 999px;
}

/* Forged iron chains hanging the sign */
.chain {
  --chain-scale: 1;
  --chain-pin-inset: 0.6rem;
  --iron-black: oklch(0.075 0.006 45);
  --iron-shadow: oklch(0.02 0.003 45);
  --iron-deep: oklch(0.12 0.008 45);
  --iron-mid: oklch(0.24 0.011 50);
  --iron-high: oklch(0.53 0.018 58);
  position: absolute;
  top: -1.15rem;
  z-index: 4;
  display: flex;
  width: 1.35rem;
  flex-direction: column;
  align-items: center;
  pointer-events: none;
  transform-origin: top center;
  filter:
    drop-shadow(0.18rem 0.28rem 0.18rem oklch(0 0 0 / 0.62))
    drop-shadow(0 0.75rem 0.7rem oklch(0 0 0 / 0.36));
}

.chain::before {
  position: absolute;
  top: -0.15rem;
  left: 50%;
  width: 1.05rem;
  height: 0.68rem;
  border: 1px solid oklch(0.5 0.018 58 / 0.34);
  border-radius: 0 0 999px 999px;
  background:
    radial-gradient(circle at 35% 28%, var(--iron-high) 0 0.07rem, transparent 0.08rem),
    radial-gradient(circle at 65% 28%, var(--iron-high) 0 0.06rem, transparent 0.075rem),
    linear-gradient(90deg, var(--iron-shadow), var(--iron-mid) 38%, var(--iron-high) 48%, var(--iron-deep) 68%, var(--iron-black));
  box-shadow:
    inset 0.1rem 0 0.12rem oklch(1 0 0 / 0.08),
    inset -0.12rem -0.16rem 0.16rem oklch(0 0 0 / 0.64),
    0 0.18rem 0.18rem oklch(0 0 0 / 0.52);
  content: "";
  transform: translateX(-50%);
}

.chain::after {
  position: absolute;
  top: 0.45rem;
  bottom: -0.25rem;
  left: 50%;
  z-index: -1;
  width: 0.34rem;
  border-radius: 999px;
  background: linear-gradient(90deg, transparent, oklch(0 0 0 / 0.28), transparent);
  content: "";
  transform: translateX(-50%);
}

.chain.left {
  left: calc(50% - 10rem + var(--chain-pin-inset));
  transform: rotate(-1.5deg) scale(var(--chain-scale));
}

.chain.right {
  right: calc(50% - 10rem + var(--chain-pin-inset));
  transform: rotate(1.5deg) scale(var(--chain-scale));
}

.chain .link {
  position: relative;
  display: block;
  flex: 0 0 auto;
  transform-style: preserve-3d;
}

.chain .link + .link {
  margin-top: -0.65rem;
}

.chain .link::before,
.chain .link::after {
  position: absolute;
  content: "";
  pointer-events: none;
}

/* Forward-facing links: open forged ovals with visible inner voids. */
.chain .link:nth-child(odd) {
  z-index: 2;
  width: 1.16rem;
  height: 1.78rem;
  border-radius: 999px;
  background:
    radial-gradient(ellipse at 32% 14%, oklch(0.82 0.022 70 / 0.34) 0 0.08rem, transparent 0.18rem),
    radial-gradient(ellipse at 72% 86%, oklch(0 0 0 / 0.76) 0 0.18rem, transparent 0.34rem),
    repeating-linear-gradient(124deg, transparent 0 0.2rem, oklch(1 0 0 / 0.045) 0.21rem 0.24rem, transparent 0.25rem 0.48rem),
    linear-gradient(100deg, var(--iron-black), var(--iron-deep) 18%, var(--iron-high) 38%, var(--iron-mid) 47%, var(--iron-black) 63%, var(--iron-deep) 82%, var(--iron-shadow));
  box-shadow:
    inset 0.18rem 0.1rem 0.15rem oklch(1 0 0 / 0.08),
    inset -0.2rem -0.24rem 0.2rem oklch(0 0 0 / 0.62),
    0.08rem 0.16rem 0.14rem oklch(0 0 0 / 0.68),
    0 0 0 1px oklch(0.66 0.022 62 / 0.2);
  -webkit-mask: radial-gradient(ellipse at 50% 50%, transparent 0 39%, #000 41% 100%);
  mask: radial-gradient(ellipse at 50% 50%, transparent 0 39%, #000 41% 100%);
}

.chain .link:nth-child(odd)::before {
  inset: 0.11rem 0.2rem auto auto;
  width: 0.2rem;
  height: 1.22rem;
  border-radius: 999px;
  background: linear-gradient(180deg, oklch(0.9 0.02 70 / 0.38), transparent 58%);
  transform: rotate(10deg);
}

.chain .link:nth-child(odd)::after {
  right: 0.18rem;
  bottom: 0.12rem;
  width: 0.22rem;
  height: 0.72rem;
  border-radius: 999px;
  background: oklch(0 0 0 / 0.38);
  transform: rotate(18deg);
}

/* Perpendicular links: edge-on ovals read as thick vertical iron bars. */
.chain .link:nth-child(even) {
  z-index: 3;
  width: 0.54rem;
  height: 1.68rem;
  border-radius: 999px;
  background:
    radial-gradient(ellipse at 42% 10%, oklch(0.82 0.02 68 / 0.32), transparent 0.22rem),
    radial-gradient(ellipse at 70% 92%, oklch(0 0 0 / 0.72), transparent 0.3rem),
    repeating-linear-gradient(164deg, transparent 0 0.16rem, oklch(1 0 0 / 0.055) 0.17rem 0.19rem, transparent 0.2rem 0.42rem),
    linear-gradient(90deg, var(--iron-shadow), var(--iron-deep) 18%, var(--iron-high) 44%, var(--iron-mid) 55%, var(--iron-black) 100%);
  box-shadow:
    inset 0.1rem 0 0.12rem oklch(1 0 0 / 0.1),
    inset -0.16rem 0 0.14rem oklch(0 0 0 / 0.6),
    0.12rem 0.18rem 0.16rem oklch(0 0 0 / 0.72),
    0 0 0 1px oklch(0.68 0.022 62 / 0.18);
}

.chain .link:nth-child(even)::before {
  inset: 0.14rem 0.1rem;
  border-radius: inherit;
  background: linear-gradient(90deg, oklch(1 0 0 / 0.14), transparent 38%, oklch(0 0 0 / 0.28) 76%);
}

.chain .link:nth-child(even)::after {
  top: 50%;
  left: 50%;
  width: 1.02rem;
  height: 0.28rem;
  border-radius: 999px;
  background: radial-gradient(ellipse at center, oklch(0 0 0 / 0.5), transparent 68%);
  transform: translate(-50%, -50%);
}

.hero-copy,
.login-panel,
.stat-board,
.brand-lockup {
  position: relative;
  z-index: 5;
}

.brand-lockup {
  --chain-pin-inset: 0.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20rem;
  margin: 5rem auto 1.35rem;
  padding: 1rem 0.5rem 1.1rem;
  border: 3px solid oklch(0.12 0.025 40);
  border-radius: 3px;
  /* Realistic dark wood grain: layered repeating gradients at slight angles */
  background:
    /* Top sheen: subtle overhead light reflecting off polished wood */
    linear-gradient(180deg,
      oklch(0.35 0.06 50 / 0.18) 0%,
      transparent 35%),
    /* Grain layer 1: fine lines, slight angle */
    repeating-linear-gradient(2deg,
      transparent 0px,
      transparent 3px,
      oklch(0.22 0.045 45 / 0.4) 3px,
      oklch(0.22 0.045 45 / 0.4) 4px,
      transparent 4px,
      transparent 8px),
    /* Grain layer 2: medium lines, opposite angle for depth */
    repeating-linear-gradient(-1deg,
      transparent 0px,
      transparent 6px,
      oklch(0.28 0.055 48 / 0.35) 6px,
      oklch(0.28 0.055 48 / 0.35) 7.5px,
      transparent 7.5px,
      transparent 14px),
    /* Grain layer 3: wider, softer streaks */
    repeating-linear-gradient(0.5deg,
      transparent 0px,
      transparent 12px,
      oklch(0.18 0.035 42 / 0.3) 12px,
      oklch(0.18 0.035 42 / 0.3) 14px,
      transparent 14px,
      transparent 22px),
    /* Grain layer 4: occasional lighter heartwood streaks */
    repeating-linear-gradient(-0.5deg,
      transparent 0px,
      transparent 28px,
      oklch(0.32 0.06 52 / 0.2) 28px,
      oklch(0.32 0.06 52 / 0.2) 30px,
      transparent 30px,
      transparent 45px),
    /* Edge darkening: vignette for aged sign look */
    linear-gradient(90deg,
      oklch(0.06 0.015 35 / 0.7) 0%,
      transparent 12%,
      transparent 88%,
      oklch(0.06 0.015 35 / 0.7) 100%),
    /* Base wood color: dark walnut */
    linear-gradient(180deg,
      oklch(0.22 0.05 46) 0%,
      oklch(0.18 0.04 42) 50%,
      oklch(0.15 0.035 38) 100%);
  box-shadow:
    /* Brass trim inset */
    0 0 0 4px oklch(0.65 0.12 78 / 0.3) inset,
    0 0 0 7px oklch(0.08 0.02 30 / 0.9) inset,
    /* Deep inset shadow for thickness */
    inset 0 8px 16px oklch(0 0 0 / 0.4),
    inset 0 -4px 8px oklch(0 0 0 / 0.25),
    /* Drop shadow for hanging depth */
    0 6px 12px oklch(0 0 0 / 0.5),
    0 12px 24px oklch(0 0 0 / 0.35);
}

.brand-lockup::before,
.brand-lockup::after {
  position: absolute;
  top: -0.45rem;
  z-index: 5;
  width: 1.36rem;
  height: 0.92rem;
  margin: 0 .65rem;
  border: 1px solid oklch(0.58 0.02 62 / 0.28);
  border-radius: 0.18rem 0.18rem 0.42rem 0.42rem;
  background:
    radial-gradient(circle at 32% 68%, oklch(0.78 0.025 70 / 0.55) 0 0.08rem, oklch(0.08 0.006 45) 0.09rem 0.15rem, transparent 0.16rem),
    radial-gradient(circle at 68% 68%, oklch(0.78 0.025 70 / 0.42) 0 0.065rem, oklch(0.07 0.005 45) 0.08rem 0.14rem, transparent 0.15rem),
    linear-gradient(90deg, oklch(0.035 0.004 45), oklch(0.22 0.012 52) 38%, oklch(0.46 0.018 60) 48%, oklch(0.12 0.009 48) 68%, oklch(0.025 0.003 45));
  box-shadow:
    inset 0.08rem 0.1rem 0.12rem oklch(1 0 0 / 0.08),
    inset -0.12rem -0.16rem 0.18rem oklch(0 0 0 / 0.64),
    0 0.18rem 0.18rem oklch(0 0 0 / 0.46);
  content: "";
}

.brand-lockup::before {
  left: var(--chain-pin-inset);
  transform: translateX(-50%);
}

.brand-lockup::after {
  right: var(--chain-pin-inset);
  transform: translateX(50%);
}

.brand-mark {
  width: min(13rem, 56%);
  height: auto;
  flex: 0 0 auto;
  object-fit: contain;
  filter: drop-shadow(0 4px 3px oklch(0 0 0 / 0.42));
}

.guild-note,
.section-note {
  margin: 0 0 0.7rem;
  color: var(--brass-bright);
  font-size: var(--text-sm);
  font-weight: 800;
  letter-spacing: 0.01em;
}

h1,
h2,
h3,
p {
  margin-top: 0;
}

h1 {
  max-width: 13ch;
  margin-bottom: 1rem;
  color: var(--tooth);
  font-family: var(--font-display);
  font-size: var(--text-display);
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.05;
  text-wrap: balance;
}

h2 {
  margin-bottom: 0.25rem;
  color: var(--tooth);
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: 0.005em;
  line-height: 1.2;
  text-wrap: balance;
}

h3 {
  margin-bottom: 0.45rem;
  color: var(--tooth);
  font-size: var(--text-lg);
  font-weight: 700;
  letter-spacing: -0.005em;
  line-height: 1.25;
  text-wrap: balance;
}

.hero-copy p:not(.guild-note),
.empty-state p {
  max-width: 65ch;
  color: var(--muted);
  font-size: var(--text-base);
  line-height: 1.65;
  letter-spacing: 0.005em;
  text-wrap: pretty;
}

.login-panel {
  display: grid;
  gap: 1rem;
  align-items: start;
}

.login-panel p {
  color: var(--muted);
}

.button {
  display: inline-flex;
  min-height: 2.75rem;
  align-items: center;
  justify-content: center;
  border: 1px solid oklch(0.31 0.08 54);
  border-radius: 7px;
  cursor: pointer;
  font-size: var(--text-base);
  font-weight: 700;
  text-decoration: none;
  transition:
    transform 170ms cubic-bezier(0.25, 1, 0.5, 1),
    filter 170ms cubic-bezier(0.25, 1, 0.5, 1),
    box-shadow 170ms cubic-bezier(0.25, 1, 0.5, 1);
}

.discord-button,
.primary-action {
  background:
    radial-gradient(ellipse at 50% 0, oklch(0.96 0.15 88 / 0.72), transparent 1.2rem),
    linear-gradient(180deg, var(--brass-bright), var(--brass) 48%, var(--brass-dark));
  color: var(--vellum-ink);
  padding: 0 1.1rem;
  text-shadow: 0 1px 0 oklch(1 0 0 / 0.15);
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.38),
    inset 0 -4px 0 oklch(0.25 0.07 50 / 0.32),
    0 3px 0 oklch(0.1 0.02 30 / 0.68);
}

.button:hover {
  filter: brightness(1.06);
  transform: translateY(-1px);
}

.button:active {
  filter: brightness(0.95);
  transform: translateY(0);
  box-shadow:
    inset 0 2px 4px oklch(0 0 0 / 0.2),
    inset 0 -1px 0 oklch(1 0 0 / 0.1);
}

.button:focus-visible,
input:focus-visible {
  outline: 3px solid oklch(0.9 0.14 84 / 0.55);
  outline-offset: 2px;
}

.primary-action:disabled {
  cursor: wait;
  opacity: 0.7;
}

.delete-button {
  background:
    linear-gradient(180deg, oklch(0.25 0.05 25), oklch(0.15 0.03 25));
  color: oklch(0.7 0.1 25);
  border-color: oklch(0.3 0.08 25);
  padding: 0 0.75rem;
  font-size: var(--text-sm);
  min-height: 2rem;
}

.delete-button:hover {
  background:
    linear-gradient(180deg, oklch(0.3 0.06 25), oklch(0.2 0.04 25));
  color: oklch(0.8 0.12 25);
}

/* Reorder chevrons: ▲ / ▼ on the user's own songs in day mode.
   Brass gradient at ~60% opacity of the primary action, fixed 2rem×2rem
   square so the pair sits side-by-side cleanly. Disabled variant is
   visibly faded so the user understands the boundary state. */
.swap-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  min-height: unset;
  padding: 0;
  border: 1px solid oklch(0.31 0.08 54);
  border-radius: 5px;
  cursor: pointer;
  font-size: var(--text-xs);
  font-weight: 700;
  line-height: 1;
  background:
    radial-gradient(ellipse at 50% 0, oklch(0.96 0.15 88 / 0.45), transparent 0.8rem),
    linear-gradient(180deg, oklch(0.68 0.13 78 / 0.6), oklch(0.42 0.1 72 / 0.6));
  color: var(--vellum-ink);
  text-shadow: 0 1px 0 oklch(1 0 0 / 0.1);
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.25),
    inset 0 -2px 0 oklch(0.25 0.07 50 / 0.2),
    0 1px 0 oklch(0.1 0.02 30 / 0.5);
  transition:
    transform 170ms cubic-bezier(0.25, 1, 0.5, 1),
    filter 170ms cubic-bezier(0.25, 1, 0.5, 1),
    box-shadow 170ms cubic-bezier(0.25, 1, 0.5, 1);
}

.swap-button:hover:not(:disabled) {
  filter: brightness(1.06);
  transform: translateY(-1px);
}

.swap-button:active:not(:disabled) {
  filter: brightness(0.95);
  transform: translateY(0);
}

.swap-button:disabled {
  opacity: 0.35;
  cursor: not-allowed;
  filter: none;
  transform: none;
  box-shadow: none;
}

.swap-button:focus-visible {
  outline: 3px solid oklch(0.9 0.14 84 / 0.55);
  outline-offset: 2px;
}

.swap-button-row {
  display: flex;
  flex-direction: row;
  gap: 2px;
  justify-content: flex-end;
}

/* Logout: sits in the user-chip alongside the avatar and username.
   It should be visually quiet — the loud brass CTA is for primary
   actions only. Smaller, dimmer, secondary palette. */
.logout-button {
  background:
    linear-gradient(180deg, oklch(0.21 0.04 36), oklch(0.13 0.025 30));
  color: oklch(0.78 0.05 60);
  border-color: oklch(0.32 0.06 50);
  padding: 0 0.7rem;
  font-size: var(--text-sm);
  min-height: 2rem;
  letter-spacing: 0.04em;
}

.logout-button:hover {
  background:
    linear-gradient(180deg, oklch(0.27 0.05 36), oklch(0.18 0.03 30));
  color: oklch(0.86 0.06 65);
  border-color: oklch(0.42 0.08 50);
}

/* Notes affordances. The "+ Add note" link-style button should
   not compete with the song title. The "Edit note" sits next to
   the existing note text and is similarly quiet. */
.notes-add-button,
.notes-edit-button {
  background: oklch(0.9 0.045 82 / 0.3);
  color: var(--vellum-ink);
  border-color: oklch(0.24 0.055 44 / 0.2);
  padding: 0 0.45rem;
  min-height: 1.5rem;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
}

.notes-add-button:hover,
.notes-edit-button:hover {
  background: oklch(0.92 0.05 82 / 0.46);
  color: var(--vellum-text-strong);
  border-color: oklch(0.24 0.055 44 / 0.28);
}

.duplicate-warning {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  margin-top: 0.75rem;
  border: 1px solid oklch(0.7 0.15 80);
  border-radius: 8px;
  background: linear-gradient(180deg, oklch(0.25 0.06 80), oklch(0.18 0.04 80));
  color: oklch(0.85 0.1 80);
  font-size: var(--text-sm);
}

.duplicate-warning strong {
  color: oklch(0.9 0.18 80);
}

.duplicate-warning em {
  font-style: normal;
  font-weight: 700;
  color: var(--vellum);
}

.duplicate-warning .avatar {
  width: 1.25rem;
  height: 1.25rem;
  vertical-align: middle;
}

.dismiss-warning {
  margin-left: auto;
  background: transparent;
  border: 1px solid oklch(0.5 0.1 80);
  color: oklch(0.7 0.1 80);
  padding: 0.25rem 0.5rem;
  font-size: var(--text-xs);
  min-height: auto;
}

.dismiss-warning:hover {
  background: oklch(0.3 0.08 80);
  color: oklch(0.9 0.15 80);
}

.stat-board {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
}

/* The candle (RuntimeStat) is the first child of the stat-board
   and is meant to be the tall, full-width piece. Spanning both
   columns puts it on the top row and pushes the two compact
   stat tiles ("songs" / "your offerings") to a shared second
   row below it. On mobile the grid collapses to a single column
   (see the media query below) where the span is released. */
.stat-board > :first-child {
  grid-column: 1 / -1;
}

.stat-tile {
  position: relative;
  min-width: 0;
  border: 1px solid oklch(0.43 0.08 56 / 0.9);
  border-radius: 8px;
  background:
    radial-gradient(circle at top right, oklch(0.69 0.14 82 / 0.18), transparent 5.5rem),
    linear-gradient(180deg, oklch(0.19 0.045 36 / 0.96), oklch(0.085 0.014 28 / 0.97));
  padding: 0.9rem;
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.08),
    inset 0 -8px 14px oklch(0 0 0 / 0.18);
}

.stat-tile strong {
  display: block;
  max-width: 100%;
  color: var(--tooth);
  font-size: var(--text-xl);
  font-weight: 800;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.stat-tile span {
  display: block;
  max-width: 100%;
  color: var(--dim);
  font-size: var(--text-sm);
  font-weight: 600;
  overflow-wrap: anywhere;
}

.runtime-warning {
  border-color: oklch(0.6 0.2 25);
  animation: runtime-pulse 1.5s ease-in-out infinite;
}

.runtime-warning strong {
  color: oklch(0.8 0.2 25);
}

.runtime-warning-text {
  display: block;
  margin-top: 0.35rem;
  color: oklch(0.75 0.2 25) !important;
  font-weight: 700;
  font-size: var(--text-sm) !important;
}

@keyframes runtime-pulse {
  0%, 100% {
    box-shadow:
      inset 0 1px 0 oklch(1 0 0 / 0.08),
      inset 0 -8px 14px oklch(0 0 0 / 0.18),
      0 0 0 0 oklch(0.6 0.2 25 / 0);
  }
  50% {
    box-shadow:
      inset 0 1px 0 oklch(1 0 0 / 0.08),
      inset 0 -8px 14px oklch(0 0 0 / 0.18),
      0 0 20px 4px oklch(0.6 0.2 25 / 0.4);
  }
}

.queue-panel {
  position: relative;
  min-width: 0;
  padding: 1.35rem 1.35rem 1.35rem 2.8rem;
  border-radius: 5px 10px 10px 5px;
  background:
    radial-gradient(circle at 24% 0, oklch(0.78 0.14 82 / 0.1), transparent 18rem),
    radial-gradient(circle at 85% 88%, oklch(0 0 0 / 0.36), transparent 22rem),
    linear-gradient(90deg, oklch(0.055 0.018 24 / 0.94), var(--leather-dark) 9%, var(--leather) 56%, var(--leather-dark) 96%),
    var(--leather);
}

/* Spine: rounded leather book-binding on the left edge, raised cords underneath */
.queue-panel::before {
  position: absolute;
  top: 0.35rem;
  bottom: 0.35rem;
  left: 0;
  width: 2rem;
  z-index: 1;
  pointer-events: none;
  border-radius: 7px 0 0 7px;
  content: "";
  background:
    /* raised cord bands running across the spine */
    repeating-linear-gradient(
      180deg,
      oklch(0.3 0.065 44) 0,
      oklch(0.26 0.055 40) 1.35rem,
      oklch(0.11 0.028 30) 1.35rem,
      oklch(0.09 0.022 28) 1.45rem,
      oklch(0.42 0.09 49) 1.45rem,
      oklch(0.46 0.095 51) 1.57rem,
      oklch(0.38 0.08 46) 1.69rem,
      oklch(0.09 0.022 28) 1.69rem,
      oklch(0.13 0.03 32) 1.79rem,
      oklch(0.3 0.065 44) 1.89rem
    ),
    /* base leather: warm brown, candlelight from the left */
    linear-gradient(90deg, oklch(0.34 0.075 46), oklch(0.22 0.05 38) 65%, oklch(0.12 0.03 30));
  box-shadow:
    inset -6px 0 9px oklch(0 0 0 / 0.5),
    inset 2px 0 0 oklch(0.5 0.1 50 / 0.22),
    6px 0 16px oklch(0 0 0 / 0.4);
}

/* Clasps: brass bosses riveted onto the spine */
.ledger-clasp {
  position: absolute;
  left: 0.5rem;
  z-index: 2;
  width: 1rem;
  height: 1rem;
  pointer-events: none;
  border: 1px solid oklch(0.26 0.08 48);
  border-radius: 50%;
  background:
    radial-gradient(circle at 36% 30%, var(--brass-bright), var(--brass) 55%, var(--brass-dark));
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.45),
    inset 0 -2px 3px oklch(0 0 0 / 0.35),
    0 2px 4px oklch(0 0 0 / 0.55);
}

.ledger-clasp::after {
  position: absolute;
  inset: 0.28rem;
  border-radius: 50%;
  background: radial-gradient(circle at 40% 35%, oklch(0.5 0.12 78), var(--brass-dark));
  box-shadow: inset 0 1px 1px oklch(1 0 0 / 0.25);
  content: "";
}

.ledger-clasp.top {
  top: 1.8rem;
}

.ledger-clasp.bottom {
  bottom: 1.8rem;
}



.queue-main {
  position: relative;
  isolation: isolate;
}

.toolbar {
  position: relative;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
}

.user-chip,
.song-meta {
  display: flex;
  align-items: center;
}

.user-chip {
  gap: 0.55rem;
  border: 1px solid oklch(0.44 0.07 55);
  border-radius: 999px;
  background: linear-gradient(180deg, oklch(0.18 0.035 38), oklch(0.09 0.012 28));
  color: var(--muted);
  font-size: var(--text-base);
  font-weight: 600;
  padding: 0.3rem 0.7rem 0.3rem 0.3rem;
  white-space: nowrap;
  box-shadow: inset 0 1px 0 oklch(1 0 0 / 0.08);
}

.offering-board {
  position: relative;
  z-index: 2;
  margin: 1.15rem 0 0.95rem;
  border: 1px solid oklch(0.42 0.07 52);
  border-radius: 3px 10px 3px 12px;
  background:
    radial-gradient(ellipse at 13% 0, oklch(1 0.05 90 / 0.38), transparent 9rem),
    radial-gradient(ellipse at 91% 90%, oklch(0.5 0.12 42 / 0.14), transparent 7rem),
    linear-gradient(180deg, var(--vellum), var(--vellum-deep));
  color: var(--vellum-ink);
  padding: 1rem;
  box-shadow:
    0 5px 0 oklch(0.07 0.015 24 / 0.48),
    inset 0 0 0 2px oklch(0.3 0.06 52 / 0.13),
    inset 0 -14px 24px oklch(0.35 0.08 42 / 0.13);
}

.offering-board::before {
  position: absolute;
  inset: -0.43rem 1.2rem auto;
  height: 0.42rem;
  border: 1px solid oklch(0.1 0.01 40 / 0.65);
  border-radius: 999px;
  background: linear-gradient(180deg, oklch(0.64 0.02 65), var(--iron), var(--iron-dark));
  content: "";
}

.wax-seal {
  position: absolute;
  right: 1rem;
  bottom: -0.82rem;
  width: 2.2rem;
  height: 2.2rem;
  cursor: pointer;
  border: 1px solid oklch(0.22 0.11 22 / 0.72);
  border-radius: 54% 46% 58% 42% / 46% 57% 43% 54%;
  background:
    /* Wet wax glints and tiny surface dimples. */
    radial-gradient(ellipse at 30% 22%, oklch(0.78 0.19 24 / 0.76) 0 0.16rem, transparent 0.48rem),
    radial-gradient(circle at 69% 30%, oklch(0.66 0.18 18 / 0.36) 0 0.07rem, transparent 0.26rem),
    radial-gradient(circle at 23% 72%, oklch(0.18 0.08 21 / 0.48) 0 0.12rem, transparent 0.34rem),
    radial-gradient(circle at 78% 66%, oklch(0.17 0.07 20 / 0.42) 0 0.09rem, transparent 0.32rem),
    /* Uneven raised rim: brighter candlelit top-left, darker pooled bottom-right. */
    conic-gradient(from 222deg at 49% 49%,
      oklch(0.24 0.11 21) 0deg,
      var(--wax) 44deg,
      oklch(0.6 0.19 21) 82deg,
      var(--tongue) 108deg,
      var(--mimic) 146deg,
      oklch(0.34 0.14 22) 214deg,
      oklch(0.17 0.08 20) 286deg,
      oklch(0.42 0.16 25) 334deg,
      oklch(0.24 0.11 21) 360deg),
    /* Oxblood body under the pooled rim. */
    radial-gradient(ellipse at 47% 43%, oklch(0.55 0.19 23), var(--wax) 44%, oklch(0.28 0.12 22) 73%, oklch(0.16 0.07 20));
  box-shadow:
    inset 0.16rem 0.18rem 0.22rem oklch(0.86 0.18 28 / 0.18),
    inset -0.22rem -0.25rem 0.34rem oklch(0.07 0.035 20 / 0.78),
    inset 0 0 0 0.12rem oklch(0.28 0.13 23 / 0.72),
    inset 0 0.08rem 0.06rem oklch(1 0 0 / 0.1),
    0 0.08rem 0 oklch(0.98 0.035 82 / 0.18),
    0 0.28rem 0.34rem oklch(0 0 0 / 0.48),
    0 0.64rem 0.82rem oklch(0 0 0 / 0.24);
  transform: rotate(-7deg);
}

.wax-seal::after {
  position: absolute;
  inset: 0.43rem;
  border: 0.12rem solid oklch(0.14 0.06 23 / 0.68);
  border-radius: 49% 51% 46% 54% / 55% 46% 54% 45%;
  background:
    /* Simple tavern-rune stamp cut into the wax. */
    linear-gradient(90deg, transparent 0 calc(50% - 0.035rem), oklch(0.11 0.045 22 / 0.43) calc(50% - 0.035rem) calc(50% + 0.035rem), transparent calc(50% + 0.035rem)),
    linear-gradient(38deg, transparent 0 42%, oklch(0.12 0.05 22 / 0.34) 43% 48%, transparent 49%),
    linear-gradient(142deg, transparent 0 43%, oklch(0.12 0.05 22 / 0.32) 44% 49%, transparent 50%),
    radial-gradient(ellipse at 50% 57%, oklch(0.12 0.05 22 / 0.34) 0 0.17rem, transparent 0.19rem),
    radial-gradient(circle at 42% 34%, oklch(0.78 0.16 24 / 0.08), transparent 0.34rem),
    radial-gradient(circle at 50% 50%, oklch(0.06 0.025 20 / 0.24), transparent 70%);
  box-shadow:
    inset 0.06rem 0.08rem 0.1rem oklch(0.04 0.02 20 / 0.58),
    inset -0.05rem -0.06rem 0.08rem oklch(0.84 0.16 26 / 0.12),
    0 0.04rem 0 oklch(0.75 0.16 25 / 0.12),
    0 -0.04rem 0.05rem oklch(0.05 0.02 20 / 0.28);
  content: "";
}

.board-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.8rem;
}

.board-heading span {
  color: var(--vellum-text);
  font-size: var(--text-base);
  font-weight: 800;
}

.board-heading strong {
  color: var(--vellum-text-strong);
  font-size: var(--text-base);
  font-weight: 600;
}

.avatar {
  display: inline-grid;
  width: 1.85rem;
  height: 1.85rem;
  flex: 0 0 auto;
  place-items: center;
  overflow: hidden;
  border-radius: 999px;
  background: var(--mimic);
  color: white;
  font-size: var(--text-xs);
  font-weight: 800;
}

.avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.proposal-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 10rem auto;
  gap: 0.75rem;
  align-items: end;
  margin-bottom: 0;
}

.proposal-form > form {
  display: contents;
}

.proposal-form > .form-status,
.proposal-form > .notice,
.proposal-form > .confirmation-panel {
  grid-column: 1 / -1;
}

.form-status {
  margin: 0;
  color: var(--vellum-text-strong);
  font-size: var(--text-base);
  font-weight: 700;
}

.confirmation-panel {
  display: grid;
  grid-template-columns: minmax(7.5rem, 10.5rem) minmax(0, 1fr) auto;
  gap: 0.95rem;
  align-items: center;
  min-width: 0;
  max-width: 100%;
  border: 1px solid oklch(0.42 0.075 52 / 0.9);
  border-radius: 8px;
  background:
    radial-gradient(ellipse at top left, oklch(0.94 0.08 84 / 0.24), transparent 12rem),
    linear-gradient(180deg, oklch(0.73 0.07 80 / 0.98), oklch(0.55 0.075 68 / 0.98));
  color: var(--vellum-ink);
  padding: 0.85rem;
  box-shadow:
    0 4px 0 oklch(0.07 0.015 24 / 0.42),
    inset 0 1px 0 oklch(1 0 0 / 0.26);
}

.confirmation-panel.duplicate-conflict {
  grid-template-columns: minmax(0, 1fr) auto;
}

.confirmation-thumb {
  display: grid;
  width: 100%;
  max-width: 10.5rem;
  aspect-ratio: 16 / 9;
  place-items: center;
  overflow: hidden;
  border: 2px solid oklch(0.35 0.07 48);
  border-radius: 5px;
  background: oklch(0.075 0.012 30);
  color: var(--brass-bright);
  font-size: var(--text-sm);
  font-weight: 800;
}

.confirmation-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.confirmation-thumb span {
  display: grid;
  width: 100%;
  height: 100%;
  place-items: center;
}

.confirmation-body {
  display: grid;
  min-width: 0;
  gap: 0.35rem;
}

.confirmation-kicker {
  color: var(--vellum-text);
  font-size: var(--text-sm);
  font-weight: 800;
}

.confirmation-body > strong {
  min-width: 0;
  color: var(--vellum-ink);
  font-size: var(--text-lg);
  font-weight: 850;
  line-height: 1.15;
  overflow-wrap: anywhere;
  text-wrap: pretty;
}

.confirmation-runtime,
.confirmation-note {
  color: var(--vellum-text-strong);
  font-size: var(--text-sm);
  font-weight: 700;
  line-height: 1.35;
}

.confirmation-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: flex-end;
}

.similar-status,
.similar-list {
  display: grid;
  gap: 0.25rem;
  margin-top: 0.35rem;
  max-width: 100%;
}

.similar-status {
  border: 1px solid oklch(0.42 0.07 54 / 0.42);
  border-radius: 6px;
  background: oklch(0.68 0.06 78 / 0.42);
  padding: 0.55rem 0.65rem;
}

.similar-status strong,
.similar-list > strong {
  color: var(--vellum-text-strong);
  font-size: var(--text-sm);
  font-weight: 800;
}

.similar-status span {
  color: var(--vellum-text);
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: 1.35;
}

.similar-list ul {
  display: grid;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.similar-list li {
  display: flex;
  min-width: 0;
  flex-wrap: wrap;
  gap: 0.25rem 0.4rem;
  align-items: baseline;
  border: 1px solid oklch(0.42 0.07 54 / 0.38);
  border-radius: 6px;
  background: oklch(0.62 0.065 74 / 0.38);
  color: var(--vellum-text);
  padding: 0.5rem 0.6rem;
  font-size: var(--text-sm);
  line-height: 1.3;
}

.similar-list li em {
  min-width: 0;
  color: var(--vellum-ink);
  font-style: normal;
  font-weight: 800;
  overflow-wrap: anywhere;
}

.similar-list li strong {
  color: var(--vellum-text-strong);
}

.similarity-score {
  margin-left: auto;
  border-radius: 999px;
  background: oklch(0.45 0.14 24 / 0.18);
  color: var(--vellum-text-accent);
  padding: 0.1rem 0.45rem;
  font-size: var(--text-xs);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

label {
  display: grid;
  gap: 0.4rem;
  color: currentColor;
  font-size: var(--text-base);
  font-weight: 700;
}

input {
  width: 100%;
  min-height: 2.75rem;
  border: 1px solid oklch(0.42 0.075 46);
  border-radius: 5px;
  background:
    radial-gradient(circle at top left, oklch(1 0.02 86 / 0.34), transparent 8rem),
    oklch(0.72 0.065 78);
  color: var(--vellum-ink);
  outline: none;
  padding: 0 0.85rem;
  box-shadow:
    inset 0 2px 4px oklch(0 0 0 / 0.18),
    inset 0 1px 0 oklch(1 0 0 / 0.28);
}

input::placeholder {
  color: var(--placeholder);
}

input:focus {
  border-color: var(--brass);
}

.form-error {
  margin: 0.5rem 0 1rem;
  color: var(--danger);
  font-size: var(--text-sm);
  font-weight: 600;
}

.filter-bar {
  position: relative;
  z-index: 3;
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.filter-input {
  flex: 1;
  padding: 0.6rem 0.85rem;
  border: 1px solid oklch(0.4 0.08 55);
  border-radius: 6px;
  background: oklch(0.15 0.03 30);
  color: var(--vellum);
  font-size: var(--text-base);
  font-family: inherit;
}

.filter-input::placeholder {
  color: oklch(0.5 0.05 50);
}

.filter-input:focus {
  outline: 2px solid oklch(0.8 0.15 84);
  outline-offset: 1px;
}

.filter-select {
  padding: 0.6rem 0.85rem;
  border: 1px solid oklch(0.4 0.08 55);
  border-radius: 6px;
  background: oklch(0.15 0.03 30);
  color: var(--vellum);
  font-size: var(--text-base);
  font-family: inherit;
  min-width: 140px;
}

.filter-select:focus {
  outline: 2px solid oklch(0.8 0.15 84);
  outline-offset: 1px;
}

.filter-select option {
  background: oklch(0.15 0.03 30);
  color: var(--vellum);
}

.song-list {
  position: relative;
  z-index: 3;
  display: grid;
  gap: 0.75rem;
  margin: 1.1rem 0 0;
  padding: 0;
  list-style: none;
}

.song-row {
  position: relative;
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr) auto;
  gap: 1rem;
  align-items: center;
  border: 1px solid oklch(0.42 0.075 52 / 0.9);
  border-radius: 3px 9px 4px 11px;
  background:
    radial-gradient(ellipse at top left, oklch(0.92 0.07 82 / 0.2), transparent 10rem),
    linear-gradient(180deg, oklch(0.74 0.07 80 / 0.98), oklch(0.55 0.075 68 / 0.98));
  color: var(--vellum-ink);
  padding: 0.85rem;
  box-shadow:
    0 5px 0 oklch(0.07 0.015 24 / 0.45),
    inset 0 1px 0 oklch(1 0 0 / 0.28),
    inset 0 -12px 22px oklch(0.28 0.08 42 / 0.12);
}

.song-row::before {
  position: absolute;
  inset: 0.32rem;
  border: 1px solid oklch(0.25 0.06 44 / 0.12);
  border-radius: 3px 7px 3px 8px;
  content: "";
  pointer-events: none;
}

.notice-pin {
  position: absolute;
  top: 0.45rem;
  z-index: 1;
  width: 0.72rem;
  height: 0.72rem;
  border: 1px solid var(--brass-dark);
  border-radius: 999px;
  background:
    radial-gradient(circle at 35% 30%, oklch(0.94 0.13 88), transparent 0.16rem),
    radial-gradient(circle, var(--brass), var(--brass-dark));
  box-shadow: 0 2px 2px oklch(0 0 0 / 0.38);
}

.notice-pin.left {
  left: 0.55rem;
}

.notice-pin.right {
  right: 0.55rem;
}

.song-row.mine {
  background:
    radial-gradient(ellipse at top left, oklch(0.9 0.12 82 / 0.3), transparent 12rem),
    linear-gradient(180deg, oklch(0.78 0.08 82 / 0.98), oklch(0.6 0.09 70 / 0.98));
}

.song-thumb {
  display: grid;
  aspect-ratio: 16 / 9;
  place-items: center;
  overflow: hidden;
  border: 2px solid oklch(0.35 0.07 48);
  border-radius: 4px;
  background: oklch(0.075 0.012 30);
  color: var(--brass-bright);
  font-weight: 800;
  text-decoration: none;
  box-shadow:
    inset 0 0 0 1px oklch(1 0 0 / 0.08),
    0 2px 3px oklch(0 0 0 / 0.22);
  transition: border-color 170ms cubic-bezier(0.25, 1, 0.5, 1);
}

.song-thumb:hover {
  border-color: var(--brass);
}

.song-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.song-main {
  min-width: 0;
}

.song-heading a {
  min-width: 0;
  overflow: hidden;
  color: var(--vellum-ink);
  font-size: var(--text-lg);
  font-weight: 800;
  text-decoration: none;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: color 170ms cubic-bezier(0.25, 1, 0.5, 1);
}

.song-heading a:hover {
  color: var(--vellum-text-accent);
}

.runtime-single {
  color: var(--vellum-text);
  font-size: var(--text-base);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.song-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  gap: 0.45rem;
  min-width: 0;
}

.song-action-buttons {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.4rem;
}

.song-meta {
  gap: 0.35rem;
  margin-top: 0.5rem;
  color: var(--vellum-text-muted);
  font-size: var(--text-base);
}

.song-meta .avatar {
  width: 1.35rem;
  height: 1.35rem;
  font-size: var(--text-xs);
}

.song-meta strong {
  color: var(--vellum-text-strong);
}

.song-meta em {
  border-radius: 999px;
  background: oklch(0.45 0.16 24 / 0.18);
  color: var(--vellum-text-accent);
  font-style: normal;
  font-weight: 700;
  padding: 0.1rem 0.45rem;
}

/* Avatar + name stay on the same line even in a wrapping flex container */
.song-meta .proposer {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  white-space: nowrap;
}



.empty-state,
.notice,
.loading-stack {
  display: grid;
  min-height: 0;
  align-content: center;
  justify-items: start;
  border: 1px solid oklch(0.42 0.07 52);
  border-radius: 3px 11px 3px 12px;
  background:
    radial-gradient(ellipse at top left, oklch(0.96 0.08 84 / 0.26), transparent 14rem),
    radial-gradient(ellipse at 90% 100%, oklch(0.42 0.1 44 / 0.16), transparent 12rem),
    linear-gradient(180deg, var(--vellum), var(--vellum-deep));
  color: var(--vellum-ink);
  padding: 2rem;
  box-shadow:
    0 5px 0 oklch(0.07 0.015 24 / 0.45),
    inset 0 1px 0 oklch(1 0 0 / 0.28),
    inset 0 -16px 24px oklch(0.28 0.08 42 / 0.13);
}

.empty-state .section-note {
  color: var(--vellum-text);
}

.empty-state h3 {
  color: var(--vellum-ink);
}

.empty-state p {
  color: var(--vellum-text-strong);
}

.notice {
  gap: 0.8rem;
}

.notice.error {
  color: var(--danger);
}

.notice span {
  color: currentColor;
}

.notice button {
  background:
    radial-gradient(ellipse at 50% 0, oklch(0.92 0.13 84 / 0.34), transparent 1.2rem),
    linear-gradient(180deg, var(--brass), var(--brass-dark));
  color: var(--vellum-ink);
  text-shadow: 0 1px 0 oklch(1 0 0 / 0.15);
  padding: 0 1rem;
}

.skeleton {
  width: min(34rem, 100%);
  height: 4rem;
  border-radius: 12px;
  background: linear-gradient(
    90deg,
    oklch(0.18 0.03 36),
    oklch(0.28 0.055 44),
    oklch(0.18 0.03 36)
  );
  animation: shimmer 1.2s ease-in-out infinite;
}

.skeleton.wide {
  width: min(42rem, 100%);
}

.skeleton.short {
  width: min(24rem, 72%);
}

@keyframes shimmer {
  0%,
  100% {
    opacity: 0.48;
  }
  50% {
    opacity: 1;
  }
}

@media (max-width: 900px) {
  .app-shell {
    grid-template-columns: 1fr;
  }

  .hero-panel {
    position: relative;
    top: auto;
    min-height: auto;
    max-height: none;
    gap: 2rem;
  }

  .brand-lockup {
    width: 16rem;
    margin: 4.7rem auto 1.35rem;
  }

  .brand-lockup::before,
  .brand-lockup::after {
    margin: 0 .65rem;
  }

  .chain {
    --chain-scale: 0.94;
    top: -1.05rem;
  }

  .chain.left {
    left: calc(50% - 8rem + 0.6rem);
  }

  .chain.right {
    right: calc(50% - 8rem + 0.6rem);
  }

  h1 {
    max-width: 12ch;
  }

  .proposal-form,
  .song-row {
    grid-template-columns: 1fr;
  }

  .confirmation-panel,
  .confirmation-panel.duplicate-conflict {
    grid-template-columns: 1fr;
    align-items: stretch;
  }

  .confirmation-thumb {
    width: min(18rem, 100%);
    max-width: 100%;
  }

  .confirmation-actions {
    justify-content: flex-start;
  }

  .song-thumb {
    width: min(16rem, 100%);
    justify-self: center;
  }

  /* Let song titles wrap instead of truncating with ellipsis */
  .song-heading a {
    overflow: visible;
    text-overflow: clip;
    white-space: normal;
    overflow-wrap: break-word;
  }

  /* Song actions: runtime on the left, remove button on the right */
  .song-actions {
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
  }

  .song-action-buttons {
    flex-direction: row;
  }

  /* Song meta: flexbox that wraps naturally */
  .song-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
  }

  /* Avatar + name: always on the same line */
  .song-meta .proposer {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    white-space: nowrap;
  }
}

@media (max-width: 560px) {
  .app-shell {
    width: min(100% - 1rem, 1600px);
    padding: 0.5rem 0;
  }

  .hero-panel,
  .queue-panel {
    padding: 1rem;
  }

  .queue-panel {
    padding-left: 2.2rem;
  }

  .confirmation-panel {
    gap: 0.8rem;
    padding: 0.75rem;
  }

  .confirmation-actions {
    display: grid;
    grid-template-columns: 1fr;
  }

  .confirmation-actions .button {
    width: 100%;
  }

  .queue-panel::before {
    width: 1.5rem;
  }

  .ledger-clasp {
    left: 0.3rem;
    width: 0.85rem;
    height: 0.85rem;
  }

  .brand-lockup {
    width: 13rem;
    padding: 0.85rem 0.4rem 0.95rem;
  }

  .chain {
    --chain-scale: 0.84;
    top: -0.95rem;
  }

  .brand-mark {
    width: min(10rem, 65%);
  }

  h1 {
    font-size: var(--text-2xl);
  }

  .toolbar,
  .song-heading,
  .board-heading {
    align-items: flex-start;
    flex-direction: column;
  }

  .chain.left {
    left: calc(50% - 6.5rem + 0.6rem);
  }

  .chain.right {
    right: calc(50% - 6.5rem + 0.6rem);
  }
}

@media (max-width: 767px) {
  /* Between 560-767 the 2-column stat-board was too tight —
     single column gives the candle + tiles room to breathe.
     At <=560 the grid goes back to 2 columns so the two
     stat-tiles sit side-by-side (see override below). */
  .stat-board {
    grid-template-columns: 1fr;
  }
  .stat-board > :first-child {
    grid-column: auto;
  }
  .stat-board .wax-candle-meter {
    align-items: center;
    gap: 0.65rem;
  }
  .stat-board .wax-candle-meter .meter-svg--tankard {
    width: min(4.9rem, 24vw);
    max-width: 32%;
    flex: 0 0 auto;
  }
  .stat-board .wax-candle-meter .meter-text {
    min-width: 0;
  }
  .stat-board .wax-candle-meter .meter-text .meter-now {
    font-size: var(--text-lg);
    overflow-wrap: anywhere;
  }
  .stat-board .wax-candle-meter .meter-text .meter-sub,
  .stat-board .wax-candle-meter .meter-text .meter-warning {
    font-size: var(--text-xs);
    line-height: 1.2;
  }
}



@media (max-width: 360px) {
  /* Very narrow: tiles stack below the candle. */
  .stat-board {
    grid-template-columns: 1fr;
  }
  .stat-board > :first-child {
    grid-column: auto;
  }
}

/* ─── Mimic chest chomp animation ─────────────────────────────────── */

.mimic-stage {
  position: relative;
  display: flow-root;
  z-index: 1;
  isolation: isolate;
  perspective: 1000px;
  transform-style: preserve-3d;
}

.mimic-stage::before {
  position: absolute;
  inset: -0.7rem -1rem;
  z-index: 1;
  pointer-events: none;
  border-radius: 12px;
  background:
    radial-gradient(ellipse at 50% 50%,
      oklch(0.02 0.012 24 / 0.88) 0 12%,
      oklch(0.03 0.02 24 / 0.62) 26%,
      transparent 60%);
  content: "";
  opacity: 0;
  transform: scaleX(0.7) scaleY(0.32);
  filter: blur(10px);
  will-change: opacity, transform, filter;
}

/* Container: overlays the offering board only during the devour. */
.mimic {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 1;
  width: min(42rem, calc(100% + 5rem));
  height: calc(100% + 7rem);
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.86);
  transform-style: preserve-3d;
  will-change: transform, opacity;
}

.mimic-stage.chomping .mimic {
  opacity: 1;
}

/* ── Chest base (bottom jaw) ─────────────────────────────────────── */

.mimic-body {
  position: absolute;
  top: calc(50% + 0.15rem);
  left: 0;
  width: 100%;
  height: calc(50% + 3.2rem);
  /* Dark wood grain */
  background:
    repeating-linear-gradient(2deg,
      transparent 0, transparent 4px,
      oklch(0.15 0.04 40 / 0.4) 4px, oklch(0.15 0.04 40 / 0.4) 5px,
      transparent 5px, transparent 11px),
    repeating-linear-gradient(-1deg,
      transparent 0, transparent 8px,
      oklch(0.2 0.05 44 / 0.3) 8px, oklch(0.2 0.05 44 / 0.3) 9px,
      transparent 9px, transparent 18px),
    linear-gradient(180deg, var(--oak) 0%, var(--oak-dark) 100%);
  border: 3px solid oklch(0.1 0.02 35);
  border-top: none;
  border-radius: 0 0 8px 8px;
  box-shadow:
    inset 0 8px 16px oklch(1 0 0 / 0.04),
    inset 0 -12px 24px oklch(0 0 0 / 0.4),
    0 12px 32px oklch(0 0 0 / 0.6);
  overflow: visible;
}

/* Iron band: bottom */
.mimic-body::before {
  content: "";
  position: absolute;
  bottom: 8px;
  left: -3px;
  right: -3px;
  height: 7px;
  background: linear-gradient(180deg,
    oklch(0.12 0.008 45),
    oklch(0.35 0.018 52) 30%,
    oklch(0.25 0.012 48) 65%,
    oklch(0.1 0.006 42));
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.1),
    0 1px 3px oklch(0 0 0 / 0.4);
}

/* Iron band: top of base (mouth edge) */
.mimic-body::after {
  content: "";
  position: absolute;
  top: -1px;
  left: -3px;
  right: -3px;
  height: 7px;
  background: linear-gradient(180deg,
    oklch(0.12 0.008 45),
    oklch(0.35 0.018 52) 30%,
    oklch(0.25 0.012 48) 65%,
    oklch(0.1 0.006 42));
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.1),
    0 1px 3px oklch(0 0 0 / 0.4);
}

/* ── Eyes: menacing, glowing ──────────────────────────────────────── */

.mimic-eyes {
  position: absolute;
  top: 24%;
  left: 50%;
  width: 140px;
  margin-left: -70px;
  display: flex;
  justify-content: space-between;
  z-index: 5;
}

.mimic-eye {
  position: relative;
  border-radius: 50% 50% 45% 55% / 55% 55% 45% 45%;
  background:
    radial-gradient(circle at 45% 40%,
      oklch(0.98 0.2 90),
      oklch(0.9 0.22 86) 20%,
      oklch(0.6 0.2 80) 50%,
      oklch(0.35 0.15 75));
  box-shadow:
    0 0 14px oklch(0.85 0.22 88 / 0.7),
    0 0 28px oklch(0.85 0.22 88 / 0.35),
    inset 0 2px 4px oklch(0 0 0 / 0.4);
  overflow: hidden;
}

.mimic-eye.main {
  width: 32px;
  height: 36px;
}

.mimic-eye.side {
  width: 18px;
  height: 20px;
  margin-top: 12px;
}

/* Vertical slit pupil */
.mimic-eye::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 28%;
  height: 68%;
  margin: -34% 0 0 -14%;
  border-radius: 50%;
  background: oklch(0.02 0.01 20);
  box-shadow: 0 0 4px oklch(0 0 0 / 0.9);
}

/* ── Bottom jaw teeth ────────────────────────────────────────────── */

.mimic-jaw-bottom {
  position: absolute;
  top: calc(50% - 1.25rem);
  left: 0;
  width: 100%;
  height: 1.5rem;
  transform-origin: center top;
  transform: rotateX(0deg);
  will-change: transform;
  z-index: 4;
}

.mimic-jaw-bottom .jaw-shape {
  width: 100%;
  height: 100%;
  background: linear-gradient(180deg, var(--oak-dark), var(--oak) 50%);
  border-radius: 2px;
}

.mimic-jaw-bottom .teeth {
  position: absolute;
  top: -16px;
  left: 6%;
  right: 6%;
  height: 20px;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
}

.mimic-jaw-bottom .tooth {
  width: 11px;
  height: 18px;
  background: linear-gradient(0deg, var(--tooth), oklch(0.92 0.05 90));
  clip-path: polygon(20% 0%, 80% 0%, 100% 100%, 0% 100%);
  filter: drop-shadow(0 -2px 2px oklch(0 0 0 / 0.4));
}

/* Fangs: longer at the sides */
.mimic-jaw-bottom .tooth:nth-child(1),
.mimic-jaw-bottom .tooth:nth-child(7) {
  height: 26px;
  width: 13px;
}

/* ── Lid (top jaw): hinged at back, opens upward ──────────────────── */

.mimic-jaw-top {
  position: absolute;
  bottom: calc(50% + 0.15rem);
  left: -0.25rem;
  width: calc(100% + 0.5rem);
  height: clamp(4.75rem, 42%, 8.25rem);
  transform-origin: center bottom;
  transform: rotateX(0deg);
  will-change: transform;
  z-index: 6;
}

.mimic-jaw-top .jaw-shape {
  width: 100%;
  height: 100%;
  /* Slightly lighter oak for the lid */
  background:
    repeating-linear-gradient(3deg,
      transparent 0, transparent 5px,
      oklch(0.18 0.045 42 / 0.35) 5px, oklch(0.18 0.045 42 / 0.35) 6px,
      transparent 6px, transparent 13px),
    linear-gradient(180deg, var(--oak-light), var(--oak));
  border: 3px solid oklch(0.1 0.02 35);
  border-bottom: none;
  border-radius: 10px 10px 0 0;
  box-shadow:
    inset 0 8px 14px oklch(1 0 0 / 0.06),
    inset 0 -4px 8px oklch(0 0 0 / 0.2);
  position: relative;
}

/* Iron band across lid */
.mimic-jaw-top .jaw-shape::before {
  content: "";
  position: absolute;
  top: 14px;
  left: -3px;
  right: -3px;
  height: 7px;
  background: linear-gradient(180deg,
    oklch(0.12 0.008 45),
    oklch(0.35 0.018 52) 30%,
    oklch(0.25 0.012 48) 65%,
    oklch(0.1 0.006 42));
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.1),
    0 1px 3px oklch(0 0 0 / 0.4);
}

/* Lid top edge highlight */
.mimic-jaw-top .jaw-shape::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: linear-gradient(90deg,
    oklch(0.1 0.02 35),
    oklch(0.28 0.06 48 / 0.5) 30%,
    oklch(0.1 0.02 35));
}

/* Teeth along bottom edge of lid */
.mimic-jaw-top .teeth {
  position: absolute;
  bottom: -5px;
  left: 6%;
  right: 6%;
  height: 20px;
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
}

.mimic-jaw-top .tooth {
  width: 11px;
  height: 18px;
  background: linear-gradient(180deg, var(--tooth), oklch(0.92 0.05 90));
  clip-path: polygon(0% 0%, 100% 0%, 80% 100%, 20% 100%);
  filter: drop-shadow(0 2px 2px oklch(0 0 0 / 0.4));
}

.mimic-jaw-top .tooth:nth-child(1),
.mimic-jaw-top .tooth:nth-child(7) {
  height: 26px;
  width: 13px;
}

/* ── Tongue: forked, lolls out when mouth opens ───────────────────── */

.mimic-tongue {
  position: absolute;
  top: calc(50% - 1.1rem);
  left: 50%;
  width: 2.35rem;
  height: 2.35rem;
  margin-left: -1.175rem;
  border-radius: 40% 40% 50% 50% / 30% 30% 70% 70%;
  background:
    radial-gradient(ellipse at 50% 30%,
      oklch(0.7 0.22 20),
      var(--tongue) 50%,
      oklch(0.38 0.14 18));
  box-shadow:
    inset 0 5px 8px oklch(1 0 0 / 0.15),
    inset 0 -4px 8px oklch(0 0 0 / 0.35),
    0 4px 8px oklch(0 0 0 / 0.35);
  z-index: 3;
}

/* Forked tongue tip */
.mimic-tongue::after {
  content: "";
  position: absolute;
  bottom: -7px;
  left: 50%;
  width: 18px;
  height: 11px;
  margin-left: -9px;
  background: var(--tongue);
  clip-path: polygon(0% 0%, 35% 100%, 50% 60%, 65% 100%, 100% 0%);
}

/* ── Lock on front of chest ──────────────────────────────────────── */

.mimic-lock {
  position: absolute;
  top: calc(50% + 2.3rem);
  left: 50%;
  width: 26px;
  height: 30px;
  margin-left: -13px;
  z-index: 7;
}

/* Lock hasp (U-shape at top) */
.mimic-lock::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: 18px;
  height: 16px;
  margin-left: -9px;
  border: 3px solid var(--brass);
  border-bottom: none;
  border-radius: 9px 9px 0 0;
  box-shadow: 0 -1px 5px oklch(0.68 0.13 78 / 0.4);
}

/* Lock body */
.mimic-lock::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 22px;
  height: 18px;
  margin-left: -11px;
  border-radius: 3px;
  background:
    radial-gradient(circle at 40% 35%, var(--brass-bright), var(--brass) 55%, var(--brass-dark));
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.3),
    inset 0 -2px 3px oklch(0 0 0 / 0.35),
    0 2px 5px oklch(0 0 0 / 0.4);
}

/* ── Hinges at back of lid ───────────────────────────────────────── */

.mimic-hinge {
  position: absolute;
  bottom: calc(50% - 0.05rem);
  z-index: 1;
}

.mimic-hinge.left {
  left: 18px;
}

.mimic-hinge.right {
  right: 18px;
}

.mimic-hinge::before {
  content: "";
  display: block;
  width: 16px;
  height: 20px;
  border-radius: 3px;
  background:
    linear-gradient(90deg,
      oklch(0.1 0.006 42),
      oklch(0.3 0.015 50) 40%,
      oklch(0.2 0.01 46));
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.1),
    0 2px 4px oklch(0 0 0 / 0.5);
}

/* ── Animation keyframes ─────────────────────────────────────────── */

.mimic-stage.chomping .mimic {
  animation: mimic-devour 1.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.mimic-stage.chomping {
  animation: mimic-stage-layer 1.8s step-end forwards;
}

.mimic-stage.chomping::before {
  animation: mimic-mouth-shadow 1.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.mimic-stage.chomping .mimic-body {
  animation: mimic-body-devour 1.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.mimic-stage.chomping .mimic-jaw-top {
  animation: jaw-devour-top 1.8s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

.mimic-stage.chomping .mimic-jaw-bottom {
  animation: jaw-devour-bottom 1.8s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

.mimic-stage.chomping .mimic-tongue {
  animation: tongue-devour 1.8s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

.mimic-stage.chomping .mimic-eye {
  animation: mimic-eye-flare 1.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.mimic-stage.chomping .mimic-jaw-top .tooth,
.mimic-stage.chomping .mimic-jaw-bottom .tooth {
  animation: tooth-bite 1.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.mimic-stage.chomping .offering-board {
  transform-origin: 50% 54%;
  will-change: transform, opacity, filter, clip-path;
  animation: board-devoured 1.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

@keyframes mimic-stage-layer {
  0%, 13% {
    z-index: 1;
  }
  14%, 74% {
    z-index: 5;
  }
  75%, 100% {
    z-index: 1;
  }
}

@keyframes mimic-devour {
  0% {
    z-index: 1;
    opacity: 0;
    transform: translate(-50%, -50%) translateY(4.5rem) rotateX(-10deg) scale(0.76);
  }
  10% {
    opacity: 0.42;
  }
  14% {
    z-index: 4;
    opacity: 0.72;
  }
  20% {
    opacity: 1;
  }
  24% {
    transform: translate(-50%, -50%) translateY(1.4rem) rotateX(-4deg) scale(0.9, 0.82);
  }
  38% {
    z-index: 4;
    opacity: 1;
    transform: translate(-50%, -50%) rotateX(0deg) scale(1.03, 1.09);
  }
  47% {
    z-index: 4;
    transform: translate(-50%, -50%) translateY(-0.3rem) rotateX(5deg) scale(1.08, 0.94);
  }
  56% {
    transform: translate(-50%, -50%) translateY(0.15rem) rotateX(0deg) scale(0.98, 1.03);
  }
  72% {
    z-index: 4;
    opacity: 1;
    transform: translate(-50%, -50%) translateY(0.55rem) scale(0.92, 0.98);
  }
  100% {
    z-index: 1;
    opacity: 0;
    transform: translate(-50%, -50%) translateY(2.4rem) rotateX(8deg) scale(0.72, 0.82);
  }
}

@keyframes mimic-mouth-shadow {
  0%, 18% {
    z-index: 3;
    opacity: 0;
    transform: scaleX(0.62) scaleY(0.2);
    filter: blur(12px);
  }
  34% {
    z-index: 3;
    opacity: 0.9;
    transform: scaleX(1.12) scaleY(1.06);
    filter: blur(7px);
  }
  48% {
    z-index: 3;
    opacity: 1;
    transform: scaleX(0.7) scaleY(0.18);
    filter: blur(4px);
  }
  70% {
    z-index: 3;
    opacity: 0.55;
    transform: scaleX(0.28) scaleY(0.12);
    filter: blur(9px);
  }
  100% {
    z-index: 1;
    opacity: 0;
    transform: scaleX(0.18) scaleY(0.08);
    filter: blur(12px);
  }
}

@keyframes mimic-body-devour {
  0%, 20% {
    transform: translateY(3.8rem) scaleY(0.72);
  }
  38% {
    transform: translateY(calc(42% + 1.6rem)) scaleY(1.12);
  }
  47% {
    transform: translateY(-0.9rem) scaleY(0.92);
  }
  55% {
    transform: translateY(0.25rem) scaleY(1.06);
  }
  72% {
    transform: translateY(0.65rem) scaleY(0.96);
  }
  100% {
    transform: translateY(2.3rem) scaleY(0.78);
  }
}

@keyframes jaw-devour-top {
  0%, 20% {
    transform: translateY(3.1rem) rotateX(12deg) scaleY(0.78);
  }
  32% {
    transform: translateY(calc(-45% - 1.3rem)) rotateX(-46deg) scaleX(1.04) scaleY(1.22);
  }
  40% {
    transform: translateY(calc(-50% - 1.7rem)) rotateX(-58deg) scaleX(1.08) scaleY(1.28);
  }
  48% {
    transform: translateY(0.6rem) rotateX(13deg) scaleX(0.96) scaleY(0.86);
  }
  56% {
    transform: translateY(-0.22rem) rotateX(-4deg) scaleX(1.01) scaleY(1.02);
  }
  68%, 100% {
    transform: translateY(0) rotateX(0deg) scale(1);
  }
}

@keyframes jaw-devour-bottom {
  0%, 20% {
    transform: translateY(3.2rem) rotateX(-8deg) scaleY(0.72);
  }
  32% {
    transform: translateY(calc(42% + 1rem)) rotateX(22deg) scaleX(1.04) scaleY(1.18);
  }
  40% {
    transform: translateY(calc(50% + 1.35rem)) rotateX(31deg) scaleX(1.08) scaleY(1.24);
  }
  48% {
    transform: translateY(-0.4rem) rotateX(-12deg) scaleX(0.95) scaleY(0.82);
  }
  56% {
    transform: translateY(0.2rem) rotateX(4deg) scaleX(1.02) scaleY(1.04);
  }
  68%, 100% {
    transform: translateY(0) rotateX(0deg) scale(1);
  }
}

@keyframes tongue-devour {
  0%, 20% {
    transform: translateY(1.2rem) scaleX(0.7) scaleY(0.22);
    opacity: 0;
  }
  34% {
    transform: translateY(-1.4rem) scaleX(1.18) scaleY(2.7);
    opacity: 1;
  }
  44% {
    transform: translateY(0.6rem) scaleX(0.62) scaleY(0.25);
    opacity: 0.5;
  }
  58%, 100% {
    transform: translateY(1.1rem) scaleX(0.7) scaleY(0.18);
    opacity: 0;
  }
}

@keyframes mimic-eye-flare {
  0%, 22% {
    transform: scaleY(0.58);
    filter: brightness(0.8);
  }
  36% {
    transform: scaleY(1.18) scaleX(1.08);
    filter: brightness(1.45) saturate(1.2);
  }
  50% {
    transform: scaleY(0.38) scaleX(1.2);
    filter: brightness(1.8) saturate(1.35);
  }
  72%, 100% {
    transform: scaleY(0.72);
    filter: brightness(0.9);
  }
}

@keyframes tooth-bite {
  0%, 34% {
    transform: translateY(0) scaleY(1);
  }
  48% {
    transform: translateY(0.2rem) scaleY(1.24);
  }
  56% {
    transform: translateY(-0.05rem) scaleY(0.94);
  }
  68%, 100% {
    transform: translateY(0) scaleY(1);
  }
}

@keyframes board-devoured {
  0%, 20% {
    transform: translateY(0) scale(1);
    clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
    filter: brightness(1);
    opacity: 1;
  }
  30% {
    transform: translateY(-0.35rem) rotate(-0.6deg) scale(1.015, 0.98);
    clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
    filter: brightness(0.94) saturate(1.04);
    opacity: 1;
  }
  40% {
    transform: translateY(0.15rem) rotate(0.7deg) scaleX(1.04) scaleY(0.92);
    clip-path: polygon(2% 0, 98% 0, 100% 100%, 0 100%);
    filter: brightness(0.72) saturate(1.1);
    opacity: 0.96;
  }
  48% {
    transform: translateY(0.5rem) rotate(-0.4deg) scaleX(0.68) scaleY(0.48);
    clip-path: polygon(12% 10%, 88% 4%, 82% 93%, 18% 100%);
    filter: brightness(0.52) saturate(1.2) blur(0.2px);
    opacity: 0.82;
  }
  58% {
    transform: translateY(1.7rem) rotate(1.5deg) scaleX(0.28) scaleY(0.22);
    clip-path: polygon(38% 0, 64% 10%, 58% 100%, 42% 90%);
    filter: brightness(0.34) saturate(1.25) blur(0.45px);
    opacity: 0.46;
  }
  70% {
    transform: translateY(2.4rem) rotate(-1deg) scaleX(0.06) scaleY(0.08);
    clip-path: polygon(48% 0, 53% 12%, 52% 100%, 47% 90%);
    filter: brightness(0.22) blur(0.7px);
    opacity: 0;
  }
  100% {
    transform: translateY(2.4rem) scale(0);
    clip-path: polygon(50% 0, 50% 0, 50% 100%, 50% 100%);
    filter: brightness(0.2) blur(0.7px);
    opacity: 0;
  }
}

/* Reduced motion: instant swap */
@media (prefers-reduced-motion: reduce) {
  .mimic-stage.chomping,
  .mimic-stage.chomping::before,
  .mimic-stage.chomping .mimic,
  .mimic-stage.chomping .mimic-body,
  .mimic-stage.chomping .mimic-jaw-top,
  .mimic-stage.chomping .mimic-jaw-bottom,
  .mimic-stage.chomping .mimic-tongue,
  .mimic-stage.chomping .mimic-eye,
  .mimic-stage.chomping .mimic-jaw-top .tooth,
  .mimic-stage.chomping .mimic-jaw-bottom .tooth,
  .mimic-stage.chomping .offering-board {
    animation: none !important;
  }

  .mimic-stage.chomping .offering-board {
    opacity: 0 !important;
  }

  .mimic-stage.chomping .mimic {
    opacity: 0 !important;
  }

  .mimic-stage.chomping {
    z-index: 1 !important;
  }
}

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

/* ============================================================
   Runtime meter — wax candle (desktop) / tankard (mobile)
   ============================================================
   The component sets these inline custom properties on the root:
     --meter-fill    0..=1    fill level (0 empty, 1 full)
     --meter-warning  0 or 1   1 when past the 3h safe point
     --meter-phase    idle|active   visual state
     --flame-scale    unitless multiplier for flame size (default 1)
     --flame-flicker-period    CSS time for one flicker cycle
     --flame-tint    "warm" | "warn"   flame color preset

   --flame-scale is set by the component based on the candle's
   remaining wax (low candle => smaller flame). --flame-flicker-period
   shortens as wax runs out (a guttering flame flickers faster).
   --flame-tint swaps the flame fill when the warning state is on.

   The same SVG renders on both phases; only the wax color, the
   flame visibility, and the rune visibility differ. Mobile
   (@media max-width: 767px) widens the silhouette so the same
   shape reads as a tankard of ale rather than a candle — a
   visual swap, not a new component.
*/

.wax-candle-meter {
  --meter-fill: 0;
  --meter-warning: 0;
  --meter-phase: idle;
  --flame-scale: 1;
  --flame-flicker-period: 1.4s;
  --flame-tint: warm;
  --candle-wax: oklch(0.88 0.06 80);
  --candle-wax-shadow: oklch(0.7 0.08 70);
  --candle-flame: oklch(0.85 0.18 60);
  --candle-warn-wax: oklch(0.55 0.22 22);
  --candle-warn-flame: oklch(0.7 0.3 145);
  --candle-warn-glow: oklch(0.6 0.25 22);
  display: flex;
  align-items: flex-end;
  gap: 0.6rem;
  width: 100%;
  font-variant-numeric: tabular-nums;
}

.wax-candle-meter .meter-svg {
  /* The candle's intrinsic ratio. The candle SVG is 56x140; the
     tankard SVG (mobile only) is full container width and
     auto-height. */
  width: 56px;
  height: 140px;
  flex: 0 0 auto;
  display: block;
}

/* The tankard fills the available width and keeps its own
   intentionally taller stein ratio from the SVG viewBox. */
.wax-candle-meter .meter-svg--tankard {
  width: 100%;
  height: auto;
  aspect-ratio: 120 / 88;
}

/* Candle stack: four separate SVG layers share the same
   80x200 viewBox and are overlaid in one fixed-size box.
   This keeps each job dumb and isolated: wax clips itself,
   drips are clipped to the current wax area, pooled wax stays
   at the base, and the flame/wick layer simply follows the
   wax top. */
.wax-candle-meter .candle-stack {
  position: relative;
}

.wax-candle-meter .candle-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

.wax-candle-meter .candle-layer--body {
  position: relative;
}

/* The flame is intentionally NOT a full-height overlay. It is
   a 40-unit-tall SVG rendered at 28px tall (same 0.7 scale as
   the candle stack). Its bottom edge is positioned exactly at
   the current wax surface: full-wax top is 28px, wax travel is
   105px, flame height is 28px. */
.wax-candle-meter .candle-layer--flame {
  top: calc((28px + (1 - var(--meter-fill)) * 105px) - 28px);
  height: 28px;
  transition: top 360ms cubic-bezier(0.22, 1, 0.36, 1);
}

.wax-candle-meter .meter-text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.wax-candle-meter .meter-text .meter-now {
  font-size: var(--text-xl);
  font-weight: 800;
  line-height: 1;
  color: var(--tooth);
}

.wax-candle-meter .meter-text .meter-sub {
  font-size: var(--text-sm);
  color: var(--dim);
  font-weight: 600;
}

.wax-candle-meter .meter-text .meter-warning {
  margin-top: 0.35rem;
  color: var(--candle-warn-glow);
  font-weight: 700;
  font-size: var(--text-sm);
  opacity: calc(var(--meter-warning));
  transition: opacity 240ms ease;
}

/* Candle wax body: a simple vertical bar clipped from the
   top. At fill=0 the inset is 100% (no wax visible); at
   fill=1 the inset is 0% (wax fills the full candle). */
.wax-candle-meter .candle-wax {
  fill: var(--candle-wax);
  filter: drop-shadow(0 1px 0 var(--candle-wax-shadow));
  clip-path: inset(calc((1 - var(--meter-fill)) * 100%) 0 0 0);
  transition: clip-path 360ms cubic-bezier(0.22, 1, 0.36, 1);
}

.wax-candle-meter .candle-shell {
  clip-path: inset(calc((1 - var(--meter-fill)) * 100%) 0 0 0);
  transition: clip-path 360ms cubic-bezier(0.22, 1, 0.36, 1);
}

.wax-candle-meter .candle-wick {
  stroke: oklch(0.16 0.04 40);
  stroke-width: 1.6;
  stroke-linecap: round;
}

/* Flame internals no longer do layout. The separate flame SVG
   layer is positioned with CSS; this group only exists as a
   styling hook for the wick/flame/spark/rune/vapor. */
.wax-candle-meter .candle-top {
  transform: none;
}

.wax-candle-meter .candle-flame {
  fill: var(--candle-flame);
  opacity: 0;
  transform-origin: 50% 100%;
  transition: opacity 240ms ease;
}

/* Active phase: show the flame and run the flicker. Idle hides
   the flame (the candle is unlit, just a wax reservoir). The
   flame size and flicker speed both scale with --flame-scale /
   --flame-flicker-period so the component can drive a low-wax
   flame to be smaller and more nervous. The base scale of 1
   becomes whatever --flame-scale resolves to (component sets it
   from candle fill level). */
.wax-candle-meter[data-phase="active"] .candle-flame {
  opacity: 1;
  transform: scale(var(--flame-scale));
  animation: flame-flicker var(--flame-flicker-period) ease-in-out infinite,
             flame-gust 9s ease-in-out infinite;
}

/* Warning tint: swap the flame fill to the sickly green
   preset. We keep the flicker going because a dying flame
   still flickers, just at the wrong color. */
.wax-candle-meter[data-warning="1"][data-phase="active"] .candle-flame {
  fill: var(--candle-warn-flame);
}

/* Snuffed: the queue is fully consumed in the active phase. The
   flame dips and gutters, then fades to a wisp of smoke. After
   the snuff completes the flame stays invisible until the next
   session start ignites it again. The snuff animation overrides
   the flicker/gust so the flame doesn't keep going while it
   dies. */
.wax-candle-meter[data-phase="active"][data-snuffer="1"] .candle-flame {
  animation: flame-snuff 1.2s cubic-bezier(0.55, 0.06, 0.68, 0.19) forwards;
}

/* Drip interaction: when a drip path fires (data-drip-75 etc),
   the flame dips briefly — a tiny gust from the falling wax
   disturbing the air around the wick. Reads as "the flame
   winced", not a snuff. */
.wax-candle-meter[data-phase="active"][data-drip-75="1"] .candle-flame,
.wax-candle-meter[data-phase="active"][data-drip-50="1"] .candle-flame,
.wax-candle-meter[data-phase="active"][data-drip-25="1"] .candle-flame {
  animation: flame-dip 1.6s cubic-bezier(0.55, 0.06, 0.68, 0.19),
             flame-flicker var(--flame-flicker-period) ease-in-out infinite;
}

@keyframes flame-snuff {
  0% {
    opacity: 1;
    transform: scale(var(--flame-scale)) scaleY(1) translateY(0);
  }
  30% {
    opacity: 0.85;
    transform: scale(var(--flame-scale)) scaleY(0.7) translateY(2px);
  }
  60% {
    opacity: 0.45;
    transform: scale(var(--flame-scale)) scaleY(0.35) translateY(6px);
  }
  100% {
    opacity: 0;
    transform: scale(var(--flame-scale)) scaleY(0.05) translateY(12px);
  }
}

/* Drip dip: the flame shrinks briefly then springs back. The
   keyframes are co-prime with the flicker so they don't
   synchronize (a real flame looks chaotic, not choreographed).
   After the dip the flicker resumes from wherever the flame
   was. */
@keyframes flame-dip {
  0% {
    opacity: 1;
    transform: scale(var(--flame-scale)) scaleY(1) translateX(0);
  }
  18% {
    opacity: 0.85;
    transform: scale(var(--flame-scale)) scaleY(0.7) translateX(2px);
  }
  40% {
    opacity: 0.95;
    transform: scale(calc(var(--flame-scale) * 1.05)) scaleY(1.1) translateX(-1px);
  }
  100% {
    opacity: 1;
    transform: scale(var(--flame-scale)) scaleY(1) translateX(0);
  }
}

/* Wind gust: rare, asymmetric skew of the flame. Runs at a
   9s period so it appears every few cycles, not on every
   flicker. The skew is small (~4deg) so it reads as
   'a draft passed', not 'the flame is dying'. */
@keyframes flame-gust {
  0%, 78%, 100% {
    transform: scale(var(--flame-scale)) skewX(0deg);
  }
  83% {
    transform: scale(calc(var(--flame-scale) * 1.02)) skewX(-4deg);
  }
  88% {
    transform: scale(calc(var(--flame-scale) * 0.96)) skewX(3deg);
  }
  93% {
    transform: scale(var(--flame-scale)) skewX(-1deg);
  }
}

/* Warning: red wax, sickly green flame (active), pulsing glow. */
.wax-candle-meter[data-warning="1"] .candle-wax {
  fill: var(--candle-warn-wax);
  animation: warning-pulse 2s ease-in-out infinite;
}

.wax-candle-meter[data-warning="1"][data-phase="active"] .candle-flame {
  fill: var(--candle-warn-flame);
}

.wax-candle-meter .candle-rune {
  fill: var(--candle-warn-glow);
  opacity: calc(var(--meter-warning));
  transition: opacity 240ms ease;
}

.wax-candle-meter[data-warning="1"] .candle-rune {
  animation: warning-pulse 2s ease-in-out infinite;
}

/* ===== Drips =====
   The drips live in their own SVG layer. That whole layer is
   clipped to the current wax rectangle, so a drip can never
   appear above the remaining wax body (it must have wax to cling
   to). The wax rectangle spans y=40..190 in a 200-unit viewBox,
   so the dynamic top clip is 20% + (1 - fill) * 75%; the bottom
   clip is 5%. */
.wax-candle-meter .candle-layer--drips {
  clip-path: inset(calc(20% + (1 - var(--meter-fill)) * 75%) 0 5% 0);
  transition: clip-path 360ms cubic-bezier(0.22, 1, 0.36, 1);
}
.wax-candle-meter .candle-drip {
  fill: var(--candle-wax);
  opacity: 0;
  transform: translateY(0);
  transform-origin: 50% 50%;
}

.wax-candle-meter[data-drip-75="1"] .candle-drip--75,
.wax-candle-meter[data-drip-50="1"] .candle-drip--50,
.wax-candle-meter[data-drip-25="1"] .candle-drip--25 {
  opacity: 1;
  animation: drip-fall 1.6s cubic-bezier(0.55, 0.06, 0.68, 0.19) forwards;
}

/* Separate pooled wax layer. Always visible and not clipped
   by the wax body or drip layer. */
.wax-candle-meter .candle-pool {
  fill: var(--candle-wax);
  opacity: 1;
  filter: drop-shadow(0 1px 0 var(--candle-wax-shadow));
}

.wax-candle-meter[data-warning="1"] .candle-drip,
.wax-candle-meter[data-warning="1"] .candle-pool {
  /* Red wax during the warning state, per PLAN.md §6. */
  fill: var(--candle-warn-wax);
}

@keyframes drip-fall {
  0% {
    transform: translate(0, 0);
    opacity: 1;
  }
  60% {
    transform: translate(8px, 80px);
    opacity: 1;
  }
  85% {
    transform: translate(0, 130px);
    opacity: 0.9;
  }
  100% {
    transform: translate(0, 130px);
    opacity: 0;
  }
}

/* ===== Wax settle =====
   When a new song arrives, the wax body wobbles briefly and a
   wisp of "scent" vapor rises from the wick. Triggered by
   [data-settle="1"] which the component sets for 250ms after a
   level increase, then unsets. The class is on a child element
   (not the root) because the root already has data-phase and
   data-warning for layout decisions. */
.wax-candle-meter .candle-wax--settling {
  animation: wax-settle 250ms cubic-bezier(0.36, 0.07, 0.19, 0.97);
  transform-origin: 50% 100%;
}

.wax-candle-meter .candle-vapor {
  fill: oklch(0.85 0.04 80 / 0.5);
  opacity: 0;
  transform: translateY(0);
}

.wax-candle-meter[data-settle="1"] .candle-vapor {
  animation: vapor-rise 1.4s ease-out forwards;
}

@keyframes wax-settle {
  0% {
    transform: scaleX(1) scaleY(1);
  }
  30% {
    transform: scaleX(1.04) scaleY(0.985);
  }
  60% {
    transform: scaleX(0.985) scaleY(1.005);
  }
  100% {
    transform: scaleX(1) scaleY(1);
  }
}

@keyframes vapor-rise {
  0% {
    transform: translateY(0);
    opacity: 0.5;
  }
  100% {
    transform: translateY(-26px);
    opacity: 0;
  }
}

/* ===== Ignition =====
   Runs once on the idle→active transition. Sequence: spark at
   the wick (visible briefly), then the flame scales from 0 to
   full over 600ms, while the wax recedes briefly from the top
   to suggest it was just lit. Triggered by [data-igniting="1"]
   for the 600ms duration. */
.wax-candle-meter .candle-spark {
  fill: oklch(0.95 0.18 90);
  opacity: 0;
}

.wax-candle-meter[data-igniting="1"] .candle-spark {
  animation: spark-burst 600ms ease-out forwards;
}

.wax-candle-meter[data-igniting="1"] .candle-flame {
  /* Override the steady-state flicker during ignition with a
     scale-up from 0. */
  animation: ignition-flame 600ms ease-out forwards,
             flame-flicker 1.4s ease-in-out 600ms infinite;
  opacity: 1;
}

.wax-candle-meter[data-igniting="1"] .candle-wax {
  /* Brief recession: the clip-path inset goes from 0% (full)
     to 2% (tiny gap at top) and back. We override the
     fill-based clip with an explicit inset that is briefly
     larger. */
  animation: ignition-wax-recede 600ms ease-out;
}

@keyframes spark-burst {
  0% {
    opacity: 0;
    transform: scale(0.3);
  }
  20% {
    opacity: 1;
    transform: scale(1.6);
  }
  50% {
    opacity: 0.8;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(0.6);
  }
}

@keyframes ignition-flame {
  0% {
    transform: scaleY(0) scaleX(0.5);
    opacity: 0;
  }
  40% {
    transform: scaleY(0.6) scaleX(0.9);
    opacity: 0.8;
  }
  100% {
    transform: scaleY(1) scaleX(1);
    opacity: 1;
  }
}

@keyframes ignition-wax-recede {
  0%, 100% {
    /* The fill-based clip is on this element via the
       .candle-wax base rule; the ignition animation
       rides on top via filter, not via the clip itself,
       so the steady-state fill math is preserved. */
    filter: drop-shadow(0 0 0 transparent);
  }
  40% {
    filter: drop-shadow(0 -2px 4px oklch(0.95 0.15 80 / 0.5));
  }
}

/* ===== Tankard (mobile) =====
   The tankard SVG is rendered on every viewport; the @media
   rules below swap which one is visible. The candle SVG is
   visible by default (desktop); on mobile (<=767px) the
   tankard shows instead. Both consume the same --meter-fill
   and --meter-warning vars. */
.wax-candle-meter .meter-svg--tankard {
  display: none;
}

@media (max-width: 767px) {
  .wax-candle-meter .meter-svg--candle {
    display: none;
  }
  .wax-candle-meter .meter-svg--tankard {
    display: block;
  }
}

.wax-candle-meter .tankard-ale {
  /* The ale level: clip-path inset driven by --meter-fill, same
     pattern as the candle wax. At fill=0 the inset is 100% (no
     ale); at fill=1 the inset is 0% (full to the foam line). */
  --ale-color: oklch(0.78 0.14 75);
  fill: var(--ale-color);
  clip-path: inset(calc((1 - var(--meter-fill)) * 100%) 0 0 0);
  transition: clip-path 360ms cubic-bezier(0.22, 1, 0.36, 1);
}

/* Tankard foam: the foam follows the ale surface as the
   tankard drains. The ale rect is 50 user units tall, so
   the foam translates by (1 - fill) * 50 in user units. The
   transition matches the ale clip-path so the foam stays
   glued to the surface during the 360ms easing. */
.wax-candle-meter .tankard-top {
  transform: translateY(calc((1 - var(--meter-fill)) * 50px));
  transition: transform 360ms cubic-bezier(0.22, 1, 0.36, 1);
}

.wax-candle-meter[data-warning="1"] .tankard-ale {
  --ale-color: oklch(0.55 0.22 22);
  animation: warning-pulse 2s ease-in-out infinite;
}

.wax-candle-meter .tankard-foam {
  fill: oklch(0.92 0.04 80);
  filter: drop-shadow(0 -1px 0 oklch(0.7 0.06 70));
}

.wax-candle-meter[data-warning="1"] .tankard-foam {
  fill: oklch(0.7 0.2 22);
}

.wax-candle-meter .tankard-ripple {
  fill: none;
  stroke: oklch(0.85 0.06 80 / 0.5);
  stroke-width: 1.2;
  opacity: 0;
  transform-origin: 50% 50%;
}

.wax-candle-meter[data-settle="1"] .tankard-ripple--1 {
  animation: tankard-ripple 800ms ease-out forwards;
}

.wax-candle-meter[data-settle="1"] .tankard-ripple--2 {
  animation: tankard-ripple 800ms ease-out 120ms forwards;
}

@keyframes tankard-ripple {
  0% {
    transform: scale(0.4);
    opacity: 0.7;
    stroke-width: 1.6;
  }
  100% {
    transform: scale(2.4);
    opacity: 0;
    stroke-width: 0.4;
  }
}

/* Mobile: the candle SVG is hidden and a separate tankard SVG
   shows. Both SVGs share the same flex container; only one is
   display:block at any viewport. */

/* Flicker: subtle brightness + scale wobble. The base scale is
   driven by --flame-scale on the element; we wobble around it
   with scaleY/scaleX deltas inside the keyframe. The flame also
   carries the parent transform from flame-gust during the
   9-second cycle; the flicker only changes the wobble. */
@keyframes flame-flicker {
  0%, 100% {
    opacity: 0.95;
  }
  25% {
    opacity: 1;
  }
  50% {
    opacity: 0.9;
  }
  75% {
    opacity: 0.95;
  }
}

/* Smaller-scale flicker variant: the flame wobbles more
   nervously when wax is low. We use scaleY instead of opacity
   alone so a low candle has a visibly twitchier flame, not a
   dimmer one. This keyframe is referenced from the component
   via --flame-flicker-key when --flame-scale < 0.5. */
@keyframes flame-flicker-nervous {
  0%, 100% {
    transform: scale(var(--flame-scale)) scaleY(1) scaleX(1);
    opacity: 0.9;
  }
  20% {
    transform: scale(var(--flame-scale)) scaleY(1.15) scaleX(0.92);
    opacity: 1;
  }
  40% {
    transform: scale(var(--flame-scale)) scaleY(0.9) scaleX(1.08);
    opacity: 0.8;
  }
  60% {
    transform: scale(var(--flame-scale)) scaleY(1.1) scaleX(0.95);
    opacity: 1;
  }
  80% {
    transform: scale(var(--flame-scale)) scaleY(0.92) scaleX(1.05);
    opacity: 0.85;
  }
}

@keyframes warning-pulse {
  0%, 100% {
    filter: drop-shadow(0 0 0 transparent);
  }
  50% {
    filter: drop-shadow(0 0 6px var(--candle-warn-glow));
  }
}

.session-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border: 1px solid;
}

.session-badge-active {
  background: oklch(0.32 0.08 145 / 0.25);
  border-color: oklch(0.5 0.12 145);
  color: oklch(0.85 0.13 145);
}

.session-badge-paused {
  background: oklch(0.32 0.1 80 / 0.25);
  border-color: oklch(0.5 0.12 80);
  color: oklch(0.88 0.13 80);
}

.admin-controls {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px dashed oklch(0.3 0.05 50);
}

.admin-button-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.admin-button {
  background:
    linear-gradient(180deg, oklch(0.21 0.04 36), oklch(0.13 0.025 30));
  color: oklch(0.82 0.06 65);
  border-color: oklch(0.32 0.06 50);
  padding: 0 1rem;
  min-height: 2.4rem;
  font-size: var(--text-sm);
}

.admin-button:hover:not(:disabled) {
  background:
    linear-gradient(180deg, oklch(0.27 0.05 36), oklch(0.18 0.03 30));
  color: oklch(0.92 0.07 70);
  border-color: oklch(0.42 0.08 50);
}

.admin-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.admin-button-stop {
  margin-left: auto;
}

.queue-section-heading {
  position: relative;
  z-index: 3;
  font-family: 'IM Fell English SC', 'IM Fell English', Georgia, serif;
  font-size: 1.05rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 1.25rem 0 0.5rem;
  border-bottom: 1px solid oklch(0.25 0.04 50);
  padding-bottom: 0.25rem;
}

.queue-section-empty {
  position: relative;
  z-index: 3;
  color: var(--dim);
  font-style: italic;
  padding: 0.75rem 0;
  margin: 0;
}

.tonights-sung {
  position: relative;
  z-index: 3;
  margin-top: 1.25rem;
  border-top: 1px dashed oklch(0.25 0.04 50);
  padding-top: 0.5rem;
}

.tonights-sung-hidden {
  display: none;
}

.tonights-sung-toggle {
  background: transparent;
  border: 0;
  color: var(--dim);
  font: inherit;
  font-family: 'IM Fell English SC', 'IM Fell English', Georgia, serif;
  font-size: 1rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.4rem 0.5rem;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  cursor: pointer;
  width: 100%;
  text-align: left;
}

.tonights-sung-toggle:hover {
  color: var(--tooth);
  background: oklch(1 0 0 / 0.04);
}

.tonights-sung-chevron {
  display: inline-block;
  font-size: 0.85em;
  transition: transform 220ms cubic-bezier(0.25, 1, 0.5, 1);
}

.tonights-sung-chevron[data-open="true"] {
  transform: rotate(90deg);
}

.tonights-sung-label {
  flex: 1;
}

.tonights-sung-count {
  background: oklch(0.25 0.05 50 / 0.4);
  color: var(--dim);
  font-family: inherit;
  font-size: 0.75rem;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  letter-spacing: 0;
  text-transform: none;
}

.tonights-sung-list {
  display: none;
  margin: 0.5rem 0 0;
  padding: 0;
  list-style: none;
}

.tonights-sung-list[data-open="true"] {
  display: block;
}

/* Step 6: close-the-tavern button + confirm dialog + past parties
   panel. The confirm flow is intentionally a small two-step
   interaction: click to reveal the type-CLOSE input, then a second
   click on Confirm (only enabled when the input matches) submits.
   The past parties panel is a flat list with one Restore button
   per row; the per-song archive viewer is a future enhancement. */

.close-tavern {
  margin-top: 1rem;
}

.close-tavern-actions {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.close-tavern-confirm {
  background:
    linear-gradient(180deg, oklch(0.21 0.04 36), oklch(0.13 0.025 30));
  border: 1px solid oklch(0.5 0.12 25);
  border-radius: 8px;
  padding: 0.85rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.close-tavern-warning {
  color: oklch(0.85 0.13 25);
  font-style: italic;
  margin: 0;
}

.close-tavern-label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  color: var(--dim);
  font-size: var(--text-sm);
}

.close-tavern-input {
  background: oklch(0.1 0.02 30);
  border: 1px solid oklch(0.3 0.05 50);
  border-radius: 4px;
  color: var(--tooth);
  padding: 0.4rem 0.6rem;
  font-family: monospace;
  letter-spacing: 0.06em;
}

.close-tavern-error {
  color: oklch(0.85 0.13 25);
  margin: 0;
}

.close-tavern-buttons {
  display: flex;
  gap: 0.5rem;
  justify-content: flex-end;
}

.past-parties {
  margin-top: 1.5rem;
}

.past-parties-list {
  list-style: none;
  padding: 0;
  margin: 0.5rem 0 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.past-party-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.6rem 0.8rem;
  border: 1px solid oklch(0.25 0.05 50);
  border-radius: 6px;
  background: oklch(0.15 0.03 30 / 0.4);
}

.past-party-meta {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}

.past-party-meta strong {
  color: var(--tooth);
  font-family: 'IM Fell English SC', 'IM Fell English', Georgia, serif;
  font-size: 1rem;
  font-weight: 400;
  letter-spacing: 0.04em;
}

.past-party-sub {
  color: var(--dim);
  font-size: var(--text-xs);
}
