/**
 * SING:ON — 프로젝트 토큰과 공통 스타일
 *
 * 정본 = singon-design/design-guide/DESIGN_GUIDE.md
 * 값을 여기서 바꾸지 말고 가이드를 먼저 고친다. 이 파일은 가이드 §1 의 이관본이다.
 *
 * 🔑 색은 도출한 게 아니라 **크루 브랜드 보드에서 계승**했다(§0.1).
 *    파생 토큰(--warm-deep · --stage · --alert)은 §2 대비 계약을 만족시키려 유도한 값이고,
 *    값이 브랜드 팔레트와 달라도 **거기서 나온 색이면 토큰이어야 한다** — 하드코딩하면
 *    팔레트를 바꿔도 그것만 옛 색으로 남는다(cm§57).
 */

:root {
    /* ── 브랜드 (브랜드 보드 라벨 = 정본. 임의 변경 금지) ───────────── */
    --ink:        #111111;  /* 본문·기본 전경 */
    --ink-2:      #333333;  /* 보조 텍스트 */
    --warm:       #A69B8A;  /* 🔴 면·선·구분자 전용. 밝은 지면 위 텍스트 금지(§2: 2.74) */
    --sand:       #E7E0D4;  /* 보조 배경면 · 어두운 지면 위 보조 전경 */
    --paper:      #FFFFFF;  /* 최상단 지면 */

    /* ── 안개 그라디언트 (§0.5 — 적용 예시에서 도출한 하나의 지면) ──── */
    --fog-0:      #F2EEE9;  /* 하늘. 팬 지면 상단 */
    --fog-1:      #DED8D0;  /* 옅은 안개 */
    --fog-2:      #8E877D;  /* 🔴 전환대 — 텍스트 금지(흰 3.55 / ink-2 3.56) */
    --fog-3:      #3A342D;  /* 해질녘. 스탭 지면 상단 */
    --stage:      #1E1B18;  /* 지면. 스탭 기본 배경 */
    --stage-2:    #2A2621;  /* 어두운 지면의 카드·융기면 */

    /* ── 파생 (§2 계약을 만족시키기 위해 유도. 하드코딩 금지) ────────── */
    --warm-deep:  #6A6358;  /* --warm × 0.64 · 밝은 지면 위 웜톤 텍스트 (paper 5.93) */
    --on-dark:    #FFFFFF;  /* 어두운 지면 위 전경 (stage 17.14) */
    --on-dark-2:  #E7E0D4;  /* 어두운 지면 위 보조 전경 (stage 13.07) */
    --glass:      rgba(255,255,255,.04);  /* 화면 반사(§5-4). 4% 상한 */

    /* ── 기능색 (UI 전용. 브랜드 아님 — 로고·인쇄물에 쓰지 않는다) ───── */
    --alert:         #A8412F;  /* 취소·삭제. 밝은 지면 전용 (ink 위 3.11 = 본문 금지) */
    --alert-on-dark: #E08A72;  /* 어두운 지면의 취소·삭제 (stage 6.57) */

    /* ── 별(byeol) — 라이브 방송 유도 블록에서만 쓴다 ───────────────── */
    --by-base:#0E0B1A; --by-accent:#7C5CFF; --by-accent-deep:#6A40FF;
    --by-accent-pale:#C9B8FF; --by-live:#FF3D71; --by-text-2:#ADA7CC;

    /* ── 타이포 (§3) ─────────────────────────────────────────────── */
    --display:"Cormorant Garamond", Georgia, serif;   /* 로고 계열. 24px 이상에서만 */
    --body:"Noto Sans KR", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --mono:"JetBrains Mono", ui-monospace, Menlo, monospace;

    /* ── 스케일 ──────────────────────────────────────────────────── */
    --r-1:8px; --r-2:12px; --r-3:16px;

    /* ── safe-area (§7) — 고정 크롬이 흡수한다. 안드로이드는 env 가 0 으로 오는 일이 잦아
           네이티브/브릿지가 --safe-area-* 를 주입하면 그쪽을 쓴다. ─────── */
    --safe-top: max(env(safe-area-inset-top, 0px), var(--safe-area-top, 0px));
    --safe-bot: max(env(safe-area-inset-bottom, 0px), var(--safe-area-bottom, 0px));
    --gnb-h: calc(64px + var(--safe-bot));

    /* ── NSKit 레이아웃 토큰 override ────────────────────────────────
       ⚠️ 프레임워크 기본이 밝은 색이라, 어두운 지면(스탭)에서 PAGE 슬라이드-인 중
          흰 배경이 스친다. 각 화면이 자기 배경을 칠해 가려왔을 뿐이다. */
    --nskit-page-header-height: 64px;
    /* ⚠️ 프레임워크 CSS 가 --nskit-spacing-* 를 참조하는데 **정의가 어디에도 없다** →
       그 간격 선언들이 조용히 무시된다(정의 없는 var 는 에러가 아니다, cm 공방 P1 계열).
       가이드 §1 의 4배수 스케일로 채운다. */
    --nskit-spacing-xs: 4px;
    --nskit-spacing-sm: 8px;
    --nskit-spacing-md: 16px;
    --nskit-spacing-lg: 24px;
    --nskit-spacing-xl: 32px;
    /* 파생 경계색 — 값이 토큰과 달라도 **거기서 나온 색**이라 토큰이어야 한다(cm§57) */
    --rule:#E4DED4;        /* 밝은 지면의 테두리·구분선 (sand 를 살짝 내린 값) */
    --rule-dark:#3E3931;   /* 어두운 지면의 테두리 (stage-2 를 올린 값) */
    --rule-dark-2:#34302B; /* 어두운 지면의 옅은 구분선 */
    --chip-dark:#4A443C;   /* 어두운 지면의 칩 테두리 */
    --by-border:#2E2A4D;   /* 별 지면의 경계 */
}

