/*
아이패드 가로형 레이아웃 레이어입니다.

기준 해상도는 1180 × 820 (아이패드 11" 가로) 하나이고,
1024 × 768 ~ 1366 × 1024 는 기기별 레이아웃이 아니라 스케일로 대응합니다.
— 토스 해상도 가이드 "하나의 기준 해상도를 정하고 스케일링으로 대응한다"

이 파일은 app.css 뒤에 마지막으로 불러옵니다.
좁은 화면(max-width) 규칙은 건드리지 않고, 넓은 화면에만 얹습니다.

세로 예산이 이 파일의 핵심입니다.
820px 에서 상단 바를 뺀 764px 안에 각 화면의 주인공과 다음 버튼이 들어가야 합니다.
— 토스 그래픽 가이드 "핵심 정보가 아래로 밀려 불필요한 스크롤이 생기지 않게 한다"
*/

:root {
  /* 데스크톱에서는 이 내부 좌표계를 바꾸지 않고 화면 바깥에서만 축소한다. */
  --artboard-w: 1336px;
  --artboard-h: 1024px;
  --artboard-scale: 1;
  --topbar-h: 64px;
  /* 화면 좌우 여백. 1024 에서 20px, 1366 에서 38px 언저리로 자란다 */
  /* --vw 는 기본이 100vw 라 모바일은 지금 그대로이고, 아트보드 안에서는
     1336px 을 읽는다 — 1336 × 2.8% = 37.4px 로 예전 2.8vw 가 1336 창에서
     내던 값과 같다. 기준 해상도의 픽셀은 한 칸도 안 움직인다 */
  --gutter: clamp(20px, calc(var(--vw) * .028), 40px);
  /* 본문 최대 폭. 1180 에서 1112px */
  --shell: min(1320px, 100% - var(--gutter) * 2);
  /* 상단 바를 뺀 실제 사용 가능한 높이. --vh 가 모바일에서는 실제 창(100vh),
     아트보드 안에서는 1024px 이다 */
  --app-h: calc(var(--vh) - var(--topbar-h));
  --pane-gap: clamp(14px, calc(var(--vw) * .016), 24px);
  /* 부스에서 관람객 머리가 화면 아래를 가린다. 거치대에 세운 아이패드라
     하단 20%에 놓인 것은 사실상 안 보인다 — 하단 고정 CTA 가 딱 그 자리에 있었다(726~796).
     px 로 박으면 세로가 큰 기기(1366x1024)에서 다시 걸린다. 비율로 잡는다.
     실제 가림 정도가 다르면 이 값 하나만 바꾸면 모든 화면이 따라온다. */
  --safe-bottom: calc(var(--vh) * .2);
}

