/* ============================================================
   NOIR WAVE — Artist EPK Page / Master Template
   Design direction: Cold Night / Urban Silence / Refined Emotion
   Palette: Near Black, Cool Gray, Off White, Electric Cyan (accent, sparing)
============================================================= */

:root{
  /* ---- Color ---- */
  --bg:            #0A0B0D;
  --bg-deep:       #0D1319; /* Deep Blue Black — Visual Rhythm Patch 02 §05, Zone 02 (Music/Works) atmosphere. Pushed cooler/darker than Patch 01's #0B1015 so the shift reads against --bg-elevated instead of blending into it. */
  --bg-elevated:   #15171B;
  --bg-elevated-2: #1D2025;
  --border:        #24272C;
  --border-soft:   #1B1D22;
  --boundary:      rgba(255, 255, 255, 0.12); /* Visual Rhythm Patch 02 §06 — Global Section Boundary, raised from Patch 01's 0.08 to the spec's upper bound (0.11~0.12) so zone/section changes are legible, not just implied by background */

  --text-primary:   #EDEDEF;
  --text-secondary: #9AA0A8;
  --text-tertiary:  #63686F;

  --accent:      #5FD1E8;
  --accent-line: rgba(95, 209, 232, 0.35);
  --violet:      #747A9E; /* Atmospheric Violet — ambient/section-tone use only, never CTA (Patch §05) */

  /* ---- Type — Premium Reference 1:1 정렬 (Patch 20260926_01 §02) ---- */
  --font-display: 'Pretendard Variable', -apple-system, BlinkMacSystemFont, 'Malgun Gothic', 'Segoe UI', sans-serif;
  --font-body:    'Pretendard Variable', -apple-system, BlinkMacSystemFont, 'Malgun Gothic', 'Segoe UI', Helvetica, Arial, sans-serif;
  --font-serif:   Georgia, 'Noto Serif KR', serif;

  /* Premium Type Scale (Patch §02) — 역할별 임의 px 난립 방지 */
  --scale-display: clamp(3rem, 5vw, 5.6rem);
  --scale-h3:      clamp(1.2rem, 2vw, 1.6rem);
  --scale-body:    1rem;
  --scale-small:   0.875rem;

  /* ---- Layout ---- */
  --content-max: 1360px;
  --text-max: 720px;
  --edge: clamp(20px, 5vw, 72px);
  --nav-height: 72px;
  /* Anchor landing — Section Title 윗면이 고정 Header 바로 아래 이 간격만큼 떨어져 도착한다 */
  --anchor-gap: clamp(20px, 2.4vw, 36px);
  /* Video Modal sizing — 폭은 뷰포트 폭과 높이(16:9 + 모달 크롬) 중 작은 쪽 */
  --modal-max: 1440px;
  --modal-vpad: clamp(12px, 3vh, 28px);
  --modal-chrome: 140px; /* panel 상단 44(닫기 행) + 하단 24 + border 2 + frame margin 16 + title/type ≈ 52 */
  /* 일반 8개 섹션(#bio #music #works #career #proof #video #press #contact)의 상·하 공통 여백. 예외 없음. */
  --epk-section-space: clamp(64px, 7.8vw, 120px);

  /* ---- Space ---- */
  --space-section: clamp(64px, 9vw, 128px);
  --space-lg: 40px;
  --space-md: 24px;
  --space-sm: 12px;

  --radius: 2px;

  /* ---- Motion timing (STEP 05 §19 — single shared scale) ---- */
  --motion-fast: 180ms;
  --motion-standard: 380ms;
  --motion-editorial: 600ms;
  --ease-standard: cubic-bezier(.4,0,.2,1);
}

*{ box-sizing: border-box; }
/* Anchor offset — 한 체계만 사용한다: 각 section의 scroll-margin-top (아래 section 규칙).
   html scroll-padding-top은 두지 않는다(두 값이 누적되면 섹션마다 도착 간격이 달라진다).
   각 section은 자기 padding-top(--pt)을 알고 있으므로 "Section Title 윗면 = Header 하단 +
   --anchor-gap"이 되도록 scroll-margin-top을 계산한다. 값이 음수여도 정상이다. */