/* 🔥 `hidden` 속성은 UA 기본 `[hidden]{display:none}` 으로 걸리는데 **명시 display 에 진다.**
   `.x{display:flex}` 규칙 하나면 `el.hidden = true` 가 통째로 무력해진다 — 속성은 true 인데
   화면엔 그대로 보인다(2026-08-31 실측). 숨김은 눈으로 확인하기 전엔 "된 것"이 아니다. */
[hidden]{ display:none !important; }

* { -webkit-tap-highlight-color: transparent; }

/* 🔥 프레임워크 `nskit-base.css` 가 `html, body { height:100%; overflow:hidden }` 을 건다
   — 모바일 SPA(씬이 풀스크린, 내부만 스크롤) 전제다. 그런데 **퍼블리싱 정본은
   페이지가 그냥 세로로 흐르는 구조**다(`.app{min-height:100vh}`).
   그대로 두면 홈이 1624px 인데 뷰포트 853px 에서 **스크롤이 안 된다**(2026-08-31 실측).
   정본을 따르기로 했으므로 되돌린다. */
html, body {
    height: auto !important;
    overflow: visible !important;
}

body {
    font-family: var(--body);
    font-weight: 300;
    font-size: 15px;
    line-height: 1.7;
    background: var(--fog-2);          /* 정본: 프레임 바깥 지면 */
    color: var(--ink);
    -webkit-font-smoothing: antialiased;
}

/* 씬 호스트도 같은 이유로 흐름에 되돌린다(cm§30 의 모바일 판) */
#scene-area{ position:static !important; inset:auto !important; margin:0 !important;
  width:100% !important; height:auto !important; overflow:visible !important; }
#scene-area > div[include-scene]{ position:static; inset:auto; overflow:visible; }

/* §5-3 들어오는 모든 사진에 같은 변환 — 예외 없음.
   ⚠️ 단 하나의 예외가 앨범아트다(§4-4-d) — 남의 저작물이고 원본이 식별 단서다. */
.sn-photo { filter: grayscale(1) sepia(.30) contrast(1.12) brightness(.96); }

/* §4-2 스와시 룰 — 화면당 1회, 헤더 직하에만 */
.sn-rule { display: block; width: 100%; height: auto; color: var(--warm); }

/* §7 PAGE 안전영역 — 고정 헤더/푸터는 **height 를 늘려** 인셋을 흡수한다.
   padding 으로 먹으면 콘텐츠 박스가 짓눌려 아이폰에서 헤더가 사라진다(cm§63). */
