/* ---------------------------------------------------------------------------
   TWICE Content Archive — shared stylesheet.

   Every colour is a token on :root so the dark-mode block below only has to
   restate the handful that actually change. Pages set data-accent on <html>
   to tint themselves per section (discography, time-to-twice, …) without
   needing their own stylesheet.
--------------------------------------------------------------------------- */

:root {
  --peach:      #ff9d76;
  --candy:      #ff6fa5;
  --grape:      #8b6fd1;
  --mint:       #4ec9b0;

  --accent:     var(--peach);
  --accent-2:   var(--candy);
  --accent-ink: var(--accent);   /* accent used as text; pages with a pale accent point it at --accent-2 */

  --bg:         #fff7f3;
  --surface:    #ffffff;
  --surface-2:  #fff1ea;
  --line:       #f0ddd4;
  --line-soft:  #f7e8e1;

  --text:       #33242a;
  --text-soft:  #7d6a70;
  --text-faint: #a99a9f;

  --ok:         #2e9e6b;
  --warn:       #c97a1e;

  --radius:     14px;
  --radius-sm:  9px;
  --shadow:     0 1px 2px rgba(80,40,50,.06), 0 6px 20px rgba(80,40,50,.07);
  --shadow-lg:  0 10px 50px rgba(60,25,40,.22);

  --font: "Pretendard", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
}

/* Section tints. Each page sets one on <html>. */
:root[data-accent="discography"] { --accent: var(--candy);  --accent-2: var(--peach); }
:root[data-accent="shows"]       { --accent: var(--grape);  --accent-2: var(--candy); }
/* Updates through TV Variety each wear one member's colour, in menu order,
   fading into a deeper shade of it (the member hex matches memberColors in data/). */