html{ scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior: auto; }
  *{ animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

body{
  margin: 0;
  background: var(--bg);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: var(--scale-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  word-break: keep-all;
  overflow-wrap: break-word;
  line-break: strict;
}

a{ color: inherit; text-decoration: none; }
ul{ list-style: none; margin: 0; padding: 0; }
button{ font-family: inherit; }

img{ max-width: 100%; display: block; }

.section-inner{
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 0 var(--edge);
}

/* ============================================================
   TYPOGRAPHY HIERARCHY (STEP 05 §03, unified per user feedback)
   Level 1 Artist Name → .hero-name
   Level 2 Section Title → .section-title — one consistent size,
     weight, and title-to-content margin across every section (Bio,
     Music, Works, Career, Proof, Video, Press, Contact). Previously
     varied by role (--large / default / --eyebrow, each a different
     size, case treatment, and margin-bottom) — removed for a
     unified page rhythm.
   Level 3 Content Title → work/music/career/credit item titles
   Level 4 Metadata → small type/year/location strings
============================================================= */
.section-title{
  font-family: var(--font-display);
  font-size: clamp(0.85rem, 1vw + 0.6rem, 1rem);
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0.08em;
  color: var(--text-primary);

  position: relative;
  display: inline-block;
  padding-left: 16px;

  margin-top: 0;
  margin-bottom: var(--space-lg);
}
.section-title::before{
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  translate: 0 -50%;
  width: 9px;
  height: 1px;
  background: var(--accent);
}

section{
  /* Vertical rhythm — 각 섹션은 --pt / --pb 두 값으로만 상·하 여백을 정한다.
     이전의 "top-only rhythm"(하단 24~40px)은 경계선 위쪽이 눌려 보이는 문제가
     있어, 섹션별로 위/아래 시각 균형을 맞춘 값으로 대체했다(Final Patch §04).
     섹션 값을 한 숫자로 통일하지 않는다 — 아래 섹션별 값은 Before/After 스크린샷
     기준의 의도된 차이다. */
  --pt: var(--epk-section-space);
  --pb: var(--epk-section-space);
  padding: var(--pt) 0 var(--pb);
  scroll-margin-top: calc(var(--nav-height) + var(--anchor-gap) - var(--pt));
  border-top: 1px solid var(--boundary);
}
section:first-of-type{ border-top: none; }

/* Section rhythm — 일반 8개 섹션은 전부 같은 상·하 여백(--epk-section-space)을 쓴다. 섹션별 예외 없음.
   시각적 리듬은 배경 Zone, 이미지 크기, 섹션 내부 간격으로 만든다.
   Hero  : section 자체 padding 0. 고정 Header 보정(--nav-height)은 hero-inner에서 하고,
           Header 아래 상단 여백 = 하단 여백 = --epk-section-space 로 일반 섹션과 같다.
   Snapshot : 의도된 compact strip(--space-lg). Footer도 compact 유지.
   Contact : 앵커 도착 동작만 기존 방식 유지(아래 scroll-margin-top). */
.hero{ --pt: 0px; --pb: 0px; }
.snapshot{ --pt: var(--space-lg); --pb: var(--space-lg); }
.contact{ scroll-margin-top: var(--nav-height); }

/* Visual Zone tone separation (Visual Rhythm Patch §07) — four zones the
   page should read as, from top to bottom:
   Zone 01 Artist Identity  (Hero/Snapshot/Bio)      → near-black, Snapshot
                                                        stays a quiet elevated
                                                        info strip (unchanged)
   Zone 02 Music / Work     (Music/Works)             → Deep Blue Black, a
                                                        barely-there cold shift
                                                        signalling "entering
                                                        the music section"
   Zone 03 Live/Professional(Career/Proof)            → Elevated Surface;
                                                        Career is the visual
                                                        peak, Proof the quiet
                                                        evidence zone right
                                                        after it
   Zone 04 Media / Contact  (Video/Press/Contact/Footer) → back to near-black,
                                                        density stepping down
                                                        toward Contact */
.snapshot, .career, .proof{ background: var(--bg-elevated); }
.music, .works{ background: var(--bg-deep); }

/* Career ambient layer (Patch §13) — current photography isn't laid in as a
   section background per the patch's Background Image Rule; a barely-there
   radial tint (~5% Atmospheric Violet, top-weighted like stage light) is
   used instead so Career reads as the page's visual peak without becoming
   a "colour section". */
.career{
  background:
    radial-gradient(140% 90% at 50% -10%, rgba(116, 122, 158, 0.11), transparent 62%),
    var(--bg-elevated);
}

/* ============================================================
   HEADER
============================================================= */
/* Fixed, true-transparent → scrolled-translucent header (Patch §05-2).
   Overlaps Hero; Hero top padding compensates with var(--nav-height)
   (§05-6) so content never renders under the header. */
.site-header{
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;

  height: var(--nav-height);
  background: transparent;
  /* Premium과 동일 기법 — border-bottom-color만 transparent로 두고 폭은
     1px을 유지한다. 색상은 투명이지만 fixed 헤더의 컴포지팅 레이어 경계에서
     실제로 옅은 1px 라인이 렌더링되는 것까지 Premium과 동일하게 재현한다
     (사용자 확인 — Premium 실제 렌더링에도 이 라인이 존재함, 2026-09-26). */
  border-bottom: 1px solid transparent;

  -webkit-backdrop-filter: none;
  backdrop-filter: none;

  transition:
    background var(--motion-standard) var(--ease-standard),
    border-color var(--motion-standard) var(--ease-standard),
    backdrop-filter var(--motion-standard) var(--ease-standard);
}
.site-header.is-scrolled{
  background: rgba(10, 11, 13, 0.62);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-bottom-color: var(--border);
}
.header-inner{
  max-width: var(--content-max); margin:0 auto; padding: 0 var(--edge);
  height: 100%;
  display:flex; align-items:center; justify-content:space-between; gap: 24px;
}
.wordmark{
  font-family: var(--font-display); font-weight:500;
  font-size: 1.1rem; letter-spacing: 0.02em;
  color: var(--text-primary);
}
.main-nav{ display:flex; gap: 28px; margin-left: auto; }
.main-nav a{
  font-family: var(--font-body); font-size: var(--scale-small);
  font-weight: 500; color: var(--text-primary); opacity: 1;
  transition: color var(--motion-fast) var(--ease-standard), border-color var(--motion-fast) var(--ease-standard);
}
.main-nav a:hover, .main-nav a:focus-visible{ color: var(--accent); }
.nav-toggle{ display:none; background:none; border:none; cursor:pointer; padding:8px; }
.nav-toggle span{ display:block; width:20px; height:1px; background:var(--text-primary); margin:5px 0; }

/* ============================================================
   BUTTONS
   CTA feedback (STEP 05 §17-C): one mechanism only, used everywhere —
   background/foreground inversion. No mixed hover languages.
============================================================= */
.btn{
  display:inline-flex; align-items:center; justify-content:center;
  padding: 12px 22px; font-size: 14px; font-weight: 600;
  border: 1px solid transparent; border-radius: var(--radius);
  white-space: nowrap; transition: background var(--motion-fast) var(--ease-standard),
    color var(--motion-fast) var(--ease-standard), border-color var(--motion-fast) var(--ease-standard);
}
.btn[hidden]{ display: none; }
.btn--primary{ background: var(--text-primary); color: var(--bg); }
.btn--primary:hover{ background: var(--accent); color: var(--bg); }
.btn--secondary{ border-color: var(--border); color: var(--text-primary); background: transparent; }
.btn--secondary:hover{ background: var(--text-primary); color: var(--bg); border-color: var(--text-primary); }

.btn:focus-visible{ outline: 2px solid var(--accent); outline-offset: 2px; }

/* ============================================================
   HERO
============================================================= */
.hero-inner{
  max-width: var(--content-max); margin: 0 auto;
  /* Header가 fixed로 Hero 위에 겹치므로 top padding에 --nav-height를
     포함한다 (Patch §05-6). 기존 visual composition(비율)은 유지. */
  /* top: Header 아래 --epk-section-space, bottom: 다음 구획까지 --epk-section-space. */
  padding: calc(var(--nav-height) + var(--epk-section-space)) var(--edge) var(--epk-section-space);
  display:grid; grid-template-columns: minmax(0,0.9fr) minmax(0,1.1fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
}
.hero-visual .asset-slot{ max-width: 420px; }

/* Text-led fallback when Hero Portrait is unavailable (STEP 04 CASE C) */
.hero-inner--textled{ grid-template-columns: 1fr; }
.hero-inner--textled .hero-copy{ max-width: 640px; }
/* Hero eyebrow — Premium accent-colored eyebrow (Patch §06-3). Left tick
   is not forced here; ordinary Section Label eyebrow (.section-title)
   keeps the tick, Hero uses the Premium Hero reference directly. */
/* Hero information typography — fixed breakpoint scale, not viewport-
   dependent clamp/vw (Patch 20260926_02 §10). Prevents Artist Name /
   eyebrow from continuing to grow on ultra-wide viewports (1680~2560). */
.hero-copy .eyebrow{
  font-family: var(--font-body);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0.08em;
  color: var(--accent);
  margin: 0 0 16px;
}
.hero-name{
  font-family: var(--font-display);
  font-size: 4.5rem;
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--text-primary);
  margin: 0 0 20px;
}
.hero-position{
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--text-secondary);
  max-width: var(--text-max);
  margin: 0 0 32px;
}
.hero-cta{ display:flex; flex-wrap: wrap; gap: 12px; }

/* Mobile-only compact profile meta line (Patch 01 §6, Option B) —
   hidden on desktop; desktop uses the separate Snapshot section instead. */
.hero-meta-mobile{
  display: none;
  font-family: var(--font-body); font-size: var(--scale-small); color: var(--text-secondary);
  margin: 0 0 24px; padding-bottom: 20px; border-bottom: 1px solid var(--border-soft);
}
.hero-meta-mobile__sep{ color: var(--text-tertiary); margin: 0 8px; }

/* Tablet (Patch §10-2) */
@media (max-width: 1024px){
  .hero-name{ font-size: 4rem; }
}

/* ============================================================
   ASSET SLOT (placeholder system)
============================================================= */
.asset-slot{
  width: 100%;
  border: 1px dashed var(--border);
  background: var(--bg-elevated);
  display:flex; align-items:center; justify-content:center;
  position: relative; overflow: hidden;
}

/* Real image — fills the slot, object-fit per type */
.asset-slot__img{
  width: 100%; height: 100%; display:block;
  object-fit: cover; object-position: center center;
  transition: transform var(--motion-standard) var(--ease-standard);
}
.asset-slot:has(.asset-slot__img){ border-style: solid; }
.asset-slot__img--portrait{ object-position: center 22%; }
.asset-slot__img--cover{ object-position: center center; }

/* Hero portrait — no frame. Image reads directly against the
   background rather than sitting "in a card" (STEP 05 §5). */
.hero-visual .asset-slot{ border: none; background: transparent; }

/* Designed fallback surface — used when a structurally-required
   image slot (cover, thumbnail) has no asset. Never an empty box. */
.asset-slot--fallback{
  border-style: solid;
  background: radial-gradient(120% 120% at 20% 15%, var(--bg-elevated-2), var(--bg-elevated) 60%, var(--bg) 100%);
}
.asset-slot__mark{
  font-family: var(--font-serif); font-style: italic; font-size: 14px;
  letter-spacing: .08em; color: var(--text-tertiary); opacity: .5;
}

/* Image hover (STEP 05 §5/§17-B) — barely-there zoom, never a large
   zoom, glow, or tilt. Work/Video cards use their own Premium-aligned
   hover rules (no border highlight — see Selected Works / Video Media
   sections below, Patch §07-6/§09-3); this shared rule now only covers
   Music artwork. */
.music-card .asset-slot{ overflow: hidden; }
.music-card:hover .asset-slot__img{ transform: scale(1.015); }

/* ============================================================
   REVEAL ON SCROLL (STEP 05 §17-A / §19 — editorial timing,
   opacity + small Y movement only, respects reduced-motion)
============================================================= */
.reveal{
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--motion-editorial) var(--ease-standard),
              transform var(--motion-editorial) var(--ease-standard);
}
.reveal.is-visible{
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce){
  .reveal{ opacity:1; transform:none; transition:none; }
}