.sub-page-header {
    height: calc(var(--nskit-page-header-height) + var(--safe-top)) !important;
    padding-top: var(--safe-top) !important;
    box-sizing: border-box !important;
}
.sub-page-footer {
    height: calc(var(--nskit-page-header-height) + var(--safe-bot)) !important;
    padding-bottom: var(--safe-bot) !important;
    box-sizing: border-box !important;
}
/* cm§11 `.show{display:block!important}` 가 PAGE 컨테이너의 flex 를 깨 스크롤이 죽는다 */
/* 🔥 스탭의 PAGE 는 **어두운 지면**이다.
   프레임워크 `.sub-page-container` 는 밝은 배경(#FAFAFA)을 깔고, 스탭 페이지들은
   어두운 지면 전제로 흰 글자를 쓴다 → 겹치면 **흰 글자에 흰 배경**이 된다.
   실측(2026-08-31): 「너의 의미」 대비 **1.04**, 위반 9건. 콘솔 에러는 0이라 안 보인다.
   ⚠️ 페이지 CSS 에 배경을 넣는 걸로는 부족하다 — 컨테이너·헤더·푸터가 프레임워크 것이다. */
body.sn-staff-page .sub-page-container{ background:var(--stage) !important; color:var(--on-dark); }
body.sn-staff-page .sub-page-header{
  background:var(--stage) !important; border-bottom:1px solid var(--rule-dark-2) !important;
  color:var(--on-dark);
}
body.sn-staff-page .sub-page-header .page-title{ color:var(--on-dark); }
body.sn-staff-page .sub-page-header .page-back{ color:var(--on-dark-2); }
body.sn-staff-page .sub-page-footer{ background:var(--stage) !important; border-top:1px solid var(--rule-dark-2) !important; }
/* 제목 기본색이 밝은 지면용이라 어두운 데서 사라진다(cm§9 계열) — 지면이 색을 정하게 한다. */
body.sn-staff-page .sub-page-container h1,
body.sn-staff-page .sub-page-container h2,
body.sn-staff-page .sub-page-container h3,
body.sn-staff-page .sub-page-container h4{ color:inherit; }

/* ══ 레이어를 **앱 프레임에 묶는다** (cm§23) ═══════════════════════════
   PAGE·PANEL·DIALOG 는 `.sf`/`.fan` **바깥**(base-layout 의 layer-area)에 뜬다.
   그대로 두면 앱은 430px 가운데인데 페이지는 뷰포트 전체를 덮어 **밖에 뜬 것처럼** 보인다
   (2026-08-31 실측: 앱 74~504, 서브페이지 0~578).

   ⚠️ 센터링에 **transform 을 쓰지 않는다.** transform 이 걸린 조상은 fixed/absolute 자손의
      containing block 이 되어 내부 오버레이가 통째로 어긋난다(cm§23). left+margin 으로 한다. */
:root{ --frame-w:430px; }
@media (min-width:820px){ body.sn-staff-page{ --frame-w:1024px; } }   /* 스탭 태블릿 */

@media (min-width:431px){
  #sub-page-area, #sub-page-area-super, #dialog-area, #dialog-area-super, #side-panel-area{
    left:50% !important; right:auto !important;
    width:var(--frame-w) !important; margin-left:calc(var(--frame-w) / -2) !important;
  }
}

.sub-page-container.show { display: flex !important; }
.sub-page-content { min-height: 0; background: transparent; }
/* 기본 뒤로가기는 20×36 이라 44 미달 — 장식이 아니라 실제 버튼이므로 키운다(cm§43·§63) */
.sub-page-header .page-back {
    min-width: 44px; min-height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
}

/* §26 씬 mount — 래퍼가 flex 체인을 끊어 스크롤이 죽는 걸 막는다 */
#scene-area [class$="-mount"] { display: contents; }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { transition: none !important; animation: none !important; }
}

/* ══ 팬 지면 — 안개의 위쪽(§0.5). 처음 보는 화면을 짧게 쓴다 ══════════ */
.fan{ max-width:430px; margin:0 auto; min-height:100vh; background:var(--paper); position:relative;
  padding-bottom:calc(64px + var(--safe-bot)) }
.fan-hd{ position:sticky; top:0; z-index:20; background:var(--fog-0);
  height:calc(56px + var(--safe-top)); padding-top:var(--safe-top); padding-inline:18px;
  display:flex; align-items:center; justify-content:space-between }
/* 로고는 SVG 다 — 정본 규칙 그대로(fan-main.html `.hd .logo`).
   텍스트로 흉내 내면 자간·콜론 위치·굵기가 전부 달라진다. */
.fan-logo{ width:104px; height:auto; color:var(--ink); display:block }
.fan-badge{ font-family:var(--mono); font-size:14px; letter-spacing:.06em; color:var(--warm-deep);
  border:1px solid var(--warm); border-radius:999px; padding:6px 12px; min-height:32px;
  display:flex; align-items:center }