:root[data-accent="updates"]     { --accent: #49c0ec; --accent-2: #1f7fb8; } /* Nayeon */
:root[data-accent="covers"]      { --accent: #a3cc54; --accent-2: #5e8f24; } /* Jeongyeon */
:root[data-accent="live"]        { --accent: #e67ea3; --accent-2: #c2457e; } /* Momo */
:root[data-accent="vlogs"]       { --accent: #8c79b4; --accent-2: #5b4596; } /* Sana */
:root[data-accent="twicetv"]     { --accent: #f9cc85; --accent-2: #e0913a; } /* Jihyo */
:root[data-accent="variety"]     { --accent: #71c7d4; --accent-2: #2a8fa0; } /* Mina */
:root:is([data-accent="covers"], [data-accent="live"], [data-accent="vlogs"],
      [data-accent="twicetv"], [data-accent="variety"], [data-accent="updates"]) { --accent-ink: var(--accent-2); }
/* …but on the dark background it's the bright member colour that reads. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --accent-ink: var(--accent); }
}
:root[data-theme="dark"] { --accent-ink: var(--accent); }
/* Jihyo's apricot and Mina's aqua are too pale for white text on a selected chip. */
:root:is([data-accent="twicetv"], [data-accent="variety"]) .chip.on { color: #2a1b22; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:        #171114;
    --surface:   #211820;
    --surface-2: #2b2029;
    --line:      #3a2c36;
    --line-soft: #312430;
    --text:      #f6ecf1;
    --text-soft: #bda9b5;
    --text-faint:#8e7a86;
    --ok:        #5fd39b;
    --warn:      #e0a457;
    --shadow:    0 1px 2px rgba(0,0,0,.35), 0 6px 20px rgba(0,0,0,.35);
    --shadow-lg: 0 10px 50px rgba(0,0,0,.6);
  }
}
:root[data-theme="dark"] {
  --bg:#171114; --surface:#211820; --surface-2:#2b2029; --line:#3a2c36;
  --line-soft:#312430; --text:#f6ecf1; --text-soft:#bda9b5; --text-faint:#8e7a86;
  --ok:#5fd39b; --warn:#e0a457;
  --shadow:0 1px 2px rgba(0,0,0,.35), 0 6px 20px rgba(0,0,0,.35);
  --shadow-lg:0 10px 50px rgba(0,0,0,.6);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  line-height: 1.5;
}

a { color: inherit; }

.wrap { max-width: 1120px; margin: 0 auto; padding: 0 16px 80px; }

/* ---------- header ---------- */

.site-head { padding: 34px 0 22px; }

/* Site-wide notice while the archive is being filled in. Remove the <p> from
   each page when it's done. */
.wip-banner {
  margin: 14px 0 0; padding: 9px 14px;
  border: 1px solid color-mix(in srgb, #f0980d 45%, transparent);
  border-radius: 10px;
  background: color-mix(in srgb, #ffc224 14%, var(--surface));
  color: var(--text); font-size: 13px; line-height: 1.45;
}
.wip-banner b { color: #d9820a; }

/* Site navigation reads as a menu bar — plain links on a rule, the current
   page underlined — so it can't be mistaken for the filter pills below it. */
.site-nav {
  display: flex; flex-wrap: wrap; gap: 0 20px; align-items: center;
  margin-bottom: 26px;
  border-bottom: 1px solid var(--line);
}
.site-nav a {
  position: relative;
  text-decoration: none; font-size: 14px; font-weight: 600;
  color: var(--text-soft);
  padding: 11px 0;
}
.site-nav a:hover { color: var(--text); }
.site-nav a.on { color: var(--text); }
.site-nav a.on::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px;
  height: 3px; border-radius: 3px 3px 0 0;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
}

/* Light / dark toggle, pushed to the right end of the nav row. */
.theme-toggle {
  margin: 5px 0 5px auto;
  width: 36px; height: 36px; border-radius: 999px;
  display: inline-grid; place-items: center;
  font-size: 16px; line-height: 1; cursor: pointer;
  border: 1px solid var(--line); background: var(--surface);
  transition: border-color .15s ease, transform .15s ease;
}
.theme-toggle:hover { border-color: var(--accent); transform: rotate(-12deg); }
.theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.site-head h1 {
  margin: 0 0 6px;
  font-size: clamp(26px, 5vw, 40px);
  letter-spacing: -.02em;
  background: linear-gradient(100deg, var(--accent), var(--accent-2));
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
/* The home page's site name: capitals from CSS rather than typed, so screen
   readers still read it as words. Loosened, since caps crowd at -.02em. */
.site-head h1.site-title { text-transform: uppercase; letter-spacing: .04em; }
.site-head p { margin: 0; color: var(--text-soft); font-size: 15px; }
/* ---------- Get to Know TWICE (home page) ---------- */

/* A rule under the section sets it apart from the archive cards below. */
.intro {
  margin: 8px 0 30px; padding-bottom: 32px;
  border-bottom: 1px solid var(--line);
}
.intro-title { margin: 0 0 4px; font-size: 20px; }
.intro-lede { margin: 0 0 14px; font-size: 14px; color: var(--text-soft); }
.intro-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
.intro-card {
  display: flex; flex-direction: column; text-decoration: none;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
  transition: transform .15s ease, border-color .15s ease;
}
.intro-card:hover { transform: translateY(-3px); border-color: var(--accent); }
.intro-card .thumb { position: relative; display: block; aspect-ratio: 16 / 9; background: var(--surface-2); }
.intro-card .thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.intro-card .thumb i {
  position: absolute; right: 8px; bottom: 8px;
  font-style: normal; font-size: 11.5px; font-weight: 700; color: #fff;
  padding: 2px 6px; border-radius: 5px; background: rgba(0,0,0,.72);
}
.intro-card .body { display: block; padding: 12px 14px 14px; }
.intro-card b { display: block; font-size: 15px; margin-bottom: 3px; }
.intro-card small { display: block; font-size: 12.5px; color: var(--text-soft); }

/* Other fan sites: a row of pill buttons under the intro cards. */
.intro-sites { margin-top: 22px; }
.intro-sites h3 {
  margin: 0 0 10px; font-size: 11.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em; color: var(--text-soft);
}
.site-links { display: flex; flex-wrap: wrap; gap: 10px; }
.site-link {
  display: inline-flex; align-items: center; gap: 11px;
  max-width: 100%; padding: 9px 16px 9px 10px;
  text-decoration: none; color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line); border-radius: 999px;
  box-shadow: var(--shadow);
  transition: transform .15s ease, border-color .15s ease;
}
.site-link:hover { transform: translateY(-2px); border-color: var(--accent); }
.site-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.site-link .ico {
  flex: none; width: 34px; height: 34px; border-radius: 999px;
  display: grid; place-items: center; font-size: 17px;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
}
.site-link .txt { min-width: 0; }
.site-link b { display: block; font-size: 14px; line-height: 1.25; }
.site-link small { display: block; font-size: 12px; color: var(--text-soft); }
.site-link .go { flex: none; margin-left: 2px; font-size: 14px; font-weight: 700; color: var(--accent-ink); transition: transform .15s ease; }
.site-link:hover .go { transform: translate(2px, -2px); }

/* ---------- hub cards ---------- */

.hub-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  margin-top: 8px;
}
.hub-card {
  display: block; text-decoration: none;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 20px;
  box-shadow: var(--shadow);
  transition: transform .15s ease, border-color .15s ease;
}
.hub-card:hover { transform: translateY(-3px); border-color: var(--accent); }
.hub-card.soon { opacity: .55; pointer-events: none; }
.hub-card .emoji { font-size: 26px; display: block; margin-bottom: 10px; }
.hub-card h2 { margin: 0 0 5px; font-size: 17px; }
.hub-card p { margin: 0; font-size: 13px; color: var(--text-soft); }
.hub-card .tag {
  display: inline-block; margin-top: 12px; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em; color: var(--accent-ink);
}
/* Watched totals under the Discography card's tag, filled in by index.html
   from what discography.js last counted. */
.hub-progress { display: block; margin-top: 10px; font-size: 12px; color: var(--text-soft); }
.hub-progress .bar {
  display: block; height: 4px; border-radius: 999px; margin-bottom: 6px;
  background: var(--line); overflow: hidden;
}
.hub-progress .bar b {
  display: block; height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
}
.hub-progress > b { color: var(--accent-ink); }
.hub-progress.done { color: var(--ok); font-weight: 600; }
.hub-progress.done .bar b { background: var(--ok); }

/* ---------- toolbar ---------- */

.toolbar {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line-soft);
  padding: 12px 0;
  margin-bottom: 20px;
}
.toolbar .row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.toolbar .row + .row { margin-top: 9px; }

.search {
  flex: 1 1 220px; min-width: 0;
  padding: 10px 14px; font-size: 14px; font-family: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line); border-radius: 999px;
}
.search:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: transparent; }

.chip {
  font: inherit; font-size: 12.5px; font-weight: 600;
  color: var(--text-soft); cursor: pointer;
  padding: 7px 12px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface);
}
.chip:hover { color: var(--text); }
.chip.on {
  color: #fff; border-color: transparent;
  background: linear-gradient(120deg, var(--accent), var(--accent-2));
}

/* The page's main split (Melody Project / Cover Project…, Tours / Festivals…)
   is a segmented control rather than more pills: one tinted track, the chosen
   segment lifted out of it. It wraps inside the track rather than scrolling:
   a page with many series (TV Variety) outgrows one line, and a mouse can't
   swipe a hidden-scrollbar row sideways. */
.toolbar .row.tabs {
  display: inline-flex; flex-wrap: wrap; gap: 2px;
  max-width: 100%;
  padding: 4px; border-radius: 12px;
  background: var(--surface-2); border: 1px solid var(--line);
}
.tabs .chip {
  flex: none; white-space: nowrap;
  font-size: 13.5px; padding: 8px 14px; border-radius: 9px;
  border: 0; background: transparent;
}
.tabs .chip.on {
  color: var(--accent-ink); background: var(--surface);
  box-shadow: 0 1px 2px rgba(80,40,50,.10), 0 2px 8px rgba(80,40,50,.08);
}
/* In the dark the surface is darker than the track, so a white-card lift
   would read as sunken — tint the chosen segment with the accent instead. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tabs .chip.on {
    color: var(--text); box-shadow: none;
    background: color-mix(in srgb, var(--accent) 32%, var(--surface-2));
  }
}
:root[data-theme="dark"] .tabs .chip.on {
  color: var(--text); box-shadow: none;
  background: color-mix(in srgb, var(--accent) 32%, var(--surface-2));
}
.toolbar .row.tabs + .row { margin-top: 12px; }

/* On a phone the nav doesn't fit one line, and wrapping it leaves the first
   row's underline floating off the rule. Keep it one row that swipes sideways,
   with the theme toggle pinned at the right end over a fade. The main tabs wrap
   inside their track instead, so no category hides off the edge. A mouse
   has no swipe, so theme.js turns the wheel sideways on the nav row. */
@media (max-width: 640px) {
  .site-nav {
    flex-wrap: nowrap; gap: 0 18px;
    overflow-x: auto; scrollbar-width: none;
  }
  .site-nav::-webkit-scrollbar { display: none; }
  .site-nav a { flex: none; white-space: nowrap; }
  .site-nav a.on::after { bottom: 0; }       /* the scroller clips anything below its edge */
  .theme-toggle {
    position: sticky; right: 0; flex: none;
    /* a solid ring, then a fade, so links slide out of sight under it */
    box-shadow: 0 0 0 6px var(--bg), -26px 0 16px 2px var(--bg);
  }
  .toolbar .row.tabs { display: flex; flex-wrap: wrap; }
  .toolbar .row:first-child { flex-wrap: nowrap; }   /* search and progress share one line */
  .search { flex-basis: 0; }

  /* Wrapped member and year chips stacked up to fill most of a phone screen,
     and the toolbar is sticky, so they stayed there. Give each row one line
     that swipes sideways and runs to the screen edges. */
  .toolbar .row:not(.tabs):not(:first-child) {
    flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
    margin-inline: -16px; padding-inline: 16px;
  }
  .toolbar .row:not(.tabs):not(:first-child)::-webkit-scrollbar { display: none; }
  .toolbar .row:not(.tabs):not(:first-child) > * { flex: none; white-space: nowrap; }

  /* theme.js tucks the toolbar away while you scroll down the list and
     brings it back as soon as you scroll up. */
  .toolbar { transition: transform .25s ease; }
  .toolbar.tucked { transform: translateY(calc(-100% - 1px)); }
}

/* Count beside a filter chip's label. */
.chip-n {
  font-size: 10.5px; font-weight: 700; opacity: .6;
  margin-left: 2px;
}
.chip.on .chip-n { opacity: .8; }

.spacer { flex: 1 1 auto; }

.progress-pill {
  font-size: 12.5px; font-weight: 600; color: var(--text-soft);
  padding: 7px 12px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--line);
  white-space: nowrap;
}
.progress-pill b { color: var(--accent-ink); }

/* ---------- album grid ---------- */

.era-head {
  display: flex; align-items: center; gap: 12px;
  margin: 34px 0 14px;
}
.era-head h2 { margin: 0; font-size: 19px; letter-spacing: -.01em; }
.era-head .rule { flex: 1; height: 1px; background: var(--line); }
.era-head .count { font-size: 12px; color: var(--text-faint); }
.era-head .era-years { margin-left: 4px; font-size: 14px; font-weight: 600; color: var(--text-faint); }

/* A season inside a series section (Vlogs: TW-LOG's Secret Friend, its tours). */
.season-head {
  display: flex; align-items: baseline; gap: 10px;
  margin: 22px 0 10px; padding-left: 10px;
  border-left: 3px solid var(--accent);
}
.season-head h3 { margin: 0; font-size: 15px; }
.season-head .count { font-size: 12px; color: var(--text-faint); }
.season-summary {
  margin: -4px 0 12px; padding-left: 13px; max-width: 70ch;
  font-size: 13px; line-height: 1.5; color: var(--text-soft);
}

.album-grid {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
}

.album-card {
  display: flex; flex-direction: column; text-align: left;
  font: inherit; color: inherit; cursor: pointer;
  padding: 0; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); overflow: hidden;
  box-shadow: var(--shadow);
  transition: transform .15s ease, border-color .15s ease;
}
.album-card:hover { transform: translateY(-3px); border-color: var(--accent); }