/* ============================================================
   SNAPSHOT — Dynamic Meta Slot (2~4 items, data-driven). Desktop only.
============================================================= */
.snapshot-grid{
  display:grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--space-md);
}
.snapshot-item{ display:flex; flex-direction:column; gap:6px; }
.snapshot-item__label{ font-size:12px; color: var(--text-tertiary); text-transform:uppercase; letter-spacing:.05em; }
.snapshot-item__value{ font-size:14px; color: var(--text-primary); }

/* ============================================================
   BIO — Container(.section-inner)는 대표 음악/주요 작업/주요 활동과
   동일한 Wide Content Grid를 공유한다(STEP 06 §03). 본문 문장만
   .bio-text에서 가독 폭으로 제한하고, Editorial Image는 Section
   전체 폭(.section-inner)까지 그대로 확장한다.
============================================================= */
.bio-text{ max-width: var(--text-max); }
.bio-short{ font-size: 18px; color: var(--text-primary); line-height: 1.7; margin: 0 0 20px; }
.bio-toggle{
  background:none; border: 1px solid var(--border); color: var(--text-secondary);
  padding: 8px 16px; cursor:pointer; font-size: 13px; display:inline-flex; align-items:center; gap:6px;
}
.bio-toggle:hover, .bio-toggle:focus-visible{ color: var(--accent); border-color: var(--accent-line); }
.bio-more{ margin-top: 24px; display:flex; flex-direction:column; gap: 16px; }
.bio-more[hidden]{ display: none; }
.bio-more p{ color: var(--text-secondary); font-size: 15px; line-height: 1.75; margin:0; }
.bio-more em{ color: var(--text-primary); font-style: normal; }

/* Editorial image — full Section Grid width (not tied to the
   readable text column), matching Music/Works/Career visual scale.
   Native ratio(3/2) is set inline by script.js; only cap max-height
   here so the crop stays editorial rather than overwhelming at
   full section width. */
.bio-visual{ margin: var(--space-lg) 0 0; }
.bio-visual .asset-slot{ max-height: 560px; }
.bio-visual[hidden]{ display:none; }
@media (max-width: 768px){
  .bio-visual .asset-slot{ max-height: none; }
}

/* ============================================================
   MUSIC
============================================================= */
/* ============================================================
   MUSIC — Selected Music. Desktop: all 3 tracks use the same Player C+
   structure (STEP 05 §8-10, locked master direction). Mobile: Primary
   keeps Artwork+Embed, Secondary collapses to a compact listen-link row
   via `.player--secondary` overrides in the 768px breakpoint below
   (STEP 06 Production Content Patch 04 §04-07) — no separate mobile DOM.
============================================================= */
.music-list{ display:flex; flex-direction:column; gap: 16px; }

/* ---- Player C+ — Full-width Horizontal Editorial Row (STEP 06 §09) ----
   Artwork | Title/Meta | Official Embed | Platform Link, one clear row.
   Flexbox (not grid-template-areas) so it degrades gracefully when a
   track has no artwork and/or no embed/platform data yet. */
.player{
  display:flex; align-items:center; gap: 24px; flex-wrap: wrap;
  border: 1px solid var(--border); background: var(--bg-elevated);
  padding: var(--space-md) var(--space-lg);
  /* Full section width kept (no card-width cap) — leftover horizontal
     space is distributed evenly across the row's internal gaps instead
     of being dumped as one block before the CTA (Patch §02 follow-up 2). */
  justify-content: space-between;
}
.player-artwork{ flex: 0 0 104px; }
.player-artwork .asset-slot{ aspect-ratio: 1/1; }
.player-info{ flex: 0 0 auto; min-width: 150px; }
.player-info__title{ font-family: var(--font-display); font-weight:600; font-size: 17px; margin:0 0 4px; }
.player-info__meta{ font-size: 13px; color: var(--text-tertiary); margin:0; }
/* Compact Editorial Player — embed grows to fill the row but is capped
   so it never stretches the full remaining section width (Patch §02). */