.fan-gnb{ position:fixed; left:50%; transform:translateX(-50%); bottom:0; width:100%; max-width:430px;
  z-index:30; height:calc(64px + var(--safe-bot)); padding-bottom:var(--safe-bot); display:flex;
  background:var(--by-base); border-top:1px solid var(--by-border) }
/* 정본 `.gnb a` — 아이콘 위, 라벨 아래(세로). 가로 배치는 정본과 다르다. */
.fan-gnb a{ flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:3px; text-decoration:none;
  color:var(--by-text-2); font-size:14px; min-height:44px }
.fan-gnb a.on{ color:var(--on-dark) }
.fan-gnb svg{ width:21px; height:21px }
/* 끝난 회차 — 버튼을 지운 자리에 **왜 없는지**를 남긴다. 빈 자리는 고장으로 보인다. */
.ended{ margin:0; padding:18px 20px; text-align:center; font-size:15px; line-height:1.8;
  color:var(--warm-deep); background:var(--sand); border-radius:var(--r-2) }
.ended span{ display:inline-block; margin-top:4px; font-size:13.5px; color:var(--ink-2) }

.fan-empty{ padding:64px 24px; text-align:center; font-size:16px; line-height:1.9; color:var(--ink-2) }
.fan-empty span{ font-size:14px; color:var(--warm-deep) }
.fan-empty b{ font-weight:700; color:var(--ink) }
.fan .sect{ padding:0 18px } .fan .sect + .sect{ margin-top:30px } .fan .top{ margin-top:24px }
.fan h2{ font-size:15px; font-weight:700; margin:0 0 2px } .fan .sub{ font-size:14px; color:var(--warm-deep); margin-bottom:14px }

/* ══ 스탭 지면 — 안개의 아래쪽. 관계자가 공유하고 몇 시간을 본다 ══════ */
/* 🔥 프레임워크 `nskit-base.css` 가 `h1..h6 { color: var(--nskit-text-primary) }` 로
   **모든 제목을 밝은 지면용 zinc(#18181B)** 로 칠한다. 스탭 지면은 어두워서(--stage:#1E1B18)
   그 색이 그대로 찍히면 대비가 **1.02** — 사실상 안 보인다.
   상속(`color:inherit`)으로 되돌려 지면이 색을 정하게 한다. 대비 계약(§2)은 지면이 지킨다.
   ⚠️ `.sf` 에 color 를 주는 것만으론 안 된다 — h1..h6 이 그걸 덮는다. */
.sf h1, .sf h2, .sf h3, .sf h4, .sf h5, .sf h6{ color:inherit; }

.sf{ background:var(--stage); color:var(--on-dark); min-height:100vh; max-width:430px; margin:0 auto;
  position:relative; padding-bottom:calc(28px + var(--safe-bot)) }
.sf-hd{ position:sticky; top:0; z-index:20; background:var(--stage); border-bottom:1px solid var(--rule-dark-2);
  height:calc(56px + var(--safe-top)); padding-top:var(--safe-top); padding-inline:16px;
  display:flex; align-items:center; gap:10px }
/* 스탭 헤더 로고 — 팬 헤더와 **같은 워드마크 SVG**. 글씨로 쓰면 자간·콜론 조판이 다르다.
   높이만 헤더에 맞춘다(폭은 뷰박스 비율대로). */