@media (min-width: 900px) {

  /* 1336×1024 iPad Pro 아트보드. 노트북에서는 레이아웃을 눌러 담지 않고
     JS가 계산한 배율로 화면 전체를 같은 비율로 줄인다. */
  html {
    width: 100%; height: 100%; overflow: hidden;
    background: radial-gradient(circle at 50% 0%, #f7faf8 0, #edf2ef 72%);
  }
  body {
    position: fixed; left: 50%; top: 50%;
    width: var(--artboard-w); height: var(--artboard-h); min-height: var(--artboard-h);
    overflow: auto;
    transform: translate(-50%, -50%) scale(var(--artboard-scale));
    transform-origin: center;
    box-shadow: 0 24px 72px rgba(6, 48, 39, .14), 0 0 0 1px rgba(6, 48, 39, .07);
  }
  :root {
    --gutter: 38px;
    --app-h: calc(var(--artboard-h) - var(--topbar-h));
    --safe-bottom: 205px;
  }

  /* ══ 0. 앱 셸 ═══════════════════════════════════════════════
     내비는 고정이고 본문은 그만큼 밀린다. 폭을 --nav-w 로 두는 이유:
     .verdict·.t-band 의 전면폭 계산(calc(50% - 50vw + var(--nav-w)/2))이
     같은 값을 타야 가로 스크롤이 안 난다. */
  :root {
    --nav-w: 176px;
    /* 여기서부터 화면 단위는 실제 창이 아니라 아트보드다. 이 두 줄이
       --gutter·--app-h·--safe-bottom 을 비롯한 모든 파생값을 한 번에 돌린다 */
    --vw: var(--artboard-w);
    --vh: var(--artboard-h);
  }

  /* ── 아트보드 ────────────────────────────────────────────────
     1336×1024 한 판을 통째로 축소해 창 가운데 놓는다. 예전에는 창 크기에
     따라 요소마다 다르게 줄어서, 1920 모니터에서는 오른쪽 200px 이 죽고
     1366×768 에서는 세로가 눌렸다 — 같은 화면인데 어디를 보라가 매번 달랐다.
     스케일 값은 app.js 의 syncArtboard() 가 --artboard-scale 에 써 넣는다. */
  html {
    height: 100%;
    /* 판 바깥. 아주 옅은 회녹색이라 크림 배경 위에서도 판의 경계가 읽힌다 */
    background: #F1F3F1;
    /* 판 밖으로는 스크롤이 없다 — 이중 스크롤을 여기서 끊는다 */
    overflow: hidden;
  }
  body {
    position: fixed; left: 50%; top: 50%;
    width: var(--artboard-w); height: var(--artboard-h);
    transform: translate(-50%, -50%) scale(var(--artboard-scale));
    transform-origin: center center;
    padding-left: var(--nav-w);
    background: var(--canvas);
    /* 스크롤은 body 가 아니라 .artboard-scroll 이 맡는다 — body 가 직접
       스크롤하면 왼쪽 내비가 판을 containing block 으로 쓰는 fixed 라도
       스크롤 컨테이너와 함께 밀려 올라간다 (실제로 800px 짜리를 넣어 보니
       내비 top 이 -300 까지 갔다) */
    overflow: hidden;
    /* 판의 경계. 그림자는 여기 한 곳뿐이고 버튼에는 쓰지 않는다 */
    box-shadow: 0 1px 2px rgba(24, 24, 27, .05), 0 10px 34px rgba(24, 24, 27, .07);
  }
  /* 판 안의 스크롤 상자. 폭이 body 의 content box 와 같아서 .verdict·.t-band 의
     전면폭(±37.5px)이 정확히 이 상자 끝에 맞는다 — main 을 스크롤러로 삼으면
     그 전면폭이 잘려 나간다 */
  .artboard-scroll {
    display: block; height: 100%;
    overflow: hidden auto;
    /* 판이 이미 경계를 그리므로 스크롤바는 얇게 */
    scrollbar-width: thin;
  }

  /* 랜딩은 판을 안 쓴다 — 스크롤로 읽는 문서라 1024px 에 가둘 수 없다 */
  body:has(main.landing) {
    position: static; width: auto; height: auto;
    transform: none; overflow: visible; box-shadow: none;
  }
  html:has(main.landing) { height: auto; overflow: visible auto; background: var(--canvas); }

  .sidenav {
    display: flex; flex-direction: column; gap: 4px;
    position: fixed; inset: 0 auto 0 0; z-index: 60;
    width: var(--nav-w); padding: 14px 12px 16px;
    background: var(--surface); border-right: 1px solid var(--border);
  }
  .sidenav-brand {
    display: flex; align-items: center; gap: 8px;
    padding: 6px 8px 14px; font-size: 15px; font-weight: 700;
    color: var(--text); text-decoration: none; letter-spacing: -.02em;
  }
  .sidenav-brand .brand-mark { width: 22px; height: 22px; flex: none; }
  .sidenav-brand .brand-app-icon { width: 30px; height: 30px; border-radius: 9px; }
  .sidenav-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
  /* 7px 이던 세로 패딩. 아이패드로 쓰는 화면인데 줄 높이가 32px 이라 손가락
     기준(44px)에 한참 못 미쳤다. 아이콘이 들어오면서 줄이 자연히 42px 이 된다 */
  .sidenav-list a, .sidenav-foot {
    display: flex; align-items: center; gap: 10px;
    padding: 10px; border-radius: var(--r-ctl);
    font-size: var(--t-body); font-weight: 500; color: var(--text-2);
    text-decoration: none; transition: background .12s ease, color .12s ease;
  }
  .nav-ico {
    width: 20px; height: 20px; flex: none;
    fill: none; stroke: currentColor; stroke-width: 1.7;
    stroke-linecap: round; stroke-linejoin: round;
    color: var(--text-3); transition: color .12s ease;
  }
  .sidenav-list a:hover, .sidenav-foot:hover { background: var(--hover); color: var(--text); }
  .sidenav-list a:hover .nav-ico { color: var(--text-2); }
  /* 지금 보는 칸. aria-current 는 route() 가 붙인다 — 색만으로 말하지 않는다
     (글자 무게도 같이 올린다). 회색 면이었는데, 그러면 「눌리지 않은 버튼」처럼
     보이지 «여기 있다»로는 안 읽혔다. 브랜드 색을 옅게 깔고 글자와 아이콘에
     딥그린을 준다 — 내비에서 브랜드 색이 뜻하는 건 하나, 지금 이 자리다. */
  .sidenav-list a[aria-current="page"] {
    background: var(--brand-weak); color: var(--navy); font-weight: 650;
  }
  .sidenav-list a[aria-current="page"] .nav-ico { color: var(--brand); stroke-width: 1.9; }
  /* 이 앱에서 제일 자주 누를 버튼. 탑바 오른쪽 구석에 떠 있던 걸 내비 맨 위로
     올렸다 — 왼쪽 칸이 이름 셋만 얹은 채 세로로 텅 비어 있었고, 주 액션은
     화면마다 찾아 헤매지 않아도 되는 자리에 있어야 한다 */
  .sidenav-cta {
    display: flex; align-items: center; justify-content: center;
    /* 아래 메뉴 줄들과 같은 44px 손가락 기준으로 맞춘다. 12px 여백은 버튼과
       메뉴를 한 덩어리로 붙지 않게 띄우는 값이다 — 성격이 다른 둘이다 */
    margin: 0 0 12px; min-height: 44px; padding: 11px 12px;
    font-size: var(--t-body); font-weight: 650; letter-spacing: -.01em;
  }
  /* 맨 아래 병아리 넷 — 홈 본문에 있던 띠를 옮겼다. 화면마다 사라지지 않고
     「누가 보고 있는지」를 계속 알려 주면서 아래 여백을 메운다 */
  .sidenav-foot {
    margin-top: auto; font-size: var(--t-meta); color: var(--text-3);
    display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
    padding: 12px 10px;
  }
  /* .ch-seat 은 객석 입장 연출용이라 opacity:0 에 좌석 폭(clamp 124~178px)을 들고 온다.
     여기는 그 연출을 타지 않으므로 design-system.css 의 앱 화면 규칙과 같이 풀어 준다 */
  .sidenav-crew { display: flex; align-items: flex-end; }
  .sidenav-crew .ch-seat {
    width: 30px; flex: none; margin-right: -8px;
    opacity: 1; transform: none; filter: none; animation: none;
    transition: transform .18s var(--ease);
  }
  .sidenav-crew .ch-seat:last-child { margin-right: 0; }
  .sidenav-crew .ch-seat svg { width: 100%; height: auto; display: block; }
  .sidenav-foot:hover .sidenav-crew .ch-seat { transform: translateY(-2px); }

  /* 브랜드는 내비가 갖는다. 탑바에 또 두면 로고가 둘이다.
     「새 발표 연습」도 내비로 내려갔으므로 탑바에 남는 건 이어하기뿐이다 */
  .topbar > .brand { display: none; }
  .topbar-right #topFresh { display: none; }
  /* 브랜드를 내비로 옮기고 나니 탑바가 버튼 하나만 든 빈 흰 띠가 됐다.
     면과 선을 걷어내면 띠가 아니라 「본문 위에 뜬 버튼」으로 읽힌다 —
     sticky·높이는 그대로라 #rtabs 의 sticky top 계산이 안 흔들린다 */
  .topbar {
    justify-content: flex-end;
    background: none; border-bottom: 0;
  }

  /* 랜딩은 마케팅 화면이라 앱 크롬을 걸치지 않는다 (MVP_SPEC §4) */
  body:has(main.landing) { padding-left: 0; }
  body:has(main.landing) .sidenav { display: none; }
  body:has(main.landing) .topbar > .brand { display: flex; }

  /* ══ 1. 셸 ══════════════════════════════════════════════════ */

  .topbar { height: var(--topbar-h); padding: 0 var(--gutter); }

  main {
    width: var(--shell);
    max-width: none;
    /* 96px 이던 하단 여백은 세로가 넉넉한 데스크톱 기준이었다 */
    padding: 18px 0 24px;
  }
  main.wide { max-width: none; }
  main.narrow { width: min(880px, 100% - var(--gutter) * 2); max-width: none; }
  /* 랜딩만 전면폭이다(MVP_SPEC §4). landing.css 는 max-width 만 풀어 놨으므로
     위의 main { width: var(--shell) } 을 여기서 되돌려 준다 */
  main.landing { width: 100%; padding: 0; }

  /* 세로 스크롤이 필요 없는 화면은 높이를 예산으로 고정한다 */
  main.home,
  main.narrow { min-height: var(--app-h); }

  .card { padding: 20px 22px; }
  .page-head { margin-bottom: 16px; }
  .page-title { font-size: 22px; }

  /* ══ 스텝 4(질문 준비) — 한 줄로 쌓으면 넘친다 ═══════════════
     실측(1180x820): 내용이 976px 인데 예산은 764px 라 275px 가 넘쳤다.
     그런데 이 화면은 main.narrow(880px) 한 줄만 쓰고 좌우가 비어 있었다.

     기다리는 사람이 보는 것(상태 줄·체크리스트·다음 버튼)을 왼쪽에,
     확인하러 들어가는 것(커튼 뒤·검증 로그)을 오른쪽에 둔다.
     :has() 로 스텝 4 카드만 집는다 — app.js 를 안 건드리려는 것이고,
     :has() 를 못 읽는 브라우저는 지금처럼 한 줄로 쌓인다(깨지지 않는다). */
  main.narrow:has(.pipe-inspect) { width: min(1120px, 100% - var(--gutter) * 2); }
  main.narrow > .card:has(.pipe-inspect) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: 22px;
    align-content: start;
  }
  /* 왼쪽: 기다리는 동안 눈이 가는 것. 행을 명시해 두 칸의 짝을 고정한다 —
     한 그리드의 행 높이는 두 칸이 공유하므로, 자동 배치에 맡기면 오른쪽에
     항목이 하나 늘 때마다 왼쪽 체크리스트가 하단 고정 버튼 밑으로 밀린다 */
  main.narrow > .card:has(.pipe-inspect) > .section-title { grid-area: 1 / 1; }
  main.narrow > .card:has(.pipe-inspect) > .note { grid-area: 2 / 1; }
  main.narrow > .card:has(.pipe-inspect) > .pipe-status-bar { grid-area: 3 / 1; }
  main.narrow > .card:has(.pipe-inspect) > .checklist { grid-area: 4 / 1; }
  main.narrow > .card:has(.pipe-inspect) > .stage-accident { grid-area: 5 / 1; }
  main.narrow > .card:has(.pipe-inspect) > .step-actions { grid-area: 6 / 1; }
  /* 오른쪽: 확인하러 들어가는 것 — 타임라인·커튼·개념 지도·검증 로그 */
  main.narrow > .card:has(.pipe-inspect) > .pipe-tl { grid-area: 1 / 2 / 4; }
  main.narrow > .card:has(.pipe-inspect) > .backstage,
  main.narrow > .card:has(.pipe-inspect) > .bs-stage { grid-area: 4 / 2; }
  /* 개념 지도(wait-graph)는 피드가 빠진 5/2 자리에 들어간다. 배치 규칙이 없으면
     자동 배치로 왼쪽 열에 흘러들어, 하단 고정 버튼줄(sticky + --safe-bottom)이
     그래프 한복판을 덮는다 — 1366×1024 실측으로 확인 (2026-08-10).
     피드(pipe-feed)를 화면에 되살리면 이 자리를 두고 부딪히니 행을 다시 나눠야 한다 */
  main.narrow > .card:has(.pipe-inspect) > .pipe-feed { grid-area: 5 / 2; }
  main.narrow > .card:has(.pipe-inspect) > .wait-graph { grid-area: 5 / 2; margin: 0; }
  main.narrow > .card:has(.pipe-inspect) > .pipe-inspect { grid-area: 6 / 2; }
  /* 왼쪽 칸이 679px 에서 끝나 버튼줄이 가림 영역에 23px 걸쳤다.
     항목 다섯 줄에서 조금씩 덜어 656 위로 올린다 */
  main.narrow > .card:has(.pipe-inspect) > .checklist li { padding-top: 9px; padding-bottom: 9px; }
  /* 버튼줄을 흐름에 두면 내용 길이에 따라 가림 영역에 걸친다(실측 670~690).
     스텝 1·2 와 같은 하단 고정 CTA 로 통일한다 — 왼쪽 칸을 예산만큼 세워야
     sticky 가 걸린다 */
  main.narrow:has(.pipe-inspect) { min-height: var(--app-h); }
  main.narrow > .card:has(.pipe-inspect) { min-height: calc(var(--app-h) - 96px); }
  main.narrow > .card:has(.pipe-inspect) > .step-actions {
    position: sticky; bottom: var(--safe-bottom); z-index: 5;
    margin-top: auto; padding: 12px 0 4px; align-self: end;
    background: linear-gradient(to top, var(--surface) 72%, transparent);
  }
  /* 오른쪽 칸이 길어지면 그 안에서만 스크롤한다 — 페이지는 그대로.
     ── 190px 이 왜 안 먹었나 (2026-08-07 실측, 1180x820) ──
     이 뺄셈은 검증 로그 위에 타임라인만 있던 시절 값이다. 그 뒤 커튼 뒤(.bs-stage
     196px)와 진행 피드(.pipe-feed 50px)가 같은 칸에 들어왔는데 뺄셈은 그대로라
     상한이 566px 로 남았고, 실제 높이 263px 는 거기에 안 걸렸다. 그래서 오른쪽 칸이
     683px 까지 자라 카드가 793px 이 되고 예산(727px)을 118px 넘겼다.
     ── 상한을 같은 칸의 위쪽(타임라인+커튼+피드 ≈ 420px)까지 빼고 잡는다.
     이 칸에 무엇을 더 넣으면 이 숫자도 같이 커져야 한다 */
  main.narrow > .card:has(.pipe-inspect) > .pipe-inspect {
    max-height: calc(var(--app-h) - 615px); overflow-y: auto; scrollbar-width: thin;
  }

  /* ══ 스텝 4 — 넓고 세로 여유가 있는 화면(아이패드 프로 가로 1366×1024)은
     폭을 다 쓰고 스크롤 없이 한 화면에 다 넣는다 ═══════════════
     기본 2단은 검증 로그가 접힌 채 아래로 밀려 페이지가 1.5화면이 됐다 —
     접히는 게 아니라 잘린 것처럼 읽힌다 (2026-08-10 지적). 여기서는 카드
     높이를 화면 예산에 고정하고, 검증 로그가 오른쪽 기둥 바닥까지 서서
     안에서만 스크롤한다. 세로 900px 미만(1366×768 노트북 등)은 이 예산이
     안 나오므로 기본 2단+페이지 스크롤을 유지한다 */
  @media (min-width: 1240px) and (min-height: 900px) {
    main.narrow:has(.pipe-inspect) { width: min(1560px, 100% - var(--gutter) * 2); }
    main.narrow > .card:has(.pipe-inspect) {
      /* 왼쪽은 읽는 기둥이라 420 이면 충분하고, 남는 폭은 전부 검증 로그가
         쓴다 — 슬라이드↔발화 매핑 카드가 이 폭에서 제일 답답했다 */
      grid-template-columns: minmax(320px, 420px) minmax(0, 1fr);
      /* 7행: 1~3 제목·설명·상태 / 4 체크리스트·커튼 / 5 사고 알림 / 6 버튼 / 7 남는 높이.
         오른쪽의 검증 로그는 5행부터 fr 행(7)까지 걸쳐 있어 카드 고정 높이에
         눌린다 — 안쪽 내용이 커져도 행을 밀어 올리지 못하고 안에서 스크롤한다 */
      grid-template-rows: auto auto auto auto auto auto minmax(0, 1fr);
      /* main 위아래 여백 18+24 에 스텝 헤더(#nf 단계 줄 ≈ 39px)까지 뺀 예산.
         실측 1366×1024: 카드 시작 y=121, 아래 여백 24 → 879 = app-h − 81 */
      height: calc(var(--app-h) - 81px);
      overflow: hidden;
    }
    /* 왼쪽 기둥 — 버튼은 하단 고정 대신 체크리스트 바로 아래 흐름에 둔다.
       고정 높이 카드에서는 페이지 스크롤이 없어 sticky 가 무의미하고,
       바닥에 붙이면 부스 가림 영역(--safe-bottom)으로 들어간다 */
    main.narrow > .card:has(.pipe-inspect) > .step-actions {
      position: static; margin-top: 14px; padding: 0; background: none;
      flex-wrap: wrap;
    }
    /* 기둥이 좁아도 버튼 글자를 낱말 중간에서 꺾지 않는다 — 줄로 내린다 */
    main.narrow > .card:has(.pipe-inspect) > .step-actions .btn { white-space: nowrap; }
    /* 오른쪽 기둥 — 타임라인(1~3행)·커튼(4행)은 기본 배치 그대로,
       검증 로그만 5행부터 바닥까지 세운다 */
    main.narrow > .card:has(.pipe-inspect) > .pipe-inspect {
      grid-area: 5 / 2 / 8 / 3;
      max-height: none; min-height: 0;
    }
  }

  /* 패널 안에서만 스크롤이 생기므로 스크롤바를 얇게 둔다 */
  .home-list, .qa-dialog .qa-stream, .slide-film, #jdetail { scrollbar-width: thin; }
  /* 태블릿은 관성 스크롤이 기본 기대치다 */
  .home-list, .qa-dialog .qa-stream, .slide-film { -webkit-overflow-scrolling: touch; }


  /* ══ 2. 홈 — 왼쪽 성장 기록 · 오른쪽 발표 목록 ══════════════
     980px 한 줄에 세로로 쌓으면 정작 주인공인 "내 발표" 목록이
     화면 밖으로 밀린다. 가로형에서는 두 단으로 나눠 한 화면에 같이 둔다.

     grid-template-areas 로 배치하는 이유:
     .resume-row 는 진행 중인 연습이 있을 때만 그려진다.
     행 번호로 배치하면 그때마다 한 칸씩 밀리므로 이름으로 고정한다. */

  /* 홈은 한 기둥이다. 예전엔 2단 대시보드였는데, 발표가 5건인데 칸을 둘로
     가르면 양쪽 다 비어 보인다. 표가 화면의 주인공이 되게 폭만 잡는다 */
  main.home {
    width: min(880px, 100% - var(--gutter) * 2);
    min-height: var(--app-h);
    padding-top: 28px;
  }

  /* 홈의 판정 헤드는 전면폭에서 빠져나오지 않고 왼쪽 칸 안에 앉는다.
     선택자를 main.home 으로 좁혀서 같은 컴포넌트를 쓰는 리포트를 건드리지 않는다 */
  main.home > .verdict {
    margin-inline: 0;
    margin-top: 0;
    padding: 18px 20px 16px;
    border-radius: var(--r-print);
  }
  main.home > .verdict .verdict-grid { grid-template-columns: 1fr; gap: 12px; padding-bottom: 0; }
  main.home > .verdict .verdict-score .vs-body { padding-top: 10px; }
  main.home > .verdict .verdict-score strong { font-size: 26px; }
  main.home > .verdict .verdict-score .delta { margin-top: 6px; }
  main.home > .verdict .hg-head { margin-bottom: 4px; }
  main.home > .verdict .hg-foot { margin-top: 8px; padding-top: 10px; }
  main.home > .verdict .hg-foot strong { font-size: 17px; }
  /* .growth-svg 는 overflow:visible 로 마지막 점과 값을 박스 밖에 그린다.
     max-height 로 누르면 .verdict 의 overflow:hidden 에 잘리므로,
     높이를 직접 정하고 폭을 비율로 따라오게 한다 */
  main.home > .verdict .growth-svg { height: 112px; width: auto; max-width: 100%; }

  main.home > .home-list .block-head {
    position: sticky; top: 0; z-index: 2;
    margin: 0; padding: 0 0 12px;
    background: var(--canvas);
  }


  /* ══ 3. 새 발표 연습 ════════════════════════════════════════ */

  /* 1·2·4 단계는 폼 한 장이다. 위쪽에 몰아두면 아래 절반이 빈다 —
     단계 표시줄은 위에 두고 폼만 남은 높이의 가운데에 놓는다 */
  main.narrow:has(#nf) { display: flex; flex-direction: column; min-height: var(--app-h); }
  /* 정중앙에 두면 자료를 올리는 첫 화면이 접힌 선 근처까지 내려간다.
     위에서 한 뼘만 띄우고, 남는 세로는 #nf 가 받아 아래 CTA 까지 밀어낸다.
     #nf 가 flex 기둥이 돼야 안쪽 .step-actions 의 margin-top:auto 와
     .rehearsal-shell 의 flex:1 이 살아난다 — 둘 다 #nf 의 자식이다 */
  main.narrow:has(#nf) > #nf {
    margin-block: clamp(8px, calc(var(--vh) * 0.04), 44px) 0;
    display: flex; flex-direction: column;
    flex: 1 1 auto; min-height: 0;
  }

  /* 자료 올리기 — 640px 상자로 묶어 가운데 띄웠더니 위의 단계 표시줄과 왼쪽 끝이
     어긋나고 아래로 700px 이 비었다. 게다가 비활성 「다음」 버튼을 걷어내고 나니
     화면에 상자 하나만 덩그러니 남았다.
     상자를 읽는 칸 전체로 넓히고 남는 세로도 받게 한다 — 그러면 작업 면 자체가
     과녁이 되고, 「여기 말고 저기에 떨어뜨려야 하나」를 고민할 자리가 없어진다 */
  main.narrow:has(#nf) .dropzone {
    max-width: none; margin-inline: 0;
    flex: 1 1 auto;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
  }

  /* 다음 단계 버튼은 하단 고정 CTA 다 (TDS BottomCTA).
     왼쪽 아래에 회색 상자로 떠 있으면 다음 행동이 안 읽힌다 */
  main.narrow:has(#nf) > #nf .step-actions {
    position: static;
    margin-top: 20px; padding: 0 0 8px;
    background: none;
  }
  main.narrow:has(#nf) > #nf .step-actions .btn:first-child { flex: 1 1 auto; }
  main.narrow:has(#nf) > #nf:has(.nf-head) {
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-gutter: stable;
    padding: 0 4px calc(20px + var(--safe-bottom));
  }

  /* ── 리포트 판정 헤드 ────────────────────────────────
     세로 1024px 에서 헤드가 435px(42%)을 먹어, 어느 탭을 눌러도 본문이
     접힌 선 아래에서 시작했다. 내용은 그대로 두고 여백만 조인다 */
  .verdict { padding-top: 22px; }
  .verdict-title { font-size: 20px; }
  .verdict-grid { margin-top: 14px; padding-bottom: 18px; }

  /* 단계 표시줄과 저장 안내를 한 줄에 붙여 세로 30px 을 슬라이드에 돌려준다 */
  .flow-toolbar {
    display: flex; align-items: center; gap: 18px;
    margin-bottom: 10px;
  }
  .flow-toolbar .steps { flex: 1 1 auto; min-width: 0; margin-bottom: 0; gap: 8px; }
  .flow-toolbar .flow-save { flex: none; }

  /* ── 3단계 리허설 — 이 화면의 주인공은 슬라이드다 ──────────
     아래에 깔려 있던 필름을 슬라이드 오른쪽으로 옮겨서
     16:9 슬라이드가 남은 높이를 전부 쓰게 한다 */

  main:has(.rehearsal-shell) {
    height: var(--app-h);
    display: flex; flex-direction: column;
    /* 「발표 시작하기」가 든 녹음 패널이 화면 맨 아래(679~782)에 있었다.
       바닥을 가림 높이만큼 올리면 슬라이드도 같이 올라와 다 보인다 */
    padding-bottom: calc(14px + var(--safe-bottom));
  }
  /* 세로 예산이 빠듯해도 8px 는 제목이 무대에 붙어 보였다 — 16px 가 하한 */
  .rehearsal-head { align-items: center; margin: 0 0 16px; }
  .rehearsal-head .mode-label { font-size: 11px; }
  .rehearsal-head h1 { margin-top: 0; font-size: 18px; line-height: 1.3; }
  main:has(.rehearsal-control.is-live) .rehearsal-head { display: none; }

  /* 10px 은 무대·캡션·컨트롤 셋이 한 덩어리로 뭉쳐 보였다. 셋은 하는 일이
     다르니 사이가 보여야 한다 — 아래 바가 특히 캡션에 붙어 있었다 */
  .rehearsal-shell { flex: 1 1 auto; min-height: 0; gap: 16px; padding-bottom: 0; }
  /* 셸이 이미 gap 을 주므로 카드끼리 붙는 기본 여백은 뺀다 */
  .rehearsal-shell > .card + .card { margin-top: 0; }
  .privacy-note { margin-top: 12px; }
  /* 캡션 줄(이전·다음·제목·N/M)이 슬라이드와 필름 사이에 끼여 눌려 있었다 */
  .presentation-viewer .viewer-caption { padding-top: 12px; padding-bottom: 12px; }
  .rehearsal-control, .rehearsal-control.is-live { padding: 16px 20px; }

  /* 녹음이 시작돼도 컨트롤을 같은 자리에 둔다.
     화면 하단으로 띄우면 그만큼 슬라이드가 작아진다 */
  /* position 은 relative 를 유지한다 — .rec-log-fold 의 받아쓰기 팝오버가
     이 카드를 기준으로 붙고, z-index:5 로 필름(z-index:3) 위에 서기 때문이다.
     is-live 가 걸어 두는 fixed 좌표만 되돌린다 */
  .rehearsal-control,
  .rehearsal-control.is-live {
    position: relative; left: auto; bottom: auto; transform: none;
    width: 100%; max-width: none;
    padding: 12px 18px; gap: 14px;
    /* 슬라이드 아래 (MVP_SPEC §5.2). app.css 와 같은 값을 유지한다 */
    order: 1;
    /* flex:none 이 빠지면 안 된다. 셸이 flex 컬럼이고 뷰어가 1 1 auto 라
       컨트롤은 기본 flex-shrink:1 로 눌린다 — 91px 짜리 내용이 49px 상자에
       갇혀 「발표 시작하기」가 슬라이드 캔버스 뒤로 깔렸다 (1180×820 실측) */
    flex: none;
    min-height: 0;
  }
  .rehearsal-shell:has(.rehearsal-control.is-live) { padding-bottom: 0; }
  .rehearsal-control .rec-clock { font-size: 20px; }
  /* 안내 문구가 두 줄로 접히면 컨트롤이 그만큼 두꺼워진다 */
  .rec-upload { max-width: 340px; }
  .rec-upload .note { font-size: 11px; }
  /* 30px 이던 유일한 손가락 미달 버튼 */
  .rec-upload .btn-text { height: 44px; }

  .presentation-viewer {
    flex: 1 1 auto; min-height: 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr) clamp(112px, calc(var(--vw) * 0.11), 148px);
    grid-template-rows: minmax(0, 1fr) auto;
    grid-template-areas:
      "stage film"
      "caption film";
    gap: 0 12px;
    /* 카드 테두리를 남기면 오른쪽 슬라이드 목록까지 한 상자로 묶여
       목록이 슬라이드 안에 든 것처럼 보인다. 여기서 카드 껍데기를 벗긴다 */
    padding: 0; overflow: hidden; background: none; box-shadow: none; border: 0;
  }
  /* ── 슬라이드 위의 ‹ › 를 자막 줄로 내린다 ────────────────────
     화살표는 .viewer-stage(16:9 로 못 박은 상자) 모서리에 absolute 로 붙어
     있었다. 그런데 안에 들어오는 자료는 16:9 가 아니다 — 4:3 PDF 면
     .slide-pdf-canvas 가 max-height:100% 로 좁게 렌더돼 화살표가 슬라이드에서
     한참 떨어진 빈 여백에 뜨고, 꽉 차는 자료면 반대로 내용 위를 덮는다.
     같은 좌표인데 자료마다 다른 곳에 보이는 게 거슬림의 정체였다.

     자막 줄로 내리면 위치가 자료 비율과 무관해진다. 오버레이를 걷어내므로
     컨트롤이 세 벌이 되지도 않는다 — 자막 줄과 오른쪽 목록 둘이다.
     (세로형은 그대로 둔다. 거기선 이미 자막 줄에 이전/다음이 있다) */
  .presentation-viewer .viewer-stage .stage-nav { display: none; }
  /* 자리(grid-area)와 여백은 아래 338줄 규칙이 정한다 — 같은 특이도라
     뒤가 이긴다. 여기서는 줄 안의 배치만 잡는다 */
  .presentation-viewer .viewer-caption {
    display: flex; align-items: center; gap: 12px; flex-wrap: nowrap;
  }
  .presentation-viewer .viewer-caption .caption-nav { display: flex; flex: none; gap: 8px; }
  /* 발표 중에 누르는 버튼이다. 손가락 기준으로 세운다 */
  .presentation-viewer .viewer-caption .caption-nav .btn { min-width: 56px; height: 44px; }
  /* 제목이 길어도 슬라이드 번호를 밀어내지 않는다 */
  .presentation-viewer .viewer-caption #slideTitle {
    flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .presentation-viewer .viewer-caption #slideNo { flex: none; }
  .presentation-viewer .viewer-stage {
    grid-area: stage;
    /* 행 높이가 확정된 그리드 안이라 높이에서 폭을 되짚을 수 있다 */
    height: 100%; width: auto; max-width: 100%;
    aspect-ratio: 16 / 9;
    justify-self: center;
    border-radius: var(--r-print);
  }
  .presentation-viewer .viewer-caption {
    grid-area: caption;
    padding: 8px 4px 0; border-top: 0;
  }
  .presentation-viewer .slide-film {
    grid-area: film;
    display: flex; flex-direction: column; gap: 8px;
    min-height: 0; overflow-y: auto; overflow-x: hidden;
    padding: 2px; margin: 0;
  }
  .presentation-viewer .slide-film > button { flex: none; width: 100%; }

  /* PDF 를 올린 경우 캔버스가 스테이지보다 커지면 안쪽에서 스크롤이 생긴다 */
  .viewer-stage.has-pdf .slide-pdf-canvas { max-height: 100%; width: auto; }

  /* iPad landscape: keep the slide dominant and move presentation controls into a calm right rail. */
  .rehearsal-shell {
    display: grid;
    grid-template-columns: minmax(0, 1fr) clamp(178px, 18vw, 218px);
    grid-template-rows: minmax(0, 1fr);
    align-items: stretch;
  }
  .rehearsal-side {
    grid-column: 2;
    grid-row: 1;
    min-width: 0;
    min-height: 0;
  }
  .rehearsal-control,
  .rehearsal-control.is-live {
    order: 0;
    position: relative;
    display: flex;
    flex: 0 0 auto;
    flex-direction: column;
    align-items: stretch;
    width: 100%;
    padding: 18px;
    border-color: rgba(28, 78, 52, .10);
    background: linear-gradient(145deg, #fff 0%, #f4faf7 100%);
    box-shadow: 0 10px 28px rgba(25, 56, 40, .09);
  }
  .rehearsal-control > .btn { width: 100%; margin-left: 0; }
  .rehearsal-control .rec-upload { width: 100%; max-width: none; align-items: stretch; text-align: left; }
  .rehearsal-control .rec-status,
  .rehearsal-control .rec-status > div { align-items: flex-start; flex-direction: column; gap: 8px; }
  .rehearsal-control .meter { margin: 4px 0 0; height: 26px; }
  .rehearsal-control .rec-log-fold { width: 100%; min-width: 0; flex: none; }
  /* 오른쪽 레일 안에서 제자리로 펼친다 — 팝오버로 띄우면 종료 버튼을 덮는다 (app.css 같은 줄) */
  .rehearsal-control .rec-log-fold .trans-log { position: static; width: 100%; }
  .rehearsal-nav {
    margin-top: auto;
    flex-direction: column;
    padding: 14px;
    border-color: rgba(28, 78, 52, .10);
    background: linear-gradient(150deg, #fff 0%, #f7faf8 100%);
    box-shadow: 0 8px 22px rgba(25, 56, 40, .07);
  }
  .rehearsal-side > .sf {
    flex: none;
    margin: 0;
    padding-top: 8px;
    min-height: 58px;
  }
  .rehearsal-side > .sf .sf-row { gap: 3px; }
  .rehearsal-side > .sf .sf-row .ch-chick { width: 34px; }
  .rehearsal-nav .btn { flex: none; width: 100%; min-height: 48px; }
  .rehearsal-slide-meta { min-height: 58px; order: -1; }
  .presentation-viewer {
    grid-column: 1;
    grid-row: 1;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) auto 84px;
    grid-template-areas: "stage" "caption" "film";
    gap: 8px 0;
  }
  .presentation-viewer .viewer-stage {
    height: 100%;
    width: auto;
    max-width: 100%;
    justify-self: center;
  }
  .presentation-viewer .viewer-caption { padding: 4px 2px 0; }
  .presentation-viewer .slide-film {
    flex-direction: row;
    gap: 9px;
    overflow-x: auto;
    overflow-y: hidden;
    padding: 4px 3px 8px;
    scrollbar-gutter: stable;
  }
  .presentation-viewer .slide-film > button { width: 132px; height: 72px; flex: 0 0 132px; }


  /* ══ 4. 질문 코칭 ═══════════════════════════════════════════ */

  /* 시작 전 설정 카드도 남은 높이의 가운데에 둔다 */
  main.narrow:has(.qa-quick) { display: flex; flex-direction: column; }
  /* 정중앙에 두면 위에 400px 이 통째로 비고 툴바와 카드가 끊긴다.
     #nf 와 같게 위에서 한 뼘만 띄우고 남는 세로는 아래로 보낸다 */
  main.narrow:has(.qa-quick) > .qa-quick { margin-block: clamp(8px, calc(var(--vh) * 0.04), 44px) auto; }

  /* 코칭을 마친 화면 — 활자를 조여 877→732px 까지 줄였지만 아직 52px 이 남는다.
     더 조이면 「무엇을 이겼나」가 읽히지 않으므로 여기서 멈추고, 대신 CTA 를
     흐름의 다른 단계(.step-actions)와 같은 하단 고정으로 만든다.
     거치대에 세운 아이패드는 맨 아래가 관람객 머리에 가린다(--safe-bottom) —
     하필 잘리던 52px 이 「상세 리포트 보기」 줄이었다. 내용이 조금 흘러도
     다음 행동은 늘 손에 닿아야 한다 */
  main.narrow:has(.cere) { display: flex; flex-direction: column; }
  main.narrow > .cere { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
  main.narrow > .cere > .cere-actions {
    position: sticky; bottom: var(--safe-bottom); z-index: 5;
    margin-top: auto; padding: 12px 0 4px;
    background: linear-gradient(to top, var(--canvas) 72%, transparent);
  }

  /* 코칭 중 — 왼쪽에 상대와 개념 진행, 오른쪽에 대화.
     대화가 길어져도 개념 진행 상태가 화면에서 사라지지 않는다 */
  main:has(.qa-shell) {
    width: var(--shell);
    height: var(--app-h);
    display: flex; flex-direction: column;
    padding-bottom: 14px;
  }
  .qa-shell {
    flex: 1 1 auto; min-height: 0;
    display: grid;
    grid-template-columns: minmax(300px, 360px) minmax(0, 1fr);
    gap: var(--pane-gap);
  }
  .qa-context {
    min-height: 0; overflow-y: auto;
    display: flex; flex-direction: column; gap: 12px;
  }
  .qa-dialog {
    min-height: 0;
    display: flex; flex-direction: column; gap: 12px;
  }
  .qa-dialog .qa-stream {
    flex: 1 1 auto; min-height: 0; overflow-y: auto;
    padding-right: 4px;
  }
  .qa-dialog .qa-live,
  .qa-dialog .qa-live-input { flex: none; }
  .qa-dialog .msg-bubble { max-width: 88%; }
  .qa-context .persuade-track { margin: 0; }
  .qa-context .pt-items { flex-direction: column; }


  /* ══ 5. 최종 분석 ═══════════════════════════════════════════ */

  /* 판정 헤드가 화면을 거의 다 먹어서 정작 5개 탭이 접힌 아래에 있었다.
     헤드를 줄이고 탭을 상단 바 밑에 붙여 항상 손이 닿게 한다 */
  /* 본문이 안에서 스크롤하게 된 뒤로 판정 헤드는 그만큼 순수 오버헤드다.
     지우는 것 없이 여백과 글자만 조여 25px 을 본문에 돌려준다 */
  main.wide > .verdict { padding: 16px max(var(--gutter), calc(calc(var(--vw) * 0.5) - 556px)) 0; }
  main.wide > .verdict:first-child { margin-top: -18px; }
  .verdict-title { font-size: 21px; margin-top: 6px; }
  .verdict-grid { margin-top: 10px; }
  .verdict-score .vs-body { padding-top: 10px; }
  .verdict-score strong { font-size: 30px; }
  .verdict-score .prev { margin-top: 6px; }
  .verdict-judgement h2 { font-size: 17px; }
  .verdict-dims { margin-top: 12px; }
  /* 채점 항목이 7개다. 기본 flex-basis 로는 6 + 1 로 접혀 마지막 항목만
     전체 폭을 차지한다 — 가로형에서는 한 줄에 나란히 세운다 */
  .verdict-dims .vd { flex: 1 1 0; min-width: 78px; }
  .verdict-dims .vl { margin: 2px 0 5px; font-size: 17px; }
  .verdict-note { padding: 6px 0 10px; font-size: 12px; }

  /* 리포트는 요약 탭 본문만 1264px 이다. 내용을 덜어내지 않고 한 화면에 담으려면
     페이지가 아니라 본문이 안에서 움직여야 한다 — 점수와 7개 탭은 늘 붙어 있고
     스크롤은 카드 묶음 안에서만 생긴다. 홈 목록·코칭 대화와 같은 방식이다.

     ── 왜 세로 한 줄에서 두 단으로 바꿨나 (2026-08-07 실측) ──
     판정 헤드를 위에 통째로 눕히면 세로 예산 764px 중 430px(56%)을 헤드가 먹고,
     탭줄 56px 을 더 빼면 본문에 252px 만 남았다. 그 안에 1253px 이 들어 있었다.
     부스 가림선(하단 20%)까지 얹으면 본문의 보이는 높이는 이렇게 된다:

       1180×820  100px    1366×1024  263px
       1180×760   52px    1024×768     0px   ← 탭을 눌러도 아무것도 안 보인다

     헤드를 깎아도 부스에서는 여전히 100px 대다 — 가림선이 세로로 내려오는 한
     세로로 쌓는 배치 자체가 답이 아니다. 헤드를 왼쪽 기둥으로 세우면 헤드는
     제 높이를 그대로 쓰면서 본문이 예산 전체를 받는다. 홈 화면이 이미 같은
     컴포넌트를 왼쪽 칸에 앉히고 있어(182~198줄) 낯선 모양도 아니다. */
  main.wide:has(#rbody) {
    height: var(--app-h);
    display: grid;
    /* 왼쪽 기둥은 1024 에서 300px, 1366 에서 374px.
       ⚠ % 의 기준은 뷰포트가 아니라 main 의 폭이다. 1366 짜리 아이패드에서
       왼쪽 내비(254px)를 빼면 main 은 1074px 이라 29% 는 311px — 기둥이 늘
       바닥값(300px)에 붙어 있었다. 주석이 말하는 374px 이 한 번도 안 나왔다.
       34% 로 올리면 1074×.34 = 365px 로 의도대로 선다. 좁은 쪽은 clamp 의
       바닥이 그대로 막아 주므로 1024 에서는 달라지지 않는다. */
    /* 34% → 28%. 1366 에서 365px 이던 기둥이 300px 이 된다.
       기둥은 탭을 옮겨도 남는 앵커라 없애지 않되, 본문 폭의 34% 를 요약이
       쓰고 있던 건 과했다. 항목 줄이 두 칸 격자에서 한 줄씩으로 바뀐 뒤로
       좁은 폭을 견딘다 — 2열이던 시절에는 300px 에서 이름이 접혔다.
       바닥값 300px 은 그대로: 그 아래로는 '목적·청중 적합성' 이 접힌다. */
    grid-template-columns: clamp(300px, 28%, 360px) minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas:
      "head tabs"
      "head body";
    column-gap: var(--pane-gap);
    padding-bottom: 12px;
  }
  /* 전면폭 초록 띠를 기둥 안으로 들인다. 좌우 패딩이 50vw 기준이라
     그대로 두면 1366 에서 한 쪽에만 127px 이 붙어 내용이 76px 로 눌린다 */
  main.wide:has(#rbody) > .verdict,
  main.wide:has(#rbody) > .verdict:first-child {
    grid-area: head;
    /* start 였다. 1366×1024 에서 기둥 내용이 678px 인데 칸은 960px 이라 아래쪽
       282px 이 통째로 빈 배경이었다 — 화면이 "만들다 만" 것처럼 보였다.
       면을 칸 높이만큼 채운다. 내용은 위에 붙어 있고 아래는 조용한 여백이 된다.
       내용이 칸보다 길면 max-height:100% + overflow-y 가 그대로 스크롤을 맡는다. */
    align-self: stretch;
    margin: 0;
    padding: 18px 20px 14px;
    border-radius: var(--r-print);
    /* 채점 항목 7개에 각각 설명 한 줄이 붙어 기둥은 970px 을 원한다.
       예산은 764px 다 — 잘라내면 아래 항목이 소리 없이 사라진다(§4).
       기둥 안에서 스크롤하게 두면 스크롤바가 "아래 더 있다"를 말해 준다.
       읽는 순서가 이미 맞다: 점수 → 한 줄 판정 → 제일 낮은 항목 카드
       (app.js dimsHtml 이 마크업에서 먼저 낸다) → 나머지 여섯 개 → 채점 근거.
       부스에서 스크롤 없이 보이는 세 가지가 곧 이 화면의 결론이다 */
    max-height: 100%;
    overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin;
  }
  /* 점수와 판정을 좌우로 놓던 격자는 기둥 안에서 한 줄로 세운다 */
  main.wide:has(#rbody) > .verdict .verdict-grid {
    grid-template-columns: 1fr; gap: 14px; margin-top: 12px; padding-bottom: 0;
  }
  /* 28px 이던 항목 간격은 한 줄에 다섯 개가 서던 전면폭 기준이다.
     기둥에서는 세로로 쌓이므로 그만큼이 그대로 세로 낭비가 된다.
     ⚠ 예전 이 자리에는 `.vd { flex: 1 1 96px }` 과 `.vd-weak { flex: 1 1 100% }`
     이 있었다. .verdict-dims 가 flex-wrap 에서 column 으로 바뀌었으므로 그대로
     두면 flex-basis 100% 가 **높이** 100% 로 읽혀 카드 하나가 기둥을 다 먹는다.
     지금 폭을 정하는 건 .vd-rest 의 grid 다 (design-system.css). */
  main.wide:has(#rbody) > .verdict .verdict-dims {
    gap: 12px; margin-top: 16px; padding-top: 14px;
  }
  /* 제일 낮은 항목 카드는 기둥 한 줄을 통째로 쓴다 — 옆에 세울 자리가 없다 */
  main.wide:has(#rbody) > .verdict .verdict-dims .vd.vd-weak {
    padding: 13px 15px 15px;
  }
  main.wide:has(#rbody) > .verdict .verdict-dims .vd-weak .hint { margin-top: 8px; }
  /* 1024 에서 기둥은 300px 까지 좁아진다. 한때 여기서 한 칸으로 내렸는데,
     그러면 여섯 줄이 세로로 쌓여 기둥이 도로 길어졌다 — 이름이 두 줄로 접혀도
     두 칸(세 줄)이 한 칸(여섯 줄)보다 낮다. 칸 사이만 좁혀서 이름에 자리를 준다 */
  /* 줄 사이는 머리카락 선이 나눈다 — 여백을 주면 선과 여백이 겹쳐 성기게 보인다 */
  main.wide:has(#rbody) > .verdict .vd-rest { gap: 0; }
  /* 기둥이 칸 높이만큼 늘어났으니(align-self:stretch) 남는 높이를 어디에 둘지
     정해야 한다. 결론(점수·판정·항목)은 위에 붙이고 근거는 바닥에 붙인다 —
     빈자리가 둘 사이의 여백이 되어, 남은 공간이 "덜 만든 자리"가 아니라
     "머리말과 꼬리말 사이"로 읽힌다. 내용이 칸보다 길면 auto 는 밀 자리가
     없으므로 아무 일도 안 일어나고 그대로 스크롤한다. */
  main.wide:has(#rbody) > .verdict .verdict-inner {
    display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;
  }
  main.wide:has(#rbody) > .verdict .verdict-basis,
  main.wide:has(#rbody) > .verdict .verdict-basis.is-flat {
    margin-top: auto; padding-top: 14px; padding-bottom: 2px;
  }
  /* 샘플 표시는 스크롤 밖으로도, 접힌 선 아래로도 밀려나면 안 된다 —
     둘 중 하나라도 걸리면 샘플 숫자만 남고 "샘플"이라는 말이 사라진다(§4 정직성).
     마크업상 맨 끝(app.js:3384)이라 바닥에 붙이면 786px 에 앉아 부스 가림선
     아래로 들어간다. 기둥을 세로 flex 로 만들고 order 로 맨 위에 올려 붙인다.
     읽는 순서로도 이게 맞다 — 86점을 보기 전에 샘플이라는 걸 알아야 한다 */
  main.wide:has(#rbody) > .verdict { display: flex; flex-direction: column; }
  main.wide:has(#rbody) > .verdict .verdict-note {
    order: -1; position: sticky; top: -18px; z-index: 3;
    margin: -18px -20px 12px; padding: 12px 20px 10px;
    background: var(--navy);
  }
  main.wide:has(#rbody) > #rbody {
    grid-area: body;
    min-height: 0; overflow-y: auto;
    padding-right: 4px; scrollbar-width: thin;
  }
  /* 본문이 스크롤을 맡으므로 탭은 더 이상 떠 있을 필요가 없다.
     선택자를 #rtabs.tabs 로 맞춰야 design-system.css 의 sticky 규칙을 이긴다 */
  main.wide > #rtabs.tabs {
    grid-area: tabs; align-self: start;
    flex: none; position: static; top: auto; margin: 0 0 14px;
  }

  /* ── 슬라이드로 보는 발표 ────────────────────────────────────────────
     app.css 는 `@media (max-width:720px)` 에서 무대·설명을 위아래로 쌓는다.
     그런데 그 720 은 **뷰포트** 폭이고, 정작 이 묶음이 사는 곳은 오른쪽 칸이다 —
     1366 에서 뷰포트는 1366 이지만 칸은 683px 이라 규칙이 안 걸렸다.
     그래서 1.25fr/1fr 이 무대 369px · 설명 296px 로 갈렸다: 슬라이드는 작고
     설명은 줄마다 접히는, 둘 다 손해인 배치였다.

     이 구간에서는 위아래로 쌓는다. 이 묶음의 이름이 「슬라이드로 보는 발표」인
     만큼 주인공은 슬라이드다 — 칸 폭을 통째로 준다. 설명도 683px 을 쓰니
     「이렇게 말해보세요」가 석 줄에서 한두 줄로 줄고, 아래 순간 목록도 한 줄에 선다.

     1450 은 오른쪽 칸이 760px 을 넘기 시작하는 지점이다(칸 = 뷰포트 − 내비 254
     − 기둥 400 − 여백). 그보다 넓으면 좌우로 두는 편이 낫다. */
  @media (max-width: 1450px) {
    .deck-main { grid-template-columns: 1fr; gap: 14px; }
    /* 폭을 다 주면 4:3 슬라이드가 512px 까지 커서 한 장이 화면을 먹는다.
       그래서 높이를 220px 으로 묶는다.

       ⚠ 예전엔 여기에 object-fit:contain + 회색 배경을 줬다. 자르지 않으려는
       뜻은 맞았지만, 액자를 칸 폭(747px)에 고정해 둔 채 그림만 줄이니 슬라이드
       양옆에 회색 여백이 남았다 — 「발표자료를 딱 보여줘야지」가 안 됐다.

       고칠 곳은 그림이 아니라 액자다. 높이를 정하고 폭은 그림이 정하게 두면,
       액자가 슬라이드에 딱 맞아서 자르지도 남기지도 않는다. */
    .deck-stage {
      width: fit-content; max-width: 100%; margin-inline: auto;
    }
    .deck-stage img, .deck-stage canvas {
      height: 220px; width: auto; max-width: 100%; object-fit: contain;
    }
  }

  /* 리포트 본문은 서로 독립적인 카드 묶음이라 두 단으로 나눌 수 있다.
     다만 오른쪽 칸은 1024 에서 651px 까지 좁아진다 — 거기서도 두 단을 고집하면
     세로 답답함을 가로 답답함으로 바꾸는 것뿐이다. auto-fit 으로 칸이 좁으면
     스스로 한 단이 되게 둔다 (654px 부근에서 갈린다).
     넓은 시각 요소만 전체 폭을 쓴다 */
  #rbody {
    display: grid;
    /* 320px 이던 최소폭. 1366×1024(아이패드 프로 가로)에서 오른쪽 칸은 687px 이라
       320 기준으로는 두 단이 **간신히** 서고, 한 단이 334px 로 눌린다. 거기서
       두 단은 이득이 아니다: 줄 높이는 둘 중 큰 카드가 정하는데, 질문 코칭
       내역(599px) 옆에 개념 판정 묶음(79px)이 서면 왼쪽 칸에 566px 짜리 구멍이
       뚫리고 그 아래에 CTA 가 앉는다 — 스크롤로 빈 화면을 지나가게 된다.
       380 으로 올리면 687px 에서는 스스로 한 단이 되어 읽는 순서(슬라이드 →
       개념 판정 → 질문 코칭 → CTA)가 그대로 세로로 선다. 더 넓은 화면에서는
       여전히 두 단이다. */
    grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
    gap: 14px;
    align-items: start;
    /* ⚠ 이 한 줄이 없으면 카드 사이에 빈 띠가 생긴다.
       #rbody 는 높이가 고정된 스크롤러(grid-area:body, minmax(0,1fr))다. 격자의
       align-content 기본값은 stretch 라, 내용이 칸보다 짧으면 남는 높이를 **줄들이
       나눠 갖는다**. 거기에 align-items:start 가 카드를 줄 위쪽에 붙이니, 카드
       아래마다 남은 높이만큼 빈자리가 남았다 — 1366×1024 에서 슬라이드 묶음과
       아래 카드 사이가 14px 이 아니라 139px 이었다. 줄은 내용만큼만 차지하고,
       남는 높이는 맨 아래에 한 번에 둔다. */
    align-content: start;
  }
  #rbody > * { margin-top: 0 !important; }
  #rbody > h2,
  #rbody > .section-title,
  #rbody > .rep-deck,
  #rbody > .judge-grid,
  #rbody > .stat-row,
  #rbody > .trophy-strip,
  /* 음성 습관·연습 도구는 스스로 세로 한 줄이다 — 두 단으로 쪼개면 순서가 흐트러진다 */
  #rbody > .voice-stack,
  #rbody > .tool-sec,
  /* 질문 코칭 내역은 7줄짜리 긴 목록이다. 좁은 한 단에 넣으면 옆 카드와 높이가
     크게 어긋나 반대쪽 칸에 구멍이 남는다 — 두 단이 서는 넓은 화면에서도
     이건 통째로 한 줄을 쓴다 */
  #rbody > .qa-log,
  #rbody > .ai-note { grid-column: 1 / -1; }
  /* 카드가 하나뿐인 탭(청중 반응 등)은 한 단에만 앉으면 오른쪽이 통째로 빈다 */
  #rbody > *:only-child { grid-column: 1 / -1; }

  /* 오른쪽 칸이 1024 에서 651px 이라 두 단으로 쪼개면 개념 이름이 줄마다 접힌다.
     칸이 넓을 때만 좌우로 나누고, 좁으면 목록 위 · 상세 아래로 쌓는다 */
  .judge-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); align-items: start; }
  /* -140 은 헤드가 위에 486px 을 깔고 있던 시절의 보정이다. 이제 #rbody 자신이
     예산 전체를 쓰는 스크롤러라, 비슷한 높이의 스크롤러를 안에 또 두면
     바깥쪽이 안 움직이는 것처럼 보인다 — 흐름에 맡기고 바깥에서만 스크롤한다 */
  #jdetail { max-height: none; overflow-y: visible; }
}

/* 리포트 오른쪽 칸이 700px 아래로 내려가는 구간(≈1075px 폭 이하, 1024×768 포함).
   개념 목록과 상세를 좌우로 쪼개면 개념 이름이 줄마다 접힌다 — 위아래로 쌓는다 */
@media (min-width: 900px) and (max-width: 1100px) {
  .judge-grid { grid-template-columns: minmax(0, 1fr); }
}

@media (min-width: 900px) {


  /* ══ 6. 판단 방식(#/about) ══════════════════════════════════ */

  /* 카드 셋 중 파이프라인 표 하나만 길다. 셋을 세로로 쌓으면 표 뒤의 두 카드가
     화면 밖으로 나간다 — 표를 왼쪽 한 칸에 세우고 짧은 둘을 오른쪽에 쌓는다.
     카드가 정확히 셋이라(app.js 4494·4512·4521) 자리를 이름 대신 좌표로 박는다 */
  main:has(.about-sec) {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
    /* 행: 제목 · 리드 · 본문 두 칸 · CTA.
       높이를 화면에 못 박지 않는다. 내용이 예산보다 283px 많아서 칸마다
       안쪽 스크롤바가 생겼는데, 읽는 화면에 스크롤 영역을 둘씩 가두는 건
       페이지가 한 번 흐르는 것보다 나쁘다 (읽다가 어디를 굴려야 할지 모른다).
       여기는 조작 화면이 아니라 문서라서 세로 예산 규칙에서 뺀다. */
    grid-template-rows: auto auto auto auto;
    gap: 14px;
    min-height: var(--app-h);
    padding-bottom: 12px;
  }
  main:has(.about-sec) > .page-title { grid-area: 1 / 1 / 2 / 3; }
  main:has(.about-sec) > .about-lead { grid-area: 2 / 1 / 3 / 3; }
  main:has(.about-sec) > .about-cta { grid-area: 4 / 1 / 5 / 3; margin-bottom: 0; padding: 14px 20px; }
  /* 두 칸 다 제 높이로 선다. 안쪽 스크롤은 두지 않는다 (위 주석 참고) */
  main:has(.about-sec) > .about-sec:nth-of-type(1) { grid-area: 3 / 1 / 4 / 2; align-self: start; }
  main:has(.about-sec) > .about-side {
    grid-area: 3 / 2 / 4 / 3; align-self: start;
    display: flex; flex-direction: column; gap: 14px;
  }
  main:has(.about-sec) > .about-side > .about-sec { margin-bottom: 0; flex: none; }
  main:has(.about-sec) > * { margin-top: 0 !important; }
  /* 8행짜리 목록의 행 여백이 그대로면 카드가 세로 예산을 혼자 다 쓴다 */
  main:has(.about-sec) .card { padding: 16px 18px; }
  main:has(.about-sec) .about-steps li { padding: 8px 0; }
  main:has(.about-sec) .principles li { padding: 7px 0; }
  main:has(.about-sec) .about-lead { margin: -8px 0 0; font-size: 14px; }
  main:has(.about-sec) .about-sec p.lead { margin-bottom: 10px; }
  main:has(.about-sec) .section-title { margin-bottom: 8px; }


  /* ══ 6-2. 랜딩 — 세로로 8화면이던 것을 옆으로 넘기는 덱으로 ══
     구역 여섯이 각각 1.0~1.8화면이라 여백만 조여서 될 규모가 아니었다.
     한 구역 = 한 화면으로 두고 가로로 민다. 페이지 세로 스크롤은 0 이 되고,
     아직 긴 구역만 그 구역 안에서 스크롤한다.
     .land-progress 는 원래 position:fixed 라 트랙 밖에 그대로 떠 있는다 */

  /* v1 랜딩(가로 스냅 덱) 전용이던 높이 잠금은 걷어냈다. v2 는 그냥 스크롤되는
     문서라 화면 높이에 가두면 내용이 잘린다 — 실측 #app scrollHeight 2772px 을
     844px 로 잘라 먹고 있었다 (2026-08-07). 아래 .landing-main 규칙들은 v2 에
     그 요소가 없어 죽은 코드지만, v1 로 되돌릴 여지를 남겨 두고 손대지 않는다. */
  main.landing { width: 100%; padding: 0; }

  .landing-main {
    height: 100%;
    display: flex;
    overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .landing-main::-webkit-scrollbar { display: none; }

  .landing-main > #hero,
  .landing-main > #exampleSec,
  .landing-main > #alignTrack,
  .landing-main > #judgeSec,
  .landing-main > #demoSec,
  .landing-main > #start {
    flex: 0 0 100%;
    width: 100%;
    height: 100%;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior-y: contain;
    scroll-snap-align: start;
    scrollbar-width: thin;
  }
  /* 히어로는 min-height 로 760px 을 잡고 있어서 덱 칸을 넘긴다 */
  .landing-main > #hero,
  .landing-main > #hero .hero-inner { min-height: 0; }
  .landing-main > section,
  .landing-main > #alignTrack { margin: 0; }

  /* 세로로 이어붙일 때 쓰던 100~150px 구역 여백은 덱에선 낭비다.
     히어로는 자체 여백 체계를 쓰므로 따로 둔다 */
  .landing-main > #exampleSec,
  .landing-main > #judgeSec,
  .landing-main > #demoSec,
  .landing-main > #start {
    padding-top: clamp(14px, calc(var(--vh) * 0.026), 32px);
    padding-bottom: clamp(14px, calc(var(--vh) * 0.026), 32px);
  }
  .landing-main .hero-inner { padding: clamp(16px, calc(var(--vh) * 0.03), 40px) 0; }
  .landing-main .align-stage { padding-block: clamp(10px, calc(var(--vh) * 0.02), 24px); }
  .landing-main .section-heading { margin-bottom: 6px; }
  .landing-main .align-cap { margin-bottom: 8px; }
  .landing-main .compare-stage { gap: 10px; }
  /* 750px 짜리 장식 글로우가 흐름 안에 있어서 시작 구역만 혼자 1461px 이었다 */
  .landing-main .start-glow { position: absolute; }

  /* 제품 목업 둘은 여백을 다 걷어도 칸을 넘는다. 잘라내는 대신 통째로 줄인다.
     transform: scale 은 레이아웃 크기를 그대로 둬서 목업이 stretch 로 눌린 뒤
     축소돼 내용의 절반이 잘렸다(1180×820 실측). zoom 은 레이아웃까지 줄인다 */
  .landing-main > #judgeSec .product-showcase-shell {
    margin-top: 0; min-height: 0; width: auto;
  }
  .landing-main > #judgeSec .app-frame { zoom: .66; }
  .landing-main > #demoSec .demo-panel { zoom: .72; }


  /* ══ 7. 척척극장 객석 ══════════════════════════════════════
     좌석이 178px 로 고정돼 있어 말풍선도 178px 였다.
     대사가 다섯 줄로 접히는 동안 1180px 중 400px 이 양옆에서 놀았다 */

  .ch-row .ch-seat { width: clamp(180px, calc(var(--vw) * 0.23), 264px); }
  .ch-row .ch-empty { width: clamp(150px, calc(var(--vw) * 0.2), 230px); }
  /* 좌석 폭 안에 머물러야 옆자리 말풍선과 겹치지 않는다 */
  .ch-bubble { max-width: 100%; padding: 12px 15px 13px; }
  .ch-bubbles { gap: 10px; }


  /* ══ 8. 터치 ════════════════════════════════════════════════ */

  /* 슬라이드 넘김 버튼은 손가락 기준으로 키운다 */
  .stage-nav { width: 52px; height: 88px; }
  .sess-row, .pt, .qa-modes > * { min-height: 44px; }
  select, .aud-select select { min-height: 44px; }
}

/* 세로가 특히 짧은 기기(1024 × 768 등)에서 한 번 더 줄인다 */
/* 홈 왼쪽 칸(성장 기록 · 포스터 벽 · 연속 연습)의 자연 높이는 820px 언저리다.
   그보다 세로가 짧은 기기에서는 카드 사이 여백만 깎는다 — 내용은 그대로 두고
   공기만 뺀다. 810px 같은 어중간한 높이가 이 구간에 들어온다 */
@media (min-width: 900px) and (max-height: 860px) {
  /* 14px 였다. 그건 「내 발표」 h1 행이 46px 를 먹던 시절의 보상이다 —
     그 행을 걷어낸 뒤로는 아이패드 가로(820)에서 조일 이유가 없다.
     상단 바 바로 밑에 소제목이 붙으면 답답하다. 더 짧은 화면은 아래 규칙들이 계속 조인다 */
  main.home { padding-top: 28px; }
  main.home > .page-head { margin-bottom: 10px; }
  main.home > .pb-wall,
  main.home > .game-card { margin-top: 8px; }
  main.home > .about-link { padding-top: 4px; }
}

/* 여백만으로 부족한 구간(1080 × 810 · 1024 × 768 등)에서는 숫자와 그래프도 줄인다.
   경계는 815px — 820px(아이패드 11" 가로)은 줄이지 않아도 들어간다 */
@media (min-width: 900px) and (max-height: 815px) {
  main.home > .verdict { padding: 14px 18px 12px; }
  main.home > .verdict .growth-svg { height: 88px; }
  main.home > .verdict .verdict-score strong { font-size: 26px; }
  main.home > .pb-wall,
  main.home > .game-card { padding: 10px 14px; }
  main.wide > .verdict { padding-top: 18px; }
  .verdict-score strong { font-size: 30px; }
  .verdict-title { font-size: 20px; }
  .rehearsal-head { margin-bottom: 6px; }
  .rehearsal-head h1 { font-size: 17px; }
  .rehearsal-control, .rehearsal-control.is-live { padding: 9px 16px; }
}

/* 세로 760px 아래(창을 줄인 브라우저 등)에서는 성장 그래프까지 낮춘다.
   숫자와 항목은 그대로 남는다 — 줄이는 건 그래프 높이뿐이다 */
@media (min-width: 900px) and (max-height: 760px) {
  main.home > .verdict .growth-svg { height: 70px; }
  main.home > .verdict { padding: 12px 16px 10px; }
}

/* 랜딩 덱: 세로가 줄면 시연 무대와 제품 목업을 단계로 더 줄인다.
   내용은 그대로 있고 크기만 작아진다 */
/* 경계가 825px 인 이유: 1180×820 에서 대조 카드가 딱 4px 넘친다.
   기준 해상도가 이 구간 안에 있어야 해서 815 가 아니라 825 다 */
@media (min-width: 900px) and (max-height: 825px) {
  .landing-main .compare-stage,
  .landing-main .align-stage { zoom: .94; }
  .landing-main > #demoSec .demo-panel { zoom: .68; }
}
@media (min-width: 900px) and (max-height: 780px) {
  .landing-main .compare-stage,
  .landing-main .align-stage { zoom: .88; }
  .landing-main > #judgeSec .app-frame { zoom: .62; }
  .landing-main > #demoSec .demo-panel { zoom: .63; }
}
@media (min-width: 900px) and (max-height: 740px) {
  .landing-main .compare-stage,
  .landing-main .align-stage { zoom: .81; }
  .landing-main > #judgeSec .app-frame { zoom: .57; }
  .landing-main > #demoSec .demo-panel { zoom: .57; }
}

/* 세로 740px 아래. 여기서도 지우는 건 없다 —
   제목 글자와 남은 여백을 마지막으로 조인다 */
@media (min-width: 900px) and (max-height: 740px) {
  main.home { padding-top: 10px; padding-bottom: 4px; }
  main.home > .page-head { margin-bottom: 8px; }
  main.home > .page-head .page-title { font-size: 19px; }
  main.home > .page-head .page-sub { font-size: 13px; line-height: 1.5; }
  main.home > .verdict .verdict-score strong { font-size: 28px; }
  main.home > .verdict .hg-foot { margin-top: 4px; padding-top: 6px; }
  main.home > .pb-wall,
  main.home > .game-card { padding: 8px 12px; margin-top: 6px; }
  main.home > .about-link { padding-top: 2px; }
}

@media (prefers-reduced-motion: reduce) {
  .home-list, .qa-dialog .qa-stream, .slide-film { scroll-behavior: auto; }
}

/* 실전 질문 코칭 결과 — 가로형에서 한 화면에 담는다.
   여섯 행 + 세 묶음이면 세로 예산을 넘겨서, 내용은 두고 여백만 조인다 */
@media (min-width: 900px) {
  main.narrow:has(.qres) { display: flex; flex-direction: column; }
  .qres { margin-block: auto; }
  .qres-head { font-size: 20px; line-height: 1.4; }
  .qres-head b { font-size: 26px; }
  .qres-sub { margin-top: 6px; font-size: 13px; }
  .qres-group { margin-top: 12px; }
  .qres-gh { padding-bottom: 6px; }
  .qres-row { padding: 8px 4px; min-height: 44px; }
  .qres-main small { margin-top: 1px; }
  .cere-actions { margin-top: 12px; }
}

/* 랜딩의 진행 점·구역 버튼은 보이는 크기가 7~13px 이라 손가락으로 못 누른다.
   점은 그대로 두고 히트 영역만 44px 로 키운다 (보이는 모양은 안 바뀐다).
   축소된 제품 목업(.app-frame·.demo-panel) 안의 요소는 장식이라 건드리지 않는다 */
@media (min-width: 900px) {
  .land-progress button { padding: 0; min-width: 44px; min-height: 44px; }
  .landing-main > section button:not(.app-frame button):not(.demo-panel button),
  .landing-main .av.go { min-height: 44px; }
}

/* 포스터 벽이 재디자인되며 114 → 204px 로 커져 홈이 55px 넘쳤다 (2026-08-06 실측).
   포스터는 척척극장의 얼굴이라 내용을 덜어내지 않고, 둘레 여백과 그래프만 조인다 */
@media (min-width: 900px) {
  main.home > .verdict { padding: 14px 18px 12px; }
  main.home > .verdict .growth-svg { height: 92px; }
  main.home > .verdict .verdict-score strong { font-size: 26px; }
  main.home > .pb-wall { padding: 10px 14px; margin-top: 6px; }
  main.home > .game-card { padding: 10px 14px; margin-top: 6px; }
}
/* 세로가 짧을수록 포스터 벽과 그래프를 더 조인다 (내용은 그대로) */
@media (min-width: 900px) and (max-height: 825px) {
  main.home > .verdict .growth-svg { height: 76px; }
  main.home > .pb-wall { padding: 8px 12px; }
  main.home > .page-head { margin-bottom: 8px; }
}
@media (min-width: 900px) and (max-height: 790px) {
  main.home > .verdict { padding: 12px 16px 10px; }
  main.home > .verdict .growth-svg { height: 62px; }
  main.home > .verdict .verdict-score strong { font-size: 30px; }
  main.home > .game-card { padding: 8px 12px; }
}
/* 1024 폭은 왼쪽 칸이 좁아 포스터 문구가 더 접힌다. 한 단 더 */
@media (min-width: 900px) and (max-height: 775px) {
  main.home { padding-top: 12px; }
  main.home > .page-head { margin-bottom: 6px; }
  main.home > .verdict .growth-svg { height: 54px; }
  main.home > .verdict .hg-foot { margin-top: 4px; padding-top: 6px; }
  main.home > .pb-wall, main.home > .game-card { padding: 7px 12px; margin-top: 5px; }
  main.home > .about-link { padding-top: 2px; }
}
@media (min-width: 900px) and (max-height: 740px) {
  main.home > .pb-wall .pb-openline { font-size: 12px; line-height: 1.45; }
  main.home > .verdict .growth-svg { height: 46px; }
}

/* ══ P0 데스크톱 작업면 정리 (2026-08-10) ═════════════════════════════
   1366px 화면에서 홈은 880px 한 기둥만 써서 오른쪽 340px가 비었고, 업로드는
   남은 높이를 전부 점선 상자로 채워 행동보다 빈 공간이 먼저 보였다. 데이터와
   이벤트는 그대로 두고, 넓은 화면에서만 정보의 자리를 다시 배분한다. */
@media (min-width: 1200px) {
  main.home {
    display: grid;
    width: min(1320px, 100% - var(--gutter) * 2);
    grid-template-columns: minmax(320px, .82fr) minmax(0, 1.45fr);
    column-gap: clamp(42px, 4.5vw, 68px);
    align-content: start; align-items: start;
  }
  main.home > .h-head,
  main.home > .h-resume { grid-column: 1 / -1; }
  main.home > .h-head { flex-wrap: wrap; margin-bottom: 26px; }
  main.home > .h-head h1 { font-size: 30px; }
  main.home > .h-lead { max-width: 54ch; font-size: 15px; }

  /* 시작 안내는 또 하나의 카드가 아니라 왼쪽 작업 지시문이다. */
  main.home > .h-start,
  main.home > .h-next {
    grid-column: 1; min-height: 280px; margin: 0;
    padding: 24px 0 28px;
    border: 0; border-top: 2px solid var(--brand); border-radius: 0;
    background: transparent;
  }
  main.home > .h-start b,
  main.home > .h-next .h-next-head { font-size: 22px; line-height: 1.45; }
  main.home > .h-start p,
  main.home > .h-next .h-next-act { max-width: 34ch; font-size: 15px; }
  main.home > .h-start .h-start-act { align-items: flex-start; flex-direction: column; gap: 10px; margin-top: 24px; }

  main.home > .h-sec { grid-column: 2; margin: 0 0 28px; }
  main.home > .h-sec-head { padding-bottom: 11px; }
  main.home > .h-sec-head h2 { color: var(--text-2); font-size: 13px; }
  main.home > .h-sec-note { margin-top: 10px; font-size: 13px; }
  main.home > .h-sec .h-table th { padding-top: 14px; }
  main.home > .h-sec .h-table td { padding-top: 13px; padding-bottom: 13px; }
}

@media (min-width: 900px) {
  /* 첫 단계만 쓰는 규칙이다. 파싱·완료·리허설 상태의 높이 계약은 건드리지 않는다. */
  main.narrow:has(#nf) > #nf > .dropzone {
    flex: 0 1 auto;
    min-height: clamp(520px, 62vh, 640px);
    max-height: calc(var(--app-h) - 150px);
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(230px, .72fr);
    align-items: center; justify-content: stretch; column-gap: clamp(36px, 5vw, 72px);
    padding: clamp(42px, 5vw, 68px); text-align: left;
    border-color: #D4D4D8; background: var(--surface);
  }
  main.narrow:has(#nf) > #nf > .dropzone.hover {
    border-color: var(--brand); background: var(--brand-weak);
  }
  main.narrow:has(#nf) > #nf > .dropzone .dz-actions {
    align-items: flex-start; justify-content: center;
    min-height: 180px; margin: 0; padding-left: clamp(28px, 4vw, 52px);
    border-left: 1px solid var(--border);
  }
  main.narrow:has(#nf) > #nf > .dropzone .dz-actions .btn { min-width: 196px; }
  main.narrow:has(#nf) > #nf > .dropzone .dz-or { max-width: 24ch; }

  /* 오른쪽 분석 본문의 주인공은 실제 슬라이드다. 220px 고정 높이를 풀어
     1366×768에서도 약 260px, 1440×900에서는 약 300px까지 쓴다. */
  .rep-deck > .section-title {
    display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
    font-size: 18px;
  }
  .rep-deck > .section-title .soft { flex: none; font-size: 12px; }
}

@media (min-width: 900px) and (max-width: 1450px) {
  .deck-stage img, .deck-stage canvas {
    height: clamp(260px, 34vh, 320px); width: auto; max-width: 100%; object-fit: contain;
  }
}

@media (min-width: 721px) {
  .sidenav-list a[aria-current="page"] {
    background: color-mix(in srgb, var(--brand-weak) 55%, white);
  }
}