.player-embed{ flex: 1 1 400px; width: 100%; max-width: 480px; min-width: 200px; }
.music-embed__frame{ display:block; width: 100%; max-width: 100%; border: 0; border-radius: 4px; }
.player-platforms{ flex: 0 0 auto; display:flex; flex-wrap: wrap; gap: 8px; }

/* No listen data yet for this track — let the title/meta breathe instead
   of leaving a lopsided empty row (URL 미확정 상태의 정상 케이스). */
.player--info-only .player-info{ flex: 1 1 auto; }
.player--info-only .player-info__title{ font-size: 20px; }

/* No-artwork variant (STEP 06 §14) — artwork block simply isn't in the
   DOM at all when there's no cover; flexbox reflows without a gap. */

.platform-btn{
  display:inline-flex; align-items:center; gap:6px;
  border: 1px solid var(--border); padding: 8px 14px; font-size: 13px;
  color: var(--text-secondary); position: relative; background: transparent;
  white-space: nowrap;
  transition: background var(--motion-fast) var(--ease-standard),
    color var(--motion-fast) var(--ease-standard), border-color var(--motion-fast) var(--ease-standard);
}
.platform-btn:hover{ background: var(--text-primary); color: var(--bg); border-color: var(--text-primary); }
.platform-btn--primary{ border-color: var(--text-primary); }

/* ============================================================
   SELECTED WORKS — role / visual proof (distinct purpose from Music)
============================================================= */
/* Wider grid gap than Music's internal rhythm (Patch 02 §09) — Works
   needed its own density, not Music's leftover spacing, so it doesn't
   read as an extension of the player list above it. */
.works-grid{ display:grid; grid-template-columns: repeat(3, 1fr); gap: clamp(20px, 2.6vw, 36px); }
/* Wrapper — 텍스트 정보 컨테이너일 뿐, 자체 클릭 영역이 아니다 (사용자 피드백:
   링크 영역을 앨범 이미지로만 한정, 텍스트는 비클릭). Video Card와 동일 패턴. */
.work-card{ display: block; width: 100%; }
/* Trigger — 앨범 이미지 영역만 실제 링크 */
.work-card__trigger{ display: block; color: inherit; text-decoration: none; }
.work-card__trigger .asset-slot{ aspect-ratio: 1/1; margin-bottom: 0; border: 0; overflow: hidden; }
/* Premium Release Index spacing rhythm (Patch 20260926_02 §03-2) —
   compact image → meta → title → description, no large block margins. */
.work-card__info{ padding-top: calc(var(--space-sm) / 2); }
.work-card__meta{
  font-family: var(--font-body); font-size: var(--scale-small); line-height: 1.4;
  color: var(--text-secondary); margin: 0;
}
.work-card__title{
  font-family: var(--font-display); font-size: var(--scale-h3); font-weight: 500;
  line-height: 1.2; color: var(--text-primary);
  margin: 2px 0 0;
  transition: color var(--motion-fast) var(--ease-standard);
}
.work-card__role{
  font-family: var(--font-body); font-size: var(--scale-small); line-height: 1.6;
  color: var(--text-secondary); margin: 4px 0 0;
}

/* Premium Release Index hover (Patch §03-3) — image scale + title accent
   only, triggered by hovering/focusing the image link itself (텍스트는
   비클릭이므로 자체 hover 상태를 갖지 않는다 — 형제 결합자로 제목에만 반영).
   No border highlight / outline / overlay on the Works image. */
@media (hover: hover){
  .work-card__trigger:hover .asset-slot__img{ transform: scale(1.04); }
  .work-card__trigger:hover ~ .work-card__info .work-card__title{ color: var(--accent); }
}
.work-card__trigger:focus-visible{ outline: 2px solid var(--accent); outline-offset: 4px; }
.work-card__trigger:focus-visible .asset-slot__img{ transform: scale(1.04); }
.work-card__trigger:focus-visible ~ .work-card__info .work-card__title{ color: var(--accent); }
/* Touch / press feedback (Final Patch §06) — (hover: hover)는 터치에서 발동하지 않으므로
   :active가 같은 역할(이미지 미세 scale + 타이틀 accent)을 맡는다. hover를 고정시키지 않으므로
   첫 탭 = 바로 링크 이동이다. reduced-motion에서는 scale을 쓰지 않고 색 변화만 남긴다. */
.work-card__trigger{ -webkit-tap-highlight-color: transparent; }
/* 탭은 짧아서 기본 380ms 전환이면 눌림이 거의 안 보인다 — 누를 때는 90ms로 즉시 반응하고, 뗀 뒤에는 기본(380ms) 전환으로 천천히 돌아온다. */
.work-card__trigger:active .asset-slot__img{ transform: scale(1.04); transition-duration: 90ms; }
.work-card__trigger:active ~ .work-card__info .work-card__title{ color: var(--accent); }
@media (prefers-reduced-motion: reduce){
  .work-card__trigger:active .asset-slot__img{ transform: none; }
}

/* ============================================================
   CAREER — Wide Performance Slider (top) + Career list (below).
   No text-over-image overlay (STEP 06 §12-13): brightness varies per
   photo, Korean event names can run long, and overlay text stability
   on mobile isn't reliable — so image and text stay fully separate.
============================================================= */
.career-slider{
  position: relative;
  /* More room below the slider than the shared --space-lg default
     (Patch 02 §10) — Career text needs to read as breathing room after
     the visual peak, not a caption stacked directly under the photo. */
  margin-bottom: clamp(40px, 5vw, 64px);
  outline: none;
  /* Clip mask lives on this static wrapper, not on the element that
     gets transformed (see .career-slider__track below). Overflow and
     transform on the SAME element move the clip window together with
     the content, so slides 2/3 never entered the visible frame —
     that was the root cause of the blank slides bug. */
  overflow: hidden;
  /* Subtle lift so the performance photo reads as the section's visual
     anchor against the elevated background, not flush with it (Patch 02
     §10 — Slider visual prominence). Shadow only, no border/glow/scale. */
  box-shadow: 0 32px 72px rgba(0, 0, 0, 0.38);
}
.career-slider[hidden]{ display:none; }
/* 키보드로 slider에 포커스가 오면 보이는 링을 준다(마우스 클릭 포커스에는 나타나지 않는다). */
.career-slider:focus-visible{ outline: 2px solid var(--accent); outline-offset: 4px; }
/* Drag / swipe 대응 — 가로 제스처는 slider가, 세로 스크롤은 브라우저가 처리한다.
   텍스트·이미지의 기본 선택/드래그는 slider 영역 안에서만 막는다. */
