/* tokens.css */
/* 디자인 토큰 — 색 · 글꼴 · 둥글기 · 그림자 · 폭은 여기에만 적는다(설계 17 §8).
   다른 파일은 var(--이름) 만 쓴다. 밝은 값은 :root, 어두운 값은 :root[data-theme="dark"] 에 다시 적는다.
   체계 원본: gensapps/project-voice-studio static/design/tokens.css. 브랜드는 무대 조명 — 보라 → 자홍 → 호박 */
:root{
  /* 바탕 · 글 */
  --paper:#F7F6F9;--card:#FFFFFF;--text:#17151F;--muted:#565366;--faint:#8B8899;
  --line:#E5E2EC;--line-strong:#BEB9CC;--hover:#F1EEF6;--code-bg:#F1EEF6;
  /* 브랜드 */
  --accent:#6B35E8;--accent-deep:#5223C2;--accent-soft:#F1EBFF;--accent-line:#D6C8FB;--on-accent:#FFFFFF;
  /* 무대(히어로 · 「빠르고 믿을 수 있는」 · 바닥 띠 · 로그인 소개) — 테마마다 다르다(#63).
     밝은 테마는 연보라 조명 무대(어두운 글), 어두운 테마는 밤 무대(밝은 글). 무대 부품은 이 토큰만 쓴다 */
  --stage:#F4EFFF;--stage-2:#FFFFFF;--on-stage:#17151F;--on-stage-2:#3E3A52;--on-stage-dim:#6B6682;
  --stage-line:rgba(82,35,194,.16);--stage-glass:rgba(255,255,255,.72);--stage-shade:rgba(244,239,255,.86);
  --glow-1:#7C3AED;--glow-2:#DB2777;--glow-3:#F59E0B;--glow-opacity:.28;
  /* 무대 위 강조 — 큰 재생 단추 · 고른 칩 · 무대 단추(밝은 테마는 브랜드 보라, 어두운 테마는 흰 단추) · 무대 위 작은 제목 */
  --stage-active:#6B35E8;--stage-active-hover:#5223C2;--on-stage-active:#FFFFFF;--stage-accent:#5223C2;
  --on-glow:#FFFFFF;  /* 보라 → 자홍 → 호박 그라데이션 단추 위 글자 — 두 테마 같다 */
  /* 무대 그림 · 막(#73) — 그림은 두 테마 모두 그대로 진하게 보인다. 옅게 · 밝게 바래면 뿌옇다(#63 의 .42 · 밝기 1.35).
     밝은 테마는 글자 쪽(왼쪽 · 아래)만 흰 반투명 막으로 읽히게 하고 오른쪽은 막 없이 그림을 보인다 */
  /* 슈퍼관리자 표시(#97, voice-studio 와 같은 값) — 메뉴의 관리 콘솔 영역 */
  --admin:#C2410C;--admin-soft:#FFF1E8;--admin-line:#F8C9AE;
  --stage-art-opacity:1;--stage-art-opacity-sub:1;--stage-art-filter:none;  /* sub — 기능 페이지 무대 */
  --stage-veil:rgba(255,255,255,.9);--stage-veil-mid:rgba(255,255,255,.62);
  /* 글자 그라데이션 — 밝은 바탕에서도 읽히는 짙은 색 */
  --grad-a:#6B35E8;--grad-b:#C2187A;--grad-c:#D9690F;
  /* 파형 — 안 들은 곳 · 들은 곳 · 고른 구간 */
  --wave:#CFC8DD;--wave-played:#6B35E8;--wave-sel:rgba(107,53,232,.14);--wave-sel-line:#6B35E8;
  --wave-stage:rgba(82,35,194,.22);--wave-stage-played:#6B35E8;
  /* 코드 판(API 문서) — 두 테마에서 같다 */
  --ink:#0C0A14;--ink-2:#15121F;--ink-line:rgba(255,255,255,.09);--ink-fg:#DCD7E8;--ink-dim:#857E99;
  --syn-key:#C792EA;--syn-str:#A5E3B0;--syn-num:#F8B886;--syn-com:#6E6888;--syn-fn:#82AAFF;--syn-prop:#89DDFF;
  /* 유리 · 덮개 */
  --glass:rgba(255,255,255,.72);--veil:rgba(247,246,249,.94);--veil-soft:rgba(247,246,249,.55);
  /* 상태 */
  --ok:#22663A;--ok-bg:#E6F4EA;--warn:#7A4E00;--warn-bg:#FFF4D6;--bad:#A3300B;--bad-bg:#FFE0D6;--info:#5223C2;--info-bg:#F1EBFF;
  /* 장르 · 분야 색 — 카드 띠 · 칩. 순서대로 쓴다(config/showcase.yml 의 순서와 상관없이 고리로 돈다) */
  --series-1:#6B35E8;--series-2:#DB2777;--series-3:#E8822F;--series-4:#0E9F8E;--series-5:#2F6FE8;--series-6:#8A8499;
  /* 상단 메뉴 · 로고 */
  --logo-a:#5223C2;--logo-b:#B5179E;--logo-c:#E8822F;
  --gn-bg:rgba(255,255,255,.9);--gn-line:#E5E2EC;--gn-fg:#47445A;--gn-on:#17151F;--gn-on-bg:#F1EBFF;--gn-hover:#F1EEF6;
  --gn-panel:#FFFFFF;--gn-shadow:0 18px 40px -12px rgba(23,21,31,.22);
  --gn-admin-bg:rgba(255,236,214,.94);--gn-admin-line:#F2B877;  /* 슈퍼관리자 화면 상단 바(#200) */
  /* Google 로그인 단추 — 구글 브랜딩 가이드의 정해진 바탕 · 테두리 · 글자색 */
  --google-bg:#FFFFFF;--google-line:#747775;--google-fg:#1F1F1F;
  /* 누름 상태 — 가이드의 상태 겹(#303030 8% · 12%)을 흰 바탕에 미리 섞은 값 + 떠오르는 그림자 */
  --google-hover:#EEEEEE;--google-press:#E6E6E6;--google-shadow:0 1px 2px 0 rgba(60,64,67,.3),0 1px 3px 1px rgba(60,64,67,.15);
  /* 모양 */
  --r-sm:6px;--r:10px;--r-lg:14px;--r-xl:20px;--r-pill:999px;
  --shadow:0 1px 2px rgba(23,21,31,.06);--shadow-lift:0 14px 34px -14px rgba(23,21,31,.3);--shadow-pop:0 30px 80px rgba(0,0,0,.45);
  --sans:"Pretendard","Apple SD Gothic Neo","Malgun Gothic","Noto Sans KR",system-ui,-apple-system,sans-serif;
  --mono:ui-monospace,"SF Mono","JetBrains Mono",Menlo,Consolas,monospace;
  /* 폭 5단계(조직 RESPONSIVE.md) — S <640 · M 640~1023 · L 1024~1439 · XL 1440~1919 · 2XL >=1920 */
  --wrap:100%;--gutter:16px;--gn-h:60px;--player-h:72px
}
@media (min-width:640px){:root{--gutter:24px}}
@media (min-width:1024px){:root{--wrap:1160px;--gutter:32px}}
@media (min-width:1440px){:root{--wrap:1400px}}
@media (min-width:1920px){:root{--wrap:1760px}}