.cover {
  position: relative; aspect-ratio: 1 / 1; width: 100%;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  display: grid; place-items: center; overflow: hidden;
}
.cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Stand-in when no cover art has been dropped into assets/img/covers yet. */
.cover .initials {
  font-size: 30px; font-weight: 800; color: #fff;
  letter-spacing: -.03em; text-shadow: 0 2px 10px rgba(0,0,0,.25);
}
.cover .ring {
  position: absolute; right: 8px; bottom: 8px;
  font-size: 10.5px; font-weight: 700; color: #fff;
  padding: 3px 8px; border-radius: 999px;
  background: rgba(20,10,16,.6); backdrop-filter: blur(4px);
}
.cover .ring.done { background: var(--ok); }

/* Watched progress on a cover. The bar along the bottom fills as videos are
   watched; a finished release also gets a tick, a dimmed cover and a green
   frame so it reads as done from across the grid. */
.cover .bar {
  position: absolute; left: 0; right: 0; bottom: 0; height: 4px;
  background: rgba(20,10,16,.35);
}
.cover .bar i { display: block; height: 100%; background: var(--accent); transition: width .2s ease; }
.cover .tick {
  position: absolute; left: 8px; top: 8px;
  width: 26px; height: 26px; border-radius: 999px;
  display: grid; place-items: center;
  font-size: 14px; font-weight: 800; line-height: 1; color: #fff;
  background: var(--ok); box-shadow: 0 2px 8px rgba(0,0,0,.3);
}
.album-card.done { border-color: var(--ok); }
.album-card.done:hover { border-color: var(--ok); }
.album-card.done .cover img { filter: saturate(.55) brightness(.8); }
.album-card.done .cover .bar i { background: var(--ok); }