.career-slider{ touch-action: pan-y; overscroll-behavior-x: contain; -webkit-user-select: none; user-select: none; }
.career-slider img{ -webkit-user-drag: none; user-drag: none; }
.career-slider__track{
  display:flex;
  transition: transform var(--motion-standard) var(--ease-standard);
}
.career-slider__slide{ flex: 0 0 100%; }
.career-slider__slide .asset-slot{ aspect-ratio: 16/9; }
/* Bottom-center line indicators (Patch §08-2) — Premium과 동일한
   indicator language. 버튼은 script.js가 slide 수만큼 생성한다. */
.career-slider__indicators{
  position: absolute;
  /* 클릭 영역(높이 40px)을 키우되 보이는 2px 라인은 기존과 같은 y 위치(하단 space-md)에 둔다. */
  bottom: calc(var(--space-md) - 19px);
  left: 50%;
  translate: -50% 0;

  display: flex;
  gap: 0; /* 라인 간격 8px은 버튼 폭(28px) - 라인 폭(20px)으로 유지 → 클릭 영역이 겹치지 않는다 */
  z-index: 2;
}
.career-slider__indicators button{
  position: relative;
  width: 28px;
  height: 40px;
  border: 0;
  background: transparent;
  padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.career-slider__indicators button::before{
  content: "";
  position: absolute;
  left: 4px; right: 4px; top: 50%;
  height: 2px;
  translate: 0 -50%;
  background: rgba(245, 245, 244, 0.4);
}
.career-slider__indicators button[aria-current="true"]::before{
  background: var(--accent);
}
.career-slider__indicators button:focus-visible{
  outline: 2px solid var(--accent); outline-offset: -4px;
}
.career-slider__indicators[hidden]{ display: none; }

.career-list{ display:flex; flex-direction:column; }
.career-list li{
  display:grid; grid-template-columns: 100px 1fr;
  gap: 24px; padding: 16px 0; border-bottom: 1px solid var(--border-soft);
}
.career-year{ font-family: var(--font-display); color: var(--text-tertiary); font-size: 14px; }
.career-desc{ font-size: 15px; color: var(--text-primary); }

/* ============================================================
   CREDITS — compact list
============================================================= */
.credits-list{ display:flex; flex-direction:column; }
.credits-list li{
  break-inside: avoid; padding: 12px 0; border-bottom: 1px solid var(--border-soft);
  font-size: 14px; display:flex; justify-content: space-between; gap: 12px;
}
.credit-title{ color: var(--text-primary); }
.credit-role{ color: var(--text-tertiary); text-align:right; }

.credits-list li.is-collapsed,
.career-list li.is-collapsed{ display:none; }
.credits-toggle{
  margin-top: 16px; background:none; border: 1px solid var(--border); color: var(--text-secondary);
  padding: 8px 16px; cursor:pointer; font-size: 13px;
}
.credits-toggle:hover, .credits-toggle:focus-visible{ color: var(--accent); border-color: var(--accent-line); }

/* ============================================================
   PROFESSIONAL PROOF — wraps Credits + Collaboration (Patch 01 §3)
   Sub-blocks are independently SHOW/HIDE; the whole section hides
   only when both sub-blocks are hidden.
============================================================= */
.proof-grid{ display:grid; grid-template-columns: 1fr 1fr; gap: var(--space-section); }
.proof-block__title{
  font-family: var(--font-display); font-weight: 600; font-size: 15px;
  color: var(--text-secondary); margin: 0 0 var(--space-md);
  text-transform: uppercase; letter-spacing: .04em;
}
.proof-block[hidden]{ display:none; }

/* ============================================================
   COLLABORATION
============================================================= */
.collab-list li{
  padding: 14px 0; border-bottom: 1px solid var(--border-soft);
  display:flex; gap: 20px; font-size: 14px;
}
.collab-year{ color: var(--text-tertiary); width: 60px; flex-shrink:0; }
.collab-desc{ color: var(--text-primary); }

/* ============================================================
   VIDEO
============================================================= */
/* 3-up on desktop (Patch 02 §13 — Video is the density return after
   Career/Proof quiet down). All 3 static video cards sit in one row
   instead of 2-up-then-orphan, so the section reads as a deliberate
   dense grid rather than an uneven leftover layout. Tablet steps back
   to 2-up at 992px, mobile to 1-up at 768px (existing rule below). */
.video-grid{ display:grid; grid-template-columns: repeat(3, 1fr); gap: clamp(16px, 2vw, 28px); }
/* Wrapper — 정보 표시 컨테이너일 뿐, 자체 클릭 영역이 아니다 (Patch 20260926_02 §04/§07-2) */
.video-card{ display: block; width: 100%; cursor: default; }
/* Trigger — 썸네일만 클릭 가능한 Modal 진입점 */
.video-card__trigger{
  display: block; width: 100%; padding: 0; border: 0; background: none;
  color: inherit; cursor: pointer; text-align: left;
}
.video-card__trigger .asset-slot{ aspect-ratio: 16/9; position: relative; border: 0; overflow: hidden; }

/* Premium-aligned play control (Patch §09-2, selector migrated to
   .video-card__trigger in Patch 20260926_02 §07-1) — 48px circle, CSS
   triangle child element on every viewport (Desktop/Mobile 동일 크기,
   §07 Important — Mobile에서 별도로 축소하지 않는다). */
.video-card__trigger .asset-slot::after{
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;

  width: 48px;
  height: 48px;
  border-radius: 50%;

  background: rgba(10, 11, 13, 0.55);
  box-shadow: inset 0 0 0 1.5px rgba(245, 245, 244, 0.9);

  transform: translate(-50%, -50%);
  transition:
    background var(--motion-fast) var(--ease-standard),
    transform var(--motion-fast) var(--ease-standard),
    box-shadow var(--motion-fast) var(--ease-standard);
}
.video-card__trigger .asset-slot::before{
  content: "";
  position: absolute;
  z-index: 2;
  top: 50%;
  left: 50%;

  width: 0;
  height: 0;
  border-style: solid;
  border-width: 7px 0 7px 11px;
  border-color: transparent transparent transparent var(--text-primary);

  transform: translate(calc(-50% + 2px), -50%);
  pointer-events: none;
  transition: border-color var(--motion-fast) var(--ease-standard);
}
@media (hover: hover){
  .video-card__trigger:hover .asset-slot::after{
    background: var(--accent);
    box-shadow: inset 0 0 0 1.5px var(--accent);
    transform: translate(-50%, -50%) scale(1.04);
  }
  .video-card__trigger:hover .asset-slot::before{ border-left-color: var(--bg); }
}
.video-card__trigger:focus-visible .asset-slot::after{
  background: var(--accent);
  box-shadow: inset 0 0 0 1.5px var(--accent);
  transform: translate(-50%, -50%) scale(1.04);
}
.video-card__trigger:focus-visible .asset-slot::before{ border-left-color: var(--bg); }
.video-card__trigger:focus-visible{ outline: 2px solid var(--accent); outline-offset: 4px; }
/* Mobile touch feedback (Patch §07-1) — :active mirrors the hover/focus
   accent state since (hover: hover) doesn't fire on touch devices. */
.video-card__trigger:active .asset-slot::after{
  background: var(--accent);
  box-shadow: inset 0 0 0 1.5px var(--accent);
  transform: translate(-50%, -50%) scale(1.04);
}
.video-card__trigger:active .asset-slot::before{ border-left-color: var(--bg); }

/* Info block — text-only, no click target (Patch §04/§06) */
.video-card__info{ padding-top: 8px; }
.video-card__title{
  font-family: var(--font-display); font-size: 1rem; font-weight: 500;
  line-height: 1.3; color: var(--text-primary); margin: 0;
}
.video-card__type{
  font-family: var(--font-body); font-size: var(--scale-small); line-height: 1.3;
  color: var(--text-secondary); margin: 2px 0 0;
}

/* ============================================================
   MEDIA MODAL (§22)
============================================================= */
.media-modal{ position: fixed; inset: 0; z-index: 300; display:flex; align-items:center; justify-content:center; padding: var(--modal-vpad) var(--edge); }
.media-modal[hidden]{ display: none; }
.media-modal__backdrop{ position:absolute; inset:0; background: rgba(0,0,0,0.7); backdrop-filter: blur(4px); }
.media-modal__panel{
  position: relative; z-index: 1;
  /* Stage — 폭은 min(뷰포트 92vw, --modal-max, 뷰포트 높이에 맞는 16:9 폭). 마지막 항이 낮은 노트북/가로
     모바일에서 모달이 세로로 잘리는 것을 막는다. dvh 미지원 브라우저는 vh 값을 쓴다. */
  width: min(92vw, var(--modal-max), calc((100vh - 2 * var(--modal-vpad) - var(--modal-chrome)) * 16 / 9 + 2 * var(--space-md)));
  width: min(92vw, var(--modal-max), calc((100dvh - 2 * var(--modal-vpad) - var(--modal-chrome)) * 16 / 9 + 2 * var(--space-md)));
  max-height: calc(100vh - 2 * var(--modal-vpad));
  max-height: calc(100dvh - 2 * var(--modal-vpad));
  overflow-y: auto;
  background: var(--bg-elevated); border: 1px solid var(--border);
  padding: 44px var(--space-md) var(--space-md); /* 상단 44px = 닫기 버튼 행(영상 위를 덮지 않는다) */
}
.media-modal__close{
  position:absolute; top: 6px; right: 8px; background:none; border:none; color: var(--text-secondary);
  font-size: 16px; line-height: 1; cursor:pointer; padding: 10px; z-index: 2;
}
.media-modal__close:hover, .media-modal__close:focus-visible{ color: var(--accent); }
.media-modal__frame{
  aspect-ratio: 16/9; margin-bottom: 16px; background: var(--bg);
}
.media-modal__frame iframe{ width:100%; height:100%; display:block; border:0; }
.media-modal__title{ font-size: 15px; color: var(--text-primary); margin: 0 0 4px; }
.media-modal__type{ font-size: 12px; color: var(--text-tertiary); margin:0; }

/* ============================================================
   PRESS
============================================================= */
/* Press index (Final Patch §08) — 카드/왼쪽 라인 없이, 가는 가로 구분선으로 나뉜 editorial 기사 목록.
   Headline은 왼쪽, Publication · Year · ↗ 는 오른쪽(모바일은 아래 줄로 스택). 행 전체가 링크다.
   Section 공통 좌/우 grid 축(.section-inner)을 그대로 쓴다. Hover = headline underline + ↗ accent. */
.press-list{ display: block; border-top: 1px solid var(--border); }
.press-card{
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; column-gap: var(--space-lg);
  padding: 22px 0; border-bottom: 1px solid var(--border);
  text-decoration: none; color: inherit;
}
.press-card__title{
  font-family: var(--font-serif); font-size: 19px; line-height: 1.5; margin: 0;
  color: var(--text-primary); text-underline-offset: 5px; text-decoration-thickness: 1px;
}
.press-card__meta{
  display: flex; align-items: baseline; gap: 8px; margin: 0;
  font-size: 13px; color: var(--text-tertiary); white-space: nowrap;
}
.press-card__year::before{ content: "·"; margin-right: 8px; }
.press-card__arrow{ font-size: 12px; color: var(--text-secondary); transition: color var(--motion-fast) var(--ease-standard); }
/* hover는 터치에서 고정(sticky)되므로 (hover: hover)로 한정하고, 터치/키보드는 :active / :focus-visible가 같은 반응(underline + ↗ accent)을 준다. */
@media (hover: hover){
  .press-card:hover .press-card__title{ text-decoration: underline; }
  .press-card:hover .press-card__arrow{ color: var(--accent); }
}
.press-card:focus-visible .press-card__title,
.press-card:active .press-card__title{ text-decoration: underline; }
.press-card:focus-visible .press-card__arrow,
.press-card:active .press-card__arrow{ color: var(--accent); }
.press-card:active .press-card__title{ color: var(--accent); }
.press-card{ -webkit-tap-highlight-color: transparent; }
.press-card:focus-visible{ outline: 2px solid var(--accent); outline-offset: 4px; }
@media (max-width: 600px){
  .press-card{ grid-template-columns: 1fr; row-gap: 6px; padding: 18px 0; }
  .press-card__title{ font-size: 18px; }
}

/* ============================================================
   CONTACT — Closing Composition (Patch 02 §15, rebalanced Patch 03 §06/07,
   image-crop sync added after feedback)
   Desktop: Contact Info 50% | Artist Image 50%, info column first in
   both DOM order and reading priority so it's read before the image.
   align-items: stretch keeps both outer columns on the same top/bottom
   grid boundary. Within that, the *visible* content on each side is
   additionally bottom-anchored: info's card+socials group via CSS
   (flex-end), and the image via script.js measuring that group's actual
   height and applying it to the image (see initContactVisualSync) — so
   the image is cropped to the same vertical span as the info content
   rather than stretching to fill the full column. CSS alone provides
   the JS-off fallback (image fills the full column height instead —
   no clipping/overflow either way, just not height-matched).
   Mobile (§07): visual order flips to Image → Info via `order` only —
   DOM/semantic order is untouched. Image is optional in markup —
   .contact-layout still works as a single column if .contact-visual
   isn't present.
============================================================= */
.contact-layout{
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(36px, 5vw, 64px);
  align-items: stretch;
}
.contact-info{ min-width: 0; display: flex; flex-direction: column; justify-content: flex-end; }
/* Single measurable group (card + social icons, normal --space-lg gap
   between them) that script.js reads the height of to size the image
   to match. justify-content:flex-end on the parent bottom-anchors this
   whole group; any leftover column height collects above it. */
.contact-info__content{ display: flex; flex-direction: column; gap: var(--space-lg); }
/* Contact fields stack in a single column inside the 50% info column
   (the original 3-up grid assumed the full section width) so
   Booking/Management stay readable instead of being squeezed
   into narrow slivers. Booking-only case (.contact-panel--compact)
   already renders as one column and is unaffected. */
.contact-info .contact-panel{ grid-template-columns: 1fr; gap: var(--space-md); margin-bottom: 0; }
.contact-visual{ min-width: 0; display: flex; align-items: flex-end; }
/* height:100% is the JS-off / pre-hydration fallback (fills the full
   stretched column, matching the outer grid boundary). Once
   initContactVisualSync measures .contact-info__content, it sets an
   inline height on this element that overrides the 100% and matches
   the info content's actual height — align-items:flex-end on the
   parent then bottom-anchors the now-shorter image so both the info
   group and the image share the same top and bottom line. */
.contact-visual .asset-slot{ height: 100%; max-height: 560px; border: none; background: transparent; }
@media (max-width: 768px){
  .contact-layout{ grid-template-columns: 1fr; gap: var(--space-lg); }
  .contact-visual{ order: 1; }
  .contact-info{ order: 2; }
  /* Single-column stack has no row to stretch/match against, so fall
     back to the inline aspect-ratio (4/5) for sizing regardless of any
     JS-applied inline height — avoids a 0-height collapse and keeps
     mobile unaffected by the desktop-only height sync. */
  .contact-visual .asset-slot{ height: auto !important; max-height: 360px; }
}

/* Contact intro copy (Patch 06 §01) — now lives inside .contact-panel
   as its first row so intro + Booking + Management read as one
   merged section; divider line separates it from the contact blocks.
   No max-width clamp — lets it run on one line at the column widths
   this section actually uses, wrapping only if the viewport is too
   narrow to fit it (never forced nowrap, to avoid overflow). */
.contact-intro{
  font-size: 14px; color: var(--text-secondary); line-height: 1.5;
}
.contact-panel .contact-intro{
  border-bottom: 1px solid var(--border);
  padding-bottom: var(--space-sm);
  /* Grid `gap` on .contact-panel already adds var(--space-md) after this
     row; without this, the divider sits 12px below the text but 24px
     above Booking — off-center and out of rhythm with the rest of the
     panel (Booking↔Management also uses --space-md). Pull the next
     row in by the difference so the divider sits symmetrically
     (--space-sm on both sides), matching the panel's internal ratio. */
  margin-bottom: calc(var(--space-sm) - var(--space-md));
}

.contact-panel{
  display:grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-md);
  padding: var(--space-lg); border: 1px solid var(--border); background: var(--bg-elevated);
  margin-bottom: var(--space-lg);
}
/* Booking-only (Missing Data case) — single block shouldn't stretch
   across a 3-column grid meant for up to three contact methods. */
