@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; }
}

/* 그려지는 선 — 차시 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 를 쓰지 않는다(겹치는 층이 없다).
     · 움직임은 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) ────────────────────────────────────────────────
   ⚠️ `display:none` 이 아니라 **visibility:hidden** 이다. 까닭 둘:
      ① 자리는 그대로 잡아 두므로 안쪽 무대(.es-stage)가 **제 폭으로** 만들어진다 —
         숨겼다 보이면 폭 0 으로 그려진 그림이 깨진 채 열린다.
      ② visibility:hidden 은 **어느 브라우저에서나 Tab 차례에서 빠진다.** es.js 가 함께 거는
         `inert` 는 낭독기까지 막지만 옛 브라우저가 모른다 — 이 한 줄이 그 자리를 메운다. */
.es-lock{ visibility:hidden; }
.es-lock-note{
  display:flex; align-items:center; gap:10px;
  margin:var(--es-sp-3) 0 var(--es-sp-2); padding:14px 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-lg); font-weight:800; color:var(--es-ink-2);
  max-width:var(--es-mid);
}

/* ── ㉓ 수평잡기 판 (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-note{
    background:#fff !important; color:#000 !important; border-color:#666 !important;
  }
  .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; }
}


/* ============================================================================
   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; }
}