/* 어두운 테마 — '어둡게' 를 골랐거나 '시스템' 인데 기기가 어두울 때(<html data-theme="dark">) */
:root[data-theme="dark"]{color-scheme:dark;
  --admin:#FB923C;--admin-soft:rgba(251,146,60,.12);--admin-line:rgba(251,146,60,.38);
  --stage:#08060F;--stage-2:#130F22;--on-stage:#F4F1FA;--on-stage-2:#CFC8E0;--on-stage-dim:#A49CBA;
  --stage-line:rgba(255,255,255,.16);--stage-glass:rgba(19,15,34,.62);--stage-shade:rgba(8,6,15,.8);--glow-opacity:.55;
  --grad-a:#B89CFF;--grad-b:#FF7EC4;--grad-c:#FFC266;
  --stage-art-opacity:1;--stage-art-opacity-sub:.55;--stage-art-filter:none;--stage-veil:var(--stage);--stage-veil-mid:var(--stage-shade);
  --stage-active:#F4F1FA;--stage-active-hover:#CFC8E0;--on-stage-active:#08060F;--stage-accent:#FF7EC4;
  --wave-stage:rgba(244,241,250,.32);--wave-stage-played:#FFFFFF;
  --glass:rgba(19,15,34,.62);--veil:rgba(12,10,20,.9);--veil-soft:rgba(12,10,20,.45);
  --paper:#0C0A14;--card:#15121F;--text:#ECE9F3;--muted:#A8A1BA;--faint:#777089;
  --line:#28233A;--line-strong:#3D3654;--hover:#1C182A;--code-bg:#110E1B;
  --accent:#A98BFF;--accent-deep:#C6B2FF;--accent-soft:#221A3D;--accent-line:#3A2E66;--on-accent:#0C0A14;
  --wave:#3A3450;--wave-played:#B89CFF;--wave-sel:rgba(169,139,255,.16);--wave-sel-line:#B89CFF;
  --ok:#6FD39A;--ok-bg:#12291C;--warn:#F0C26B;--warn-bg:#2B2213;--bad:#FF9C84;--bad-bg:#2E1612;--info:#C6B2FF;--info-bg:#221A3D;
  --series-1:#A98BFF;--series-2:#FF7EC4;--series-3:#FFB06E;--series-4:#3CCFBC;--series-5:#7FA8FF;--series-6:#A9A3B8;
  --logo-a:#A98BFF;--logo-b:#FF7EC4;--logo-c:#FFC266;
  --gn-bg:rgba(12,10,20,.92);--gn-line:rgba(255,255,255,.1);--gn-fg:#B7B0C8;--gn-on:#F4F1FA;--gn-on-bg:rgba(255,255,255,.09);
  --gn-hover:rgba(255,255,255,.06);--gn-panel:#15121F;--gn-shadow:0 24px 50px -12px rgba(0,0,0,.6);
  --gn-admin-bg:rgba(58,30,8,.94);--gn-admin-line:rgba(240,160,80,.4);
  --google-bg:#131314;--google-line:#8E918F;--google-fg:#E3E3E3;
  --google-hover:#262627;--google-press:#2F2F30;--google-shadow:0 1px 2px 0 rgba(0,0,0,.5),0 1px 3px 1px rgba(0,0,0,.3);
  --shadow:0 1px 2px rgba(0,0,0,.4);--shadow-lift:0 18px 40px -14px rgba(0,0,0,.7)}

/* base.css */
/* 요소 기본값과 작은 도우미 — 색은 토큰만 쓴다 */
*,*::before,*::after{box-sizing:border-box}
[hidden]{display:none!important} /* hidden 속성은 늘 숨긴다 — .btn 같은 display 규칙이 덮지 못하게(이슈 135) */
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--paper);color:var(--text);font-family:var(--sans);font-size:15px;line-height:1.6;
  word-break:keep-all;overflow-wrap:break-word}  /* 한국어는 어절 단위로 줄을 바꾼다 — 화면마다 따로 넣지 않는다 */
h1,h2,h3{line-height:1.25;letter-spacing:-.3px;margin:0;text-wrap:balance}  /* 두세 줄 제목은 줄 길이를 고르게 */
p,li,dd,td,figcaption,label{text-wrap:pretty}  /* 마지막 줄에 한두 어절만 남지 않게 */
p{margin:0}
a{color:var(--accent)}
a:hover{color:var(--accent-deep)}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
img{max-width:100%;display:block}
code,pre{font-family:var(--mono)}
.wrap{max-width:var(--wrap);margin:0 auto;padding:0 var(--gutter)}
.dim{color:var(--muted)}
.small{font-size:12px}
.title-sm{font-size:24px}
/* 세로로 쌓기 — 배치 도우미. 화면마다 인라인 style 로 쓰지 않는다 */
.stack{display:flex;flex-direction:column;gap:14px}
.stack-start{display:flex;flex-direction:column;gap:14px;align-items:flex-start}
.nowrap{white-space:nowrap}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}
.skip{position:absolute;left:-9999px;top:8px;z-index:100;padding:8px 12px;background:var(--card);border-radius:var(--r)}
.skip:focus{left:8px}
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}

/* motion.css */
/* 움직임 — @keyframes 는 여기에만 둔다(시험이 막는다). 화면 CSS 는 이름만 가져다 쓴다.
   움직임 줄이기 설정은 base.css 의 전역 규칙 하나가 모두 멈춘다 — 화면마다 다시 적지 않는다 */
@keyframes asSpin{to{transform:rotate(360deg)}}
/* 소리 막대가 오르내린다 — 로고 · 재생 중 표시 */
@keyframes asBar{0%,100%{transform:scaleY(.25)}50%{transform:scaleY(1)}}
/* 그라데이션이 옆으로 흐른다 — background-size:200% 와 함께 */
@keyframes asFlow{0%{background-position:0% 50%}100%{background-position:200% 50%}}
/* 물결 SVG 를 한 주기(1440)만큼 민다 — 경로는 waves.py 가 2배 폭으로 그린다 */
@keyframes asSlide{0%{transform:translateX(0)}100%{transform:translateX(-1440px)}}
/* 띠가 제 폭의 반만큼 흐른다 — 같은 내용을 두 번 이어 붙인 띠 */
@keyframes asMarquee{0%{transform:translateX(0)}100%{transform:translateX(-50%)}}
/* 빛 번짐이 떠다닌다 */
@keyframes asFloatA{0%,100%{transform:translate(0,0) scale(1)}50%{transform:translate(110px,50px) scale(1.12)}}
@keyframes asFloatB{0%,100%{transform:translate(0,0) scale(1.08)}50%{transform:translate(-120px,40px) scale(.95)}}
/* 숨 쉬듯 밝아졌다 어두워진다 */
@keyframes asPulse{0%,100%{opacity:.55}50%{opacity:1}}
/* 그림이 천천히 다가온다 */
@keyframes asZoom{0%{transform:scale(1.04)}100%{transform:scale(1.12)}}
/* 누른 칸에서 소리가 퍼진다 — 사운드보드 */
@keyframes asRipple{0%{transform:scale(.6);opacity:.7}100%{transform:scale(2.4);opacity:0}}
/* 아래에서 떠오른다 — 차례 등장 */
@keyframes asRise{0%{transform:translateY(14px);opacity:0}100%{transform:translateY(0);opacity:1}}
/* 단계 표시의 점이 차례로 깜빡인다 */
@keyframes asBlink{0%,100%{opacity:.25}50%{opacity:1}}
/* 가사 무대 전체 화면의 빛 — 박자마다 숨쉰다(#46) */
@keyframes ly-breathe{from{transform:scale(1);opacity:.35}to{transform:scale(1.08);opacity:.6}}

/* components.css */
/* 공통 부품 — 화면은 이 클래스만 쓴다. 같은 이름을 다른 파일에서 다시 정의하지 않는다(시험이 막는다).
   형태 원본: project-voice-studio components.css. 재생기 · 파형은 player.css */

/* 단추 — <a> · <button> 모두 */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:44px;padding:10px 18px;
  border-radius:var(--r);border:1px solid var(--line-strong);background:var(--card);color:var(--text);
  font:inherit;font-weight:500;text-decoration:none;cursor:pointer}
.btn:hover{background:var(--hover);color:var(--text)}
.btn-primary{background:var(--accent);border-color:var(--accent);color:var(--on-accent);font-weight:700}
.btn-primary:hover{background:var(--accent-deep);border-color:var(--accent-deep);color:var(--on-accent)}
.btn-lg{min-height:52px;padding:14px 24px;border-radius:var(--r-lg)}
.btn-sm{min-height:36px;padding:6px 12px;font-size:13px;white-space:nowrap}  /* 작은 단추 이름은 꺾지 않는다 */
.btn-stage{background:var(--stage-active);border-color:var(--stage-active);color:var(--on-stage-active);font-weight:700}
.btn-stage:hover{background:var(--stage-active-hover);border-color:var(--stage-active-hover);color:var(--on-stage-active)}
.btn-stage-ghost{background:transparent;border-color:var(--stage-line);color:var(--on-stage)}
.btn-stage-ghost:hover{background:var(--stage-glass);color:var(--on-stage)}
/* 무대 위 큰 강조 단추 — 브랜드 그라데이션이 흐른다 */
.btn-glow{border:0;color:var(--on-glow);font-weight:800;background:linear-gradient(90deg,var(--glow-1),var(--glow-2),var(--glow-3),var(--glow-2),var(--glow-1));
  background-size:200% 100%;animation:asFlow 8s linear infinite;box-shadow:0 10px 30px -8px var(--glow-2)}
.btn-glow:hover{color:var(--on-glow);background:linear-gradient(90deg,var(--glow-2),var(--glow-3),var(--glow-1),var(--glow-2));background-size:200% 100%}
.btn[aria-busy="true"]{pointer-events:none;opacity:.7}