.contact-panel--compact{ grid-template-columns: minmax(0, 360px); }
.contact-block{ display:flex; flex-direction:column; align-items:flex-start; gap: 6px; }
.contact-block__label{ font-size: 12px; color: var(--text-tertiary); text-transform:uppercase; letter-spacing:.05em; }
.contact-block__value{ font-size: 15px; overflow-wrap: anywhere; }
a.contact-block__value:hover{ color: var(--accent); }

/* Primary contact (Booking) — the one CTA priority this section
   should make unmistakable at a glance (STEP 05 §16). */
.contact-block--primary .contact-block__label{ color: var(--accent); }
.contact-block--primary .contact-block__value{
  font-family: var(--font-display); font-weight: 600; font-size: 18px;
}
/* Contact channel icons (STEP 06 §16) — original line-art SVGs using
   currentColor, never the platform's own brand color. */
.social-links{ display:flex; flex-wrap: wrap; gap: 14px; }
.social-links[hidden]{ display:none; }
.social-icon{
  display:flex; align-items:center; justify-content:center;
  width: 40px; height: 40px; border: 1px solid var(--border);
  color: var(--text-secondary);
  transition: color var(--motion-fast) var(--ease-standard), border-color var(--motion-fast) var(--ease-standard);
}
.social-icon svg{ width: 18px; height: 18px; }
/* Hover / Focus / Active (Final Patch §09) — 마우스 hover만으로 Icon과 Border가 accent로 바뀐다.
   touch 기기는 sticky hover를 피하려고 hover를 (hover: hover)로 한정하고 :active가 짧은 피드백을 준다. */
