/* ============================================================
   КОНТРАСТ — UI-kit
   1. Токены   2. Основа   3. Типографика   4. Раскладка
   5. Компоненты   6. Сцены   7. Адаптивность и доступность
   Витрина всех элементов: ui-kit.html
   ============================================================ */

/* 1. Токены ------------------------------------------------- */
:root {
  /* Цвет: одна бумага, одна тушь, один акцент. */
  --paper: #f1f0eb;
  --paper-deep: #e5e6db;
  --ink: #191a17;
  --ink-deep: #0e0f0c;
  --muted: var(--ink);
  --muted-on-ink: var(--paper);
  --line: #d1d1c8;
  --line-on-ink: #3a3c35;
  --accent: #ee492c;
  --accent-hover: #ff6040;
  --accent-shade: #a92e1a;
  --sage: #a8af99;
  --sage-shade: #68705c;
  --dot: #c0c2b6;
  --moss: #293022;

  /* Шрифт: Manrope для всего, Oswald только для обложки, Georgia — курсивный голос. */
  --sans: 'Manrope', Arial, sans-serif;
  --display: 'Oswald', 'Arial Narrow', sans-serif;
  --serif: Georgia, 'Times New Roman', serif;

  /* Шкала: четыре размера текста на весь лонгрид (обложка — отдельно, в .hero-title).
     Крупный размер зависит и от высоты окна: абзац над графиком бала не должен под него уходить. */
  --text-title: clamp(38px, 5.6vw, 84px);
  --text-lead: clamp(22px, min(2.8vw, 4.4svh), 40px);
  --text-body: clamp(16px, 1.15vw, 18px);
  --text-ui: 14px;

  /* Отступы: шаг ×1.6. */
  --space-1: 8px;
  --space-2: 16px;
  --space-3: 24px;
  --space-4: 40px;
  --space-5: 64px;
  --space-6: 104px;
  --space-7: 160px;

  /* Сетка: общие поля и ширина для всех сцен. */
  --gutter: clamp(20px, 6vw, 96px);
  --measure: 1240px;
  --measure-text: 640px;
  --measure-lead: 1080px;
  --inline: max(var(--gutter), calc((100% - var(--measure)) / 2));

  --ease: cubic-bezier(.22, 1, .36, 1);
}

