@charset "UTF-8";
/* ============================================================================
   es.css — 초등 3~4학년군 웹 교과서 디자인 시스템  (2판 · 2026-09-08 전면 개정)
   ----------------------------------------------------------------------------
   차시에서 부르는 법 (차시는 과목/권/대단원/차시/index.html 이므로 3단 위):

     <link rel="stylesheet" href="../../../_assets/es.css">
     <script src="../../../_assets/es.js" defer></script>

   이 파일을 차시 HTML 안으로 복사하지 않는다. 고치면 14개 차시가 한꺼번에 바뀐다.
   차시 고유 스타일이 필요하면 <style> 로 조금 덧붙이되 여기 있는 클래스를
   재정의하지 않는다.

   ── 1판이 왜 퇴짜를 맞았나 (SPEC_초등차시.md 4절 · _redesign/level.md) ──
   1판은 중학교 스타일시트에서 **빼기만** 했다. 폭을 680px 로 줄이고, 스크롤 연출을
   금지하고, 애니메이션을 오답 피드백 하나로 줄이고, 채도를 낮췄다. 넷 다 국가 문서에도
   접근성 지침에도 근거가 없었다. 실측 결과 1366×768 에서 화면 폭의 50%가 비었고,
   디자인 시스템 전체의 @keyframes 가 1개(es-shake)였으며 **오답일 때만** 재생됐다.
   3학년이 이 교과서에서 보는 유일한 움직임이 '틀렸다'는 신호였다.

   ── 2판이 서 있는 자리 ──
     · 글줄 폭과 화면 폭은 **다른 변수**다. --es-measure(560px)는 <p>·<li> 에만,
       --es-content(1100px)는 캔버스에, 섹션 배경 띠는 **화면 끝까지**.
     · 7:1 은 '본문 글자 ↔ 그 글자의 배경' 쌍만 묶는다. 색면·비텍스트·사진·큰 글자는
       자유다. 그래서 **채도를 낮추지 않는다.** 색을 고르지 말고 색 '쌍'을 고른다.
     · 그라디언트 위에 글씨를 얹지 않는다(대비를 한 점에서 검증할 수 없다).
       단색 위 흰 글씨는 검증된다 — 이 파일의 --es-deep 은 전부 흰 글자와 9:1 이상이다.
     · 등장 연출은 animation-timeline: view() 로 한다. **JS 0줄 · IntersectionObserver 0개.**
       시작 opacity 는 0 이 아니라 .4 — 연출이 어긋나도 글이 남는다.
     · 잘한 쪽이 더 크게 움직인다. 도장·튀어오름·반짝임·카운트업·그려지는 선.
     · 자동으로 시작해 스스로 멈추지 않는 것은 없다(WCAG 2.2.2). 맥동은 3회 = 4.8초.
     · prefers-reduced-motion 에서 전부 꺼진다. **이제 그 블록이 끌 대상이 실제로 있다.**

   ── 그대로 지킨 것 (근거가 있다) ──
     · 본문 20px 이상, 캡션 14px 이상, 12px 이하 0개.
     · 전부 고딕(Pretendard). 명조 금지.
     · 활동 버튼 56×56px 이상, 버튼 사이 12px 이상 (WCAG 2.5.5 상회).
     · 색만으로 정보를 구분하지 않는다 — 맞음·틀림은 색 + 모양 + 글자를 함께 쓴다.
     · z-index 는 900 을 넘지 않는다 — 진도 알약(99998)·따라가기 오버레이(100000).
     · 다크모드는 만들지 않는다(교실 기기는 전부 밝은 화면).
     · 인쇄하면 .es-sheet 가 A4 한 장이 된다.

   ── 3판이 더한 것 (2026-09-09) ──
     · **출처를 작게.** .es-src 만 12px·흐린 회색으로 내렸다(--es-fs-credit·--es-src-ink).
       캡션(.es-cap 18px)은 그대로 크다 — 아이가 읽을 말은 캡션이다. 24절 위 주석 참고.
     · **그림이 슉 날아와 앉는다.** .es-fly-l / .es-fly-r / .es-fly-up (24절). JS 0줄.
     · **배경에 흩날리는 것.** .es-drift (25절). 기본은 4.8초 한 번, data-loop 면 멈춤 단추.
     · **시뮬레이터 공용 부품.** .es-sim·.es-stage·.es-slider·.es-steps·.es-dial·
       .es-num·.es-toggles (26절). 14차시가 밑바닥부터 짜지 않게.
     · **쇼츠 무대.** .es-short (27절). 30초 이내·자동 재생 없음.

   ── 클래스 이름은 하나도 바꾸지 않았다 ──
   14개 차시가 이미 쓰는 이름과 변수(--es-brand, --es-accent, --es-sp-3 …)는 전부
   살아 있다. 같은 마크업에 새 옷을 입힌 것이다. 새로 **더한** 것만 아래 「덧붙인 것」에.
   ========================================================================== */

/* 폰트는 여기서 한 번 못 박는다 — 집필자가 <link> 를 빠뜨려도 명조로 떨어지지 않게.
   더 빠르게 하려면 차시 <head> 에 아래 <link> 를 함께 넣는다:
   <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css"> */
@import url("https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css");

/* ── 1. 변수 ─────────────────────────────────────────────────────────────── */
:root{
  /* ---- 중립 · 종이 ---- 괄호 안은 실측 명도비 --------------------------- */
  --es-bg:        #fbf9f3;   /* 종이 */
  --es-surface:   #ffffff;
  --es-soft:      #f4f1e8;   /* 옅은 크림 면 */
  --es-line:      #ded8ca;   /* 장식용 선 */
  --es-line-2:    #8a8272;   /* 뜻이 있는 테두리 (흰 바탕 3.8:1 — 1.4.11 의 3:1 상회) */

  --es-ink:       #14202e;   /* 본문 (흰 바탕 16.5:1 · --es-bg 위 15.6:1) */
  --es-ink-2:     #3d4a5c;   /* 보조 글자·캡션 (9.0:1 · --es-bg 위 8.6:1) */
  --es-ink-abs:   #14202e;   /* **덮어쓰지 않는 잉크.** 짙은 색면 안의 입력 칸이 쓴다 */

  /* ---- 판정색 — 색만으로 구분하지 않으므로 모양·글자와 늘 함께 쓴다 ----- */
  --es-ok:        #0f5c39;   /* 맞음 (흰 바탕 8.1:1 · ok-soft 위 7.1:1) */
  --es-ok-soft:   #e4f4eb;
  --es-ok-edge:   #3e8c68;   /* (3.9:1) */
  --es-no:        #8e1f20;   /* 틀림 (흰 바탕 8.9:1 · no-soft 위 7.6:1) */
  --es-no-soft:   #fce9e9;
  --es-no-edge:   #c05c5c;

  --es-focus:     #0b57d0;

  /* ---- 주제색 6칸 세트 ---------------------------------------------------
     차시·대단원마다 <body data-hue="sun"> 한 줄로 통째로 갈린다(아래 2절).
       --es-deep   짙은 단색. **흰 큰 글자를 얹는 유일한 자리.** 흰색과 9:1 이상
       --es-deep-2 더 짙은 것. 눌리는 버튼의 밑그림자·테두리
       --es-edge   뜻이 있는 테두리 (흰 바탕 3:1 이상 — WCAG 1.4.11)
       --es-vivid  **글자를 얹지 않는 색면.** 진행 막대·레일·아이콘. 채도를 아끼지 않는다
       --es-glow   밝은 빛. 잉크 글자를 얹어도 9:1 이상
       --es-tint   섹션 배경 띠. 잉크 글자 13:1 이상
       --es-tint-2 더 옅은 띠
     기본값은 green(1단원 '우리가 사는 곳'). ------------------------------ */
  --es-deep:      #08512f;   /* 흰 글자 9.4:1 */
  --es-deep-2:    #05321d;
  --es-edge:      #3e8c68;   /* 4.1:1 */
  --es-vivid:     #12a56a;
  --es-glow:      #7fe7b4;   /* 잉크 11.0:1 */
  --es-tint:      #dbf4e7;   /* 잉크 14.2:1 · deep 8.1:1 */
  --es-tint-2:    #effbf4;   /* 잉크 15.5:1 */

  /* ---- 옛 이름 — 14개 차시의 <style> 이 그대로 쓴다. 지우지 않는다 ------ */
  --es-brand:       var(--es-deep);
  --es-brand-soft:  var(--es-tint);
  --es-brand-line:  var(--es-edge);
  --es-soft-2:      var(--es-tint-2);
  --es-accent:      #6e3a00;   /* 강조 글자 (흰 바탕 9.3:1 · accent-soft 위 8.1:1) */
  --es-accent-soft: #ffeecf;
  --es-accent-line: #b4711a;   /* (4.0:1) */
  --es-accent-glow: #ffd84d;

  /* ---- 글자 — 이 목록 아래로 내려가는 값을 새로 만들지 않는다 ---------- */
  --es-fs:      20px;   /* 본문 */
  --es-fs-lg:   22px;   /* 앞머리 글 */
  --es-fs-sm:   18px;   /* 작은 글 (하한) */
  --es-fs-cap:  18px;   /* 그림 설명 — **아이가 읽을 말은 이쪽이다.** 줄이지 않는다 */
  --es-fs-src:  17px;   /* 작은 UI 라벨 (겹쳐보기 태그·핀 이름·연표 칸). 출처가 아니다 */
  --es-fs-btn:  19px;
  --es-fs-eyebrow: 15px;
  /* 출처 — 규격 하한(12px 초과)의 **명시된 예외**. 2026-09-09 사용자 결정.
     "그림 출처는 작게 만들어라. 초등학생들이 출처의 의미를 알 필요도 없다."
     지우지는 않는다 — CC 라이선스 의무이고 [4국02-05]('자료의 출처가 믿을 만한지
     판단한다')가 여기 산다. 다만 3학년이 **읽을 말은 캡션**이지 출처가 아니다.
     이 두 값은 `.es-src` 하나만 쓴다. 다른 곳에 가져다 쓰지 말 것. */
  --es-fs-credit: 12px;
  --es-src-ink:  #666c78;   /* 종이 위 5.0:1 · 흰 바탕 5.3:1 — 작아도 대비는 지킨다 */
  /* 제목은 화면 폭을 따라 자란다. 1판은 34px 고정이라 넓은 교실 화면에서
     본문 20px 대비 1.7배뿐이었다(중학교는 3.2배). */
  --es-h1:      clamp(30px, 4.4vw, 48px);
  --es-h2:      clamp(26px, 2.6vw, 34px);
  --es-h3:      24px;
  --es-lh:      1.9;

  /* ---- 폭 — 글줄과 캔버스는 다른 축이다 -------------------------------- */
  --es-measure: 560px;   /* 글줄. 한 줄 20~24자. **이 값은 바꾸지 않는다** */
  --es-mid:     780px;   /* 낱말 상자·퀴즈·정리처럼 글이 주인인 상자 */
  --es-content: 1100px;  /* 사진·활동판·지도·연표가 쓰는 캔버스 */
  --es-pad:     clamp(16px, 3vw, 40px);   /* 캔버스 바깥 여백 */
  --es-wrap:    var(--es-content);        /* 옛 이름. 인쇄 블록이 아직 쓴다 */

  /* ---- 손가락 ---------------------------------------------------------- */
  --es-tap: 56px;
  --es-gap: 12px;

  /* ---- 간격 — 1판의 최대값 48px 은 중·고의 80~84px 에 견주어 빽빽했다 --- */
  --es-sp-1: 6px;
  --es-sp-2: 12px;
  --es-sp-3: 20px;
  --es-sp-4: 32px;
  --es-sp-5: 48px;
  /* 섹션 안쪽 위아래 여백. 띠가 맞닿으므로 섹션 **사이**는 이 값의 두 배가 된다
     (1366px 에서 116px). 중·고의 섹션 간격 80~84px 보다 조금 넓다 —
     초등은 글이 크고 사진이 커서 그만큼이 필요하다. 1판은 48px 하나뿐이라 빽빽했다. */
  --es-sp-6: clamp(40px, 4.2vw, 58px);

  /* ---- 모서리 (중·고 9권 전수 집계: 카드 14 · 칩 8~10 · 패널 16~18) ---- */
  --es-r:      14px;
  --es-r-sm:   10px;
  --es-r-lg:   22px;
  --es-r-pill: 999px;

  /* ---- 그림자 — 검은 그림자가 아니라 주제색 그림자에 음수 spread ------- */
  --es-shadow:    0 2px 0 var(--es-line), 0 10px 24px -16px rgba(20,32,46,.40);
  --es-shadow-up: 0 14px 34px -18px rgba(20,32,46,.45);

  /* ---- 겹침 — 900 을 넘기지 않는다 ------------------------------------- */
  --es-z-top: 90;
  --es-z-pop: 200;
}

/* ── 2. 주제색 훅 ────────────────────────────────────────────────────────
   대단원·차시마다 색이 갈린다. <body data-hue="sun"> 한 줄이면 끝이다.
   섹션 하나만 갈고 싶으면 <section class="es-sec" data-hue="sky"> 도 된다.
   전부 흰 글자 9:1 이상 / 잉크 글자 13:1 이상으로 실측해 골랐다.
   ─────────────────────────────────────────────────────────────────────── */
[data-hue="green"]{           /* 초록 — 마을·자연·살아 있는 것 */
  --es-deep:#08512f; --es-deep-2:#05321d; --es-edge:#3e8c68;
  --es-vivid:#12a56a; --es-glow:#7fe7b4; --es-tint:#dbf4e7; --es-tint-2:#effbf4;
}
[data-hue="sun"]{             /* 금잔화 — 옛날·시간·따뜻함 */
  --es-deep:#6e3a00; --es-deep-2:#4a2600; --es-edge:#b4711a;
  --es-vivid:#e88a00; --es-glow:#ffd84d; --es-tint:#ffeecf; --es-tint-2:#fff8ea;
}
[data-hue="sky"]{             /* 하늘 — 물·날씨·멀리 보기 */
  --es-deep:#08456f; --es-deep-2:#052e4b; --es-edge:#2f7eb5;
  --es-vivid:#0e8fd0; --es-glow:#7fe0ff; --es-tint:#d8f0fc; --es-tint-2:#eef9fe;
}
[data-hue="coral"]{           /* 산호 — 마음·사람·이야기 */
  --es-deep:#8a1740; --es-deep-2:#5e0e2b; --es-edge:#c74b78;
  --es-vivid:#e0457f; --es-glow:#ffb3c7; --es-tint:#ffe0ea; --es-tint-2:#fff1f5;
}
[data-hue="violet"]{          /* 자주 — 상상·만들기 */
  --es-deep:#51249a; --es-deep-2:#371768; --es-edge:#8257c9;
  --es-vivid:#7c4deb; --es-glow:#c9b6ff; --es-tint:#ebe3fe; --es-tint-2:#f6f2ff;
}
[data-hue="cobalt"]{          /* 코발트 — 조사·자료·규칙 */
  --es-deep:#143a9e; --es-deep-2:#0d276c; --es-edge:#3f6fd6;
  --es-vivid:#2b62e8; --es-glow:#a8c6ff; --es-tint:#e0e9ff; --es-tint-2:#f1f5ff;
}
[data-hue="earth"]{           /* 흙 — 유물·땅·오래된 것 */
  --es-deep:#5e3810; --es-deep-2:#3f2409; --es-edge:#9c6b33;
  --es-vivid:#b4762a; --es-glow:#e8c48a; --es-tint:#f3e6d2; --es-tint-2:#faf3e9;
}

/* ── 3. 바탕 ─────────────────────────────────────────────────────────────── */
*, *::before, *::after{ box-sizing:border-box; }

/* 브라우저 기본 [hidden] 은 아래 .es-btn(display:inline-flex) 같은 규칙에 밀린다.
   숨긴 버튼이 그대로 보이던 실제 버그를 여기서 막는다. el.hidden = true 로 켠다. */
[hidden]{ display:none !important; }

html{ -webkit-text-size-adjust:100%; }

body{
  margin:0;
  background:var(--es-bg);
  color:var(--es-ink);
  font-family:'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont,
              'Malgun Gothic', 'Apple SD Gothic Neo', system-ui, sans-serif;
  font-size:var(--es-fs);
  line-height:var(--es-lh);
  letter-spacing:0;
  word-break:keep-all;          /* 낱말 가운데서 줄이 끊기지 않게 */
  overflow-wrap:break-word;
  -webkit-font-smoothing:antialiased;
}

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

a{ color:var(--es-deep); text-underline-offset:4px; }
a:hover{ color:var(--es-accent); }

h1,h2,h3,h4{
  font-family:inherit;          /* 명조 금지 */
  line-height:1.3;
  letter-spacing:-0.02em;       /* 큰 글씨는 자간을 죈다 */
  margin:0 0 var(--es-sp-2);
  font-weight:800;
  word-break:keep-all;
}
h1{ font-size:var(--es-h1); line-height:1.16; }
h2{ font-size:var(--es-h2); }
h3{ font-size:var(--es-h3); letter-spacing:-0.01em; }

p{ margin:0 0 var(--es-sp-3); max-width:var(--es-measure); }
ul,ol{ margin:0 0 var(--es-sp-3); padding-left:1.3em; max-width:var(--es-measure); }
li{ margin:0 0 var(--es-sp-1); }
strong,b{ font-weight:800; }

/* em 은 기울임이 아니라 **아래 40%만 칠하는 형광펜**. 한글에 기울임은 안 어울린다.
   ⚠️ "그라디언트 위에 글씨를 얹지 않는다"에 걸리지 않는다 — 이건 색이 섞이는
      그라디언트가 아니라 **딱 끊기는 두 색**이라 대비를 두 점에서 다 잴 수 있다:
      잉크↔종이 15.6:1, 잉크↔--es-glow 9.1~11.9:1(주제색 일곱 전부). */
em{
  font-style:normal; font-weight:800; color:inherit;
  background-image:linear-gradient(transparent 58%, var(--es-glow) 58%);
  padding:0 2px;
}

/* 어디를 누르고 있는지 항상 보이게 */
:focus-visible{
  outline:4px solid var(--es-focus);
  outline-offset:3px;
  border-radius:6px;
}

/* 읽어 주는 사람에게만 보이는 글 */
.es-sr{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

/* 가로로 넓은 것은 반드시 자기 상자 안에서만 흐른다 */
.es-scroll{ overflow-x:auto; -webkit-overflow-scrolling:touch; }

/* 작은 아이브로우 — 큰 글씨는 자간을 죄고, 작은 글씨는 벌린다.
   ⚠️ 영문 라벨은 쓰지 않는다(SPEC 2절). 한글로만 적는다. */
.es-eyebrow{
  display:inline-block;
  font-size:var(--es-fs-eyebrow); font-weight:800;
  letter-spacing:.22em; color:var(--es-deep);
  margin:0 0 var(--es-sp-1);
}

/* ── 4. 움직임 — @keyframes 전부 여기 모아 둔다 ──────────────────────────
   이 파일에서 움직이는 것은 셋뿐이다:
     ① 스크롤 등장 (JS 0줄, animation-timeline: view())
     ② 손이 닿았을 때의 반응 (누름·정답·오답·도장)
     ③ 다음에 할 것을 가리키는 맥동 — **3회 = 4.8초 뒤 스스로 멈춘다**(WCAG 2.2.2)
   내용과 무관한 장식적 움직임은 없다(Mayer seductive details).
   ─────────────────────────────────────────────────────────────────────── */

/* 기본 = 보인다. JS 가 죽어도, 인쇄해도, 구형 브라우저에서도 전부 읽힌다. */
.es-sec, .es-card, .es-fig{ opacity:1; transform:none; }

@supports (animation-timeline: view()){
  @media (prefers-reduced-motion: no-preference){
    .es-sec, .es-card, .es-fig{
      animation:es-rise linear both;
      animation-timeline:view();
      animation-range:entry 0% entry 40%;
    }
    .es-hero-q, .es-do, .es-wrap-up, .es-quiz{
      animation:es-rise-soft linear both;
      animation-timeline:view();
      animation-range:entry 0% entry 34%;
    }
  }
}

/* ① 등장 — 시작 opacity 는 0 이 아니라 .4. 어긋나도 글이 남는다 */
@keyframes es-rise{
  from{ opacity:.4; transform:translateY(18px); }
  to  { opacity:1;  transform:none; }
}
@keyframes es-rise-soft{
  from{ opacity:.55; transform:translateY(10px) scale(.985); }
  to  { opacity:1;   transform:none; }
}
/* 순차 등장 — .es-stagger 의 자식이 --i 만큼 늦게 온다 */
@keyframes es-fade-up{
  from{ opacity:.35; transform:translateY(14px); }
  to  { opacity:1;   transform:none; }
}

/* ② 손이 닿았을 때 */
@keyframes es-shake{            /* 오답 (1판에서 유일하게 살아 있던 것) */
  0%,100%{ transform:translateX(0); }
  20%{ transform:translateX(-8px); }
  45%{ transform:translateX(8px); }
  70%{ transform:translateX(-4px); }
}
@keyframes es-pop{              /* 정답 — 잘한 쪽이 더 크게 움직인다 */
  0%  { transform:scale(1); }
  35% { transform:scale(1.11); }
  62% { transform:scale(.98); }
  100%{ transform:scale(1); }
}
@keyframes es-pop-in{           /* 새로 생긴 것 */
  0%  { opacity:0; transform:scale(.72) translateY(8px); }
  62% { opacity:1; transform:scale(1.06) translateY(0); }
  100%{ opacity:1; transform:none; }
}
@keyframes es-land{             /* 카드가 칸에 날아와 앉는다 */
  0%  { opacity:0; transform:translateY(-26px) scale(.84) rotate(-4deg); }
  55% { opacity:1; transform:translateY(4px)  scale(1.05) rotate(1deg); }
  78% { transform:translateY(-2px) scale(.99); }
  100%{ opacity:1; transform:none; }
}
@keyframes es-drop{             /* 지도 스티커가 툭 떨어진다 */
  0%  { opacity:0; transform:translate(-50%,-160%) scale(.6); }
  60% { opacity:1; transform:translate(-50%,-42%) scale(1.12); }
  80% { transform:translate(-50%,-54%) scale(.97); }
  100%{ opacity:1; transform:translate(-50%,-50%) scale(1); }
}
@keyframes es-stamp{            /* 도장이 쿵 찍힌다 */
  0%  { transform:scale(2.1) rotate(-16deg); opacity:0; }
  45% { transform:scale(.86) rotate(6deg);   opacity:1; }
  70% { transform:scale(1.1) rotate(-2deg); }
  100%{ transform:scale(1) rotate(0);        opacity:1; }
}
@keyframes es-wiggle{           /* 들썩 — 눌러도 되는 것 */
  0%,100%{ transform:rotate(0); }
  25%{ transform:rotate(-2.5deg); }
  75%{ transform:rotate(2.5deg); }
}
@keyframes es-slide-down{       /* 까닭이 아래로 펼쳐진다 */
  from{ opacity:0; transform:translateY(-10px); max-height:0; }
  to  { opacity:1; transform:none; max-height:60em; }
}
@keyframes es-flash{            /* 다 했을 때 판 전체가 한 번 밝아진다 */
  0%,100%{ box-shadow:0 0 0 0 rgba(0,0,0,0); }
  40%    { box-shadow:0 0 0 10px var(--es-glow); }
}
@keyframes es-ripple{           /* 사진에서 찾았을 때의 파문 */
  0%  { opacity:.85; transform:translate(-50%,-50%) scale(.3); }
  100%{ opacity:0;   transform:translate(-50%,-50%) scale(2.6); }
}
@keyframes es-miss-fade{        /* 빗맞힌 자리 — 어디를 눌렀는지 남긴다 */
  0%  { opacity:.9; transform:translate(-50%,-50%) scale(.5); }
  30% { opacity:.9; transform:translate(-50%,-50%) scale(1); }
  100%{ opacity:0;  transform:translate(-50%,-50%) scale(1.2); }
}
@keyframes es-spark{            /* 축하 — 조각이 사방으로 튄다 */
  0%  { opacity:0;  transform:translate(0,0) scale(.3); }
  18% { opacity:1; }
  100%{ opacity:0;  transform:translate(var(--dx,0), var(--dy,0)) scale(1.15); }
}
@keyframes es-confetti{         /* 마무리 — 2.6초에 끝나고 스스로 사라진다 */
  0%  { opacity:0; transform:translateY(-14px) rotate(0); }
  12% { opacity:1; }
  100%{ opacity:0; transform:translateY(180px) rotate(420deg); }
}
@keyframes es-banner-in{
  0%  { opacity:0; transform:translate(-50%, -22px) scale(.9); }
  60% { opacity:1; transform:translate(-50%, 4px)  scale(1.03); }
  100%{ opacity:1; transform:translate(-50%, 0)    scale(1); }
}
@keyframes es-banner-out{
  from{ opacity:1; transform:translate(-50%,0) scale(1); }
  to  { opacity:0; transform:translate(-50%,-16px) scale(.95); }
}

/* ③ 주의 유도(signaling) — Mayer: 다음에 할 것을 가리키는 단서는 학습을 깊게 한다.
   ⚠️ 3회 = 4.8초. 5초를 넘기지 않으므로 WCAG 2.2.2 의 정지 수단 요건에 걸리지 않는다. */
@keyframes es-hint{
  0%,100%{ box-shadow:0 0 0 0 var(--es-vivid); }
  50%    { box-shadow:0 0 0 12px rgba(0,0,0,0); }
}
@keyframes es-bar-shine{        /* 진행 막대가 채워질 때의 빛 */
  from{ background-position:-160px 0; }
  to  { background-position:160px 0; }
}
@keyframes es-swell{            /* 히어로 장식이 천천히 숨 쉰다 (4.5초 · 3회) */
  0%,100%{ transform:scale(1); }
  50%    { transform:scale(1.05); }
}
@keyframes es-draw{             /* 선이 그려진다 — 차시 SVG 가 쓴다 */
  from{ stroke-dashoffset:var(--es-draw-len, 400); }
  to  { stroke-dashoffset:0; }
}
/* (12판) 소리가 날 때 그림이 **느리게** 떨린다 — 31절 .es-trem 이 쓴다. 폭(--es-trem-amp)과 빠르기(--es-trem-t)는 es.js 가 준다.
   진짜 떨림은 1초에 수백 번이다. 그대로 그리면 1초 3번 넘는 번쩍임(WCAG 2.3.1)이라 느린 그림 + '진짜는 훨씬 빨라요' 다.
   ⚠️ 이름에 -x 를 쓰지 않는다(progress.js NO_RX 가 판정으로 읽는다) — 가로 h · 세로 v. */
@keyframes es-trem-h{
  0%,100%{ transform:translateX(0); }
  25%    { transform:translateX(var(--es-trem-amp, 4px)); }
  75%    { transform:translateX(calc(-1 * var(--es-trem-amp, 4px))); }
}
@keyframes es-trem-v{
  0%,100%{ transform:translateY(0); }
  25%    { transform:translateY(var(--es-trem-amp, 4px)); }
  75%    { transform:translateY(calc(-1 * var(--es-trem-amp, 4px))); }
}

/* 그려지는 선 — 차시 SVG 가 <path class="es-draw" style="--es-draw-len:420"> 로 쓴다.
   길이를 모르면 400 으로 잡는다. 미지원·감속에서는 그냥 그려진 채로 보인다. */
.es-draw{ stroke-dasharray:var(--es-draw-len, 400); stroke-dashoffset:0; }
@media (prefers-reduced-motion: no-preference){
  .es-draw{ animation:es-draw 1.6s cubic-bezier(.22,.61,.36,1) both; }
  @supports (animation-timeline: view()){
    .es-draw{ animation-timeline:view(); animation-range:entry 10% cover 45%; }
  }
}

/* 순차 등장 — 차시가 <div class="es-stagger"> 로 감싸면 자식이 차례로 온다 */
@media (prefers-reduced-motion: no-preference){
  .es-stagger > *{ animation:es-fade-up .55s cubic-bezier(.22,.61,.36,1) both; }
  .es-stagger > *:nth-child(1){ animation-delay:0ms; }
  .es-stagger > *:nth-child(2){ animation-delay:90ms; }
  .es-stagger > *:nth-child(3){ animation-delay:180ms; }
  .es-stagger > *:nth-child(4){ animation-delay:270ms; }
  .es-stagger > *:nth-child(5){ animation-delay:360ms; }
  .es-stagger > *:nth-child(6){ animation-delay:450ms; }
  .es-stagger > *:nth-child(n+7){ animation-delay:540ms; }
}

/* 연출 클래스 — es.js 가 붙였다 뗀다 */
.es-shake  { animation:es-shake .38s ease 1; }
.es-pop    { animation:es-pop .42s cubic-bezier(.18,.89,.32,1.28) 1; }
.es-pop-in { animation:es-pop-in .38s cubic-bezier(.18,.89,.32,1.28) 1; }
.es-land   { animation:es-land .44s cubic-bezier(.22,.61,.36,1) 1; }
.es-flash  { animation:es-flash .7s ease 1; }
.es-wiggle { animation:es-wiggle .5s ease 1; }
.es-hint{
  animation:es-hint 1.6s ease-out 3;   /* 4.8초 뒤 스스로 멈춘다 */
  position:relative; z-index:1;
}

/* 축하 조각 — body 끝에 잠깐 붙였다 지운다(1.1초). 위치는 fixed, 클릭을 막지 않는다 */
.es-burst{
  position:fixed; width:0; height:0; pointer-events:none;
  z-index:var(--es-z-pop);
}
.es-burst > i{
  position:absolute; left:0; top:0;
  width:11px; height:11px; margin:-5px 0 0 -5px; border-radius:3px;
  background:var(--es-vivid);
  animation:es-spark .78s cubic-bezier(.22,.61,.36,1) both;
}
.es-burst > i:nth-child(3n)  { background:var(--es-accent-glow); border-radius:50%; }
.es-burst > i:nth-child(3n+1){ background:var(--es-glow); }

/* 마무리 배너 — 한 번, 4.5초, 스스로 사라진다. 닫기 단추가 있다 */
/* ⚠️ width:max-content 를 빼면 안 된다(2026-09-16). position:fixed + left:50% 인 상자는 폭을 **왼쪽 끝에서 화면 끝까지**
      (화면의 절반)만 받아, 390 에서 약 195px 에 갇혀 '오늘 할 / 일을 모두 / 마쳤어요.…' 다섯 줄로 위 띠를 4.5초 덮었다
      (4-1 집필자 여섯이 같은 것을 보고했다 · 3-1·3-2 전 쪽 같음). 글 길이만큼 넓히고 max-width 로 화면 안에 묶는다. */
.es-finale{
  position:fixed; left:50%; top:14px; z-index:var(--es-z-pop);
  display:flex; align-items:center; gap:14px;
  width:max-content;
  max-width:min(92vw, 620px);
  padding:14px 18px;
  background:var(--es-deep); color:#fff;
  border-radius:var(--es-r-lg);
  box-shadow:0 18px 46px -18px rgba(20,32,46,.65);
  font-size:var(--es-fs-lg); font-weight:800;
  animation:es-banner-in .5s cubic-bezier(.18,.89,.32,1.28) both;
}
.es-finale.is-out{ animation:es-banner-out .4s ease forwards; }
.es-finale .es-finale-em{ font-size:32px; line-height:1; }
.es-finale .es-finale-x{
  margin-left:auto; flex:0 0 auto;
  width:44px; height:44px; border-radius:50%;
  background:rgba(255,255,255,.16); color:#fff;
  border:2px solid rgba(255,255,255,.5);
  font:inherit; font-size:20px; cursor:pointer;
}
.es-confetti{
  position:fixed; inset:0 0 auto 0; height:0; pointer-events:none;
  z-index:var(--es-z-pop);
}
.es-confetti > i{
  position:absolute; top:0; width:10px; height:14px; border-radius:2px;
  background:var(--es-vivid);
  animation:es-confetti 2.4s cubic-bezier(.3,.1,.6,1) both;
}
.es-confetti > i:nth-child(4n)  { background:var(--es-accent-glow); }
.es-confetti > i:nth-child(4n+1){ background:var(--es-glow); border-radius:50%; }
.es-confetti > i:nth-child(4n+2){ background:var(--es-deep); }

/* 진행 막대 — 숫자 배지와 **늘 함께** 쓴다(색만으로 정보를 주지 않는다) */
.es-progress{
  display:block; height:14px; margin:var(--es-sp-2) 0 0;
  background:var(--es-soft);
  border:2px solid var(--es-line);
  border-radius:var(--es-r-pill);
  overflow:hidden; max-width:var(--es-mid);
}
.es-progress > i{
  display:block; height:100%; width:0;
  background:var(--es-vivid);
  border-radius:var(--es-r-pill);
  transition:width .45s cubic-bezier(.22,.61,.36,1);
}
.es-progress[data-full="1"] > i{
  background-image:linear-gradient(100deg,
    rgba(255,255,255,0) 0%, rgba(255,255,255,.75) 45%, rgba(255,255,255,0) 90%);
  background-size:160px 100%; background-repeat:no-repeat;
  animation:es-bar-shine .9s ease 2;
}

/* ── 5. 상단 — 오늘 할 일 ────────────────────────────────────────────────── */
.es-top{
  position:sticky; top:0; z-index:var(--es-z-top);
  background:var(--es-surface);
  border-bottom:4px solid var(--es-deep);
  padding:10px var(--es-pad);
  box-shadow:0 6px 18px -14px rgba(20,32,46,.6);
  max-height:40vh; overflow-y:auto;   /* 좁은 화면에서 화면 절반을 먹지 않게 */
}
.es-top-in{ max-width:var(--es-content); margin:0 auto; }
.es-top-row{ display:flex; align-items:center; gap:var(--es-gap); flex-wrap:wrap; }
.es-top-title{
  font-size:var(--es-fs-lg); font-weight:800; color:var(--es-deep);
  margin:0; line-height:1.35; max-width:none;
}
.es-top-back{
  display:inline-flex; align-items:center; min-height:40px;
  font-size:var(--es-fs-sm); font-weight:800; color:var(--es-ink-2);
  text-decoration:none; padding:4px 10px;
  border:2px solid var(--es-line); border-radius:var(--es-r-pill);
}
.es-top-back:hover{ border-color:var(--es-edge); color:var(--es-deep); background:var(--es-tint-2); }
.es-dots{ display:flex; gap:10px; margin-left:auto; align-items:center; }
.es-dot{
  width:18px; height:18px; border-radius:50%;
  background:var(--es-surface); border:3px solid var(--es-line-2);
  transition:background-color .25s ease, border-color .25s ease, transform .25s ease;
}
.es-dot.is-on{ background:var(--es-vivid); border-color:var(--es-deep); }
.es-dot.es-pop{ animation:es-pop .42s cubic-bezier(.18,.89,.32,1.28) 1; }
.es-dot-txt{ font-size:var(--es-fs-sm); color:var(--es-ink-2); font-weight:800; }

/* 오늘 할 일 3개 */
.es-todo{
  list-style:none; margin:10px 0 0; padding:0;
  display:flex; gap:var(--es-gap); flex-wrap:wrap; max-width:none;
}
.es-todo > li{ margin:0; }
.es-todo-btn{
  display:inline-flex; align-items:center; gap:10px;
  min-height:48px; padding:6px 16px 6px 8px;
  background:var(--es-soft); color:var(--es-ink);
  border:2px solid var(--es-line);
  border-radius:var(--es-r-pill);
  font:inherit; font-size:var(--es-fs-sm); font-weight:700;
  cursor:pointer; text-align:left;
  transition:transform .18s ease, border-color .18s ease, background-color .25s ease,
             box-shadow .18s ease;
}
.es-todo-btn:hover{
  border-color:var(--es-edge); background:var(--es-tint-2);
  transform:translateY(-2px);
  box-shadow:0 8px 18px -12px var(--es-deep);
}
.es-todo-btn:active{ transform:translateY(1px); }
.es-todo-stamp{
  width:32px; height:32px; flex:0 0 auto; border-radius:50%;
  display:inline-flex; align-items:center; justify-content:center;
  background:var(--es-surface); border:2px dashed var(--es-line-2);
  font-size:18px; line-height:1;
}
.es-todo-btn[data-done="1"]{
  background:var(--es-ok-soft); border-color:var(--es-ok); color:var(--es-ok);
}
.es-todo-btn[data-done="1"] .es-todo-stamp{
  background:var(--es-ok); border:2px solid var(--es-ok); color:#fff;
}
.es-todo-stamp.es-stamped{ animation:es-stamp .5s cubic-bezier(.18,.89,.32,1.28) 1; }

/* 좁은 화면(폰 세로)·낮은 화면(폰 가로) — 위 띠를 **두 줄**로 (2026-09-15, 4-1 05/02 기준 차시가 찾았다)
   ⚠️ 옛 모습은 390×844 에서 310px(기록이 남아 '다시 하기'가 붙으면 338px — 40vh 에 걸려 띠 안에서 또 스크롤)였다.
      할 일 단추 셋이 한 줄씩 쌓이고 제목·돌아가기가 두 줄을 먹었다. 남는 높이가 534px 라
      '무대 + 조작 + 결과 안내 줄'이 **어느 쪽에서도** 한 화면에 들지 않았다 — 누르고 나서 결과를 보려면 스크롤해야 했다
      (기준 차시 실측: 무대 362 + 캡션·단추 → 안내 줄 아래 끝 938 / 화면 844).
   그래서 두 줄(112px 안팎)로 접는다:
     1줄  [← 목록으로] [제목…(말줄임)] [● ● ○]      — '3개 중 1개 했어요' 글자는 낭독기에만 남긴다(점이 같은 것을 보인다)
     2줄  [✔ 할 일 ▸ 할 일 ▸ 할 일 ]  [↻]           — 할 일은 **가로로 밀어** 본다. 둘째 단추가 잘려 보이는 것이 밀 수 있다는 표시다.
   · 단추 높이 44px 이상(WCAG 2.5.8 넉넉히) · 글자 18px(--es-fs-sm 하한) 그대로. 제목은 히어로 h1 에 온전히 있다.
   · 도장이 찍히면 es.js(todoReveal)가 그 단추를 목록 안에서 보이게 민다 — 쪽은 위아래로 움직이지 않는다.
   · 초점 테두리(4px + 3px)가 가로 스크롤 상자에 잘리지 않게 목록에 안쪽 여백 7px 을 두고 같은 만큼 바깥 여백을 당긴다.
   · '↻ 이 쪽 다시 하기'(기록이 있을 때만 붙는다)는 둘째 줄 끝 44px 둥근 단추로 — 글자는 낭독기 이름으로 남는다.
   ⚠️ screen 에만 — 인쇄는 위 띠를 통째로 숨긴다(아래 인쇄 절). */
@media screen and (max-width:600px), screen and (max-height:500px){
  .es-top{
    display:grid; grid-template-columns:minmax(0,1fr) auto; column-gap:8px; align-items:center;
    padding:6px var(--es-pad) 1px;
  }
  .es-top-in{ display:contents; }
  .es-top-row{ grid-column:1 / -1; flex-wrap:nowrap; gap:10px; min-width:0; }
  .es-top-back{ flex:0 0 auto; min-height:44px; padding:2px 10px; white-space:nowrap; }
  .es-top-title{
    flex:1 1 auto; min-width:0; font-size:var(--es-fs-sm);
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  .es-dots{ flex:0 0 auto; gap:6px; }
  .es-dot{ width:16px; height:16px; }
  .es-dot-txt{
    position:absolute; width:1px; height:1px; padding:0; margin:-1px;
    overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0;
  }
  .es-todo{
    grid-column:1 / -1; flex-wrap:nowrap; gap:8px;
    margin:-1px -7px 0; padding:7px;
    overflow-x:auto; overflow-y:hidden; overscroll-behavior-x:contain;
    scroll-snap-type:x proximity; scroll-padding-inline:7px; scrollbar-width:thin;
  }
  .es-top:has(> .es-reset) .es-todo{ grid-column:1; margin-right:0; }   /* 잘린 단추 끝이 ↻ 에 붙지 않게 */
  .es-todo > li{ flex:0 0 auto; scroll-snap-align:start; }
  .es-todo-btn{ min-height:44px; padding:3px 12px 3px 6px; gap:8px; white-space:nowrap; }
  .es-todo-btn:hover{ transform:none; box-shadow:none; }   /* 뜨는 그림자가 가로 스크롤 상자에 잘린다 */
  .es-todo-stamp{ width:30px; height:30px; font-size:16px; }
  /* ⚠️ '.es-top > .es-reset' — 맨 끝 '이 쪽 다시 하기' 절의 '.es-reset'(같은 명시도, 뒤에 온다)이 글자 크기·여백·테두리를
        되돌려 15px 글자가 44px 상자 안에서 여러 줄로 접히고 띠 안에 세로 스크롤(312px)이 생겼다(크롬 실측). */
  .es-top > .es-reset{
    grid-column:2; grid-row:2; align-self:center;
    display:inline-flex; align-items:center; justify-content:center;
    width:44px; height:44px; min-height:44px; padding:0;
    border:2px solid var(--es-line); background:var(--es-soft); font-size:0; line-height:1;
  }
  .es-top > .es-reset::before{ content:"↻"; content:"↻" / ""; font-size:24px; line-height:1; color:var(--es-ink-2); }
}

/* ── 6. 히어로 ───────────────────────────────────────────────────────────
   전면 색면(단색 — 그라디언트 위에 글씨를 얹지 않는다) + 장식 슬롯 + 큰 제목.
   넓은 화면에서는 왼쪽에 글, 오른쪽에 사진의 2단이 된다.
   ─────────────────────────────────────────────────────────────────────── */
.es-hero{
  position:relative; overflow:hidden; isolation:isolate;
  background:var(--es-deep);
  color:#fff;                                   /* 흰 큰 글자 — 실측 9:1 이상 */
  padding:clamp(36px,5vw,64px) var(--es-pad) clamp(64px,7vw,96px);
}
/* 40px 격자를 깔고 가장자리를 마스크로 지운다 — 그냥 깔면 촌스럽고, 페이드하면 설계도가 된다.
   ⚠️ 글자가 얹히지 않는 장식이다. 대비 계산에 들어가지 않는다. */
.es-hero::before{
  content:""; position:absolute; inset:0; pointer-events:none; z-index:0;
  background-image:
    linear-gradient(rgba(255,255,255,.10) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.10) 1px, transparent 1px);
  background-size:44px 44px;
  -webkit-mask-image:radial-gradient(ellipse at 30% 40%, #000 12%, transparent 72%);
          mask-image:radial-gradient(ellipse at 30% 40%, #000 12%, transparent 72%);
}
.es-hero-in{
  position:relative; z-index:1;
  max-width:var(--es-content); margin:0 auto;
  display:grid; gap:0 clamp(24px,3vw,44px);
  grid-template-columns:minmax(0,1fr);
}
.es-hero h1{ color:#fff; margin-bottom:var(--es-sp-3); max-width:16em; }
.es-hero-lead{
  font-size:var(--es-fs-lg); color:#fff; opacity:.94;
  margin-bottom:var(--es-sp-3); max-width:var(--es-measure);
}
.es-hero .es-fig{ margin:var(--es-sp-3) 0 var(--es-sp-3); }
.es-hero .es-fig img{
  border:5px solid rgba(255,255,255,.85);
  border-radius:var(--es-r-lg);
  box-shadow:0 22px 44px -22px rgba(0,0,0,.7);
  background:rgba(255,255,255,.12);
}
.es-hero .es-cap{ color:#fff; }
/* 짙은 색면 위의 출처 — 흰 72%. 주제색 일곱 전부에서 5.6:1 이상이다 */
.es-hero{ --es-src-ink:rgba(255,255,255,.72); }

/* 오늘의 질문 — 히어로와 본문 사이에 걸터앉는 흰 카드(중·고의 -72px 수법) */
.es-hero-q{
  position:relative; z-index:2;
  margin:var(--es-sp-3) 0 clamp(-72px,-6vw,-52px);
  background:var(--es-surface); color:var(--es-ink);
  border:0; border-top:8px solid var(--es-glow);
  border-radius:var(--es-r-lg);
  padding:var(--es-sp-4) clamp(20px,3vw,34px);
  font-size:clamp(21px,2.1vw,26px); font-weight:800; line-height:1.55;
  max-width:none;
  box-shadow:0 24px 50px -26px rgba(20,32,46,.75);
}
.es-hero-q::before{
  content:"❓"; display:inline-block; margin-right:10px; font-size:1.15em;
}

/* 히어로 장식 슬롯 — 차시가 그 개념을 선으로 그린 <svg class="es-hero-art"> 를 넣는다.
   ⚠️ 장식이지 정보가 아니다. aria-hidden="true" 로 넣는다. */
.es-hero-art{
  position:absolute; right:-40px; top:8%;
  width:min(420px, 38vw); height:auto; opacity:.20; z-index:0;
  pointer-events:none; color:#fff;
}
@media (prefers-reduced-motion: no-preference){
  .es-hero-art{ animation:es-swell 4.5s ease-in-out 3; transform-origin:60% 50%; }
}
@media (max-width:900px){ .es-hero-art{ display:none; } }
/* ⚠️ 히어로에 사진(`.es-hero .es-fig`)이 있으면 장식은 오른쪽 칸에 **깔린다** —
   1366 실측으로 선화의 3/4 이 사진 뒤였다. 사진이 있을 때는 왼쪽 아래로 흘린다. */
.es-hero:has(.es-fig) .es-hero-art{ right:auto; left:-40px; top:auto; bottom:-24px; }

@media (min-width:900px){
  .es-hero-in{ grid-template-columns:minmax(0,1.06fr) minmax(0,.94fr); align-items:start; }
  .es-hero-in > h1,
  .es-hero-in > .es-hero-lead,
  .es-hero-in > .es-hero-q{ grid-column:1; }
  .es-hero-in > .es-fig{
    grid-column:2; grid-row:1 / span 3; align-self:center;
    margin:0; max-width:none;
  }
}

/* ── 7. 본문 뼈대 — 글줄 560, 캔버스 1100, 배경 띠는 화면 끝까지 ────────
   .es-main 과 .es-sec 이 같은 3칸 격자를 쓴다. 자식은 가운데 칸(content)에
   떨어지고, 섹션 자신은 바깥 칸까지(full) 뻗어 배경 띠가 화면을 가로지른다.
   → 마크업을 하나도 바꾸지 않고 full-bleed 가 된다.
   ⚠️ 100vw 를 쓰지 않는다 — 스크롤바 폭 때문에 가로 스크롤이 생긴다.
   ─────────────────────────────────────────────────────────────────────── */
.es-main{
  display:grid;
  grid-template-columns:
    [full-start] minmax(var(--es-pad), 1fr)
    [content-start] minmax(0, var(--es-content))
    [content-end] minmax(var(--es-pad), 1fr)
    [full-end];
  max-width:none; margin:0; padding:0 0 var(--es-sp-6);
}
.es-main > *{ grid-column:content; min-width:0; }

.es-sec{
  grid-column:full;
  display:grid;
  grid-template-columns:
    [full-start] minmax(var(--es-pad), 1fr)
    [content-start] minmax(0, var(--es-content))
    [content-end] minmax(var(--es-pad), 1fr)
    [full-end];
  margin:0;
  padding:var(--es-sp-6) 0;
  position:relative;
}
.es-sec > *{ grid-column:content; min-width:0; }
.es-sec > :last-child{ margin-bottom:0; }

/* 섹션 배경 띠 — 홀수는 종이, 짝수는 옅은 주제색. 화면 끝까지 흐른다. */
/* ⚠️ `:where()` 로 감싸 **특이도 0** 으로 만든다.
   전에는 `.es-main > .es-sec:nth-of-type(even)`(0,3,0)이 `.es-sec.is-deep`(0,2,0)을 이겨서,
   짝수 자리에 놓인 is-deep 섹션은 **배경만 밀리고 흰 글자는 그대로** 먹었다 —
   옅은 띠 위 흰 글씨(대비 약 1.1:1)가 오류 한 줄 없이 나갔다. 집필자 넷이 각자 우회하고 있었다. */
:where(.es-main > .es-sec:nth-of-type(even)){
  background:var(--es-tint-2);
  box-shadow:inset 0 1px 0 var(--es-tint), inset 0 -1px 0 var(--es-tint);
}
/* 옵션 — 차시가 골라 쓴다 */
.es-sec.is-band{ background:var(--es-tint); }
.es-sec.is-paper{ background:var(--es-surface); }
.es-sec.is-deep{                       /* 글만 있는 마무리 띠에만 쓴다 */
  background:var(--es-deep);
  --es-ink:#ffffff; --es-ink-2:#e6eef2;
  --es-src-ink:rgba(255,255,255,.72);
  color:#fff;
}
.es-sec.is-deep h2, .es-sec.is-deep h3, .es-sec.is-deep .es-lead{ color:#fff; }
.es-sec.is-deep .es-sec-step{ background:#fff; color:var(--es-deep); }

/* 첫 섹션은 걸터앉은 질문 카드를 피해 위를 비운다 */
.es-main > .es-sec:first-of-type{ padding-top:clamp(76px,7vw,96px); }

.es-sec-head{
  display:flex; align-items:center; gap:var(--es-sp-2);
  margin-bottom:var(--es-sp-3);
}
.es-sec-step{
  flex:0 0 auto; width:56px; height:56px; border-radius:20px;
  background:var(--es-deep); color:#fff;
  display:flex; align-items:center; justify-content:center;
  font-size:26px; font-weight:800;
  box-shadow:0 10px 22px -12px var(--es-deep-2);
  transform:rotate(-4deg);
}
.es-sec-head h2{ margin:0; color:var(--es-ink); }

/* 각 섹션 첫 줄 — "먼저 사진을 볼 거예요." */
.es-lead{
  font-size:var(--es-fs-lg); font-weight:800; color:var(--es-deep);
  margin:0 0 var(--es-sp-3); max-width:var(--es-measure);
  padding-left:16px; border-left:6px solid var(--es-glow);
}

/* 카드 — 위 4px 색 띠 + 뜨는 그림자. 검은 그림자가 아니라 주제색 그림자다 */
.es-card{
  position:relative; overflow:hidden;
  background:var(--es-surface);
  border:2px solid var(--es-line);
  border-radius:var(--es-r-lg);
  padding:var(--es-sp-4) var(--es-sp-3) var(--es-sp-3);
  margin:0 0 var(--es-sp-3);
  max-width:var(--es-mid);
  box-shadow:var(--es-shadow);
  transition:transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}
.es-card::before{
  content:""; position:absolute; left:0; right:0; top:0; height:6px;
  background:var(--es-vivid);
}
.es-card:hover{
  transform:translateY(-3px);
  border-color:var(--es-edge);
  box-shadow:0 16px 34px -18px var(--es-deep);
}
.es-card > :last-child{ margin-bottom:0; }

.es-para{ max-width:var(--es-measure); margin:0 0 var(--es-sp-3); }

/* 나란히 놓는 판 — 넓어진 캔버스를 쓰라고 새로 더한다 */
.es-cols{
  display:grid; gap:var(--es-sp-3);
  grid-template-columns:repeat(auto-fit, minmax(280px, 1fr));
  margin:0 0 var(--es-sp-3); max-width:none;
}
.es-cols > *{ margin:0; max-width:none; }

/* 새 낱말 뜻 — 한 화면에 하나만 */
.es-word{
  position:relative;
  background:var(--es-accent-soft);
  border:2px solid var(--es-accent-line);
  border-left:12px solid var(--es-accent);
  border-radius:var(--es-r);
  padding:var(--es-sp-3);
  margin:var(--es-sp-3) 0;
  max-width:var(--es-mid);
  box-shadow:0 10px 24px -18px rgba(110,58,0,.6);
}
.es-word-t{
  display:inline-block;
  font-size:var(--es-fs-lg); font-weight:800; color:var(--es-accent);
  margin-bottom:var(--es-sp-1);
}
.es-word-t::before{ content:"📖 "; }
.es-word p{ margin:0; }

/* 그림·사진 — 480px 기둥은 폐기. 캔버스에 맞게 다시 잡았다.
   ⚠️ 차시 <style> 의 .pXXX-shot{max-width:…} 가 이 값을 덮는다(그쪽이 뒤에 온다).
      얼굴이 식별되지 않게 일부러 작게 묶어 둔 것도 있으니 함부로 키우지 말 것. */
.es-fig{ margin:0 0 var(--es-sp-4); max-width:var(--es-content); }
.es-fig img{
  width:100%; border-radius:var(--es-r-lg);
  border:3px solid var(--es-line); background:var(--es-soft);
  box-shadow:var(--es-shadow-up);
}
.es-fig figcaption{ margin-top:12px; max-width:var(--es-mid); }
.es-cap{
  display:block; font-size:var(--es-fs-cap); font-weight:800; color:var(--es-ink);
  margin-bottom:4px;
}
/* 출처 — **작고 조용하게.** (2026-09-09 개정)
   전에는 캡션과 같은 굵기·거의 같은 크기(17px)로 서고 링크가 파랗게 튀어서,
   사진마다 시선이 두 번 걸렸다. 사진 아래 한 줄로 조용히 접혀 있어야 한다.
   · 12px · 흐린 회색 · 링크도 같은 회색에 밑줄 없음 — hover/focus 에서만 드러난다.
   · 지우지 않는다. 접어 숨기지도 않는다(라이선스 표기는 늘 보여야 한다).
   · 짙은 색면(히어로·is-deep·정리)에서는 --es-src-ink 를 그쪽에서 갈아 끼운다. */
.es-src{
  display:block;
  font-size:var(--es-fs-credit); line-height:1.45; font-weight:400;
  color:var(--es-src-ink);
  margin-top:3px; letter-spacing:0;
}
.es-src a{
  color:inherit; text-decoration:none;
  border-bottom:1px solid transparent;
}
.es-src a:hover, .es-src a:focus-visible{ color:var(--es-ink-2); border-bottom-color:currentColor; }

/* 활동 상자 — 캔버스를 다 쓴다 */
.es-do{
  position:relative;
  background:var(--es-surface);
  border:3px solid var(--es-edge);
  border-radius:var(--es-r-lg);
  padding:var(--es-sp-4) clamp(16px,2.4vw,28px) var(--es-sp-3);
  margin:var(--es-sp-4) 0;
  max-width:none;
  box-shadow:0 18px 38px -26px var(--es-deep);
}
.es-do::before{
  content:""; position:absolute; left:0; right:0; top:0; height:8px;
  background:var(--es-vivid);
  border-radius:var(--es-r-lg) var(--es-r-lg) 0 0;
}
.es-do-head{
  display:flex; align-items:center; gap:10px;
  font-size:clamp(21px,2vw,25px); font-weight:800; color:var(--es-deep);
  margin-bottom:var(--es-sp-2);
}
.es-do-head::before{ content:"✋"; font-size:30px; line-height:1; }
.es-do-how{ margin:0 0 var(--es-sp-3); padding-left:1.4em; max-width:var(--es-mid); }
.es-do-how li{ font-size:var(--es-fs-sm); font-weight:700; }
.es-do > :last-child{ margin-bottom:0; }

/* 정리 — 차시를 닫는 짙은 색면 + 흰 글자 (패턴 2) */
.es-wrap-up{
  --es-ink:#ffffff; --es-ink-2:#dfe9e4;
  --es-src-ink:rgba(255,255,255,.72);
  background:var(--es-deep); color:#fff;
  border:0;
  border-radius:var(--es-r-lg);
  padding:var(--es-sp-4) clamp(18px,2.4vw,30px);
  margin:var(--es-sp-4) 0;
  max-width:var(--es-mid);
  box-shadow:0 22px 46px -26px var(--es-deep-2);
}
.es-wrap-up h2, .es-wrap-up h3{ color:var(--es-glow); margin-top:0; }
.es-wrap-up ul{ padding-left:1.3em; }
.es-wrap-up a{ color:var(--es-glow); }
.es-wrap-up > :last-child{ margin-bottom:0; }
/* 짙은 면 위의 입력 칸은 **덮어쓰지 않는 잉크**를 쓴다 */
.es-wrap-up .es-write,
.es-wrap-up textarea,
.es-wrap-up input.es-input{ color:var(--es-ink-abs); border-color:var(--es-glow); }
/* 짙은 면 위의 흰 단추도 **덮어쓰지 않는 잉크**로 (2026-09-16)
   ⚠️ 정리 띠·is-deep 는 --es-ink 를 #fff 로 갈아 끼우는데 .es-btn 은 color:var(--es-ink) · background:var(--es-surface)(흰색)라
      **흰 바탕에 흰 글자(1:1)** 였다(07/01 '첫 문장 넣기' 단추 크롬 실측). 단추 안에서만 잉크를 되돌린다 — is-primary 는 제 색(#fff)을 쓴다. */
.es-wrap-up .es-btn, .es-sec.is-deep .es-btn{ --es-ink:var(--es-ink-abs); --es-ink-2:#3d4a5c; }

/* 다음 버튼 — 늘 같은 자리에 하나만 */
.es-next{
  max-width:var(--es-content); margin:0 auto var(--es-sp-6);
  padding:0 var(--es-pad); display:flex; justify-content:center;
}
.es-next a{
  display:inline-flex; align-items:center; justify-content:center; gap:10px;
  min-height:var(--es-tap); padding:16px 38px;
  background:var(--es-deep); color:#fff; text-decoration:none;
  border-radius:var(--es-r-pill);
  font-size:var(--es-fs-lg); font-weight:800;
  box-shadow:0 6px 0 var(--es-deep-2), 0 18px 32px -20px var(--es-deep);
  transition:transform .16s ease, box-shadow .16s ease;
}
.es-next a:hover{ transform:translateY(-2px); box-shadow:0 8px 0 var(--es-deep-2), 0 22px 38px -20px var(--es-deep); }
.es-next a:active{ transform:translateY(4px); box-shadow:0 2px 0 var(--es-deep-2); }

/* ── 8. 버튼 ───────────────────────────────────────────────────────────────
   ⚠️ inline-flex + gap 8px 이다. 그 틈은 **그림 글자(.em)와 이름 사이**를 띄우려고 있다.
      그래서 단추 안에 '글자 + 이어지는 <span>' 을 적으면 낱말 가운데에 틈이 생긴다 —
      es.js(initBtnText)가 쪽에 적힌 단추를 훑어 그 둘을 <span class="es-btn-t"> 로 묶어 준다(5판).
      차시가 스크립트로 단추를 새로 만들 때는 글자를 span 하나에 담는다. */
.es-btn{
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  min-width:var(--es-tap); min-height:var(--es-tap);
  padding:10px 22px;
  background:var(--es-surface); color:var(--es-ink);
  border:3px solid var(--es-line-2);
  border-radius:var(--es-r);
  font:inherit; font-size:var(--es-fs-btn); font-weight:800; line-height:1.3;
  text-align:center; cursor:pointer;
  box-shadow:0 4px 0 var(--es-line);
  transition:transform .14s ease, box-shadow .14s ease, border-color .16s ease,
             background-color .18s ease;
}
.es-btn:hover{
  border-color:var(--es-deep); background:var(--es-tint-2);
  transform:translateY(-2px);
  box-shadow:0 6px 0 var(--es-line), 0 12px 22px -14px var(--es-deep);
}
.es-btn:active{ transform:translateY(3px); box-shadow:0 1px 0 var(--es-line); }
.es-btn[disabled], .es-btn[aria-disabled="true"]{
  opacity:.45; cursor:default; box-shadow:none; transform:none;
}
.es-btn[disabled]:hover{ transform:none; background:var(--es-surface); }
.es-btn.is-primary{
  background:var(--es-deep); color:#fff; border-color:var(--es-deep);
  box-shadow:0 4px 0 var(--es-deep-2);
}
.es-btn.is-primary:hover{ background:var(--es-deep); box-shadow:0 6px 0 var(--es-deep-2), 0 14px 26px -14px var(--es-deep); }
.es-btn.is-primary:active{ box-shadow:0 1px 0 var(--es-deep-2); }
.es-btn.is-quiet{ background:var(--es-soft); box-shadow:none; border-width:2px; }
.es-btn.is-quiet:active{ transform:none; }
/* 곁들이 버튼(빼기·되돌리기·다시 하기)만 48px. 활동 버튼은 위의 56px 를 그대로 쓴다. */
.es-btn.is-small{ min-height:48px; padding:6px 14px; font-size:var(--es-fs-sm); box-shadow:none; }
.es-btn.is-icon{ padding:0; width:var(--es-tap); height:var(--es-tap); font-size:24px; }

/* 버튼 줄 — 사이는 항상 12px 이상 */
.es-btns{ display:flex; flex-wrap:wrap; gap:var(--es-gap); margin:var(--es-sp-3) 0; }

/* 눌린 것 · 맞은 것 · 틀린 것 — 색 + 모양 + 글자를 함께 쓴다 */
.es-btn.is-picked{ border-color:var(--es-accent); background:var(--es-accent-soft); }
.es-btn.is-picked::before{ content:"👉"; }
.es-good{
  border-color:var(--es-ok) !important; background:var(--es-ok-soft) !important;
  color:var(--es-ok) !important;
}
.es-good::before{ content:"⭕"; }
.es-miss{
  border-color:var(--es-no) !important; background:var(--es-no-soft) !important;
  color:var(--es-no) !important;
}
.es-miss::before{ content:"✖"; }

/* 안내 줄 */
.es-note{
  font-size:var(--es-fs-sm); font-weight:700; color:var(--es-ink-2);
  margin:var(--es-sp-2) 0 0; max-width:none;
  transition:color .2s ease;
}
.es-note.is-ok{ color:var(--es-ok); }
.es-note.is-no{ color:var(--es-no); }
.es-count{
  display:inline-flex; align-items:center; gap:6px;
  font-size:var(--es-fs-sm); font-weight:800;
  color:var(--es-deep); background:var(--es-tint);
  border:2px solid var(--es-edge); border-radius:var(--es-r-pill);
  padding:5px 16px;
}

/* ── 9. 저장 칸 (.es-summary) ────────────────────────────────────────────── */
/* 위젯 결과가 사람이 읽는 글로 적히는 칸. 숨기지 않는다 — 이 칸이 저장의 정본이다. */
.es-summary-wrap{
  margin:var(--es-sp-3) 0 0;
  background:var(--es-surface);
  border:2px dashed var(--es-line-2);
  border-radius:var(--es-r);
  padding:var(--es-sp-2) var(--es-sp-3) var(--es-sp-3);
  max-width:var(--es-mid);
}
.es-summary-label{
  display:block; font-size:var(--es-fs-sm); font-weight:800; color:var(--es-ink-2);
  margin:0 0 var(--es-sp-1);
}
.es-summary-label::before{ content:"💾 "; }
textarea.es-summary, .es-summary{
  display:block; width:100%;
  font:inherit; font-size:var(--es-fs-sm); line-height:1.7; color:var(--es-ink-abs);
  background:var(--es-soft); border:2px solid var(--es-line);
  border-radius:var(--es-r-sm); padding:10px 12px;
  resize:vertical; min-height:76px;
}
textarea.es-summary:focus{ border-color:var(--es-deep); background:#fff; }

/* 자유롭게 쓰는 칸 */
.es-write{
  display:block; width:100%; max-width:var(--es-measure);
  font:inherit; font-size:var(--es-fs); line-height:1.8; color:var(--es-ink-abs);
  background:var(--es-surface); border:3px solid var(--es-line-2);
  border-radius:var(--es-r); padding:12px 14px;
  resize:vertical; min-height:96px;
  transition:border-color .18s ease, box-shadow .18s ease;
}
.es-write:focus{ border-color:var(--es-deep); box-shadow:0 0 0 5px var(--es-tint); }
.es-label{
  display:block; font-size:var(--es-fs-sm); font-weight:800;
  margin:var(--es-sp-2) 0 var(--es-sp-1);
}
input.es-input{
  font:inherit; font-size:var(--es-fs-sm); color:var(--es-ink-abs);
  min-height:48px; padding:6px 12px;
  background:var(--es-surface); border:2px solid var(--es-line-2);
  border-radius:var(--es-r-sm);
  transition:border-color .18s ease, box-shadow .18s ease;
}
input.es-input:focus{ border-color:var(--es-deep); box-shadow:0 0 0 4px var(--es-tint); }

/* ── 10. 읽어주기 ────────────────────────────────────────────────────────── */
.es-read-row{
  position:relative;
  display:flex; gap:var(--es-gap); align-items:flex-start;
  margin:0 0 var(--es-sp-3);
  max-width:calc(var(--es-measure) + var(--es-tap) + var(--es-gap));
}
.es-read-row > *{ margin-bottom:0; }
.es-read{
  flex:0 0 auto;
  width:var(--es-tap); height:var(--es-tap);
  display:inline-flex; align-items:center; justify-content:center;
  background:var(--es-surface); border:3px solid var(--es-edge);
  border-radius:50%; font-size:24px; line-height:1; cursor:pointer;
  color:var(--es-deep);
  transition:transform .16s ease, background-color .2s ease, box-shadow .2s ease;
}
.es-read:hover{ background:var(--es-tint); transform:scale(1.07); }
.es-read[aria-pressed="true"]{
  background:var(--es-deep); border-color:var(--es-deep); color:#fff;
}
@media (prefers-reduced-motion: no-preference){
  .es-read[aria-pressed="true"]{ animation:es-hint 1.6s ease-out infinite; }
}
.es-reading{
  background:var(--es-accent-soft);
  box-shadow:0 0 0 8px var(--es-accent-soft);
  border-radius:6px;
}
/* 어디까지 읽었는지 — 문단 아래 얇은 띠. es.js 가 onboundary 로 채운다 */
.es-read-bar{
  position:absolute; left:calc(var(--es-tap) + var(--es-gap)); right:0; bottom:-8px;
  height:5px; background:var(--es-soft); border-radius:var(--es-r-pill);
  overflow:hidden;
}
.es-read-bar > i{
  display:block; height:100%; width:0;
  background:var(--es-accent-line);
  transition:width .18s linear;
}

/* ── 11. 분류하기 (esSort) ───────────────────────────────────────────────── */
.es-sort{ max-width:none; }
.es-sort-pool{
  display:flex; flex-wrap:wrap; gap:var(--es-gap);
  padding:var(--es-sp-3); margin:0 0 var(--es-sp-3);
  background:var(--es-surface); border:3px dashed var(--es-line-2);
  border-radius:var(--es-r-lg); min-height:88px;
  align-content:flex-start;
}
.es-sort-card{
  min-height:var(--es-tap); padding:10px 20px;
  background:var(--es-surface); border:3px solid var(--es-line-2);
  border-radius:var(--es-r); box-shadow:0 4px 0 var(--es-line);
  font:inherit; font-size:var(--es-fs-btn); font-weight:800; cursor:pointer;
  transition:transform .16s ease, box-shadow .16s ease, border-color .16s ease,
             background-color .18s ease;
}
.es-sort-card:hover{
  transform:translateY(-3px); border-color:var(--es-deep);
  box-shadow:0 7px 0 var(--es-line), 0 14px 24px -16px var(--es-deep);
}
.es-sort-card:active{ transform:translateY(3px); box-shadow:0 1px 0 var(--es-line); }
.es-sort-card.is-picked{
  border-color:var(--es-accent); background:var(--es-accent-soft);
  box-shadow:0 4px 0 var(--es-accent-line);
}
.es-sort-ask{
  background:var(--es-accent-soft); border:3px solid var(--es-accent-line);
  border-radius:var(--es-r-lg); padding:var(--es-sp-3); margin:0 0 var(--es-sp-3);
  animation:es-pop-in .3s cubic-bezier(.18,.89,.32,1.28) 1;
}
.es-sort-ask[hidden]{ display:none; }
/* (7판 · 2026-09-22) 상자가 누른 카드의 줄 **바로 아래**(풀 안)에 끼면 한 줄을 다 쓴다 — es.js placeAsk().
   풀의 gap 이 위아래 틈을 맡으므로 자기 여백은 없앤다. 마지막 줄의 카드면 옛 자리(풀 아래)라 이 규칙이 안 걸린다. */
.es-sort-pool > .es-sort-ask{ flex:1 1 100%; min-width:0; margin:0; }
.es-sort-ask-q{
  font-size:clamp(21px,2vw,24px); font-weight:800; margin:0 0 var(--es-sp-2);
  max-width:none; color:var(--es-accent);
}
/* 칸이 넷일 때 셋 + 혼자 남은 넷째가 가로로 길게 눕지 않도록 격자로 짠다.
   auto-fit 은 빈 트랙을 접으므로 칸이 둘뿐이면 둘이 폭을 반씩 나눠 가진다. */
.es-sort-bins{
  display:grid; gap:var(--es-gap);
  grid-template-columns:repeat(auto-fit, minmax(200px, 1fr));
}
.es-sort-bin{
  min-width:0;
  background:var(--es-tint-2); border:3px solid var(--es-edge);
  border-radius:var(--es-r-lg); padding:var(--es-sp-3);
  transition:background-color .2s ease, border-color .2s ease, transform .2s ease;
}
.es-sort-bin.is-over{
  border-color:var(--es-accent); background:var(--es-accent-soft);
  transform:translateY(-3px);
}
.es-sort-bin-h{
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  font-size:var(--es-fs-sm); font-weight:800; color:var(--es-deep);
  margin-bottom:var(--es-sp-2); padding-bottom:8px;
  border-bottom:3px solid var(--es-edge);
}
.es-sort-slot{ display:flex; flex-direction:column; gap:10px; min-height:56px; }
.es-sort-chip{
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  background:var(--es-surface); border:2px solid var(--es-edge);
  border-left:8px solid var(--es-vivid);
  border-radius:var(--es-r-sm); padding:10px 8px 10px 12px;
  font-size:var(--es-fs-sm); font-weight:700;
  box-shadow:0 6px 14px -10px var(--es-deep);
}

/* ── 12. 순서 배열 (esOrder) ─────────────────────────────────────────────── */
.es-order-list{ list-style:none; margin:0 0 var(--es-sp-3); padding:0; max-width:var(--es-mid); }
.es-order-row{
  display:flex; align-items:center; gap:var(--es-gap);
  background:var(--es-surface); border:3px solid var(--es-line-2);
  border-radius:var(--es-r); padding:10px 12px; margin:0 0 var(--es-gap);
  box-shadow:0 6px 16px -14px var(--es-deep);
  will-change:transform;
}
.es-order-no{
  flex:0 0 auto; width:44px; height:44px; border-radius:14px;
  background:var(--es-deep); color:#fff; font-weight:800; font-size:20px;
  display:flex; align-items:center; justify-content:center;
}
.es-order-txt{ flex:1 1 auto; font-size:var(--es-fs-sm); font-weight:700; }
.es-order-btns{ flex:0 0 auto; display:flex; gap:8px; }

/* ── 13. 퀴즈 (esQuiz) ───────────────────────────────────────────────────── */
.es-quiz{ margin:var(--es-sp-3) 0 var(--es-sp-4); max-width:var(--es-mid); }
/* 활동판 안에서는 판 폭을 그대로 쓴다 — 780px 로 묶으면 1100 캔버스에서 오른쪽 320px 가 빈다. */
.es-do .es-quiz{ max-width:none; }
/* 문항이 둘 이상이면 나란히. 차시마다 같은 우회를 반복하지 않게 공용에 둔다. */
.es-quiz.is-cols{ max-width:none; display:grid; gap:var(--es-sp-3);
  grid-template-columns:repeat(auto-fit, minmax(320px, 1fr)); align-items:start; }
/* es.js 가 나중에 붙이는 채점 단추 줄·알림 줄은 문항 칸이 아니다 — 한 줄을 다 쓴다(2026-09-16).
   옛본은 둘이 격자 칸이 되어 마지막 문항 옆에 붙었다(3-2 04/07 · 4-1 05/08 · 06/07 · 07/07 이 각자 막았다). */
.es-quiz.is-cols > .es-btns, .es-quiz.is-cols > .es-quiz-note{ grid-column:1 / -1; }
.es-q{
  position:relative; overflow:hidden;
  background:var(--es-surface); border:3px solid var(--es-line);
  border-radius:var(--es-r-lg); padding:var(--es-sp-4) var(--es-sp-3) var(--es-sp-3);
  margin:0 0 var(--es-sp-3);
  box-shadow:var(--es-shadow);
  transition:border-color .2s ease, box-shadow .2s ease;
}
.es-q::before{
  content:""; position:absolute; left:0; right:0; top:0; height:6px;
  background:var(--es-vivid);
}
.es-q.is-done{ border-color:var(--es-ok-edge); }
.es-q.is-done::before{ background:var(--es-ok); }
.es-q .q-text{
  font-size:clamp(21px,2vw,24px); font-weight:800; margin:0 0 var(--es-sp-3);
  max-width:var(--es-measure);
}
.es-q-no{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:38px; height:38px; border-radius:12px;
  background:var(--es-deep); border:0;
  color:#fff; font-size:var(--es-fs-sm); font-weight:800;
  margin-right:10px; vertical-align:-6px;
}
.es-q-opts{ display:flex; flex-direction:column; gap:var(--es-gap); }
.es-q .opt{
  display:flex; align-items:center; gap:12px;
  width:100%; min-height:var(--es-tap); padding:12px 18px;
  background:var(--es-surface); border:3px solid var(--es-line-2);
  border-radius:var(--es-r); box-shadow:0 4px 0 var(--es-line);
  font:inherit; font-size:var(--es-fs-btn); font-weight:700; line-height:1.5;
  text-align:left; cursor:pointer; color:var(--es-ink);
  transition:transform .14s ease, box-shadow .14s ease, border-color .16s ease,
             background-color .18s ease;
}
.es-q .opt:hover:not([disabled]){
  transform:translateY(-2px); border-color:var(--es-deep);
  box-shadow:0 6px 0 var(--es-line), 0 12px 22px -16px var(--es-deep);
}
.es-q .opt:active{ transform:translateY(3px); box-shadow:0 1px 0 var(--es-line); }
.es-q .opt::before{
  content:attr(data-mark); flex:0 0 auto;
  width:38px; height:38px; border-radius:50%;
  background:var(--es-soft); border:2px solid var(--es-line-2);
  display:inline-flex; align-items:center; justify-content:center;
  font-size:var(--es-fs-sm); font-weight:800;
}
.es-q .opt.is-picked{
  border-color:var(--es-accent); background:var(--es-accent-soft);
  box-shadow:0 4px 0 var(--es-accent-line);
}
.es-q .opt.is-picked::before{ content:"👉"; border-color:var(--es-accent); }
.es-q .opt.es-good{ box-shadow:none; }
.es-q .opt.es-good::before{ content:"⭕"; background:#fff; border-color:var(--es-ok); }
.es-q .opt.es-miss{ box-shadow:none; }
.es-q .opt.es-miss::before{ content:"✖"; background:#fff; border-color:var(--es-no); }
.es-q-why{
  margin:var(--es-sp-3) 0 0; padding:var(--es-sp-3);
  background:var(--es-tint); border-left:10px solid var(--es-deep);
  border-radius:var(--es-r-sm); font-size:var(--es-fs-sm); line-height:1.8;
  overflow:hidden;
}
.es-q-why[hidden]{ display:none; }
.es-q-why::before{ content:"💡 "; font-weight:800; }
@media (prefers-reduced-motion: no-preference){
  .es-q-why{ animation:es-slide-down .38s cubic-bezier(.22,.61,.36,1) 1; }
}
.es-quiz-note{ margin:var(--es-sp-2) 0 0; font-size:var(--es-fs-lg); font-weight:800; }
.es-quiz-note.is-ok{ color:var(--es-ok); }
.es-quiz-note.is-no{ color:var(--es-no); }

/* ── 14. 형광펜 (esHighlight) ────────────────────────────────────────────── */
.es-hl-text{
  background:var(--es-surface); border:3px solid var(--es-line);
  border-radius:var(--es-r-lg); padding:var(--es-sp-4) var(--es-sp-3);
  font-size:var(--es-fs); line-height:2.3; margin:0 0 var(--es-sp-3);
  max-width:var(--es-mid);
  box-shadow:var(--es-shadow);
}
.es-hl-w{
  display:inline; font:inherit; color:inherit;
  background-color:transparent;
  /* 형광펜은 background-image 로 칠한다 — 왼쪽에서 오른쪽으로 0.32초에 번진다 */
  background-image:linear-gradient(var(--es-accent-glow), var(--es-accent-glow));
  background-repeat:no-repeat; background-position:0 100%; background-size:0% 72%;
  border:0; border-bottom:3px dotted var(--es-line-2);
  padding:2px 1px; margin:0; cursor:pointer; border-radius:4px;
  transition:background-size .32s cubic-bezier(.22,.61,.36,1), background-color .18s ease;
}
.es-hl-w:hover{ background-color:var(--es-soft); }
.es-hl-w.is-found{
  background-size:100% 72%;
  border-bottom:4px solid var(--es-accent);
  color:var(--es-ink); font-weight:800;
}
.es-hl-w.is-found::after{ content:"✔"; font-size:.8em; vertical-align:super; }

/* ── 15. 겹쳐 보기 (esWipe) ──────────────────────────────────────────────── */
.es-wipe{ max-width:var(--es-content); }
.es-wipe-box{
  position:relative; width:100%; overflow:hidden;
  border:4px solid var(--es-deep); border-radius:var(--es-r-lg);
  background:var(--es-soft); touch-action:none; user-select:none;
  box-shadow:var(--es-shadow-up);
}
.es-wipe-box img{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; border:0; border-radius:0; box-shadow:none;
}
.es-wipe-box.is-contain img{ object-fit:contain; }
.es-wipe-handle{
  position:absolute; top:0; bottom:0; width:var(--es-tap);
  margin-left:calc(var(--es-tap) / -2);
  display:flex; align-items:center; justify-content:center;
  background:none; border:0; cursor:ew-resize; padding:0; z-index:2;
  font:inherit;   /* 브라우저 기본 13.3px 이 남지 않게 — 12px 이하 0개가 규격이다 */
}
.es-wipe-handle::before{
  content:""; position:absolute; top:0; bottom:0; left:calc(50% - 3px);
  width:6px; background:#fff; box-shadow:0 0 0 2px rgba(20,32,46,.45);
}
.es-wipe-grip{
  position:relative; width:var(--es-tap); height:var(--es-tap);
  border-radius:50%; background:#fff; box-shadow:0 0 0 4px var(--es-accent);
  display:flex; align-items:center; justify-content:center;
  font-size:24px; color:var(--es-accent); font-weight:800;
  transition:transform .16s ease;
}
.es-wipe-handle:hover .es-wipe-grip{ transform:scale(1.1); }
.es-wipe-box.is-playing .es-wipe-grip{ box-shadow:0 0 0 4px var(--es-vivid); }
.es-wipe-tag{
  position:absolute; top:12px; z-index:3;
  background:rgba(255,255,255,.95); color:var(--es-ink);
  border:2px solid var(--es-line-2); border-radius:var(--es-r-pill);
  padding:5px 16px; font-size:var(--es-fs-src); font-weight:800;
}
.es-wipe-tag.is-left{ left:12px; }
.es-wipe-tag.is-right{ right:12px; }

/* ── 16. 찾기 (esFind) ───────────────────────────────────────────────────── */
.es-find{ max-width:var(--es-content); }
.es-find-box{
  position:relative; display:block; width:100%;
  border:4px solid var(--es-deep); border-radius:var(--es-r-lg);
  overflow:hidden; cursor:crosshair; background:var(--es-soft);
  box-shadow:var(--es-shadow-up);
}
.es-find-box img{ width:100%; border:0; border-radius:0; box-shadow:none; }
.es-find-spot{
  position:absolute; width:var(--es-tap); height:var(--es-tap);
  margin:calc(var(--es-tap) / -2) 0 0 calc(var(--es-tap) / -2);
  border-radius:50%; background:none; border:0; padding:0;
  pointer-events:none; color:transparent; font:inherit;
}
.es-find-spot.is-found{
  border:5px solid var(--es-ok);
  background:rgba(255,255,255,.30); color:#fff;
  animation:es-pop .42s cubic-bezier(.18,.89,.32,1.28) 1;
}
/* 두 번 빗맞히면 가장 가까운 못 찾은 자리를 알려 준다(es.js · 2026-09-16) — 점선 고리가 세 번 숨 쉬고 멈춘다.
   글자(자리 이름)는 여전히 숨긴다. 누르는 것은 여전히 아이 몫이다(찾기 판정은 사진 좌표). */
.es-find-spot.is-hint:not(.is-found){
  border:5px dashed var(--es-accent-glow);
  box-shadow:0 0 0 3px rgba(20,32,46,.55), inset 0 0 0 3px rgba(20,32,46,.55);
  animation:es-find-hint 1.2s ease-in-out 3;
}
@keyframes es-find-hint{ 0%,100%{ transform:scale(1); } 50%{ transform:scale(1.25); } }
.es-find-spot.is-found::after{
  content:attr(data-no);
  position:absolute; right:-12px; top:-12px;
  width:34px; height:34px; border-radius:50%;
  background:var(--es-ok); color:#fff;
  font-size:var(--es-fs-src); font-weight:800;
  display:flex; align-items:center; justify-content:center;
  box-shadow:0 4px 10px -4px rgba(0,0,0,.6);
}
/* 맞힌 자리의 파문 · 빗맞힌 자리의 흔적 — 둘 다 스스로 사라진다 */
.es-find-ripple{
  position:absolute; width:120px; height:120px; border-radius:50%;
  border:5px solid var(--es-ok); pointer-events:none;
  animation:es-ripple .7s cubic-bezier(.22,.61,.36,1) both;
}
.es-find-miss{
  position:absolute; width:44px; height:44px; border-radius:50%;
  border:4px dashed var(--es-no); pointer-events:none;
  animation:es-miss-fade 1.2s ease both;
}
.es-find-list{ list-style:none; margin:var(--es-sp-2) 0 0; padding:0; max-width:var(--es-mid); }
.es-find-list li{
  font-size:var(--es-fs-sm); font-weight:700; color:var(--es-ok);
  animation:es-pop-in .34s cubic-bezier(.18,.89,.32,1.28) 1;
}
.es-find-list li::before{ content:"⭕ "; }

/* ── 17. 확대해 보기 (esZoom) ────────────────────────────────────────────── */
.es-zoom{ max-width:var(--es-content); }
.es-zoom-box{
  position:relative; width:100%; overflow:hidden;
  border:4px solid var(--es-deep); border-radius:var(--es-r-lg);
  background:var(--es-soft); touch-action:none;
  box-shadow:var(--es-shadow-up);
}
.es-zoom-box img{
  width:100%; border:0; border-radius:0; box-shadow:none;
  transform-origin:0 0; will-change:transform;
  transition:transform .26s cubic-bezier(.22,.61,.36,1);
}
.es-zoom-box.is-grabbing img{ transition:none; }   /* 끌 때는 손끝을 그대로 따라온다 */
.es-zoom-box.is-zoomed{ cursor:grab; }
.es-zoom-box.is-grabbing{ cursor:grabbing; }

/* ── 18. 놓기 판 (esMap · esMental 공용) ─────────────────────────────────── */
.es-map, .es-mental{ max-width:var(--es-content); }
.es-place-pal{ display:flex; flex-wrap:wrap; gap:var(--es-gap); margin:0 0 var(--es-sp-3); }
.es-place-pal .es-btn{ flex-direction:column; gap:2px; padding:8px 14px; }
.es-place-pal .es-btn .em{ font-size:28px; line-height:1.1; }
.es-place-pal .es-btn .tx{ font-size:var(--es-fs-src); font-weight:800; }
.es-place-pal .es-btn[aria-pressed="true"]{
  border-color:var(--es-accent); background:var(--es-accent-soft);
  box-shadow:0 4px 0 var(--es-accent-line);
}
.es-place-board{
  position:relative; width:100%; min-height:280px;
  border:4px solid var(--es-deep); border-radius:var(--es-r-lg);
  background:var(--es-surface); overflow:hidden; touch-action:manipulation;
  cursor:pointer;
  box-shadow:var(--es-shadow-up);
}
/* 그림 없는 격자판(심상지도)은 사진이 높이를 만들어 주지 않는다. 격자일 때만 키운다. */
.es-place-board.is-grid{
  min-height:400px;
  background-color:var(--es-tint-2);
  background-image:
    linear-gradient(to right, var(--es-glow) 1px, transparent 1px),
    linear-gradient(to bottom, var(--es-glow) 1px, transparent 1px);
  background-size:44px 44px;
}
.es-place-board img{ width:100%; border:0; border-radius:0; box-shadow:none; }
.es-place-pin{
  position:absolute; transform:translate(-50%,-50%);
  display:flex; flex-direction:column; align-items:center; gap:2px;
  pointer-events:none;
}
.es-place-pin.es-drop{ animation:es-drop .48s cubic-bezier(.18,.89,.32,1.28) 1; }
.es-place-pin .em{ font-size:38px; line-height:1; filter:drop-shadow(0 3px 4px rgba(0,0,0,.35)); }
.es-place-pin .tx{
  background:rgba(255,255,255,.96); border:2px solid var(--es-line-2);
  border-radius:var(--es-r-pill); padding:2px 10px;
  font-size:var(--es-fs-src); font-weight:800; white-space:nowrap;
}
.es-place-cross{
  position:absolute; width:44px; height:44px; margin:-22px 0 0 -22px;
  border:4px dashed var(--es-accent); border-radius:50%;
  pointer-events:none;
}
.es-place-cross[hidden]{ display:none; }
/* 무엇을 몇 개 놓았나 — 숫자가 스스로 올라간다 */
.es-place-tally{
  display:flex; flex-wrap:wrap; gap:10px;
  list-style:none; margin:var(--es-sp-3) 0 0; padding:0; max-width:none;
}
.es-place-tally li{ margin:0; }
.es-place-tally .es-count{ background:var(--es-surface); }
.es-place-list{ list-style:none; margin:var(--es-sp-3) 0 0; padding:0; max-width:var(--es-mid); }
.es-place-row{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  padding:10px; margin:0 0 10px;
  background:var(--es-surface); border:2px solid var(--es-line);
  border-left:8px solid var(--es-edge); border-radius:var(--es-r-sm);
}
.es-place-row .em{ font-size:28px; }
.es-place-row .es-input{ flex:1 1 180px; min-width:140px; }

/* ── 19. 연표 (esTimeline) ───────────────────────────────────────────────── */
.es-timeline{ max-width:var(--es-content); }
.es-tl-rows{ display:flex; flex-direction:column; gap:var(--es-gap); margin:0 0 var(--es-sp-3); max-width:var(--es-mid); }
.es-tl-row{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  background:var(--es-surface); border:2px solid var(--es-line);
  border-radius:var(--es-r-sm); padding:10px 12px;
}
.es-tl-row .es-order-no{ width:38px; height:38px; font-size:18px; border-radius:12px; }
.es-tl-row .when{ flex:0 1 190px; min-width:140px; }
.es-tl-row .what{ flex:1 1 260px; min-width:190px; }
.es-tl-band{ position:relative; margin:var(--es-sp-4) 0 0; padding:var(--es-sp-4) 0 8px; }
.es-tl-track{
  display:flex; align-items:stretch; gap:0; min-width:560px;
  border-top:10px solid var(--es-vivid); border-radius:5px;
}
.es-tl-node{
  flex:1 1 0; min-width:120px; position:relative;
  padding:28px 8px 0; text-align:center;
}
.es-tl-node::before{
  content:""; position:absolute; top:-17px; left:calc(50% - 12px);
  width:24px; height:24px; border-radius:50%;
  background:var(--es-surface); border:6px solid var(--es-deep);
}
.es-tl-node.is-empty::before{ border-color:var(--es-line-2); }
.es-tl-node.es-pop-in::before{ animation:es-pop .42s cubic-bezier(.18,.89,.32,1.28) 1; }
.es-tl-when{ font-size:var(--es-fs-sm); font-weight:800; color:var(--es-deep); }
.es-tl-what{ font-size:var(--es-fs-src); color:var(--es-ink); line-height:1.6; }
.es-tl-node.is-empty .es-tl-when,
.es-tl-node.is-empty .es-tl-what{ color:var(--es-ink-2); opacity:.6; }

/* ── 20. 짝 맞추기 (esMatch) ─────────────────────────────────────────────── */
.es-match{ max-width:var(--es-content); }
.es-match-cols{ display:flex; gap:var(--es-sp-3); flex-wrap:wrap; }
.es-match-col{ flex:1 1 300px; min-width:240px; }
.es-match-col h4{
  font-size:var(--es-fs-sm); color:var(--es-deep);
  margin:0 0 var(--es-sp-2); padding-bottom:8px;
  border-bottom:3px solid var(--es-edge);
}
.es-match-card{
  display:block; width:100%; min-height:var(--es-tap);
  padding:12px 16px; margin:0 0 var(--es-gap);
  background:var(--es-surface); border:3px solid var(--es-line-2);
  border-radius:var(--es-r); box-shadow:0 4px 0 var(--es-line);
  font:inherit; font-size:var(--es-fs-sm); font-weight:700; line-height:1.5;
  text-align:left; cursor:pointer;
  transition:transform .16s ease, box-shadow .16s ease, border-color .16s ease,
             background-color .18s ease;
}
.es-match-card:hover:not([disabled]){
  transform:translateY(-3px); border-color:var(--es-deep);
  box-shadow:0 7px 0 var(--es-line), 0 14px 24px -16px var(--es-deep);
}
.es-match-card:active{ transform:translateY(3px); box-shadow:0 1px 0 var(--es-line); }
.es-match-card.is-picked{
  border-color:var(--es-accent); background:var(--es-accent-soft);
  box-shadow:0 4px 0 var(--es-accent-line);
}
.es-match-card.is-done{
  border-color:var(--es-ok); background:var(--es-ok-soft); color:var(--es-ok);
  box-shadow:none; cursor:default;
}
.es-match-card.is-hint{ border-color:var(--es-accent); background:#fff6e3; }
/* 짝이 맞으면 두 장이 서로에게 한 걸음 다가간다 */
.es-match-card.es-snap-l{ animation:es-snap-l .42s cubic-bezier(.22,.61,.36,1) 1; }
.es-match-card.es-snap-r{ animation:es-snap-r .42s cubic-bezier(.22,.61,.36,1) 1; }
@keyframes es-snap-l{
  0%{ transform:translateX(0); } 45%{ transform:translateX(14px); } 100%{ transform:translateX(0); }
}
@keyframes es-snap-r{
  0%{ transform:translateX(0); } 45%{ transform:translateX(-14px); } 100%{ transform:translateX(0); }
}
.es-match-pairs{ list-style:none; margin:var(--es-sp-3) 0 0; padding:0; max-width:var(--es-mid); }
.es-match-pairs li{
  font-size:var(--es-fs-sm); font-weight:700; color:var(--es-ok);
  padding:8px 0; border-bottom:2px dotted var(--es-line);
  animation:es-pop-in .34s cubic-bezier(.18,.89,.32,1.28) 1;
}
.es-match-pairs li::before{ content:"🔗 "; }

/* ── 21. 인쇄 — 활동지를 A4 한 장으로 ────────────────────────────────────── */
.es-print-only{ display:none; }

@page{ size:A4; margin:14mm; }

@media print{
  :root{ --es-fs:12pt; --es-fs-sm:11pt; --es-fs-src:9.5pt; --es-fs-cap:10.5pt;
         --es-fs-credit:7pt; --es-src-ink:#555;
         --es-h1:20pt; --es-h2:16pt; --es-h3:13pt; --es-lh:1.6;
         --es-wrap:100%; --es-measure:100%; --es-mid:100%; --es-content:100%;
         --es-pad:0px; --es-sp-6:6mm; }
  body{ background:#fff; color:#000; }
  .es-top, .es-next, .es-read, .es-read-row .es-read, .es-read-bar,
  .es-btn, .es-btns, .es-dots, .es-place-pal, .es-sort-ask,
  .es-quiz-note, .es-hero-art, .es-progress, .es-burst, .es-confetti,
  .es-finale{ display:none !important; }
  .es-print-only{ display:block; }
  .es-noprint{ display:none !important; }
  .es-hero{ border:0; background:#fff; color:#000; padding:0 0 6mm; }
  .es-hero::before{ display:none; }
  .es-hero h1, .es-hero-lead, .es-hero .es-cap{ color:#000; }
  .es-hero .es-src, .es-hero .es-src a{ color:#333; }
  .es-hero-in{ display:block; }
  .es-hero-q{ margin:0 0 4mm; box-shadow:none; border:1px solid #666; }
  /* 인쇄에서는 격자를 풀어 흐름 그대로 쌓는다 */
  .es-main, .es-sec{ display:block; padding:0; max-width:100%; background:#fff !important; }
  .es-main{ padding:0; }
  .es-sec{ margin:0 0 6mm; break-inside:avoid; }
  .es-sec + .es-sec{ border-top:1px solid #999; padding-top:4mm; }
  .es-card, .es-do, .es-word, .es-wrap-up, .es-summary-wrap, .es-q{
    border:1px solid #666; box-shadow:none; break-inside:avoid;
    background:#fff !important; color:#000 !important; padding:4mm;
  }
  .es-wrap-up{ --es-ink:#000; --es-ink-2:#333; }
  .es-wrap-up h2, .es-wrap-up h3{ color:#000; }
  .es-card::before, .es-do::before, .es-q::before{ display:none; }
  textarea.es-summary, .es-write, input.es-input{
    background:#fff; border:1px solid #666; min-height:22mm; color:#000;
  }
  /* 활동지 한 장만 뽑기 — <body class="es-printing-sheet"> 를 JS 가 잠깐 붙인다 */
  .es-printing-sheet .es-main > *:not(.es-sheet){ display:none !important; }
  .es-printing-sheet .es-hero{ display:none !important; }
  .es-sheet{ break-inside:auto; }
  .es-sheet .es-sheet-line{ border-bottom:1px solid #333; height:11mm; margin:0 0 3mm; }
  a[href^="http"]::after{ content:" (" attr(href) ")"; font-size:8pt; word-break:break-all; }
}

/* ── 22. 움직임 줄이기 — 이제 이 블록이 끌 대상이 실제로 있다 ───────────── */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    animation-delay:0ms !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
  .es-sec, .es-card, .es-fig, .es-hero-q, .es-do, .es-wrap-up, .es-quiz,
  .es-stagger > *{ opacity:1 !important; transform:none !important; }
  .es-btn:hover, .es-card:hover, .es-sort-card:hover, .es-match-card:hover,
  .es-q .opt:hover, .es-todo-btn:hover, .es-next a:hover, .es-read:hover{
    transform:none !important;
  }
  .es-btn:active, .es-sort-card:active, .es-match-card:active,
  .es-q .opt:active, .es-next a:active{ transform:none !important; }
  .es-burst, .es-confetti{ display:none !important; }
  .es-hint{ animation:none !important; outline:4px solid var(--es-vivid); outline-offset:3px; }
  .es-hl-w{ transition:none !important; }
}

/* ── 23. 좁은 화면 (태블릿 세로·크롬북) ──────────────────────────────────── */
@media (max-width:900px){
  .es-hero-q{ margin-bottom:clamp(-56px,-5vw,-40px); }
}
@media (max-width:760px){
  :root{
    --es-h3:22px;
    --es-fs:19px; --es-fs-lg:21px;
    --es-sp-6:44px;
  }
  .es-sec-step{ width:48px; height:48px; font-size:22px; }
  .es-sort-bins{ grid-template-columns:1fr; }
  /* 짝 맞추기 — 좁은 화면에서도 **왼쪽·오른쪽을 나란히** (2026-09-16)
     ⚠️ 옛본은 왼쪽 여섯 장을 모두 쌓고 그 아래 오른쪽 여섯 장을 두어(flex:1 1 100%), 왼쪽을 누른 아이가 카드 여섯 장을
        스크롤해 내려가야 짝을 고를 수 있었고, 틀렸다는 말은 오른쪽 열 아래에 떴다(4-1 05/07 · 06/07 · 3-2 04/07).
        두 열이 좁아지면 카드 글이 두세 줄로 접힐 뿐 누를 곳은 한 화면에 모인다. 글자는 18px 그대로. */
  .es-match-cols{ flex-wrap:nowrap; gap:10px; }
  .es-match-col{ flex:1 1 0; min-width:0; }
  .es-match-card{ padding:10px 10px; overflow-wrap:anywhere; }
  .es-order-row{ flex-wrap:wrap; }
  .es-order-txt{ flex:1 1 100%; order:3; }
  .es-place-board.is-grid{ min-height:320px; }
  .es-finale{ font-size:var(--es-fs-sm); gap:10px; padding:12px 14px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   24. 슉 날아와 앉는다 — .es-fly-l · .es-fly-r · .es-fly-up   (3판 · 2026-09-09)
   ──────────────────────────────────────────────────────────────────────────
   "웹교과서의 특징이라면 다양한 움직임을 구현할 수 있다고 본다.
    예를 들어 그림이 슉 날라와서 위치한다던지…"  ← 사용자 지시

   7절의 es-rise 는 **위로 16px 떠오르는 것**이라 사진에는 약했다. 옆에서 날아와
   자리를 잡는 쪽이 초등에는 맞다. 셋 중 하나를 골라 쓴다.

     <figure class="es-fig es-fly-l">   왼쪽에서 날아온다
     <figure class="es-fig es-fly-r">   오른쪽에서
     <div class="es-card es-fly-up">    아래에서 솟는다

   나란히 놓인 것은 --i 로 차례를 준다(한 칸에 5% 씩 늦게 들어온다):
     <div class="es-cols">
       <div class="es-card es-fly-l" style="--i:0">…</div>
       <div class="es-card es-fly-l" style="--i:1">…</div>
       <div class="es-card es-fly-l" style="--i:2">…</div>
     </div>

   ⚠️ 지키는 것 셋
     ① **JS 0줄.** animation-timeline: view() 로만 돈다. 스크롤을 되돌리면 되감긴다.
     ② **시작 상태가 보인다**(opacity .45). 연출이 어긋나도 사진·글이 남는다.
        미지원 브라우저·prefers-reduced-motion 에서는 그냥 제자리에 정적으로 놓인다.
     ③ **가로 스크롤이 생기지 않는다.** transform 은 배치를 안 바꾸지만 스크롤 영역은
        넓힌다 — 오른쪽으로 56px 민 사진이 문서 폭을 56px 늘린다. .es-main 의
        overflow-x:clip 이 그걸 자른다(clip 은 스크롤 컨테이너를 만들지 않아
        .es-top 의 position:sticky 를 깨지 않는다).
   ────────────────────────────────────────────────────────────────────────── */
.es-main{ overflow-x:clip; }              /* ③ — hidden 이 아니라 clip 이어야 한다 */

.es-fly-l, .es-fly-r, .es-fly-up{ opacity:1; transform:none; }

@supports (animation-timeline: view()){
  @media (prefers-reduced-motion: no-preference){
    .es-fly-l, .es-fly-r, .es-fly-up{
      animation-duration:1s;              /* view() 는 진행률로 돌아 무시된다 */
      animation-timing-function:cubic-bezier(.22,.61,.36,1);
      animation-fill-mode:both;
      animation-timeline:view();
      /* 차례차례 — --i 한 칸에 5%. calc 이 안 풀리면 선언만 버려지고 기본 범위로 돈다 */
      animation-range:entry calc(0% + 5% * var(--i, 0)) entry calc(54% + 5% * var(--i, 0));
    }
    .es-fly-l  { animation-name:es-fly-l; }
    .es-fly-r  { animation-name:es-fly-r; }
    .es-fly-up { animation-name:es-fly-up; }
  }
}
/* 날아오는 거리는 변수다 — 좁은 화면에서는 짧게 잡는다(360px 실측에서 사진의
   58px 가 화면 밖으로 나갔다. 잘리지는 않지만 처음 한 순간이 답답하다). */
@keyframes es-fly-l{
  from{ opacity:.45; transform:translate3d(calc(-1 * var(--es-fly-x, 58px)), 12px, 0) rotate(-3.5deg) scale(.93); }
  to  { opacity:1;   transform:none; }
}
@keyframes es-fly-r{
  from{ opacity:.45; transform:translate3d(var(--es-fly-x, 58px), 12px, 0) rotate(3.5deg) scale(.93); }
  to  { opacity:1;   transform:none; }
}
@media (max-width:760px){ :root{ --es-fly-x:28px; } }
@keyframes es-fly-up{
  from{ opacity:.45; transform:translate3d(0, 46px, 0) scale(.95); }
  to  { opacity:1;   transform:none; }
}

/* 활동 결과가 자리에 앉는 순간은 **더 세게** 간다.
   es-land 는 카드가 칸에 떨어지는 것(11절 esSort), es-land-big 은 그 강조판이다. */
@keyframes es-land-big{
  0%  { opacity:0; transform:translate(-60px,-34px) scale(.72) rotate(-9deg); }
  48% { opacity:1; transform:translate(6px, 6px)    scale(1.10) rotate(2.5deg); }
  72% { transform:translate(-2px,-3px) scale(.97) rotate(-1deg); }
  88% { transform:translate(0,1px) scale(1.02); }
  100%{ opacity:1; transform:none; }
}
.es-land-big{ animation:es-land-big .58s cubic-bezier(.18,.89,.32,1.28) 1; }


/* ══════════════════════════════════════════════════════════════════════════
   25. 배경에 흩날리는 것 — .es-drift
   ──────────────────────────────────────────────────────────────────────────
   "배경에 꽃잎이 흩날린다"  ← 사용자 지시

     <section class="es-sec es-drift" data-kind="petal" data-count="16">

   종류: petal(꽃잎) · leaf(낙엽) · snow(눈) · dust(먼지) · star(별)
   개수: data-count (기본 16 · 4~28 로 물린다)

   ⚠️ **내용과 이어질 때만 쓴다.** Mayer 의 seductive details — 학습과 무관한
      장식은 화면을 예쁘게 하는 대신 **학습을 해친다.** 봄 마을을 다루는 절에
      꽃잎, 옛 물건을 다루는 절에 먼지처럼 **그 절이 말하는 것과 같을 때만.**
      '심심해서' 까는 순간 그건 방해물이다. 한 차시에 한 번을 넘기지 않는다.

   ⚠️ WCAG 2.2.2 — 5초 넘게 스스로 도는 것에는 멈출 수단이 있어야 한다.
      · 기본은 **한 번만 흩날리고 끝난다.** 화면에 들어올 때 시작해 4.8초에 멈춘다
        (입자 지연 최대 1.2s + 낙하 3.6s = 4.8s < 5s). 정지 단추가 필요 없는 값이다.
      · 계속 돌리려면 data-loop 를 준다. 그때는 es.js 가 **'❄ 멈춤' 단추를
        자동으로 붙인다.** 단추 없이 도는 길은 만들어 두지 않았다.
      · prefers-reduced-motion 에서는 **입자를 아예 만들지 않는다**(es.js 가 먼저 나간다).
   ────────────────────────────────────────────────────────────────────────── */
.es-drift{ position:relative; }
.es-drift > .es-drift-layer{
  position:absolute; inset:0;
  grid-column:full; grid-row:1 / -1;      /* .es-sec 격자에서도 화면 끝까지 */
  overflow:hidden; pointer-events:none;
  /* ⚠️ 0.25 는 밝은 띠 위에서 **한 알도 안 보인다**(쇼츠 담당이 재 보고 아예 걷어냈다).
     장식은 은은해야 하지만 안 보이면 넣은 뜻이 없다. 0.38 로 올리고, 흰 입자는
     밝은 바탕에서 원리적으로 안 보이므로 눈(snow)만 테두리를 준다. */
  z-index:0; opacity:var(--es-drift-op, .38);
}
/* 글이 늘 입자 위에 온다.
   ⚠️ 멈춤 단추는 빼야 한다 — 안 빼면 (0,2,0) 인 이 규칙이 .es-drift-stop 의
      position:absolute 를 이겨서 단추가 절 맨 아래로 흘러내린다. */
.es-drift > :not(.es-drift-layer):not(.es-drift-stop){ position:relative; z-index:1; }

.es-drift-layer > i{
  position:absolute; top:0; left:0;
  width:var(--w,14px); height:var(--h,14px);
  background:var(--es-drift-c, var(--es-glow));
  animation:es-drift-fall var(--dur,3.6s) linear var(--del,0s) 1 both;
  will-change:transform;
}
.es-drift-layer.is-loop > i{ animation-iteration-count:infinite; }
.es-drift-layer.is-paused > i{ animation-play-state:paused; }

.es-drift-layer.is-petal > i{ border-radius:64% 6% 64% 6%; --es-drift-c:var(--es-glow); }
.es-drift-layer.is-leaf  > i{ border-radius:6% 68% 6% 68%; --es-drift-c:var(--es-vivid); }
.es-drift-layer.is-snow  > i{ border-radius:50%;           --es-drift-c:#ffffff;
  box-shadow:0 0 0 1.5px var(--es-line-2); }   /* 밝은 바탕에서도 보이게 테두리 */
.es-drift-layer.is-dust  > i{ border-radius:50%;           --es-drift-c:var(--es-line-2); }
.es-drift-layer.is-star  > i{
  --es-drift-c:var(--es-accent-glow); border-radius:0;
  clip-path:polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
}

@keyframes es-drift-fall{
  0%  { opacity:0; transform:translate3d(0, -40px, 0) rotate(0deg); }
  10% { opacity:1; }
  86% { opacity:1; }
  100%{ opacity:0; transform:translate3d(var(--dx,40px), var(--fall,520px), 0) rotate(var(--rot,260deg)); }
}

/* 떠다니기 멈춤 단추 — data-loop 일 때만 es.js 가 붙인다 */
.es-drift-stop{
  position:absolute; right:var(--es-pad); top:12px; z-index:2;
  min-height:44px; padding:6px 14px;
  background:var(--es-surface); color:var(--es-ink);
  border:2px solid var(--es-line-2); border-radius:var(--es-r-pill);
  font:inherit; font-size:var(--es-fs-sm); font-weight:800; cursor:pointer;
  box-shadow:0 6px 16px -12px var(--es-deep);
}
.es-drift-stop:hover{ border-color:var(--es-deep); background:var(--es-tint-2); }
/* 좁은 화면에서는 제목 위로 겹칠 수 있다 — 그냥 흐름에 둔다 */
@media (max-width:760px){
  .es-drift-stop{ position:static; display:block; margin:var(--es-sp-3) 0 0; }
}


/* ══════════════════════════════════════════════════════════════════════════
   26. 시뮬레이터 공용 부품 — 14차시가 각자 밑바닥부터 짜지 않게
   ──────────────────────────────────────────────────────────────────────────
   "가장 임펙트가 있는 것은 매우 정교하게 다양한 시뮬레이터들이 있는 것이다"

   껍데기 .es-sim 이 부품을 담는다. 조작 요소는 **한 번에 5개 이하**로 둔다
   (중·고 sim-panel 은 조작줄이 두 줄에 8개다 — 초등은 안 된다).
   ────────────────────────────────────────────────────────────────────────── */
.es-sim{
  position:relative;
  background:var(--es-surface);
  border:3px solid var(--es-edge);
  border-radius:var(--es-r-lg);
  padding:var(--es-sp-4) clamp(16px,2.4vw,26px) var(--es-sp-3);
  margin:var(--es-sp-4) 0; max-width:none;
  box-shadow:0 18px 38px -26px var(--es-deep);
}
.es-sim::before{
  content:""; position:absolute; left:0; right:0; top:0; height:8px;
  background:var(--es-vivid); border-radius:var(--es-r-lg) var(--es-r-lg) 0 0;
}
.es-sim-head{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  font-size:clamp(21px,2vw,25px); font-weight:800; color:var(--es-deep);
  margin:0 0 var(--es-sp-2);
}
.es-sim-head::before{ content:"🎛"; font-size:28px; line-height:1; }
.es-sim-how{ font-size:var(--es-fs-sm); font-weight:700; color:var(--es-ink-2);
  margin:0 0 var(--es-sp-3); max-width:var(--es-mid); }
.es-sim > :last-child{ margin-bottom:0; }

/* ── 무대 (esStage) — <canvas> 또는 <svg>. 그리는 좌표는 늘 1100 기준이다 ── */
.es-stage{
  position:relative; width:100%; max-width:var(--es-content);
  margin:0 0 var(--es-sp-3);
  background:var(--es-tint-2);
  border:3px solid var(--es-line-2); border-radius:var(--es-r-lg);
  overflow:hidden;
  box-shadow:inset 0 2px 10px -6px rgba(20,32,46,.5);
}
.es-stage canvas, .es-stage svg{
  display:block; width:100%; height:100%;
  border:0; border-radius:0; box-shadow:none; background:none;
}
.es-stage-cap{                         /* 무대 아래 한 줄 — 3학년은 그림 변화를 스스로 말로 못 바꾼다 */
  position:absolute; left:0; right:0; bottom:0; z-index:2;
  margin:0; padding:8px 14px; max-width:none;
  background:rgba(255,255,255,.94);
  border-top:2px solid var(--es-line);
  font-size:var(--es-fs-sm); font-weight:800; color:var(--es-ink);
}

/* ── (4판) 무대 위 지도 — ES.svg · st.tap ─────────────────────────────────
   차시는 무대 안에 <img> 를 먼저 적는다. ES.svg 가 성공하면 그 자리가 .es-map-svg 가 된다.
   ⚠️ 무대 SVG·캔버스(es.js 가 뒤에 붙인 것)는 지도 **위에 투명하게 겹친다.** 겹치지 않으면
      지도 아래로 밀려나 overflow:hidden 에 잘려 화살표가 사라진다.
   ⚠️ 겹친 층은 누름을 받지 않는다(pointer-events:none) — 누름은 아래 지도의 [data-hit] 로 간다.
      겹친 층에 그린 것도 [data-hit] 이면 다시 받는다. */
.es-stage > img,
.es-stage > .es-map-svg{
  display:block; width:100%; height:100%; object-fit:contain;
  border:0; border-radius:0; box-shadow:none; background:none; margin:0; max-width:none;
}
.es-stage > img ~ svg:not(.es-map-svg),
.es-stage > img ~ canvas,
.es-stage > .es-map-svg ~ svg,
.es-stage > .es-map-svg ~ canvas{
  position:absolute; inset:0; pointer-events:none;
}
/* ⚠️ **SVG 가 스스로 적은 pointer-events 는 덮지 않는다** — :not([pointer-events]) (2026-09-15, 4-1 05/02 기준 차시가 찾았다).
   이 줄의 할 일은 **겹친 무대 SVG**(pointer-events:none 을 물려받는다)에 그린 [data-hit] 이 누름을 다시 받게 하는 것뿐이다.
   옛 줄 `.es-stage > svg [data-hit]{pointer-events:auto}` 는 권 연습 지도 누를 곳의 pointer-events="all"(건물·산·밭·정류장 —
   채움도 선도 없는 보이지 않는 도형)과 "stroke"(강·철도)까지 auto(= visiblePainted)로 덮었다. 그러면 칠한 것이 없는
   도형은 마우스·손가락이 **통째로 지나간다** — 실제 크롬에서 병원·도서관 한가운데를 눌러도 el=null 이었다.
   키보드 Enter 는 초점으로 가서 멀쩡해 보여 놓치기 쉽다. :where() 로 감싸 명시도는 옛 줄과 같다(0,2,1) —
   차시가 덮던 규칙의 승패가 바뀌지 않는다. */
.es-stage > svg [data-hit]:where(:not([pointer-events])){ pointer-events:auto; }
.es-stage.is-tappable{ cursor:pointer; touch-action:manipulation; }
.es-stage [data-hit]{ cursor:pointer; }
/* 이름표도 누른다 (리뷰 c) — tap 을 건 무대에서만.
   ⚠️ 권 지도 SVG 는 이름표 층에 pointer-events="none" 을 적었다(누름이 글자 아래 도형으로 내려가게).
      그런데 글자 아래가 **다른 곳**일 때가 있다 — 비켜 놓은 '인천광역시' 글자 아래는 경기도였다(실제 크롬).
      여기서 이름표에 누름을 되돌리고, es.js(hitFromLabel)가 data-sido·data-for·data-f 로 그 도형을 찾는다.
      CSS 가 표현 속성(pointer-events="none")을 이긴다. 키보드 길은 그대로(이름표에 tabindex 없음).
   · text[data-f] — 권 **연습 지도**(practice_map.svg) pm-names 이름표. 글자가 건물 도형 **바깥**에 있어
     누르면 종이로 내려갔다(4-1 05/02). **text 에만** 건다 — 그림층 g[data-f] 는 그림이라 누름을 되돌리지 않는다. */
.es-stage.is-tappable > .es-map-svg text[data-sido],
.es-stage.is-tappable > .es-map-svg text[data-for],
.es-stage.is-tappable > .es-map-svg text[data-f]{ pointer-events:auto; cursor:pointer; }
/* 키보드 초점 — SVG 도형은 outline 이 잘 안 그려져서 굵은 선으로도 보인다 */
.es-stage [data-hit]:focus{ outline:none; }
.es-stage [data-hit]:focus-visible{ outline:3px solid var(--es-vivid); outline-offset:2px; }
/* 굵은 선은 **도형에만** (리뷰 d)
   ⚠️ stroke·stroke-width·paint-order 는 물려받는 속성이다. g[data-hit](바다 이름·섬)에 주면 안의 <text> 가
      초록 6px 테두리를 물려받아 글자가 번진다 — 섬 글자는 조상 g 의 흰 테두리로 읽히는데 그 자리를 덮었다.
      g 는 outline 상자만 두고, 그 안의 **누름 도형**(pointer-events="all" 인 보이지 않는 상자·원 — 권 지도 계약)에 선을 준다.
      차시가 그린 g[data-hit] 도 초점 선을 원하면 누름 도형에 pointer-events="all" 을 적는다. */
.es-stage path[data-hit]:focus-visible,
.es-stage rect[data-hit]:focus-visible,
.es-stage circle[data-hit]:focus-visible,
.es-stage ellipse[data-hit]:focus-visible,
.es-stage polygon[data-hit]:focus-visible,
.es-stage polyline[data-hit]:focus-visible,
.es-stage line[data-hit]:focus-visible,
.es-stage g[data-hit]:focus-visible > rect[pointer-events="all"],
.es-stage g[data-hit]:focus-visible > circle[pointer-events="all"],
.es-stage g[data-hit]:focus-visible > ellipse[pointer-events="all"],
.es-stage g[data-hit]:focus-visible > path[pointer-events="all"]{
  stroke:var(--es-vivid); stroke-width:6px; paint-order:stroke;
}
.es-svg-fail{ margin-top:calc(var(--es-sp-3) * -1 + 6px); }

/* ── 조작줄 ────────────────────────────────────────────────────────────── */
.es-ctrls{
  display:flex; flex-wrap:wrap; gap:var(--es-sp-3);
  align-items:flex-end; margin:0 0 var(--es-sp-3); max-width:none;
}
.es-ctrls > *{ margin-bottom:0; }

/* ── 큰 손잡이 슬라이더 (esSlider) — 손잡이 56px, 양 끝 단추가 늘 함께 온다 ── */
.es-slider{ flex:1 1 320px; min-width:260px; max-width:var(--es-mid); }
.es-slider-top{
  display:flex; align-items:baseline; gap:10px; flex-wrap:wrap;
  margin:0 0 var(--es-sp-1);
}
.es-slider-name{ font-size:var(--es-fs-sm); font-weight:800; color:var(--es-deep); }
.es-slider-val{
  display:inline-flex; align-items:center; gap:6px;
  font-size:var(--es-fs-lg); font-weight:800; color:var(--es-ink);
  background:var(--es-tint); border:2px solid var(--es-edge);
  border-radius:var(--es-r-pill); padding:2px 14px;
}
.es-slider-word{ font-size:var(--es-fs-sm); font-weight:800; color:var(--es-accent); }
.es-slider-row{ display:flex; align-items:center; gap:var(--es-gap); }
.es-range{
  -webkit-appearance:none; appearance:none;
  flex:1 1 auto; min-width:120px; height:var(--es-tap);
  background:transparent; margin:0; padding:0; cursor:pointer;
}
.es-range:focus{ outline:none; }
.es-range:focus-visible{ outline:4px solid var(--es-focus); outline-offset:3px; border-radius:8px; }
.es-range::-webkit-slider-runnable-track{
  height:18px; border-radius:var(--es-r-pill);
  background:var(--es-soft); border:2px solid var(--es-line-2);
}
.es-range::-webkit-slider-thumb{
  -webkit-appearance:none; appearance:none;
  width:var(--es-tap); height:var(--es-tap); margin-top:-21px;
  border-radius:50%; background:var(--es-surface);
  border:6px solid var(--es-deep);
  box-shadow:0 6px 14px -6px rgba(20,32,46,.8);
  cursor:grab;
}
.es-range:active::-webkit-slider-thumb{ cursor:grabbing; transform:scale(1.06); }
.es-range::-moz-range-track{
  height:18px; border-radius:var(--es-r-pill);
  background:var(--es-soft); border:2px solid var(--es-line-2);
}
.es-range::-moz-range-thumb{
  width:44px; height:44px; border-radius:50%;
  background:var(--es-surface); border:6px solid var(--es-deep);
  box-shadow:0 6px 14px -6px rgba(20,32,46,.8); cursor:grab;
}
.es-slider .es-btn.is-icon{ flex:0 0 auto; }

/* ── 단계 재생 (esSteps) — 자동 재생 없음 ─────────────────────────────── */
.es-steps{ max-width:none; margin:0 0 var(--es-sp-3); }
.es-steps-rail{
  display:flex; align-items:center; gap:8px; flex-wrap:wrap;
  list-style:none; margin:0 0 var(--es-sp-2); padding:0; max-width:none;
}
.es-steps-rail > li{ margin:0; }
.es-step-dot{
  width:48px; height:48px; border-radius:50%;   /* 곁들이 단추 하한(.es-btn.is-small 과 같다) */
  background:var(--es-surface); border:3px solid var(--es-line-2);
  color:var(--es-ink-2); font:inherit; font-size:var(--es-fs-sm); font-weight:800;
  display:inline-flex; align-items:center; justify-content:center;
  cursor:pointer;
  transition:background-color .22s ease, border-color .22s ease, transform .22s ease, color .22s ease;
}
.es-step-dot:hover{ border-color:var(--es-deep); transform:translateY(-2px); }
.es-step-dot.is-on{
  background:var(--es-deep); border-color:var(--es-deep); color:#fff;
}
.es-step-dot.is-past{ background:var(--es-tint); border-color:var(--es-edge); color:var(--es-deep); }
.es-step-cap{
  display:block; margin:0 0 var(--es-sp-2); max-width:var(--es-mid);
  padding:12px 16px;
  background:var(--es-tint); border-left:10px solid var(--es-deep);
  border-radius:var(--es-r-sm);
  font-size:var(--es-fs-lg); font-weight:800; line-height:1.6;
}
.es-step-no{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:34px; height:34px; border-radius:11px; margin-right:10px;
  background:var(--es-deep); color:#fff;
  font-size:var(--es-fs-sm); font-weight:800; vertical-align:-5px;
}
/* (7판 · 2026-09-22) data-btns="top" — es.js 가 단추 줄을 걸음 글 **앞**(DOM)에 둔다. 걸음 글이 한 줄 ↔ 세 줄로 바뀌어도
   ◀ ▶ 가 제자리다(4-2 08/02 기준 차시 보고). 위젯 머리라 위 여백은 없애고, 아래는 걸음 글과 12px. */
.es-steps.is-btns-top > .es-btns{ margin:0 0 var(--es-sp-2); }

/* (11판 · 2026-09-25, 과학 3-1 권 감사 · LEAD 결정 24) 걸음 글을 **자식 목록으로도** 적는다.
   27절 쇼츠와 **같은 문법**이다 — 평소엔 그냥 번호 목록이라 es.js 가 못 붙어도 전부 읽히고,
   부품이 붙으면 뿌리에 `is-live` 가 걸려 접힌다(걸음판이 같은 글을 다시 말하므로).
   → 스크립트가 죽어도 그 절이 빈 상자가 되지 않는다(SPEC 4절 철칙).
   ⚠️ 기본은 **보이는 쪽**이다. 여기에는 '접는' 규칙만 적는다 — 조건이 안 맞으면 목록이 그대로 남는다.
   ⚠️ `.es-steps-rail`(1..N 점 줄)은 빼 둔다 — 그것도 es.js 가 만드는 <ul> 이다.
   ⚠️ `opacity:0` 이 아니라 `display:none` 이다 — 접힌 목록을 낭독기가 두 번 읽지 않게.
   ⚠️ 목록 모양은 247행의 `ul,ol` 기본을 그대로 쓴다(새로 꾸미지 않는다). */
.es-steps.is-live > ol:not(.es-steps-rail),
.es-steps.is-live > ul:not(.es-steps-rail){ display:none; }

/* ── 돌리는 손잡이 (esDial) — 드래그 + **단추 대안 필수**(WCAG 2.5.7) ──── */
/* ⚠️ .es-dial 자체는 **블록**이다. 여기에 flex 를 걸면 es.js 가 아래에 붙이는
   저장 칸(.es-summary-wrap)까지 가로 칸이 되어 손바닥만 하게 눌린다(실측). */
.es-dial{ margin:0 0 var(--es-sp-3); max-width:none; }
.es-dial-row{ display:flex; align-items:center; gap:var(--es-sp-3); flex-wrap:wrap; }
.es-dial-pad{
  position:relative; flex:0 0 auto;
  width:168px; height:168px; border-radius:50%;
  background:var(--es-tint); border:6px solid var(--es-deep);
  box-shadow:inset 0 4px 16px -8px rgba(20,32,46,.7), 0 12px 26px -18px var(--es-deep);
  touch-action:none; cursor:grab; padding:0;
}
.es-dial-pad:active{ cursor:grabbing; }
/* 붙박이 눈금 — '여기가 위'라는 고정 표시. 돌아가는 손잡이 막대와 **색이 달라야**
   0도에서 둘이 한 줄로 겹쳐 하나처럼 보이지 않는다(1366 실측에서 그랬다). */
.es-dial-pad::after{
  content:""; position:absolute; left:calc(50% - 5px); top:2px;
  width:10px; height:10px; border-radius:50%;
  background:var(--es-accent-glow); box-shadow:0 0 0 2px var(--es-accent-line);
}
.es-dial-knob{
  position:absolute; inset:14px; border-radius:50%;
  background:var(--es-surface); border:4px solid var(--es-edge);
  display:flex; align-items:center; justify-content:center;
  font-size:38px; line-height:1;
  will-change:transform;
}
.es-dial-knob::before{                  /* 손잡이 막대 */
  content:""; position:absolute; left:calc(50% - 5px); top:10px;
  width:10px; height:34px; border-radius:5px; background:var(--es-deep);
}
.es-dial-side{ flex:1 1 240px; min-width:220px; }
.es-dial-val{
  display:inline-flex; align-items:center; gap:8px;
  font-size:clamp(24px,2.4vw,30px); font-weight:800; color:var(--es-deep);
  background:var(--es-tint-2); border:2px solid var(--es-edge);
  border-radius:var(--es-r-pill); padding:4px 18px; margin:0 0 var(--es-sp-2);
}

/* ── 숫자가 올라간다 (esCount) ────────────────────────────────────────── */
.es-num{
  display:inline-flex; align-items:baseline; gap:4px;
  font-size:clamp(28px,3vw,40px); font-weight:800; color:var(--es-deep);
  font-variant-numeric:tabular-nums; line-height:1.2;
}
.es-num .u{ font-size:var(--es-fs-lg); color:var(--es-ink-2); }
.es-nums{
  display:flex; flex-wrap:wrap; gap:var(--es-gap);
  list-style:none; margin:0 0 var(--es-sp-3); padding:0; max-width:none;
}
.es-nums > li{
  margin:0; flex:1 1 160px; min-width:140px;
  background:var(--es-tint-2); border:2px solid var(--es-edge);
  border-radius:var(--es-r); padding:10px 16px;
}
.es-nums .k{ display:block; font-size:var(--es-fs-sm); font-weight:800; color:var(--es-ink-2); }

/* ── 켜고 끄는 판 (esToggleSet) ───────────────────────────────────────── */
.es-toggles{ max-width:none; margin:0 0 var(--es-sp-3); }
.es-toggle-grid{
  display:grid; gap:var(--es-gap);
  grid-template-columns:repeat(auto-fit, minmax(150px, 1fr));
}
.es-toggle{
  display:flex; flex-direction:column; align-items:center; gap:4px;
  min-height:96px; padding:12px 10px;
  background:var(--es-surface); color:var(--es-ink);
  border:3px solid var(--es-line-2); border-radius:var(--es-r);
  box-shadow:0 4px 0 var(--es-line);
  font:inherit; font-size:var(--es-fs-sm); font-weight:800; cursor:pointer;
  transition:transform .16s ease, box-shadow .16s ease, border-color .16s ease,
             background-color .18s ease;
}
.es-toggle .em{ font-size:34px; line-height:1.1; }
.es-toggle:hover{ transform:translateY(-3px); border-color:var(--es-deep);
  box-shadow:0 7px 0 var(--es-line), 0 14px 24px -16px var(--es-deep); }
.es-toggle:active{ transform:translateY(3px); box-shadow:0 1px 0 var(--es-line); }
/* 켜짐은 색만으로 알리지 않는다 — 색 + 테두리 + ✓ 글자를 함께 쓴다(WCAG 1.4.1) */
.es-toggle[aria-pressed="true"]{
  background:var(--es-ok-soft); border-color:var(--es-ok); color:var(--es-ok);
  box-shadow:0 4px 0 var(--es-ok-edge);
}
.es-toggle[aria-pressed="true"] .st::before{ content:"✔ "; }
.es-toggle .st{ font-size:var(--es-fs-src); font-weight:800; color:var(--es-ink-2); }
.es-toggle[aria-pressed="true"] .st{ color:var(--es-ok); }
.es-toggle.is-full{ opacity:.55; }
.es-toggle-out{
  margin:var(--es-sp-3) 0 0; padding:var(--es-sp-3);
  background:var(--es-tint); border-left:10px solid var(--es-deep);
  border-radius:var(--es-r-sm);
  font-size:var(--es-fs-lg); font-weight:800; max-width:var(--es-mid);
}
/* (4판) 합계 제약 — data-budget. 항목 값은 단추 안 알약, 합은 판 아래 막대 + 한 줄 */
.es-toggle .val{
  display:inline-block; padding:1px 10px; border-radius:var(--es-r-pill);
  background:var(--es-tint); color:var(--es-deep);
  font-size:var(--es-fs-src); font-weight:800;
}
.es-toggle[aria-pressed="true"] .val{ background:#fff; color:var(--es-ok); }
.es-toggle-sum{
  display:flex; align-items:center; gap:var(--es-sp-2); flex-wrap:wrap;
  margin:var(--es-sp-3) 0 0; max-width:var(--es-mid);
  font-size:var(--es-fs-sm); font-weight:800; color:var(--es-ink);
}
.es-toggle-bar{
  position:relative; flex:1 1 180px; height:16px; min-width:120px;
  background:var(--es-surface); border:2px solid var(--es-line-2); border-radius:var(--es-r-pill);
  overflow:hidden;
}
.es-toggle-bar > i{
  position:absolute; left:0; top:0; bottom:0; width:0;
  background:var(--es-ok); border-radius:inherit; transition:width .25s ease;
}
/* (2026-09-16) data-layout="row" — 단추를 **한 줄 목록**으로 눕힌다: [그림] 이름 ……… [값] [상태]
   ⚠️ 기본 단추는 그림·이름·값·상태를 세로로 쌓아 390 에서 한 개가 178px, 옆 칸 판에서도 판 끝이 화면 밖이었다(07/01 · 07/06).
      차시 셋이 각자 CSS 로 눕히고 있었다. 이름은 줄바꿈하되 상태 글자는 접지 않는다. 누르는 높이는 56px 이상. */
.es-toggles.is-row .es-toggle-grid{ grid-template-columns:repeat(auto-fit, minmax(min(100%, 300px), 1fr)); }
.es-toggles.is-row .es-toggle{
  display:grid; grid-template-columns:auto minmax(0, 1fr) auto auto; align-items:center; column-gap:10px;
  min-height:var(--es-tap); padding:8px 14px; text-align:left;
}
.es-toggles.is-row .es-toggle .em{ font-size:28px; }
.es-toggles.is-row .es-toggle .tx{ grid-column:2; line-height:1.35; }
.es-toggles.is-row .es-toggle .val{ grid-column:3; white-space:nowrap; }
.es-toggles.is-row .es-toggle .st{ grid-column:4; white-space:nowrap; }
.es-toggles.is-row .es-toggle:not(:has(.em)) .tx{ grid-column:1 / 3; }
.es-toggles.is-row .es-toggle-out{ margin-top:var(--es-sp-2); padding:10px var(--es-sp-3); font-size:var(--es-fs); }


/* ══════════════════════════════════════════════════════════════════════════
   27. 쇼츠 — .es-short  (대단원 소개 30초 이내)
   ──────────────────────────────────────────────────────────────────────────
   장면을 세로로 쌓아 두면 **JS 없이도 전부 읽히는 글**이다. es.js 가 뜨면
   `is-live` 가 붙어 그때부터 무대가 되고 장면이 하나씩 넘어간다.
   → 스크립트가 죽어도 백지가 되지 않는다(SPEC 4절 철칙).

   · **자동 재생 없음.** 큰 ▶ 단추를 눌러야 시작한다.
   · 진행 막대 · ⏭ 건너뛰기 · ↻ 다시 보기 · ⏸ 멈추기.
   · 총 길이는 es.js 가 **30초로 물린다.**
   · 배경 음악(data-music, 6판)은 ▶ 를 **누른 뒤에만** 운다. 조작줄 끝 '🔈 음악 끄기' 는 누르기 전에도 보인다.
   ────────────────────────────────────────────────────────────────────────── */
.es-short{ max-width:var(--es-content); margin:var(--es-sp-4) 0; }

/* 죽었을 때의 모습 — 그냥 카드 넉 장 */
.es-short-scene{
  background:var(--es-surface); border:2px solid var(--es-line);
  border-radius:var(--es-r); padding:var(--es-sp-3); margin:0 0 var(--es-gap);
}

/* ⚠️ 무대 높이는 **위 고정 띠를 뺀 화면** 안에 든다(2026-09-16). 옛본 78vh 는 띠를 세지 않아
      1366×768 에서 '다시 하기' 줄이 붙은 띠(178px) 아래로 무대 끝이 13px, 폰 가로 844×390 에서는 36px 이 화면 밖이었다
      (쇼츠 일곱 편 모두 — shot_write41.mjs B). 띠 높이는 es.js 가 --es-top-h 로 알려 준다(없으면 0 → 옛 78vh 그대로).
      넓은 화면은 띠가 짧아 대개 78vh 가 그대로 이긴다. 220px 아래로는 줄이지 않는다.
      낮은 화면(높이 500 이하)은 28절 끝에서 옛 78vh 로 되돌린다 — 그 까닭은 거기에. */
.es-short-stage{
  position:relative; width:100%; aspect-ratio:16 / 9;
  max-height:78vh;
  max-height:max(220px, min(78vh, calc(100vh - var(--es-top-h, 0px) - 12px)));
  overflow:hidden;
  background:var(--es-deep-2); color:#fff;
  border:4px solid var(--es-deep); border-radius:var(--es-r-lg);
  box-shadow:0 26px 54px -30px rgba(20,32,46,.85);
}
.es-short.is-tall .es-short-stage{ aspect-ratio:9 / 16; max-width:440px; margin-inline:auto; }
.es-short-stage::before{                /* 히어로와 같은 격자 — 글자가 얹히지 않는 장식 */
  content:""; position:absolute; inset:0; z-index:0; pointer-events:none;
  background-image:
    linear-gradient(rgba(255,255,255,.10) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.10) 1px, transparent 1px);
  background-size:44px 44px;
  -webkit-mask-image:radial-gradient(ellipse at 50% 45%, #000 10%, transparent 74%);
          mask-image:radial-gradient(ellipse at 50% 45%, #000 10%, transparent 74%);
}
.es-short.is-live .es-short-scene{
  position:absolute; inset:0; z-index:1;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:var(--es-sp-2); text-align:center;
  border:0; margin:0; background:none;
  padding:clamp(20px,4vw,52px);
  opacity:0; visibility:hidden;
  transition:opacity .5s ease, transform .5s cubic-bezier(.22,.61,.36,1);
}
/* 장면 전환은 CSS 로만 — data-fx 가 **들어오기 전** 자리를 정한다.
   ⚠️ 이 셋을 `.is-on` 뒤에 두면 안 된다. 특이도가 같아(0,4,0) 뒤엣것이 이기므로
      켜진 장면의 목표가 '들어오던 변형' 그대로 굳는다 — 움직임이 아예 안 보이고
      장면이 치우친 채 멈춘다(실측: slide translateX(38.9px)·up 53.2px·zoom 1.1 고정).
      쇼츠 담당 둘이 각자 자기 파일에서 우회하고 있었다. 순서를 되돌린다. */
.es-short.is-live .es-short-scene[data-fx="slide"]{ transform:translateX(9%); }
.es-short.is-live .es-short-scene[data-fx="up"]   { transform:translateY(9%); }
.es-short.is-live .es-short-scene[data-fx="zoom"] { transform:scale(1.1); }
.es-short.is-live .es-short-scene.is-on{ opacity:1; visibility:visible; transform:none; }
/* ⚠️ 색은 **무대가 살아 있을 때만** 흰색이다.
   전에는 조건 없이 `color:#fff` 라, es.js 가 못 뜨면 장면이 흰 카드가 되면서
   **흰 면 위 흰 글자**가 되어 한 자도 안 읽혔다(SPEC 4절 '콘텐츠를 JS 뒤에 숨기지 마라' 위반).
   폴백을 살려 두려고 만든 구조가 정작 폴백에서 죽고 있었다. 쇼츠 담당 둘이 같이 짚었다. */
.es-short-h{
  font-size:clamp(26px,4.4vw,52px); font-weight:800; line-height:1.2;
  color:var(--es-ink); margin:0; max-width:none; letter-spacing:-0.02em;
}
.es-short-p{
  font-size:clamp(18px,2.2vw,26px); font-weight:700; line-height:1.6;
  color:var(--es-ink-2); margin:0; max-width:none;
}
.es-short.is-live .es-short-h{ color:#fff; }
.es-short.is-live .es-short-p{ color:var(--es-glow); }
.es-short-em{ font-size:clamp(44px,8vw,96px); line-height:1; }
/* ⚠️ 백분율 max-height 는 **`<figure>` 안에서 풀린다** — 출처 표기를 담으려면 figure 가 필요한데
   (SPEC 6절) figure 높이는 다시 사진이 정하므로 서로 물고 줄어든다(실측: 599px 무대에서 사진 127px).
   그래서 px 로 준다. 그리고 `width:auto` 면 사진이 액자보다 좁아지는데 액자 폭은 **출처 줄 길이**가
   정하므로, 출처가 긴 사진만 왼쪽으로 쏠린다 — 짧은 것은 우연히 가운데라 눈으로는 안 잡힌다.
   쇼츠 담당 셋이 각자 px 로 우회하고 있었다. 여기서 한 번에 준다. */
.es-short-scene img{
  max-height:min(300px, 34vh); width:auto; margin-inline:auto;
  border-radius:var(--es-r);
  border:4px solid rgba(255,255,255,.85); box-shadow:0 18px 34px -20px #000;
}
@media (max-width:560px){ .es-short-scene img{ max-height:min(200px, 26vh); } }
/* ⚠️ 액자에 **폭을 준다**(2026-09-25). 장면은 세로 flex + align-items:center 라 액자가
   제 내용 폭으로 오그라드는데, 그 '내용 폭' 을 정하는 것이 사진이 아니라 **출처 줄 길이**다.
   사진은 위에서 px 로 잡아 두어 괜찮았지만, **액자 안에 인라인 그림(SVG)을 넣으면** 그림이
   출처 줄만큼 줄어든다 — 실측: 1366px 화면에서 384px 로 설 그림이 **188px** 로 떴다.
   과학 3-1 여는 쪽 담당이 잡았다. 한 줄로 공용에서 끝낸다(사회 네 권의 사진 장면도 함께 산다).
   text-align:center 는 장면이 물려주므로 출처 줄은 그대로 가운데다. */
.es-short-scene .es-fig{ margin-inline:auto; width:100%; }
.es-short-scene .es-fig > svg{ width:100%; height:auto; }
.es-short.is-live .es-short-scene .es-src{ --es-src-ink:rgba(255,255,255,.6); }
/* ⚠️ 캡션도 흰빛으로(2026-09-25). 무대가 살아 있으면 바닥이 --es-deep-2(짙은 색)인데
   `.es-cap` 만 잉크색(--es-ink) 그대로라 **한 자도 안 보였다** — 제목·본문·출처 셋은
   위에서 이미 바꿨는데 캡션만 빠져 있었다. 사회 네 권과 이 권의 01/00·02/00 은 무대 안에서
   캡션을 한 번도 안 써서 여태 드러나지 않았다(과학 3-1 03/00 담당이 띄워 보고 잡았다).
   무대 밖(.es-short 가 is-live 가 아닐 때)의 캡션은 그대로 잉크색이다. */
.es-short.is-live .es-short-scene .es-cap{ color:#fff; }

/* 큰 ▶ — 이걸 눌러야 시작한다.
   ⚠️ 덮개가 옅으면 첫 장면 글씨와 안내 글씨가 **겹쳐 읽힌다**(1366 실측).
      .82 로 덮고 안내 글은 알약을 깔아 준다. */
.es-short-play{
  position:absolute; inset:0; z-index:3;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:18px;
  background:rgba(5,20,14,.82); border:0; color:#fff;
  font:inherit; font-size:var(--es-fs-lg); font-weight:800; cursor:pointer;
  text-align:center; padding:var(--es-sp-3);
}
.es-short-play > span:not(.em):not(.es-short-ttl){
  background:rgba(255,255,255,.14); border:2px solid rgba(255,255,255,.42);
  border-radius:var(--es-r-pill); padding:6px 20px;
}
/* 표지 제목 — 장면을 켜지 않고 여기에 크게 적는다 */
.es-short-ttl{
  font-size:clamp(26px,4vw,46px); font-weight:800; line-height:1.2;
  letter-spacing:-0.02em; color:#fff;
}
.es-short-play .em{
  width:104px; height:104px; border-radius:50%;
  background:var(--es-glow); color:var(--es-deep-2);
  display:flex; align-items:center; justify-content:center;
  font-size:46px; line-height:1;
  box-shadow:0 16px 34px -14px rgba(0,0,0,.8);
  transition:transform .2s ease;
}
.es-short-play:hover .em{ transform:scale(1.08); }
.es-short-play[hidden]{ display:none !important; }

.es-short-bar{
  position:absolute; left:0; right:0; bottom:0; z-index:2;
  height:8px; background:rgba(255,255,255,.22);
}
.es-short-bar > i{ display:block; height:100%; width:0; background:var(--es-glow); }
.es-short-tools{ display:flex; flex-wrap:wrap; gap:var(--es-gap); margin:var(--es-sp-2) 0 0; }
/* 🔈 음악 끄기 / 🔇 음악 켜기 (6판) — 곁들이 단추(48px · is-small is-quiet). 한 덩어리로 줄바꿈되게 글 안에서는 안 꺾는다.
   꺼진 때는 **점선 테두리** — 글(켜기/끄기)과 함께 두 겹으로 알린다(색만으로 가르지 않는다, WCAG 1.4.1). */
.es-short-music{ white-space:nowrap; }
.es-short-music.is-off{ border-style:dashed; }
.es-short-no{
  position:absolute; right:14px; top:12px; z-index:2;
  background:rgba(0,0,0,.42); color:#fff;
  border:2px solid rgba(255,255,255,.4); border-radius:var(--es-r-pill);
  padding:3px 14px; font-size:var(--es-fs-src); font-weight:800;
}


/* ══════════════════════════════════════════════════════════════════════════
   28. 새 부품의 인쇄 · 감속 · 좁은 화면
   ────────────────────────────────────────────────────────────────────────── */
@media print{
  .es-drift-layer, .es-drift-stop, .es-short-play, .es-short-bar,
  .es-short-tools, .es-short-no, .es-ctrls, .es-slider, .es-dial,
  .es-steps-rail{ display:none !important; }
  .es-sim, .es-stage, .es-short-stage, .es-toggles{
    border:1px solid #666; box-shadow:none; break-inside:avoid;
    background:#fff !important; color:#000 !important;
  }
  .es-sim::before, .es-short-stage::before{ display:none !important; }
  .es-short-stage{ aspect-ratio:auto; height:auto; }
  .es-short.is-live .es-short-scene{
    position:static; opacity:1 !important; visibility:visible !important;
    transform:none !important; border-bottom:1px solid #999; padding:3mm 0;
  }
  .es-short-h, .es-short-p{ color:#000 !important; }
  .es-stage{ min-height:40mm; }
}

@media (prefers-reduced-motion: reduce){
  .es-drift-layer{ display:none !important; }
  .es-fly-l, .es-fly-r, .es-fly-up{ opacity:1 !important; transform:none !important; }
  .es-short.is-live .es-short-scene{ transition:none !important; }
  .es-toggle:hover, .es-step-dot:hover, .es-short-play:hover .em{ transform:none !important; }
}

@media (max-width:760px){
  .es-dial-pad{ width:132px; height:132px; }
  .es-dial-knob{ font-size:30px; }
  .es-short-stage{ aspect-ratio:4 / 3; }
  .es-short.is-tall .es-short-stage{ aspect-ratio:9 / 16; }
  .es-toggle-grid{ grid-template-columns:repeat(auto-fit, minmax(128px, 1fr)); }
}

/* 낮고 넓은 화면(폰 가로 844×390 · 작은 노트북 창) — 쇼츠 장면을 **낮은 무대에 맞춘다** (2026-09-16)
   ⚠️ 무대가 띠를 뺀 265px 안팎으로 낮아지는데 제목은 4.4vw(37px)·안쪽 여백은 4vw 그대로라, 세로로 쌓인 장면의
      자막이 무대 밖으로 18~21px 잘렸다(3-2 쇼츠 두 편 실측 — overflow:hidden 이라 오류가 없다). 4-1 쇼츠 셋은 각자 막았다.
      배치는 바꾸지 않고(차시가 고른 격자·그림 크기가 그대로 이긴다) 글자·여백·그림 상한만 **화면 높이**를 따르게 한다. */
@media (max-height:500px){
  /* ⚠️ 낮은 화면에서는 무대를 띠만큼 줄이지 **않는다**(옛 78vh 그대로). 쇼츠 일곱 편의 사진·지도·선화 크기가
        차시마다 px 로 304px 무대에 맞춰져 있어, 띠를 뺀 261~273px 로 줄이면 3-2 사진 장면이 23~30px, 4-1 지도 장면이
        4~13px 잘렸다(shot_write41 탐침 실측). 잘린 글은 오류가 없어 못 찾는다 — 무대 끝 31px 이 띠 아래로 가는 쪽이 낫다. */
  .es-short-stage{ max-height:78vh; }
  .es-short.is-live .es-short-scene{ padding:10px clamp(16px, 3vw, 32px) 16px; gap:6px; }
  .es-short-h{ font-size:clamp(22px, 7vh, 34px); line-height:1.2; }
  .es-short-p{ font-size:var(--es-fs-sm); line-height:1.45; }
  .es-short-em{ font-size:clamp(30px, 10vh, 52px); }
  .es-short-scene img{ max-height:min(170px, 36vh); }
  .es-short-play{ gap:10px; }
  .es-short-ttl{ font-size:clamp(22px, 7vh, 36px); }
  .es-short-play .em{ width:64px; height:64px; font-size:30px; }
}


/* ============================================================================
   덧붙인 것 — 차시가 골라 쓰는 새 클래스 (기존 이름은 하나도 바꾸지 않았다)
   ----------------------------------------------------------------------------
   ── 2판 ──
   <body data-hue="sun">          대단원·차시 주제색. green|sun|sky|coral|violet|cobalt|earth
   <svg class="es-hero-art" aria-hidden="true">  히어로 오른쪽 장식 슬롯(선화). 개념을 선으로 그린다
   <p class="es-eyebrow">          섹션 위 작은 아이브로우(자간 .22em). **한글로만**
   <div class="es-cols">           자동 2~4단 카드 격자(최소 280px)
   <div class="es-stagger">        자식이 90ms 씩 차례로 등장
   <section class="es-sec is-band|is-paper|is-deep">  섹션 배경 띠를 손으로 고를 때
   <div class="es-progress"><i></i></div>            진행 막대 (es.js 가 만들어 준다)
   .es-draw                        SVG 선이 그려지는 연출(--es-draw-len 로 길이를 준다)

   ── 3판 (2026-09-09) ──
   .es-fly-l / .es-fly-r / .es-fly-up   스크롤로 들어올 때 옆·아래에서 날아와 앉는다
                                        나란히면 style="--i:0|1|2" 로 차례를 준다
   .es-land-big                    활동 결과가 칸에 앉는 **강한** 연출(es.js 가 붙였다 뗀다)
   .es-drift (data-kind·data-count·data-loop)   배경에 흩날리는 입자. **내용과 이어질 때만**
   .es-sim / .es-sim-head / .es-sim-how          시뮬레이터 껍데기
   .es-stage / .es-stage-cap       무대(캔버스·SVG). 그리는 좌표는 늘 1100 기준
   .es-ctrls                       조작줄 (요소 5개 이하)
   .es-slider / .es-range          큰 손잡이 슬라이더(56px)
   .es-steps / .es-step-cap        단계 재생 (◀ ▶ ▶‖ · 자동 재생 없음)
   .es-dial                        돌리는 손잡이 (드래그 + 단추 대안)
   .es-num / .es-nums              올라가는 숫자
   .es-toggles / .es-toggle        켜고 끄는 판
   .es-short / .es-short-scene     30초 이내 쇼츠 무대
   --es-fs-credit / --es-src-ink   출처 전용 (12px · #666c78). 다른 데 쓰지 말 것
   ========================================================================== */


/* ── 차시 이동 (앞·목록·다음) ─────────────────────────────────────────
   전에는 '차시 목록으로 가요' 하나뿐이라, 다음 차시로 가려면 목록을 거쳐야 했다.
   3학년이 한 시간을 마치고 바로 다음으로 넘어가는 길이 없었다(사용자가 짚었다). */
.es-next{
  display:grid; gap:var(--es-sp-3); margin:var(--es-sp-5) auto var(--es-sp-6);
  max-width:var(--es-content); grid-template-columns:1fr auto 1fr; align-items:stretch;
}
/* ⚠️ 첫 차시·마지막 차시는 링크가 둘뿐이라 3칸 격자에서 빈 칸이 유령으로 남아
   단추가 한쪽으로 쏠린다(3-1 오프닝 두 편도 같은 상태였다). 링크 수에 맞춰 칸을 줄인다. */
.es-next:not(:has(> :nth-child(3))){ grid-template-columns:1fr auto; }
.es-next:not(:has(> :nth-child(2))){ grid-template-columns:1fr; }
@media (max-width:760px){ .es-next{ grid-template-columns:1fr; } }
.es-next > a{
  display:flex; flex-direction:column; justify-content:center; gap:4px;
  min-height:76px; padding:14px 22px; border-radius:var(--es-r);
  text-decoration:none; border:3px solid var(--es-edge); background:var(--es-surface);
  color:var(--es-ink); font-weight:800; transition:transform .18s ease, box-shadow .18s ease;
}
.es-next > a:hover, .es-next > a:focus-visible{ transform:translateY(-3px); box-shadow:var(--es-shadow-2); }
/* ⚠️ 명시도를 '.es-next > a'(0,1,1) 위로 올린다 — '.es-next > a.es-nav-next'(0,2,1).
   옛 '.es-nav-next'(0,1,0) 는 위 줄에 져서 바탕·테두리·글자색이 **한 번도 먹지 않았다.** 다음 차시 단추는 흰 바탕이었고
   라벨만 '.es-nav-next .es-nav-lab'(0,2,0) 로 --es-glow 가 먹어 흰 바탕에 옅은 하늘색(코발트 1.7:1)이 떴다.
   3-1·3-2 32쪽도 같은 모습이었다(2026-09-15, 4-1 05/02 기준 차시가 찾았다 — 검증 es.shared.test 캐스케이드 · shot_shared_fixes). */
.es-nav-prev{ text-align:left; }
.es-next > a.es-nav-next{ text-align:right; background:var(--es-deep); border-color:var(--es-deep); color:#fff; }
.es-nav-next .es-nav-lab{ color:var(--es-glow); }
.es-next > a.es-nav-list{
  align-items:center; text-align:center; background:var(--es-tint);
  border-color:var(--es-edge); white-space:nowrap;
}
.es-nav-lab{ font-size:15px; font-weight:700; color:var(--es-ink-2); letter-spacing:.02em; }
.es-nav-t{ font-size:20px; font-weight:800; line-height:1.3; }
@media print{ .es-next{ display:none; } }

/* ── 이 쪽 다시 하기 ──────────────────────────────────────────────────
   활동 기록은 이 브라우저에 남는다. 공용 기기에서 다음 아이가 열면 이미 도장이 찍혀 있다.
   지우는 길이 없어서 "시작도 안 했는데 완료되어 있다" 가 됐다(사용자가 짚었다). */
.es-reset{
  border:none; background:none; cursor:pointer; font:inherit;
  font-size:15px; font-weight:700; color:var(--es-ink-2);
  padding:8px 12px; border-radius:999px; min-height:44px;
}
.es-reset:hover{ background:var(--es-tint); color:var(--es-deep); }
.es-reset:focus-visible{ outline:3px solid var(--es-edge); outline-offset:2px; }


/* ============================================================================
   29. 9판 부품 넷 — .es-guess · .es-balance · .es-scale · .es-force
   ----------------------------------------------------------------------------
   (2026-09-24 · 초등 과학 3-1 원장 NW6 · NW1 · NW2 · NW3)

   ⚠️ **여기서는 기존 선택자를 하나도 다시 정의하지 않는다.** 전부 새 이름이고
      (사회 트리 grep 0건), 초점 굵은 선은 위 3절의 전역 `:focus-visible` 이 그대로 그린다.

   넷이 함께 지키는 것:
     · 누르는 것은 전부 **56px 이상**(--es-tap). 끌기가 없다(WCAG 2.5.7).
     · **색만으로 알리지 않는다** — 켜짐에 ✔, 고름에 ◉, 넘침에 '—' 를 함께 쓴다(1.4.1).
       safety.md 6절이 '왼쪽 빨강 / 오른쪽 파랑' 을 이름 대어 금지했으므로,
       수평잡기의 쪽 이름은 **늘 글자 딱지**(.es-balance-side)로 서 있다.
     · z-index 를 쓰지 않는다(겹치는 층이 없다). **예외 하나** — 잠긴 판 위에 겹쳐 서는 할 일 한 줄
       (.es-lock-note, 2026-10-08 흐린 미리보기)만 z-index:3 을 쓴다. 판 자식의 흐림·투명도가 쌓임 맥락을
       만들어 DOM 순서상 뒤에 오는 판이 앞 형제인 이 줄을 덮기 때문이다. 파일 머리의 900 상한 안이다.
     · 움직임은 0.3~0.35초 전환 하나뿐이고, 22절의 전역 감속이 그 시간을 끈다.
       누를 때 내려앉는 것만은 전역 감속이 못 끄므로 이 절 끝에 reduce 블록을 따로 두었다.
   ────────────────────────────────────────────────────────────────────────── */

/* ── ㉒ 예상 고르기 (esGuess) ──────────────────────────────────────────────
   ⚠️ 고른 보기에 **판정색(--es-ok / --es-no)을 쓰지 않는다.** 이 부품은 채점하지 않는다 —
      초록은 '맞았다' 로 읽힌다. 강조색(--es-accent)으로 '내가 고른 것' 만 말한다. */
.es-guess{ max-width:var(--es-mid); margin:0 0 var(--es-sp-3); }
.es-guess-opts{
  display:grid; gap:var(--es-gap);
  grid-template-columns:repeat(auto-fit, minmax(min(100%, 230px), 1fr));
}
.es-guess-opt{
  display:flex; align-items:center; gap:10px;
  min-height:var(--es-tap); padding:12px 18px; text-align:left;
  background:var(--es-surface); color:var(--es-ink);
  border:3px solid var(--es-line-2); border-radius:var(--es-r);
  box-shadow:0 4px 0 var(--es-line);
  font:inherit; font-size:var(--es-fs-btn); font-weight:800; line-height:1.35; cursor:pointer;
  transition:transform .16s ease, box-shadow .16s ease, border-color .16s ease,
             background-color .18s ease;
}
.es-guess-opt::before{ content:"○"; font-size:22px; line-height:1; color:var(--es-ink-2); }
.es-guess-opt .em{ font-size:28px; line-height:1; }
.es-guess-opt .tx{ flex:1 1 auto; }
.es-guess-opt:hover{
  transform:translateY(-3px); border-color:var(--es-deep);
  box-shadow:0 7px 0 var(--es-line), 0 14px 24px -16px var(--es-deep);
}
.es-guess-opt:active{ transform:translateY(3px); box-shadow:0 1px 0 var(--es-line); }
.es-guess-opt[aria-pressed="true"]{
  background:var(--es-accent-soft); border-color:var(--es-accent-line); color:var(--es-accent);
  box-shadow:0 4px 0 var(--es-accent-line);
}
.es-guess-opt[aria-pressed="true"]::before{ content:"◉"; color:var(--es-accent); }
.es-guess-out{
  margin:var(--es-sp-3) 0 0; padding:var(--es-sp-3);
  background:var(--es-accent-soft); border-left:10px solid var(--es-accent-line);
  border-radius:var(--es-r-sm);
  font-size:var(--es-fs-lg); font-weight:800; max-width:var(--es-mid);
}
.es-guess-out:empty{ display:none; }
.es-guess-after{
  margin:var(--es-sp-2) 0 0; font-size:var(--es-fs); font-weight:700; color:var(--es-ink-2);
  max-width:var(--es-mid);
}

/* ── 잠긴 자리 (data-opens) — 흐린 미리보기 ───────────────────────────────
   2026-10-08 (초등 수정계획 0단계 응급 수정): visibility:hidden 을 버렸다. 예상 전 판이 1366 에서
   흰 빈칸 642px · 390 에서 925px 로 남아 '판에 칸이 넷이라는데 비어 있다' 가 됐다(과학 3-1 21쪽 + 3-2 2쪽).
   이제 판은 **보이되 흐리고**(그림·칸 윤곽·무대), **글자는 지우고**, **누를 수 없다.**
   옛 방식이 지키던 두 까닭은 그대로 지킨다:
      ① 자리를 그대로 잡는다 — display·크기를 건드리지 않으므로 안쪽 무대(.es-stage)가 **제 폭으로** 그려진다.
      ② Tab 차례·낭독기에서 빠진다 — es.js 가 거는 `inert`. inert 를 모르는 옛 브라우저에는 es.js 가
         aria-hidden + tabindex=-1 을 대신 걸고, 그래도 초점이 들어오면 판 밖으로 넘긴다(초점 지킴이).
         마우스·손가락은 여기 pointer-events 가 막는다.
   ⚠️ 정답이 새지 않게 — 잠금 상자 안에 결과 줄·뜻 상자가 든 쪽이 있다(3-2 07/03 #p703-lab 등).
      흐림만으로는 큰 글자가 어렴풋이 읽히므로 **글자는 투명으로 따로 지운다**(가상 요소·자리표시 글·SVG 글자까지).
      색 이모지는 color 를 따르지 않아 흐림이 맡는다. 고대비 모드가 투명 글자를 되살리지 않게 forced-color-adjust 를 끈다.
   ⚠️ 흐림은 판 **자식**에 건다(판 자신이 아니라). 판의 테두리·바탕(칸 윤곽)은 또렷이 남고,
      판 앞 형제인 할 일 한 줄(.es-lock-note)은 흐림을 받지 않는다. */
.es-lock{
  pointer-events:none; user-select:none; -webkit-user-select:none;
  forced-color-adjust:none;
}
/* !important — 판 자식에 걸린 나타나기 연출(es-fly 의 opacity 애니메이션)이 끝값 1 로 흐림을 덮지 않게 */
.es-lock > *{ filter:blur(2.5px) saturate(.55) !important; opacity:.5 !important; }
.es-lock, .es-lock *, .es-lock::before, .es-lock::after, .es-lock *::before, .es-lock *::after{
  color:transparent !important; -webkit-text-fill-color:transparent !important;
  text-shadow:none !important;
}
.es-lock ::placeholder{ color:transparent !important; -webkit-text-fill-color:transparent !important; }
.es-lock svg text{ opacity:0 !important; }
/* ⚠️ 사진은 글자보다 더 세게 흐린다(2026-10-08 반증 — 0단계 응급 수정의 새 누출).
   위 2.5px 는 칸 윤곽·직접 그린 무대(첫 모습뿐이라 결과가 없다)에는 알맞지만, **사진이 곧 예상의 근거**인 쪽에서는
   답을 그대로 보였다 — 과학 3-1 02/01 나비의 날개·더듬이·다리('날개만 / 날개와 더듬이 / …와 다리'),
   02/04 하얀 북극여우('하얀 / 까만 / 알록달록'), 03/01 잎의 그물 줄('가는 줄이 보여요 / 아무것도 안 보여요'),
   02/05 두더지 앞발. 옛 visibility:hidden 은 이 사진들을 통째로 가렸으니 흐린 미리보기가 새로 낸 구멍이다.
   22px 에서 나비는 날개 덩어리만(더듬이·다리 없음), 여우는 흰 면, 잎은 큰 잎맥까지 번진다(헤드리스 1366·390 실측).
   그림 파일(<img src=*.svg> — 3-2 05/04 칸 속 결과 그림)도 같은 규칙을 받는다. 직접 그린 인라인 SVG 무대는 2.5px 그대로다.
   saturate(.4) — '알록달록' 같은 색 보기도 색 덩어리로 읽히지 않게. */
.es-lock img, .es-lock video, .es-lock canvas, .es-lock svg image{
  filter:blur(22px) saturate(.4) !important;
}

/* 할 일 한 줄 — 판 위에 겹쳐 선다.  짜임: p.es-lock-note(닻) > span.es-lock-track(길) > span.es-lock-tx(글 상자)
   p 는 **높이 0 의 닻**이다. 그래서
     · 판 위에 또렷이 선다(흐림은 판 자식에만 걸린다 — 이 줄은 판의 형제다),
     · 열 때 쪽 높이가 변하지 않는다(줄이 빠져도 아래 글이 밀려 올라가지 않는다 — 함께 보기 스크롤 맞춤에 이롭다),
     · inert 바깥이라 낭독기가 읽는다.
   판의 부모가 grid·flex 이면 es.js 가 block 흐름이 나올 때까지 올라가 **그 상자 앞**에 둔다 —
   grid 칸 하나를 차지하면 '사진 | 걸음 판' 같은 두 칸 배치가 잠긴 동안 무너진다(과학 3-1 0304 · 0407).
   글자색은 덮어쓰지 않는 잉크(--es-ink-abs) — 짙은 색면(.is-deep · .es-wrap-up) 안에서 --es-ink 가 흰색이 되어도 흰 상자 위에서 읽힌다. */
.es-lock-note{
  position:relative; z-index:3;
  height:0; margin:0; padding:0; border:0; overflow:visible;
  max-width:none !important;          /* 본문 p 의 글 폭 상한이 닻을 좁히지 않게 — 가운데가 판 가운데여야 한다 */
}
/* 길 = 판과 **같은 자리·같은 크기**의 투명한 상자. --es-lock-dx/dy/w/h 는 es.js 가 판을 재서 넣는다
   (닻에서 판까지 거리 · 판 폭 · 판 높이). 글 상자는 이 길 안에서만 sticky 로 따라 내려온다.
   값이 없으면(못 쟀을 때) 닻 자리에 닻 폭으로 — 판 바로 앞에 선 보통의 경우와 같은 자리다(따라오기만 없다). */
.es-lock-track{
  position:absolute; display:block;
  top:var(--es-lock-dy, 0px); left:var(--es-lock-dx, 0px);
  width:var(--es-lock-w, 100%); height:var(--es-lock-h, auto);
  pointer-events:none;
}
/* 글 상자 — 판 머리 20px 아래 · 판 가운데에서 시작한다.
   2026-10-08 반증: 긴 판(3-1 01/02 964px · 01/08 1,122px · 3-2 07/03 390 에서 1,200px)을 내려 읽으면 상자가 위로 사라지고
   흐린 판만 남았다. 그래서 **sticky** — 판이 화면에 있는 동안 띠(.es-top, 높이는 es.js 가 --es-top-h 로) 바로 아래에 붙어
   따라오고, 판 끝에서 멈춘다(길 = 판 높이라 판 밖으로 나가지 않는다). JS 스크롤 감시가 아니라 CSS 라 끊기지 않는다.
   조상 가운데 스크롤 상자가 없어야 붙는다 — 잠금 23쪽 모두 조상은 .es-main(overflow-x:clip — 스크롤 상자가 아니다)뿐이다.
   붙지 못하는 곳에서는 옛 자리(판 머리 20px 아래)에 그대로 선다. */
.es-lock-tx{
  position:sticky; top:calc(var(--es-top-h, 0px) + 8px);
  display:block;
  width:max-content; max-width:calc(100% - 2 * var(--es-sp-2));
  margin:var(--es-sp-3) auto 8px;
  box-sizing:border-box;
  padding:12px var(--es-sp-3);
  background:#fff; border:3px solid var(--es-line-2); border-radius:var(--es-r);
  box-shadow:0 6px 18px rgba(20,32,46,.18);
  font-size:var(--es-fs-lg); font-weight:800; line-height:1.4; color:var(--es-ink-abs);
  text-align:center;
}
/* 좁은 화면 — 글자는 본문 크기(19px)로, 안쪽 여백은 줄인다. 본문 20px 하한(파일 머리)은 760 이하 본문 19px 규칙을 그대로 따른다. */
@media (max-width:760px){
  .es-lock-tx{ font-size:var(--es-fs); padding:8px 14px; }
}
/* 낮은 판 — es.js 가 판 높이 200px 미만이면 닻에 .is-short 를 단다. 3-1 01/01 무대는 390 에서 113px 라
   상자(두 줄 75px)가 흐린 미리보기의 61~78% 를 덮었다(2026-10-08 반증, 320~390). 판 머리에 바짝 붙이고
   글자를 작은 글 하한(--es-fs-sm 18px)으로, 여백·테두리를 줄여 390 에서 한 줄로 선다. */
.es-lock-note.is-short .es-lock-tx{
  margin-top:var(--es-sp-1); padding:4px 10px; border-width:2px;
  font-size:var(--es-fs-sm); line-height:1.3;
  max-width:calc(100% - 8px);
}

/* ── ㉓ 수평잡기 판 (esBalance) ────────────────────────────────────────────
   그림은 es.js 가 aria-hidden 으로 감춘다 — 기울기는 아래 결과 줄이 글자로 말한다.
   그래서 그림 안에는 **누를 것이 하나도 없고**, 좁은 화면에서 작아져도 손 자리가 줄지 않는다. */
.es-balance{ max-width:var(--es-content); margin:0 0 var(--es-sp-3); }
.es-balance-fig{
  display:flex; flex-direction:column; align-items:center;
  margin:var(--es-sp-3) 0 0; padding:var(--es-sp-4) var(--es-sp-2) var(--es-sp-2);
  background:var(--es-tint-2); border:3px solid var(--es-line); border-radius:var(--es-r-lg);
}
.es-balance-beam{
  display:flex; align-items:flex-end; justify-content:center;
  width:min(100%, 620px);
  border-bottom:10px solid var(--es-deep); border-radius:var(--es-r-pill);
  transform:rotate(var(--es-bal-deg, 0deg)); transform-origin:50% 100%;
  transition:transform .35s ease;
}
.es-balance-arm{ display:flex; align-items:flex-end; flex:1 1 0; min-width:0; gap:4px; }
/* 받침에서 가까운 칸(첫째)이 안쪽에 오도록 왼팔만 되짚는다 */
.es-balance-arm.is-l{ flex-direction:row-reverse; justify-content:flex-start; }
.es-balance-arm.is-r{ justify-content:flex-start; }
/* 접시가 하나뿐인 팔(= data-mode="same")은 막대 **끝**에 달린다 — 실물 양팔저울이 그렇다.
   칸이 여럿인 move 모드는 위 flex-start 그대로 — 첫째 칸이 받치는 곳 곁에 와야 뜻이 맞는다. */
.es-balance-arm:not(:has(.es-balance-cup + .es-balance-cup)){ justify-content:flex-end; }
.es-balance-cup{
  display:flex; flex-direction:column; align-items:center; gap:3px;
  flex:0 1 auto; min-width:0; padding:0 2px 6px;
}
.es-balance-hold{
  display:flex; flex-wrap:wrap; align-items:flex-end; justify-content:center; gap:4px;
  min-width:56px; min-height:56px; padding:5px;
  background:var(--es-surface); border:3px solid var(--es-line-2);
  border-radius:var(--es-r-sm) var(--es-r-sm) var(--es-r-lg) var(--es-r-lg);
  /* 접시는 늘 수평이다 — 막대가 기울어도 물건이 쏟아져 보이지 않게 되돌려 세운다 */
  transform:rotate(calc(-1 * var(--es-bal-deg, 0deg)));
  transition:transform .35s ease;
}
.es-balance-chip{ font-size:28px; line-height:1; }
.es-balance-cup-t{ font-size:var(--es-fs-src); font-weight:800; color:var(--es-ink-2); white-space:nowrap; }
.es-balance-side{
  align-self:flex-end; flex:0 0 auto; margin:0 2px 6px;
  padding:3px 12px; border-radius:var(--es-r-pill); white-space:nowrap;
  background:var(--es-tint); border:2px solid var(--es-edge); color:var(--es-deep);
  font-size:var(--es-fs-sm); font-weight:800;
}
.es-balance-pivot{
  align-self:flex-end; flex:0 0 auto; margin:0 6px -15px;
  width:20px; height:20px; border-radius:50%; background:var(--es-deep-2);
}
.es-balance-stand{
  width:0; height:0;
  border-left:30px solid transparent; border-right:30px solid transparent;
  border-bottom:46px solid var(--es-deep-2);
}
.es-balance-out{
  margin:var(--es-sp-3) 0 0; padding:var(--es-sp-3);
  background:var(--es-tint); border-left:10px solid var(--es-deep);
  border-radius:var(--es-r-sm);
  font-size:var(--es-fs-lg); font-weight:800; max-width:var(--es-mid);
}
.es-balance-pick{
  margin:var(--es-sp-3) 0 0; padding:var(--es-sp-3);
  background:var(--es-tint-2); border:3px solid var(--es-edge); border-radius:var(--es-r);
  max-width:var(--es-content);
}
.es-balance-pick-h{ margin:0; font-size:var(--es-fs-lg); font-weight:800; }

/* ── ㉔ 저울 (esScale) ─────────────────────────────────────────────────────
   그림도 aria-hidden 이다 — 잰 수는 아래 결과 줄이 말한다(같은 수를 두 번 읽지 않는다). */
.es-scale{ max-width:var(--es-content); margin:0 0 var(--es-sp-3); }
.es-scale-fig{
  margin:var(--es-sp-3) 0 0; padding:var(--es-sp-3);
  background:var(--es-tint-2); border:3px solid var(--es-line); border-radius:var(--es-r-lg);
  /* es.js 가 인라인으로 덮어쓴다. 여기 값은 스크립트가 못 돌 때의 **0 g 모습**이다 */
  --es-scale-t:0;
  --es-scale-run:150px;    /* 용수철이 늘어나는 최대 길이 */
  --es-scale-tick:10%;     /* 50 g 이 눈금자 높이에서 차지하는 몫 */
}
.es-scale-fig.is-digital{ display:flex; flex-direction:column; align-items:center; gap:var(--es-sp-3); }
.es-scale-fig.is-spring{
  display:grid; grid-template-columns:auto auto; justify-content:center;
  align-items:start; gap:var(--es-sp-3) var(--es-sp-4);
}
.es-scale-pan{
  display:flex; align-items:flex-end; justify-content:center;
  min-width:180px; min-height:76px; padding:8px 14px;
  background:var(--es-surface); border:3px solid var(--es-line-2);
  border-radius:var(--es-r-sm) var(--es-r-sm) 5px 5px;
}
.es-scale-hold{ display:flex; flex-wrap:wrap; align-items:flex-end; justify-content:center; gap:6px; }
.es-scale-chip{ line-height:1; }
.es-scale-read{
  display:inline-flex; align-items:baseline; justify-content:center; gap:6px;
  min-width:158px; padding:10px 18px; border-radius:var(--es-r-sm);
  background:var(--es-deep-2); color:#fff;
  font-variant-numeric:tabular-nums;
}
.es-scale-read b{ font-size:40px; font-weight:800; line-height:1.1; }
.es-scale-read .u{ font-size:22px; font-weight:800; }
/* 넘침은 **수 대신 '—'** 를 보이고 결과 줄이 까닭을 말한다. 색은 거들 뿐이다(1.4.1) */
.es-scale-fig.is-over .es-scale-read{ background:var(--es-no); }
.es-scale-fig.is-spring .es-scale-read{ grid-column:1 / -1; justify-self:center; }
/* 눈금자 — 50 g 마다 한 줄. data-max 가 달라지면 --es-scale-tick 이 달라진다.
   ⚠️ **자처럼 보여야 한다.** 처음엔 눈금을 칸 전체에 깔았더니 브라우저에서 용수철과 똑같은
      사다리 둘로 보였다(3학년이 둘을 가를 수 없다). 눈금은 왼쪽 60% 에만 긋는다. */
.es-scale-track{
  position:relative; width:46px; height:var(--es-scale-run);
  /* 위 여백 = 걸이(8px) + 늘어나지 않은 용수철(40px). 그래야 0 g 의 눈금과 접시가 나란하다 */
  margin-top:48px;
  background-color:var(--es-surface);
  background-image:repeating-linear-gradient(to bottom,
    var(--es-line-2) 0 2px, transparent 2px var(--es-scale-tick));
  background-size:60% 100%; background-repeat:no-repeat;
  border:3px solid var(--es-line-2); border-radius:var(--es-r-sm);
}
/* 바늘은 눈금자 밖으로 **접시 쪽까지** 뻗어 어디를 가리키는지 보이게 한다 */
.es-scale-needle{
  position:absolute; left:-6px; right:-26px; height:6px; margin-top:-3px;
  top:calc(var(--es-scale-t) * 100%);
  background:var(--es-vivid); border-radius:3px;
  transition:top .3s ease;
}
.es-scale-hang{ display:flex; flex-direction:column; align-items:center; }
/* 걸이 — 용수철이 여기 매달린다 */
.es-scale-hang::before{
  content:""; display:block; width:62px; height:8px;
  background:var(--es-deep); border-radius:4px;
}
/* 용수철은 무게만큼 **늘어난다** — 접시는 그만큼 내려간다.
   빗금(감긴 모양)으로 그려 위 눈금자의 가로줄과 한눈에 갈린다. */
.es-scale-coil{
  display:block; width:26px;
  height:calc(40px + var(--es-scale-t) * var(--es-scale-run));
  background:repeating-linear-gradient(-72deg,
    var(--es-line-2) 0 3px, transparent 3px 11px);
  transition:height .3s ease;
}
.es-scale-out{
  margin:var(--es-sp-3) 0 0; padding:var(--es-sp-3);
  background:var(--es-tint); border-left:10px solid var(--es-deep);
  border-radius:var(--es-r-sm);
  font-size:var(--es-fs-lg); font-weight:800; max-width:var(--es-mid);
}

/* ── 물건 카드 — 수평잡기와 저울이 같은 모양을 쓴다(문법이 같으니 모양도 같다) ── */
.es-balance-tray, .es-scale-tray{
  display:grid; gap:var(--es-gap);
  grid-template-columns:repeat(auto-fit, minmax(min(100%, 160px), 1fr));
  margin:var(--es-sp-3) 0 0;
}
.es-balance-item, .es-scale-item{
  display:flex; flex-direction:column; align-items:center; gap:4px;
  min-height:96px; padding:12px 10px;
  background:var(--es-surface); color:var(--es-ink);
  border:3px solid var(--es-line-2); border-radius:var(--es-r);
  box-shadow:0 4px 0 var(--es-line);
  font:inherit; font-size:var(--es-fs-sm); font-weight:800; cursor:pointer;
  transition:transform .16s ease, box-shadow .16s ease, border-color .16s ease,
             background-color .18s ease;
}
.es-balance-item .em, .es-scale-item .em{ font-size:34px; line-height:1.1; }
.es-balance-item .tx, .es-scale-item .tx{ line-height:1.3; }
.es-balance-item .st, .es-scale-item .st{
  font-size:var(--es-fs-src); font-weight:800; color:var(--es-ink-2);
}
.es-balance-item:hover, .es-scale-item:hover{
  transform:translateY(-3px); border-color:var(--es-deep);
  box-shadow:0 7px 0 var(--es-line), 0 14px 24px -16px var(--es-deep);
}
.es-balance-item:active, .es-scale-item:active{ transform:translateY(3px); box-shadow:0 1px 0 var(--es-line); }
/* 올려 둔 것 — 색 + 테두리 + ✔ 글자를 함께 쓴다 */
.es-balance-item.is-on, .es-scale-item.is-on{
  background:var(--es-tint); border-color:var(--es-deep); box-shadow:0 4px 0 var(--es-edge);
}
.es-balance-item.is-on .st, .es-scale-item.is-on .st{ color:var(--es-deep); }
.es-balance-item.is-on .st::before, .es-scale-item.is-on .st::before{ content:"✔ "; }

/* ── ㉕ 힘 막대 (esForce) — 숫자도 화살표도 없다. 길이와 낱말뿐이다 ────────── */
.es-force{ max-width:var(--es-mid); margin:var(--es-sp-3) 0; }
.es-force-top{
  display:flex; align-items:baseline; flex-wrap:wrap; gap:var(--es-sp-2);
  margin:0 0 6px;
}
.es-force-name{ font-size:var(--es-fs-sm); font-weight:800; color:var(--es-ink-2); }
.es-force-word{ font-size:var(--es-fs-lg); font-weight:800; color:var(--es-deep); }
.es-force-bar{
  height:30px; overflow:hidden;
  background:var(--es-surface);
  border:3px solid var(--es-line-2); border-radius:var(--es-r-pill);
}
/* 채운 자리를 **무늬로도** 알린다 — 색이 안 보이는 화면에서도 어디까지인지 보인다 */
.es-force-bar > i{
  display:block; width:0; height:100%;
  background-color:var(--es-vivid);
  background-image:repeating-linear-gradient(135deg,
    rgba(255,255,255,.30) 0 9px, rgba(255,255,255,0) 9px 18px);
  border-radius:inherit;
  transition:width .3s ease;
}
/* 짝지은 두 막대는 바싹 붙여 **길이를 눈으로 견주게** 한다 */
.es-force.is-pair{ margin:0 0 var(--es-sp-2); }
.es-force-cmp{
  margin:var(--es-sp-2) 0 0; padding:10px var(--es-sp-3);
  background:var(--es-tint); border-left:10px solid var(--es-deep);
  border-radius:var(--es-r-sm);
  font-size:var(--es-fs); font-weight:800; max-width:var(--es-mid);
}
.es-force-cmp:empty{ display:none; }

/* ── 움직임 줄이기 — 22절 전역 감속이 **끄지 못하는 자리** 하나 ───────────────
   22절(1631행)의 `*` 규칙은 **전환 시간**만 0 으로 만든다. 그래서 누를 때 2~3px
   내려앉는 것이 사라지지 않고 '순간 이동' 으로 남는다. 22절은 그 때문에 옛 부품들을
   이름 대어 `transform:none` 으로 한 번 더 못 박았는데, 그 목록은 이름으로 적혀 있어
   새 이름 넷에 닿지 않는다.
   ⚠️ **전역 목록에 새 이름을 끼워 넣지 않는다** — 그 줄은 배포된 사회 네 권이 쓰는 줄이다.
      같은 일을 새 선택자에만 하는 블록을 여기에 따로 둔다(더하기만 한다). */
@media (prefers-reduced-motion: reduce){
  .es-guess-opt:hover, .es-guess-opt:active,
  .es-balance-item:hover, .es-balance-item:active,
  .es-scale-item:hover, .es-scale-item:active{ transform:none !important; }
}

/* ── 좁은 화면 (390 세로) ─────────────────────────────────────────────────
   그림에는 누를 것이 없으므로 줄여도 손 자리가 줄지 않는다. 물건 카드는 그대로 크게 둔다. */
@media (max-width:760px){
  .es-guess-opts{ grid-template-columns:1fr; }
  .es-balance-tray, .es-scale-tray{ grid-template-columns:repeat(auto-fit, minmax(128px, 1fr)); }
  .es-balance-fig{ padding:var(--es-sp-4) 4px var(--es-sp-2); }
  .es-balance-hold{ min-width:44px; min-height:48px; padding:3px; border-width:2px; }
  .es-balance-chip{ font-size:22px; }
  .es-balance-side{ font-size:var(--es-fs-src); padding:2px 8px; margin:0 0 6px; }
  .es-balance-pivot{ width:16px; height:16px; margin:0 3px -13px; }
  .es-balance-stand{ border-left-width:24px; border-right-width:24px; border-bottom-width:38px; }
  .es-scale-read b{ font-size:32px; }
  .es-scale-pan{ min-width:150px; }
  .es-scale-fig.is-spring{ gap:var(--es-sp-2) var(--es-sp-3); }
}

/* ── 인쇄 — 조작 단추는 빼고, 지금 화면에 남은 **결과 글**만 종이에 남긴다 ── */
@media print{
  .es-guess-opts, .es-balance-tray, .es-balance-pick, .es-scale-tray{ display:none !important; }
  .es-guess-out, .es-balance-out, .es-scale-out, .es-force-cmp, .es-lock-tx{
    background:#fff !important; color:#000 !important; border-color:#666 !important;
  }
  /* 종이에서는 겹쳐 띄우지 않는다 — 판이 빠진 자리 위에 한 줄로 그대로 남는다 */
  .es-lock-note{ height:auto; }
  .es-lock-track{ position:static; width:auto; height:auto; }
  .es-lock-tx{ position:static; transform:none; display:block; width:auto; max-width:none; margin:0; box-shadow:none; }
  .es-balance-fig, .es-scale-fig, .es-force-bar{
    background:#fff !important; box-shadow:none; break-inside:avoid;
  }
  .es-scale-read{ background:#fff !important; color:#000 !important; border:1px solid #666; }
  .es-force-bar > i{ background-color:#666 !important; }
  /* 잠긴 자리는 종이에서도 잠긴 채다 — 답이 먼저 찍히지 않게 */
  .es-lock{ display:none !important; }
}


/* ============================================================================
   31. 12판 부품 — .es-sound(소리 단추판 · NW1) · esTrial 의 소리 켜기(NW2) · 떨림 .es-trem
   ----------------------------------------------------------------------------
   (2026-09-29 · 초등 과학 3-2 리드 결정 38 · 39 · SPEC 6-2)

   ⚠️ **번호는 31 인데 30절 앞에 둔다.** es.shared.test.mjs 17-ⓕ 가 30절 첫 규칙(.es-sort-bin-name)부터
      **파일 끝까지**를 30절로 세고 '새 이름(.es-trial · .es-build · …)만 있는가' 를 본다 — 30절 뒤에 붙이면
      이 절의 새 이름이 '기존 선택자를 다시 정의했다' 로 읽힌다(그 시험은 고치지 않는다). 옛 규칙과 겹치는
      선택자가 하나도 없으므로 차례는 뜻이 없다. 이 절의 계약은 19-ⓚ 가 따로 센다.
   ⚠️ **여기서도 기존 선택자를 하나도 다시 정의하지 않는다.** 전부 새 이름이다(`.es-sound*` · `.es-trem` —
      초등 트리 grep 0건). 떨림 방향 `is-vert` · `is-anti` 도 새 조각이고 `.es-trem` 과 **함께일 때만** 뜻이 있다.
      꺼짐 표시 `is-off` 는 쇼츠 음악 단추와 **같은 뜻**으로 `.es-sound-gate` 에만 건다.

   함께 지키는 것:
     · 누르는 것은 56px 이상(--es-tap · 켜기 단추만 곁들이 48px — 쇼츠 음악 단추와 같다). 끌기가 없다.
     · **색만으로 알리지 않는다**(1.4.1) — 꺼짐은 점선 + 글('🔇 소리 켜기'), 울림은 굵은 테두리 + 〰 글자,
       세기는 막대 **폭** + 글, 높낮이는 계단의 **점 자리** + 글. 두 성질을 다른 모양 · 다른 자리로 그린다.
     · z-index 를 쓰지 않는다(겹치는 층이 없다 · 99998 아래 규칙).
     · 떨림은 한 번 오가는 데 0.35초 이상(1초에 3번 아래 — 2.3.1)이고, **울리는 동안만**(8초 안) 돈다.
       멈춤 단추가 늘 곁에 선다(2.2.2). 움직임 줄이기에서는 es.js 가 떨림을 **만들지 않고**, 아래 reduce 블록이 한 번 더 끈다.
   ────────────────────────────────────────────────────────────────────────── */
.es-sound{ max-width:var(--es-content); margin:0 0 var(--es-sp-3); }
/* 판 맨 위 — 귀를 지키는 한 줄과 켜기. 조용한 면에 둔다(판의 주인은 소리 단추다) */
.es-sound-top{
  margin:0 0 var(--es-sp-3); padding:var(--es-sp-2) var(--es-sp-3);
  background:var(--es-soft); border:3px solid var(--es-line); border-radius:var(--es-r);
  max-width:var(--es-mid);
}
.es-sound-safe{ margin:0 0 8px; font-size:var(--es-fs-sm); font-weight:800; color:var(--es-ink); max-width:none; }
.es-sound-row{ display:flex; flex-wrap:wrap; align-items:center; gap:8px var(--es-gap); }
.es-sound-gate{ white-space:nowrap; }
.es-sound-gate.is-off{ border-style:dashed; }
.es-sound-tip{ font-size:var(--es-fs-sm); font-weight:700; color:var(--es-ink-2); }
.es-sound-note{
  margin:var(--es-sp-2) 0 0; max-width:var(--es-mid);
  font-size:var(--es-fs-sm); font-weight:700; color:var(--es-ink-2);
}
.es-sound-note:empty{ display:none; }
.es-sound-top .es-sound-note{ margin:8px 0 0; }

/* 소리 단추 — 넓으면 두세 칸, 좁으면 한 줄에 하나.
   글이 주인인 상자 폭(--es-mid)까지만 — 단추 하나짜리 판(소리굽쇠)이 1366 에서 1100px 띠가 되지 않게(실제 크롬으로 보고 잡았다) */
.es-sound-pads{
  display:grid; gap:var(--es-gap); margin:0 0 var(--es-sp-2); max-width:var(--es-mid);
  grid-template-columns:repeat(auto-fit, minmax(min(100%, 240px), 1fr));
}
.es-sound-cell{ display:flex; flex-direction:column; gap:8px; min-width:0; }
.es-sound-pad{
  display:flex; align-items:center; justify-content:center; gap:10px;
  min-width:var(--es-tap); min-height:var(--es-tap); padding:14px 18px;
  background:var(--es-surface); color:var(--es-ink);
  border:3px solid var(--es-line-2); border-radius:var(--es-r);
  box-shadow:0 4px 0 var(--es-line);
  font:inherit; font-size:var(--es-fs-btn); font-weight:800; line-height:1.35; cursor:pointer;
  transition:transform .16s ease, box-shadow .16s ease, border-color .16s ease,
             background-color .18s ease;
}
.es-sound-pad:hover{
  transform:translateY(-3px); border-color:var(--es-deep);
  box-shadow:0 7px 0 var(--es-line), 0 14px 24px -16px var(--es-deep);
}
.es-sound-pad:active{ transform:translateY(3px); box-shadow:0 1px 0 var(--es-line); }
/* 울리는 동안 — 테두리가 굵어지고(6px) 〰 글자가 선다. 안쪽 여백을 그만큼 줄여 단추 크기는 그대로다 */
.es-sound-pad.is-ringing{
  border-width:6px; border-color:var(--es-deep); padding:11px 15px;
  background:var(--es-tint-2);
}
.es-sound-wave{ display:none; font-size:24px; line-height:1; color:var(--es-deep); }
.es-sound-pad.is-ringing .es-sound-wave{ display:inline; }
.es-sound-still{ margin:0; font-size:var(--es-fs-sm); font-weight:800; color:var(--es-deep); max-width:none; }

/* 소리 카드 — 처음 누른 뒤에 뜬다. 소리를 꺼 두어도 뜬다(눈으로 가는 길) */
.es-sound-card{
  display:flex; flex-direction:column; gap:6px;
  padding:10px 14px;
  background:var(--es-tint-2); border:2px solid var(--es-edge); border-radius:var(--es-r-sm);
}
.es-sound-loud, .es-sound-high{
  display:flex; align-items:center; flex-wrap:wrap; gap:6px 10px;
  margin:0; max-width:none; line-height:1.4;
}
.es-sound-k{ min-width:3.4em; font-size:var(--es-fs-src); font-weight:700; color:var(--es-ink-2); }
.es-sound-em{ font-size:24px; line-height:1; }
.es-sound-w{ font-size:var(--es-fs); font-weight:800; color:var(--es-ink); }
/* 세기 — 가로 막대의 **폭**. 채운 자리는 무늬로도 알린다(힘 막대와 같은 문법) */
.es-sound-meter{
  flex:1 1 80px; max-width:160px; height:18px; overflow:hidden;
  background:var(--es-surface); border:2px solid var(--es-line-2); border-radius:var(--es-r-pill);
}
.es-sound-meter > i{
  display:block; height:100%; width:0;
  background-color:var(--es-vivid);
  background-image:repeating-linear-gradient(135deg,
    rgba(255,255,255,.30) 0 7px, rgba(255,255,255,0) 7px 14px);
}
/* 높낮이 — 세 칸 계단(늘 같은 모양)과 그 위 **점 자리**. 막대 높이로 그리지 않는다(세기와 섞인다) */
.es-sound-stair{ display:inline-flex; align-items:flex-end; gap:4px; height:44px; padding-top:14px; }
.es-sound-stair > i{
  position:relative; display:block; width:22px;
  background:var(--es-surface); border:2px solid var(--es-line-2); border-bottom-width:3px;
  border-radius:4px 4px 0 0;
}
.es-sound-stair > i:nth-child(1){ height:10px; }
.es-sound-stair > i:nth-child(2){ height:20px; }
.es-sound-stair > i:nth-child(3){ height:30px; }
.es-sound-stair > i.is-at{ border-color:var(--es-deep); }
.es-sound-stair > i.is-at::after{
  content:""; position:absolute; left:50%; top:-14px;
  width:12px; height:12px; margin-left:-6px; border-radius:50%;
  background:var(--es-deep);
}

/* 멈춤 — 울리는 동안만(es.js 가 hidden 을 푼다). 활동 단추 크기(56px) 그대로 */
.es-sound-stop{ margin:0 0 var(--es-sp-2); }
/* 진짜와 다른 점 — 교실로 돌려보내는 한 줄과 같은 모양(esTrial data-note) */
.es-sound-said{
  margin:var(--es-sp-2) 0 0; padding:12px var(--es-sp-3);
  background:var(--es-soft); border:3px dashed var(--es-line-2); border-radius:var(--es-r);
  font-size:var(--es-fs-sm); font-weight:700; color:var(--es-ink-2);
  max-width:var(--es-mid);
}

/* 떨림 — 떨릴 그림(`transform` **속성이 없는** 안쪽 <g>)에 es.js 가 울리는 동안만 붙였다 뗀다.
   기본은 가로, is-vert 는 위아래, is-anti 는 반대쪽(소리굽쇠 두 갈래 — 한쪽에만 적는다). */
.es-trem{ animation:es-trem-h var(--es-trem-t, .5s) ease-in-out infinite; }
.es-trem.is-vert{ animation-name:es-trem-v; }
.es-trem.is-anti{ animation-direction:reverse; }

/* ── 움직임 줄이기 — 떨림은 es.js 가 아예 안 붙이지만 한 번 더 끈다 · 누를 때 내려앉는 것도 끈다
      (22절 전역 목록은 옛 이름으로만 적혀 있어 새 이름에 닿지 않는다 — 29 · 30절과 같은 이유) */
@media (prefers-reduced-motion: reduce){
  .es-trem{ animation:none !important; }
  .es-sound-pad:hover, .es-sound-pad:active{ transform:none !important; }
}

/* ── 좁은 화면 (390 세로) ── */
@media (max-width:760px){
  .es-sound-pads{ grid-template-columns:1fr; }
  .es-sound-top{ padding:var(--es-sp-2); }
}

/* ── 인쇄 — 누를 것은 빼고 카드 · 안내만 남긴다 ── */
@media print{
  .es-sound-top, .es-sound-stop, .es-sound-wave{ display:none !important; }
  .es-sound-pad, .es-sound-card, .es-sound-said{
    background:#fff !important; color:#000 !important; border-color:#666 !important; box-shadow:none;
  }
  .es-trem{ animation:none !important; }
}


/* ============================================================================
   30. 10판 부품 셋 — .es-trial(+견주기) · .es-build · esSort 의 이름 칸
   ----------------------------------------------------------------------------
   (2026-09-24 · 초등 과학 3-1 원장 NW4 · NW9 · NW8 · NW5)

   ⚠️ **여기서도 기존 선택자를 하나도 다시 정의하지 않는다.** 전부 새 이름이다
      (`.es-trial*` · `.es-build*` · `.es-sort-bin-name` · `.es-sort-bin-hint` · `.es-sort-hint`
       — 사회 트리 grep 0건). 이름 칸과 보기 칩은 `.es-sort-bin-h` **안에 새로 생기는 자식**이라
      옛 규칙을 건드리지 않고 얹힌다. 초점 굵은 선은 3절의 전역 `:focus-visible` 이 그대로 그린다.
      (검증: _verify_es/es.shared.test.mjs 17-ⓕ 가 이 절의 규칙 머리를 전수로 센다)

   셋이 함께 지키는 것:
     · 누르는 것은 전부 **56px 이상**(--es-tap). 끌기가 없다(WCAG 2.5.7).
     · **색만으로 알리지 않는다**(1.4.1) — 연 칸에는 ✔, 견줄 칸으로 고른 것에는 ◉,
       안 고른 그림 자리에는 점선 네모와 **자리 이름 글자**가 함께 선다.
     · z-index 를 쓰지 않는다(겹치는 층이 없다 · 99998 아래 규칙).
     · 움직임은 0.16~0.3초 전환뿐이고, 누를 때 내려앉는 transform 은 이 절 끝의 감속 블록이 끈다
       (22절의 전역 목록은 **옛 이름으로만** 적혀 있어 새 이름에 닿지 않는다 — 29절과 같은 이유).
   ────────────────────────────────────────────────────────────────────────── */

/* ── esSort 의 이름 칸·보기 칩 (NW5) ───────────────────────────────────────
   칸 머리(.es-sort-bin-h)는 이름과 장 수를 양끝으로 미는 flex 다. 이름 칸이 그 왼쪽 자리를
   그대로 물려받아야 옛 판과 같은 모양이 된다 — 그래서 flex:1 1 auto 에 min-width:0 이다. */
.es-sort-bin-name{
  flex:1 1 auto; min-width:0;
  font:inherit; font-size:var(--es-fs-sm); font-weight:800; color:var(--es-ink-abs);
  background:var(--es-surface); border:3px solid var(--es-edge); border-radius:var(--es-r-sm);
  padding:10px 12px; min-height:48px;
}
.es-sort-bin-name::placeholder{ color:var(--es-ink-2); font-weight:700; }
.es-sort-bin-name:focus-visible{ outline:3px solid var(--es-focus); outline-offset:2px; }
.es-sort-bin-hint{ display:flex; flex-wrap:wrap; gap:8px; margin:0 0 var(--es-sp-2); }
/* 보기 칩 — **정답이 아니라 본보기다.** 그래서 강조색이 아니라 옅은 면에 점선으로 둔다 */
.es-sort-hint{
  min-height:44px; padding:8px 14px;
  background:var(--es-surface); color:var(--es-ink-2);
  border:2px dashed var(--es-line-2); border-radius:999px;
  font:inherit; font-size:var(--es-fs-src); font-weight:700; cursor:pointer;
  transition:transform .16s ease, border-color .16s ease, background-color .18s ease;
}
.es-sort-hint::before{ content:"\270E  "; }
.es-sort-hint:hover{ transform:translateY(-2px); border-color:var(--es-deep); background:var(--es-tint-2); }
.es-sort-hint:active{ transform:translateY(2px); }

/* ── 조건 두 칸 비교 (esTrial) ─────────────────────────────────────────────
   네 칸은 **처음부터 다 보인다** — 무엇을 견주는 판인지 한눈에 보여야 한다.
   잠긴 것은 결과뿐이고, 그 결과는 칸 **안**에서 열린다. 그래야 네 칸을 다 연 뒤
   네 결과가 화면에 나란히 남아 견주기 한 걸음이 설 수 있다. */
.es-trial{ max-width:var(--es-content); margin:0 0 var(--es-sp-3); }
.es-trial-grid{
  display:grid; gap:var(--es-gap); margin:0 0 var(--es-sp-3);
  grid-template-columns:repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
.es-trial-cell{
  display:flex; flex-direction:column; align-items:stretch; gap:6px;
  min-height:var(--es-tap); padding:14px 16px; text-align:left;
  background:var(--es-surface); color:var(--es-ink);
  border:3px solid var(--es-line-2); border-radius:var(--es-r);
  box-shadow:0 4px 0 var(--es-line);
  font:inherit; line-height:1.4; cursor:pointer;
  transition:transform .16s ease, box-shadow .16s ease, border-color .16s ease,
             background-color .18s ease;
}
.es-trial-cell:hover{
  transform:translateY(-3px); border-color:var(--es-deep);
  box-shadow:0 7px 0 var(--es-line), 0 14px 24px -16px var(--es-deep);
}
.es-trial-cell:active{ transform:translateY(3px); box-shadow:0 1px 0 var(--es-line); }
/* 조건 한 줄 — 이름은 작게 윗줄, 상태는 크게 아랫줄. 한 덩어리로 붙여 쓰면
   "온도 따뜻한 곳" 이 한 낱말처럼 읽힌다. 줄을 나누면 그대로 "온도: 따뜻한 곳" 으로 읽힌다. */
.es-trial-cond{ display:flex; flex-direction:column; }
.es-trial-cond .nm{ font-size:var(--es-fs-src); font-weight:700; color:var(--es-ink-2); }
.es-trial-cond .vl{ font-size:var(--es-fs-btn); font-weight:800; }
/* 연 칸은 옅은 면으로 물러나고, 결과 줄이 앞에 선다 */
.es-trial-cell[data-open="1"]{ background:var(--es-tint-2); border-color:var(--es-edge); }
.es-trial-out{
  display:block; margin:8px 0 0; padding:12px;
  background:var(--es-accent-soft); border-left:8px solid var(--es-accent-line);
  border-radius:var(--es-r-sm);
  font-size:var(--es-fs); font-weight:800; color:var(--es-accent);
}
.es-trial-out[hidden]{ display:none; }
/* ✔ 는 색을 못 보는 아이에게 '열렸다' 를 말하는 글자다(1.4.1) */
.es-trial-out .tx::before{ content:"\2714  "; }
.es-trial-out img{
  display:block; width:100%; height:auto; margin:0 0 8px;
  border-radius:var(--es-r-sm); border:2px solid var(--es-accent-line);
}
/* 고르기 모드(네 칸을 다 연 뒤) — 동그라미가 앞에 서서 고른 칸을 글자로도 말한다 */
.es-trial-cell.is-pickable{ border-style:dashed; }
.es-trial-cell.is-pickable::before{
  content:"\25CB  견주기"; font-size:var(--es-fs-src); font-weight:800; color:var(--es-ink-2);
}
.es-trial-cell.is-pickable[aria-pressed="true"]{
  border-style:solid; border-color:var(--es-accent-line);
  background:var(--es-accent-soft); box-shadow:0 4px 0 var(--es-accent-line);
}
.es-trial-cell.is-pickable[aria-pressed="true"]::before{
  content:"\25C9  골랐어요"; color:var(--es-accent);
}

/* 견주기 한 걸음 (NW9) — **판정판이 아니다.** 맞음/틀림 색(--es-ok/--es-no)을 쓰지 않는다 */
.es-trial-pair{
  margin:0 0 var(--es-sp-3); padding:var(--es-sp-3);
  background:var(--es-tint); border:3px solid var(--es-edge); border-radius:var(--es-r-lg);
  max-width:var(--es-mid);
}
.es-trial-pair[hidden]{ display:none; }
.es-trial-pair-ask{ margin:0 0 var(--es-sp-2); font-size:var(--es-fs-lg); font-weight:800; color:var(--es-deep); }
.es-trial-pair-out{ margin:0; font-size:var(--es-fs-lg); font-weight:800; color:var(--es-ink); }
.es-trial-pair-out:empty{ display:none; }
.es-trial-pair-rows{ list-style:none; margin:var(--es-sp-2) 0 0; padding:0; }
.es-trial-pair-rows li{
  background:var(--es-surface); border:2px solid var(--es-edge); border-left:8px solid var(--es-vivid);
  border-radius:var(--es-r-sm); padding:10px 12px; margin:0 0 8px;
  font-size:var(--es-fs-sm); font-weight:700;
}
/* 교실로 돌려보내는 한 줄(data-note) — 화면이 실물 관찰을 대신하지 않게 하는 자리다 */
.es-trial-said{
  margin:0 0 var(--es-sp-3); padding:12px var(--es-sp-3);
  background:var(--es-soft); border:3px dashed var(--es-line-2); border-radius:var(--es-r);
  font-size:var(--es-fs-sm); font-weight:700; color:var(--es-ink-2);
  max-width:var(--es-mid);
}

/* ── 조각을 골라 그림 완성 (esBuild) ───────────────────────────────────────
   그림판은 **아이가 옮기지 않는다** — 자리는 부품이 정하고 조각만 고른다.
   그래서 저장할 것이 조각 이름뿐이고, 되읽기가 완전하다(좌표를 저장하지 않는다). */
.es-build{ max-width:var(--es-content); margin:0 0 var(--es-sp-3); }
.es-build-art{
  display:flex; flex-wrap:wrap; justify-content:center; align-items:stretch; gap:var(--es-gap);
  margin:0 0 var(--es-sp-3); padding:var(--es-sp-4) var(--es-sp-3);
  background:var(--es-tint-2); border:3px solid var(--es-line); border-radius:var(--es-r-lg);
}
.es-build-art-cell{
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px;
  min-width:120px; min-height:120px; padding:12px;
  border-radius:var(--es-r); text-align:center;
}
.es-build-art-cell[data-on="0"]{ border:3px dashed var(--es-line-2); background:transparent; }
.es-build-art-cell[data-on="1"]{ border:3px solid var(--es-edge); background:var(--es-surface); }
.es-build-art-cell .em{ font-size:56px; line-height:1; }
.es-build-art-cell .nm{ font-size:var(--es-fs-sm); font-weight:800; color:var(--es-ink-2); }
.es-build-art-cell[data-on="1"] .nm{ color:var(--es-deep); }
.es-build-slot{ margin:0 0 var(--es-sp-3); }
.es-build-slot-h{ margin:0 0 8px; font-size:var(--es-fs-lg); font-weight:800; color:var(--es-deep); }
.es-build-items{
  display:grid; gap:var(--es-gap);
  grid-template-columns:repeat(auto-fit, minmax(min(100%, 180px), 1fr));
}
.es-build-item{
  display:flex; align-items:center; gap:10px;
  min-height:var(--es-tap); padding:12px 16px; text-align:left;
  background:var(--es-surface); color:var(--es-ink);
  border:3px solid var(--es-line-2); border-radius:var(--es-r);
  box-shadow:0 4px 0 var(--es-line);
  font:inherit; font-size:var(--es-fs-btn); font-weight:800; line-height:1.35; cursor:pointer;
  transition:transform .16s ease, box-shadow .16s ease, border-color .16s ease,
             background-color .18s ease;
}
.es-build-item::before{ content:"\25CB"; font-size:20px; line-height:1; color:var(--es-ink-2); }
.es-build-item .em{ font-size:28px; line-height:1; }
.es-build-item .tx{ flex:1 1 auto; }
.es-build-item:hover{
  transform:translateY(-3px); border-color:var(--es-deep);
  box-shadow:0 7px 0 var(--es-line), 0 14px 24px -16px var(--es-deep);
}
.es-build-item:active{ transform:translateY(3px); box-shadow:0 1px 0 var(--es-line); }
.es-build-item[aria-pressed="true"]{
  background:var(--es-accent-soft); border-color:var(--es-accent-line); color:var(--es-accent);
  box-shadow:0 4px 0 var(--es-accent-line);
}
.es-build-item[aria-pressed="true"]::before{ content:"\25C9"; color:var(--es-accent); }
.es-build-out{
  margin:0 0 var(--es-sp-2); padding:var(--es-sp-3);
  background:var(--es-accent-soft); border-left:10px solid var(--es-accent-line);
  border-radius:var(--es-r-sm);
  font-size:var(--es-fs-lg); font-weight:800; max-width:var(--es-mid);
}
.es-build-out:empty{ display:none; }

/* ── 움직임 줄이기 ────────────────────────────────────────────────────────
   22절의 전역 `*` 규칙은 transition-duration 만 0 으로 만든다. 누를 때 내려앉는 transform 은
   그대로 남아 '순간 이동' 이 되는데, 22절의 transform:none 목록은 **옛 이름으로만** 적혀 있다.
   ⚠️ 그 전역 목록에 새 이름을 끼워 넣지 않는다 — 그 줄은 배포된 사회 네 권이 쓰는 줄이다. */
@media (prefers-reduced-motion: reduce){
  .es-trial-cell:hover, .es-trial-cell:active,
  .es-build-item:hover, .es-build-item:active,
  .es-sort-hint:hover, .es-sort-hint:active{ transform:none !important; }
}

/* ── 좁은 화면 (390 세로) ─────────────────────────────────────────────── */
@media (max-width:760px){
  .es-trial-grid{ grid-template-columns:1fr; }
  .es-trial-cell{ padding:12px 14px; }
  .es-build-items{ grid-template-columns:1fr; }
  .es-build-art{ padding:var(--es-sp-3) var(--es-sp-2); }
  .es-build-art-cell{ min-width:104px; min-height:104px; padding:8px; }
  .es-build-art-cell .em{ font-size:44px; }
}

/* ── 인쇄 — 조작 단추는 빼고, 지금 화면에 남은 **결과 글**만 종이에 남긴다 ── */
@media print{
  .es-build-items{ display:none !important; }
  .es-trial-cell{ box-shadow:none; break-inside:avoid; }
  .es-trial-out, .es-trial-pair, .es-trial-pair-rows li, .es-build-out, .es-trial-said{
    background:#fff !important; color:#000 !important; border-color:#666 !important;
  }
  .es-trial-out[hidden]{ display:none !important; }
  .es-build-art{ background:#fff !important; break-inside:avoid; }
}
/* ════════════════════════════════════ ES2 시작 — v2(초등 재설계 2-나 E2) ════════════════════════════════════
   이 줄 위는 v1 — 초등학교3-4학년군/_assets/es.css @ master 8f62bedf 와 **바이트까지 같다**(116쪽이 그대로 쓴다. 한 글자도 고치지 않는다).
   이 줄 아래가 v2 — 정본은 _next/DESIGN_ES.md(모양) · _next/CONTRACT_ES.md(이름 · 문구) · _next/design/tokens.css(값). 두 문서와 다르게 짓지 않는다.
   ① 토큰 블록(==ES2-TOKENS-BEGIN/END== 사이) = design/tokens.css 그대로(첫 줄 @charset 만 뺀다 — 파일 맨 앞에서만 뜻이 있다). 손으로 고치지 않는다.
      토큰은 --es2-* 변수만 정의한다(:root · [data-hue] · [data-subject] · [data-band]) — v1 쪽 모양에 닿는 속성이 없다.
   ② v2 규칙은 전부 body.es-page 아래(+ TV 는 html.es-tv · JS 꺼짐은 html:not(.js) · 잠금은 html.js 를 앞에). es-page 는 v1 에 없는 이름이라
      v1 쪽 116쪽에는 한 줄도 닿지 않는다(계약 1-3). @keyframes · @counter-style 이름은 es2- 로 시작한다.
   ③ 배치는 클래스가 아니라 칸 이름(.es-predict · .es-scene · .es-log …)과 data-zone 으로 잡는다(계약 1-7-1). 상태는 es.js 가 다는 속성으로 읽는다
      (data-st · data-state · data-gate · data-busy · data-pressed · data-queued · data-pulse · data-fx · is-open · is-shown — E1 고정물 contract/fixtures/dom.es.html).
   시험: node wonedu/deploy/es_gen/_next/assets/es.css.test.mjs   (정적 셋 + 크롬 — 자세한 것은 그 파일 머리)
   ═════════════════════════════════════════════════════════════════════════════════════════════════════════ */
/* ==ES2-TOKENS-BEGIN== design/tokens.css (확정 2026-10-08) — 아래부터 ==ES2-TOKENS-END== 앞까지가 그 파일과 같다 */
/* ============================================================================
   tokens.css — 초등 디자인 체계 토큰 (2단계 2-가 · 2026-10-08)
   ----------------------------------------------------------------------------
   해설은 DESIGN_ES.md 2절. 이 파일은 **값만** 둔다 — 부품 모양은 2-나 공용 es.css 가 이 값을 써서 만든다.
   클래스 · 속성 이름은 CONTRACT_ES.md 가 정본이다(v2 쪽의 클래스는 v1 es.css · es.js 에 없는 이름만 — CONTRACT 1-3).
   확정 2026-10-08 · 대조 반영: 과목 키 moral → ethics(카드 id es34-ethics) · 과목 기본값을 중립 회색으로(없는 과목이 과학 하늘색으로 보이지 않게) · TV 띠 안쪽 85(전체 92).

   ── 지위 ──
   · 관문 ① 결정(2026-10-08 "c로 가라. 권고대로 진행해라.")에 따라 시안 c「실험 놀이터」의 값을 뼈대로 뽑았다.
     c 의 :root 변수는 5개뿐이고 나머지는 인라인 숫자였다(비교 쪽 ③ '손볼 것'). 그 숫자를 여기 한 곳으로 모았다.
   · 아직 어느 쪽도 이 파일을 부르지 않는다. 배포 경로 밖(wonedu/deploy/ — build.py 가 굽지 않는다)이다.
   · 정본 위치(DESIGN_ES 1-1): 2단계 동안 여기, 관문 ③ 에서 초등 공통 정본 한 벌로 옮긴다.

   ── 이름 ──
   · 접두사 --es2- = 재설계 '2세대' 체계(학년이 아니다). 지금 공용 es.css 의 --es-* 와 겹치지 않게 갈랐다 —
     옛 이름(--es-ink · --es-r …)은 116쪽이 쓰고 있어 같은 이름에 다른 값을 주면 조용히 모양이 바뀐다.
     옛 이름 → 새 토큰 대응은 DESIGN_ES 1-3 표. 새 쪽은 --es2-* 만 쓴다.

   ── 거는 자리 — 마크업 이름은 CONTRACT_ES.md 가 정본이다 ──
     <html lang="ko" class="js es-tv" data-band="34" data-subject="science">   ← js 는 head 인라인 한 줄(CONTRACT 1-2), es-tv 는 TV 수업 화면일 때만(CONTRACT 3-5 ES.tv)
     <body class="es-page" data-hue="sky">                                   ← 단원 색(CONTRACT 1-3 · 절 하나만 다르면 <section data-hue>)
     · 글자 크기 토큰이 --es2-zoom 을 곱해 **html 에서** 계산된다. es-tv · data-band 를 body 에 달면
       값이 이미 계산된 뒤라 바뀌지 않는다(사용자 정의 속성은 계산된 값으로 물려준다 — DESIGN_ES 1-2 실측).
     · data-band · data-subject 는 es.js 가 단다(CONTRACT 1-2): 주소 /es34-science/… 에서, 로컬 미리보기(/과학/…)면 폴더 이름 대응표에서.
       과목 키 = 카드 id 의 하이픈 뒤(es34-ethics → ethics). 이 파일에 없는 키면 아래 중립 기본값이 보인다.

   ── 대비 ──
   글자 쌍의 대비는 **손으로 적지 않는다.** contrast.py 가 이 파일의 값을 읽어 계산하고 DESIGN_ES 2-2 표를 다시 쓴다.
     py -3 contrast.py           # 표를 화면에 · 기준 미달이면 1
     py -3 contrast.py --write   # DESIGN_ES.md 의 표 자리를 다시 쓴다
   7:1 = 본문 글자 ↔ 그 글자의 바탕(SPEC 4절) · 4.5:1 = 큰 글자(24px 이상, 또는 18.66px 굵게)와 출처 · 3:1 = 글자 아닌 표시(테두리 · 초점 고리).
   ========================================================================== */

:root{
  /* ── 1. 중립 · 종이 ─────────────────────────────────────────────────────── */
  --es2-ink:          #17203A;   /* 본문 · 굵은 선 · 어두운 알약 바탕 (c --ink) */
  --es2-ink-2:        #36405F;   /* 보조 글 — 그래도 7:1 위 (c --ink2) */
  --es2-ink-hint:     #4D5568;   /* 입력 칸 자리표시 글('두 글자') — c 의 #8A93AD 는 흰 바탕 3:1 이라 못 읽었다 */
  --es2-ink-dim:      #3D4763;   /* 잠긴 조작의 이름 글(예고형 잠금: 무엇을 하게 될지는 읽힌다) */
  --es2-ink-credit:   #666C78;   /* 사진 출처 12px **전용**(SPEC 5절 2026-09-09 사용자 결정 — 작게 · 흐리게 · 밑줄 없음) */
  --es2-on-dark:      #FFFFFF;   /* 짙은 바탕 위 글자(어두운 알약 · 정거장 ✓ 점) */

  --es2-paper:        #FFF8EA;   /* 쪽 바탕(c --paper) */
  --es2-paper-top:    #FFF1B8;   /* 첫 화면 위 360px 의 단색 띠(c body 배경의 첫 칸 — 그라데이션이 아니라 끊어진 두 색) */
  --es2-paper-sun:    #FFE27A;   /* 첫 화면 왼쪽 해 동그라미(장식 · 물음 글자가 겹칠 수 있어 잰다) */
  --es2-paper-sky:    #BFE6FF;   /* 첫 화면 오른쪽 하늘 동그라미(장식) */
  --es2-fiber:        rgba(140,106,46,.10);   /* 종이 결의 올 색 — make_paper.py 의 FIBER · OPACITY 와 같다 */
  /* 종이 결 배경 한 장 — 필터 0 · 그라데이션 0 · 짧은 선 46 + 티 28 의 280px 타일. make_paper.py 가 만든다(손으로 고치지 않는다) */
  --es2-paper-grain: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22280%22 height=%22280%22 viewBox=%220 0 280 280%22%3E%3Cg fill=%22none%22 stroke=%22%238C6A2E%22 stroke-opacity=%220.1%22 stroke-linecap=%22round%22%3E%3Cpath d=%22M81.8 122.8Q105.4 121.5 128.8 118.2%22 stroke-width=%221.2%22/%3E%3Cpath d=%22M219.0 198.6Q234.8 198.6 250.5 199.6%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M66.4 279.5Q76.9 276.6 87.8 275.6%22 stroke-width=%221.5%22/%3E%3Cpath d=%22M113.6 129.9Q129.9 127.4 145.8 122.8%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M92.1 162.0Q110.4 158.5 129.1 159.0%22 stroke-width=%221.5%22/%3E%3Cpath d=%22M33.5 223.7Q46.0 220.5 59.0 220.9%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M54.0 30.0Q71.0 33.8 88.5 34.5%22 stroke-width=%221.5%22/%3E%3Cpath d=%22M23.2 226.5Q33.9 227.1 44.4 225.9%22 stroke-width=%221.2%22/%3E%3Cpath d=%22M187.2 20.6Q201.3 21.4 215.3 18.9%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M67.4 216.9Q86.3 215.0 105.3 216.3%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M68.7 155.7Q82.4 154.4 96.2 155.3%22 stroke-width=%221.2%22/%3E%3Cpath d=%22M254.4 149.0Q268.4 146.2 282.4 143.2%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M-25.6 149.0Q-11.6 146.2 2.4 143.2%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M98.4 3.5Q109.3 4.3 120.2 3.3%22 stroke-width=%221.2%22/%3E%3Cpath d=%22M274.4 58.8Q297.2 63.4 319.7 68.8%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M-5.6 58.8Q17.2 63.4 39.7 68.8%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M86.0 207.0Q106.3 209.1 126.1 213.9%22 stroke-width=%221.5%22/%3E%3Cpath d=%22M209.6 178.7Q224.4 175.4 239.6 176.1%22 stroke-width=%221.2%22/%3E%3Cpath d=%22M251.0 81.2Q248.7 91.9 250.6 102.7%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M173.4 160.0Q196.1 161.9 218.8 164.1%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M68.7 68.1Q87.3 68.3 105.7 70.6%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M133.0 211.9Q149.5 213.0 166.0 213.3%22 stroke-width=%221.5%22/%3E%3Cpath d=%22M204.1 133.3Q216.8 132.0 229.4 133.2%22 stroke-width=%221.2%22/%3E%3Cpath d=%22M184.3 237.4Q203.5 237.1 222.2 233.0%22 stroke-width=%221.5%22/%3E%3Cpath d=%22M44.8 94.2Q59.1 95.7 73.0 99.0%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M224.9 74.1Q223.1 91.8 218.4 109.0%22 stroke-width=%221.2%22/%3E%3Cpath d=%22M272.1 78.0Q284.6 74.0 297.8 74.3%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M-7.9 78.0Q4.6 74.0 17.8 74.3%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M112.0 125.8Q111.5 145.6 112.7 165.2%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M209.7 83.1Q230.8 81.6 251.9 79.8%22 stroke-width=%221.5%22/%3E%3Cpath d=%22M156.1 253.2Q170.7 253.5 185.3 253.2%22 stroke-width=%221.2%22/%3E%3Cpath d=%22M34.8 118.4Q49.4 116.5 63.8 118.6%22 stroke-width=%221.5%22/%3E%3Cpath d=%22M75.9 84.0Q94.9 84.6 113.6 87.8%22 stroke-width=%221.2%22/%3E%3Cpath d=%22M45.4 138.0Q57.4 136.2 69.4 134.6%22 stroke-width=%221.2%22/%3E%3Cpath d=%22M30.2 12.3Q48.7 9.5 67.3 10.5%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M49.3 221.7Q60.2 221.0 71.1 221.1%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M16.8 259.8Q39.0 254.8 61.8 253.5%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M203.0 14.7Q215.8 16.0 228.5 14.8%22 stroke-width=%221.5%22/%3E%3Cpath d=%22M238.4 13.2Q260.1 13.1 281.7 15.2%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M-41.6 13.2Q-19.9 13.1 1.7 15.2%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M177.2 25.1Q196.4 26.8 215.7 27.8%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M11.0 5.7Q32.1 9.3 52.8 14.4%22 stroke-width=%221.5%22/%3E%3Cpath d=%22M131.2 169.8Q143.5 170.4 155.7 168.1%22 stroke-width=%221.2%22/%3E%3Cpath d=%22M154.4 153.2Q174.4 158.4 194.7 162.0%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M184.8 43.6Q206.6 42.4 227.9 37.7%22 stroke-width=%221.2%22/%3E%3Cpath d=%22M84.8 86.0Q103.5 88.6 122.5 89.0%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M125.9 35.2Q138.5 33.3 151.3 34.9%22 stroke-width=%221.2%22/%3E%3Cpath d=%22M95.8 198.9Q107.3 196.0 119.0 194.2%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M6.7 257.6Q25.6 262.0 44.6 266.1%22 stroke-width=%220.9%22/%3E%3Cpath d=%22M191.4 267.2Q206.9 266.4 222.0 270.1%22 stroke-width=%220.9%22/%3E%3C/g%3E%3Cg fill=%22%238C6A2E%22 fill-opacity=%220.1%22%3E%3Ccircle cx=%22156.2%22 cy=%2293.9%22 r=%221.6%22/%3E%3Ccircle cx=%22129.9%22 cy=%22226.4%22 r=%221.6%22/%3E%3Ccircle cx=%22273.9%22 cy=%22239.4%22 r=%221.2%22/%3E%3Ccircle cx=%22142.4%22 cy=%22188.6%22 r=%221.6%22/%3E%3Ccircle cx=%22257.5%22 cy=%22187.6%22 r=%221.6%22/%3E%3Ccircle cx=%22212.9%22 cy=%22133.7%22 r=%221.6%22/%3E%3Ccircle cx=%2290.8%22 cy=%22126.9%22 r=%221.2%22/%3E%3Ccircle cx=%22170.5%22 cy=%22176.1%22 r=%221.2%22/%3E%3Ccircle cx=%22274.8%22 cy=%220.7%22 r=%221.6%22/%3E%3Ccircle cx=%22269.7%22 cy=%2261.2%22 r=%220.9%22/%3E%3Ccircle cx=%22244.7%22 cy=%22277.9%22 r=%220.9%22/%3E%3Ccircle cx=%22142.9%22 cy=%22136.8%22 r=%220.9%22/%3E%3Ccircle cx=%2260.5%22 cy=%2257.6%22 r=%221.2%22/%3E%3Ccircle cx=%22218.4%22 cy=%22264.2%22 r=%221.6%22/%3E%3Ccircle cx=%22236.7%22 cy=%2236.3%22 r=%220.9%22/%3E%3Ccircle cx=%22215.7%22 cy=%22132.6%22 r=%221.6%22/%3E%3Ccircle cx=%2216.3%22 cy=%22159.3%22 r=%221.2%22/%3E%3Ccircle cx=%2273.4%22 cy=%22178.8%22 r=%220.9%22/%3E%3Ccircle cx=%22108.1%22 cy=%22164.7%22 r=%221.2%22/%3E%3Ccircle cx=%2240.3%22 cy=%22104.0%22 r=%221.2%22/%3E%3Ccircle cx=%22169.9%22 cy=%22199.7%22 r=%221.2%22/%3E%3Ccircle cx=%22108.8%22 cy=%2227.8%22 r=%220.9%22/%3E%3Ccircle cx=%22154.6%22 cy=%22115.3%22 r=%221.6%22/%3E%3Ccircle cx=%2299.1%22 cy=%22227.6%22 r=%220.9%22/%3E%3Ccircle cx=%22251.8%22 cy=%22210.6%22 r=%221.6%22/%3E%3Ccircle cx=%22184.5%22 cy=%225.5%22 r=%221.2%22/%3E%3Ccircle cx=%2248.9%22 cy=%22253.1%22 r=%221.2%22/%3E%3Ccircle cx=%2259.1%22 cy=%22276.7%22 r=%221.2%22/%3E%3C/g%3E%3C/svg%3E");
  --es2-card:         #FFFFFF;   /* 절 카드 · 무대 틀 */
  --es2-panel:        #FFFDF6;   /* 단계판 · 문항 카드 · 개념 카드 안쪽(c .panel) */
  --es2-wall:         #E2F4EC;   /* 무대 장면의 벽(c --wall) */
  --es2-floor:        #F2C27F;   /* 무대 탁자(장식 — c stage.js 132행) */
  --es2-tip:          #FFFBE6;   /* 단계판의 '알아 두기' 칸(c .sg-tip) */
  --es2-cmp:          #F7F9FF;   /* 나란히 보기 판(c .sg-cmp) */
  --es2-dim:          #EEF1F6;   /* 잠긴 조작 바탕(예고형 잠금) */
  --es2-skeleton:     #E1E6F2;   /* 글줄 막대 — 아직 열리지 않은 결과 글의 자리(장식) */
  --es2-line-todo:    #7A84A0;   /* '아직' 칸의 점선 테두리(비텍스트 3:1 — c #8A93AD 는 흰 바탕 3.06 으로 문턱에 붙어 있었다) */
  --es2-focus:        #0B57D0;   /* 초점 고리(옛 --es-focus 그대로) */

  /* ── 2. 의미 색 — 과목과 상관없이 고정. 아이가 '노랑 = 다음에 누를 것' 을 한 번 배우면 끝 ── */
  --es2-sun:          #FFD43B;   /* 주 단추 · 지금 정거장 · 노란 띠(c --sun). 글자는 늘 --es2-ink */
  --es2-sun-soft:     #FFF0A8;   /* 강조 밑칠 · 낱말 칩 바탕(c --sun2) */
  --es2-sky:          #2F8FE0;   /* 물 · 고른 것의 고리 · 물음 낱말 밑줄(비텍스트 — 글자로 쓰지 않는다, 흰 바탕 3.4:1) */
  --es2-sky-soft:     #DCEFFF;   /* 고른 보기 · '해 보기' 갈래 바탕(c --skyS) */
  --es2-sky-deep:     #0B4A82;   /* 하늘색 글자가 필요할 때(b --water-ink) */
  --es2-ok:           #07553A;   /* 맞았어요 · 했어요 ✓ 점 — 흰 바탕 글자 / 흰 글자 바탕 둘 다(c --mintD) */
  --es2-ok-soft:      #EFFAF4;   /* 맞은 문항 카드 · 열린 예시 답안 바탕 */
  --es2-mint:         #C3EDD8;   /* 끝난 정거장 · '정리' 갈래 바탕(c --mint). 글자는 --es2-ink(--es2-ok 글자는 7:1 미달 — 쓰지 않는다) */
  --es2-again:        #6E3A00;   /* '다시 보러 가기' 글자 — 틀림을 빨강으로 말하지 않는다(c #7A4A00 은 바탕 위 6.8:1 이라 짙게) */
  --es2-again-soft:   #FFF3D1;   /* 다시 보기 · 확인 창 · 안전 상자 바탕 */
  --es2-danger:       #8E1F20;   /* 안전 글자(흰 바탕) — c --red #A3261A 는 안전 바탕 위 6.7:1 */
  --es2-danger-line:  #C92A2A;   /* 안전 상자 테두리(비텍스트 — b TV safe-strip) */
  --es2-stamp:        #C2331F;   /* 도장 테(비텍스트 · c stage.js 158행). 도장 글자는 --es2-danger */
  --es2-coral-soft:   #FFB3A3;   /* '확인' 갈래 바탕(c --coral) */
  --es2-grape-soft:   #E8DDFF;   /* '더 알아보기' 갈래 바탕(c --grape) */
  --es2-wood:         #D9A35E;   /* 나무 · 선반 · 바구니(장식 — c stage.js 18행) */

  /* 절 갈래 — 정거장 넷(CONTRACT 1-4 data-station 값 open · try · check · fin) + 더 알아보기(fin + data-explore). 글자는 전부 --es2-ink */
  --es2-k-open:       var(--es2-sun-soft);
  --es2-k-try:        var(--es2-sky-soft);
  --es2-k-check:      var(--es2-coral-soft);
  --es2-k-fin:        var(--es2-mint);
  --es2-k-more:       var(--es2-grape-soft);

  /* ── 3. 과목 색 · 단원 색 (아래 [data-subject] · [data-hue] 가 갈아 끼운다) ──
     deep = 흰 글자의 바탕이자 흰 바탕의 글자(둘 다 7:1) · mid = 테두리 · 막대 · 스티커 테(비텍스트 3:1) · soft = 띠 · 단원 줄 바탕(잉크 글자 7:1)
     과목 기본값은 **중립 회색**이다 — 아직 색 줄이 없는 과목(영어 · 체육 · 정보 …)이나 키가 틀린 쪽이 과학 하늘색으로 조용히 보이지 않게
     (대조 2026-10-08: 도덕 카드 id 가 es34-ethics 인데 키가 moral 이어서 도덕 쪽이 하늘색으로 나올 뻔했다). 단원 기본값은 sky 그대로. */
  --es2-subj-deep:    #36405F;   /* = --es2-ink-2 */
  --es2-subj-mid:     #7A84A0;   /* = --es2-line-todo */
  --es2-subj-soft:    #EEF1F6;   /* = --es2-dim */
  --es2-unit-deep:    #0B4A82;
  --es2-unit-mid:     #2F8FE0;
  --es2-unit-soft:    #DCEFFF;

  /* ── 4. 글자 — 본문 20 · 캡션 18 · TV 는 --es2-zoom 1.4 배(본문 28) ─────────── */
  --es2-font: "Pretendard Variable", Pretendard, system-ui, -apple-system, "Segoe UI", "Malgun Gothic", "Apple SD Gothic Neo", "Noto Sans KR", sans-serif;
  --es2-zoom:         1;
  --es2-fs-body:      calc(20px * var(--es2-zoom));   /* 본문(SPEC 4절 하한) */
  --es2-fs-lead:      calc(22px * var(--es2-zoom));   /* 절 머리 글 · 쓰기 물음 */
  --es2-fs-cap:       calc(18px * var(--es2-zoom));   /* 그림 설명 · 아이가 읽는 작은 말의 하한 */
  --es2-fs-label:     calc(17px * var(--es2-zoom));   /* 표지 칩 · 셈(0/6) · '확인 1' — 문장이 아닌 이름표만 */
  --es2-fs-credit:    12px;                            /* 사진 출처만(배율 없음 — TV 에는 출처를 크게 띄우지 않는다) */
  --es2-fs-btn:       calc(21px * var(--es2-zoom));   /* 단추 글자(c .btn) */
  --es2-fs-btn-lg:    calc(23px * var(--es2-zoom));   /* 제출하기 · 선생님께 보내기 */
  --es2-fs-h3:        calc(24px * var(--es2-zoom));
  --es2-fs-h2:        calc(30px * var(--es2-zoom));   /* 절 제목(c .sec-h h2) */
  --es2-fs-h1:        calc(34px * var(--es2-zoom));   /* 오늘의 물음(c .hero h1) */
  --es2-fs-say:       calc(20px * var(--es2-zoom));   /* 안내자 말풍선 */
  --es2-fw-body:      500;
  --es2-fw-strong:    800;
  --es2-fw-head:      900;
  --es2-lh-body:      1.62;   /* 본문(c body). WCAG 1.4.12 의 1.5 위. SPEC 4절의 1.8~2.0 은 근거 칸이 비어 있다 — DESIGN_ES 7절 */
  --es2-lh-tight:     1.3;    /* 단추 · 표지 · 짧은 줄 */
  --es2-lh-head:      1.25;
  --es2-measure:      560px;  /* 긴 문단의 글줄 폭(옛 --es-measure 그대로 — SPEC 4절 '바꾸지 않는다') */

  /* ── 5. 크기 · 간격 ─────────────────────────────────────────────────────── */
  --es2-tap:          calc(56px * var(--es2-zoom));   /* 누르는 것 최소(계획 4-7). TV 78 */
  --es2-tap-lg:       calc(64px * var(--es2-zoom));   /* 제출 · 보내기 · 이전/다음 */
  --es2-gap:          12px;   /* 누르는 것 사이 최소(계획 4-7). c 는 8~10px 인 곳이 여섯이었다 — DESIGN_ES 6절 */
  --es2-sp-1: 4px;  --es2-sp-2: 8px;  --es2-sp-3: 12px; --es2-sp-4: 16px;
  --es2-sp-5: 20px; --es2-sp-6: 24px; --es2-sp-7: 32px; --es2-sp-8: 44px;
  --es2-gutter:       24px;   /* 화면 가장자리 여백(c .wrap) — 860px 이하 16 */
  --es2-sec-gap:      44px;   /* 절 카드 사이(c .sec margin-top) — 860px 이하 32 */
  --es2-content:      1240px; /* 무대 · 절 카드 최대 폭(c .wrap) */
  --es2-band-h:       76px;   /* 띠 안쪽 높이(c .bar-in). 윗선(과목 색) 4 + 아랫선 3 을 더해 83 ≤ 88(계획 4-2 · 견본 실측) */
  --es2-icon:         34px;   /* 단추 안 그림 · 정거장 점 */
  --es2-guide:        84px;   /* 안내자 얼굴 폭(무대) — 860px 이하 56 · TV 118 */

  /* ── 6. 모서리 · 테두리(c 의 굵은 선) · 그림자 ─────────────────────────────── */
  --es2-r-xs:   8px;    /* 작은 표지(내 예상 · 답) */
  --es2-r-sm:   14px;   /* 해 본 칸 · 입력 칸 */
  --es2-r:      18px;   /* 단추 */
  --es2-r-md:   22px;   /* 단계판 · 문항 카드 · 개념 카드 */
  --es2-r-lg:   26px;   /* 절 카드 */
  --es2-r-xl:   34px;   /* 무대 틀 */
  --es2-r-pill: 999px;
  --es2-bw-1:   2px;    /* 흰 고리(✓ 점 · 답 표지) */
  --es2-bw:     3px;    /* 단추 · 카드 · 띠 아랫선 — c 의 기본 굵기 */
  --es2-bw-2:   4px;    /* 무대 틀 · 초점 고리 */
  --es2-bw-tv:  5px;    /* TV 카드(배율 대신 고정) */
  --es2-press:      4px;   /* 누르면 내려앉는 거리 */
  --es2-press-on:   3px;   /* 고른 채로 내려앉아 있는 거리 */
  --es2-sh-btn:     0 5px 0 var(--es2-ink);
  --es2-sh-btn-on:  0 2px 0 var(--es2-ink);
  --es2-sh-btn-act: 0 1px 0 var(--es2-ink);
  --es2-sh-card:    0 6px 0 rgba(23,32,58,.18);
  --es2-sh-stage:   0 10px 0 rgba(23,32,58,.20);
  --es2-sh-say:     0 4px 0 rgba(23,32,58,.20);
  /* 그림(SVG) 선 굵기 — 속성에 숫자로 쓴다. 그려진 크기에서 2~5px 이 되게(DESIGN_ES 2-4) */
  --es2-svg-line:   5;     /* 겉선 */
  --es2-svg-inner:  4;     /* 안쪽 선 */
  --es2-svg-fine:   3.5;   /* 잔선 · 아이콘 */

  /* ── 7. 움직임 ───────────────────────────────────────────────────────────── */
  --es2-motion:     1;        /* JS 가 읽는 한 곳: 0 이면 끝그림으로 바로(아래 reduce 블록) */
  --es2-t-press:    80ms;     /* 단추 내려앉기(c .btn) */
  --es2-t-quick:    180ms;    /* 안내자 표정 톡(c .g-face) */
  --es2-t-state:    300ms;    /* 색 · 고리 · 막대 길이 */
  --es2-t-pop:      450ms;    /* 해 본 칸 퐁(c @keyframes pop) */
  --es2-t-reveal:   500ms;    /* 열리는 글 올라오기(c fadeup) */
  --es2-t-peel:     700ms;    /* 스티커 붙기(c peel) */
  --es2-t-bars:     1000ms;   /* TV 반 분포 막대 · 콩 */
  --es2-t-react-max: 300ms;   /* 누른 뒤 무대 그림이 바뀌기 시작할 때까지 상한(계획 4-1 #2) */
  --es2-t-act-max:   3000ms;  /* 조작 한 번의 인과 그림이 끝까지 가는 상한(c 붓기 2.7초) */
  --es2-t-scene-max: 3000ms;  /* 첫 화면 장면 한 번 재생 상한(c opening 2.55초) */
  --es2-ease:       cubic-bezier(.45,0,.55,1);   /* 들고 · 옮기고 · 내려놓기(c ease = 2차 들고나기) */
  --es2-ease-in:    cubic-bezier(.11,0,.5,0);    /* 떨어지기(c easeIn) */
  --es2-ease-out:   cubic-bezier(.2,.9,.3,1);    /* 막대 차오르기(c TV .fill) */
  --es2-ease-pop:   cubic-bezier(.2,1.6,.4,1);   /* 붙기 · 찍기(c peel) — 한 번 넘쳤다 돌아온다 */

  /* ── 8. 겹침 층 · 고정 단추 자리 ─────────────────────────────────────────── */
  --es2-z-lock:  3;     /* 잠금 알약 — 흐린 판(형제)보다 위(0단계 es-lock-note 와 같은 까닭) */
  --es2-z-band:  30;    /* 띠(c .bar) */
  --es2-z-pop:   200;   /* 확인 창 · 크게 보기. 900 을 넘지 않는다(SPEC 1절 — 99998 이상은 진도 알약 · 함께 보기 · 챗봇 자리) */
  --es2-safe-br: 96px;  /* 오른쪽 아래: 챗봇 단추 60 + 띄움 24 + 여유 12(widget.js 214-215행) */
  --es2-safe-bl: 104px; /* 왼쪽 아래: 내 학습 알약(progress.js 648행) · 교사 함께 보기 단추(follow.js 266행 bottom 60) 위 + 여유 */
  --es2-safe-bottom: 104px; /* 쪽 맨 아래 여백 · 무대 핵심(장면+조작) 아래 끝이 화면 아래에서 떨어질 거리 */
}

/* ── 좁은 화면(860px 이하 — c 의 분기 그대로: 768 세로 태블릿 · 폰) ───────────── */
@media (max-width:860px){
  :root{
    --es2-fs-h1: 26px;  --es2-fs-h2: 25px;   /* c 302 · 324행 */
    --es2-gutter: 16px; --es2-sec-gap: 32px;
    --es2-band-h: 68px;  /* 56 단추 + 위아래 6 · 윗선 4 · 아랫선 3 → 75 ≤ 80(es_gate 폰 목표 · 견본 실측) */
    --es2-guide: 56px;
  }
}

/* ── TV 수업 화면 — 같은 쪽의 모드(차시 폴더에 자식 html 을 두지 않는다 · 계획 12절). ES.tv 가 html 에 es-tv 를 단다(CONTRACT 3-5) ── */
:root.es-tv{
  --es2-zoom: 1.4;       /* 본문 28 · 단추 글자 29.4 · 물음 47.6 · 누르는 것 78 (계획 4-5 'TV 본문 28px 이상') */
  --es2-guide: 118px;    /* c tv.html .g-face */
  --es2-content: 1848px; /* 1920 − 좌우 36 */
  --es2-gutter: 36px;
  --es2-band-h: 85px;    /* 안쪽 85 + 윗선 4 + 아랫선 3 = 92 = c tv.html 첫 줄(대조 2026-10-08: 92 를 안쪽에 주면 전체 99). 띠 ≤ 88 검사는 TV 를 빼고 잰다 */
}

/* ── 과목 색 — 권 랜딩 · 도감 머리 · 띠 윗선 4px · 카드 랜딩에만. 단추 · 정거장 · 판정 색은 바꾸지 않는다 ── */
:root[data-subject="science"]{ --es2-subj-deep:#0B4A82; --es2-subj-mid:#2F8FE0; --es2-subj-soft:#DCEFFF; }   /* 하늘 */
:root[data-subject="social"] { --es2-subj-deep:#7A2C04; --es2-subj-mid:#E8590C; --es2-subj-soft:#FFE8D6; }   /* 주황 흙 */
:root[data-subject="ethics"] { --es2-subj-deep:#8A1740; --es2-subj-mid:#E0457F; --es2-subj-soft:#FFE0EA; }   /* 장미 — 도덕(카드 id es34-ethics) */
:root[data-subject="music"]  { --es2-subj-deep:#51249A; --es2-subj-mid:#7C4DEB; --es2-subj-soft:#EBE3FE; }   /* 보라 */
:root[data-subject="art"]    { --es2-subj-deep:#094848; --es2-subj-mid:#0E8C8C; --es2-subj-soft:#CFF2EE; }   /* 청록 */
:root[data-subject="korean"] { --es2-subj-deep:#08512F; --es2-subj-mid:#12A56A; --es2-subj-soft:#DBF4E7; }   /* 초록 */
:root[data-subject="math"]   { --es2-subj-deep:#143A9E; --es2-subj-mid:#2B62E8; --es2-subj-soft:#E0E9FF; }   /* 코발트 */
/* 영어(english) · 체육(pe) · 정보(info) · 실과(practical) · 통합교과(integrated): 그 과목을 시작할 때 채운다 — 키는 카드 id 의 하이픈 뒤(es_split.json).
   한 줄을 더하면 contrast.py 가 그 줄을 찾아 잰다 — 0 으로 끝나야 한다. 채우기 전까지는 중립 기본값이 보인다(es_check v2 가 경고 — CONTRACT 7-5 #55) */

/* ── 단원 색 — body(또는 절)의 data-hue(CONTRACT 1-3). 도감 단원 줄 · 차시 머리의 단원 표지 · 스티커 테 ──
   이름은 지금 es.css 의 data-hue 일곱(green · sun · sky · coral · violet · cobalt · earth)을 그대로 쓰고 둘(teal · brick)을 더했다.
   옛 es.css 의 [data-hue] 는 --es-deep 따위를 바꾸고, 여기는 --es2-unit-* 만 바꾼다 — 같은 속성에 두 세대가 함께 서도 겹치지 않는다. */
[data-hue="sky"]   { --es2-unit-deep:#0B4A82; --es2-unit-mid:#2F8FE0; --es2-unit-soft:#DCEFFF; }   /* c 도감 05 */
[data-hue="teal"]  { --es2-unit-deep:#094848; --es2-unit-mid:#0E8C8C; --es2-unit-soft:#CFF2EE; }   /* c 도감 06 */
[data-hue="brick"] { --es2-unit-deep:#7A2410; --es2-unit-mid:#D9573B; --es2-unit-soft:#FFE1D9; }   /* c 도감 07 */
[data-hue="green"] { --es2-unit-deep:#0B4F31; --es2-unit-mid:#1F8A55; --es2-unit-soft:#D4F2E2; }   /* c 도감 08 */
[data-hue="violet"]{ --es2-unit-deep:#51249A; --es2-unit-mid:#7C4DEB; --es2-unit-soft:#EBE3FE; }   /* es.css violet 과 같은 값 */
[data-hue="coral"] { --es2-unit-deep:#8A1740; --es2-unit-mid:#E0457F; --es2-unit-soft:#FFE0EA; }   /* es.css coral 과 같은 값 */
[data-hue="sun"]   { --es2-unit-deep:#6E3A00; --es2-unit-mid:#B86E00; --es2-unit-soft:#FFEECF; }   /* es.css sun 의 vivid #E88A00 은 흰 바탕 3:1 미만이라 mid 를 짙게 */
[data-hue="cobalt"]{ --es2-unit-deep:#143A9E; --es2-unit-mid:#2B62E8; --es2-unit-soft:#E0E9FF; }   /* es.css cobalt 과 같은 값 */
[data-hue="earth"] { --es2-unit-deep:#5E3810; --es2-unit-mid:#9C6B33; --es2-unit-soft:#F3E6D2; }   /* es.css earth 와 같은 값 */

/* ── 학년군 토큰 — DESIGN_ES 2-6 표. 3~4 만 채웠다. 1~2 · 5~6 은 그 학년군을 시작할 때 채운다 ──
   CSS 로 담을 수 있는 것(글자 · 단추 · 간격 · 안내자 크기)만 여기에 두고, 문장 상한 · 응답 방식 · 안내자 말투는 표에 둔다. */
:root[data-band="34"]{
  /* 위 :root 기본값이 곧 3~4 값이다(본문 20 · 단추 56 · 간격 12 · 안내자 84). 다른 학년군이 생기면 기본값을 여기로 옮긴다 */
}
/* :root[data-band="12"]{ 그 학년군 시작 때 }  — 후보 질문: 본문 22~24? 단추 64? 고르기만? 소리 기본 켬? (2-6 표) */
/* :root[data-band="56"]{ 그 학년군 시작 때 } */

/* ── 움직임 줄이기 — 시간 토큰을 0 으로, JS 는 --es2-motion 0 을 보고 끝그림을 바로 그린다(b 17ms 처럼) ── */
@media (prefers-reduced-motion:reduce){
  :root{
    --es2-motion: 0;
    --es2-t-press: 0ms; --es2-t-quick: 0ms; --es2-t-state: 0ms; --es2-t-pop: 0ms;
    --es2-t-reveal: 0ms; --es2-t-peel: 0ms; --es2-t-bars: 0ms;
  }
}
/* ==ES2-TOKENS-END== */
/* ── 이름표 — es.css 안에서만 쓰는 보조 변수(--es2x-*). 토큰(--es2-*)이 아니다 ──────────────────────────
   토큰 값은 위 토큰 블록(= design/tokens.css)이 정본이고 여기서 바꾸지 않는다. 아래는 부품 치수를 한 곳에 모은 것뿐.
   · --es2x-cap  : 그림 설명 · 상태 줄 같은 '읽는 작은 말'. 평소 캡션 18, TV 는 본문 28(DESIGN 3-15 '읽을 글 28px 이상' · es_gate N14 —
                   캡션 토큰 × 1.4 = 25.2 는 28 에 모자란다. 리드에게 보고했다)
   · --es2x-blk  : 한 절 안 덩어리 사이(TV 1.4배)
   · --es2x-col  : 무대 틀 왼쪽 열(단계판) 폭 — c 의 366(DESIGN 3-4)                                            */
body.es-page{
  --es2x-cap: var(--es2-fs-cap);
  --es2x-blk: calc(24px * var(--es2-zoom));
  --es2x-col: calc(366px * var(--es2-zoom));
  --es2x-band: calc(var(--es2-band-h) + 7px);            /* 띠 전체 = 안쪽 + 윗선 4 + 아랫선 3 (DESIGN 3-2) */
  --es2x-pad: calc(26px * var(--es2-zoom));              /* 절 카드 안쪽 */
}
html.es-tv body.es-page{ --es2x-cap: var(--es2-fs-body); }

/* ══ 1. 바탕 — v1 의 전역 규칙(body · p · a · h2 · em)을 v2 쪽에서만 덮는다 ══ :where(:not(.es-land)) = 권 랜딩(body.es-page.es-land — 도감이 든 권)은 겉모습이 다른 권 랜딩(v1)과 같게(관문 ③ 반증 2026-10-13 — 4-2 랜딩만 종이 바탕 · 390 히어로 아래 노란 띠 46px · 히어로 409→396). :where 라 특정도 그대로 — 차시 쪽 캐스케이드 0 변화. 도감 안 v2 글 바탕은 11b절 .es-dogam 이 다시 준다 ══ */
body.es-page:where(:not(.es-land)){
  margin:0;
  color:var(--es2-ink);
  font-family:var(--es2-font); font-size:var(--es2-fs-body); font-weight:var(--es2-fw-body);
  line-height:var(--es2-lh-body); letter-spacing:0;
  word-break:keep-all; overflow-wrap:break-word;
  /* 첫 화면 위 360px 단색 띠 + 해 · 하늘 동그라미(장식 — 끊어진 색, 글자는 단색 위) + 종이 결 한 장(DESIGN 3-3 · 관문 ① (나)) */
  background-color:var(--es2-paper);
  background-image:
    var(--es2-paper-grain),
    radial-gradient(circle at 8% 120px, var(--es2-paper-sun) 0 70px, transparent 71px),
    radial-gradient(circle at 96% 60px, var(--es2-paper-sky) 0 54px, transparent 55px),
    linear-gradient(var(--es2-paper-top) 0 360px, transparent 360px);
  background-repeat:repeat, no-repeat, no-repeat, no-repeat;
  background-size:280px 280px, auto, auto, auto;
}
body.es-page:where(:not(.es-land)) :focus-visible{ outline:var(--es2-bw-2) solid var(--es2-focus); outline-offset:3px; border-radius:6px; }
body.es-page:where(:not(.es-land)) p{ max-width:var(--es2-measure); }
body.es-page:where(:not(.es-land)) :is(h1, h2, h3, h4){ font-family:inherit; letter-spacing:-0.01em; }
body.es-page:where(:not(.es-land)) a{ color:var(--es2-ink); }
body.es-page:where(:not(.es-land)) a:hover{ color:var(--es2-ink); }
body.es-page:where(:not(.es-land)) em{ background-image:linear-gradient(transparent 58%, var(--es2-paper-sky) 58%); }
body.es-page:where(:not(.es-land)) svg{ overflow:hidden; }

/* ══ 2. 띠 — .es-bar (DESIGN 3-2 · 1366 ≤ 88 · 폰 ≤ 80 · TV 92) ══════════════════════════════════════════
   쪽은 돌아가기 · 제목만 쓰고 나머지는 es.js 가 넣는다(계약 1-3). 숨은 칸은 display:none 이라 틀을 차지하지 않게
   칸 사이는 gap 이 아니라 각 칸의 왼쪽 여백으로 둔다. */
body.es-page .es-bar{
  position:sticky; top:0; z-index:var(--es2-z-band);
  box-sizing:border-box; height:var(--es2x-band);
  display:grid; grid-template-columns:auto minmax(0,1fr) repeat(6, auto); grid-template-rows:auto auto;
  align-content:center; align-items:center;
  padding:0 max(var(--es2-gutter), calc((100% - var(--es2-content)) / 2));
  background:var(--es2-card);
  border-top:4px solid var(--es2-subj-mid); border-bottom:var(--es2-bw) solid var(--es2-ink);
  font-family:var(--es2-font); line-height:var(--es2-lh-tight);
}
body.es-page .es-bar > *{ margin:0; grid-row:1 / 3; }
body.es-page .es-bar > * + *{ margin-left:var(--es2-gap); }
body.es-page .es-bar > .es-bar-back{ grid-column:1; }
body.es-page .es-bar > .es-bar-unit{ grid-column:2; grid-row:1; align-self:end; min-width:0;
  font-size:var(--es2-fs-label); font-weight:700; color:var(--es2-ink-2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:none; }
body.es-page .es-bar > .es-bar-title{ grid-column:2; grid-row:2; align-self:start; min-width:0;
  font-size:calc(22px * var(--es2-zoom)); font-weight:var(--es2-fw-head); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:none; }
body.es-page .es-bar > .es-bar-title:first-child,
body.es-page .es-bar > .es-bar-back + .es-bar-title{ grid-row:1 / 3; align-self:center; }
body.es-page .es-bar > .es-bar-unit + .es-bar-title{ grid-row:2; align-self:start; margin-left:var(--es2-gap); }
body.es-page .es-bar > .es-st{ grid-column:3; }
body.es-page .es-bar > .es-room{ grid-column:4; }
body.es-page .es-bar > .es-who{ grid-column:5; }
body.es-page .es-bar > .es-bar-dogam{ grid-column:6; }
body.es-page .es-bar > .es-bar-teacher{ grid-column:7; }
body.es-page .es-bar > .es-bar-me{ grid-column:8; display:none; }
/* 차시 목록 — ≡ 그림 단추(56). 글('차시 목록')은 낭독기 몫으로 단추 안에 남기고 색만 지운다(단추 밖으로 넘치지 않게 두 줄로) */
body.es-page .es-bar-back{
  position:relative; display:grid; place-items:center; box-sizing:border-box;
  width:var(--es2-tap); height:var(--es2-tap); padding:0 4px;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:16px; background:var(--es2-card);
  color:transparent; font-size:var(--es2-fs-label); font-weight:800; line-height:1.15; text-align:center; text-decoration:none; overflow:hidden;
}
body.es-page .es-bar-back::before{ content:"≡"; position:absolute; inset:0; display:grid; place-items:center;
  color:var(--es2-ink); font-size:calc(30px * var(--es2-zoom)); font-weight:900; line-height:1; }
/* 정거장 넷 — 56×56 이상 · 사이 12 · 숫자가 ✓ 로 바뀐다(지금 = 노랑 + 그림자 · 했어요 = 민트 + 초록 ✓ 점 · 아직 = 흰) */
body.es-page .es-st{ display:flex; gap:var(--es2-gap); align-items:center; }
body.es-page .es-st-chip{
  position:relative; display:flex; align-items:center; gap:8px; box-sizing:border-box;
  min-height:var(--es2-tap); min-width:var(--es2-tap); padding:0 16px 0 8px;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r-pill);
  background:var(--es2-card); color:var(--es2-ink); text-decoration:none;
  font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); white-space:nowrap;
  transition:background-color var(--es2-t-state);
}
body.es-page .es-st-n{
  display:grid; place-items:center; flex:none; box-sizing:border-box;
  width:var(--es2-icon); height:var(--es2-icon); border-radius:50%;
  border:var(--es2-bw) solid var(--es2-ink); background:var(--es2-card);
  font-size:var(--es2-fs-label); font-weight:var(--es2-fw-head); line-height:1;
}
body.es-page .es-st-chip[data-st="now"]{ background:var(--es2-sun); box-shadow:0 4px 0 var(--es2-ink); }
body.es-page .es-st-chip[data-st="done"]{ background:var(--es2-mint); }
body.es-page .es-st-chip[data-st="done"] .es-st-n{ background:var(--es2-ok); border-color:var(--es2-ok); color:var(--es2-on-dark); }
body.es-page .es-st-teacher{
  position:absolute; top:-10px; right:-6px; z-index:1;
  padding:0 6px; border-radius:6px; background:var(--es2-ink); color:var(--es2-on-dark);
  font-size:var(--es2-fs-label); font-weight:var(--es2-fw-head); line-height:1.2;
}
/* 반 알약 · 로그인 표시 — 글 + 모양으로 가른다(in 민트 · 꽉 찬 점 / out 흰 · 점선 · 빈 동그라미 / pv 흰 · 실선) */
body.es-page .es-room{
  display:inline-flex; align-items:center; min-height:44px; padding:4px 14px; box-sizing:border-box;
  border-radius:var(--es2-r-pill); background:var(--es2-ink); color:var(--es2-on-dark);
  font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); white-space:nowrap;
}
body.es-page .es-who{
  display:inline-flex; align-items:center; gap:8px; min-height:44px; padding:4px 14px; box-sizing:border-box;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r-pill);
  background:var(--es2-card); color:var(--es2-ink); text-decoration:none;
  font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); white-space:nowrap;
}
body.es-page a.es-who{ min-height:var(--es2-tap); }
body.es-page .es-who::before{ content:""; flex:none; width:14px; height:14px; border-radius:50%; box-sizing:border-box; }
body.es-page .es-who[data-st="in"]{ background:var(--es2-mint); }
body.es-page .es-who[data-st="in"]::before{ background:var(--es2-ok); }
body.es-page .es-who[data-st="out"]{ border-style:dashed; border-color:var(--es2-ink-2); }
body.es-page .es-who[data-st="out"]::before{ border:2.5px solid var(--es2-ink-2); }
body.es-page .es-who[data-st="pv"]::before{ display:none; }
/* 도감 — 별 단추 56(1240 이하 그림만 · 글은 낭독기 몫) */
body.es-page .es-bar-dogam{
  position:relative; display:inline-flex; align-items:center; justify-content:center; box-sizing:border-box;
  min-height:var(--es2-tap); min-width:var(--es2-tap); padding:0 14px;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:16px; background:var(--es2-card); color:var(--es2-ink);
  font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); text-decoration:none; white-space:nowrap;
}
/* 교사 서랍 단추 · '나' 단추 */
body.es-page :is(.es-bar-teacher, .es-bar-me){
  display:inline-flex; align-items:center; justify-content:center; gap:6px; box-sizing:border-box;
  min-height:var(--es2-tap); min-width:var(--es2-tap); padding:0 14px;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:16px; background:var(--es2-card); color:var(--es2-ink);
  font:var(--es2-fw-strong) var(--es2x-cap)/var(--es2-lh-tight) var(--es2-font); cursor:pointer;
}
body.es-page .es-bar-teacher[aria-expanded="true"]{ background:var(--es2-sky-soft); }
body.es-page .es-bar-me{ position:relative; padding:0; }
body.es-page .es-bar-me::after{
  content:"✓"; position:absolute; right:-6px; bottom:-6px; box-sizing:border-box;
  width:22px; height:22px; border-radius:50%; display:grid; place-items:center;
  border:var(--es2-bw-1) solid var(--es2-card); background:var(--es2-ok); color:var(--es2-on-dark);
  font-size:13px; font-weight:900; line-height:1;
}
body.es-page .es-bar-me[data-st="out"]::after{ content:""; background:var(--es2-card); border:2.5px dashed var(--es2-ink-2); }
body.es-page .es-bar-me[data-st="pv"]::after{ display:none; }
/* '나' 판(폰) — 띠 아래로 내려오는 판. 로그인 표시 · 반 · 차시 목록 · 도감 · (교사) 서랍 */
body.es-page .es-me{
  position:absolute; top:calc(100% + var(--es2-bw)); right:var(--es2-gutter); z-index:var(--es2-z-pop);
  width:min(320px, calc(100vw - 2 * var(--es2-gutter))); box-sizing:border-box;
  display:grid; gap:var(--es2-gap); padding:14px;
  background:var(--es2-card); border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r-md); box-shadow:var(--es2-sh-stage);
  margin:0 !important; grid-row:auto;
}
body.es-page .es-me > *{ margin:0; max-width:none; }
body.es-page .es-me .es-who{ justify-self:start; }
body.es-page .es-me-room{ font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); }
body.es-page :is(.es-me-back, .es-me-dogam, .es-me-teacher){
  display:flex; align-items:center; box-sizing:border-box; min-height:var(--es2-tap); padding:0 16px;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r); background:var(--es2-card); color:var(--es2-ink);
  font:var(--es2-fw-strong) var(--es2-fs-btn)/var(--es2-lh-tight) var(--es2-font); text-decoration:none; cursor:pointer; text-align:left;
}
@media (max-width:1240px){
  body.es-page .es-st-name{ display:none; }
  body.es-page .es-st-chip{ justify-content:center; padding:0; width:var(--es2-tap); }
  body.es-page .es-bar-dogam{ width:var(--es2-tap); padding:0; color:transparent; overflow:hidden; font-size:var(--es2-fs-label); line-height:1.15; text-align:center; white-space:normal; }
  body.es-page .es-bar-dogam::before{ content:"★"; position:absolute; inset:0; display:grid; place-items:center; color:var(--es2-ink); font-size:calc(28px * var(--es2-zoom)); line-height:1; }
}
@media (max-width:860px){
  body.es-page .es-bar{ grid-template-columns:auto minmax(0,1fr) auto; }
  body.es-page .es-bar > :is(.es-bar-back, .es-bar-unit, .es-bar-title, .es-room, .es-who, .es-bar-dogam, .es-bar-teacher){ display:none; }
  body.es-page .es-bar > .es-st{ grid-column:1; margin-left:0; }
  body.es-page .es-bar > .es-bar-me{ grid-column:3; display:inline-flex; }
}
/* REVIEW robust-6: 폰 띠의 한 줄 최소폭이 약 360(칩 넷 56 + '나' 56 + 사이 12 + 바깥 16×2)이라 320~359 창에서 '나' 가 화면 밖으로 밀리고
   쪽 전체가 가로로 밀렸다. 좁은 창에서는 바깥 8 · 사이 6, 정거장 줄이 줄어들 수 있게(칩 56 → 최소 44) 한다 */
@media (max-width:374px){
  body.es-page .es-bar{ grid-template-columns:minmax(0, max-content) minmax(0,1fr) auto; padding:0 8px; }
  body.es-page .es-bar > .es-st{ min-width:0; gap:6px; }
  body.es-page .es-bar > .es-bar-me{ margin-left:6px; }
  body.es-page .es-st-chip{ min-width:44px; width:clamp(44px, calc((100vw - 112px) / 4), var(--es2-tap)); flex:0 1 auto; }   /* 바깥 8×2 · 사이 6×4 · '나' 56 · 스크롤바 여유 */
}

/* ══ 3. 본문 뼈대 — 절 카드 · 절 머리 · 맨 아래 이동 ══════════════════════════════════════════════════════ */
body.es-page .es-body{
  display:block; box-sizing:border-box; max-width:calc(var(--es2-content) + 2 * var(--es2-gutter));
  margin:0 auto; padding:0 var(--es2-gutter);
}
body.es-page .es-part{
  position:relative; box-sizing:border-box;
  margin:var(--es2-sec-gap) 0 0; padding:var(--es2x-pad) calc(28px * var(--es2-zoom)) calc(30px * var(--es2-zoom));
  background:var(--es2-card); border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r-lg); box-shadow:var(--es2-sh-card);
  scroll-margin-top:calc(var(--es2x-band) + 12px);          /* 함께 하기 착지 · 정거장 이동(계약 4-2 — 띠 높이로) */
}
/* 열기 절(첫 화면)과 무대만 든 절은 카드가 아니다 — 무대 틀이 곧 판이다(c 의 실험대). 두 겹 테를 두지 않는다 */
body.es-page .es-part[data-station="open"],
body.es-page .es-part:has(> .es-play){ background:none; border:0; box-shadow:none; padding:0; border-radius:0; }
body.es-page .es-part[data-station="open"]{ margin-top:0; padding-top:calc(16px * var(--es2-zoom)); }
body.es-page .es-part > *{ margin-top:0; margin-bottom:0; }
body.es-page .es-part > * + *{ margin-top:var(--es2x-blk); }
/* 갈래 표지 — 카드 위 테에 걸친 이름표(해 보기 · 확인 · 정리). 글은 계약 2-11 정거장 이름 그대로. 열기 · 더 알아보기(머리표가 따로 있다) · 무대 절은 뺀다 */
body.es-page .es-part[data-station]:not([data-station="open"]):not([data-explore]):not(:has(> .es-play))::before{
  position:absolute; top:calc(-20px * var(--es2-zoom)); left:calc(28px * var(--es2-zoom));
  box-sizing:border-box; height:calc(40px * var(--es2-zoom)); padding:0 14px; display:grid; place-items:center;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:14px; box-shadow:0 4px 0 var(--es2-ink);
  font-size:var(--es2-fs-label); font-weight:var(--es2-fw-head); line-height:1; color:var(--es2-ink);
}
body.es-page .es-part[data-station="try"]:not([data-explore]):not(:has(> .es-play))::before{ content:"해 보기"; background:var(--es2-k-try); }
body.es-page .es-part[data-station="check"]:not(:has(> .es-play))::before{ content:"확인"; background:var(--es2-k-check); }
body.es-page .es-part[data-station="fin"]:not([data-explore]):not(:has(> .es-play))::before{ content:"정리"; background:var(--es2-k-fin); }
body.es-page .es-part > h2{ margin:0; font-size:var(--es2-fs-h2); font-weight:var(--es2-fw-head); line-height:var(--es2-lh-head); max-width:none; }
body.es-page .es-part > h2 + *{ margin-top:calc(14px * var(--es2-zoom)); }
body.es-page .es-part > h3{ font-size:var(--es2-fs-h3); font-weight:var(--es2-fw-head); line-height:var(--es2-lh-head); }
body.es-page .es-part > p{ font-size:var(--es2-fs-lead); font-weight:700; color:var(--es2-ink-2); }
/* 맨 아래 이동(DESIGN 3-19 · 관문 ② ⑩) — 쪽 소스는 '← 앞 차시' · '다음 차시 →' 그대로, dist 에서는 빌드(build_es_cards.Pager)가 '← 이전: <차시 제목>' · '다음: <차시 제목> →' 로 바꾼다(폰은 두 줄로 감긴다 — 아래 860px 블록) + 떠 있는 단추를 피하는 104px */
body.es-page .es-pager{
  display:flex; justify-content:space-between; gap:calc(16px * var(--es2-zoom)); box-sizing:border-box;
  max-width:calc(var(--es2-content) + 2 * var(--es2-gutter)); margin:var(--es2-sec-gap) auto 0;
  padding:0 var(--es2-gutter) var(--es2-safe-bottom);
}
body.es-page .es-pager a{
  flex:1 1 0; display:flex; align-items:center; box-sizing:border-box; min-height:calc(72px * var(--es2-zoom)); padding:10px 20px;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r); background:var(--es2-card); color:var(--es2-ink);
  box-shadow:var(--es2-sh-btn); font-size:var(--es2-fs-btn); font-weight:var(--es2-fw-strong); text-decoration:none;
  transition:transform var(--es2-t-press), box-shadow var(--es2-t-press);
}
body.es-page .es-pager a[rel="next"]{ justify-content:flex-end; text-align:right; }
body.es-page .es-pager a:only-child[rel="next"]{ margin-left:auto; flex:0 1 50%; }
body.es-page .es-pager a:active{ transform:translateY(var(--es2-press)); box-shadow:var(--es2-sh-btn-act); }

/* ══ 4. 장난감 단추 — v2 의 모든 단추 한 결(c .btn: 굵은 테 + 아래로 꺼진 그림자, 누르면 4px 내려앉는다) ═══════
   v2 단추에는 클래스를 달지 않는다(계약 1-3 · 1-8-3) — 그래서 속성 · 자리로 잡는다. 장면 SVG 안 [data-op] 는 단추가 아니다(button 만). */
body.es-page :where(.es-play button[data-op], button[data-op][data-for], .es-opt, button[data-grade-btn], button[data-send], button[data-replay], button[data-help],
  .es-say, .es-wq-yes, .es-wq-no, .es-wq-retry, .es-wq-carry, .es-wq-chip, a.es-cq-back, a.es-wq-login, a.es-sticker-go, .es-login-line a,
  .es-drawer button, .es-tv-side button){
  display:inline-flex; align-items:center; justify-content:center; gap:10px; box-sizing:border-box;
  min-height:var(--es2-tap); min-width:var(--es2-tap); margin:0; padding:8px 18px;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r);
  background:var(--es2-card); color:var(--es2-ink); box-shadow:var(--es2-sh-btn);
  font:var(--es2-fw-strong) var(--es2-fs-btn)/var(--es2-lh-tight) var(--es2-font); text-align:center; text-decoration:none;
  cursor:pointer; -webkit-tap-highlight-color:transparent;
  transition:transform var(--es2-t-press), box-shadow var(--es2-t-press), background-color var(--es2-t-state);
}
body.es-page :where(.es-play button[data-op], button[data-op][data-for], .es-opt, button[data-grade-btn], button[data-send], button[data-replay], button[data-help],
  .es-say, .es-wq-yes, .es-wq-no, .es-wq-retry, .es-wq-carry, .es-wq-chip, a.es-cq-back, a.es-wq-login, a.es-sticker-go, .es-login-line a,
  .es-drawer button, .es-tv-side button):active:not([aria-disabled="true"]):not([disabled]){
  transform:translateY(var(--es2-press)); box-shadow:var(--es2-sh-btn-act);
}
body.es-page :is(.es-opt, button[data-op])[aria-pressed="true"],
body.es-page .es-opt[aria-checked="true"]{
  /* 고른 채 — 그림자가 줄어 '꺼져 있는' 모양. 상자는 옮기지 않고(옮기면 이웃 사이가 12 아래로 준다 — es_gate N6) 안의 글만 내려앉는다 */
  background:var(--es2-sky-soft); box-shadow:var(--es2-sh-btn-on);
  padding-top:calc(8px + var(--es2-press-on)); padding-bottom:calc(8px - var(--es2-press-on));
}
/* REVIEW screen-7: 위아래 안쪽이 6px 인 단추(예상 보기 · 무대 조작)는 고른 채에도 위아래 합 12 를 지킨다 — 8 기준을 그대로 쓰면
   고른 보기만 58 → 62 로 커져 같은 줄 높이가 들쭉날쭉하고 그 아래가 4px 밀렸다 */
body.es-page .es-predict .es-opt[aria-pressed="true"],
body.es-page .es-play button[data-op][aria-pressed="true"]{ padding-top:calc(6px + var(--es2-press-on)); padding-bottom:calc(6px - var(--es2-press-on)); }
body.es-page :is(.es-opt, button)[aria-disabled="true"],
body.es-page button[disabled]{ cursor:default; }
body.es-page :is(button[data-grade-btn], button[data-send], .es-wq-yes){
  min-height:var(--es2-tap-lg); padding:10px 30px; background:var(--es2-sun); font-size:var(--es2-fs-btn-lg); border-radius:20px;
}
body.es-page .es-wq-yes{ min-height:var(--es2-tap); font-size:var(--es2-fs-btn); padding:8px 22px; }
body.es-page button[data-send][data-sent]{ background:var(--es2-mint); }
body.es-page button[data-grade-btn][data-ready]{ box-shadow:var(--es2-sh-btn), 0 0 0 5px var(--es2-sun-soft); }
/* 🔊 읽어 주기 — 카드 머리의 56 원(DESIGN 3-17) */
body.es-page .es-say{ width:var(--es2-tap); height:var(--es2-tap); padding:0; border-radius:50%; flex:none; font-size:calc(24px * var(--es2-zoom)); }
body.es-page .es-say[aria-pressed="true"]{ background:var(--es2-sky-soft); outline:var(--es2-bw-2) solid var(--es2-sky-deep); outline-offset:2px; }   /* REVIEW robust-5: 읽는 중을 색 하나가 아니라 고리로도 */
/* 다시 보기 · 도움 · 다시 보러 가기 — 흰 단추. 도움은 갈색 점선 테 + 손 그림(노랑이 아니다 — DESIGN 3-7) */
body.es-page button[data-replay]{ font-size:var(--es2-fs-btn); }
body.es-page button[data-help]{
  border-style:dashed; border-color:var(--es2-again); color:var(--es2-again); box-shadow:none; gap:6px;
}
body.es-page button[data-help]::before{ content:"☝"; font-size:1.1em; line-height:1; }
body.es-page .es-helped{
  display:inline-flex; align-items:center; gap:4px; margin-left:8px;
  color:var(--es2-again); font-size:var(--es2-fs-label); font-weight:var(--es2-fw-strong); white-space:nowrap;
}
body.es-page .es-helped::before{ content:"☝"; }
body.es-page a.es-cq-back{ color:var(--es2-again); }

/* ══ 5. 예고형 잠금 — 잠그는 것은 조작과 결과 글뿐(DESIGN 3-5 · 계약 1-6). 전부 html.js 아래 — JS 가 죽으면 다 보인다 ══ */
/* (가) 조작 대기 — 보이고 읽히되 누를 수 없다: 흐린 바탕 · 점선 테 · 흐린 잉크 글(8.14:1). 불투명도로 흐리지 않는다 */
html.js body.es-page [data-wait]:not(.is-open) :is(button, input, select, textarea, a){
  background:var(--es2-dim); color:var(--es2-ink-dim); border-style:dashed; border-color:var(--es2-line-todo);
  box-shadow:none; transform:none; cursor:not-allowed;
}
html.js body.es-page [data-wait]:not(.is-open) :is(button, a) *{ color:var(--es2-ink-dim); }
/* REVIEW screen-14(과학 3-2 07/02 기준편 · 2026-10-14): 잠긴 판 안 출처 줄의 링크(소리 판 · 사진 출처 — .es-credit)는 누르는 것이 아니라 읽는 글이다.
   위 (가) 가 단추와 같은 흐린 바탕 · 점선 상자(테 3px)를 둘러 12px 출처 위에 디버그 표시처럼 보였다. 출처 글 모양(--es2-ink-credit · 밑줄 없음)은 잠겨도 그대로 —
   판이 inert 라 잠긴 동안 링크는 어차피 눌리지 않는다. 테가 없어지므로 열릴 때 글이 3px 움직이던 것도 없다 */
html.js body.es-page [data-wait]:not(.is-open) .es-credit a{ background:none; border-style:none; color:inherit; cursor:default; }
/* (나) 결과 대기 — 그림은 흐리게 보이고, 결과 글은 visibility:hidden(자리 · 높이 그대로) + 그 자리에 글줄 막대(1lh 마다 한 줄).
   글자색만 지우지 않는다 — 문장이 innerText 에 남는다(DESIGN 3-5 실측). 막대는 숨긴 요소 자신의 ::before(visibility:visible) — es_gate N1 의 '글줄 막대' 정의 */
html.js body.es-page :is(span, p, b, strong, small, li, dd, dt, figcaption, h3, h4, label)[data-reveal]:not(.is-open),
html.js body.es-page [data-reveal]:not(.is-open) :is(p, h3, h4, figcaption, dd, dt, blockquote, label, td, th, caption){
  visibility:hidden; position:relative;
}
html.js body.es-page :is(span, b, strong, small, label)[data-reveal]{ display:inline-block; max-width:100%; vertical-align:top; }
html.js body.es-page :is(span, p, b, strong, small, li, dd, dt, figcaption, h3, h4, label)[data-reveal]:not(.is-open)::before,
html.js body.es-page [data-reveal]:not(.is-open) :is(p, h3, h4, figcaption, dd, dt, blockquote, label, td, th, caption)::before{
  content:""; visibility:visible; position:absolute; inset:0; z-index:0; pointer-events:none;
  background-image:linear-gradient(to bottom, transparent 22%, var(--es2-skeleton) 22%, var(--es2-skeleton) 74%, transparent 74%);
  background-size:100% 1lh; background-repeat:repeat-y; border-radius:8px;
}
html.js body.es-page [data-reveal]:not(.is-open) :is(svg, canvas){ filter:blur(2.5px) saturate(.55); opacity:.5; }
html.js body.es-page [data-reveal]:not(.is-open) :is(img, video){ filter:blur(22px) saturate(.4); }
html.js body.es-page [data-reveal]:not(.is-open) :is(img, video, svg, canvas){ transition:none; }
html.js body.es-page [data-reveal].is-open:not(.is-shown) :is(p, figcaption, li){ animation:es2-up var(--es2-t-reveal) var(--es2-ease-out) both; }
/* 잠금 알약 — 어두운 알약(16.1:1) · 흐린 무리의 형제(흐림을 물려받지 않는다) · 묶음마다 하나(계약 1-6 · E1 span.es-pill) */
body.es-page .es-pill{
  display:inline-flex; align-items:center; justify-content:center; gap:8px; box-sizing:border-box;
  width:max-content; max-width:calc(100% - 16px); padding:4px 14px;
  border-radius:var(--es2-r-pill); background:var(--es2-ink); color:var(--es2-on-dark);
  font-size:var(--es2x-cap); font-weight:var(--es2-fw-head); line-height:var(--es2-lh-tight); text-align:center;
  position:relative; z-index:var(--es2-z-lock); pointer-events:none;
}
body.es-page .es-pill::before{
  content:""; flex:none; width:.8em; height:.9em;
  background:no-repeat center/contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 18'%3E%3Crect x='1.5' y='7.5' width='13' height='9' rx='2' fill='%23fff'/%3E%3Cpath d='M4.5 7.5V5a3.5 3.5 0 0 1 7 0v2.5' fill='none' stroke='%23fff' stroke-width='2.2'/%3E%3C/svg%3E");
}
/* 알약 자리 셋. ① 카드 앞(이름 붙이기 · 오늘 알게 된 것): 높이 0 닻 — 흐름에서 빠져 다음 카드 위 테에 걸친다(열려도 쪽 높이 그대로) */
body.es-page .es-pill{ position:absolute; margin:var(--es2x-blk) 0 0 calc(24px * var(--es2-zoom)); transform:translateY(-50%); }
/* REVIEW robust-6: 왼쪽 24 를 띄운 카드 앞 알약은 그만큼 폭을 덜 쓴다 — 320 창에서 X1 개념 그림 알약이 오른쪽으로 5px 넘쳐 쪽이 가로로 밀렸다 */
body.es-page :not(.es-play, .es-cmp p) > .es-pill{ max-width:calc(100% - 16px - 24px * var(--es2-zoom)); }
body.es-page :has(> .es-pill){ position:relative; }
/* 알약이 걸치는 묶음이 테 있는 카드가 아니면(오늘 알게 된 것 ul 은 줄마다 카드) 아래 반쪽 자리를 묶음 위에 둔다 — 첫 줄 그림을 덮지 않게(N7) */
body.es-page .es-pill + :is(ul, ol){ padding-top:calc((var(--es2x-cap) * 1.3 + 8px) / 2 + 6px); }
/* ② 무대 틀 안 — 조작 줄 위 한 줄(DESIGN 3-4). 줄을 처음부터 잡고, 열리면 글만 숨긴다(쪽 높이 그대로) */
body.es-page .es-play > .es-pill{ position:relative; margin:0; transform:none; justify-self:center; align-self:end; }
/* ③ 나란히 보기 줄 안 — 값 칸(글줄 막대) 위에 겹친다 */
body.es-page .es-cmp p > .es-pill{ position:relative; margin:0; transform:none; grid-column:2; grid-row:1; justify-self:start; align-self:center; max-width:100%; }
html.js body.es-page :is(.es-play, .es-cmp p) > .es-pill[hidden]{ display:inline-flex !important; visibility:hidden; }

/* ══ 6. 오늘의 물음 — 첫 화면(DESIGN 3-3 · 계약 1-8-0) ═══════════════════════════════════════════════════ */
body.es-page .es-today{
  display:grid; grid-template-columns:minmax(0,1fr) auto; column-gap:16px; align-items:center;
  max-width:var(--es2-content); margin:0 auto;
}
body.es-page .es-today > *{ margin:0; max-width:none; }
body.es-page .es-today-head{ display:none; grid-column:1 / -1; font-size:var(--es2x-cap); font-weight:700; color:var(--es2-ink-2); margin-bottom:6px; }
body.es-page .es-today-label{
  grid-column:1; justify-self:start; padding:2px 12px; margin-bottom:4px;
  border-radius:10px; background:var(--es2-ink); color:var(--es2-on-dark);
  font-size:var(--es2x-cap); font-weight:var(--es2-fw-head); line-height:var(--es2-lh-tight);
}
body.es-page .es-today-q{ grid-column:1; font-size:var(--es2-fs-h1); font-weight:var(--es2-fw-head); line-height:var(--es2-lh-head); }
body.es-page .es-today > .es-say{ grid-column:2; grid-row:1 / span 3; }
body.es-page .es-today-head ~ .es-say{ grid-row:2 / span 2; }
/* 로그인 안내 줄 — 물음 바로 아래 · 점선(계약 2-9). 누르는 것이라 56(es_gate N6 — DESIGN 3-3 의 '48 이하' 와 맞섰다: 보고) */
body.es-page .es-login-line{ max-width:var(--es2-content); margin-left:auto; margin-right:auto; }
body.es-page .es-part > .es-login-line{ margin-top:calc(12px * var(--es2-zoom)); }
body.es-page .es-login-line a{
  justify-content:flex-start; border-style:dashed; border-color:var(--es2-ink-2); box-shadow:none; background:var(--es2-card);
  font-size:var(--es2x-cap); font-weight:700; padding:6px 16px;
}

/* ══ 7. 무대 틀 — .es-play (DESIGN 3-4 · 5-1 · 계약 1-7-1) ════════════════════════════════════════════════
   배치는 칸 이름과 data-zone 으로만 잡는다(집필자는 배치 클래스를 쓰지 않는다).
   1366: 왼쪽 열 = 예상 · 고를 것 · 알아 두기 / 오른쪽 열 = 장면 · (말풍선) · 알약 · 조작 줄 / 아래 = 기록 칸 · 나란히 보기.
   860 이하: 예상 → 장면 → 말풍선 → 알약 → 조작 줄 → 고를 것 → 알아 두기 → 기록 칸 → 나란히 보기.
   칸이 빠지면 남은 칸이 넓어진다(:has — 빈 판 금지). 같은 zone 둘째 줄은 아래 트랙으로. */
body.es-page .es-play{
  container:es2play / inline-size;
  counter-reset:es2step;
  position:relative; box-sizing:border-box;
  display:grid; column-gap:calc(18px * var(--es2-zoom)); row-gap:0;
  grid-template-columns:[l] var(--es2x-col) [r] minmax(0,1fr);
  grid-template-rows:repeat(8, auto) minmax(0,1fr) auto;   /* 9째 줄(유연)이 '알아 두기' 가 조작 줄보다 긴 만큼을 조작 줄 **아래**에서 받는다 — 조작 줄이 장면에 붙어 있게(장면 + 조작 한 화면) */
  margin-top:calc(28px * var(--es2-zoom));
  padding:calc(18px * var(--es2-zoom)) calc(20px * var(--es2-zoom)) calc(20px * var(--es2-zoom));
  background:var(--es2-card); border:var(--es2-bw-2) solid var(--es2-ink); border-radius:var(--es2-r-xl); box-shadow:var(--es2-sh-stage);
}
body.es-page .es-play > *{ margin:0; min-width:0; }
/* 탭 — data-tab 글(차시가 고른 이름) */
body.es-page .es-play[data-tab]::before{
  content:attr(data-tab); position:absolute; top:calc(-24px * var(--es2-zoom)); left:30px; z-index:1;
  padding:2px 16px; border:var(--es2-bw) solid var(--es2-ink); border-radius:14px; background:var(--es2-sun); box-shadow:0 4px 0 var(--es2-ink);
  font-size:var(--es2-fs-body); font-weight:var(--es2-fw-head); line-height:var(--es2-lh-tight); color:var(--es2-ink);
}
/* 자리 — 넓은 창 */
body.es-page .es-play > .es-predict{ grid-column:l; grid-row:1; }
body.es-page .es-play > .es-ops[data-zone="pick"]{ grid-column:l; grid-row:2; }
body.es-page .es-play > .es-ops[data-zone="pick"] ~ .es-ops[data-zone="pick"]{ grid-row:3; }
body.es-page .es-play > .es-tip{ grid-column:l; grid-row:4 / 10; }
body.es-page .es-play > .es-scene{ grid-column:r; grid-row:1 / 5; align-self:start; }
body.es-page .es-play > .es-guide{ grid-column:r; grid-row:5; }
body.es-page .es-play > .es-pill{ grid-column:r; grid-row:6; }
/* POLISH: ↻ 다시 보기 — 말풍선 줄 밖(엔진이 말풍선 바로 뒤 형제로 만든다). 잠금 알약과 같은 줄의 오른쪽 끝 — 장면 바로 아래
   (말풍선이 장면 아래로 오는 폭에서는 말풍선 바로 아래). 글자 단추 56 그대로 · 장면 그림을 덮지 않는다(N7) ·
   아래 조작 줄과 사이 12(N6 — 아래 여백 6 + 조작 줄 위 여백 6). 예상을 고르면 알약과 함께 사라지지만 자리는 그대로 둔다(쪽 높이 그대로 — N3).
   ⚠️ 1366(말풍선이 장면에 겹치는 폭)에서 장면 위 끝 → 조작 줄 아래 끝이 알약 줄 31 → 이 줄 68 만큼 늘어 X1 570 → 601 · X2 577 → 608 —
   DESIGN 3-4 의 581 을 넘는다. 1366 에서는 무대 오른쪽 끝(1279)이 💬 단추(1282~1342)보다 왼쪽이라 실제로 깔리지는 않는다(CHANGES POLISH 에 보고) */
body.es-page .es-play > button[data-replay]{ grid-column:r; grid-row:6; justify-self:end; align-self:start; margin:calc(6px * var(--es2-zoom)) 0 6px; }
html.js body.es-page .es-play > button[data-replay][hidden]{ display:inline-flex !important; visibility:hidden; }
body.es-page .es-play:has(> button[data-replay]) > .es-pill{ align-self:center; }
body.es-page .es-play > .es-ops[data-zone="act"]{ grid-column:r; grid-row:7; }
body.es-page .es-play > .es-ops[data-zone="act"] ~ .es-ops[data-zone="act"]{ grid-row:8; }
body.es-page .es-play > .es-ops[data-zone="undo"]{ grid-column:r; grid-row:9; }
body.es-page .es-play > .es-log{ grid-column:l; grid-row:10; }
body.es-page .es-play > .es-cmp{ grid-column:r; grid-row:10; }
body.es-page .es-play > :not(.es-predict, .es-ops, .es-tip, .es-scene, .es-guide, .es-pill, .es-log, .es-cmp, .es-still){ grid-column:1 / -1; }
/* 빠진 칸 — 왼쪽 열의 마지막 칸이 아래 끝까지 */
body.es-page .es-play:not(:has(> .es-tip)) > .es-ops[data-zone="pick"]:last-of-type,
body.es-page .es-play:not(:has(> .es-tip)):not(:has(> .es-ops[data-zone="pick"])) > .es-predict{ grid-row-end:10; }
body.es-page .es-play:not(:has(> .es-predict)) > .es-ops[data-zone="pick"]{ grid-row:1; }
body.es-page .es-play:not(:has(> .es-predict)) > .es-ops[data-zone="pick"] ~ .es-ops[data-zone="pick"]{ grid-row:2; }
body.es-page .es-play:not(:has(> .es-ops[data-zone="pick"])) > .es-tip{ grid-row-start:2; }
body.es-page .es-play:not(:has(> .es-predict)):not(:has(> .es-ops[data-zone="pick"])) > .es-tip{ grid-row-start:1; }
body.es-page .es-play:not(:has(> .es-cmp)) > .es-log{ grid-column:1 / -1; }
body.es-page .es-play:not(:has(> .es-log)) > .es-cmp{ grid-column:1 / -1; }
/* 왼쪽 열이 통째로 없으면(지도판처럼 장면 안 누를 곳으로만 하는 무대) 한 열 */
body.es-page .es-play:not(:has(> :is(.es-predict, .es-tip, .es-ops[data-zone="pick"]))){ grid-template-columns:[l r] minmax(0,1fr); }
/* 칸 사이 — row-gap 을 쓰지 않고(빈 트랙이 틈을 남긴다) 칸마다 위 여백 */
body.es-page .es-play > :is(.es-ops[data-zone="pick"], .es-tip){ margin-top:calc(14px * var(--es2-zoom)); }
body.es-page .es-play > :is(.es-guide, .es-ops[data-zone="undo"]){ margin-top:calc(12px * var(--es2-zoom)); }
body.es-page .es-play > :is(.es-pill, .es-ops[data-zone="act"]){ margin-top:calc(6px * var(--es2-zoom)); }
body.es-page .es-play > :is(.es-pill, .es-ops[data-zone="act"], .es-guide){ align-self:start; }
body.es-page .es-play > :is(.es-log, .es-cmp){ margin-top:calc(16px * var(--es2-zoom)); }
body.es-page .es-play:not(:has(> .es-predict)) > .es-ops[data-zone="pick"]:first-of-type,
body.es-page .es-play:not(:has(> .es-predict)):not(:has(> .es-ops[data-zone="pick"])) > .es-tip{ margin-top:0; }
/* 판 공통(단계판 · 기록 칸 · 나란히 보기) */
body.es-page .es-play > :is(.es-predict, .es-ops[data-zone="pick"], .es-tip, .es-log, .es-cmp){
  box-sizing:border-box; padding:calc(12px * var(--es2-zoom)) calc(14px * var(--es2-zoom)) calc(14px * var(--es2-zoom));
  border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r-md); background:var(--es2-panel);
}
/* 단계 번호 ①②③ — 있는 칸만 센다(예상 · 고를 것 · 기록 칸) */
body.es-page .es-play > :is(.es-predict, .es-ops[data-zone="pick"], .es-log){ counter-increment:es2step; }
/* 장면 — 벽 · 굵은 테. SVG 는 엔진이 그리고(빌드가 정지 그림을 굽는다) 폭에 맞춘다 */
body.es-page .es-scene{
  position:relative; box-sizing:border-box;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:24px; background:var(--es2-wall);
}
body.es-page .es-scene > :is(svg, canvas, .es-still){ border-radius:calc(24px - var(--es2-bw)); overflow:hidden; }
body.es-page .es-scene > svg, body.es-page .es-scene > canvas, body.es-page .es-still > :is(svg, img){ display:block; width:100%; height:auto; }
body.es-page .es-scene svg [data-op]{ cursor:pointer; }
body.es-page .es-scene svg [data-op]:focus-visible{ outline:var(--es2-bw-2) solid var(--es2-focus); outline-offset:2px; }
body.es-page .es-play[data-live] .es-still{ display:none; }
body.es-page .es-scene[data-fx="blocked"]{ animation:es2-nudge var(--es2-t-pop) var(--es2-ease) 1; }
/* 조작 줄 — c 의 그릇 단추: 이름 + 아랫줄(span)이 단추 안 두 줄. 사이 12 · 단추 5개 이하(계약 1-7-1) */
body.es-page .es-play .es-ops{ display:grid; gap:var(--es2-gap); grid-template-columns:repeat(auto-fit, minmax(min(100%, calc(140px * var(--es2-zoom))), 1fr)); }
body.es-page .es-play .es-ops[data-zone="pick"]{ grid-template-columns:repeat(auto-fit, minmax(min(100%, calc(120px * var(--es2-zoom))), 1fr)); }
body.es-page .es-play .es-tip > .es-ops{ grid-template-columns:minmax(0,1fr); }
body.es-page .es-play button[data-op]{ width:100%; flex-direction:column; gap:0; padding:6px 10px; font-weight:var(--es2-fw-head); }
body.es-page .es-play button[data-op] > span{ display:block; font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); color:var(--es2-ink-2); }
body.es-page .es-play .es-ops[data-zone="act"] button[data-op]{ min-height:var(--es2-tap-lg); }
/* 고를 것 머리 — 묶음의 aria-label 을 그대로 판 머리로(쪽이 쓴 말) */
body.es-page .es-play > .es-ops[data-zone="pick"]::before,
body.es-page .es-play > .es-log::before{
  grid-column:1 / -1; display:flex; align-items:center; gap:10px; margin:0;
  font-size:var(--es2-fs-btn); font-weight:var(--es2-fw-head); line-height:var(--es2-lh-tight);
}
body.es-page .es-play > .es-ops[data-zone="pick"]::before{ content:counter(es2step, es2-circ) "\00a0" attr(aria-label); }
body.es-page .es-play > .es-ops[data-zone="pick"]:not([aria-label])::before{ content:counter(es2step, es2-circ); }
/* 알아 두기 — 짧은 설명 + 되돌리기 */
body.es-page .es-play > .es-tip{ display:flex; flex-direction:column; justify-content:center; gap:calc(10px * var(--es2-zoom)); background:var(--es2-tip); }
body.es-page .es-tip > p{ margin:0; font-weight:var(--es2-fw-strong); line-height:1.4; max-width:none; }
/* 누름 상태(엔진 표지 — 클래스가 아니라 속성) */
body.es-page .es-play[data-busy] button[data-op]{ cursor:progress; }
body.es-page button[data-op][data-pressed]{ transform:translateY(var(--es2-press)); box-shadow:var(--es2-sh-btn-act); background:var(--es2-sky-soft); }
body.es-page button[data-op][data-queued]{ outline:var(--es2-bw) dashed var(--es2-sky); outline-offset:3px; }
body.es-page :is(button[data-op], button[data-help])[data-fx="wait"]{ outline:var(--es2-bw) dashed var(--es2-sky); outline-offset:3px; animation:es2-tick var(--es2-t-quick) var(--es2-ease) 1; }
body.es-page button[data-op][data-fx="blocked"]{ animation:es2-nudge var(--es2-t-pop) var(--es2-ease) 1; }
body.es-page button[data-help][data-fx="pop"]{ animation:es2-tick var(--es2-t-quick) var(--es2-ease) 1; }
/* 맥동 — 다음에 누를 것이 노란 빛으로 3번(1초 간격 · 계약 1-7-3 보장 14). 움직임 줄이기면 테두리가 한 번 노랗게(once) */
body.es-page [data-pulse="on"]{ animation:es2-pulse 1s var(--es2-ease) 3; }
body.es-page [data-pulse="once"]{ outline:var(--es2-bw-2) solid var(--es2-sun); outline-offset:3px; }
/* 예상 — 단계판 ①. 고르기 전에는 판 둘레에 노란 고리(다음에 누를 것) */
body.es-page .es-predict{ display:grid; gap:var(--es2-gap); align-content:start; }
body.es-page .es-predict > *{ margin:0; max-width:none; }
body.es-page .es-predict-q{ display:flex; align-items:flex-start; gap:10px; font-size:var(--es2-fs-body); font-weight:var(--es2-fw-head); line-height:1.3; }
body.es-page .es-play > .es-predict > .es-predict-q::before{
  content:counter(es2step); flex:none; display:grid; place-items:center;
  width:var(--es2-icon); height:var(--es2-icon); border-radius:50%; background:var(--es2-ink); color:var(--es2-on-dark);
  font-size:var(--es2-fs-label); font-weight:var(--es2-fw-head); line-height:1;
}
body.es-page .es-predict .es-opt{ position:relative; justify-content:flex-start; width:100%; text-align:left; padding:6px 14px; }
body.es-page .es-predict .es-opt[aria-pressed="true"]::after{
  content:"내 예상"; position:absolute; right:10px; top:-11px;
  padding:1px 8px; border-radius:var(--es2-r-xs); background:var(--es2-ink); color:var(--es2-on-dark);
  font-size:var(--es2-fs-label); font-weight:var(--es2-fw-head); line-height:1.3;
}
body.es-page .es-play[data-gate="shut"] > .es-predict{ box-shadow:0 0 0 6px var(--es2-sun); }
body.es-page :is(.es-predict, .es-pick) .es-opt svg{ width:calc(40px * var(--es2-zoom)); height:calc(40px * var(--es2-zoom)); flex:none; }
/* 상태 줄 — 높이를 처음부터 잡는다(빈 줄 → '정했어요' 로 바뀌어도 쪽 높이 그대로) */
body.es-page :is(.es-predict-st, .es-pick-st, .es-self-st){
  min-height:calc(var(--es2x-cap) * 1.45); margin:0; max-width:none;
  font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); line-height:1.45; color:var(--es2-ok);
}
body.es-page :is(.es-predict, .es-pick)[data-st="shown"] :is(.es-predict-st, .es-pick-st){ color:var(--es2-ink-2); }
/* 안내자 말풍선 — 장면 폭 700 이상이면 장면 오른쪽 위에 겹치고, 미만이면 장면 아래 [얼굴 | 말] 한 줄(DESIGN 3-4 · 3-14).
   장면 폭 = 무대 틀 폭 − 왼쪽 열 − 사이. 그래서 틀(.es-play)을 container 로 재고 칸 수에 따라 문턱을 둘로 둔다.
   POLISH: ↻ 다시 보기는 말풍선 줄에서 뺐다(엔진이 .es-play 의 형제로 만든다 — 자리는 아래 '다시 보기' 규칙). 셋이 한 줄에 서면 말이
   3~5줄로 꺾였다(관문 ② 실측 390 5줄 · 1366 4줄 · 1180 6줄 · TV 교사 3줄) */
body.es-page .es-guide{
  display:grid; grid-template-columns:var(--es2-guide) minmax(0,1fr); align-items:center; column-gap:8px;
  min-height:max(calc(var(--es2-guide) + 4px), calc(var(--es2-fs-say) * 1.42 * 2 + 22px)); box-sizing:border-box;   /* 말 두 줄까지는 줄 높이가 그대로(계약 3-2 — 두 문장 40자) */
}
body.es-page .es-guide-face{ display:block; width:var(--es2-guide); grid-column:1; grid-row:1; }
body.es-page .es-guide-face > svg{ display:block; width:100%; height:auto; overflow:visible; }
body.es-page .es-guide-face[data-fx="tick"]{ animation:es2-tick var(--es2-t-quick) var(--es2-ease) 1; }
body.es-page .es-guide-say{
  grid-column:2; grid-row:1; justify-self:start; margin:0; max-width:none;
  padding:8px 14px; border:var(--es2-bw) solid var(--es2-ink); border-radius:20px; background:var(--es2-card);
  font-size:var(--es2-fs-say); font-weight:var(--es2-fw-strong); line-height:1.42; box-shadow:var(--es2-sh-say);
}
html.js body.es-page .es-guide[hidden]{ display:grid !important; visibility:hidden; }
@container es2play (min-width:1084px){
  body.es-page .es-play > .es-guide{
    grid-row:1 / 5; align-self:start; justify-self:end; z-index:2; pointer-events:none;
    margin:calc(var(--es2-bw) + 10px) calc(var(--es2-bw) + 10px) 0 0; min-height:0;
    grid-template-columns:var(--es2-guide) minmax(0, max-content); max-width:min(400px, 46%);
  }
  html.js body.es-page .es-play > .es-guide[hidden]{ display:none !important; }
}
@container es2play (min-width:700px){
  body.es-page .es-play:not(:has(> :is(.es-predict, .es-tip, .es-ops[data-zone="pick"]))) > .es-guide{
    grid-row:1 / 5; align-self:start; justify-self:end; z-index:2; pointer-events:none;
    margin:calc(var(--es2-bw) + 10px) calc(var(--es2-bw) + 10px) 0 0; min-height:0;
    grid-template-columns:var(--es2-guide) minmax(0, max-content); max-width:min(400px, 46%);
  }
  html.js body.es-page .es-play:not(:has(> :is(.es-predict, .es-tip, .es-ops[data-zone="pick"]))) > .es-guide[hidden]{ display:none !important; }
}
/* 도장 — 엔진이 장면 오른쪽 아래에 한 번(DESIGN 3-4). 장면 아래 테에 걸쳐 장면 안 누를 곳을 덜 가린다 */
body.es-page .es-stamp{
  position:absolute; right:-8px; bottom:-16px; z-index:2; pointer-events:none;
  padding:4px 12px; border:var(--es2-bw-2) solid var(--es2-stamp); border-radius:14px; background:var(--es2-card);
  color:var(--es2-danger); font-size:var(--es2-fs-btn); font-weight:var(--es2-fw-head); line-height:1.2; white-space:nowrap;
  transform:rotate(-7deg); transform-origin:50% 50%;
}
body.es-page .es-stamp[data-fx="stamp"]{ animation:es2-stamp var(--es2-t-peel) var(--es2-ease-pop) 1 both; }
/* 기록 칸 — 잠그지 않는다. 처음부터 칸마다 '빈 그릇 + ?' 그림, 채우면 퐁 + ✓ 점 + 셈(계약 1-6 · 1-7-3 보장 12) */
body.es-page .es-play > .es-log{ display:grid; grid-template-columns:minmax(0,1fr) auto; align-content:start; row-gap:8px; column-gap:8px; }
body.es-page .es-play > .es-log::before{ grid-column:1; grid-row:1; content:counter(es2step, es2-circ) "\00a0" attr(aria-label); }
body.es-page .es-play > .es-log:not([aria-label])::before{ content:counter(es2step, es2-circ); }
body.es-page .es-log-sum{ grid-column:2; grid-row:1; display:flex; align-items:center; gap:6px; margin:0; max-width:none; }
body.es-page .es-log-n{
  display:inline-flex; align-items:center; justify-content:center; box-sizing:border-box; min-width:var(--es2-tap); height:var(--es2-icon); padding:0 6px;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:10px; background:var(--es2-sun);
  font-size:var(--es2-fs-label); font-weight:var(--es2-fw-head); line-height:1; white-space:nowrap;
}
body.es-page .es-log-star{ font-size:var(--es2-fs-btn); color:var(--es2-again); line-height:1; }
body.es-page .es-log-row{ grid-column:1 / -1; display:grid; grid-template-columns:calc(76px * var(--es2-zoom)) repeat(auto-fill, minmax(calc(72px * var(--es2-zoom)), 1fr)); gap:8px; align-items:stretch; }
body.es-page .es-log-head{ display:flex; align-items:center; font-size:var(--es2-fs-body); font-weight:var(--es2-fw-head); line-height:1.15; }
body.es-page .es-log-cell{
  position:relative; box-sizing:border-box; display:grid; grid-template-rows:minmax(0,1fr) auto; justify-items:center; align-items:center;
  height:calc(112px * var(--es2-zoom)); padding:4px 2px 4px;
  border:var(--es2-bw) dashed var(--es2-line-todo); border-radius:var(--es2-r-sm); background:var(--es2-card);
}
body.es-page .es-log-cell > svg{ display:block; width:100%; height:100%; min-height:0; }
body.es-page .es-log-name{ font-size:var(--es2-fs-label); font-weight:var(--es2-fw-strong); line-height:1.15; text-align:center; max-width:100%; }
body.es-page .es-log-cell[data-st="got"]{ border-style:solid; border-color:var(--es2-ink); background:var(--es2-cmp); }
body.es-page .es-log-cell[data-st="got"]::after{
  content:"✓"; position:absolute; right:-7px; top:-10px; box-sizing:border-box;
  width:26px; height:26px; border-radius:50%; display:grid; place-items:center;
  border:var(--es2-bw-1) solid var(--es2-card); background:var(--es2-ok); color:var(--es2-on-dark); font-size:16px; font-weight:900; line-height:1;
}
body.es-page .es-log-cell[data-star]{ border-color:var(--es2-again); }
body.es-page .es-log-cell[data-star][data-st="got"]{ background:var(--es2-sun-soft); border-color:var(--es2-ink); }
body.es-page .es-log-cell[data-fx="pop"]{ animation:es2-pop var(--es2-t-pop) var(--es2-ease-out) 1; }
body.es-page .es-log-cell[data-fx="again"]{ animation:es2-tick var(--es2-t-quick) var(--es2-ease) 1; }
/* 나란히 보기 — 줄 머리(어두운 이름표)와 '내 예상' 은 처음부터, 값 칸만 잠긴다. 판정 칩 줄은 처음부터 자리를 잡는다 */
body.es-page .es-play > .es-cmp{ display:grid; align-content:center; gap:calc(10px * var(--es2-zoom)); background:var(--es2-cmp); }
body.es-page .es-cmp > p{
  display:grid; grid-template-columns:auto minmax(0,1fr); column-gap:12px; row-gap:6px; align-items:center;
  margin:0; max-width:none; font-weight:var(--es2-fw-strong); line-height:1.45;
}
body.es-page .es-cmp > p > b{
  grid-column:1; grid-row:1; align-self:start; box-sizing:border-box; min-width:calc(104px * var(--es2-zoom)); text-align:center;
  padding:1px 9px; border-radius:var(--es2-r-xs); background:var(--es2-ink); color:var(--es2-on-dark);
  font-size:var(--es2-fs-label); font-weight:var(--es2-fw-head); line-height:1.6;
}
body.es-page .es-cmp > p > :not(b):not(.es-pill){ grid-column:2; grid-row:1; }
body.es-page .es-cmp > p > .es-cmp-judge:not(.es-pill){ grid-row:2; }
body.es-page .es-cmp > p:has(> .es-cmp-mine){ grid-template-rows:auto calc(var(--es2-fs-label) * 1.6 + 6px); }
body.es-page .es-cmp-mine{
  justify-self:start; box-sizing:border-box; padding:2px 12px;
  border:var(--es2-bw) dashed var(--es2-line-todo); border-radius:14px; background:var(--es2-card); color:var(--es2-ink-2);
  font-weight:var(--es2-fw-head);
}
body.es-page .es-cmp-mine[data-st="set"]{ border-style:solid; border-color:var(--es2-ink); background:var(--es2-sky-soft); color:var(--es2-ink); }
/* REVIEW screen-9: 판정 알약('예상과 같았어요!')은 아이가 읽는 문장이다 — 이름표 17 이 아니라 캡션 18(SPEC_v2 266 · DESIGN 318 '이름표만 17') */
body.es-page .es-cmp-judge{
  justify-self:start; padding:0 10px; border-radius:var(--es2-r-xs); background:var(--es2-sun-soft);
  font-size:var(--es2-fs-cap); font-weight:var(--es2-fw-head); line-height:1.6;
}
/* 무대 — 861~1240(태블릿 가로 · 작은 노트북): 장면이 단계판 둘보다 낮아 장면 아래가 비지 않게 — 장면은 예상과 같은 줄, 그 아래 줄부터 말풍선 · 알약 · 조작 줄 */
@media (min-width:861px) and (max-width:1240px){
  body.es-page .es-play > .es-predict{ grid-row:1; }
  body.es-page .es-play > .es-scene{ grid-row:1; }
  body.es-page .es-play > .es-ops[data-zone="pick"]{ grid-row:2 / 4; }
  body.es-page .es-play > .es-guide{ grid-row:2; }
  body.es-page .es-play > .es-pill{ grid-row:3; }
  body.es-page .es-play > button[data-replay]{ grid-row:3; }
  body.es-page .es-play > .es-ops[data-zone="act"]{ grid-row:4; }
  body.es-page .es-play > .es-ops[data-zone="act"] ~ .es-ops[data-zone="act"]{ grid-row:5; }
  body.es-page .es-play > .es-tip{ grid-row:4 / 10; }
  body.es-page .es-play > .es-ops[data-zone="pick"] ~ .es-ops[data-zone="pick"]{ grid-row:4; }
  body.es-page .es-play:has(> .es-ops[data-zone="pick"] ~ .es-ops[data-zone="pick"]) > .es-tip{ grid-row:5 / 10; }
}
/* 위 묶음은 말풍선이 장면 아래 줄일 때만 — 말풍선이 장면에 겹치는 폭(틀 안쪽 1084 이상)이면 넓은 창 자리로 되돌린다 */
@container es2play (min-width:1084px){
  body.es-page .es-play > .es-scene{ grid-row:1 / 5; }
  body.es-page .es-play > .es-ops[data-zone="pick"]{ grid-row:2; }
  body.es-page .es-play > .es-ops[data-zone="pick"] ~ .es-ops[data-zone="pick"]{ grid-row:3; }
  body.es-page .es-play > .es-tip{ grid-row:4 / 10; }
  body.es-page .es-play > .es-pill{ grid-row:6; }
  body.es-page .es-play > .es-ops[data-zone="act"]{ grid-row:7; }
  body.es-page .es-play > .es-ops[data-zone="act"] ~ .es-ops[data-zone="act"]{ grid-row:8; }
  body.es-page .es-play > .es-guide{ grid-row:1 / 5; }
  body.es-page .es-play > button[data-replay]{ grid-row:6; }
}
/* POLISH: 말풍선이 장면에 겹치지 않는 폭(틀 안쪽 1084 미만)에서는 알약 줄이 좁다 — 알약은 왼쪽, 다시 보기는 오른쪽 끝(X2 알약 274 · 1024 장면 열 544 에서 가운데 두면 겹쳤다) */
@container es2play (max-width:1083px){
  body.es-page .es-play:has(> button[data-replay]) > .es-pill{ justify-self:start; }
}
/* 무대 — 860 이하: 한 줄로 쌓는다(예상 → 장면 → 조작 — DESIGN 3-4 · 6절 #12) */
@media (max-width:860px){
  body.es-page .es-play{ grid-template-columns:[l r] minmax(0,1fr); grid-template-rows:none; padding:8px 8px 10px; border-radius:26px; margin-top:calc(30px * var(--es2-zoom)); }
  body.es-page .es-play > *{ grid-column:1 / -1 !important; }
  body.es-page .es-play > .es-predict{ grid-row:1; }
  body.es-page .es-play > .es-scene{ grid-row:2; margin-top:12px; }
  body.es-page .es-play:not(:has(> .es-predict)) > .es-scene{ margin-top:0; }
  body.es-page .es-play > .es-guide{ grid-row:3; }
  body.es-page .es-play > button[data-replay]{ grid-row:5; }   /* POLISH: 알약 줄 끝(폰은 아래에서 따로 4) */
  body.es-page .es-play > .es-pill{ grid-row:5; }
  body.es-page .es-play > .es-ops[data-zone="act"]{ grid-row:6; }
  body.es-page .es-play > .es-ops[data-zone="act"] ~ .es-ops[data-zone="act"]{ grid-row:7; }
  body.es-page .es-play > .es-ops[data-zone="pick"],
  body.es-page .es-play:not(:has(> .es-predict)) > .es-ops[data-zone="pick"]{ grid-row:8; margin-top:12px; }
  body.es-page .es-play > .es-ops[data-zone="pick"] ~ .es-ops[data-zone="pick"],
  body.es-page .es-play:not(:has(> .es-predict)) > .es-ops[data-zone="pick"] ~ .es-ops[data-zone="pick"]{ grid-row:9; }
  body.es-page .es-play > .es-tip,
  body.es-page .es-play:not(:has(> .es-predict)) > .es-tip,
  body.es-page .es-play:not(:has(> .es-ops[data-zone="pick"])) > .es-tip,
  body.es-page .es-play:not(:has(> .es-predict)):not(:has(> .es-ops[data-zone="pick"])) > .es-tip{ grid-row:10; margin-top:12px; }
  body.es-page .es-play > .es-ops[data-zone="undo"]{ grid-row:11; }
  body.es-page .es-play > .es-log{ grid-row:12; margin-top:12px; }
  body.es-page .es-play > .es-cmp{ grid-row:13; margin-top:12px; }
  body.es-page .es-play[data-tab]::before{ left:22px; }
  body.es-page .es-log-row{ grid-template-columns:72px repeat(auto-fill, minmax(60px, 1fr)); }
  body.es-page .es-log-head{ font-size:var(--es2-fs-label); }
  body.es-page .es-play .es-ops[data-zone="act"]{ grid-template-columns:repeat(auto-fit, minmax(min(100%, 96px), 1fr)); }
  body.es-page .es-play > :is(.es-pill, .es-ops){ align-self:start; }
  body.es-page .es-play .es-ops[data-zone="act"] button[data-op]{ padding:6px 4px; font-size:var(--es2-fs-body); }
  body.es-page .es-cmp > p{ grid-template-columns:minmax(0,1fr); }
  body.es-page .es-cmp > p > b{ justify-self:start; }
  body.es-page .es-cmp > p > :not(b):not(.es-pill),
  body.es-page .es-cmp p > .es-pill{ grid-column:1; grid-row:2; }
  body.es-page .es-cmp > p > .es-cmp-judge:not(.es-pill){ grid-row:3; }
  body.es-page .es-cmp > p:has(> .es-cmp-mine){ grid-template-rows:auto auto calc(var(--es2-fs-label) * 1.6 + 6px); }
}
/* POLISH: 폰(틀 안쪽 480 미만)에서는 알약(X2 274px)과 다시 보기(143)가 한 줄에 안 든다 — 다시 보기는 말풍선 아래 줄(4)의 오른쪽 끝에 따로,
   알약은 그 아래 줄 가운데. 둘 다 자리를 처음부터 잡는다(N3) */
@container es2play (max-width:479px){
  body.es-page .es-play > button[data-replay]{ grid-row:4; margin-top:8px; }
  body.es-page .es-play:has(> button[data-replay]) > .es-pill{ justify-self:center; }
  /* 폰은 말풍선 줄을 세 줄까지 처음부터 잡는다 — 40자 말(계약 3-2)이 390 에서 세 줄이다(X2 '자연이 만든 것만 남았어요. 남은 것도 집게로 집어 볼까요?' 실측 3줄 ·
     두 줄만 잡으면 그 말이 뜰 때 쪽 높이가 28px 뛰었다 — N3) */
  body.es-page .es-guide{ min-height:max(calc(var(--es2-guide) + 4px), calc(var(--es2-fs-say) * 1.42 * 3 + 22px)); }
}

/* ══ 8. 교실 실물 · 이름 붙이기 — .es-real · .es-concept (DESIGN 3-7 · 3-8) ═══════════════════════════════ */
body.es-page .es-real{ display:grid; gap:calc(14px * var(--es2-zoom)); }
body.es-page .es-real > *{ margin:0; }
body.es-page .es-real-steps{ counter-reset:es2real; list-style:none; margin:0; padding:0; max-width:none; display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:var(--es2-gap); }
body.es-page .es-real-steps > li{
  counter-increment:es2real; position:relative; margin:0; box-sizing:border-box; display:grid; justify-items:center; align-content:start; gap:6px;
  padding:10px 10px 12px; border:var(--es2-bw) solid var(--es2-ink); border-radius:18px; background:var(--es2-wall);
  text-align:center; font-weight:var(--es2-fw-strong); line-height:1.35;
}
body.es-page .es-real-steps > li::before{
  content:counter(es2real); justify-self:start; display:grid; place-items:center; width:30px; height:30px; border-radius:50%;
  background:var(--es2-ink); color:var(--es2-on-dark); font-size:var(--es2-fs-label); font-weight:var(--es2-fw-head); line-height:1;
}
body.es-page .es-real-steps figure{ margin:0; width:100%; }
body.es-page .es-real-steps :is(svg, img){ display:block; width:100%; height:calc(118px * var(--es2-zoom)); object-fit:contain; }
body.es-page .es-real-steps p{ margin:0; max-width:none; }
body.es-page .es-safe{
  display:flex; align-items:center; gap:12px; margin:0; max-width:none; box-sizing:border-box;
  padding:10px 14px; border:var(--es2-bw) solid var(--es2-ink); border-radius:16px; background:var(--es2-again-soft);
  font-weight:var(--es2-fw-strong); line-height:1.45;
}
body.es-page .es-safe::before{
  content:""; flex:none; width:calc(44px * var(--es2-zoom)); height:calc(40px * var(--es2-zoom));
  background:no-repeat center/contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 44 40'%3E%3Cpath d='M22 3 L41 37 H3 Z' fill='%23FFD43B' stroke='%2317203A' stroke-width='3.5' stroke-linejoin='round'/%3E%3Cpath d='M22 15 V25' stroke='%2317203A' stroke-width='4' stroke-linecap='round'/%3E%3Ccircle cx='22' cy='31' r='2.6' fill='%2317203A'/%3E%3C/svg%3E");
}
/* 결과 고르기 · 수 입력 — 고르기 단추 2~3(56 · 사이 12) + '정했어요' 줄(높이를 미리 잡는다) */
body.es-page .es-pick{ display:flex; flex-wrap:wrap; gap:var(--es2-gap); align-items:center; }
body.es-page .es-pick > *{ margin:0; }
body.es-page .es-pick-q{ flex:1 1 100%; max-width:none; font-weight:var(--es2-fw-head); }
body.es-page .es-pick .es-opt{ flex:1 1 auto; }
body.es-page .es-pick-st{ flex:1 1 100%; }
body.es-page :is(.es-pick-num, .es-cq-in){
  box-sizing:border-box; width:calc(150px * var(--es2-zoom)); min-height:var(--es2-tap-lg); padding:4px 8px;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:16px; background:var(--es2-card); color:var(--es2-ink);
  font:var(--es2-fw-head) calc(30px * var(--es2-zoom))/1 var(--es2-font); text-align:center;
}
body.es-page :is(.es-pick-num, .es-cq-in)::placeholder{ color:var(--es2-ink-hint); opacity:1; }
body.es-page :is(.es-pick-num, .es-cq-in)[readonly]{ background:var(--es2-dim); }
/* REVIEW kid-4: 끝말을 붙여 쓴 답('인문환경이라고 해요')이 150 칸에서 다섯 글자만 보였다 — 처음엔 150(한 낱말 신호), 치는 만큼 칸이 는다(카드 폭까지) */
body.es-page .es-cq-in{ width:auto; field-sizing:content; min-width:calc(150px * var(--es2-zoom)); max-width:100%; }
/* 이름 붙이기 카드 — 사진(왼쪽 40%) + 이름표 + 두 문장. 잠긴 동안 사진은 흐리고 글은 막대(5절) */
body.es-page .es-concept{
  display:grid; grid-template-columns:minmax(0,1fr); gap:10px 18px; align-content:start; box-sizing:border-box;
  padding:calc(22px * var(--es2-zoom)) 18px 18px; border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r-md); background:var(--es2-panel);
}
body.es-page .es-concept:has(> figure){ grid-template-columns:minmax(0,2fr) minmax(0,3fr); }
body.es-page .es-concept > figure{ grid-column:1; grid-row:1 / span 8; margin:0; }
body.es-page .es-concept > figure > svg{ display:block; width:100%; height:auto; max-height:calc(300px * var(--es2-zoom)); }
body.es-page .es-concept > :not(figure){ grid-column:-2; margin:0; max-width:none; }
body.es-page .es-concept-name{
  justify-self:start; padding:2px 14px; border:var(--es2-bw) solid var(--es2-ink); border-radius:14px; background:var(--es2-sun-soft);
  font-size:calc(40px * var(--es2-zoom)); font-weight:var(--es2-fw-head); line-height:1.1;
}
/* 오늘 알게 된 것 — 줄마다 그림 + 한 줄 */
body.es-page .es-learned{ list-style:none; margin-bottom:0; margin-inline:0; padding:0; max-width:none; display:grid; gap:10px; }
body.es-page .es-learned > li{
  display:flex; align-items:center; gap:12px; margin:0; box-sizing:border-box; min-height:var(--es2-tap);
  padding:8px 14px; border:var(--es2-bw) solid var(--es2-ink); border-radius:16px; background:var(--es2-panel); font-weight:var(--es2-fw-strong);
}
body.es-page .es-learned > li > :is(svg, img){ flex:none; width:calc(40px * var(--es2-zoom)); height:calc(40px * var(--es2-zoom)); }
body.es-page .es-learned > li > p{ margin:0; max-width:none; flex:1 1 auto; }

/* ══ 9. 확인 묶음 — 3문항 + 제출하기 한 번 · 판정 칸은 상태 넷 겹침(DESIGN 3-9 · 견본 4절 · 계약 1-8-3) ══════ */
body.es-page .es-check{
  counter-reset:es2cq; display:grid; gap:calc(18px * var(--es2-zoom)); align-items:stretch;
  grid-template-columns:repeat(auto-fit, minmax(min(100%, calc(360px * var(--es2-zoom))), 1fr));
}
/* REVIEW screen-1: 사진 문항이 낀 묶음은 카드를 내용 높이로 — 같은 높이로 늘리면 사진 카드(X2 605px)에 맞춰
   그림 없는 카드 가운데가 250~470px 비었다. 사진이 없는 묶음은 DESIGN 3-9 대로 같은 높이 · 판정 칸 바닥 정렬 그대로.
   두 칸으로 꺾이는 폭(1024 · 1180 · TV)에서 혼자 아랫줄에 남는 마지막 카드는 줄 전폭을 쓴다(오른쪽 반이 통째로 비었다).
   칸 수 = auto-fit(min 360 · 사이 18) — 두 칸 = 738 ≤ 폭 < 1116, TV(×1.4) 1033.2 ≤ 폭 < 1562.4 */
body.es-page .es-check{ container:es2check / inline-size; }
body.es-page .es-check:has(> .es-cq .es-photo){ align-items:start; }
/* 두 칸일 때: 사진 카드(마지막 홀수가 아니면)는 두 줄을 차지해 다음 카드가 옆 카드 아래 빈 자리로 들어온다(X2 1024: 351 + 240 ≈ 589) ·
   사진 카드가 없으면 혼자 남는 마지막 카드가 줄 전폭 */
@container es2check (min-width:738px) and (max-width:1115.98px){
  body.es-page .es-check:not(:has(> .es-cq .es-photo)) > .es-cq:last-of-type:nth-of-type(odd),
  body.es-page .es-check > .es-cq:last-of-type:nth-of-type(odd):has(.es-photo){ grid-column:1 / -1; }
  body.es-page .es-check > .es-cq:has(.es-photo):not(:last-of-type:nth-of-type(odd)){ grid-row:span 2; }
}
@container es2check (min-width:1033.2px) and (max-width:1562.38px){
  html.es-tv body.es-page .es-check:not(:has(> .es-cq .es-photo)) > .es-cq:last-of-type:nth-of-type(odd),
  html.es-tv body.es-page .es-check > .es-cq:last-of-type:nth-of-type(odd):has(.es-photo){ grid-column:1 / -1; }
  html.es-tv body.es-page .es-check > .es-cq:has(.es-photo):not(:last-of-type:nth-of-type(odd)){ grid-row:span 2; }
}
body.es-page .es-check > *{ margin:0; }
body.es-page .es-check > :not(.es-cq){ grid-column:1 / -1; }
body.es-page .es-check > button[data-grade-btn]{ justify-self:start; }
body.es-page .es-cq{
  counter-increment:es2cq; display:flex; flex-direction:column; gap:10px; box-sizing:border-box; min-width:0;
  padding:14px 14px 12px; border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r-md); background:var(--es2-panel);
  transition:background-color var(--es2-t-state);
}
body.es-page .es-cq::before{ content:"확인 " counter(es2cq); font-size:var(--es2-fs-label); font-weight:var(--es2-fw-head); color:var(--es2-ink-2); line-height:1.3; }
body.es-page .es-cq > *{ margin:0; max-width:none; }
body.es-page .es-cq-t{ font-weight:var(--es2-fw-head); line-height:1.45; }
body.es-page .es-cq[data-st="ok"], body.es-page .es-cq[data-st="ok2"]{ background:var(--es2-ok-soft); }
/* REVIEW screen-10: 폰(보기 줄 안쪽 286px)에서 88 × 3 + 사이 24 = 288 이 2px 모자라 보기 셋이 2 + 1 로 꺾였다 — 칸 하한을 '세 칸이 드는 폭' 과 88 중 작은 것으로 */
body.es-page .es-cq-opts{ display:grid; gap:var(--es2-gap); grid-template-columns:repeat(auto-fit, minmax(min(calc(88px * var(--es2-zoom)), calc((100% - 2 * var(--es2-gap)) / 3)), 1fr)); }
body.es-page .es-cq-opts .es-opt{ position:relative; flex-direction:column; gap:4px; padding:6px 4px 8px; border-radius:16px; min-height:var(--es2-tap); }
body.es-page .es-cq[data-qtype="pic"] .es-cq-opts .es-opt{ min-height:calc(120px * var(--es2-zoom)); }
body.es-page .es-cq-opts .es-opt svg{ display:block; width:100%; height:calc(96px * var(--es2-zoom)); }
body.es-page .es-cq-opts .es-opt[aria-checked="true"]{ outline:var(--es2-bw-2) solid var(--es2-sky); outline-offset:-1px; }
body.es-page .es-cq-opts .es-opt[aria-checked="true"]::before{
  content:"✓"; position:absolute; top:-11px; right:-8px; box-sizing:border-box; width:28px; height:28px; border-radius:50%;
  display:grid; place-items:center; border:var(--es2-bw-1) solid var(--es2-card); background:var(--es2-sky-deep); color:var(--es2-on-dark); font-size:17px; font-weight:900; line-height:1;
}
body.es-page .es-cq-opts .es-opt.is-hit{ background:var(--es2-ok-soft); }
body.es-page .es-cq-opts .es-opt.is-key{ outline:var(--es2-bw-2) solid var(--es2-ok); outline-offset:-1px; background:var(--es2-ok-soft); }
body.es-page .es-cq-opts .es-opt.is-key::after{
  content:"답"; position:absolute; top:-11px; left:-8px; box-sizing:border-box; width:30px; height:30px; border-radius:50%;
  display:grid; place-items:center; border:var(--es2-bw-1) solid var(--es2-card); background:var(--es2-ok); color:var(--es2-on-dark); font-size:17px; font-weight:900; line-height:1;
}
/* 판정 칸 — 상태 넷을 한 격자 칸에 겹친다. 지금 것만 보이는 일은 es.js(인라인 visibility)가 맡고, 칸 높이는 가장 큰 상태를 따른다 */
body.es-page .es-cq-fb{ display:grid; margin-top:auto; padding-top:4px; font-weight:var(--es2-fw-head); line-height:1.4; }
body.es-page .es-cq-fb > *{ grid-area:1 / 1; align-self:start; margin:0; max-width:none; }
body.es-page .es-cq-fb > * > p{ margin:0; max-width:none; }
body.es-page .es-cq-fb > [data-fb="ok"], body.es-page .es-cq-fb > [data-fb="ok2"] > p:first-child{ color:var(--es2-ok); }
body.es-page .es-cq-fb > [data-fb="again"]{ color:var(--es2-again); display:flex; flex-wrap:wrap; align-items:center; gap:6px 10px; }
body.es-page .es-cq-why{ margin-top:4px; color:var(--es2-ink); font-weight:700; }
body.es-page .es-cq-key{
  display:inline-grid; place-items:center; width:30px; height:30px; margin-right:6px; vertical-align:middle; border-radius:50%;
  background:var(--es2-ok); color:var(--es2-on-dark); font-size:var(--es2-fs-label); font-weight:900; line-height:1;
}
body.es-page .es-check-st{ min-height:calc(var(--es2x-cap) * 1.45); font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); color:var(--es2-ink-2); line-height:1.45; max-width:none; }
body.es-page .es-check > button[data-grade-btn] + .es-check-st{ margin-top:calc(-6px * var(--es2-zoom)); }

/* ══ 10. 제출형 쓰기 — .es-wq (DESIGN 3-10 · 계약 1-8-4 · 2-5) ═══════════════════════════════════════════
   확인 상자는 보내기 단추 아래 줄(상태 줄 자리)에 겹쳐 뜬다 — 단추와 한 칸을 나눠 쓰지 않는다(c 의 단추 늘어남).
   상태 줄 칸 높이 · 예시 답안 상자 높이는 처음부터 잡는다(상태가 바뀌어도 쪽 높이 그대로). */
body.es-page .es-wq{ position:relative; display:block; }
body.es-page .es-wq > *{ margin:0; max-width:none; }
body.es-page .es-wq-q{ display:block; font-size:var(--es2-fs-h3); font-weight:var(--es2-fw-head); line-height:1.4; margin-bottom:10px; }
body.es-page .es-wq-chip{ min-height:var(--es2-tap); margin:0 var(--es2-gap) var(--es2-gap) 0; padding:4px 16px; border-radius:var(--es2-r-pill); box-shadow:0 3px 0 var(--es2-ink); background:var(--es2-sun-soft); }
/* REVIEW kid-5: 이미 넣은 칩은 흐린 점선 — 다시 누르면 붙지 않고 흔들림만(es.js) */
body.es-page .es-wq-chip[data-used]{ background:var(--es2-card); box-shadow:none; border-style:dashed; color:var(--es2-ink-2); }
body.es-page .es-wq-chip[data-fx="blocked"]{ animation:es2-nudge var(--es2-t-pop) var(--es2-ease) 1; }
body.es-page .es-wq-draft{
  display:block; box-sizing:border-box; width:100%; min-height:calc(126px * var(--es2-zoom)); resize:vertical; padding:12px 16px;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:18px; background:var(--es2-panel); color:var(--es2-ink);
  font:600 var(--es2-fs-lead)/1.55 var(--es2-font);
}
body.es-page .es-wq-draft::placeholder{ color:var(--es2-ink-hint); opacity:1; }
body.es-page .es-wq-draft[readonly]{ background:var(--es2-dim); }
body.es-page .es-wq > button[data-send]{ margin-top:12px; }
body.es-page .es-wq-st{
  display:flex; flex-wrap:wrap; align-items:center; gap:8px 12px; box-sizing:border-box; margin-top:10px;
  min-height:var(--es2-tap);
  font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); line-height:1.45; color:var(--es2-ink);
}
body.es-page .es-wq-st::before{ flex:none; font-weight:900; }
body.es-page .es-wq-st:is([data-st="idle"], [data-st="in"], [data-st="short"])::before{ content:"✎"; }
body.es-page .es-wq-st[data-st="sending"]::before{ content:"…"; }
body.es-page .es-wq-st[data-st="server"]{ color:var(--es2-ok); }
body.es-page .es-wq-st[data-st="server"]::before{ content:"✓"; }
body.es-page .es-wq-st:is([data-st="out"], [data-st="pv"]){ align-self:start; }
body.es-page .es-wq-st:is([data-st="fail"], [data-st="refused"], [data-st="auth"]){ color:var(--es2-again); }
body.es-page .es-wq-st:is([data-st="fail"], [data-st="refused"], [data-st="auth"])::before{ content:"↺"; }
body.es-page .es-wq-st[data-st="authwait"]::before, body.es-page .es-wq-st[data-st="auth-wait"]::before{ content:"…"; }
body.es-page .es-wq-st[data-st="carry"]{ color:var(--es2-sky-deep); }
body.es-page .es-wq-st[data-st="carry"]::before{ content:"✎"; }
body.es-page .es-wq-st :is(a.es-wq-login, button){ font-size:var(--es2-fs-btn); }
body.es-page .es-wq-st a.es-wq-login{ border-style:dashed; border-color:var(--es2-ink-2); box-shadow:none; }
body.es-page .es-wq-ask{
  position:absolute; left:0; right:0; z-index:var(--es2-z-lock);
  display:flex; flex-wrap:wrap; align-items:center; gap:10px 12px; box-sizing:border-box; margin-top:10px; padding:10px 14px;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:18px; background:var(--es2-again-soft); box-shadow:var(--es2-sh-say);
}
body.es-page .es-wq-ask > p{ flex:1 1 14em; margin:0; max-width:none; font-weight:var(--es2-fw-head); }
body.es-page .es-wq-ask:not([hidden]) ~ .es-wq-st{ visibility:hidden; }
/* 예시 답안 — 서버 확인 뒤에만 열린다. 열린 높이를 처음부터 잡고(점선 테 + 글줄 막대), 열리면 초록 판 */
body.es-page .es-model{
  position:relative; box-sizing:border-box; margin-top:calc(14px * var(--es2-zoom)); padding:14px 18px;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:20px; background:var(--es2-ok-soft);
  font-weight:700; line-height:1.55;
}
html.js body.es-page .es-model[hidden]{ display:block !important; visibility:hidden; }
html.js body.es-page .es-model[hidden]::before{
  content:""; visibility:visible; position:absolute; inset:calc(-1 * var(--es2-bw)); box-sizing:border-box;
  border:var(--es2-bw) dashed var(--es2-line-todo); border-radius:20px; background:var(--es2-cmp);
}
html.js body.es-page .es-model[hidden]::after{
  content:""; visibility:visible; position:absolute; inset:14px 18px;
  background-image:linear-gradient(to bottom, transparent 22%, var(--es2-skeleton) 22%, var(--es2-skeleton) 74%, transparent 74%);
  background-size:100% 1lh; background-repeat:repeat-y;
}

/* ══ 11. 정리 — 스스로 점검 · 스티커 · 더 알아보기 (DESIGN 3-11 · 3-12) ═════════════════════════════════════ */
body.es-page .es-self{ display:flex; flex-wrap:wrap; gap:var(--es2-gap); align-items:stretch; }
body.es-page .es-self > *{ margin:0; }
body.es-page .es-self-q{ flex:1 1 100%; max-width:none; font-weight:var(--es2-fw-head); }
body.es-page .es-self .es-opt{ flex:1 1 calc(160px * var(--es2-zoom)); min-height:calc(96px * var(--es2-zoom)); font-size:var(--es2-fs-btn); }
body.es-page .es-self-st{ flex:1 1 100%; color:var(--es2-ink-2); }
/* 스티커 칸 — 200 고정(상태가 바뀌어도 높이 그대로). 아직 = 점선 + 회색 윤곽 · 붙음 = 실선 + 붙기 · out = 점선 */
body.es-page .es-sticker{
  position:relative; box-sizing:border-box; height:calc(200px * var(--es2-zoom)); display:grid; place-content:center; justify-items:center; gap:4px;
  padding:10px; border:var(--es2-bw) dashed var(--es2-line-todo); border-radius:24px; background:var(--es2-panel); text-align:center;
}
body.es-page .es-sticker > *{ margin:0; max-width:none; }
body.es-page .es-sticker-art{ width:calc(112px * var(--es2-zoom)); height:calc(112px * var(--es2-zoom)); }
body.es-page .es-sticker-art > svg{ display:block; width:100%; height:100%; }
body.es-page .es-sticker:not([data-st="on"]) .es-sticker-art{ filter:grayscale(1); opacity:.35; width:calc(84px * var(--es2-zoom)); height:calc(84px * var(--es2-zoom)); }
body.es-page .es-sticker-say{ font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); color:var(--es2-ink-2); line-height:1.4; }
body.es-page .es-sticker[data-st="on"]{ border-style:solid; border-color:var(--es2-ink); background:var(--es2-tip); }
body.es-page .es-sticker[data-st="on"] .es-sticker-say{ color:var(--es2-ink); }
body.es-page .es-sticker[data-st="on"] .es-sticker-art{ transform:rotate(-6deg); }
body.es-page .es-sticker-art[data-fx="peel"], body.es-page .es-sticker[data-fx="peel"] .es-sticker-art{ animation:es2-peel var(--es2-t-peel) var(--es2-ease-pop) 1 both; }
body.es-page .es-sticker:has(> a.es-sticker-go:not([hidden])){ grid-template-rows:auto auto auto; }
body.es-page .es-sticker:has(> a.es-sticker-go:not([hidden])) .es-sticker-art{ width:calc(88px * var(--es2-zoom)); height:calc(88px * var(--es2-zoom)); }
body.es-page a.es-sticker-go{ font-size:var(--es2-fs-btn); }
/* 더 알아보기 — 머리표 + 카드 둘 이상(1366 두 칸 · 860 이하 한 칸). 잠그지 않는다 */
body.es-page .es-part[data-explore]{ display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); column-gap:calc(20px * var(--es2-zoom)); row-gap:0; }
body.es-page .es-part[data-explore] > *{ grid-column:1 / -1; }
body.es-page .es-part[data-explore] > .es-more{ grid-column:auto; }
body.es-page .es-more-kicker{
  justify-self:start; padding:0 12px; border:var(--es2-bw) solid var(--es2-ink); border-radius:14px; background:var(--es2-k-more);
  font-size:var(--es2-fs-label); font-weight:var(--es2-fw-head); line-height:1.8; max-width:none;
}
body.es-page .es-part[data-explore] > .es-more-kicker{ position:absolute; top:calc(-20px * var(--es2-zoom)); left:calc(28px * var(--es2-zoom)); margin:0; box-shadow:0 4px 0 var(--es2-ink); }
body.es-page .es-part[data-explore] > .es-more-kicker + *{ margin-top:0; }
/* REVIEW screen-12(과학 3-2 07/02 기준편): 머리표는 절 위 끝에 걸친 absolute(아래 그림자 4)라 제목 윗줄과 겹쳤다 — 390 에서 머리표 아래 끝 + 그림자가
   제목 상자 위 끝보다 5px 아래(사회 4-2 10/01 도 같음) · 1366 은 3px. 제목을 12px 내려 그림자 아래 6px 이상을 둔다(320 · 360 · 390 · 1366 · TV 실측) */
body.es-page .es-part[data-explore] > .es-more-kicker + h2{ margin-top:calc(12px * var(--es2-zoom)); }
/* REVIEW screen-8: 두 칸일 때 첫 줄 두 카드의 위 끝을 맞춘다 — 첫 카드는 h2 뒤 14, 둘째는 블록 사이 24 라 10~14px 계단이 졌다(아랫줄은 둘 다 24) */
@media (min-width:861px){ body.es-page .es-part[data-explore] > h2 + .es-more + .es-more{ margin-top:calc(14px * var(--es2-zoom)); } }
body.es-page .es-more{ display:flex; flex-direction:column; gap:10px; box-sizing:border-box; overflow:hidden; border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r-md); background:var(--es2-card); padding:0 0 16px; }
body.es-page .es-more > *{ margin:0 18px; max-width:none; }
body.es-page .es-more > figure:first-child{ margin:0; border-bottom:var(--es2-bw) solid var(--es2-ink); background:var(--es2-wall); }
body.es-page .es-more > figure:first-child > figcaption{ margin:8px 18px 10px; }
body.es-page .es-more > figure > svg{ display:block; width:100%; height:auto; aspect-ratio:560 / 250; }
body.es-page .es-more > :is(h3, h4){ font-size:var(--es2-fs-h3); font-weight:var(--es2-fw-head); }
/* REVIEW kid-7 · screen-9(과학 3-2 07/02 기준편): 사진 머리 카드(4:3 사진 — 높이 420 안팎)와 그림 머리 카드(560:250)가 한 줄에 서면 격자 기본(stretch)이
   그림 카드를 사진 카드 높이로 늘려 글 아래에 빈 흰 판이 생겼다(1366 252px · TV 298px). 사진 머리 카드가 있는 절만 카드를 제 높이로 둔다 —
   그림 카드뿐인 절(사회 4-2 10/01 넷)은 지금처럼 키를 맞춘다. 사진 머리는 카드 머리 띠(아래 테 · 바탕)가 틀을 맡으므로 사진 자신의 테를 걷는다(이중 테두리) */
body.es-page .es-part[data-explore]:has(> .es-more > figure.es-photo:first-child) > .es-more{ align-self:start; }
body.es-page .es-more > figure.es-photo:first-child > img{ border:0; border-radius:0; }

/* ══ 11b. 권 도감 — 권 랜딩 안 구획 section.es-dogam#es-dogam (DESIGN 3-13 · 계약 2-10) ══════════════════════════
   붙음 = 단원 색 테 + 기울기 · 방금 = 노랑 '방금 붙었어요!' · 아직 = 점선 + 회색 그림 — 모양과 글로도 가른다. 점수 · 등수 없음.
   ⚠️ 권 랜딩의 body 에 es-page 가 있어야 이 규칙이 붙는다(계약 1-3 'v2 모양 규칙은 body.es-page 아래' — B1 · 리드에게 보고) */
body.es-page .es-dogam{
  display:grid; gap:calc(16px * var(--es2-zoom)); box-sizing:border-box; max-width:var(--es2-content); margin:var(--es2-sec-gap) auto 0;
  padding:var(--es2x-pad) calc(28px * var(--es2-zoom)) calc(30px * var(--es2-zoom));
  background:var(--es2-card); border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r-lg); box-shadow:var(--es2-sh-card);
  scroll-margin-top:calc(var(--es2x-band) + 12px); color:var(--es2-ink); font-family:var(--es2-font); font-size:var(--es2-fs-body); font-weight:var(--es2-fw-body); line-height:var(--es2-lh-body); letter-spacing:0; word-break:keep-all; overflow-wrap:break-word;   /* 권 랜딩은 1절 바탕을 안 받는다(es-land) — 도감 안 글 바탕을 여기서 다시 준다 */
}
body.es-page .es-dogam-head{ display:grid; gap:6px; border-top:6px solid var(--es2-subj-mid); padding-top:12px; }
body.es-page .es-dogam-head > *{ margin:0; max-width:none; }
body.es-page .es-dogam-head > :is(h2, h3){ font-size:var(--es2-fs-h2); font-weight:var(--es2-fw-head); line-height:var(--es2-lh-head); font-family:inherit; letter-spacing:-0.01em; }
body.es-page .es-dogam-head > p{ font-size:var(--es2-fs-lead); font-weight:700; color:var(--es2-ink-2); }
body.es-page .es-dogam-login{ display:flex; flex-wrap:wrap; align-items:center; gap:8px 12px; padding:8px 14px; border:var(--es2-bw) dashed var(--es2-ink-2); border-radius:16px; background:var(--es2-card); }
body.es-page .es-dogam-login > a{
  display:inline-flex; align-items:center; justify-content:center; box-sizing:border-box; min-height:var(--es2-tap); min-width:var(--es2-tap); padding:8px 18px;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r); background:var(--es2-sun); color:var(--es2-ink); box-shadow:var(--es2-sh-btn);
  font-size:var(--es2-fs-btn); font-weight:var(--es2-fw-strong); text-decoration:none;
}
body.es-page .es-dogam-grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(calc(132px * var(--es2-zoom)), 1fr)); gap:calc(18px * var(--es2-zoom)) var(--es2-gap); }
body.es-page .es-dogam-cell{ position:relative; display:grid; justify-items:center; align-content:start; gap:6px; text-align:center; min-width:0; }
/* 스티커 원 108(390 86) — 칸 안 그림(svg · img · .es-sticker-art)이 있으면 그것을, 없으면 빈 원을 그린다 */
body.es-page .es-dogam-cell > :is(svg, img, .es-sticker-art),
body.es-page .es-dogam-cell:not(:has(> :is(svg, img, .es-sticker-art)))::before{
  content:""; display:block; box-sizing:border-box; width:calc(108px * var(--es2-zoom)); height:calc(108px * var(--es2-zoom)); border-radius:50%;
  border:var(--es2-bw-2) solid var(--es2-unit-mid); background:var(--es2-unit-soft); object-fit:contain; overflow:hidden;
}
body.es-page .es-dogam-cell > .es-sticker-art > svg{ display:block; width:100%; height:100%; }
body.es-page .es-dogam-cell:is([data-st="on"], [data-st="just"]) > :is(svg, img, .es-sticker-art){ transform:rotate(-6deg); }
body.es-page .es-dogam-cell[data-st="wait"] > :is(svg, img, .es-sticker-art),
body.es-page .es-dogam-cell[data-st="wait"]:not(:has(> :is(svg, img, .es-sticker-art)))::before,
body.es-page .es-dogam[data-st="out"] .es-dogam-cell > :is(svg, img, .es-sticker-art){
  border:var(--es2-bw) dashed var(--es2-line-todo); background:var(--es2-card); filter:grayscale(1); opacity:.45; transform:none;
}
body.es-page .es-dogam-name{ font-size:var(--es2-fs-label); font-weight:var(--es2-fw-strong); line-height:1.3; overflow-wrap:anywhere; }
body.es-page .es-dogam-just{
  white-space:nowrap; padding:1px 10px;
  border:var(--es2-bw-1) solid var(--es2-ink); border-radius:var(--es2-r-pill); background:var(--es2-sun);
  font-size:var(--es2-fs-label); font-weight:var(--es2-fw-head); line-height:1.4;
}
body.es-page .es-dogam-cell[data-st="just"] > :is(svg, img, .es-sticker-art){ animation:es2-peel var(--es2-t-peel) var(--es2-ease-pop) 1 both; }
@media (max-width:860px){
  body.es-page .es-dogam{ padding:calc(24px * var(--es2-zoom)) 16px 22px; }
  body.es-page .es-dogam-grid{ grid-template-columns:repeat(3, minmax(0,1fr)); }
  body.es-page .es-dogam-cell > :is(svg, img, .es-sticker-art),
  body.es-page .es-dogam-cell:not(:has(> :is(svg, img, .es-sticker-art)))::before{ width:86px; height:86px; }
}

/* ══ 12. 그림 · 사진 · 움직이는 그림 · 영상 (DESIGN 3-16 · 3-22 · 3-23 · 계약 1-8-6 · 1-8-7) ══════════════════ */
body.es-page figure{ margin:0; }
body.es-page figcaption{ font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); line-height:1.45; color:var(--es2-ink); max-width:none; }
body.es-page .es-credit{ display:block; margin-top:2px; font-size:var(--es2-fs-credit); font-weight:500; line-height:1.4; color:var(--es2-ink-credit); }
body.es-page .es-credit a{ color:inherit; text-decoration:none; }
/* 사진 — 자르지 않는다(contain) · 높이 420 이하 · 상자가 사진 비율을 따르게(빈 띠 0 — es_gate N12) */
body.es-page .es-photo{ display:grid; justify-items:center; gap:6px; }
body.es-page .es-photo > img{
  display:block; width:auto; height:auto; max-width:100%; max-height:calc(420px * var(--es2-zoom)); object-fit:contain;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r-sm); background:var(--es2-card);
}
body.es-page .es-photo > figcaption{ justify-self:stretch; } /* 3단계 Fix(계약 9 #21) — 아직 안 받은 사진(es.js 가 data-es-wait · --es-pw · --es-ar 를 단다)은 받은 뒤와 같은 폭을 미리 잡는다: 받기 전 0px → 받는 순간 아래를 밀던 것(X1 1366 516px) */ body.es-page .es-photo > img[data-es-wait]{ width:min(calc(var(--es-pw) * 1px + 2 * var(--es2-bw)), 100%, calc((420px * var(--es2-zoom) - 2 * var(--es2-bw)) * var(--es-ar) + 2 * var(--es2-bw))); }
/* 움직이는 개념 그림 — 한 번 재생 + '↻ 다시 보기'(오른쪽 아래) */
body.es-page :is(.es-anim, .es-clip){ width:100%; max-width:calc(760px * var(--es2-zoom)); margin-inline:auto;
  display:grid; grid-template-columns:minmax(0,1fr) auto; gap:10px 12px; align-items:center; box-sizing:border-box;
  padding:12px; border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r-md); background:var(--es2-panel);
}
body.es-page .es-anim > :is(svg, .es-still, canvas){ grid-column:1 / -1; display:block; width:100%; height:auto; aspect-ratio:560 / 250; border-radius:14px; background:var(--es2-card); }
/* REVIEW kid-3: 그림을 잠금 껍데기(<div data-reveal>)로 감싼 쪽(X1 — SPEC_v2 6-3 · E5 의 래퍼 꼴)도 그림이 카드 전폭을 쓴다.
   껍데기가 1열(단추 칸 옆)에만 들어 1366 에서 575/760 · 390 에서 135×60 으로 쪼그라들었다 */
body.es-page .es-anim > div[data-reveal]{ grid-column:1 / -1; min-width:0; }
body.es-page .es-anim > div[data-reveal] > :is(svg, .es-still, canvas){ display:block; width:100%; height:auto; aspect-ratio:560 / 250; border-radius:14px; background:var(--es2-card); }
body.es-page .es-anim > figcaption{ grid-column:1; }
body.es-page .es-anim > button[data-replay]{ grid-column:2; }
/* REVIEW screen-10(과학 3-2 07/02 기준편): 폭 400 이하에서는 캡션과 [↻ 다시 보기] 를 위아래로 — 한 줄에 두면 단추 칸(143)이 캡션을 남은 칸에 가둬
   320 에서 7줄 · 낱말 중간이 끊겼다(사회 4-2 10/01 도 같음). 단추는 캡션 아래 오른쪽 끝(DESIGN 3-22 '오른쪽 아래') */
@media (max-width:400px){
  body.es-page .es-anim{ grid-template-columns:minmax(0,1fr); }
  body.es-page .es-anim > button[data-replay]{ grid-column:1; justify-self:end; }
}
/* 직접 촬영 실험 영상 — 16:9 · 포스터 · 가운데 큰 재생 단추(96 · 노랑) · 자막 22px 잉크 바탕 */
body.es-page .es-clip > video{ grid-column:1 / -1; grid-row:1; display:block; width:100%; height:auto; max-height:calc(420px * var(--es2-zoom)); aspect-ratio:16 / 9; object-fit:contain; border-radius:14px; background:var(--es2-ink); }
body.es-page .es-clip > .es-clip-play{
  grid-column:1 / -1; grid-row:1; align-self:center; justify-self:center; z-index:1;
  width:calc(96px * var(--es2-zoom)); height:calc(96px * var(--es2-zoom)); min-width:0; padding:0; border-radius:50%;
  border:var(--es2-bw-2) solid var(--es2-ink); background:var(--es2-sun); color:var(--es2-ink); box-shadow:var(--es2-sh-btn);
  font-size:calc(40px * var(--es2-zoom)); line-height:1; cursor:pointer;
}
body.es-page .es-clip > figcaption{ grid-column:1 / -1; }
body.es-page .es-clip video::cue{ font-size:calc(22px * var(--es2-zoom)); background:var(--es2-ink); color:var(--es2-on-dark); }

/* ══ 13. 쇼츠 — v1 부품 .es-short 를 그대로 돌리고 모양만 v2 로(계약 1-8-6 · DESIGN 3-20) ═══════════════════ */
body.es-page .es-short{ max-width:none; margin:0; }
body.es-page .es-short-stage{ border:var(--es2-bw-2) solid var(--es2-ink); border-radius:var(--es2-r-xl); background:var(--es2-unit-deep); box-shadow:var(--es2-sh-stage); }
body.es-page .es-short-play{ background:rgba(23,32,58,.86); font-family:var(--es2-font); font-size:var(--es2-fs-lead); }
body.es-page .es-short-play .em{ width:calc(96px * var(--es2-zoom)); height:calc(96px * var(--es2-zoom)); background:var(--es2-sun); color:var(--es2-ink); border:var(--es2-bw-2) solid var(--es2-ink); box-shadow:var(--es2-sh-btn); }
body.es-page .es-short-ttl{ font-size:var(--es2-fs-h1); }
body.es-page .es-short-bar > i{ background:var(--es2-unit-mid); }
body.es-page .es-short-tools .es-btn{ min-height:var(--es2-tap); }

/* ══ 14. v1 부품을 v2 쪽에서 쓸 때(분류 · 짝 · 순서 · 찾기 · 만들기 …) — 크기 56 · 빨강 대신 갈색 · TV 배율만 맞춘다 ══ */
body.es-page .es-btn.is-small{ min-height:var(--es2-tap); }
body.es-page :is(.es-note.is-no, .es-miss){ color:var(--es2-again) !important; }
body.es-page .es-miss{ border-color:var(--es2-again) !important; background:var(--es2-again-soft) !important; }
body.es-page .es-miss::before{ content:"↺"; }
body.es-page .es-sort-pool > button[data-help]{ align-self:center; }
body.es-page .es-find-box > button[data-help]{ position:absolute; z-index:2; transform:translate(-50%, calc(var(--es2-tap) / 2 + 6px)); white-space:nowrap; }
body.es-page [data-helped]{ outline:var(--es2-bw) dashed var(--es2-again); outline-offset:3px; }

/* ══ 15. JS 꺼짐 — 정지 그림이 보이고, 조작 줄 위에 한 줄(계약 3-6 · 2-11). 마크업 0 ════════════════════════ */
html:not(.js) body.es-page .es-ops[data-zone="act"]::before,
html:not(.js) body.es-page .es-play:not(:has(> .es-ops[data-zone="act"])) > .es-ops[data-zone="pick"]::after{
  content:"지금은 그림으로만 볼 수 있어요"; grid-column:1 / -1; display:block; justify-self:center;
  padding:4px 14px; border:var(--es2-bw) dashed var(--es2-ink-2); border-radius:var(--es2-r-pill); background:var(--es2-card);
  font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); color:var(--es2-ink); line-height:1.4;
}
html:not(.js) body.es-page .es-still{ display:block; }
/* FIX(2-나 실험대): 기록 칸 정지 그림(계약 3-6 — 칸 svg 를 그대로 이어 붙인 것)은 칸마다 폭 100% 라 JS 꺼짐에서 세로 기둥이 됐다
   (X2 1366 실측 300×1784 · X1 · B1 캡처). 칸 격자로 놓는다 — 살아 있는 기록 칸(.es-log-row)과 같은 칸 폭 */
body.es-page .es-log > .es-still,
html:not(.js) body.es-page .es-log > .es-still{
  display:grid; grid-template-columns:repeat(auto-fill, minmax(calc(84px * var(--es2-zoom)), 1fr)); gap:8px; align-items:start;
}
body.es-page .es-log > .es-still > svg{ width:100%; height:auto; max-height:calc(96px * var(--es2-zoom)); border:var(--es2-bw) dashed var(--es2-line-todo); border-radius:12px; box-sizing:border-box; padding:4px; background:var(--es2-card); }
/* es.js 가 채우는 빈 칸(나란히 보기 '내 예상' · 스티커 칸)은 JS 꺼짐에서 빈 상자로 남기지 않는다. 장면이 비었으면(정지 그림을 못 구운 쪽) 자리 비율만 잡는다 — 그릴 때 쪽이 출렁이지 않게 */
html:not(.js) body.es-page :is(.es-cmp-mine, .es-sticker):empty{ display:none; }
body.es-page .es-scene:empty{ aspect-ratio:780 / 440; }

/* ══ 16. 교사 서랍 — 교사 계정 · 자기 화면(DESIGN 3-15b · 계약 6-4). 오른쪽에서 겹쳐 나오는 판(쪽을 밀지 않는다) ══ */
body.es-page .es-drawer{
  position:fixed; top:var(--es2x-band); right:0; bottom:0; z-index:var(--es2-z-pop);
  width:min(400px, calc(100vw - 32px)); box-sizing:border-box; overflow:auto; overscroll-behavior:contain;
  display:flex; flex-direction:column; gap:var(--es2-gap); padding:18px 18px 24px;
  background:var(--es2-card); border-left:var(--es2-bw-2) solid var(--es2-ink); box-shadow:var(--es2-sh-stage);
  font-size:var(--es2-fs-body); line-height:1.45;
}
body.es-page .es-drawer > *{ margin:0; max-width:none; }
body.es-page .es-drawer button{ width:100%; }
body.es-page .es-drawer .es-drawer-x{ align-self:flex-end; width:var(--es2-tap); padding:0; font-size:calc(24px * var(--es2-zoom)); }
body.es-page :is(.es-drawer-tv, .es-tv-off){ background:var(--es2-sun); min-height:var(--es2-tap-lg); }
body.es-page .es-tv-off{ background:var(--es2-card); }
body.es-page .es-drawer-room{ font-weight:var(--es2-fw-strong); color:var(--es2-ink-2); }
body.es-page :is(.es-drawer-open, .es-tv-open){ background:var(--es2-sun); }
body.es-page :is(.es-drawer-open-sub, .es-tv-open-sub){ font-size:var(--es2x-cap); font-weight:700; color:var(--es2-ink-2); line-height:1.4; }
body.es-page :is(.es-drawer-open, .es-tv-open, .es-drawer-collect, .es-tv-collect):is([aria-disabled="true"], [disabled]){ background:var(--es2-dim); color:var(--es2-ink-dim); box-shadow:none; border-style:dashed; border-color:var(--es2-line-todo); }
/* REVIEW tv-2: 방 없이 누른 다 같이 열기 · 예상 모으기 — 흔들림 + 방 줄 반짝(소리 · '모았어요' 없음) */
body.es-page :is(.es-drawer, .es-tv-side) button[data-fx="blocked"]{ animation:es2-nudge var(--es2-t-pop) var(--es2-ease) 1; }
/* 교사 카드 — 목표 · 안전(붉은 테) · 민감 · 발문 · 실물 순서 · 걸음별 분(정거장 색 칸) */
body.es-page :is(.es-drawer-card, .es-tv-card){ display:grid; gap:10px; }
body.es-page :is(.es-drawer-card, .es-tv-card):empty{ display:none; }
body.es-page :is(.es-drawer-card, .es-tv-card) > *{ margin:0; max-width:none; }
body.es-page .es-card-goal{ font-weight:var(--es2-fw-head); }
body.es-page .es-card-safety{ padding:8px 14px; border:var(--es2-bw-2) solid var(--es2-danger-line); border-radius:16px; background:var(--es2-card); font-weight:var(--es2-fw-strong); }
body.es-page .es-card-safety > *{ margin:0; max-width:none; }
body.es-page .es-card-sensitive{ color:var(--es2-ink-2); font-weight:700; }
body.es-page .es-card-ask{ padding:8px 14px; border:var(--es2-bw) solid var(--es2-ink); border-radius:16px; background:var(--es2-tip); font-weight:var(--es2-fw-strong); }
body.es-page .es-card-real{ margin:0; padding-left:1.4em; max-width:none; }
body.es-page .es-card-min{ display:flex; gap:4px; flex-wrap:wrap; }
body.es-page .es-card-min > span{ padding:2px 8px; border:2px solid var(--es2-ink); border-radius:8px; font-size:var(--es2-fs-label); font-weight:var(--es2-fw-strong); }
body.es-page .es-card-min > [data-station="open"]{ background:var(--es2-k-open); }
body.es-page .es-card-min > [data-station="try"]{ background:var(--es2-k-try); }
body.es-page .es-card-min > [data-station="check"]{ background:var(--es2-k-check); }
body.es-page .es-card-min > [data-station="fin"]{ background:var(--es2-k-fin); }

/* ══ 17. TV 수업 화면 — html.es-tv (DESIGN 3-15 · 계약 3-5) ══════════════════════════════════════════════
   같은 쪽의 모드다. 글자 · 단추는 토큰(--es2-zoom 1.4)이 키우고, 여기서는 짜임만: 띠 92 · 왼쪽 열 1240(지금 절 — POLISH 전 1140) ·
   오른쪽 열 붙박이(교사만) · 절마다 한 화면 · 교사가 아니면 오른쪽 열 없이 가운데로 넓게(최대 1400). */
html.es-tv #won-chat-btn{display:none}
html.es-tv body.es-page{
  display:grid; grid-template-columns:minmax(0, 1240px) minmax(0, 1fr); column-gap:28px; align-items:start;
  /* POLISH: 왼쪽 열 1140 → 1240(오른쪽 붙박이 열 680 → 580 — 콩 병 셋 528 · 반 코드 판 478 이 든다). 1140 안에서는 장면 808 + 곁 열 1/3 이
     안 들었다(808 + 14 + 388 = 1210 > 안쪽 1094) */
  padding:0 36px 26px; box-sizing:border-box;
  background-image:var(--es2-paper-grain); background-repeat:repeat; background-size:280px 280px;
}
html.es-tv body.es-page:not(:has(> .es-tv-side)){ display:block; padding:0 0 26px; }
html.es-tv body.es-page:not(:has(> .es-tv-side)) > :is(.es-body, .es-pager){ max-width:1400px; margin-left:auto; margin-right:auto; padding-left:var(--es2-gutter); padding-right:var(--es2-gutter); box-sizing:content-box; }
html.es-tv body.es-page:has(> .es-tv-side) > .es-bar{ grid-column:1 / -1; grid-row:1; margin:0 -36px; padding:0 36px; }
html.es-tv body.es-page > :is(.es-body, .es-pager){ grid-column:1; max-width:none; padding-left:0; padding-right:0; margin-left:0; margin-right:0; }
/* POLISH: 위 margin 0 — 넓은 창의 margin:0 auto 가 격자 칸 안에서는 '내용만큼' 으로 줄여(늘이지 않는다) 왼쪽 열 폭이 쪽 글에 따라 흔들렸다
   (고정물 teacher-tv: 예상 상태 줄 글 하나로 본문 1206 ↔ 1240 · 장면 786 ↔ 808 · 쪽 높이 −28). 1140 일 때는 내용 폭이 늘 그보다 넓어 드러나지 않았다 */
html.es-tv body.es-page > .es-body{ grid-row:2; }
html.es-tv body.es-page > .es-pager{ grid-row:3; padding-bottom:0; }
html.es-tv body.es-page .es-bar-teacher{ display:none !important; }
/* FIX(2-나 실험대): 띠 단원 줄은 단원 이름이 길면(사회 '다양한 환경과 삶의 모습 · 1' 16자) 읽을 글이다 — TV 28(DESIGN 3-15 · es_gate N14 · X2 실측 23.8).
   안쪽 85 = 단원 28×1.3 + 제목 30.8×1.3 = 76.4 */
html.es-tv body.es-page .es-bar > .es-bar-unit{ font-size:var(--es2-fs-body); }
/* v1 부품 안 글 — 쪽마다 px 로 박힌 크기(예: 분류 물음 clamp(21px,2vw,24px))가 있어 TV 의 읽을 글 28 에 모자란다. 부품 안 글 요소만 28 이상으로(그림 글자 .em 은 그대로) */
html.es-tv body.es-page :is(.es-sort, .es-order, .es-match, .es-find, .es-build, .es-place, .es-tl, .es-timeline, .es-mental, .es-hl, .es-wipe, .es-zoom, .es-sim, .es-slider, .es-steps, .es-dial, .es-toggles, .es-sound, .es-balance, .es-scale, .es-trial, .es-figs) :is(p, li, label, button, b, strong, small, figcaption, h3, h4, span:not(.em)){ font-size:max(1em, var(--es2-fs-body)); }
/* REVIEW screen-13(과학 3-2 07/02 기준편): 위 규칙에서 출처 줄(.es-credit — v1 소리 판 안 p.es-src.es-credit 등)은 뺀다. 출처는 TV 에서도 12(--es2-fs-credit · DESIGN 3-16)인데
   소리 판 출처만 28 로 커져 한 쪽의 출처가 두 크기였다(사진 출처 12 · 소리 출처 28). 같은 무게(0,4,3)라 뒤에 둔다 */
html.es-tv body.es-page :is(.es-sort, .es-order, .es-match, .es-find, .es-build, .es-place, .es-tl, .es-timeline, .es-mental, .es-hl, .es-wipe, .es-zoom, .es-sim, .es-slider, .es-steps, .es-dial, .es-toggles, .es-sound, .es-balance, .es-scale, .es-trial, .es-figs) :is(p, small, span).es-credit{ font-size:var(--es2-fs-credit); }
/* v1 부품(분류 · 짝 · 순서 …)도 TV 배율 — v1 변수를 body 에서 TV 값으로(v1 규칙은 그대로 · 116쪽에는 닿지 않는다) */
html.es-tv body.es-page{
  --es-tap:var(--es2-tap); --es-fs:var(--es2-fs-body); --es-fs-lg:var(--es2-fs-lead); --es-fs-sm:var(--es2-fs-body); --es-fs-cap:var(--es2-fs-body);
  --es-fs-src:var(--es2-fs-label); --es-fs-btn:var(--es2-fs-btn); --es-fs-eyebrow:var(--es2-fs-label); --es-h3:var(--es2-fs-h3); --es-h2:var(--es2-fs-h2); --es-h1:var(--es2-fs-h1);
}
html.es-tv body.es-page .es-part{ min-height:calc(100vh - var(--es2x-band) - 2 * var(--es2-sec-gap)); }
html.es-tv body.es-page .es-part[data-station="open"]{ min-height:0; }
html.es-tv body.es-page .es-today{ max-width:none; padding:10px 18px; border:var(--es2-bw-tv) solid var(--es2-ink); border-radius:32px; background:var(--es2-paper-top); }
html.es-tv body.es-page .es-today-q{ font-size:calc(34px * var(--es2-zoom)); }
/* TV 무대 — POLISH(관문 ② 리드 판정 '교실 TV 에서 장면이 노트북보다 작다'): 고치기 전 짜임은 왼쪽 열을 장면 열(540)과 곁 열로 거의 반씩 나눠
   장면이 540×309 였다(1366 은 808×458). DESIGN 3-15 그림대로 장면을 크게 세우고 곁에 좁은 열(약 1/3)을 둔다:
     맨 위 예상(물음 한 줄 + 보기 줄 — 전폭) / 왼쪽 장면(교사 808 = 1366 장면 폭 · 교사 아님 900) + 그 바로 아래 조작 줄 /
     오른쪽 곁 열 = 포롱이(118 · 위 왼쪽) + ↻ 다시 보기(포롱이 옆 — 말풍선 줄 밖) + 말풍선(그 아래 곁 열 전폭 — 두 줄) · 고를 것 · 알아 두기 /
     그 아래 기록 칸(전폭 · 묶음을 한 줄로 눕힌다) — 여기까지가 무대 핵심(예상 줄 + 장면 + 조작 줄 + 해 본 칸)이고 한 화면(988 — 절 앵커로 왔을 때
     화면 아래 끝 안)에 든다. 나란히 보기는 그 아래(DESIGN 3-15 '스크롤하는 같은 쪽 · 절마다 최소 높이 = 화면 − 띠').
   줄: 1 예상 | 2 말풍선(+ 다시 보기) | 3 고를 것 | 4 고를 것 둘째 | 5 알아 두기 시작 | 6 유연(장면 · 알아 두기가 곁 칸들보다 긴 만큼을 받는다 —
     장면을 지나는 유연 줄이 있어 장면 아래 조작 줄이 장면에 붙는다) | 7 조작 줄 | 8 조작 줄 둘째 | 9 기록 칸 | 10 나란히 보기.
   열: 장면 = min(900, (안쪽 − 사이 14) × .676) — 교사(왼쪽 열 1240 · 안쪽 1210)에서 808, 교사 아님(1400 · 안쪽 1370)에서 900. 장면 비율은 그대로(viewBox meet).
   넓은 창의 :not(:has()) 자리 규칙(명세도 0,5,1 ~ 0,8,1 — FIX 가 겪은 것)을 이기려고 TV 자리 규칙은 .es-play 를 세 번 겹쳐 쓴다(같은 요소 · 명세도만 올린다).
   칸 이름 · data-zone · 속성으로만 잡는 것은 같다(계약 1-7-1) */
html.es-tv body.es-page .es-play{
  grid-template-columns:[s l r] minmax(0, min(900px, calc((100% - 14px) * .676))) [g c c1 c2] minmax(0,1fr);
  grid-template-rows:auto auto auto auto auto minmax(0,1fr) auto auto auto auto;
  padding:12px 10px 14px; border-width:var(--es2-bw-tv); column-gap:14px;
}
/* 곁 열 판(고를 것 · 알아 두기) — 안쪽 여백을 줄여 곁 열 글이 덜 꺾이고(알아 두기 둘째 문장 한 줄) 곁 열이 장면 + 조작 줄 높이 안에 들게 */
html.es-tv body.es-page .es-play > :is(.es-ops[data-zone="pick"], .es-tip){ padding:8px 14px 10px; }
html.es-tv body.es-page .es-play > .es-ops[data-zone="pick"]{ row-gap:8px; }
html.es-tv body.es-page .es-play > .es-tip{ gap:6px; }
/* 무대 핵심을 줄인다 — 교사 TV(1240)에서 곁 열이 장면 + 조작 줄보다 18px 길어 조작 줄이 밀렸고, 절 앵커로 왔을 때 기록 칸 아랫줄이 follow.js 의
   왼쪽 아래 '함께 보는 중' 알약(아래 60 · 왼쪽 16 — 화면 y 986~1020)에 걸렸다(실험대 s5 캡처). 곁 칸 사이 6 · 곁 판 안쪽 위아래 8/10 ·
   예상 판 위아래 6 · 기록 칸 머리를 이름표 크기로 · 두 줄 조작 단추 줄 높이 1.1 */
html.es-tv body.es-page .es-play.es-play.es-play > :is(.es-ops[data-zone="pick"], .es-tip){ margin-top:6px; }
html.es-tv body.es-page .es-play{ margin-top:calc(26px * var(--es2-zoom)); }
html.es-tv body.es-page .es-play > *{ grid-column:1 / -1; }
/* 예상 — 물음 한 줄(전폭) · 아래 줄에 보기 셋 | 상태 줄(FIX: 물음 | 보기 셋을 한 줄에 두면 물음 칸이 140~190px 라 세 줄로 꺾였다) */
html.es-tv body.es-page .es-play.es-play.es-play > .es-predict{ grid-column:1 / -1; grid-row:1; }
/* REVIEW screen-4: 고른 보기 위 '내 예상' 표(top −11)가 물음 줄 아래 9px 를 덮었다(사이 2px) — 사이를 표가 내미는 11 로 · 위 여백 6 → 2(무대 핵심 +5px) */
html.es-tv body.es-page .es-play > .es-predict{ grid-template-columns:repeat(3, auto) minmax(0,1fr); align-items:center; column-gap:var(--es2-gap); row-gap:11px; padding-top:2px; padding-bottom:6px; }
html.es-tv body.es-page .es-play > .es-predict > .es-predict-q{ grid-column:1 / -1; grid-row:1; }
html.es-tv body.es-page .es-play > .es-predict > .es-predict-st{ grid-column:4; grid-row:2; align-self:center; }
/* GATE2(고치다 본 것): 보기에 그림(svg 56)이 들면 상태 칸(4열)이 좁아 '이번엔 선생님과 함께 봤어요' 가 두 줄이 된다 — 처음부터 두 줄 자리(81.2 > 보기 78.4).
   전에는 고정물 보기에 그림이 없어 한 줄로 들어 못 봤다(실제 X1 · X2 는 그림이 있다 — 교사 TV 에서 다 같이 열기 때 쪽 높이 +2.8) */
html.es-tv body.es-page .es-play > .es-predict > .es-predict-st{ min-height:calc(var(--es2x-cap) * 1.45 * 2); }
html.es-tv body.es-page .es-play > .es-predict > .es-opt{ grid-row:2; width:auto; justify-content:center; }
/* 장면 + 조작 줄 — 왼쪽 큰 열. 조작 줄 위 30 = 장면 아래 테에 걸친 도장 자리 */
html.es-tv body.es-page .es-play.es-play.es-play > .es-scene{ grid-column:s; grid-row:2 / 7; margin-top:12px; align-self:start; }
html.es-tv body.es-page .es-play.es-play.es-play > .es-ops[data-zone="act"]{ grid-column:s; grid-row:7; margin-top:30px; align-self:start; }
html.es-tv body.es-page .es-play.es-play.es-play > .es-ops[data-zone="act"] ~ .es-ops[data-zone="act"]{ grid-row:8; margin-top:12px; }
/* 곁 열 — 포롱이(위 왼쪽) · 다시 보기(포롱이 옆, 같은 칸의 오른쪽 위 — 포롱이 줄의 빈 자리) · 말풍선(곁 열 전폭 · 두 줄 자리를 처음부터) */
html.es-tv body.es-page .es-play.es-play.es-play > .es-guide{
  grid-column:g; grid-row:2; margin:12px 0 0; align-self:start; justify-self:stretch; max-width:none; z-index:auto; pointer-events:auto;
  grid-template-columns:var(--es2-guide) minmax(0,1fr); grid-template-rows:auto auto; align-items:start; row-gap:6px;
  min-height:calc(var(--es2-guide) * 220 / 230 + 6px + var(--es2-fs-say) * 1.42 * 2 + 22px);
}
html.es-tv body.es-page .es-play > .es-guide > .es-guide-say{ grid-column:1 / -1; grid-row:2; }
html.js.es-tv body.es-page .es-play > .es-guide[hidden]{ display:grid !important; visibility:hidden; }
html.es-tv body.es-page .es-play.es-play.es-play > button[data-replay]{ grid-column:g; grid-row:2; justify-self:end; align-self:start; margin:12px 0 0; }
html.es-tv body.es-page .es-play.es-play.es-play > .es-ops[data-zone="pick"]{ grid-column:g; grid-row:3; margin-top:12px; align-self:start; }
html.es-tv body.es-page .es-play.es-play.es-play > .es-ops[data-zone="pick"] ~ .es-ops[data-zone="pick"]{ grid-row:4; }
html.es-tv body.es-page .es-play.es-play.es-play > .es-tip{ grid-column:g; grid-row:5 / 8; margin-top:12px; align-self:start; justify-content:flex-start; }
html.es-tv body.es-page .es-play.es-play.es-play > .es-ops[data-zone="undo"]{ grid-column:g; grid-row:8; margin-top:12px; align-self:start; }   /* 알아 두기 밖 되돌리기 */
html.es-tv body.es-page .es-play.es-play.es-play:not(:has(> .es-predict)) > :is(.es-scene, .es-guide, button[data-replay]){ margin-top:0; }
/* 기록 칸 · 나란히 보기 — 전폭. 나란히 보기는 무대 핵심 아래(한 화면 밖이어도 된다) */
html.es-tv body.es-page .es-play.es-play.es-play > .es-log{ grid-column:1 / -1; grid-row:9; margin-top:12px; align-self:start; }
html.es-tv body.es-page .es-play.es-play.es-play > .es-cmp{ grid-column:1 / -1; grid-row:10; margin-top:12px; align-self:start; }
/* 조작 대기 알약은 TV 에서 그리지 않는다 — 교사 화면은 다 같이 열기로 연다(아이 하나에게 하는 말이다 · 잠긴 단추의 흐린 모양 · 예상 판의 노란 고리는 그대로). 보고했다 */
html.es-tv body.es-page .es-play > .es-pill, html.js.es-tv body.es-page .es-play > .es-pill[hidden]{ display:none !important; }
/* 고를 것 — 곁 열 폭을 단추 수대로 채운다(격자 auto-fit 은 머리가 모든 칸을 걸쳐 빈 칸이 접히지 않았다 — 교사 아님 TV 에서 단추 둘이 왼쪽에 몰렸다) */
html.es-tv body.es-page .es-play > .es-ops[data-zone="pick"]{ display:flex; flex-wrap:wrap; gap:var(--es2-gap); }
html.es-tv body.es-page .es-play > .es-ops[data-zone="pick"]::before{ flex:1 0 100%; font-size:var(--es2-fs-label); }
html.es-tv body.es-page .es-play > .es-ops[data-zone="pick"] > button{ flex:1 1 130px; width:auto; }
html.es-tv body.es-page .es-play .es-ops[data-zone="act"]{ grid-template-columns:repeat(auto-fit, minmax(150px, 1fr)); }
html.es-tv body.es-page .es-play .es-ops[data-zone="act"] button[data-op]{ min-height:var(--es2-tap); line-height:1.1; }
html.es-tv body.es-page .es-play .es-ops[data-zone="act"] button[data-op] > span{ line-height:1.1; }   /* 두 줄 단추(이름 + 에 담기) 93 → 78 — 무대 핵심을 줄인다 */
html.es-tv body.es-page .es-play button[data-op]{ padding:6px 8px; }
/* 기록 칸 — 머리(③ 해 본 칸 · 셈) 한 줄 + 묶음(물 · 나무토막 · 덤)을 한 줄로 눕힌다(칸 높이 52 × 1.4). 넓이가 모자라면 묶음째 다음 줄로 */
html.es-tv body.es-page .es-play > .es-log{ display:flex; flex-wrap:wrap; align-items:stretch; column-gap:18px; row-gap:4px; padding-top:6px; padding-bottom:8px; }
html.es-tv body.es-page .es-play > .es-log::before{ font-size:var(--es2-fs-label); }
html.es-tv body.es-page .es-play > .es-log::before{ order:0; flex:1 0 calc(100% - 160px); align-self:center; }
html.es-tv body.es-page .es-play > .es-log > .es-log-sum{ order:1; flex:none; margin-left:auto; align-self:center; }
html.es-tv body.es-page .es-play > .es-log > .es-log-row{ order:2; flex:1 1 auto; display:flex; gap:8px; }
html.es-tv body.es-page .es-log-head{ flex:none; font-size:var(--es2-fs-label); }
html.es-tv body.es-page .es-log-cell{ flex:1 0 calc(72px * var(--es2-zoom)); max-width:calc(122px * var(--es2-zoom)); height:calc(52px * var(--es2-zoom)); grid-template-rows:minmax(0,1fr) auto; padding-top:2px; }   /* 칸 하나뿐인 묶음(덤)이 남는 폭을 혼자 먹지 않게 */
html.es-tv body.es-page .es-cmp > p{ row-gap:2px; line-height:1.35; }
html.es-tv body.es-page .es-cmp > p > b{ min-width:0; }
html.es-tv body.es-page .es-cmp > p:has(> .es-cmp-mine){ grid-template-rows:auto calc(var(--es2-fs-cap) * 1.6 + 2px); }   /* REVIEW screen-9: 판정 알약 18 × 1.4 */
html.es-tv body.es-page .es-play > .es-cmp{ gap:8px; padding-top:10px; padding-bottom:10px; }
html.es-tv body.es-page .es-scene{ border-width:var(--es2-bw-tv); }
/* TV 오른쪽 열 — 붙박이(띠 아래부터 화면 끝까지) · 교사만(es.js 가 교사일 때만 만든다) */
html.es-tv body.es-page > .es-tv-side{
  grid-column:2; grid-row:2 / 4; position:sticky; top:calc(var(--es2x-band) + 16px);
  max-height:calc(100vh - var(--es2x-band) - 32px); overflow:auto; box-sizing:border-box; margin-top:16px;
  display:flex; flex-direction:column; gap:16px; padding:0 4px 8px;
}
body.es-page .es-tv-side > *{ margin:0; max-width:none; }
body.es-page :is(.es-tv-code, .es-tv-jars, .es-tv-dist, .es-tv-card){
  box-sizing:border-box; padding:14px 20px 16px; border:var(--es2-bw-tv) solid var(--es2-ink); border-radius:32px; background:var(--es2-card); box-shadow:var(--es2-sh-card);
}
body.es-page .es-tv-code{ display:grid; grid-template-columns:auto minmax(0,1fr); grid-template-rows:auto auto; column-gap:18px; align-items:center; }
body.es-page .es-tv-qr{ grid-row:1 / 3; display:block; width:160px; height:160px; background:var(--es2-card); }
body.es-page .es-tv-qr:empty{ border:var(--es2-bw) dashed var(--es2-line-todo); border-radius:12px; box-sizing:border-box; }
body.es-page .es-tv-qr > :is(svg, canvas, img){ display:block; width:100%; height:100%; }
body.es-page .es-tv-code > b{ font-size:calc(40px * var(--es2-zoom)); font-weight:var(--es2-fw-head); letter-spacing:.06em; line-height:1.1; }
body.es-page .es-tv-present{ font-size:var(--es2-fs-body); font-weight:var(--es2-fw-strong); color:var(--es2-ink-2); }
body.es-page .es-tv-h{ margin:0 0 6px; font-size:var(--es2-fs-h3); font-weight:var(--es2-fw-head); max-width:none; }
/* 반의 예상 — 콩 병 그림그래프: 보기마다 병 하나 · 콩 한 알 = 한 사람 · 한 줄 다섯 알 · 아래부터(DESIGN 3-15) */
body.es-page .es-tv-jars{ display:flex; flex-wrap:wrap; justify-content:space-around; align-items:flex-end; gap:14px; }
body.es-page .es-tv-jars > .es-tv-h{ flex:1 1 100%; }
body.es-page .es-tv-jar{ flex:1 1 0; min-width:150px; display:grid; justify-items:center; gap:6px; text-align:center; }
body.es-page .es-tv-jar-n{ font-size:calc(40px * var(--es2-zoom)); font-weight:var(--es2-fw-head); line-height:1; }
body.es-page .es-tv-beans{
  display:flex; flex-wrap:wrap-reverse; align-content:flex-start; justify-content:center; gap:2px; box-sizing:border-box;
  width:150px; height:calc(6 * 21px + 18px); padding:8px 8px 6px;
  border:5px solid var(--es2-ink); border-top:0; border-radius:0 0 14px 14px; background:var(--es2-card);
  box-shadow:inset 0 10px 0 var(--es2-floor);
}
body.es-page .es-tv-beans > i{ display:block; box-sizing:border-box; width:22px; height:17px; margin:1px; border-radius:50%; border:2.5px solid var(--es2-ink); background:var(--es2-wood); }
body.es-page .es-tv-jar:nth-child(3n+2) .es-tv-beans > i{ background:var(--es2-floor); }
body.es-page .es-tv-jar:nth-child(3n) .es-tv-beans > i{ background:var(--es2-paper-sky); }
body.es-page .es-tv-jar:nth-child(3n+1) .es-tv-beans > i{ background:var(--es2-grape-soft); }
body.es-page .es-tv-jar-name{ font-size:var(--es2-fs-body); font-weight:var(--es2-fw-head); line-height:1.2; }
/* 확인 분포 — 문항마다 막대(이름 없이) */
body.es-page .es-tv-dist{ display:grid; gap:10px; }
body.es-page .es-tv-q{ display:flex; flex-wrap:wrap; align-items:center; gap:6px 12px; }
body.es-page .es-tv-q > b{ font-size:var(--es2-fs-label); font-weight:var(--es2-fw-head); }
body.es-page .es-tv-bar{
  display:inline-flex; align-items:center; min-height:calc(var(--es2-fs-label) * 1.8); padding:0 12px; box-sizing:border-box;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:10px; font-size:var(--es2-fs-label); font-weight:var(--es2-fw-strong);
  background-image:repeating-linear-gradient(-45deg, var(--es2-sky-soft) 0 8px, var(--es2-card) 8px 16px);
}
body.es-page .es-tv-writes{ font-size:var(--es2-fs-h3); font-weight:var(--es2-fw-head); }
body.es-page .es-tv-open{ min-height:calc(92px * var(--es2-zoom) / 1.4 * 1.4); font-size:var(--es2-fs-btn-lg); }
body.es-page .es-tv-side button{ width:100%; }

/* ══ 18. 860 이하 · 움직임 줄이기 ═════════════════════════════════════════════════════════════════════════ */
@media (max-width:860px){
  body.es-page .es-today-head{ display:block; }
  body.es-page .es-part{ padding:calc(24px * var(--es2-zoom)) 16px 22px; }
  body.es-page .es-part[data-station="open"],
  body.es-page .es-part:has(> .es-play){ padding:0; }
  body.es-page .es-part[data-station="open"]{ padding-top:14px; }
  body.es-page .es-real-steps{ grid-template-columns:minmax(0,1fr); }
  body.es-page .es-real-steps > li{ grid-template-columns:auto minmax(96px, 40%) minmax(0,1fr); align-items:center; justify-items:start; text-align:left; }
  body.es-page .es-real-steps > li:not(:has(> figure, > svg, > img)){ grid-template-columns:auto minmax(0,1fr); }
  body.es-page .es-real-steps > li > p{ grid-column:-2; }
  body.es-page .es-real-steps > li::before{ align-self:start; }
  body.es-page .es-real-steps :is(svg, img){ height:96px; }
  body.es-page .es-concept:has(> figure){ grid-template-columns:minmax(0,1fr); }
  body.es-page .es-concept > figure{ grid-row:auto; }
  body.es-page .es-concept > :not(figure){ grid-column:1; }
  body.es-page .es-photo > img{ max-height:300px; } body.es-page .es-photo > img[data-es-wait]{ width:min(calc(var(--es-pw) * 1px + 2 * var(--es2-bw)), 100%, calc((300px - 2 * var(--es2-bw)) * var(--es-ar) + 2 * var(--es2-bw))); }
  body.es-page .es-part[data-explore]{ grid-template-columns:minmax(0,1fr); }
  body.es-page .es-pager{ flex-direction:column; }
  body.es-page .es-pager a[rel="next"]{ justify-content:flex-start; text-align:left; }
  body.es-page .es-pager a:only-child[rel="next"]{ margin-left:0; flex-basis:auto; }
  body.es-page .es-sticker{ height:200px; }
  body.es-page .es-stamp{ font-size:var(--es2-fs-cap); padding:2px 10px; bottom:-14px; }   /* REVIEW screen-9: 도장 글('다 해 봤어요!')은 문장 — 폰에서도 18 */
  body.es-page .es-wq-st{ min-height:calc(var(--es2x-cap) * 2.9 + 8px + var(--es2-tap)); }
}
@media (prefers-reduced-motion:reduce){
  body.es-page *, body.es-page *::before, body.es-page *::after{ animation:none !important; transition:none !important; }
  body.es-page [data-pulse="on"]{ outline:var(--es2-bw-2) solid var(--es2-sun); outline-offset:3px; }
  body.es-page :is(.es-predict, .es-pill, .es-drawer-room)[data-fx="call"]{ outline:var(--es2-bw-2) solid var(--es2-sun); outline-offset:3px; }
}
/* REVIEW kid-10: 잠긴 판을 누르면 예상 판 · 알약이 한 번 반짝(어디서 먼저 고르나) */
body.es-page .es-predict[data-fx="call"]{ animation:es2-call .9s var(--es2-ease) 1; }
body.es-page :is(.es-pill, .es-drawer-room)[data-fx="call"]{ animation:es2-ring .9s var(--es2-ease) 1; }
/* REVIEW robust-1: 키보드 초점이 붙박이 띠(83) 밑에 깔리지 않게 — 누르는 것만(절 앵커는 .es-part 의 scroll-margin 그대로) */
body.es-page :is(a[href], button, input, textarea, select, [tabindex]:not([tabindex="-1"]), [data-op]){ scroll-margin-top:calc(var(--es2x-band) + 12px); scroll-margin-bottom:12px; }

/* ══ 18b. 관문 ② 사용자 결정(GATE2 · 2026-10-09) — ⑥ 함께 하기 중 🔊 · ⑪ 나란히 보기 그림 줄 ═════════════════════════ */
/* ⑥ 함께 하기 방에 붙은 학생 기기의 🔊 — 꺼진 모양(잠긴 조작과 같은 결: 흐린 바탕 · 점선 테 · 그림자 없음 · 그림 글자는 회색).
   누르면 흔들림 + 한 줄(.es-say-note — 쪽 흐름 밖 fixed 라 쪽 높이 · 자리를 흔들지 않는다 · es.js 가 단추 바로 아래에 놓는다) */
body.es-page .es-say[data-room-off]{ background:var(--es2-dim); border-style:dashed; border-color:var(--es2-line-todo); box-shadow:none; filter:grayscale(1); cursor:not-allowed; }
body.es-page .es-say[data-room-off][data-fx="blocked"]{ animation:es2-nudge var(--es2-t-pop) var(--es2-ease) 1; }
body.es-page .es-say-note{
  position:fixed; left:8px; top:8px; z-index:var(--es2-z-pop); box-sizing:border-box; margin:0; width:max-content; max-width:min(380px, calc(100vw - 16px));
  padding:8px 16px; border-radius:16px; background:var(--es2-ink); color:var(--es2-on-dark); box-shadow:var(--es2-sh-card);
  font-size:var(--es2-fs-cap); font-weight:var(--es2-fw-head); line-height:1.35; pointer-events:none;
}
/* ⑪ 나란히 보기 카드의 작은 그림 — 엔진이 '내 예상' 줄 · '해 보니' 줄에 하나씩 넣는다: p > span.es-cmp-fig[data-k=mine|got][data-st](aria-hidden) > span.es-cmp-pic.
   '내 예상' = 고른 예상 보기의 그림(고르기 전 = 보기 그림들을 흐리게) · '해 보니' = 무대 결과의 작은 정지 그림(열리기 전 = 빈 칸 그림을 흐리게 — DESIGN 3-5 그린 그림 꼴).
   줄 = [이름표 | 그림 칸 | 글](무대 틀 폭 480~559 는 이름표가 위 줄, 그 아래 [그림 칸 | 글]). 그림 칸 높이는 줄(카드)이 정한다 — 그림 크기가 줄을 밀지 않는다(contain:size).
   넓은 창(기록 칸 옆 · 두 열 바닥을 맞춘 카드): 그림 든 줄이 남는 높이를 나눠 먹는다 — 관문 ② 5절 ⑪ 의 위아래 빈 자리(1366 118+118 · 1024 104+104)가 0.
   860 이하 · TV: 카드를 늘리는 이웃이 없다 — 그림 칸이 정한 높이(116 · TV ×1.4). 폰(무대 틀 480 미만)은 그림을 그리지 않는다(아래 — 글 화면 조각).
   칸 자리는 처음부터(예상 전 · 무대 중 · 다 한 뒤 쪽 높이 그대로 — N3).
   선택자 두 벌 — 그림 든 줄 `> p:has(> .es-cmp-fig)` · 그림 없는 줄(알게 된 것) `:has(.es-cmp-fig) > p:not(:has(> .es-cmp-fig))`. 둘 다 명세도가 위 7절 줄 규칙(0,3,3)보다 높다 */
body.es-page .es-cmp:has(.es-cmp-fig){ --es2x-figw:clamp(calc(96px * var(--es2-zoom)), 28%, calc(220px * var(--es2-zoom))); --es2x-figh:calc(116px * var(--es2-zoom)); }
body.es-page .es-play > .es-cmp:has(.es-cmp-fig){ display:flex; flex-direction:column; justify-content:flex-start; }
body.es-page .es-play > .es-cmp:has(.es-cmp-fig) > *{ flex:none; }
body.es-page .es-play > .es-cmp:has(.es-cmp-fig) > p:has(> .es-cmp-fig){ flex:1 1 0; }
body.es-page .es-cmp.es-cmp:has(.es-cmp-fig) > p{ grid-template-columns:auto var(--es2x-figw) minmax(0,1fr); }
/* 그림 든 줄 — 글 묶음은 그림 칸 높이의 가운데(위아래 1fr) */
body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig){ grid-template-rows:minmax(0,1fr) auto minmax(0,1fr); }
body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig):has(> .es-cmp-mine){ grid-template-rows:minmax(0,1fr) auto calc(var(--es2-fs-label) * 1.6 + 6px) minmax(0,1fr); }
body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > *{ grid-column:3; grid-row:2; }
body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > b{ grid-column:1; grid-row:2; }
body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > .es-cmp-judge{ grid-column:3; grid-row:3; }
body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > .es-pill{ grid-column:3; grid-row:2; }
body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > .es-cmp-fig{
  grid-column:2; grid-row:1 / -1; align-self:stretch; justify-self:stretch; display:grid; place-items:center; box-sizing:border-box; min-width:0; min-height:var(--es2x-figh);
  padding:6px; border:var(--es2-bw) dashed var(--es2-line-todo); border-radius:var(--es2-r-sm); background:var(--es2-card);
}
/* 그림 없는 줄 — 글이 그림 칸 자리부터 끝까지 */
body.es-page .es-cmp.es-cmp:has(.es-cmp-fig) > p:not(:has(> .es-cmp-fig)) > *{ grid-column:2 / -1; grid-row:1; }
body.es-page .es-cmp.es-cmp:has(.es-cmp-fig) > p:not(:has(> .es-cmp-fig)) > b{ grid-column:1; grid-row:1; }
body.es-page .es-cmp-pic{ display:flex; justify-content:center; align-items:center; gap:8%; box-sizing:border-box; width:100%; height:100%; min-width:0; min-height:0; max-height:calc(200px * var(--es2-zoom)); contain:size; }   /* 그림 크기가 줄을 밀지 않는다 */
body.es-page .es-cmp-pic > :is(svg, img, canvas){ display:block; flex:0 1 auto; width:auto; height:100%; max-width:100%; min-width:0; object-fit:contain; }
body.es-page .es-cmp-fig[data-k="mine"][data-st="empty"] .es-cmp-pic > *{ height:58%; opacity:.4; }
body.es-page .es-cmp.es-cmp > p > .es-cmp-fig:is([data-st="set"], [data-st="open"]){ border-style:solid; border-color:var(--es2-ink); }
body.es-page .es-cmp.es-cmp > p > .es-cmp-fig[data-st="set"]{ background:var(--es2-sky-soft); }
html.js body.es-page .es-cmp-fig[data-st="wait"] .es-cmp-pic > *{ filter:blur(2.5px) saturate(.55); opacity:.5; }
body.es-page .es-cmp-fig[data-fx="pop"]{ animation:es2-pop var(--es2-t-pop) var(--es2-ease-out) 1; }
@container es2play (max-width:559px){
  body.es-page .es-cmp:has(.es-cmp-fig){ --es2x-figw:clamp(96px, 34%, 180px); }
  body.es-page .es-cmp.es-cmp:has(.es-cmp-fig) > p{ grid-template-columns:var(--es2x-figw) minmax(0,1fr); }
  body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig){ grid-template-rows:auto minmax(0,1fr) auto minmax(0,1fr); }
  body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig):has(> .es-cmp-mine){ grid-template-rows:auto minmax(0,1fr) auto calc(var(--es2-fs-label) * 1.6 + 6px) minmax(0,1fr); }
  body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > *{ grid-column:2; grid-row:3; }
  body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > b{ grid-column:1 / -1; grid-row:1; }
  body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > .es-cmp-judge{ grid-column:2; grid-row:4; }
  body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > .es-pill{ grid-column:2; grid-row:3; }
  body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > .es-cmp-fig{ grid-column:1; grid-row:2 / -1; }
  body.es-page .es-cmp.es-cmp:has(.es-cmp-fig) > p:not(:has(> .es-cmp-fig)) > *{ grid-column:1 / -1; grid-row:2; }
  body.es-page .es-cmp.es-cmp:has(.es-cmp-fig) > p:not(:has(> .es-cmp-fig)) > b{ grid-column:1 / -1; grid-row:1; }
}
/* 폰(무대 틀 480 미만) — 그림을 그리지 않고 전과 같은 글 세 줄. 카드가 기록 칸 아래 한 줄이라 메울 빈 높이가 없고(관문 ② 쪽 5절 ⑪ '폰은 해당 없음'),
   그림 칸이 글 칸을 좁혀 '해 보니' 글이 2 → 4줄 · 카드 352 → 440(+88)이 되자 X1 390 의 글 화면 조각 경계가 밀려 7.7 → 15.6% 로 걸렸다(es_gate 실측).
   쪽 높이 · 조각을 전과 같게 둔다. 7절 860 이하 줄 규칙(이름표 위 · 값 아래)을 그림 든 카드 선택자로 되돌린다 */
@container es2play (max-width:479px){
  body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > .es-cmp-fig{ display:none; }
  body.es-page .es-cmp.es-cmp:has(.es-cmp-fig) > p{ grid-template-columns:minmax(0,1fr); }
  body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig){ grid-template-rows:auto auto; }
  body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig):has(> .es-cmp-mine){ grid-template-rows:auto auto calc(var(--es2-fs-label) * 1.6 + 6px); }
  body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > *,
  body.es-page .es-cmp.es-cmp:has(.es-cmp-fig) > p:not(:has(> .es-cmp-fig)) > *{ grid-column:1; grid-row:2; }
  body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > b,
  body.es-page .es-cmp.es-cmp:has(.es-cmp-fig) > p:not(:has(> .es-cmp-fig)) > b{ grid-column:1; grid-row:1; }
  body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > .es-cmp-judge{ grid-column:1; grid-row:3; }
  body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig) > .es-pill{ grid-column:1; grid-row:2; }
  body.es-page .es-play > .es-cmp:has(.es-cmp-fig){ display:grid; align-content:center; }
}
html.es-tv body.es-page .es-cmp.es-cmp > p:has(> .es-cmp-fig):has(> .es-cmp-mine){ grid-template-rows:minmax(0,1fr) auto calc(var(--es2-fs-cap) * 1.6 + 2px) minmax(0,1fr); }
html.es-tv body.es-page .es-cmp.es-cmp:has(.es-cmp-fig) > p > b{ min-width:calc(104px * var(--es2-zoom)); }   /* 줄마다 이름표 폭이 같아야 그림 칸이 한 세로줄에 선다(TV 는 7절에서 0 으로 풀었다) */

/* ══ 18c. 사용자 결정 셋(2026-10-14 과학 3-2 기준편 '권고대로') — 소리 판 v2 · 무대 켜기 · 방 안 학습 소리 끔 · 320 띠 ═══════════
   (가산 — 있던 규칙은 하나도 고치지 않았다. 이름은 v1 에 없는 es-snd* 만 · 상태는 속성(data-st · data-room-off · data-fold)) */

/* ① 소리 판 v2 — 카드 꼴(DESIGN 토큰). 판 = 패널(테 3 · 모서리 md) · 카드 = 그림 크게 + 소리마다 큰 단추(64) · 울리는 동안 하늘 테 · 판 아래 [✋ 멈추기] + 안내 줄 · 출처 12 맨 아래 */
body.es-page .es-snd{
  display:flex; flex-wrap:wrap; align-items:stretch; gap:var(--es2-gap) calc(16px * var(--es2-zoom));
  box-sizing:border-box; max-width:var(--es2-content); margin:0; padding:calc(16px * var(--es2-zoom));
  background:var(--es2-panel); border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r-md); box-shadow:var(--es2-sh-card);
}
body.es-page .es-snd > :not(.es-snd-card){ flex:1 0 100%; margin:0; max-width:none; }   /* 머리 · 아래 · 출처는 한 줄씩, 카드는 한 줄에 나란히(폭을 나눠 먹는다) */
body.es-page .es-snd-top{ display:grid; gap:8px; }
body.es-page .es-snd-safe{
  display:flex; align-items:center; gap:10px; margin:0; max-width:none;
  color:var(--es2-danger); font-size:var(--es2x-cap); font-weight:var(--es2-fw-head); line-height:1.35;
}
body.es-page .es-snd-safe::before{
  content:""; flex:none; width:calc(30px * var(--es2-zoom)); height:calc(27px * var(--es2-zoom));
  background:no-repeat center/contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 44 40'%3E%3Cpath d='M22 3 L41 37 H3 Z' fill='%23FFD43B' stroke='%2317203A' stroke-width='3.5' stroke-linejoin='round'/%3E%3Cpath d='M22 15 V25' stroke='%2317203A' stroke-width='4' stroke-linecap='round'/%3E%3Ccircle cx='22' cy='31' r='2.6' fill='%2317203A'/%3E%3C/svg%3E");
}
body.es-page .es-snd-row{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--es2-gap); }
body.es-page .es-snd-tip{ font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); color:var(--es2-ink-2); line-height:1.35; }
/* 장난감 단추 한 결(4절과 같은 값 — 4절 목록은 고치지 않고 이름만 더한다) */
body.es-page :is(.es-snd-gate, .es-snd-stop, .es-snd-card > button[data-snd]){
  display:inline-flex; align-items:center; justify-content:center; gap:10px; box-sizing:border-box;
  min-height:var(--es2-tap); min-width:var(--es2-tap); margin:0; padding:8px 18px;
  border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r);
  background:var(--es2-card); color:var(--es2-ink); box-shadow:var(--es2-sh-btn);
  font:var(--es2-fw-strong) var(--es2-fs-btn)/var(--es2-lh-tight) var(--es2-font); text-align:center; text-decoration:none;
  cursor:pointer; -webkit-tap-highlight-color:transparent;
  transition:transform var(--es2-t-press), box-shadow var(--es2-t-press), background-color var(--es2-t-state);
}
body.es-page :is(.es-snd-gate, .es-snd-stop, .es-snd-card > button[data-snd]):active:not([aria-disabled="true"]):not([disabled]){
  transform:translateY(var(--es2-press)); box-shadow:var(--es2-sh-btn-act);
}
body.es-page button.es-snd-gate.is-off{ border-style:dashed; }                       /* 꺼짐 — 색만이 아니라 점선(v1 .es-sound-gate.is-off 와 같은 뜻) */
/* 카드 — 그림이 판의 주인공(크게) · 그 아래 소리마다 큰 단추 */
body.es-page .es-snd-card{
  position:relative; display:grid; grid-template-rows:minmax(0,1fr) auto; gap:var(--es2-gap); align-content:start; box-sizing:border-box;
  flex:1 1 calc(250px * var(--es2-zoom)); min-width:0; margin:0; padding:calc(12px * var(--es2-zoom));
  background:var(--es2-card); border:var(--es2-bw) solid var(--es2-ink); border-radius:var(--es2-r);
  transition:border-color var(--es2-t-state), box-shadow var(--es2-t-state);
}
body.es-page .es-snd-card > :is(svg, img){ display:block; justify-self:center; width:100%; max-width:calc(420px * var(--es2-zoom)); height:auto; max-height:calc(240px * var(--es2-zoom)); }
body.es-page .es-snd-card > button[data-snd]{ width:100%; min-height:var(--es2-tap-lg); font-size:var(--es2-fs-btn-lg); font-weight:var(--es2-fw-head); }
body.es-page .es-snd-card > button[data-snd]::before{ content:"♪"; flex:none; font-size:1.1em; line-height:1; color:var(--es2-sky-deep); }
/* 울리는 동안 — 하늘 테 + 단추 바탕 노랑 · '〰' (색만이 아니라 글자) */
body.es-page .es-snd-card[data-st="ring"]{ border-color:var(--es2-sky); box-shadow:0 0 0 calc(5px * var(--es2-zoom)) var(--es2-sky-soft); }
body.es-page .es-snd-card[data-st="ring"] > button[data-snd]{ background:var(--es2-sun-soft); }
body.es-page .es-snd-card[data-st="ring"] > button[data-snd]::before{ content:"〰"; }
/* 움직임 줄이기 — 떨림 대신 낱말을 그림 위에(쪽 높이를 밀지 않는다) */
body.es-page .es-snd-still{
  position:absolute; left:calc(12px * var(--es2-zoom) + 8px); bottom:calc(12px * var(--es2-zoom) + var(--es2-tap-lg) + var(--es2-gap) + 8px); z-index:1; margin:0; max-width:none;
  padding:2px 12px; border-radius:var(--es2-r-pill); background:var(--es2-ink); color:var(--es2-on-dark);
  font-size:var(--es2x-cap); font-weight:var(--es2-fw-head); line-height:1.35;
}
/* 멈추기 — 울리는 카드 그림 오른쪽 위에 떠 있다(쪽 흐름 밖 — 나타나고 숨어도 쪽 높이 그대로 · 판 아래 빈 줄 0) */
body.es-page .es-snd-card > .es-snd-stop{ position:absolute; z-index:2; top:calc(12px * var(--es2-zoom) + 8px); right:calc(12px * var(--es2-zoom) + 8px); background:var(--es2-card); }
/* 판 아래 — 안내 줄 */
body.es-page .es-snd-foot{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--es2-gap); }
body.es-page .es-snd-msg{ flex:1 1 12em; display:grid; min-width:0; }
body.es-page .es-snd-msg > *{ grid-area:1 / 1; margin:0; max-width:none; font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); line-height:1.4; }
body.es-page .es-snd-sz{ visibility:hidden; pointer-events:none; }                   /* 가장 긴 안내 글 둘 — 칸 높이만 잡는다(글이 바뀌어도 쪽 높이 그대로 · N3) */
body.es-page .es-snd-said{ font-size:var(--es2x-cap); font-weight:var(--es2-fw-strong); color:var(--es2-ink-2); line-height:1.4; }
/* 판 뿌리에 잠금(data-wait)을 걸면 알약이 판 테 위에 걸친다 — 아래 반쪽 자리를 판 안쪽 위에 더 둔다(안전 한 줄을 덮지 않게 · 열려도 그대로 — 쪽 높이 N3) */
body.es-page .es-pill + .es-snd{ padding-top:calc(16px * var(--es2-zoom) + (var(--es2x-cap) * 1.3 + 8px) / 2 + 6px); }
body.es-page .es-snd > .es-credit{ margin:0; font-size:var(--es2-fs-credit); }
body.es-page .es-snd > .es-credit + .es-credit{ margin-top:calc(-1 * var(--es2-gap) + 2px); }
html.es-tv body.es-page .es-snd > .es-credit{ font-size:var(--es2-fs-credit); }   /* TV 에서도 12(DESIGN 3-16 — 출처는 배율 없음) */
@media (prefers-reduced-motion:reduce){
  body.es-page :is(.es-snd-gate, .es-snd-stop, .es-snd-card > button[data-snd]):active{ transform:none !important; }
}
/* ② 무대 소리 길 (가) — 엔진이 조작 줄 끝에 단 켜기 단추 · 알아 두기 맨 위 안전 한 줄 */
body.es-page .es-play .es-ops > .es-snd-gate{ width:100%; flex-direction:column; gap:0; padding:6px 10px; font-weight:var(--es2-fw-head); }
body.es-page .es-play .es-ops[data-zone="act"] > .es-snd-gate{ min-height:var(--es2-tap-lg); }
html.es-tv body.es-page .es-play .es-ops[data-zone="act"] > .es-snd-gate{ min-height:var(--es2-tap); line-height:1.1; padding:6px 8px; }
body.es-page .es-tip > .es-snd-safe{ margin:0; }
/* ③ 함께 하기 방에 붙은 학생 기기 — 학습 소리 켜기 단추도 🔊 와 같은 꺼진 모양(흐린 바탕 · 점선 · 그림자 0) + 누르면 흔들림 */
body.es-page :is(.es-snd-gate, .es-sound-gate)[data-room-off]{ background:var(--es2-dim); border-style:dashed; border-color:var(--es2-line-todo); box-shadow:none; filter:grayscale(1); cursor:not-allowed; }
body.es-page :is(.es-snd-gate, .es-sound-gate)[data-room-off][data-fx="blocked"]{ animation:es2-nudge var(--es2-t-pop) var(--es2-ease) 1; }

/* ④ 계약 9 #24 리드 판정 (b) — 폰 띠 정거장 칩 56 · 사이 12.
   360~374: 정거장 넷 + '나' 가 56 · 사이 12 로 든다(4×56 + 3×12 + 12 + 56 + 바깥 8×2 = 344) — robust-6 의 줄인 칩 · 사이 6 을 되돌린다.
   359 이하: es.js(es2InitMeFold)가 '나' 를 띠에서 첫 화면 머리 줄(.es-today)로 옮긴다 → 띠에는 정거장 넷(260)만. 오늘의 물음이 없는 쪽(쇼츠)은
   '나' 가 띠에 남고 robust-6 꼴(칩이 줄어든다)이 그대로 산다 — 정거장이 하나라 넘치지 않는다 */
@media (max-width:374px){
  body.es-page .es-bar > .es-st{ gap:var(--es2-gap); }
  body.es-page .es-bar > .es-bar-me{ margin-left:var(--es2-gap); }
  body.es-page .es-bar > .es-st > .es-st-chip{ width:var(--es2-tap); min-width:var(--es2-tap); flex:none; }
}
@media (max-width:359px){
  body.es-page .es-bar:has(> .es-bar-me) > .es-st{ gap:6px; }
  body.es-page .es-bar:has(> .es-bar-me) > .es-bar-me{ margin-left:6px; }
  body.es-page .es-bar:has(> .es-bar-me) > .es-st > .es-st-chip{ min-width:44px; width:clamp(44px, calc((100vw - 112px) / 4), var(--es2-tap)); flex:0 1 auto; }
  body.es-page .es-bar:not(:has(> .es-bar-me)){ padding:0 var(--es2-gutter); }
  /* 첫 화면 머리 줄 오른쪽 끝 — 단원 · 차시 줄과 한 줄(🔊 는 그 아래 두 줄) */
  body.es-page .es-today > .es-bar-me{ grid-column:2; grid-row:1; justify-self:end; align-self:start; margin:0 0 6px; }
  body.es-page .es-today:has(> .es-bar-me) > .es-today-head{ grid-column:1; grid-row:1; align-self:center; }
  body.es-page .es-today:has(> .es-bar-me) > .es-say{ grid-row:2 / span 2; }
}

/* ══ 18d. 과학 3-2 권 감사 공용 몫(2026-10-14) — 쇼츠 대기 화면 · 320 쇼츠 · 이름 칸 56 · 나란히 보기 판정 줄 · 한 단추 이동 ═════
   (가산 — 있던 규칙은 하나도 고치지 않았다. 새 이름은 v1 에 없는 es-short-poster 하나 · 상태는 속성 data-press) */

/* ① 쇼츠 대기 화면(계약 1-8-6 · DESIGN 3-20 — measure-1~4): 덮개(단추) 안에 첫 장면 그림(es.js es2InitShorts 가 넣는 span.es-short-poster).
   줄 = 제목 / 그림 / [▶ 안내 한 줄](가운데 한 줄). ▶ 를 그림 위에 얹지 않는다 — 그림 한가운데(05/00 의 물음표 · 07/00 의 '딩—')를 가렸다.
   그림은 자르지 않는다(svg 는 viewBox meet · 사진은 비율 그대로 칸 안에). 첫 장면에 그림이 없는 쇼츠는 옛 꼴 그대로.
   v1 `.es-short-play > span:not(.em):not(.es-short-ttl)`(안내 알약 꼴)이 그림 칸에도 닿아 그것을 걷는다 */
body.es-page .es-short-play:has(> .es-short-poster){
  display:grid; grid-template-columns:minmax(0,1fr) auto auto minmax(0,1fr); grid-template-rows:auto minmax(0,1fr) auto;
  justify-items:center; align-items:center; gap:calc(12px * var(--es2-zoom)); padding:calc(16px * var(--es2-zoom)) calc(20px * var(--es2-zoom));
}
body.es-page .es-short-play:has(> .es-short-poster) > .es-short-ttl{ grid-row:1; grid-column:1 / -1; max-width:100%; }
body.es-page .es-short-play > span.es-short-poster{
  grid-row:2; grid-column:1 / -1; align-self:stretch; justify-self:stretch; display:flex; justify-content:center; align-items:center;
  min-width:0; min-height:0; padding:0; border:0; border-radius:0; background:none; overflow:hidden;
}
body.es-page .es-short.is-live .es-short-play > .es-short-poster > :is(svg, img){
  display:block; flex:0 1 auto; box-sizing:border-box; width:100%; height:100%; max-width:100%; max-height:100%; min-width:0; min-height:0;
  margin:0; border:0; border-radius:var(--es2-r-md); box-shadow:none;
}
/* 사진은 상자를 사진 크기로(빈 띠 0 — es_gate N12) · svg 는 칸을 채우고 viewBox 가 맞춘다(preserveAspectRatio meet) */
body.es-page .es-short.is-live .es-short-play > .es-short-poster > img{ width:auto; height:auto; }
body.es-page .es-short-play:has(> .es-short-poster) > .em{ grid-row:3; grid-column:2; }
body.es-page .es-short-play:has(> .es-short-poster) > span:not(.em):not(.es-short-ttl):not(.es-short-poster){ grid-row:3; grid-column:3; justify-self:start; }
/* ▶ 는 늘 동그라미 — 덮개가 낮으면 flex 가 높이만 줄여 96×54 타원이 됐다(measure-9 · 320) */
body.es-page .es-short-play .em{ flex:none; aspect-ratio:1; }
/* kid-8 — 누르는 순간 눌림(장난감 단추와 같은 결: 내려앉고 그림자 줄임). :active 는 브라우저가, data-press 는 es.js 가 pointerdown 에 단다 */
body.es-page .es-short-play:is(:active, [data-press]) .em{ transform:translateY(var(--es2-press)); box-shadow:var(--es2-sh-btn-act); }
/* 덮개가 서 있는 동안 '장면 N개' 알약을 내린다 — 덮개(z 3)가 알약(z 2)을 덮어 흐리게 비치고 겹쳤다(measure-5~8 · README_es_gate 8절 보고 15).
   ▶ 를 누르면 덮개가 숨고 알약이 '1 / N' 으로 돌아온다 */
body.es-page .es-short-stage:has(> .es-short-play:not([hidden])) > .es-short-no{ display:none; }
/* 좁은 무대(폰 4:3 · 320 창 288×216) — 제목 · 그림 · [▶ 안내] 가 한 판에 들게 사이 · 글을 줄이고 ▶ 56(계약 1-8-6 '56 이상') · 안내는 문장 18(이름표 17 아님) */
@media (max-width:560px){
  body.es-page .es-short-play:has(> .es-short-poster){ gap:6px 10px; padding:8px 10px; }
  body.es-page .es-short-play:has(> .es-short-poster) > .es-short-ttl{ font-size:calc(22px * var(--es2-zoom)); line-height:1.2; }
  body.es-page .es-short-play:has(> .es-short-poster) > .em{ width:var(--es2-tap); height:var(--es2-tap); font-size:calc(26px * var(--es2-zoom)); }
  body.es-page .es-short-play:has(> .es-short-poster) > span:not(.em):not(.es-short-ttl):not(.es-short-poster){ font-size:var(--es2-fs-cap); padding:2px 12px; white-space:nowrap; }
}
/* 칩이 하나뿐인 띠(쇼츠 — 정거장 '열기' 하나)는 줄일 까닭이 없다 — 359 이하 robust-6 꼴의 52 를 56 으로(measure-9~12) */
@media (max-width:359px){
  body.es-page .es-bar:has(> .es-bar-me) > .es-st > .es-st-chip:only-child{ width:var(--es2-tap); min-width:var(--es2-tap); flex:none; }
}

/* ② 분류 칸 이름 입력(v1 .es-sort-bin-name — min-height 48 · 그려진 55) → 56(TV 78) (measure-13) */
body.es-page .es-sort-bin-name{ min-height:var(--es2-tap); }

/* ③ 나란히 보기 — 그림 칸이 있는 카드에서 '내 예상' 줄만 그림이 없을 때(예상 보기가 글뿐 — 06/03) 판정 알약이 내 예상 위 같은 칸(1행)에 얹혔다
   (`:has(.es-cmp-fig) > p:not(:has(> .es-cmp-fig)) > *` 가 7절 `.es-cmp-judge{grid-row:2}` 를 이긴다 — measure-14 · kid-3). 판정은 그 아래 줄로 */
body.es-page .es-cmp.es-cmp:has(.es-cmp-fig) > p:not(:has(> .es-cmp-fig)) > .es-cmp-judge{ grid-column:2 / -1; grid-row:2; }
@container es2play (max-width:559px){
  body.es-page .es-cmp.es-cmp:has(.es-cmp-fig) > p:not(:has(> .es-cmp-fig)):has(> .es-cmp-mine){ grid-template-rows:auto auto calc(var(--es2-fs-label) * 1.6 + 6px); }
  body.es-page .es-cmp.es-cmp:has(.es-cmp-fig) > p:not(:has(> .es-cmp-fig)) > .es-cmp-judge{ grid-column:1 / -1; grid-row:3; }
}
@container es2play (max-width:479px){
  body.es-page .es-cmp.es-cmp:has(.es-cmp-fig) > p:not(:has(> .es-cmp-fig)) > .es-cmp-judge{ grid-column:1; grid-row:3; }
}

/* ④ 맨 아래 이동에 단추가 하나뿐일 때 — 첫 쪽(다음만)은 오른쪽 반 폭인데 끝 쪽(앞만)은 전폭이었다. 같은 반 폭으로 왼쪽에(consist-16) */
body.es-page .es-pager a:only-child[rel="prev"]{ margin-right:auto; flex:0 1 50%; }
@media (max-width:860px){ body.es-page .es-pager a:only-child[rel="prev"]{ margin-right:0; flex-basis:auto; } }

/* ══ 18e. 과학 3-2 관문 ⑤ 공용 몫(2026-10-15) — TV 예상 줄 상태 글 · 카드 앞 잠금 알약이 두 줄일 때 ═══════════════════════════
   (가산 — 있던 규칙은 하나도 고치지 않았다. 새 이름은 속성 data-wrap · 사용자 속성 --es2-pill-x 둘 — 둘 다 es.js 가 단다) */

/* ① TV 예상 줄(관문 ⑤ 쪽이 눈으로 찾음 — 05/03 · 06/03): 17절 TV 격자는 '보기 셋 | 상태 줄' 이라 열 넷(auto auto auto 1fr)에 상태 줄을 4열에 못 박았다.
   보기가 넷인 일곱 쪽(05/02 · 05/03 · 06/02 · 06/03 · 07/03 · 07/04 · 07/05)은 넷째 보기('잘 모르겠어요')가 5열(암묵 열)로 밀려 상태 줄이
   셋째 · 넷째 보기 사이에 끼었고(일곱 쪽 모두), 보기 글이 길어 한 줄이 가득 차면(05/03 · 06/03) 1fr 칸이 0px 이 되어 '정했어요' 가
   한 글자씩 세로로 접혀(폭 0 · 높이 162 · 네 줄) 넷째 보기 위에 겹쳤다. 폭 0 상자는 넓이가 0 이라 es_gate N7 겹침이 못 잡았다.
   상태 줄을 보기 줄에서 빼 **물음 줄 오른쪽 끝**에 둔다 — 보기와 자리를 다투지 않는다. 물음 줄에는 늘 자리가 남는다(TV 실측 25쪽:
   물음 글 끝 ~ 판 오른쪽 627~979px · 가장 긴 상태 글 '이번엔 선생님과 함께 봤어요' 한 줄 309px). 물음 글은 그 자리(11.5배)를 비우고 꺾인다.
   보기 줄은 보기 수만큼 열(auto × N + 1fr 남는 칸 — 넷이면 넷 · 다섯이면 다섯)이라 보기끼리 붙어 서고 남는 칸은 늘 맨 끝이다.
   한 줄 글이라 두 줄 자리(GATE2 '열 때 높이 그대로' — 좁은 4열에서 두 줄이던 것)가 필요 없다: 상태 줄 높이 = 물음 줄 높이(28 × 1.3) — 물음 줄 높이 그대로,
   보기 줄은 상태 줄 두 줄 자리(81.2)가 빠져 보기 높이(78.4)로 — 예상 판 −2.8px(05/03 · 06/03 은 접힌 상태 줄 162px 가 빠져 더 준다).
   보기 글이 길어 한 줄이 가득 찬 쪽(05/03)은 17절 그대로 보기 글이 두 줄로 꺾여 한 줄에 선다(TV 무대 한 화면 — 보기를 두 줄로 늘어놓으면 1067 > 988 실측) */
html.es-tv body.es-page .es-play > .es-predict > .es-predict-q{ padding-right:calc(var(--es2x-cap) * 11.5 + var(--es2-gap)); }
html.es-tv body.es-page .es-play > .es-predict > .es-predict-st{
  grid-row:1; grid-column:1 / -1; justify-self:end; align-self:center;
  max-width:calc(var(--es2x-cap) * 11.5); min-height:calc(var(--es2x-cap) * 1.3); line-height:1.3; text-align:right;
}
html.es-tv body.es-page .es-play > .es-predict:has(> .es-opt:nth-of-type(4)){ grid-template-columns:repeat(4, auto) minmax(0,1fr); }
html.es-tv body.es-page .es-play > .es-predict:has(> .es-opt:nth-of-type(5)){ grid-template-columns:repeat(5, auto) minmax(0,1fr); }

/* ② 카드 앞 잠금 알약(5절 자리 ① — 흐름 밖 · 높이 0 닻)이 두 줄로 꺾일 때(관문 ⑤ 06/07 · 320 창 — '편지 부치기를 다 하면 열려요').
   5절은 translateY(-50%) 로 알약 가운데를 닻 줄에 얹는다 — 두 줄이면 위로 반 줄 더 자라 바로 위 제목을 덮었다
   (2026-10-15 실측 v2 33쪽 × 320: 카드 앞 알약 93개 중 두 줄 52 · 위 제목을 덮음 17 · 아래 카드 글(안전 줄 '귀가 아프면 바로 멈춰요.' 포함)을 덮음 11 ·
   목록 첫 카드를 덮음 6. 390 · 1366 · TV 는 한 줄).
   es.js(es2PillRoom)가 알약 높이를 재어 한 줄보다 높으면 data-wrap 과 --es2-pill-x(늘어난 높이)를 달고 다음 형제의 위 안쪽 여백을 그만큼 늘린다.
   여기서는 첫 줄을 닻에 둔다(늘어난 줄은 아래로 — 늘린 여백 안). 한 줄 알약 · JS 꺼짐 · 무대 틀 안(②) · 나란히 보기 줄(③)은 그대로 */
body.es-page :not(.es-play, .es-cmp p) > .es-pill[data-wrap]{ transform:translateY(calc(-50% + var(--es2-pill-x, 0px) / 2)); }

/* ══ 19. 움직임 — 이름은 es2- 로 시작(v1 @keyframes 와 겹치지 않게). 한 번만 돌고 멈춘다 ══════════════════ */
@keyframes es2-up{ from{ opacity:0; transform:translateY(8px); } to{ opacity:1; transform:none; } }
@keyframes es2-pop{ 0%{ transform:scale(.6); } 60%{ transform:scale(1.12); } 100%{ transform:scale(1); } }
@keyframes es2-tick{ 0%{ transform:scale(1); } 50%{ transform:scale(1.12); } 100%{ transform:scale(1); } }
@keyframes es2-nudge{ 0%,100%{ transform:translateX(0); } 25%{ transform:translateX(-6px); } 75%{ transform:translateX(6px); } }
@keyframes es2-call{ 0%,100%{ box-shadow:0 0 0 6px var(--es2-sun); } 45%{ box-shadow:0 0 0 14px var(--es2-sun); } }
@keyframes es2-ring{ 0%,100%{ box-shadow:0 0 0 0 rgba(255,212,59,0); } 45%{ box-shadow:0 0 0 7px rgba(255,212,59,.95); } }
@keyframes es2-pulse{ 0%,100%{ box-shadow:var(--es2-sh-btn), 0 0 0 0 rgba(255,212,59,0); } 50%{ box-shadow:var(--es2-sh-btn), 0 0 0 10px rgba(255,212,59,.95); } }
@keyframes es2-stamp{ from{ transform:rotate(-7deg) scale(1.8); opacity:0; } to{ transform:rotate(-7deg) scale(1); opacity:1; } }
@keyframes es2-peel{ from{ transform:rotate(-30deg) scale(.3); opacity:0; } to{ transform:rotate(-6deg) scale(1); opacity:1; } }
@counter-style es2-circ{ system:fixed; symbols:"\2776" "\2777" "\2778" "\2779" "\277A" "\277B" "\277C" "\277D" "\277E"; suffix:""; fallback:decimal; }
/* ════════════════════════════════════ ES2 끝 ════════════════════════════════════ */