@media (hover: hover){
  .social-icon:hover{ color: var(--accent); border-color: var(--accent); }
}
.social-icon:focus-visible{ color: var(--accent); border-color: var(--accent); outline: 2px solid var(--accent); outline-offset: 3px; }
.social-icon:active{ color: var(--text-primary); border-color: var(--text-primary); }

/* ============================================================
   FOOTER
============================================================= */
.site-footer{ border-top: 1px solid var(--border); padding: 32px 0; color: var(--text-secondary); font-size: 12px; }
.footer-copyright,
.footer-signature,
.footer-note{
  margin: 0; font-family: var(--font-body); font-size: 12px; font-weight: 400;
  line-height: 1.5; color: var(--text-secondary);
}
/* Desktop(≥1024): 한 행 3열 — copyright(왼쪽) | 데모 안내(가운데) | SOUND FRAME credit(오른쪽).
   DOM 순서는 copyright → signature → note 그대로, 배치만 grid-column으로 한다. */
.footer-inner{
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: baseline; column-gap: var(--space-md); row-gap: 8px;
}
.footer-copyright{ grid-column: 1; grid-row: 1; justify-self: start; }
.footer-note{ grid-column: 2; grid-row: 1; justify-self: center; text-align: center; }
.footer-signature{ grid-column: 3; grid-row: 1; justify-self: end; text-align: right; }
/* Tablet / Mobile(<1024): copyright | signature 한 행, 데모 안내는 마지막 행. */
@media (max-width: 1023px){
  .footer-inner{ grid-template-columns: 1fr auto; }
  .footer-note{ grid-column: 1 / -1; grid-row: 2; justify-self: start; text-align: left; margin-top: 4px; }
}
@media (max-width: 600px){
  .footer-inner{ grid-template-columns: 1fr; }
  .footer-copyright, .footer-signature, .footer-note{ grid-column: 1; grid-row: auto; justify-self: start; text-align: left; }
}