/* 카드 · 구역 머리 */
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);padding:20px;box-shadow:var(--shadow)}
.card-featured{border:2px solid var(--accent)}
.sec{padding:72px 0}
.sec-head{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:flex-end;gap:16px;margin-bottom:28px}
.sec-lede{color:var(--muted);font-size:16px;margin-top:10px}
.eyebrow{font-size:13px;font-weight:700;letter-spacing:.5px;color:var(--accent)}  /* 한국어 머리말 — 영문 대문자용 넓은 자간을 쓰지 않는다 */
.eyebrow-stage{color:var(--stage-accent)}
/* 옅은 바탕 구역 — 흰 구역과 번갈아 */
.sec-tint{background:var(--hover)}
.sec-title{font-size:clamp(28px,3.2vw,42px);font-weight:900;margin-top:6px}

/* 카드 격자 — 폭 단계마다 열을 늘린다(S1 · M2 · L3 · XL4 · 2XL5) */
.grid{display:grid;gap:16px;grid-template-columns:repeat(1,minmax(0,1fr))}
@media (min-width:640px){.grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (min-width:1024px){.grid{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media (min-width:1440px){.grid{grid-template-columns:repeat(4,minmax(0,1fr))}}
@media (min-width:1920px){.grid{grid-template-columns:repeat(5,minmax(0,1fr))}}

/* 칩 — 보기만 하는 표시. 누르는 칩은 .pick */
.chip{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:var(--r-pill);font-size:12px;
  background:var(--hover);color:var(--muted);white-space:nowrap}
.chip-accent{background:var(--accent);color:var(--on-accent)}
.chip-stage{background:var(--stage-glass);color:var(--on-stage-2);border:1px solid var(--stage-line)}
/* AI 생성 표시 — 모든 쇼케이스 · 결과 소리 곁에(AI 기본법 제31조, 설계 17 §1) */
.chip-ai{background:var(--accent-soft);color:var(--accent-deep);font-weight:700}
.chip-dev{background:var(--warn-bg);color:var(--warn);font-weight:700}
/* 고르는 칩 — 장르 · 분야 · 거르기. aria-pressed 로 켠다 */
.pick{display:inline-flex;align-items:center;gap:6px;min-height:36px;padding:6px 14px;border-radius:var(--r-pill);
  border:1px solid var(--line-strong);background:var(--card);color:var(--text);font:inherit;font-size:14px;cursor:pointer;white-space:nowrap}
.pick:hover{background:var(--hover);color:var(--text)}
.pick[aria-pressed="true"]{background:var(--accent);border-color:var(--accent);color:var(--on-accent);font-weight:700}
.pick[aria-pressed="true"]:hover{background:var(--accent-deep);color:var(--on-accent)}
.pick-stage{background:var(--stage-glass);border-color:var(--stage-line);color:var(--on-stage-2)}
.pick-stage:hover{background:var(--stage-2);color:var(--on-stage)}
.pick-stage[aria-pressed="true"]{background:var(--stage-active);border-color:var(--stage-active);color:var(--on-stage-active)}
.pick-stage[aria-pressed="true"]:hover{background:var(--stage-active-hover);color:var(--on-stage-active)}
.picks{display:flex;flex-wrap:wrap;gap:8px}

/* 둘 중 하나 고르기(켜기 · 끄기 비교) */
.seg{display:inline-flex;padding:4px;border-radius:var(--r-pill);background:var(--hover);gap:4px}
.seg button{border:0;background:transparent;color:var(--muted);font:inherit;font-size:14px;font-weight:600;padding:8px 16px;border-radius:var(--r-pill);cursor:pointer}
.seg button[aria-pressed="true"]{background:var(--card);color:var(--text);box-shadow:var(--shadow)}

/* 표 — 좁으면 옆으로 민다 */
.table-box{overflow-x:auto}
.table{width:100%;border-collapse:collapse;font-size:14px}
.table th{text-align:left;font-weight:500;font-size:12px;color:var(--muted);padding:8px;border-bottom:1px solid var(--line)}
.table td{padding:10px 8px;border-bottom:1px solid var(--line);vertical-align:top}

/* 입력 */
.field{display:flex;flex-direction:column;gap:6px;font-size:13px}
.input{font:inherit;font-size:14px;padding:12px;border:1px solid var(--line-strong);border-radius:var(--r);
  background:var(--card);color:var(--text);min-height:44px}
.input::placeholder{color:var(--faint)}
.range{width:100%;accent-color:var(--accent)}

/* 오류 · 빈 화면 — 가운데 카드 하나 */
.center-card{max-width:520px;margin:96px auto;text-align:center;display:flex;flex-direction:column;gap:14px;align-items:center}
.center-card .code-big{font-size:56px;font-weight:900;color:var(--accent)}

/* 진행 표시 — 누른 즉시 단추 안에(조직 UX_BASICS) */
.spin{display:inline-block;width:16px;height:16px;border-radius:50%;border:2px solid currentColor;border-right-color:transparent;animation:asSpin .8s linear infinite}

/* 알림 상자 — 화면 안 안내(무슨 일 + 할 일) */
.alert{margin:0;padding:10px 14px;border-radius:var(--r-sm);font-size:14px;line-height:1.6}
.alert-bad{background:var(--bad-bg);color:var(--bad)}
.alert-ok{background:var(--ok-bg);color:var(--ok)}
.alert-warn{background:var(--warn-bg);color:var(--warn)}
.alert-info{background:var(--info-bg);color:var(--info)}

/* 모달 — <dialog class="modal">. 열기 · 닫기는 ui.js 의 asModal */
.modal{border:0;padding:0;border-radius:var(--r-xl);background:var(--card);color:var(--text);box-shadow:var(--shadow-pop);
  width:min(560px,calc(100vw - 32px));max-height:calc(100vh - 48px)}
.modal::backdrop{background:var(--stage-shade)}
.modal-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:18px 20px;border-bottom:1px solid var(--line)}
.modal-body{padding:20px;display:flex;flex-direction:column;gap:14px}
.modal-foot{display:flex;justify-content:flex-end;gap:8px;padding:14px 20px;border-top:1px solid var(--line)}
.icon-btn{display:grid;place-items:center;width:36px;height:36px;border-radius:var(--r-sm);border:0;background:transparent;color:var(--muted);cursor:pointer}
.icon-btn:hover{background:var(--hover);color:var(--text)}

/* 토스트 — 화면 아래에서 잠깐. 넣기는 ui.js 의 asToast */
.toasts{position:fixed;left:50%;transform:translateX(-50%);bottom:calc(var(--player-h) + 16px);z-index:90;display:flex;flex-direction:column;gap:8px;align-items:center;pointer-events:none}
.toast{pointer-events:auto;padding:10px 16px;border-radius:var(--r-pill);background:var(--text);color:var(--paper);font-size:14px;box-shadow:var(--shadow-lift);animation:asRise .25s ease-out}

/* 빛 번짐 — 무대 · 첫 구역 뒤에 깐다. <div class="as-glows"><span></span><span></span><span></span></div> */
.as-glows{position:absolute;inset:0;overflow:hidden;pointer-events:none;--glow-op:var(--glow-opacity)}
.as-glows.is-soft{--glow-op:calc(var(--glow-opacity) * .5)}
.as-glows span{position:absolute;border-radius:50%;filter:blur(90px);opacity:var(--glow-op);animation:asFloatA 18s ease-in-out infinite}
.as-glows span:nth-child(1){width:640px;height:640px;left:-140px;top:-160px;background:var(--glow-1)}
.as-glows span:nth-child(2){width:560px;height:560px;right:-120px;top:60px;background:var(--glow-2);animation-name:asFloatB;animation-duration:22s}
.as-glows span:nth-child(3){width:480px;height:480px;left:45%;bottom:-160px;background:var(--glow-3);
  opacity:calc(var(--glow-op) * .75);animation-duration:26s}

/* 물결 — 마크업은 templates/_waves.html, 경로는 services/waves.py */
.as-waves{display:block;width:100%;overflow:hidden;pointer-events:none}
.as-waves .g-a{stop-color:var(--grad-a)}.as-waves .g-b{stop-color:var(--grad-b)}.as-waves .g-c{stop-color:var(--grad-c)}
.as-waves path{opacity:var(--o,1);animation:asSlide var(--d,40s) linear infinite}
.as-waves .is-line{fill:none;stroke-width:1.4;vector-effect:non-scaling-stroke}
.as-waves .is-rev{animation-direction:reverse}
.as-waves .v-top{stop-opacity:1}.as-waves .v-mid{stop-opacity:.35}.as-waves .v-end{stop-opacity:0}

/* 그라데이션 글자 — 제목의 강조 낱말 */
.grad{background:linear-gradient(90deg,var(--grad-a),var(--grad-b) 45%,var(--grad-c));-webkit-background-clip:text;background-clip:text;color:transparent}

/* 공통 목록 부품(#38, templates/_list.html) — 도구줄(검색 · 거르기 · 기간) · 페이지 · 빈 목록 · 정렬 링크 */
.toolbar{display:flex;flex-direction:column;gap:8px;margin:0}
.toolbar-row{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.toolbar-grow{flex:1 1 220px;min-width:0}
.toolbar-pick{flex:0 1 180px;min-width:0}
@media (min-width:1024px){
  .toolbar{flex-direction:row;flex-wrap:wrap;align-items:center}
  .toolbar-row:first-of-type{flex:1 1 360px}
  .toolbar-row+.toolbar-row{flex:0 0 auto;flex-wrap:nowrap}
  .toolbar-pick{flex:0 0 160px}
}
.pager{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px}
.pager-btns{display:flex;gap:6px}
.pager .btn[aria-disabled="true"]{opacity:.45;pointer-events:none}
.list-empty{display:flex;flex-direction:column;align-items:center;gap:10px;padding:28px 16px;border:1px dashed var(--line-strong);
  border-radius:var(--r-lg);color:var(--muted);text-align:center}
.seg-links{display:flex;gap:4px;font-size:13px}
.seg-links a{padding:6px 10px;border-radius:var(--r-pill);color:var(--muted);text-decoration:none}
.seg-links a:hover{background:var(--hover);color:var(--text)}
.seg-links a[aria-current="true"]{background:var(--accent-soft);color:var(--accent-deep);font-weight:700}

/* 상태 칩(#63) — 성공 · 주의 · 문제 · 안내. 화면마다 따로 만들지 않는다 */
.chip-ok{background:var(--ok-bg);color:var(--ok);font-weight:700}
.chip-warn{background:var(--warn-bg);color:var(--warn);font-weight:700}
.chip-bad{background:var(--bad-bg);color:var(--bad);font-weight:700}
.chip-info{background:var(--accent-soft);color:var(--accent-deep);font-weight:700}

/* 화면 머리(#63) — 작은 제목 · 큰 제목 · 오른쪽 단추. 로그인 뒤 화면 · 관리 콘솔 · 갤러리가 같이 쓴다 */
.page-head{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:flex-end;gap:12px}
.page-head>div{display:flex;flex-direction:column;gap:4px;min-width:0}
.page-eyebrow{display:inline-flex;align-items:center;gap:6px;font-size:13px;font-weight:700;color:var(--accent)}
.page-title{font-size:clamp(24px,2.6vw,32px);font-weight:900}

/* 탭 줄(#63) — 화면 안의 갈래. 지금 탭은 aria-current="page" */
.tabs{display:flex;gap:4px;overflow-x:auto;border-bottom:1px solid var(--line)}
.tabs a{display:inline-flex;align-items:center;gap:6px;padding:10px 14px;color:var(--muted);text-decoration:none;font-size:14px;
  white-space:nowrap;border-bottom:2px solid transparent;margin-bottom:-1px}
.tabs a:hover{color:var(--text)}
.tabs a[aria-current="page"]{color:var(--text);font-weight:700;border-bottom-color:var(--accent)}

/* 표 카드(#63) — 테두리 · 머리 줄 바탕 · 숫자 칸. <div class="table-box table-card"><table class="table"> . 넓은 표는 table-wide */
.table-card{border:1px solid var(--line);border-radius:var(--r-lg);background:var(--card)}
.table-card .table{min-width:640px}
.table-card.table-wide .table{min-width:760px}
.table-card .table th,.table-card .table td{padding:10px 14px}
.table-card .table th{background:var(--hover)}
.table-card tr:last-child td{border-bottom:0}
.table-card td{overflow-wrap:break-word}  /* anywhere 는 body 의 어절 단위 줄바꿈을 무시하고 낱말 가운데서 자른다(「성/공」) */
.table-card th{white-space:nowrap}
.table-card .num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
/* 글자 단추 — 문장 안에서 링크처럼 보이는 동작(링크 복사 등). 이동은 <a>, 동작은 이것 */
.btn-text{padding:0;border:0;background:none;color:var(--accent);font:inherit;text-decoration:underline;text-underline-offset:2px;cursor:pointer}
.btn-text:hover{color:var(--accent-deep)}
/* 대행 보기 막대 — 슈퍼관리자가 회원 화면을 읽기 전용으로 보는 중(맨 위, 메뉴는 그 아래 고정) */
.view-as{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:8px 12px;
  padding:8px 16px;background:var(--warn-bg);color:var(--warn);border-bottom:1px solid var(--line-strong);font-size:13px}
/* 켜기 · 끄기 스위치 — <button role="switch" aria-checked> 가 폼을 보낸다(JS 없이). 첫 쓰임: 가입자 알림 메일(이슈 198) */
.toggle{flex:none;position:relative;width:44px;height:26px;padding:0;border:0;border-radius:999px;background:var(--line-strong);cursor:pointer;transition:background .15s}
.toggle[aria-checked="true"]{background:var(--accent)}
.toggle:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.toggle-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:var(--card);transition:transform .15s}
.toggle[aria-checked="true"] .toggle-knob{transform:translateX(18px)}

/* player.css */
/* 재생기 — 파형 곡 카드 · 하단 미니 재생기 · 실시간 막대(설계 17 §8). 마크업은 templates/_player.html, 동작은 js/player.js.
   파형은 서버가 봉우리로 그린 SVG 막대라 JS 를 기다리지 않고 바로 보인다. JS 는 들은 만큼(--p)만 칠한다 */

/* 파형 — 두 겹(안 들은 막대 위에 들은 막대를 --p 만큼 잘라 얹는다). 누르면 그 자리로 간다 */
.wave{position:relative;height:var(--wave-h,48px);cursor:pointer;touch-action:none;--p:0%}
.wave svg{position:absolute;inset:0;width:100%;height:100%;display:block}
.wave .w-base{fill:var(--wave)}
.wave .w-played{fill:var(--wave-played);clip-path:inset(0 calc(100% - var(--p)) 0 0)}
.wave-stage .w-base{fill:var(--wave-stage)}
.wave-stage .w-played{fill:var(--wave-stage-played)}
/* 막대(rect)에는 색을 두지 않는다 — 들은 겹은 <use> 로 같은 막대를 가져오므로 겹(svg)의 색을 물려받게 한다 */
/* 고른 구간(고치기 예시) — --a · --b 는 0~100% */
.wave-sel{position:absolute;top:-4px;bottom:-4px;left:var(--a);width:calc(var(--b) - var(--a));background:var(--wave-sel);
  border-left:2px solid var(--wave-sel-line);border-right:2px solid var(--wave-sel-line);border-radius:var(--r-sm);pointer-events:none}
.wave:focus-visible{outline:2px solid var(--accent);outline-offset:4px;border-radius:var(--r-sm)}

/* 곡 카드 — 표지 · 재생 단추 · 제목 · 파형 · 시간 */
.track{display:grid;grid-template-columns:auto 1fr;gap:14px;align-items:center;padding:14px;border-radius:var(--r-lg);
  background:var(--card);border:1px solid var(--line);box-shadow:var(--shadow);transition:box-shadow .2s,border-color .2s}
.track:hover{box-shadow:var(--shadow-lift)}
.track.is-playing{border-color:var(--accent);box-shadow:var(--shadow-lift)}
.track-cover{position:relative;width:72px;height:72px;border-radius:var(--r);overflow:hidden;background:linear-gradient(135deg,var(--glow-1),var(--glow-2),var(--glow-3))}
.track-cover img{width:100%;height:100%;object-fit:cover}
.track-main{display:flex;flex-direction:column;gap:6px;min-width:0}
.track-head{display:flex;justify-content:space-between;gap:8px;align-items:baseline}
.track-title{font-weight:800;font-size:15px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.track-sub{font-size:12px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.track-time{display:flex;justify-content:space-between;font:12px var(--mono);color:var(--faint);font-variant-numeric:tabular-nums}
.track-tags{display:flex;flex-wrap:wrap;gap:6px}

/* 재생 단추 — 원. 표지 위에 얹을 때는 .play-on-cover */
.play{display:grid;place-items:center;width:44px;height:44px;border-radius:50%;border:0;cursor:pointer;
  background:var(--accent);color:var(--on-accent);box-shadow:0 8px 20px -8px var(--accent)}
.play:hover{background:var(--accent-deep);color:var(--on-accent)}
.play .ico-pause{display:none}
.is-playing .play .ico-play,.play[aria-pressed="true"] .ico-play{display:none}
.is-playing .play .ico-pause,.play[aria-pressed="true"] .ico-pause{display:block}
.play-on-cover{position:absolute;inset:0;margin:auto;width:40px;height:40px;background:var(--stage-glass);color:var(--on-stage);box-shadow:none;
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.play-on-cover:hover{background:var(--stage-shade);color:var(--on-stage)}
.play-xl{width:88px;height:88px;background:var(--stage-active);color:var(--on-stage-active);box-shadow:0 0 0 10px var(--stage-glass),0 20px 60px -10px var(--glow-2)}
.play-xl .ico{width:48px;height:48px}
.play-sm{width:36px;height:36px}
.play-xl:hover{background:var(--stage-active-hover);color:var(--on-stage-active)}

/* 재생 중 표시 — 작은 막대 셋이 오르내린다 */
.eq{display:inline-flex;gap:2px;align-items:flex-end;height:12px}
.eq i{width:3px;height:100%;border-radius:1px;background:currentColor;transform-origin:bottom;transform:scaleY(.3)}
.is-playing .eq i{animation:asBar .8s ease-in-out infinite}
.is-playing .eq i:nth-child(2){animation-delay:-.25s}
.is-playing .eq i:nth-child(3){animation-delay:-.5s}

/* 실시간 막대 — Web Audio 분석기가 그린다(canvas). 소리가 없으면 잔잔한 물결 */
.live{display:block;width:100%;height:var(--live-h,120px)}

/* 하단 미니 재생기 — 화면을 옮겨도 이어 듣는다. 처음엔 없고, 무엇이든 재생하면 생긴다 */
.mini{position:fixed;left:0;right:0;bottom:0;z-index:80;height:var(--player-h);background:var(--gn-bg);border-top:1px solid var(--gn-line);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);box-shadow:var(--gn-shadow)}
.mini-in{display:grid;grid-template-columns:auto minmax(0,220px) 1fr auto;gap:16px;align-items:center;height:100%}
.mini-info{display:flex;flex-direction:column;min-width:0}
.mini-title{font-weight:800;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mini-sub{font-size:12px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mini-bar{display:flex;align-items:center;gap:10px;font:12px var(--mono);color:var(--faint);font-variant-numeric:tabular-nums}
.mini-prog{position:relative;flex:1 1 auto;height:6px;border-radius:var(--r-pill);background:var(--wave);cursor:pointer;--p:0%}
.mini-prog i{position:absolute;left:0;top:0;bottom:0;width:var(--p);border-radius:var(--r-pill);background:linear-gradient(90deg,var(--glow-1),var(--glow-2),var(--glow-3))}
.mini-prog:focus-visible{outline:2px solid var(--accent);outline-offset:4px}
.mini .play{width:40px;height:40px}
@media (max-width:639px){
  .mini-in{grid-template-columns:auto 1fr auto;gap:10px}
  .mini-bar span{display:none}
}
/* 미니 재생기가 떠 있으면 바닥글이 그 밑에 숨지 않게 */
.has-mini{padding-bottom:var(--player-h)}

/* 레코드판 표지(#65, _player.html disc) — 홈 · 딱지 · 둘레 파형. 색은 장르색 토큰(--series-*) 하나 */
.disc{position:absolute;inset:5px;display:block;border-radius:50%;box-shadow:var(--shadow-lift);background:radial-gradient(circle at 50% 50%,var(--disc) 0 17%,var(--card) 17% 19%,
  var(--ink) 19% 100%)}
.disc::before{content:"";position:absolute;inset:12%;border-radius:50%;
  background:repeating-radial-gradient(circle at 50% 50%,transparent 0 3px,var(--ink-line) 3px 4px)}
/* 픽처 디스크(#83) — 표지 그림을 판 전체에 깔고, 눈금이 도는 바깥 띠만 짙게 덮어 진행이 그림 위에서도 보인다 */
.disc-art{background:radial-gradient(circle closest-side,transparent 0 72%,color-mix(in srgb,var(--ink) 78%,transparent) 74% 100%),
  var(--disc-img) center/cover}
.disc-art::before{opacity:.35}
.disc svg{position:absolute;inset:0;width:100%;height:100%}
.disc-bar{fill:var(--disc);opacity:.85;transition:opacity .3s}
/* 재생 진행(#74, player.js dial) — 표지는 그대로, 들은 만큼 위에서부터 시계 방향으로 눈금이 밝아진다(--deg).
   밝은 겹은 같은 눈금을 원뿔 그라데이션으로 가려 끊김 없이 드러낸다. 끝의 점이 지금 자리 */
.disc-lit{-webkit-mask:conic-gradient(var(--ink) var(--deg,0deg),transparent 0);mask:conic-gradient(var(--ink) var(--deg,0deg),transparent 0)}
.disc-lit .disc-bar{fill:var(--on-glow);opacity:1}
.disc.is-live > svg:first-of-type .disc-bar{opacity:.35}
.disc-head{position:absolute;inset:0;transform:rotate(var(--deg,0deg));opacity:0;transition:opacity .3s}
.disc-head::after{content:"";position:absolute;left:50%;top:3%;width:9%;height:0;padding-top:9%;margin-left:-4.5%;border-radius:50%;
  background:var(--disc);box-shadow:0 0 0 2px var(--on-glow),0 0 10px 3px var(--disc)}
.disc.is-live .disc-head{opacity:1}

/* sections.css */
/* 공개 화면 구역 부품 — 첫 화면과 기능 페이지가 함께 쓴다(설계 27 §4-7). 마크업은 templates/_demos.html, 동작은 js/demos.js.
   이 파일의 클래스는 다른 파일에서 다시 정의하지 않는다(시험이 막는다). 화면에만 있는 배치는 pages/*.css */

/* 무대 카드 — 장르 칩 · 실시간 막대 · 가사 */
.stage-card{position:relative;display:flex;flex-direction:column;gap:16px;padding:22px;border-radius:var(--r-xl);background:var(--stage-glass);
  border:1px solid var(--stage-line);-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);box-shadow:var(--shadow-pop)}
.stage-top{display:flex;gap:18px;align-items:center}
.stage-now{flex:1 1 auto;min-width:0}
.stage-panel{display:flex;flex-direction:column;gap:6px}
.stage-genre{font-size:12px;font-weight:700;letter-spacing:1px;color:var(--stage-accent)}
.stage-title{font-size:22px;font-weight:900;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.stage-time{color:var(--on-stage-dim)}
.stage-card .live{--live-h:96px;border-radius:var(--r)}
/* 가사 칸은 높이를 고정한다 — 곡을 바꿔도 카드 높이가 그대로(가사가 없으면 빈 채로, 길면 칸 안에서 스크롤) */
.stage-lyrics{height:var(--stage-lyrics-h,200px)}
.stage-lyrics .lyrics{position:relative;height:100%;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin}
.stage-lyrics .lyrics-none{height:100%;display:flex;align-items:center;justify-content:center;text-align:center}
.lyrics{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px;font-size:16px;color:var(--on-stage-dim)}
.lyrics li{padding:4px 10px;border-radius:var(--r-sm);transition:color .3s,background .3s,transform .3s}
.lyrics li.is-on{color:var(--on-stage);background:var(--stage-line);transform:translateX(6px);font-weight:700}
.lyrics .lyrics-none{font-size:14px}
.stage-picks{gap:6px}
.stage-note{font-size:12px;color:var(--on-stage-dim);display:flex;gap:8px;align-items:center;flex-wrap:wrap}

/* 한 줄 → 노래 */
.flow{display:grid;gap:16px}
@media (min-width:1024px){.flow{grid-template-columns:repeat(3,minmax(0,1fr))}}
.flow-step{display:flex;flex-direction:column;gap:12px;padding:20px;border-radius:var(--r-lg);background:var(--card);border:1px solid var(--line)}
.flow-no{display:grid;place-items:center;width:28px;height:28px;border-radius:50%;background:var(--accent-soft);color:var(--accent-deep);font-weight:900;font-size:14px}
.prompt-box{display:flex;gap:10px;align-items:flex-start;padding:16px;border-radius:var(--r);background:var(--hover);font-size:17px;font-weight:700;color:var(--accent-deep)}
.filled{display:flex;flex-direction:column;gap:8px}
.filled-caption{font-size:13px;color:var(--muted)}
.filled-lyrics{margin:0;padding:12px;border-radius:var(--r);background:var(--hover);font:13px/1.7 var(--sans);white-space:pre-wrap;max-height:220px;overflow:auto}
.lyrics-card{color:var(--muted);font-size:14px}
.lyrics-card li.is-on{color:var(--accent-deep);background:var(--accent-soft)}

/* 사운드보드 */
.board{display:grid;gap:12px;grid-template-columns:repeat(2,minmax(0,1fr))}
@media (min-width:640px){.board{grid-template-columns:repeat(4,minmax(0,1fr))}}
@media (min-width:1440px){.board{grid-template-columns:repeat(8,minmax(0,1fr))}}
.pad{position:relative;overflow:hidden;display:flex;flex-direction:column;align-items:flex-start;gap:6px;min-height:118px;padding:16px;border-radius:var(--r-lg);
  border:1px solid var(--line);background:var(--card);color:var(--text);font:inherit;text-align:left;cursor:pointer;box-shadow:var(--shadow);transition:transform .15s,box-shadow .2s,border-color .2s}
.pad:hover{transform:translateY(-2px);box-shadow:var(--shadow-lift);border-color:var(--accent-line);background:var(--card)}
.pad:disabled{opacity:.5;cursor:not-allowed;transform:none}
.pad-ico{display:grid;place-items:center;width:44px;height:44px;border-radius:var(--r);color:var(--on-accent);
  background:linear-gradient(135deg,var(--glow-1),var(--glow-2))}
.pad[data-cat="환경"] .pad-ico{background:linear-gradient(135deg,var(--series-4),var(--series-5))}
.pad[data-cat="도시"] .pad-ico{background:linear-gradient(135deg,var(--series-5),var(--glow-1))}
.pad[data-cat="액션"] .pad-ico{background:linear-gradient(135deg,var(--glow-2),var(--glow-3))}
.pad[data-cat="동물"] .pad-ico{background:linear-gradient(135deg,var(--glow-3),var(--series-3))}
.pad[data-cat="UI"] .pad-ico,.pad[data-cat="사람"] .pad-ico{background:linear-gradient(135deg,var(--series-1),var(--series-4))}
.pad-label{font-weight:800}
.pad-cat{font-size:12px;color:var(--faint)}
.pad.is-on{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft),var(--shadow-lift)}
.pad.is-on::after{content:"";position:absolute;left:38px;top:38px;width:40px;height:40px;margin:-20px;border-radius:50%;
  border:2px solid var(--accent);animation:asRipple 1.2s ease-out infinite;pointer-events:none}

/* 영상 → 소리 · 글과 그림 나란히 */
.split{display:grid;gap:32px;align-items:center}
@media (min-width:1024px){.split{grid-template-columns:minmax(0,5fr) minmax(0,7fr)}}
.split-copy{display:flex;flex-direction:column;gap:14px;align-items:flex-start}
.cues{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px;width:100%}
.cues li{display:flex;gap:12px;align-items:center;padding:8px 12px;border-radius:var(--r);background:var(--hover);color:var(--muted);transition:background .3s,color .3s}
.cues li.is-on{background:var(--accent-soft);color:var(--accent-deep);font-weight:700}
.cue-t{font:12px var(--mono);color:var(--faint)}
.video-box{position:relative;border-radius:var(--r-xl);overflow:hidden;background:var(--stage);box-shadow:var(--shadow-lift)}
.video-box video,.video-empty img{display:block;width:100%;aspect-ratio:16/9;object-fit:cover}
.video-bar{position:absolute;left:12px;right:12px;bottom:12px;display:flex;justify-content:space-between;gap:8px;flex-wrap:wrap}
.video-empty{position:relative;aspect-ratio:16/9;display:grid;place-items:center}
.video-empty img{position:absolute;inset:0}
.video-empty .chip{position:relative}

/* 고치기 — 바꿔 듣기 */
.edit-grid{display:grid;gap:16px}
@media (min-width:1024px){.edit-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
.edit-card{display:flex;flex-direction:column;gap:12px}
.edit-head{display:flex;gap:10px;align-items:center;font-size:17px}
.switch{display:flex;flex-direction:column;gap:14px}
.switch-bar{display:flex;gap:12px;align-items:center;flex-wrap:wrap}

/* 요금 · 자주 묻는 질문 */
.costs{display:grid;gap:12px;grid-template-columns:repeat(2,minmax(0,1fr))}
@media (min-width:1024px){.costs{grid-template-columns:repeat(4,minmax(0,1fr))}}
.cost{display:flex;flex-direction:column;gap:6px;padding:18px;border-radius:var(--r-lg);background:var(--card);border:1px solid var(--line)}
.cost-v{font-size:28px;font-weight:900;color:var(--accent)}
.cost-v small{font-size:13px;font-weight:500;color:var(--muted);margin-left:4px}
.faq-wrap{display:flex;flex-direction:column;gap:20px}
.faq{display:flex;flex-direction:column;gap:8px}
.faq details{border:1px solid var(--line);border-radius:var(--r-lg);background:var(--card);padding:0 18px}
.faq summary{cursor:pointer;padding:16px 0;font-weight:700}
.faq details p{padding:0 0 16px;color:var(--muted)}


/* 무대 구역 · 수치 — 첫 화면 엔진 구역 · 기능 페이지 무대 */
.sec-stage{position:relative;overflow:hidden;background:var(--stage);color:var(--on-stage)}
.sec-stage .wrap{position:relative}
.stats{display:grid;gap:16px;grid-template-columns:repeat(2,minmax(0,1fr));margin-bottom:28px}
@media (min-width:1024px){.stats{grid-template-columns:repeat(4,minmax(0,1fr))}}
.stat{display:flex;flex-direction:column;gap:4px;padding:20px;border-radius:var(--r-lg);background:var(--stage-glass);border:1px solid var(--stage-line)}
.stat-v{font-size:clamp(32px,4vw,52px);font-weight:900;background:linear-gradient(90deg,var(--grad-a),var(--grad-b),var(--grad-c));-webkit-background-clip:text;background-clip:text;color:transparent}
.stat-l{font-weight:700}
.stat-n{font-size:12px;color:var(--on-stage-dim)}

/* 기능 카드 — 첫 화면 「네 가지 일」 · 기능 페이지 「다음 기능」 · 같은 자료(features.yml) */
.feat-grid{display:grid;gap:16px;grid-template-columns:repeat(1,minmax(0,1fr))}
@media (min-width:640px){.feat-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (min-width:1024px){.feat-grid{grid-template-columns:repeat(var(--cols,4),minmax(0,1fr))}}
.feat-card{display:flex;flex-direction:column;gap:8px;padding:20px;border-radius:var(--r-lg);background:var(--card);border:1px solid var(--line);
  box-shadow:var(--shadow);transition:box-shadow .2s,border-color .2s,transform .15s}
.feat-card:hover{box-shadow:var(--shadow-lift);border-color:var(--accent-line);transform:translateY(-2px)}
.feat-card.is-playing{border-color:var(--accent)}
.feat-top{display:flex;justify-content:space-between;align-items:center;gap:8px}
.feat-ico{display:grid;place-items:center;width:44px;height:44px;border-radius:var(--r);color:var(--on-accent);
  background:linear-gradient(135deg,var(--glow-1),var(--glow-2))}
.feat-name{font-size:18px;font-weight:900}
.feat-line{color:var(--muted);font-size:14px}
.feat-stat{font-size:13px;color:var(--muted)}
.feat-stat b{font-family:var(--mono);color:var(--text)}
.feat-more{margin-top:auto;font-weight:700;font-size:14px;text-decoration:none}
/* 구역 끝의 「자세히」 — 기능 페이지로 */
.sec-more{display:inline-flex;align-items:center;gap:6px;font-weight:700;text-decoration:none;white-space:nowrap}
/* 구역 머리 오른쪽 단추 묶음 */
.sec-acts{display:flex;flex-wrap:wrap;gap:12px;align-items:center}
.sec-stage .sec-more{color:var(--stage-accent)}

/* 가사 무대(#46, templates/_lyrics.html) — 작품 상세 · 편집기가 같이 쓴다. 지금 줄 크게 · 지나간 줄 흐리게 · 낱말은 부르는 만큼 */
.ly{display:flex;flex-direction:column;gap:10px;padding:20px;border-radius:var(--r-xl);background:var(--card);border:1px solid var(--line)}
.ly-bar{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.ly-tools{display:flex;flex-wrap:wrap;gap:6px;margin-left:auto}
.ly-lines{position:relative;list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px;max-height:440px;overflow-y:auto;
  font-size:18px;line-height:1.6;color:var(--faint);overscroll-behavior:contain}
.ly-lines li[data-t]{cursor:pointer;padding:4px 10px;border-radius:var(--r-sm);transition:color .3s,font-size .3s}
.ly-lines li[data-t]:hover{background:var(--hover)}
.ly-lines li.is-past{color:var(--muted)}
.ly-lines li.is-on{color:var(--text);font-size:22px;font-weight:800}
.ly-lines li.is-on [data-wt]{color:var(--faint);transition:color .15s}
.ly-lines li.is-on [data-wt].is-sung{color:var(--accent-deep)}
.ly-sec{margin-top:10px}
.ly-plain{margin:0;white-space:pre-wrap;font:15px/1.9 var(--sans);overflow-wrap:break-word}
/* 전체 화면 — 무대색 위 가운데 큰 가사, 뒤의 빛이 박자(--beat = 60/BPM 초)에 맞춰 숨쉰다 */
.ly:fullscreen{position:relative;isolation:isolate;overflow:hidden;justify-content:center;padding:6vh 8vw;border:0;border-radius:0;
  background:var(--stage);color:var(--on-stage)}
.ly:fullscreen::before{content:"";position:absolute;inset:-20%;z-index:-1;pointer-events:none;
  background:radial-gradient(circle at 30% 40%,var(--glow-1),transparent 55%),radial-gradient(circle at 70% 65%,var(--glow-2),transparent 55%);
  animation:ly-breathe var(--beat,1s) ease-in-out infinite alternate}
.ly:fullscreen .ly-bar .title-sm,.ly:fullscreen .chip{color:var(--on-stage-2)}
.ly:fullscreen .ly-lines{max-height:none;align-items:center;text-align:center;font-size:clamp(22px,2.8vw,38px);color:var(--on-stage-dim)}
.ly:fullscreen .ly-lines li[data-t]:hover{background:var(--stage-glass)}
.ly:fullscreen .ly-lines li.is-past{color:var(--on-stage-dim)}
.ly:fullscreen .ly-lines li.is-on{color:var(--on-stage);font-size:clamp(30px,4.2vw,58px)}
.ly:fullscreen .ly-lines li.is-on [data-wt]{color:var(--on-stage-dim)}
.ly:fullscreen .ly-lines li.is-on [data-wt].is-sung{color:var(--grad-b)}

/* code.css */
/* 코드 판 — 언어 탭 · 복사 · 구문 강조. 늘 어두운 판(토큰 --ink · --syn-*). 마크업은 templates/_code.html, 동작은 js/code_tabs.js */
.ctab{border-radius:var(--r-lg);background:var(--ink);border:1px solid var(--ink-line);overflow:hidden;color:var(--ink-fg)}
.ctab-bar{display:flex;align-items:center;gap:12px;padding:8px 10px 8px 14px;background:var(--ink-2);border-bottom:1px solid var(--ink-line)}
.ctab-dots{display:flex;gap:6px}
.ctab-dots i{width:10px;height:10px;border-radius:50%;background:var(--ink-line)}
.ctab-tabs{display:flex;gap:2px}
.ctab-tab{border:0;background:transparent;color:var(--ink-dim);font:600 13px var(--sans);padding:6px 10px;border-radius:var(--r-sm);cursor:pointer}
.ctab-tab:hover{color:var(--ink-fg)}
.ctab-title{flex:1 1 auto;min-width:0;text-align:right;font:12px var(--mono);color:var(--ink-dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ctab-copy{border:1px solid var(--ink-line);background:transparent;color:var(--ink-fg);font:600 12px var(--sans);
  padding:5px 10px;border-radius:var(--r-sm);cursor:pointer;white-space:nowrap}
.ctab-copy:hover{background:var(--ink-line)}
.ctab-code{margin:0;padding:18px 20px;overflow-x:auto;font:13px/1.7 var(--mono);tab-size:2}
.ctab-code code{font:inherit;background:none;padding:0;color:inherit}

/* 고른 언어만 보인다 — 기본은 node, 머리 스크립트가 html[data-lang] 을 정한다 */
.ctab-code[data-lang="python"]{display:none}
:root[data-lang="python"] .ctab-code[data-lang="node"]{display:none}
:root[data-lang="python"] .ctab-code[data-lang="python"]{display:block}
.ctab-tab[data-lang-set="node"],:root[data-lang="python"] .ctab-tab[data-lang-set="python"]{color:var(--ink-fg);background:var(--ink-line)}
:root[data-lang="python"] .ctab-tab[data-lang-set="node"]{color:var(--ink-dim);background:transparent}

/* 구문 강조(pygments 클래스, 접두어 tk-) */
.tk-k,.tk-kd,.tk-kn,.tk-kc,.tk-kr,.tk-ow{color:var(--syn-key)}
.tk-s,.tk-s1,.tk-s2,.tk-sb,.tk-sd,.tk-dl,.tk-sa,.tk-si,.tk-se{color:var(--syn-str)}
.tk-mi,.tk-mf,.tk-m{color:var(--syn-num)}
.tk-c,.tk-c1,.tk-cm,.tk-ch,.tk-cs{color:var(--syn-com);font-style:italic}
.tk-nf,.tk-fm,.tk-nb,.tk-bp,.tk-nc{color:var(--syn-fn)}
.tk-nv,.tk-no,.tk-nt,.tk-na{color:var(--syn-prop)}
.tk-o,.tk-p{color:var(--ink-dim)}

/* nav.css */
/* 상단 메뉴 · 테마 단추 · 폭 단계 표시 · 바닥글 — 형태 원본: project-voice-studio nav.css. 계정 칸 · 로그인 입구(#37) */
.gnav{position:sticky;top:0;z-index:50;background:var(--gn-bg);border-bottom:1px solid var(--gn-line);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}
/* 슈퍼관리자 화면 — 주황빛 바로 중요한 화면임을 알린다(이슈 200) */
.gnav-admin{background:var(--gn-admin-bg);border-bottom-color:var(--gn-admin-line)}
.gnav-in{display:flex;align-items:center;gap:20px;min-height:var(--gn-h)}
.gnav-logo{display:flex;align-items:center;gap:10px;font-weight:900;font-size:18px;color:var(--gn-on);text-decoration:none;white-space:nowrap}
.gnav-logo:hover{color:var(--gn-on)}
.gnav-mark{display:block;flex:none}
.gnav-ver{margin-left:-4px;font-weight:400;font-family:var(--mono);font-size:11px;color:var(--gn-fg);white-space:nowrap}  /* 로고 옆 버전(이슈 203) */
.gnav-links{display:flex;gap:2px;flex:1 1 auto}
.gnav-links a{padding:8px 12px;border-radius:var(--r-sm);color:var(--gn-fg);text-decoration:none;font-size:14px}
.gnav-links a:hover{background:var(--gn-hover);color:var(--gn-on)}
.gnav-links a[aria-current="page"]{background:var(--gn-on-bg);color:var(--gn-on);font-weight:700}
/* 「기능」 펼침 — 기능마다 아이콘 · 이름 · 한 줄 · 대표 수치. 왼쪽에 붙어 열린다 */
.gnav-feat-btn{display:flex;align-items:center;gap:4px;padding:8px 12px;border-radius:var(--r-sm);color:var(--gn-fg);font-size:14px}
.gnav-feat-btn:hover,.gnav-feat[open]>.gnav-feat-btn{background:var(--gn-hover);color:var(--gn-on)}
.gnav-feat-btn[aria-current="page"]{background:var(--gn-on-bg);color:var(--gn-on);font-weight:700}
.gnav-menu.gnav-mega{left:0;right:auto;min-width:340px;padding:8px}
.gnav-menu.gnav-mega a{justify-content:flex-start;align-items:center;gap:12px;padding:10px 12px}
.mega-ico{display:grid;place-items:center;flex:none;width:36px;height:36px;border-radius:var(--r-sm);color:var(--on-accent);background:linear-gradient(135deg,var(--glow-1),var(--glow-2))}
.mega-txt{display:flex;flex-direction:column;gap:2px;min-width:0}
.mega-txt b{color:var(--gn-on);font-size:14px}
.mega-txt small{color:var(--gn-fg);font-size:12px;text-wrap:pretty}
.gnav-sep{border:0;border-top:1px solid var(--gn-line);margin:6px 4px;width:calc(100% - 8px)}
/* 슈퍼관리자 영역(#97) — 구분선 사이 이름표 · 관리자 색. 일반 메뉴와 섞여 보이지 않게 */
.gnav-sep-admin{display:flex;align-items:center;gap:6px;margin:10px 4px 4px;font-size:11px;font-weight:700;letter-spacing:.04em;color:var(--admin)}
.gnav-sep-admin::before,.gnav-sep-admin::after{content:"";flex:1 1 auto;height:1px;background:var(--admin-line)}
.gnav-menu a.gnav-admin{color:var(--admin);font-weight:600}
.gnav-menu a.gnav-admin:hover,.gnav-menu a.gnav-admin[aria-current="page"]{background:var(--admin-soft);color:var(--admin)}
.gnav-right{display:flex;align-items:center;gap:6px;margin-left:auto}
.gnav-dev{font-size:11px;padding:3px 8px}
.gnav-cta{min-height:36px;padding:6px 14px;font-size:14px}

/* 펼침 칸 — 테마 · 계정 · 휴대폰 메뉴(#76). <details> 라 JS 없이도 열린다. 하나만 열고 바깥을 누르면 닫는 것은 ui.js */
.gnav-pop{position:relative}
.gnav-pop>summary{list-style:none;cursor:pointer}
.gnav-pop>summary::-webkit-details-marker{display:none}
.gnav-icon{display:flex;align-items:center;gap:4px;height:36px;padding:0 10px;border-radius:var(--r-sm);color:var(--gn-fg)}
.gnav-icon:hover,.gnav-pop[open]>.gnav-icon{background:var(--gn-hover);color:var(--gn-on)}
.gnav-caret{opacity:.7;transition:transform .2s}
.gnav-pop[open] .gnav-caret{transform:rotate(180deg)}
.gnav-menu{position:absolute;right:0;top:calc(100% + 8px);z-index:60;min-width:180px;padding:6px;border-radius:var(--r);
  background:var(--gn-panel);border:1px solid var(--gn-line);box-shadow:var(--gn-shadow);display:flex;flex-direction:column}
.gnav-menu a,.gnav-menu button{display:flex;justify-content:space-between;gap:12px;width:100%;padding:9px 10px;border:none;
  border-radius:var(--r-sm);background:transparent;color:var(--gn-fg);font:inherit;font-size:14px;text-align:left;text-decoration:none;cursor:pointer}
.gnav-menu a:hover,.gnav-menu button:hover{background:var(--gn-hover);color:var(--gn-on)}
.gnav-menu a[aria-current="page"]{color:var(--gn-on);font-weight:700}
.gnav-menu form{margin:0}
.theme-menu button[aria-checked="true"]{color:var(--gn-on);font-weight:700}
.theme-menu button[aria-checked="true"]::after{content:"✓"}

/* 로그인 입구 하나 — 옅은 알약 */
.gnav-login{display:inline-flex;align-items:center;height:36px;padding:0 14px;border-radius:var(--r-sm);
  background:var(--gn-on-bg);color:var(--gn-on);font-size:14px;font-weight:700;text-decoration:none;white-space:nowrap}
.gnav-login:hover{color:var(--gn-on);box-shadow:inset 0 0 0 1px var(--gn-line)}

/* 로그인한 사람 — 머리글자 · 이름 ▾ → 등급 · 남은 크레딧 · 내 계정 · 로그아웃 */
.gnav-me{display:flex;align-items:center;gap:8px;height:36px;padding:0 8px 0 4px;border-radius:var(--r-pill);font-size:14px;
  color:var(--gn-on);white-space:nowrap}
.gnav-me:hover,.gnav-pop[open]>.gnav-me{background:var(--gn-hover)}
.gnav-avatar{display:grid;place-items:center;width:28px;height:28px;border-radius:50%;font-size:13px;font-weight:800;
  color:var(--on-stage);background:linear-gradient(135deg,var(--logo-a),var(--logo-b))}
.gnav-avatar-lg{flex:none;width:40px;height:40px;font-size:16px}
.gnav-who{display:flex;align-items:center;gap:12px;padding:8px 10px 12px;margin-bottom:4px;border-bottom:1px solid var(--gn-line);
  font-size:12px;color:var(--gn-fg)}
.gnav-who>div{display:flex;flex-direction:column;gap:2px;min-width:0}
.gnav-who b{color:var(--gn-on);font-size:14px}
.gnav-who span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gnav-who-role{margin-top:2px;color:var(--gn-on);font-weight:600}
.gnav-account .gnav-menu{min-width:260px;max-width:min(320px,calc(100vw - 32px))}
.gnav-account .gnav-menu a,.gnav-account .gnav-menu button{justify-content:flex-start;align-items:center;gap:10px}
.gnav-account .gnav-menu a.gnav-credit{justify-content:space-between;font-size:13px}
.gnav-credit b{color:var(--gn-on);font-variant-numeric:tabular-nums}

/* 지금 폭 단계 — 화면이 어느 모양인지 바로 말할 수 있게(조직 RESPONSIVE.md). 작고 옅게 */
.bp{font:700 10px/1 var(--mono);color:var(--gn-fg);opacity:.7;border:1px solid var(--gn-line);border-radius:var(--r-sm);
  padding:4px 5px;min-width:26px;text-align:center}
.bp::after{content:"S"}
@media (min-width:640px){.bp::after{content:"M"}}
@media (min-width:1024px){.bp::after{content:"L"}}
@media (min-width:1440px){.bp::after{content:"XL"}}
@media (min-width:1920px){.bp::after{content:"2XL"}}

/* 태블릿 — 「만들기」 단추가 생기면 계정 이름까지는 한 줄에 못 들어간다. 머리글자만 */
@media (max-width:1023px){.gnav-me b,.gnav-dev,.theme .gnav-caret{display:none}.gnav-in{gap:12px}.gnav-links a,.gnav-feat-btn{padding:8px 10px}}

/* 휴대폰 — 메뉴는 ☰ 안으로 접는다. 한 줄을 넘기지 않는다 */
.gnav-burger{display:none}
@media (max-width:639px){
  .gnav-in{gap:8px}
  .gnav-links{display:none}
  .gnav-burger{display:block}
  .gnav-right{gap:2px}
  .gnav-dev,.theme .gnav-caret,.gnav-me b,.gnav-make{display:none}
  .gnav-icon{padding:0 8px}
}

.gfoot{border-top:1px solid var(--line);padding:32px 0;font-size:12px;color:var(--faint);line-height:1.8}
.gfoot a{color:var(--muted)}
.gfoot-ver{font-family:var(--mono);font-size:11px}

/* 물결 장식(#31) — 메뉴 아래 흐르는 그라데이션 선 · 로고 위에 올리면 레코드판이 돈다 · 바닥글 위 겹친 물결 */
.gnav::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;opacity:.55;pointer-events:none;
  background:linear-gradient(90deg,transparent,var(--grad-a),var(--grad-b),var(--grad-c),var(--grad-a),transparent);
  background-size:200% 100%;animation:asFlow 12s linear infinite}
.gnav-name{background:linear-gradient(90deg,var(--gn-on),var(--gn-on));-webkit-background-clip:text;background-clip:text;
  background-size:200% 100%}
.gnav-logo:hover .gnav-name,.gnav-logo:focus-visible .gnav-name{color:transparent;
  background-image:linear-gradient(90deg,var(--logo-a),var(--logo-b),var(--logo-c),var(--logo-b),var(--logo-a));animation:asFlow 2.4s linear infinite}
/* 로고에 올리면 레코드판이 돈다(#68) */
.gnav-disc{transform-origin:32px 32px;transform-box:view-box}
.lg-a{stop-color:var(--logo-a)}
.lg-b{stop-color:var(--logo-b)}
.lg-c{stop-color:var(--logo-c)}
.gnav-logo:hover .gnav-disc,.gnav-logo:focus-visible .gnav-disc{animation:asSpin 1.6s linear infinite}

.gfoot{position:relative;margin-top:120px;border-top:0;padding-top:72px;background:transparent}
/* 물결이 바닥글 안쪽으로 80px 걸쳐 내려와 겹마다 완만하게 투명해진다 — 바닥글에 따로 바탕색을 두지 않아 경계가 없다 */
.gfoot > .as-waves{position:absolute;left:0;right:0;bottom:calc(100% - 80px);height:150px}