.album-card .body { padding: 11px 12px 13px; }
.album-card h3 { margin: 0 0 3px; font-size: 14px; line-height: 1.3; }
.album-card .meta { margin: 0; font-size: 11.5px; color: var(--text-faint); }

/* Who the release is credited to, when it isn't simply Twice — the other
   artist on a collaboration. */
.card-artist {
  margin: 0 0 6px; font-size: 11.5px; font-weight: 600;
  color: var(--accent-ink); line-height: 1.3;
}
.panel-artist {
  margin: 0 0 5px; font-size: 13px; font-weight: 600; color: var(--accent-ink);
}

/* Release type, shown under the title on the card and in the panel head. */
.type-row { margin: 0 0 5px; }
.type-badge {
  display: inline-block;
  font-size: 10px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  padding: 2.5px 8px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface-2); color: var(--text-soft);
}
.type-badge[data-type="Full Album"] { background:#8b6fd1; border-color:transparent; color:#fff; }
.type-badge[data-type="EP"]         { background:#3f8fd6; border-color:transparent; color:#fff; }
.type-badge[data-type="Single"]     { background:#e0902f; border-color:transparent; color:#fff; }
.type-badge[data-type="Reissue"]    { background:#4ec9b0; border-color:transparent; color:#123; }
.type-badge[data-type="Compilation"] { background:#e2b93b; border-color:transparent; color:#2a1b22; }
.type-badge[data-type="Remix Album"] { background:#8b6fd1; border-color:transparent; color:#fff; }

/* A member writing credit. On its own line under the title rather than lost
   among the pills on the title row. */
.written-row { margin: 6px 0 0 28px; display: flex; flex-wrap: wrap; gap: 6px; }
.written, .member {
  display: inline-block;
  font-size: 11.5px; font-weight: 700; letter-spacing: .01em;
  padding: 3px 10px; border-radius: 999px;
  /* A hairline keeps a near-white member colour (Dahyun) legible against the
     light theme; it disappears against the darker colours. */
  border: 1px solid rgba(0,0,0,.14);
  /* fallback until the inline member colours apply */
  color: #fff; background: linear-gradient(120deg, var(--grape), var(--accent));
}
:root[data-theme="dark"] .written, :root[data-theme="dark"] .member { border-color: rgba(255,255,255,.18); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .written,
  :root:not([data-theme="light"]) .member { border-color: rgba(255,255,255,.18); }
}
@media (max-width: 560px) { .written-row { margin-left: 0; } }

/* Solo, sub-unit and featured credits beside a track title. */
.credit {
  font-size: 11px; font-weight: 600; color: var(--text-soft);
  padding: 2px 8px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--line);
}

/* ---------- album detail overlay ---------- */

.overlay {
  position: fixed; inset: 0; z-index: 100;
  display: none; padding: 20px 14px;
  background: rgba(30,12,22,.55); backdrop-filter: blur(4px);
  overflow-y: auto; overscroll-behavior: contain;
}
.overlay.open { display: block; }

.panel {
  max-width: 820px; margin: 0 auto;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 18px;
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.panel-head {
  display: flex; gap: 16px; align-items: flex-start;
  padding: 20px; border-bottom: 1px solid var(--line);
  background: var(--surface);
}
.panel-head .cover { width: 108px; flex: none; border-radius: var(--radius-sm); }
.panel-head .info { flex: 1; min-width: 0; }
.panel-head h2 { margin: 0 0 3px; font-size: 21px; letter-spacing: -.01em; }
.panel-head .ko { margin: 0 0 6px; font-size: 13px; color: var(--text-soft); }
.panel-head .meta { margin: 0 0 12px; font-size: 12.5px; color: var(--text-faint); }
.panel-close {
  font: inherit; font-size: 22px; line-height: 1; cursor: pointer;
  color: var(--text-soft); background: none; border: 0; padding: 4px 6px;
}
.panel-close:hover { color: var(--text); }
/* ‹ › to the neighbouring release, grouped with the close button. */
.panel-nav { display: flex; align-items: center; gap: 6px; flex: none; }
.panel-arrow {
  font: inherit; font-size: 20px; line-height: 1; cursor: pointer;
  width: 32px; height: 32px; border-radius: 999px;
  display: grid; place-items: center; padding: 0 0 2px;
  color: var(--text-soft); background: var(--surface-2); border: 1px solid var(--line);
}
.panel-arrow:hover:not(:disabled) { color: var(--text); border-color: var(--accent); }
.panel-arrow:disabled { opacity: .35; cursor: default; }

/* The arrows float at the panel's sides, vertically centred, and stay put while
   the tracklist scrolls. They only show while the overlay is open. */
.panel-float { display: none; }
.overlay.open + .panel-float { display: block; }
.panel-float .panel-arrow {
  position: fixed; z-index: 101; top: 50%; transform: translateY(-50%);
  width: 44px; height: 44px; padding: 0;
  color: var(--text); background: var(--surface);
  box-shadow: var(--shadow-lg);
}
/* 820px panel, 14px overlay padding: sit just outside its edges. */
.panel-float #panelPrev { left:  max(10px, calc(50% - 410px - 58px)); }
.panel-float #panelNext { right: max(10px, calc(50% - 410px - 58px)); }
.panel-float .panel-arrow:disabled { opacity: 0; pointer-events: none; }

.stream-links { display: flex; flex-wrap: wrap; gap: 7px; }
.region-lock {
  margin: 7px 0 0; font-size: 11.5px; font-weight: 600; color: var(--warn);
  display: inline-block;
  padding: 3px 9px; border-radius: 999px;
  background: var(--surface-2); border: 1px dashed var(--line);
}
.stream-btn {
  display: inline-flex; align-items: center; gap: 6px;
  text-decoration: none; font-size: 12.5px; font-weight: 600;
  padding: 7px 12px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface-2); color: var(--text);
}
.stream-btn:hover { border-color: currentColor; }
.stream-btn .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.stream-btn[data-svc="spotify"]   .dot { background: #1db954; }
.stream-btn[data-svc="appleMusic"].dot,
.stream-btn[data-svc="appleMusic"] .dot { background: #fa243c; }
.stream-btn[data-svc="youtubeMusic"] .dot { background: #ff0000; }
.stream-btn[data-svc="melon"]     .dot { background: #00cd3c; }
/* A service with no link yet still renders, greyed, so gaps are visible. */
.stream-btn.empty { opacity: .4; pointer-events: none; }

.panel-body { padding: 8px 20px 24px; }

/* ---------- track rows ---------- */

.track {
  padding: 14px 0;
  border-bottom: 1px solid var(--line-soft);
}
.track:last-child { border-bottom: 0; }

.track-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.track-no { font-size: 12px; color: var(--text-faint); width: 20px; flex: none; }
.track-title { font-size: 14.5px; font-weight: 650; }
.track-ko { font-size: 12.5px; color: var(--text-soft); }
.star {
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
  color: #fff; padding: 2px 7px; border-radius: 999px;
  background: linear-gradient(120deg, var(--accent), var(--accent-2));
}

.video-strip {
  display: grid; gap: 10px; margin-top: 10px;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
}

.no-video {
  margin-top: 8px; font-size: 12.5px; color: var(--text-faint);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.no-video a { color: var(--accent-ink); font-weight: 600; }

/* ---------- video card ---------- */

.vcard {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); overflow: hidden;
}
.vcard.watched { opacity: .62; }
.vcard.watched:hover { opacity: 1; }

.vthumb {
  position: relative; display: block; width: 100%; padding: 0;
  border: 0; background: #000; cursor: pointer;
  aspect-ratio: 16 / 9; overflow: hidden;
}
.vthumb img { position: relative; z-index: 1; width: 100%; height: 100%; object-fit: cover; display: block; }
.vthumb img[hidden] { display: none; }   /* stub thumbnail — let the gradient show */
/* Sits under the <img>: shows while the thumbnail decodes, and stays put if
   the video has no usable thumbnail at all. Bottom-left so it never collides
   with the centred play button. */
.vthumb .fallback {
  position: absolute; inset: 0;
  display: flex; align-items: flex-end; padding: 9px 10px;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #fff; font-size: 11px; font-weight: 700; letter-spacing: .04em;
  text-shadow: 0 1px 4px rgba(0,0,0,.25);
}
.vthumb .play {
  position: absolute; inset: 0; margin: auto;
  width: 46px; height: 46px; border-radius: 50%;
  background: rgba(0,0,0,.62); color: #fff;
  display: grid; place-items: center; font-size: 15px;
  transition: transform .15s ease, background .15s ease;
}
.vthumb:hover .play { transform: scale(1.12); background: var(--accent); }
.vthumb .dur {
  position: absolute; right: 6px; bottom: 6px;
  font-size: 10.5px; font-weight: 600; color: #fff;
  background: rgba(0,0,0,.75); padding: 1px 5px; border-radius: 3px;
}
/* A hand-picked highlight, stuck on the thumbnail itself rather than filed in
   the tag row, so it carries at a glance down a long grid. Top-left is the
   free corner: the play button owns the centre and .dur the bottom-right. The
   white rim and the drop shadow are what make it read as a sticker, and it
   keeps the site's own pink rather than the per-section accent so it looks the
   same on every page. */
.vthumb .must, .season-head .must, .era-head .must {
  position: absolute; z-index: 2; top: 7px; left: 7px;
  font-size: 9.5px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  padding: 3px 8px; border-radius: 999px; white-space: nowrap;
  background: linear-gradient(100deg, #ffc224, #f0980d);
  color: #fff;
  /* White on yellow is thin at this size, so the fill runs to the deep end of
     yellow and the text carries a shadow — the same trick .fallback uses. */
  text-shadow: 0 1px 2px rgba(120,70,0,.55);
  border: 1.5px solid #fff;
  box-shadow: 0 2px 8px rgba(0,0,0,.4);
}
/* On a season heading it sits in line after the title, not over a thumbnail. */
.season-head .must, .era-head .must { position: static; align-self: center; box-shadow: none; }

.vmeta { padding: 8px 10px 9px; display: flex; flex-direction: column; gap: 6px; }
.vlabel { font-size: 12.5px; font-weight: 600; line-height: 1.35; }
.vtags { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; }

.badge {
  font-size: 10px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  padding: 2.5px 7px; border-radius: 999px;
  border: 1px solid transparent;
}
.badge[data-kind="mv"]          { background:#ff6fa5; color:#fff; }
.badge[data-kind="special"]     { background:#d98cf0; color:#2a1b22; }
.badge[data-kind="lyric"]       { background:#8b6fd1; color:#fff; }
.badge[data-kind="performance"] { background:#3f8fd6; color:#fff; }
.badge[data-kind="dance"]       { background:#4ec9b0; color:#123; }
/* a relay dance or STUDIO CHOOM take: part dance video, part stage */
.badge[data-kind="dance-performance"] { background:linear-gradient(90deg, #4ec9b0, #3f8fd6); color:#123; }
.badge[data-kind="live"]        { background:#e0902f; color:#fff; }
.badge[data-kind="audio"]       { background:#6f7fd1; color:#fff; }
.badge[data-kind="other"]       { background:var(--surface-2); color:var(--text-soft); border-color:var(--line); }

.official {
  font-size: 10px; font-weight: 700; letter-spacing: .03em;
  display: inline-flex; align-items: center; gap: 3px;
}
.official.yes { color: var(--ok); }
.official.no  { color: var(--warn); }
.official.fancam { color: var(--accent-ink); }

.watch-btn {
  font: inherit; font-size: 11.5px; font-weight: 600; cursor: pointer;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 10px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface-2); color: var(--text-soft);
  align-self: flex-start;
}
.watch-btn:hover { color: var(--text); border-color: var(--text-faint); }
.watch-btn.on { background: var(--ok); border-color: transparent; color: #fff; }
/* The release-wide version sits under the panel's watched count. */
.watch-btn.mark-all { margin: 2px 0 10px; }

.ext {
  font-size: 11.5px; color: var(--text-faint); text-decoration: none;
  margin-left: auto;
}
.ext:hover { color: var(--accent-ink); }
/* When a video has a freely watchable copy, the card opens that and the
   official release moves to this button — still one click away, just no longer
   the thing you land on. A pill rather than a bare ↗ so it reads as a choice. */
.ext.orig {
  font-size: 10.5px; font-weight: 600; letter-spacing: .01em;
  color: var(--text-soft); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 2.5px 8px; white-space: nowrap;
}
.ext.orig:hover { color: var(--accent-ink); border-color: var(--accent); }

/* ---------- misc ---------- */

.empty-state {
  text-align: center; padding: 60px 20px; color: var(--text-faint); font-size: 14px;
}

/* ---------- covers and live pages ---------- */

/* Both sections lay their videos out as one card grid, with the entry's own
   details above the usual video tags — the song, original artist and members
   on a cover, the show, venue and date on a concert. Same rules, two names. */
.cover-grid,
.live-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
.cover-card .vmeta,
.live-card .vmeta { gap: 5px; padding-bottom: 11px; }
.cover-card .song,
.live-card .song { margin: 0; font-size: 14.5px; line-height: 1.3; }
.cover-card .song .track-ko { font-weight: 500; }
.cover-card .orig,
.live-card .orig { font-size: 12px; color: var(--text-soft); }
.cover-card .vlabel,
.live-card .vlabel { font-size: 12px; color: var(--text-soft); }
.cover-meta,
.live-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; margin: 2px 0; }
.cover-meta .date,
.live-meta .date { font-size: 11.5px; color: var(--text-faint); }
.cover-card .member,
.live-card .member { font-size: 10.5px; padding: 2px 8px; }
.cover-note,
.live-note { margin: 0; font-size: 12px; color: var(--text-soft); line-height: 1.4; }
.cover-card .no-video,
.live-card .no-video { margin-top: 4px; }
.series-badge {
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
  padding: 2.5px 7px; border-radius: 999px;
  color: var(--text-soft); background: var(--surface-2); border: 1px solid var(--line);
}
.series-badge[data-series="melody-project"] { color: #fff; background: var(--accent); border-color: transparent; }
.series-badge[data-series="performance-project"] { color: #123; background: var(--accent-2); border-color: transparent; }
/* The live page's buckets, scoped so they can't collide with a covers series
   of the same name. Four brand colours for six buckets: award shows keep the
   neutral chip, and stage covers & collabs blend two of the brand colours. */
:root[data-accent="live"] .series-badge[data-series="tour"]       { color: #123; background: var(--mint);  border-color: transparent; }
:root[data-accent="live"] .series-badge[data-series="festival"]   { color: #fff; background: var(--grape); border-color: transparent; }
:root[data-accent="live"] .series-badge[data-series="special"]    { color: #fff; background: var(--candy); border-color: transparent; }
:root[data-accent="live"] .series-badge[data-series="fanmeeting"] { color: #123; background: var(--peach); border-color: transparent; }
:root[data-accent="live"] .series-badge[data-series="stage"]      { color: #fff; background: linear-gradient(120deg, var(--candy), var(--grape)); border-color: transparent; }
/* Vlogs: every TW-LOG season shares one look, behind-the-scenes another. */
:root[data-accent="vlogs"] .series-badge[data-series="twlog"]  { color: #123; background: var(--peach); border-color: transparent; }
:root[data-accent="vlogs"] .series-badge[data-series="behind"] { color: #fff; background: var(--grape); border-color: transparent; }
/* TV Variety: one look for every show; the section heading already says which. */
:root:is([data-accent="twicetv"], [data-accent="variety"]) .series-badge { color: #2a1b22; background: linear-gradient(120deg, var(--accent), var(--accent-2)); border-color: transparent; }
/* A member chip in the filter row carries a dot in that member's colour. */
.chip .dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 999px;
  margin-right: 6px; border: 1px solid rgba(0,0,0,.14);
}
@media (max-width: 560px) {
  .cover-grid, .live-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 400px) {
  .cover-grid, .live-grid { grid-template-columns: 1fr; }
}

/* ---------- donate page ---------- */

.donate-card {
  max-width: 640px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px 24px;
  box-shadow: var(--shadow);
}
.donate-card .emoji { font-size: 28px; display: block; margin-bottom: 8px; }
.donate-card h2 { margin: 0 0 10px; font-size: 19px; }
.donate-card p { margin: 0 0 12px; color: var(--text-soft); font-size: 14.5px; }
.donate-btn {
  display: inline-flex; align-items: center; gap: 8px; margin-top: 10px;
  padding: 13px 28px; border-radius: 12px;
  font: inherit; font-weight: 800; font-size: 15.5px; letter-spacing: .01em;
  text-decoration: none; color: #fff; cursor: pointer;
  text-shadow: 0 1px 2px rgba(0,0,0,.22);
  background: linear-gradient(120deg, var(--accent), var(--accent-2));
  border: 1px solid rgba(0,0,0,.06);
  /* a light top edge and a coloured drop shadow read as a raised, pressable button */
  box-shadow: inset 0 1px 0 rgba(255,255,255,.35),
              0 4px 0 color-mix(in srgb, var(--accent-2) 70%, #000 30%),
              0 8px 18px color-mix(in srgb, var(--accent-2) 35%, transparent);
  transition: transform .12s ease, box-shadow .12s ease, filter .12s ease;
}
.donate-btn:hover {
  transform: translateY(-2px); filter: brightness(1.05);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.35),
              0 6px 0 color-mix(in srgb, var(--accent-2) 70%, #000 30%),
              0 12px 24px color-mix(in srgb, var(--accent-2) 40%, transparent);
}
.donate-btn:active {
  transform: translateY(3px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.25),
              0 1px 0 color-mix(in srgb, var(--accent-2) 70%, #000 30%),
              0 3px 8px color-mix(in srgb, var(--accent-2) 30%, transparent);
}
.donate-btn:focus-visible { outline: 3px solid var(--accent); outline-offset: 4px; }

/* "Reset watched progress", centred under the grid. Armed = one more click
   clears everything. */
.reset-row { display: flex; justify-content: center; margin-top: 44px; }
.chip.danger:hover:not(:disabled) { color: var(--warn); border-color: var(--warn); }
.chip.danger.armed { color: #fff; background: var(--warn); border-color: transparent; }
.chip:disabled { opacity: .5; cursor: default; }

/* ---------- updates ---------- */

/* A single column of post cards, newest first. Photos and embedded posts get
   the column's full width. */
.update-stream { max-width: 640px; margin: 0 auto; display: grid; gap: 16px; }
.update {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 16px 20px 6px;
}
.update-top {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 6px 10px; margin-bottom: 8px;
}
.update-when { font-size: 12px; font-weight: 700; letter-spacing: .02em; color: var(--accent-ink); }
.update-tags { display: flex; flex-wrap: wrap; gap: 5px; }
.update-tags .member { font-size: 10.5px; padding: 2px 8px; }
.update[hidden] { display: none; }
.update-body { font-size: 15px; line-height: 1.6; }
.update-body h3, .update-body h4 { margin: 18px 0 6px; line-height: 1.3; }
.update-body h3 { font-size: 17px; }
.update-body h4 { font-size: 15px; }
.update-body > :first-child { margin-top: 0; }
.update-body p, .update-body ul { margin: 0 0 14px; }
.update-body ul { padding-left: 22px; }
.update-body p a { color: var(--accent-ink); }
.update-body hr { border: 0; border-top: 1px solid var(--line); margin: 18px 0; }
.update-missing { color: var(--text-faint); font-size: 14px; }

.update-single, .update-gallery, .update-embed, .update-video, .update-link { margin: 0 0 14px; }
.update-gallery { display: grid; gap: 8px; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); }
.update-photo { display: block; border-radius: var(--radius-sm); overflow: hidden; background: var(--surface-2); }
.update-photo img { display: block; width: 100%; height: auto; }
.update-gallery .update-photo img { aspect-ratio: 4 / 5; object-fit: cover; }
.update-photo:hover img { opacity: .92; }
.update-video { max-width: 400px; }

/* Until Instagram's or X's script swaps in the post, the blockquote is a card
   holding the plain link. The platforms size their own embeds after that. */
.update-embed { display: flex; justify-content: center; }
.update-embed blockquote {
  margin: 0; width: 100%; max-width: 540px; padding: 18px 20px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius-sm); text-align: center; font-size: 14px;
}
/* Instagram's frame never goes below 326px wide: its layout inside breaks
   (the post skews) if it's squeezed narrower, so don't override that. On a
   phone the embed runs to the card's edges instead, which leaves 326px even
   on a 360px-wide screen. */
@media (max-width: 560px) {
  .update { padding-left: 14px; padding-right: 14px; }
  .update-embed { margin-left: -14px; margin-right: -14px; }
}

/* A link that can't be embedded: a news article, a Weverse post. */
.update-link {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px; text-decoration: none; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-sm);
  transition: border-color .15s ease;
}
.update-link:hover { border-color: var(--accent); }
.update-link .ico { flex: none; font-size: 20px; }
.update-link .txt { flex: 1; min-width: 0; }
.update-link b { display: block; font-size: 14px; }
.update-link small { display: block; font-size: 12px; color: var(--text-soft); }
.update-link .go { flex: none; font-weight: 700; color: var(--accent-ink); }

.more-row { display: flex; justify-content: center; margin-top: 24px; }
.more-row [hidden] { display: none; }

footer.site-foot {
  margin-top: 50px; padding-top: 20px;
  border-top: 1px solid var(--line);
  font-size: 12px; color: var(--text-faint);
}

@media (max-width: 560px) {
  .panel-head { flex-wrap: wrap; gap: 12px; padding: 16px; }
  .panel-head .cover { width: 76px; }
  .panel-body { padding: 4px 16px 20px; }
  .overlay { padding: 10px 8px; }
  /* No room beside the panel on a phone: drop to the bottom corners. */
  .panel-float .panel-arrow { top: auto; bottom: 16px; transform: none; }
  .panel-float #panelPrev { left: 16px; }
  .panel-float #panelNext { right: 16px; }
  .video-strip { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 400px) {
  .video-strip { grid-template-columns: 1fr; }
}

.brand-bar { background: var(--surface-2); border-bottom: 1px solid var(--line-soft); }
.brand-bar .wrap { padding-top: 14px; padding-bottom: 14px; }
.brand-title {
  font-family: var(--font); font-size: 18px; font-weight: 800;
  letter-spacing: .14em; color: var(--accent); text-decoration: none;
}