/* ============================================================
   RESPONSIVE — 1440 / 1280 / 1024 / 992 / 834 / 768 / 480
   Patch 01 §5 재검토 결과:
   Hero 2열 유지 구간을 992→834까지 확장. 834(iPad 계열 portrait)에서도
   Artist Name/Positioning/CTA가 한 줄 유지에 문제 없고 Page Fold 안에
   Listen CTA까지 들어오는 걸 확인. 768 이하(폰 폭)에서만 1열로 전환.
============================================================= */
@media (max-width: 992px){
  .works-grid{ grid-template-columns: repeat(2, 1fr); }
  /* Video steps down from the desktop 3-up before Works' own 2-up
     breakpoint would otherwise make three 33vw-wide cards uncomfortably
     tight (Patch 02 §13). */
  .video-grid{ grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 834px){
  .proof-grid{ grid-template-columns: 1fr; gap: var(--space-lg); }
}

@media (max-width: 768px){
  .main-nav{ display:none; }
  .nav-toggle{ display:block; }
  .site-header.is-nav-open .main-nav{
    display:flex; position:absolute; top:100%; left:0; right:0;
    flex-direction:column; background: var(--bg); border-bottom: 1px solid var(--border);
    padding: var(--space-md) var(--edge); gap: 18px;
  }

  /* Hero collapses to 1 column here, not at 992 (Patch 01 §5).
     Portrait renders first (source order) so it's the first thing in
     the mobile viewport, not text-first (Final Cleanup §07). Sized to
     read as a real hero visual, not a small thumbnail. */
  .hero-inner{ grid-template-columns: 1fr; }
  .hero-visual{ display:flex; justify-content:center; }
  .hero-visual .asset-slot{ width: 100%; max-width: 380px; }

  /* Mobile Hero copy width (Patch §06-6/§12) — text reads across the
     full section content width, not a narrow 320~380px column. */
  .hero-copy{ width: 100%; max-width: none; }
  .hero-position{ width: 100%; max-width: none; }
  .hero-cta{ width: 100%; }

  /* Fixed breakpoint typography — Mobile (Patch 20260926_02 §10-3) */
  .hero-copy .eyebrow{ font-size: 0.875rem; }
  .hero-name{ font-size: 3rem; }
  .hero-position{ font-size: 1rem; }

  /* Mobile profile flow: Snapshot section hidden, compact meta line
     shown inside Hero instead (Patch 01 §6 — Option B) */
  .snapshot{ display: none; }
  .hero-meta-mobile{ display: block; }

  .video-grid{ grid-template-columns: 1fr; }

  /* Selected Works on mobile — 1 column, large image, not a dense
     thumbnail grid (Final Cleanup §11). */
  .works-grid{ grid-template-columns: 1fr; }

  /* Player C+ on mobile — Artwork → Title/Meta → Embed → Platform,
     vertical stack (Final Cleanup §10). Artwork stays a real visual
     anchor for the section, not a small icon-sized thumbnail. */
  .player{
    flex-direction: column; align-items: stretch; gap: 16px;
    width: 100%; min-width: 0; overflow: hidden;
    justify-content: flex-start;
    /* Tighter horizontal padding than the desktop card so the Spotify
       embed gets closer to its own comfortable minimum render width
       (~300px) instead of being squeezed by a 40px card gutter. */
    padding: var(--space-md) 20px;
  }
  .player-artwork{ flex: 0 0 auto; width: 100%; }
  .player-artwork .asset-slot{ width: 100%; max-width: 320px; margin: 0 auto; }
  .player-info{ text-align: center; }
  .player-embed{ flex: none; width: 100%; max-width: 100%; min-width: 0; }
  .music-embed__frame{ width: 100%; max-width: 100%; min-width: 0; }
  /* Embed → Spotify CTA gap eased to ~12px (was 8px — read as too tight
     in practice); Artwork/Info keep the full 16px breathing room. */
  .player-platforms{ margin-left: 0; margin-top: -4px; justify-content: center; width: 100%; }

  /* Primary track (Low Signal) — Embed is the sole mobile listen surface,
     the external Spotify CTA row is hidden here (STEP 06 Production
     Content Patch 04 §06). Desktop keeps both Embed and CTA. */
  .player:not(.player--secondary) .player-platforms{ display: none; }

  /* Secondary tracks (Glass Room / After 2AM) — Desktop shows the full
     Player (Artwork + Embed + CTA, identical grammar to Low Signal, §04).
     Mobile collapses the SAME DOM to a compact listen-link row: Artwork
     and Embed are hidden, only Title/Meta + Spotify CTA remain visible
     (Patch 04 §06 — no separate mobile markup, no duplicate DOM). */
  .player--secondary{
    flex-direction: row; align-items: center; justify-content: space-between;
    gap: 16px; width: 100%; min-width: 0; overflow: visible;
    border: none; border-bottom: 1px solid var(--border-soft);
    background: transparent; padding: 14px 4px;
  }
  .player--secondary .player-artwork,
  .player--secondary .player-embed{ display: none; }
  .player--secondary .player-info{ text-align: left; flex: 1 1 auto; min-width: 0; }
  .player--secondary .player-platforms{
    display: flex; margin: 0; width: auto; justify-content: flex-end; flex-shrink: 0;
  }

  /* Mobile motion reduction (STEP 05 §20) — shorter travel distance,
     standard timing instead of the longer editorial duration */
  .reveal{
    transform: translateY(10px);
    transition: opacity var(--motion-standard) var(--ease-standard),
                transform var(--motion-standard) var(--ease-standard);
  }

  .contact-panel{ grid-template-columns: 1fr; }

  /* Video Modal on mobile — never overflow the viewport (Final Cleanup §14) */
  .media-modal{ padding: var(--modal-vpad) 3vw; }
  .media-modal__panel{
    width: min(94vw, calc((100vh - 2 * var(--modal-vpad) - var(--modal-chrome)) * 16 / 9 + 2 * var(--space-md)));
    width: min(94vw, calc((100dvh - 2 * var(--modal-vpad) - var(--modal-chrome)) * 16 / 9 + 2 * var(--space-md)));
  }

  /* Contact icons — 44px minimum touch target (Final Cleanup §16) */
  .social-icon{ width: 44px; height: 44px; }

  /* Footer layout comes from the shared Premium-aligned .footer-inner
     rule + the 600px override below (Patch 20260926_02 §09-3) — no
     separate mobile-only column stack here. */
}

@media (max-width: 480px){
  .career-list li{ grid-template-columns: 72px 1fr; gap: 14px; }
  .hero-cta .btn{ flex: 1 1 auto; }
}

/* Fixed breakpoint typography — 390px 이하 (Patch 20260926_02 §10-3) */
@media (max-width: 390px){
  .hero-name{ font-size: 2.75rem; }
}