/* 2. Основа ------------------------------------------------- */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body { margin: 0; background: var(--paper); color: var(--ink); font-family: var(--sans); font-size: var(--text-body); line-height: 1.65; -webkit-font-smoothing: antialiased; }
button, a, input { -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
button { font: inherit; color: inherit; cursor: pointer; border: 0; }
a { color: inherit; text-decoration: none; text-underline-offset: 4px; }
p a { text-decoration: underline; }
p, h1, h2, h3 { margin: 0; }
[hidden] { display: none !important; }
::selection { background: var(--accent); color: var(--ink); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 5px; }
#hero-title:focus, #sound-explanation:focus { outline: none; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

/* 3. Типографика -------------------------------------------- */
/* Шесть ролей. Каждая задаёт начертание целиком, ничего не наследует от сцены:
   сцены отвечают только за место текста, а не за его вид.
   Обложка    .hero-title  Oswald 600, только «КОНТРАСТ»
   Заголовок  h2, .title   Manrope 600, 38–84 px, интерлиньяж 1
   Лид        .lead        Manrope 600, 22–40 px, 1.25 — крупный текст сцен
   Голос      .voice       Georgia курсив, размер лида — авторская реплика
   Основной   .body-copy   Manrope 400, 16–18 px, 1.65, приглушённый
   Подпись    .label       Manrope 400, 14 px — подписи, источники, служебное
   Кнопка     .button …    Manrope 600, 14 px — всё, на что нажимают
   Внутри строки: .serif — слово-акцент курсивом, .highlight — выделение мысли. */
h2, .title { font-family: var(--sans); font-size: var(--text-title); font-weight: 600; line-height: 1; letter-spacing: -.055em; text-wrap: balance; }
.lead { max-width: var(--measure-lead); font-family: var(--sans); font-size: var(--text-lead); font-weight: 600; line-height: 1.25; letter-spacing: -.04em; text-wrap: pretty; }
.voice { max-width: var(--measure-lead); font-family: var(--serif); font-style: italic; font-size: var(--text-lead); font-weight: 400; line-height: 1.25; letter-spacing: -.025em; text-wrap: pretty; }
.body-copy { max-width: var(--measure-text); font-family: var(--sans); font-size: var(--text-body); font-weight: 400; line-height: 1.65; letter-spacing: 0; color: var(--muted); }
.label { font-family: var(--sans); font-size: var(--text-ui); font-weight: 400; line-height: 1.5; letter-spacing: 0; color: var(--muted); }
.serif { font-family: var(--serif); font-style: italic; font-weight: 400; letter-spacing: -.04em; }
.highlight { padding: 0 .12em; background: var(--accent); color: var(--ink); -webkit-box-decoration-break: clone; box-decoration-break: clone; }

/* 4. Раскладка ---------------------------------------------- */
.container { padding-inline: var(--inline); }
.section-pad { padding-block: var(--space-6); }
.scene-heading { margin-bottom: var(--space-4); }
.chapter { display: flex; gap: var(--space-1); margin-bottom: var(--space-3); }
.chapter b { font-weight: 600; color: var(--accent); }
.on-ink :is(.label, .chapter, .body-copy) { color: var(--muted-on-ink); }

/* 5. Компоненты --------------------------------------------- */

/* Кнопки: основная, контурная, текстовая, круглая. Все — от 44 px. */
.button { display: inline-flex; align-items: center; justify-content: center; gap: 14px; min-height: 48px; padding: 12px 22px; border: 1px solid transparent; background: transparent; font-size: var(--text-ui); font-weight: 600; line-height: 1.2; white-space: nowrap; transition: background .2s, color .2s, border-color .2s; }
.button--primary { background: var(--accent); color: var(--ink); }
.button--primary:hover { background: var(--accent-hover); }
.button--outline { border-color: currentColor; }
.button--outline:hover { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.on-ink .button--outline:hover { background: var(--paper); border-color: var(--paper); color: var(--ink); }
.button:disabled { opacity: .7; cursor: wait; }
.button-icon { font-size: 11px; width: 12px; }
.link-button { display: inline-flex; align-items: center; gap: 12px; min-height: 44px; padding: 10px 0; background: transparent; border-bottom: 1px solid currentColor; font-size: var(--text-ui); font-weight: 600; line-height: 1.2; white-space: nowrap; transition: color .2s; }
.link-button:hover { color: var(--accent); }
.circle-link { width: 48px; height: 48px; display: grid; place-items: center; border: 1px solid currentColor; border-radius: 50%; flex-shrink: 0; font-size: 24px; transition: background .2s, color .2s; }
.circle-link:hover { background: var(--ink); color: var(--paper); }
.circle-link span { transition: transform .25s var(--ease); }
.circle-link:hover span { transform: translateY(3px); }

/* Служебное */
.skip-link { position: fixed; left: var(--space-3); top: var(--space-3); z-index: 100; padding: 14px 20px; background: var(--accent); color: var(--ink); font-size: var(--text-ui); font-weight: 600; line-height: 1.2; transform: translateY(-160%); }
.skip-link:focus { transform: none; }
.reading-progress { position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 50; pointer-events: none; }
.reading-progress span { display: block; height: 100%; background: var(--accent); transform: scaleX(0); transform-origin: left; }

/* Мост между главами */
.chapter-bridge { margin-top: var(--space-5); color: var(--ink); }
.on-ink .chapter-bridge { color: var(--muted-on-ink); }

/* Раскрывающийся список источников */
.sources { margin-top: var(--space-5); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.sources summary { min-height: 64px; padding: var(--space-2) 0; cursor: pointer; display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); list-style: none; font-size: var(--text-ui); font-weight: 600; line-height: 1.2; }
.sources summary::-webkit-details-marker { display: none; }
.sources summary:hover { color: var(--accent); }
.sources-plus { font-size: 22px; font-weight: 400; transition: transform .2s; }
.sources[open] .sources-plus { transform: rotate(45deg); }
.source-list { padding-bottom: var(--space-3); }
.source-list>p { padding-bottom: var(--space-3); }
.source-list>a { padding: var(--space-2) 0; border-top: 1px solid var(--line); display: grid; grid-template-columns: 28px 1fr 20px; gap: 12px; font-size: var(--text-body); font-weight: 600; transition: color .2s; }
.source-list>a:hover { color: var(--accent); }
.source-list>a>span { padding-top: .2em; }
.source-list small { display: block; margin-top: 4px; max-width: var(--measure-text); }

/* Пианино */
/* Клавиши и график частот — во всю ширину экрана, с одинаковыми полями: пик стоит над своей клавишей. */
.piano-stage { flex: none; margin-inline: calc(50% - 50vw); padding: var(--space-1) var(--space-1) 10px; background: var(--ink-deep); }
.piano { position: relative; height: clamp(96px, 18svh, 190px); isolation: isolate; touch-action: none; user-select: none; -webkit-user-select: none; cursor: pointer; }
.piano-key { position: absolute; top: 0; border-radius: 0 0 3px 3px; transition: background 80ms, transform 80ms; }
.piano-key.is-white { height: 100%; background: var(--paper); border-right: 1px solid #62655a; border-bottom: 6px solid #b9bbaf; }
.piano-key.is-black { z-index: 1; height: 62%; background: #242620; border: 1px solid var(--ink-deep); border-bottom: 6px solid #090a07; box-shadow: 0 3px 3px #0005; }
.piano-key[data-label]::after { content: attr(data-label); position: absolute; left: 0; right: 0; bottom: 4px; text-align: center; font-size: 11px; line-height: 1; color: #8a8d82; pointer-events: none; }
.piano-key.is-active { background: var(--accent); border-bottom-color: var(--accent-shade); transform: translateY(3px); }
.piano-key.is-active.is-second { background: var(--sage); border-bottom-color: var(--sage-shade); }
.piano-key.is-active[data-label]::after { color: var(--ink); }
@media (hover: hover) {
  .piano-key.is-white:not(.is-active):hover { background: #fff; }
  .piano-key.is-black:not(.is-active):hover { background: #34362f; }
}
.piano-hint { text-align: center; }
.piano-hint .for-touch { display: none; }
@media (hover: none) {
  .piano-hint .for-mouse { display: none; }
  .piano-hint .for-touch { display: inline; }
}
kbd { font: inherit; padding: 0 5px; border: 1px solid currentColor; border-radius: 3px; }

/* 6. Сцены -------------------------------------------------- */

/* Обложка */
.hero { position: relative; min-height: 100vh; min-height: 100svh; padding-block: var(--space-5); padding-inline: max(var(--gutter), calc((100% - 1470px) / 2)); display: flex; flex-direction: column; justify-content: center; }
.hero-title { font: 600 clamp(64px, 19.6vw, 340px)/1.12 var(--display); letter-spacing: -.05em; white-space: nowrap; }
/* У «К» в Oswald пустое поле слева ≈ .06 кегля: сдвигаем, чтобы левой гранью был штрих буквы, а не пустое поле. */
.hero-byline { position: absolute; left: max(var(--gutter), calc((100% - 1470px) / 2)); bottom: var(--space-4); }
.hero-title h1 { display: inline; margin-left: -.055em; font: inherit; letter-spacing: inherit; }
/* Точка заголовка — кнопка «читать». Пропорции из макета: высота ≈ 0,2 кегля, нижний край на базовой линии. */
.read-button { display: inline-block; overflow: hidden; vertical-align: baseline; margin-left: .3em; font-size: max(14px, .058em); line-height: 2.45; letter-spacing: 0; padding: .33em .33em .58em; background: var(--accent); color: #fff; transition: background .2s; }
.read-button:hover { background: var(--accent-hover); }
.read-button:focus-visible { outline-offset: 4px; }
.js-enabled .hero-title { opacity: 0; transform: translateY(22px); transition: opacity .85s var(--ease), transform .85s var(--ease); }
.js-enabled.intro-ready .hero-title { opacity: 1; transform: none; }
/* Обложка гаснет вместе с прокруткой (--hero-leave от 0 до 1) или по «читать» (.is-leaving). */
.js-enabled .hero { opacity: calc(1 - var(--hero-leave, 0)); }
.js-enabled .hero.is-leaving { opacity: 0; transition: opacity 1.2s ease-in-out; }

/* Общие sticky-сцены */
.scene-sticky { position: sticky; top: 0; height: 100vh; height: 100svh; }

/* 00 Родилась она. Всё идёт от прокрутки (origin.js): надписи выезжают снизу и уходят вверх,
   чёрный квадрат распадается на формы, формы разлетаются, узор мелких форм становится полем точек. */
.origin-stage { display: flex; flex-direction: column; }
.origin-canvas { display: none; }
.origin-copy { display: grid; gap: var(--space-4); padding-block: var(--space-6); }
.origin-form { fill: var(--ink); }
.js-enabled .origin:not(.is-still) .origin-scroll { height: 800vh; height: 800svh; }
.js-enabled .origin:not(.is-still) .origin-stage { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; }
.js-enabled .origin:not(.is-still) .origin-canvas { display: block; position: absolute; inset: 0; width: 100%; height: 100%; }
.js-enabled .origin:not(.is-still) .origin-copy { position: absolute; top: clamp(72px, 13svh, 150px); left: 0; right: 0; display: grid; gap: 0; padding-block: 0; pointer-events: none; }
.js-enabled .origin:not(.is-still) .origin-text { grid-area: 1 / 1; opacity: 0; visibility: hidden; will-change: transform, opacity; }
/* Первая и последняя надписи — посередине экрана, как у заголовка. */
.js-enabled .origin:not(.is-still) .origin-text:is(:first-child, :last-child) { align-self: start; padding-top: calc(50svh - clamp(72px, 13svh, 150px) - .6em); }

/* 01 Точки и фигуры. Кадр задаёт прокрутка; перед ростом квадрата есть пауза для чтения. */
.attention-scene { --story-accent: var(--accent); --story-copy-1: 1; --story-copy-2: 1; --story-copy-3: 1; }
.js-enabled .attention-scene { height: 1250vh; height: 1250svh; }
/* Усилие: пока точка рвётся из сетки, по краям экрана нарастает оранжевое свечение. */
.js-enabled .attention-stage::after { content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none; background: linear-gradient(90deg, rgb(238 73 44 / .42), rgb(238 73 44 / 0) 16%, rgb(238 73 44 / 0) 84%, rgb(238 73 44 / .42)); opacity: var(--strain, 0); }
.attention-stage { position: relative; height: auto; min-height: 100svh; display: flex; flex-direction: column; justify-content: center; gap: var(--space-5); padding: var(--space-5) var(--gutter); }
.story-canvas { display: none; }
.story-canvas pattern circle, .story-canvas g circle, .story-dot circle { fill: var(--dot); }
.story-canvas .story-hole { fill: var(--paper); }
.story-canvas rect:not([fill]), .story-square { fill: var(--ink); }
.story-frame .story-circle, .story-frame .story-square--small { fill: var(--story-accent); }
/* Без JS и в статичном режиме — четыре кадра подряд, затем вопрос. */
.story-frames { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); gap: var(--space-4) var(--space-3); max-width: var(--measure); width: 100%; margin: 0 auto; padding: 0; list-style: none; }
.story-frame svg { display: block; width: 100%; height: auto; background: var(--paper-deep); }
.story-frame .label { margin-top: var(--space-1); }
.story-copy { max-width: var(--measure); width: 100%; margin: 0 auto; }
.story-copy .body-copy { margin-top: var(--space-3); }
.story-bridge { margin-top: var(--space-4); }
.js-enabled .attention-stage { position: sticky; height: 100vh; height: 100svh; padding: 0; }
.js-enabled .story-canvas { display: block; position: absolute; inset: 0; width: 100%; height: 100%; }
.js-enabled .story-frames { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); }
.js-enabled .story-copy { position: absolute; z-index: 1; left: var(--gutter); right: var(--gutter); bottom: var(--space-5); width: auto; pointer-events: none; }
.js-enabled .story-copy>h2 { opacity: var(--story-copy-1); }
.js-enabled .story-copy>.body-copy { opacity: var(--story-copy-2); }
.js-enabled .story-copy>.story-bridge { opacity: var(--story-copy-3); }

/* Появление сцен */
.js-enabled .scene>.scene-heading, .js-enabled .scene>.sound-lab, .js-enabled .conclusion>h2 { opacity: 0; transform: translateY(22px); transition: opacity .7s var(--ease), transform .7s var(--ease); }
.js-enabled .scene.is-entered>.scene-heading, .js-enabled .scene.is-entered>.sound-lab, .js-enabled .conclusion.is-entered>h2 { opacity: 1; transform: none; }
.scene.is-entered>.sound-lab { transition-delay: .12s; }


/* 03 Звук */
.sound-section { background: var(--ink); color: var(--paper); padding-bottom: var(--space-5); }
.sound-lab { --sound-deck-height: clamp(400px, 52svh, 560px); position: relative; display: grid; overflow-anchor: none; }
.sound-story, .sound-instrument { grid-area: 1 / 1; }
/* Дорожка: когда текст над ней доходит до верха окна, мелодия начинается и доигрывает сама. */
.js-enabled .sound-track { height: 200vh; height: 200svh; }
.js-enabled .sound-track>.sound-step { position: sticky; top: 0; }
.sound-step { min-height: 100vh; min-height: 100svh; display: flex; flex-direction: column; justify-content: center; padding-top: clamp(20px, 4svh, 48px); padding-bottom: calc(var(--sound-deck-height) + clamp(20px, 4svh, 48px)); }
/* Абзац целиком помещается над графиком: размер зависит и от ширины, и от высоты окна. */
.sound-copy { width: 100%; }
.sound-copy:focus { outline: none; }
.sound-copy .body-copy { margin-top: var(--space-3); }
.sound-instrument { position: sticky; top: calc(100svh - var(--sound-deck-height)); height: var(--sound-deck-height); align-self: start; z-index: 2; background: var(--ink); padding-block: var(--space-2); display: flex; flex-direction: column; gap: 12px; }
/* Текст уходит под график через мягкое затемнение, а не по резкой линии. */
.sound-instrument::before { content: ''; position: absolute; left: 0; right: 0; bottom: 100%; height: clamp(32px, 6svh, 64px); background: linear-gradient(to bottom, transparent, var(--ink)); pointer-events: none; }
.spectrum-stage { position: relative; flex: 1; min-height: 60px; margin-inline: calc(50% - 50vw); padding-inline: var(--space-1); display: grid; grid-template-rows: minmax(0, 1fr) auto; gap: 6px; }
#spectrum-canvas { grid-area: 1 / 1; display: block; width: 100%; height: 100%; min-height: 0; }
#spectrum-caption { grid-row: 2; text-align: center; color: var(--muted-on-ink); }
/* Бал: круг и маленький квадрат первой истории танцуют на пиках (ball.js). */
.ball-floor { grid-area: 1 / 1; position: relative; z-index: 4; pointer-events: none; --dancer: clamp(16px, 1.7vw, 28px); }
.dancer { position: absolute; left: 0; top: 0; display: block; width: var(--dancer); aspect-ratio: 1; background: var(--accent); will-change: transform; transition: opacity .3s; }
.dancer--circle { z-index: 1; border-radius: 50%; transition: opacity .3s, box-shadow .4s; }
.dancer--square { width: calc(var(--dancer) * 1.6); }
.ball-floor[data-state="hidden"] .dancer { opacity: 0; }
.ball-floor[data-merged="true"] .dancer--circle { box-shadow: 0 0 0 2px var(--ink); }
.confetti-layer { position: fixed; inset: 0; overflow: hidden; pointer-events: none; z-index: 70; }
.confetti-layer i { position: absolute; display: block; width: 6px; height: 10px; }
/* Вступление гаснет, пока идёт бал; объяснение поднимается после паузы. */
.listening-actions { flex: none; height: 52px; display: flex; align-items: center; justify-content: center; gap: var(--space-3); }
.audio-error:empty { display: none; }
.audio-error:not(:empty) { position: absolute; bottom: 82px; left: var(--inline); right: var(--inline); padding: 12px; background: var(--ink); text-align: center; color: var(--muted-on-ink); }

/* 04 Ожидание */

/* 05 Вывод */
.conclusion { padding-bottom: var(--space-5); }
/* Третий акт: тритон выглядывает из воды и трубит в раковину, на зов поднимается
   его море и накрывает экран. Под водой чужие — точка и квадрат.
   Контекст влияет на контраст. */
.stranger { --sea: 0; --lift: 0; --sink: 0; --text-a: 1; --text-b: 0; --text-c: 0; --dive: 0; --dark: 0; --tw: clamp(240px, 36vw, 540px); --floor: clamp(56px, 11svh, 120px); --tr: max(var(--gutter), calc(50% - 620px)); --fig: clamp(64px, 8.5vw, 136px); }
.stranger-scroll { height: 100vh; height: 100svh; }
.js-enabled .stranger-scroll { height: 600vh; height: 600svh; }
.stranger-stage { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; background: var(--paper); }
.sea { position: absolute; inset: 44% 0 0; transform: translateY(calc((1 - var(--sea)) * 100%)); will-change: transform; }
/* Толща воды: нижний край ближних гребней тает, и вода плавно темнеет от цвета волн
   к глубине — без шва между гравюрой и заливкой. Светлый текст под водой встаёт
   на спокойный тёмный фон. */
.sea::after { content: ""; position: absolute; left: 0; right: 0; top: calc(100% - 12vh); top: calc(100% - 12svh); height: 230vh; height: 230svh; background: linear-gradient(rgb(37 105 89 / 0), #256959 12svh, #0b3d35 40svh, #001a17 90svh, #00100e); }
/* Рисунок волн 1683×748 повторяется по горизонтали; --tile — ширина одного повтора.
   Слои стоят от низа моря и заходят друг за друга: просветы между гребнями
   занимают верхние 61% рисунка, и за ними всегда лежит дальний слой. Поэтому
   море доходит до низа экрана без сплошной заливки. --wave — высота ближнего слоя. */
.stranger { --wave: 42vh; --wave: 42svh; }
.sea-layer { position: absolute; left: 0; right: 0; bottom: calc(var(--wave) * var(--lift)); height: var(--crest); overflow: hidden; --crest: calc(var(--wave) * var(--scale)); --tile: calc(var(--crest) * 1683 / 748); }
.sea-drift { position: absolute; inset: 0 auto 0 0; width: calc(100% + var(--tile)); animation: sea-drift var(--drift) linear infinite; }
.sea-waves { height: 100%; background: url(assets/sea/sea-waves.webp) repeat-x 0 0 / var(--tile) var(--crest); }
.sea-layer--far { --lift: .62; --scale: .6; --drift: 120s; filter: saturate(.8) brightness(1.08); }
.sea-layer--mid { --lift: .36; --scale: .8; --drift: 95s; }
.sea-layer--mid .sea-drift { animation-direction: reverse; }
.sea-layer--near { --lift: 0; --scale: 1; --drift: 70s; }
/* Нижний край ближнего слоя тает в толще воды. */
.sea-layer--near .sea-waves { -webkit-mask-image: linear-gradient(#000 82%, transparent); mask-image: linear-gradient(#000 82%, transparent); }
@keyframes sea-drift { to { transform: translateX(calc(-1 * var(--tile))); } }
.stranger-cast { position: absolute; left: 0; right: 0; bottom: var(--floor); height: 0; }
/* Тритон в море, между средним и ближним слоем. Пока он чужой, ближние гребни
   закрывают его до плеч; перед зовом (--lift) он чуть приподнимается из воды. */
.stranger-triton, .triton-call { position: absolute; right: var(--tr); bottom: calc(var(--wave) * .5); width: var(--tw); aspect-ratio: 1; transform: translateY(calc((1 - var(--lift) * .55) * var(--tw) * .44)); }
.js-enabled .stranger:not(.is-still) .stranger-triton { animation: cast-bob 5.2s -2s ease-in-out infinite; }
.stranger-triton img { display: block; width: 100%; height: 100%; translate: 0 7%; }
/* Зов: тритон подносит раковину к губам и трубит, пока поднимается его море.
   Рисунок с раковиной крупнее, поэтому он уменьшен до масштаба лежащего тритона. */
.triton-pose { position: absolute; inset: 0; }
.triton-pose--call { display: none; scale: .8; transform-origin: 72% 78%; }
.is-blowing .triton-pose--rest { display: none; }
.is-blowing .triton-pose--call { display: block; }
.triton-call { pointer-events: none; }
.triton-call i { position: absolute; left: calc(57% - var(--tw) * .09); top: calc(24% - var(--tw) * .09); width: calc(var(--tw) * .18); aspect-ratio: 1; border: 3px solid var(--ink); border-radius: 50%; opacity: 0; }
.is-calling .triton-call i { animation: call-ring 1.2s ease-out 2 both; }
.is-calling .triton-call i:nth-child(2) { animation-delay: .3s; }
.is-calling .triton-call i:nth-child(3) { animation-delay: .6s; }
@keyframes call-ring { from { scale: .3; opacity: .8; } to { scale: 4.2; opacity: 0; } }
.cast-circle, .cast-square { position: absolute; bottom: 0; display: block; background: var(--accent); transform: translateY(calc(var(--sink) * -16svh + var(--dive) * 4svh)) rotate(calc(var(--sink) * 28deg + var(--dive) * 17deg)); }
/* On the way down the water turns black over everything but the figures: they keep their colour. */
.stranger-dark { position: absolute; inset: 0; background: #000; opacity: var(--dark); pointer-events: none; }
.stranger.is-still .stranger-dark { display: none; }
/* Под водой фигуры всплывают в толщу, от них поднимаются пузыри. */
.cast-circle::before, .cast-square::before, .cast-square::after { content: ""; position: absolute; left: 30%; top: -14px; width: 9px; aspect-ratio: 1; border: 1.5px solid var(--paper); border-radius: 50%; opacity: 0; }
.cast-square::after { left: 70%; width: 6px; }
.is-sea .cast-circle::before, .is-sea .cast-square::before, .is-sea .cast-square::after { animation: bubble 2.8s ease-in infinite; }
.is-sea .cast-square::before { animation-delay: -1.1s; }
.is-sea .cast-square::after { animation-delay: -2s; }
@keyframes bubble { from { translate: 0 0; opacity: calc(var(--sink) * (1 - var(--dark)) * .9); } to { translate: 6px -16svh; opacity: 0; } }
.cast-square { right: calc(var(--tr) + var(--tw) * .98); width: calc(var(--fig) * 1.6); aspect-ratio: 1; rotate: -8deg; transform-origin: 0 100%; }
.cast-circle { right: calc(var(--tr) + var(--tw) * .98 + var(--fig) * 1.6 + 14px); width: var(--fig); aspect-ratio: 1; border-radius: 50%; }
.is-sea .cast-circle { animation: cast-bob 3.4s ease-in-out infinite; }
.is-sea .cast-square { animation: cast-bob 4.1s -1.2s ease-in-out infinite; }
@keyframes cast-bob { 50% { translate: 0 -7px; } }
.stranger-copy { position: absolute; top: clamp(72px, 13svh, 150px); left: 0; right: 0; display: grid; }
.stranger-text { grid-area: 1 / 1; max-width: var(--measure-lead); }
.stranger-text .body-copy { margin-top: var(--space-3); }
.js-enabled .stranger-text--a { opacity: var(--text-a); }
.js-enabled .stranger-text--b { opacity: var(--text-b); }
.stranger-text--c { color: var(--paper); }
.js-enabled .stranger-text--c { align-self: start; margin-top: 18svh; opacity: var(--text-c); }
.stranger.is-still .stranger-text--c { color: var(--ink); }
.stranger.is-still .stranger-scroll { height: auto; }
.stranger.is-still .stranger-stage { position: relative; height: auto; display: flex; flex-direction: column; }
.stranger.is-still .stranger-copy { order: -1; position: relative; top: auto; display: block; padding-block: var(--space-6) var(--space-5); }
.stranger.is-still .stranger-text + .stranger-text { margin-top: var(--space-5); }
.stranger.is-still .sea { inset: auto 0 0; height: 62svh; }
.stranger.is-still { --wave: 40vh; --wave: 40svh; }
.stranger.is-still .stranger-cast { position: relative; bottom: auto; height: 62svh; }
.stranger.is-still .cast-circle, .stranger.is-still .cast-square { bottom: 14svh; }
/* При погружении ссылки проходят снизу вверх; итог продолжает чёрный фон. */
.sources-chapter { --source-count: 7; color: var(--paper); background: #000; }
.source-items { list-style: none; padding-block: var(--space-5); }
.source-item { max-width: 760px; margin: 0 auto var(--space-4); text-align: center; }
.source-link { display: inline-flex; align-items: center; gap: .6em; min-height: var(--source-hit, 44px); max-width: 100%; padding-block: 12px; color: inherit; font-size: var(--text-lead); line-height: 1.35; }
.source-link>span { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .2em; }
.source-link>svg { flex: none; width: .7em; height: .7em; }
.source-link:hover { color: var(--accent); }
.source-link:focus-visible { outline-offset: 6px; }
.sources-chapter.is-floating .sources-scroll { height: calc((var(--source-count) + 1) * 120vh); height: calc((var(--source-count) + 1) * 120svh); }
.is-floating .sources-stage { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: clip; }
.is-floating .source-items { position: absolute; inset: 0; max-width: none; width: 100%; padding: 0; }
.is-floating .source-item { position: absolute; top: 50%; left: 50%; width: min(760px, calc(100% - var(--gutter) * 2)); margin: 0; opacity: var(--fall-opacity, 0); transform: translate(-50%, -50%) translate(calc(var(--fall-x, 0) * clamp(24px, 14vw, 240px)), var(--fall-y, 70svh)) rotate(var(--fall-angle, 0deg)) scale(var(--fall-scale, 1)); pointer-events: none; will-change: transform, opacity; }
.is-floating .source-item.is-readable { pointer-events: auto; }
.conclusion-copy { padding-block: var(--space-5) var(--space-6); }
.conclusion-copy .lead { margin-top: var(--space-3); }
.conclusion-copy .button { display: flex; width: 100%; justify-content: space-between; min-height: 56px; margin-top: var(--space-4); }
.credits { display: grid; gap: var(--space-1); max-width: var(--measure-text); margin-top: var(--space-4); }
.credits a { text-decoration: underline; }
.restart-veil { position: fixed; inset: 0; z-index: 90; background: white; opacity: 0; pointer-events: none; transition: opacity .8s; }
.restart-veil.active { opacity: 1; transition: opacity .25s; }
/* Подвал с веб-рингом. */
.webring-zone { display: flow-root; background: #000; color: var(--paper); padding-bottom: var(--space-5); }
.webring-zone .course-webring { max-width: var(--measure); margin-inline: auto; }
.webring-zone .course-webring h2 { letter-spacing: 0; text-wrap: wrap; }
.webring-zone .course-webring__nav a:hover { color: var(--muted-on-ink); }

/* 7. Адаптивность и доступность ----------------------------- */
@media (min-width: 1600px) {
  .hero-title { font-size: 340px; }
}
@media (max-height: 500px) {
  .sound-lab { --sound-deck-height: 220px; }
  .sound-step { padding-top: 12px; padding-bottom: calc(var(--sound-deck-height) + 12px); }
  .sound-instrument { padding-block: var(--space-1); gap: 6px; }
  .piano { height: 52px; }
  .piano-stage { padding: 4px 4px 6px; }
  .spectrum-stage { padding-inline: 4px; }
  .piano-hint { display: none; }
  .listening-actions { height: 44px; }
  .button { min-height: 44px; padding-block: 10px; }
  .spectrum-stage { gap: 2px; }
}
@media (max-width: 800px) {
  .section-pad { padding-block: var(--space-5); }
}
@media (max-width: 600px) {
  .stranger { --tw: 64vw; --tr: 0px; --fig: 44px; }
  .circle-link { width: 44px; height: 44px; font-size: 22px; }
  .attention-stage { gap: var(--space-4); }
  .story-copy .body-copy { margin-top: var(--space-2); }
  .story-bridge { margin-top: var(--space-3); }
  .js-enabled .story-copy { bottom: var(--space-4); }
  .listening-actions { gap: var(--space-2); }
  .button { padding-inline: 16px; }
  .piano { height: clamp(84px, 14svh, 120px); }
  .piano-key[data-label]::after { display: none; }
  .source-list>a { gap: 8px; grid-template-columns: 22px 1fr 16px; }
}
@media (max-height: 700px) and (max-width: 600px) {
}
@media (prefers-reduced-motion: reduce) {
  .js-enabled .sound-lab { height: auto; overflow: visible; }
  html { scroll-behavior: auto; }
  *, *:before, *:after { transition: none !important; animation: none !important; }
  .js-enabled .scroll-scene { height: auto; }
  .scene-sticky { position: relative; }
  .js-enabled .scene>.scene-heading, .js-enabled .scene>.sound-lab,
  .js-enabled .conclusion>h2, .js-enabled .hero-title { opacity: 1; transform: none; visibility: visible; }
  .js-enabled .attention-stage { position: relative; height: auto; padding: var(--space-5) var(--gutter); }
  .js-enabled .story-canvas { display: none; }
  .js-enabled .story-frames { position: static; width: 100%; height: auto; margin: 0 auto; overflow: visible; clip: auto; }
  .js-enabled .story-copy { position: static; width: 100%; pointer-events: auto; }
  .js-enabled .story-copy>* { opacity: 1; }
}
@media (max-height: 600px) {
  .js-enabled .sound-lab { height: auto; overflow: visible; }
  .js-enabled .attention-scene { height: auto; }
  .js-enabled .attention-stage { position: relative; height: auto; padding: var(--space-4) var(--gutter); }
  .js-enabled .story-canvas { display: none; }
  .js-enabled .story-frames { position: static; width: 100%; height: auto; margin: 0 auto; overflow: visible; clip: auto; }
  .js-enabled .story-copy { position: static; width: 100%; pointer-events: auto; }
  .js-enabled .story-copy>* { opacity: 1; }
}

/* Рисованный тритон и распадающаяся клавиатура */
.piano-stage { position: relative; isolation: isolate; }
.sound-section { overflow: clip; }
.listening-actions { height: auto; min-height: 52px; flex-wrap: wrap; }
.triton-sprite { position: absolute; left: 53%; top: 12px; width: clamp(280px, 42vw, 500px); aspect-ratio: 1; z-index: 3; pointer-events: none; }
.triton-sprite img { position: absolute; left: 0; top: 0; height: auto; max-width: none; }
.piano-case { display: none; position: absolute; top: -8px; height: calc(100% + 22px); background: #10120e; border-top: 3px solid #646958; z-index: 0; }
.piano-case-left { left: -4px; width: 48%; clip-path: polygon(0 0, 100% 0, 88% 22%, 99% 43%, 81% 57%, 93% 76%, 85% 100%, 0 100%); transform: translate(-6px, calc(10px + var(--wreck-drop, 0px))) rotate(calc(-5deg - var(--wreck-spin, 0deg))); transform-origin: left center; }
.piano-case-right { right: -4px; width: 46%; clip-path: polygon(9% 0, 100% 0, 100% 100%, 0 100%, 12% 78%, 1% 59%, 19% 40%, 3% 20%); transform: translate(7px, calc(17px + var(--wreck-drop, 0px))) rotate(calc(7deg + var(--wreck-spin, 0deg))); transform-origin: right center; }
.piano-strings { display: none; position: absolute; left: 34%; top: 6px; width: 37%; height: 90%; background: repeating-linear-gradient(94deg, transparent 0 15px, #a09b75 16px 17px, transparent 18px 24px); transform: translateY(var(--wreck-drop, 0px)) skewY(8deg); opacity: .6; }
.piano-wreckage { position: absolute; inset: 0; z-index: 4; pointer-events: none; visibility: hidden; }
.piano-wreckage i { position: absolute; left: 49%; top: 30%; width: 6%; height: 55%; background: #575f49; clip-path: polygon(0 0, 100% 9%, 75% 40%, 100% 100%, 40% 87%, 20% 45%); transform: translate(0, 0) rotate(0); }
.piano-wreckage i:nth-child(1) { --shard-x: -170px; --shard-y: -56px; --shard-angle: -62deg; }
.piano-wreckage i:nth-child(2) { --shard-x: 140px; --shard-y: -24px; --shard-angle: 78deg; width: 3%; background: #b7b9aa; }
.piano-wreckage i:nth-child(3) { --shard-x: -100px; --shard-y: 74px; --shard-angle: -31deg; width: 9%; background: #0b0d09; }
.piano-wreckage i:nth-child(4) { --shard-x: 76px; --shard-y: 85px; --shard-angle: 40deg; width: 11%; background: #30362a; }
.piano-wreckage i:nth-child(5) { --shard-x: -45px; --shard-y: 40px; --shard-angle: 18deg; width: 4%; background: #d3d3c7; }
.piano-wreckage i:nth-child(6) { --shard-x: 185px; --shard-y: 58px; --shard-angle: 112deg; width: 3%; }
.piano-stage[data-broken="true"] { background: transparent; }
.piano-stage[data-broken="true"] .piano-case, .piano-stage[data-broken="true"] .piano-strings { display: block; }
.piano-stage[data-broken="true"] .piano-key { transform: translate(var(--break-x), calc(var(--break-y) + var(--wreck-drop, 0px))) rotate(calc(var(--break-angle) + var(--wreck-spin, 0deg))); transition: none; }
.piano-stage[data-broken="true"] .piano-wreckage { visibility: visible; }
.piano-stage[data-broken="true"] .piano-wreckage i { transform: translate(var(--shard-x), calc(var(--shard-y) + var(--wreck-drop, 0px))) rotate(calc(var(--shard-angle) + var(--wreck-spin, 0deg))); }
.piano-stage[data-gone="true"] { visibility: hidden; }
.sound-lab:is([data-broken="true"], [data-finale="done"]) :is(#spectrum-canvas, #spectrum-caption) { visibility: hidden; }
/* Тритон падает поверх танцоров, а они проваливаются за обломки клавиатуры. */
.sound-lab[data-finale="playing"] .piano-stage { z-index: 5; }
.sound-lab[data-finale="playing"] .listening-actions { position: relative; z-index: 6; }
.sound-lab[data-finale="done"] .listening-actions { display: none; }
.sound-lab:is([data-finale="playing"], [data-finale="done"]) #sound-final-step .sound-copy { opacity: 0; }
@media (max-width: 600px) {
  .triton-sprite { left: 50%; width: min(82vw, 340px); }
  .piano-wreckage i:nth-child(1) { --shard-x: -95px; }
  .piano-wreckage i:nth-child(2) { --shard-x: 85px; }
  .piano-wreckage i:nth-child(6) { --shard-x: 105px; }
}
@media (max-height: 500px) {
  .triton-sprite { width: min(240px, 60svh); }
}

.sound-lab:is([data-finale="playing"], [data-finale="done"]) .piano-hint { visibility: hidden; }
.webring-zone .webring-why { max-width: 34em; margin: 4px 0 0 auto; color: var(--muted-on-ink); text-align: right; text-wrap: pretty; }
@media (max-width: 720px) { .webring-zone .webring-why { margin-left: 0; text-align: left; } }