.sf-logo{ flex:0 0 auto; display:flex; align-items:center; color:var(--on-dark) }
.sf-logo .mark{ width:88px; height:auto; display:block }
/* 어느 회차를 조작 중인가 — 헤더의 본체다. 로고보다 이게 더 중요한 정보다. */
.sf-who{ flex:1; min-width:0; display:flex; flex-direction:column; justify-content:center; line-height:1.25 }
.sf-who b{ font-size:15px; font-weight:700; color:var(--on-dark);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.sf-who em{ font-style:normal; font-size:12.5px; color:var(--warm);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.sf-badge{ font-family:var(--mono); font-size:14px; color:var(--warm); border:1px solid var(--chip-dark);
  border-radius:999px; padding:6px 12px; min-height:32px; display:flex; align-items:center }
/* 신선도 — 성공한 마지막 로드 시각. 조용히 낡는 게 제일 나쁘다 */
.sf-sync{ font-family:var(--mono); font-size:14px; color:var(--warm) }
/* 뒤로 — 회차 안에서만 나온다. 목록으로 돌아가면 조작 대상이 비워진다. */
.sf-back{ flex:0 0 auto; width:40px; height:44px; margin-left:-10px; display:flex;
  align-items:center; justify-content:center; border:0; background:none; color:var(--on-dark-2);
  font-size:22px; cursor:pointer }

/* 회차 전환 — 동시에 여러 버스킹이 돌 때 헤더에서 바로 옮긴다. */
.sf-switch{ flex:1; min-width:0; position:relative }
.sf-switch-btn{ display:flex; align-items:center; gap:8px; width:100%; padding:0; min-height:44px;
  border:0; background:none; color:inherit; font-family:inherit; text-align:left; cursor:pointer }
.sf-switch-btn .t{ flex:1; min-width:0; display:flex; flex-direction:column; line-height:1.25 }
.sf-switch-btn b{ font-size:15px; font-weight:700; color:var(--on-dark);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.sf-switch-btn em{ font-style:normal; font-size:12.5px; color:var(--warm);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.sf-switch-btn iconify-icon{ flex:0 0 auto; color:var(--warm) }
.sf-switch-menu{ position:absolute; top:calc(100% + 8px); left:-8px; right:-8px; z-index:60;
  list-style:none; margin:0; padding:6px; max-height:60vh; overflow-y:auto;
  background:var(--stage-2); border:1px solid var(--rule-dark); border-radius:var(--r-2);
  box-shadow:0 18px 40px rgba(0,0,0,.5) }
.sf-switch-menu li{ margin:0 }
.sf-switch-menu button{ display:flex; flex-direction:column; width:100%; gap:2px; padding:11px 12px;
  min-height:52px; border:0; border-radius:var(--r-1); background:none; color:var(--on-dark-2);
  font-family:inherit; text-align:left; cursor:pointer }
.sf-switch-menu button.on{ background:var(--stage); color:var(--on-dark) }
.sf-switch-menu button b{ font-size:14.5px; font-weight:600 }
.sf-switch-menu button em{ font-style:normal; font-size:12px; color:var(--warm) }
.sf-switch-menu .none{ padding:16px; text-align:center; font-size:13.5px; color:var(--warm) }


.sf-sync.stale{ color:var(--alert-on-dark) }
.sf-tabs{ display:flex; gap:6px; padding:12px 16px 2px; background:var(--stage) }
.sf-tabs button{ flex:1; min-height:44px; border:1px solid var(--rule-dark); border-radius:999px;
  color:var(--warm); font-size:15px; background:none; font-family:inherit; cursor:pointer }
.sf-tabs button.on{ background:var(--on-dark); color:var(--stage); border-color:var(--on-dark) }
.sf-empty{ padding:56px 20px; text-align:center; font-size:16px; line-height:1.9; color:var(--on-dark-2) }
.sf-empty span{ font-size:14px; color:var(--warm) }
@media (min-width:820px){ .sf{ max-width:1024px; padding-inline:12px } .sf-tabs{ max-width:520px } }


/* ══ 인트로 ═══════════════════════════════════════════════════════════
   **정본 그대로다** — `singon-design/brand/intro/_intro.css.frag`.
   심볼마크가 워드마크로 펼쳐지는 2.85초 애니메이션(zoom·lock·글자 교대·스와시 와이프)이고,
   좌표·키프레임 값은 원 팀의 트레이스에서 나온 것이라 **손으로 다시 쓰면 어긋난다.**
   여기서 더한 것은 **전면 오버레이 껍데기**뿐이다.

   ⚠️ 값을 고쳐야 하면 정본을 고치고 다시 이식한다. 이 블록을 직접 만지지 말 것.

   지면: 팬 = 종이(--paper) + 잉크, 스탭 = 무대(--stage) + 밝은 전경. */
.sn-intro{ position:fixed; inset:0; z-index:9000; display:grid; place-items:center;
  background:var(--paper); --fg:var(--ink);
  /* 디졸브는 **넉넉히**. 애니메이션이 끝나자마자 툭 사라지면 마무리가 급해 보인다.
     본문 쪽 전환과 같은 길이여야 두 화면이 같은 구간에서 교차한다. */
  opacity:1; transition:opacity .9s ease, visibility .9s }
/* ⚠️ 지면을 팬/스탭으로 가르지 않는다. 정본 인트로는 **밝은 지면**이고,
   스탭용 어두운 변형을 만들면 `body.sn-staff-page` 를 JS 가 나중에 붙이는 탓에
   **흰색으로 떴다가 어두워지는 깜빡임**이 생긴다. 인트로는 브랜드의 순간이라 두 앱이 같아도 된다. */
.sn-intro.gone{ opacity:0; visibility:hidden; pointer-events:none }
.sn-intro .stage{ width:min(760px, 74vw) }

/* 🔑 **본문이 먼저 보이면 안 된다.** 인트로가 덮기만 하면 CSS·폰트가 붙는 사이
   아래 화면이 한 번 번쩍인다. 부팅 중에는 본문을 아예 감췄다가, 인트로가 걷힐 때
   **디졸브로** 올린다. `html.sn-booting` 은 인라인 스크립트가 **첫 페인트 전에** 건다.
   ⚠️ 인트로를 건너뛰는 날(하루 1회 규칙)에는 이 클래스를 아예 안 건다 —
      감췄다가 푸는 왕복이 오히려 깜빡임이 된다. */
html.sn-booting .content-area,
html.sn-booting .sf{ opacity:0 }
.content-area, .sf{ transition:opacity .9s ease }

.sn-intro .intro{ width:100%; height:auto; color:var(--fg); overflow:visible }
.sn-intro .intro g{ transform-box:view-box }
.sn-intro .zoom{ transform-origin:3954px 877px }

/* 시작 = 원 팀이 준 심볼마크 트레이스 **그대로**(획 두께를 원본과 일치시킴: 링 1.75px).
   심볼의 S:ON 은 워드마크를 축소한 게 아니다 — 콜론 점이 캡 대비 0.196 vs 0.135 로
   따로 조판된 것이라 재조립으로는 원본이 안 나온다.
   그래서 원본을 쓰고, 원·마이크가 빠질 때 글자만 워드마크 글리프로 교대한다.
   압축 배치 = 심볼의 **간격 비율** + 워드마크의 **글리프 폭**(저해상 침식분을 물려받지 않게). */
.sn-intro .zoom{ transform:scale(0.3892) }
.sn-intro .lock{ transform:translateX(1784px) }
.sn-intro .mv-c{ transform:translateX(-3301px) }
.sn-intro .mv-o{ transform:translateX(-3505px) }
.sn-intro .mv-n{ transform:translateX(-3568px) }
.sn-intro .word{ opacity:0 }
.sn-intro .g-I, .sn-intro .g-N1, .sn-intro .g-G{ opacity:0 }
.sn-intro .g-swash{ clip-path:inset(0 100% 0 0) }
.sn-intro .sym-mark, .sn-intro .sym-ltr{ opacity:1 }

.sn-intro .intro.play .sym-mark{ animation:fade .52s cubic-bezier(.4,0,.75,1) .40s both }
.sn-intro .intro.play .sym-ltr{ animation:fade .24s linear .46s both }
.sn-intro .intro.play .word{ animation:appear .24s linear .46s both }
.sn-intro .intro.play .zoom{ animation:zoom 1.55s linear .60s both }
.sn-intro .intro.play .lock{ animation:lock 1.55s linear .60s both }
.sn-intro .intro.play .mv-c{ animation:mvc  1.55s linear .60s both }
.sn-intro .intro.play .mv-o{ animation:mvo  1.55s linear .60s both }
.sn-intro .intro.play .mv-n{ animation:mvn  1.55s linear .60s both }
.sn-intro .intro.play .g-I{ animation:inI  1.55s linear .60s both }
.sn-intro .intro.play .g-N1{ animation:inN  1.55s linear .60s both }
.sn-intro .intro.play .g-G{ animation:inG  1.55s linear .60s both }
.sn-intro .intro.play .g-swash{ animation:wipe .65s cubic-bezier(.35,.05,.2,1) 2.20s both }

/* 확장은 구간마다 ease 를 걸지 않는다 — 양 끝(12%/88%)만 완화, 가운데 등속 */
@keyframes zoom{
  0% { transform:scale(0.3892) }
  8% { transform:scale(0.4503) }
  26% { transform:scale(0.6702) }
  44% { transform:scale(0.8534) }
  60% { transform:scale(0.9450) }
  78% { transform:scale(0.9847) }
  100% { transform:scale(1.0000) }
}
@keyframes lock{
  0% { transform:translateX(1784px) }
  8% { transform:translateX(1606px) }
  26% { transform:translateX(963px) }
  44% { transform:translateX(428px) }
  60% { transform:translateX(161px) }
  78% { transform:translateX(45px) }
  100% { transform:translateX(0px) }
}
@keyframes mvc{
  0% { transform:translateX(-3301px) }
  8% { transform:translateX(-2971px) }
  26% { transform:translateX(-1783px) }
  44% { transform:translateX(-792px) }
  60% { transform:translateX(-297px) }
  78% { transform:translateX(-83px) }
  100% { transform:translateX(-0px) }
}
@keyframes mvo{
  0% { transform:translateX(-3505px) }
  8% { transform:translateX(-3155px) }
  26% { transform:translateX(-1893px) }
  44% { transform:translateX(-841px) }
  60% { transform:translateX(-315px) }
  78% { transform:translateX(-88px) }
  100% { transform:translateX(-0px) }
}
@keyframes mvn{
  0% { transform:translateX(-3568px) }
  8% { transform:translateX(-3211px) }
  26% { transform:translateX(-1927px) }
  44% { transform:translateX(-856px) }
  60% { transform:translateX(-321px) }
  78% { transform:translateX(-89px) }
  100% { transform:translateX(-0px) }
}
@keyframes inI{ 0%,7%{opacity:0; transform:translateY(58px)} 21%,100%{opacity:1; transform:translateY(0)} }
@keyframes inN{ 0%,26%{opacity:0; transform:translateY(58px)} 40%,100%{opacity:1; transform:translateY(0)} }
@keyframes inG{ 0%,53%{opacity:0; transform:translateY(58px)} 67%,100%{opacity:1; transform:translateY(0)} }
@keyframes fade{ from{opacity:1} to{opacity:0} }
@keyframes appear{ from{opacity:0} to{opacity:1} }
@keyframes wipe{ from{clip-path:inset(0 100% 0 0)} to{clip-path:inset(0 0 0 0)} }

@media (prefers-reduced-motion: reduce){
  .intro *{ animation:none !important }
  .zoom,.lock,.mv-c,.mv-o,.mv-n{ transform:none }
  .word{ opacity:1 } .g-I,.g-N1,.g-G{ opacity:1; transform:none }
  .g-swash{ clip-path:none } .sym-mark,.sym-ltr{ opacity:0 }
}



/* ── 프로필 사진 기본 이미지 ────────────────────────────────────────────
   사진이 없는 싱어는 이니셜 글자 대신 **사람 형상**을 보여준다.

   🔑 아이콘을 마크업에 넣지 않고 **CSS 마스크**로 깐다. 팬 셸은 인라인 SVG 스프라이트를,
      스탭 셸은 Iconify 를 쓰는 서로 다른 체계라(둘 다 정본) 마크업 방식이 갈린다.
      마스크로 하면 **두 셸에서 같은 한 줄**이 돈다.
   🔑 색은 마스크가 정하지 않는다 — 지면이 정한다. 밝은 지면에서 --warm 은 대비 2.74 로
      쓰면 안 되는 값이라(가이드 §2) 그쪽은 --warm-deep 을 넘긴다.
   ⚠️ `:has(img)` 로 숨기지 않는다 — 미지원 브라우저에서 사진 **위에** 겹친다.
      사진이 없을 때만 이 클래스를 붙이는 쪽이 안전하다(붙이는 책임은 렌더 코드에). */
.sn-av-none{ position:relative }
.sn-av-none::after{
  content:''; position:absolute; inset:0; pointer-events:none;
  background:var(--sn-av-ink, var(--warm));
  -webkit-mask:url('../svg/sn-avatar.svg') center/54% no-repeat;
          mask:url('../svg/sn-avatar.svg') center/54% no-repeat;
}

/* 스탭 헤더의 도움말 — 크루·스탭만 본다(관객 소개 화면에는 두지 않는다).
   ⚠️ 헤더가 flex 라 오른쪽 끝으로 밀어 둔다. 터치타겟 44px(§43 — 실제 버튼이므로 보이는 크기를 키운다). */
.sf-hd .sf-help{ margin-left:auto; flex:0 0 auto; display:inline-flex; align-items:center; justify-content:center;
  min-width:44px; min-height:44px; border-radius:50%; color:var(--warm); text-decoration:none;
  -webkit-tap-highlight-color:transparent }
.sf-hd .sf-help:active{ opacity:.6 }
.sf-hd .sf-help iconify-icon{ font-size:20px }
