/* "Night to dawn" — a draft of the home page as one night.

   Scrolling moves the clock from bedtime to seven in the morning: the sky and
   the dunes go from the app's night images to its day images, the canvas adds
   stars and then the sun, and at seven the song rings. The colours are the
   app's "First light" palette; the sky, dunes and mascot are its baked images.

   House rule as everywhere: nothing clipped, nothing scrolling sideways, at
   320, 375, 768 and 1280. */

/* One variable file for every weight: inter-600 and inter-800 are copies of
   it under other names, and fetching all three cost two requests and 94 KB. */
@font-face { font-family: Inter; font-weight: 400; font-display: swap; src: url(/font/inter-400.woff2) format('woff2'); }
@font-face { font-family: Inter; font-weight: 600; font-display: swap; src: url(/font/inter-400.woff2) format('woff2'); }
@font-face { font-family: Inter; font-weight: 800; font-display: swap; src: url(/font/inter-400.woff2) format('woff2'); }
/* Russian letters: Inter's Cyrillic part from Google Fonts, one variable file
   for every weight. The browser fetches it only when a page has Cyrillic.
   Each weight gets its own rule, the way the Latin ones do: a single
   "400 800" rule is not joined to them, and Chrome never fetched it. */
@font-face { font-family: Inter; font-weight: 400; font-display: swap; src: url(/font/inter-cyrillic.woff2) format('woff2'); unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; }
@font-face { font-family: Inter; font-weight: 600; font-display: swap; src: url(/font/inter-cyrillic.woff2) format('woff2'); unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; }
@font-face { font-family: Inter; font-weight: 800; font-display: swap; src: url(/font/inter-cyrillic.woff2) format('woff2'); unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; }
/* Polish, Turkish and other Latin letters past the basic set (ą ę ł ż,
   ğ ş İ) and the signs ₫ ₹ ₩; then Vietnamese (ă đ ơ ư and its tones).
   Inter's own parts from Google Fonts (v20), fetched only when a page has
   such letters, the same way as Cyrillic (Igor 25.10, break-ui). */
@font-face { font-family: Inter; font-weight: 400; font-display: swap; src: url(/font/inter-latin-ext.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: Inter; font-weight: 600; font-display: swap; src: url(/font/inter-latin-ext.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: Inter; font-weight: 800; font-display: swap; src: url(/font/inter-latin-ext.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: Inter; font-weight: 400; font-display: swap; src: url(/font/inter-vietnamese.woff2) format('woff2'); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; }
@font-face { font-family: Inter; font-weight: 600; font-display: swap; src: url(/font/inter-vietnamese.woff2) format('woff2'); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; }
@font-face { font-family: Inter; font-weight: 800; font-display: swap; src: url(/font/inter-vietnamese.woff2) format('woff2'); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; }

:root {
  /* One unit for every size on the page: a pixel up to a laptop's width (1440),
     and above it the page grows with the screen, so a 2K or 4K monitor shows
     the same composition as a 13-inch laptop, not the same pixels lost in the
     middle of a big screen (Igor 26.10). Sizes in this file are written as
     calc(N * var(--u)); media queries stay in pixels.
     It grows exactly with the screen (Igor 26.10: the 0.87 of a rem+vw mix still
     read small); browser zoom on a big screen enlarges text from 300 per cent
     on, as it did with the mix. Ceiling 2.5 times. */
  --u: clamp(1px, 100vw / 1440, 2.5px);
  --night: #1A100A;
  --day: #F7E5D0;
  --n-text: #F6E7D6;
  --n-dim: #C0A48C;
  --n-card: rgba(26, 16, 10, 0.66);
  --n-line: rgba(255, 160, 97, 0.22);
  --d-text: #2E1C12;
  --d-dim: #6A4936;
  --d-card: rgba(255, 251, 245, 0.8);
  --d-line: rgba(122, 82, 56, 0.2);
  --accent: #E2561C;
  --accent-n: #FF6A26;
  --accent-soft: #FF9052;
  --on-accent: #FFF4E8;
  /* The orange that small text and filled buttons can carry: #FFF4E8 on it is
     5.2:1, and on the day panels it reads at 4.6:1 or better. --accent stays
     for large type, corners and bars. */
  --accent-strong: #B5400E;
  --accent-strong-hover: #A93B0E;
  /* The loading and progress bars run from dark earth to the soft orange and on to the first light. */
  --bar-from: #5E432D;
  --bar-to: #FFE2B8;
  --switch-off: #4a3426; /* the alarm switch before it flips */
  --fs-xs: calc(13 * var(--u)); /* the smallest text: 13, then 15, 17, 20 (Taste review 25.10: there were 12 sizes) */
  --fs-sm: calc(13 * var(--u));
  --fs-md: calc(15 * var(--u));
  /* Once a monospace for the clock and the times; now the brand face with
     even-width digits, so the page has one typeface (Taste review 25.10). */
  --mono: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --ease: cubic-bezier(.2, .7, .1, 1);

  /* The heads-up text switches with the sky, not with the section under it. */
  --hud: var(--n-text);
  --hud-dim: var(--n-dim);
  --hud-accent: var(--accent-soft);
  --hud-veil: rgba(20, 12, 7, .82);
  --hud-pill: rgba(26, 16, 10, .72);
  --hud-sheet: rgba(20, 12, 7, .95);
}
:root[data-tone="day"] {
  --hud: var(--d-text);
  --hud-dim: var(--d-dim);
  --hud-accent: var(--accent-strong);
  --hud-veil: rgba(247, 229, 208, .9);
  --hud-pill: rgba(255, 251, 245, .78);
  --hud-sheet: rgba(250, 238, 222, .97);
}
/* Dawn on the heads-up line: the grounds under it (the veil, the pills, the
   sheets) slide from night to day with the scroll, by --ground (0 to 1, set
   by the script); the words switch from light to dark in one short fade at
   6:51, with data-tone. Words that slid along with their ground met it half
   way and all but vanished for a screen of scrolling (1.1:1 at 6:50, review
   24.10). The ground passes its middle quickly, so the mid-tones where no
   colour of words reads well last as little scroll as possible. */
@supports (color: color-mix(in oklab, red 50%, blue)) {
  .hud-top, .chapters, .hud-bottom, .dock, .alarm-banner {
    --hud-veil: color-mix(in oklab, rgba(247, 229, 208, .9) calc(var(--ground, 0) * 100%), rgba(20, 12, 7, .82));
    --hud-pill: color-mix(in oklab, rgba(255, 251, 245, .78) calc(var(--ground, 0) * 100%), rgba(26, 16, 10, .72));
    --hud-sheet: color-mix(in oklab, rgba(250, 238, 222, .97) calc(var(--ground, 0) * 100%), rgba(20, 12, 7, .95));
  }
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
html.locked { overflow: hidden; }
body {
  margin: 0;
  background: var(--night);
  color: var(--n-text);
  font: 400 calc(17 * var(--u))/1.6 Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  overflow-wrap: anywhere;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}
/* Korean breaks lines between words, not inside them, so «되나요?» stays whole;
   a word too long for its line still breaks (overflow-wrap above). */
html[lang="ko"] body { word-break: keep-all; }
a { color: inherit; }
img { max-width: 100%; }
::selection { background: var(--accent-soft); color: var(--night); }

/* ---------- The scene ---------- */

.stage { position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
/* The sky drifts up slowly as the night goes (7% of the screen by the end)
   and leans with the mouse (8 px), so it is cut larger than the screen on
   every side: its edge never shows. */
.sky {
  position: absolute;
  inset: -4% calc(-12 * var(--u)) -10%;
  background: center top / cover no-repeat;
  will-change: transform, opacity;
}
.sky-n { background-image: url(/img/sky-night.webp); }
.sky-d { background-image: url(/img/sky-day.webp); opacity: 0; }
/* Big or dense screens get the sky baked larger (the app's tools/bake_sky_web.py),
   not the 1600 one stretched: the width it needs is the screen's width times its
   pixel ratio, so 2560 from 1600 real pixels and 3840 from 2560 (a 4K screen at
   150 per cent, a MacBook, a 5K Mac). Phones keep the light one. */
@media (min-width: 1601px), (min-resolution: 1.25dppx) and (min-width: 1281px), (min-resolution: 1.5dppx) and (min-width: 1068px), (min-resolution: 2dppx) and (min-width: 801px), (min-resolution: 3dppx) and (min-width: 534px) {
  .sky-n { background-image: url(/img/sky-night-2560.webp); }
  .sky-d { background-image: url(/img/sky-day-2560.webp); }
}
@media (min-width: 2561px), (min-resolution: 1.25dppx) and (min-width: 2049px), (min-resolution: 1.5dppx) and (min-width: 1708px), (min-resolution: 2dppx) and (min-width: 1281px), (min-resolution: 3dppx) and (min-width: 854px) {
  .sky-n { background-image: url(/img/sky-night-3840.webp); }
  .sky-d { background-image: url(/img/sky-day-3840.webp); }
}
.tint {
  position: absolute;
  inset: 0;
  opacity: 0;
  will-change: opacity;
  background:
    radial-gradient(120% 70% at 50% 100%, rgba(255, 144, 82, 0.75), rgba(226, 86, 28, 0.25) 45%, transparent 75%);
}
#fx { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* The dunes are wider than a phone and sit low, mostly out of frame. */
.dunes {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: max(110vw, calc(760 * var(--u)));
  aspect-ratio: 1600 / 894;
  transform: translate(-50%, 46%);
}
.dunes img { position: absolute; inset: 0; width: 100%; height: 100%; }
.dunes .dd { opacity: 0; will-change: opacity; }

/* The mascot sits in the gap between the two dunes, which is right of centre. */
:root { --sun: clamp(calc(92 * var(--u)), 13vw, calc(168 * var(--u))); --sun-low: max(3vh, calc(18 * var(--u))); } /* the sun's size and height off the bottom */
/* At the very end the footer comes down over the sun's place: the sun steps
   out (fades) instead of showing through it as a pale ghost, and the footer
   keeps only a small margin under it. */
.footer-in .mascot { opacity: 0; }
.mascot {
  position: absolute;
  left: calc(50% + 0.15 * max(110vw, calc(760 * var(--u))));
  bottom: var(--sun-low);
  width: var(--sun);
  transition: opacity .5s;
  transform: translateX(-50%);
}
/* The mascot keeps the app's moods, chapter by chapter: listening (eyes
   down or up) with notes drifting out, writing with a pencil running along
   its sheet, asleep — headphones off, sunk and tipped over, z's rising —
   and singing while the song plays. Frames, pencil, notes and z's are the
   app's own pictures (ios/Sky), placed by the app's map (ios/SkyMap.swift)
   in the sun's own square: cqw here is a hundredth of the mascot's width.
   On the site it breathes by growing: 6% over a four-second breath while
   awake, slower in its sleep (Igor's call, 24.10). */
.mascot { container-type: inline-size; --zs: 2.5; --ns: 1.8; }
.m-body { position: relative; transform-origin: 50% 80%; animation: breathe 4s ease-in-out infinite alternate; --by: -2.84cqw; translate: 0 0; rotate: 0deg; transition: translate 1.2s cubic-bezier(.45, 0, .25, 1), rotate 1.2s cubic-bezier(.45, 0, .25, 1); }
/* A new frame comes in at once and the old one leaves a moment later, so the
   sun is never half see-through between moods. */
.m-body .m { display: block; width: 100%; height: auto; transition: opacity .5s ease .35s; }
.m-body .m:not(.m-idle-down) { position: absolute; left: 0; top: 0; opacity: 0; }
.mascot:not([data-mood="idle-down"]) .m-idle-down { opacity: 0; }
.mascot[data-mood="idle-down"] .m-idle-down,
.mascot[data-mood="idle-up"] .m-idle-up,
.mascot[data-mood="writing"] .m-writing,
.mascot[data-mood="sleeping"] .m-sleeping,
.mascot[data-mood="playing"] .m-playing { opacity: 1; transition: opacity .5s ease; }
/* Asleep it sinks and tips over — gliding there over a second — and breathes slower. */
.m-sway { position: relative; transform-origin: 50% 80%; }
/* Asleep the breath sinks instead of rising; the script slows it to 6.5 s.
   Neither restarts it, so the sun never jumps between moods. */
.mascot[data-mood="sleeping"] .m-body { translate: -2.84cqw 14.2cqw; rotate: -13deg; --by: 1.9cqw; }
.mascot[data-mood="playing"] .m-body { animation-play-state: paused; }
.mascot[data-mood="playing"] .m-sway { animation: sway-play 2.2s ease-in-out infinite; }
.mascot.hop .m-sway { animation: hop .75s var(--ease); }
@keyframes breathe { from { transform: none; } to { transform: translateY(var(--by)) scale(1.06); } }
@keyframes sway-play { 0%, 100% { transform: none; } 25% { transform: rotate(-3deg); } 75% { transform: translateY(-5.2cqw) rotate(3deg); } }
@keyframes hop {
  0% { transform: none; }
  30% { transform: translateY(-26%) scale(.95, 1.07); }
  55% { transform: none; }
  62% { transform: scale(1.08, .92); }
  80% { transform: translateY(-5%); }
  100% { transform: none; }
}

/* Writing: the pencil leads a line along the sheet and snaps back to the margin. */
.pen { position: absolute; left: 74.93cqw; top: 55.05cqw; width: 13.25cqw; height: auto; opacity: 0; transition: opacity .5s; }
.mascot[data-mood="writing"] .pen { opacity: 1; animation: pen 1.23s infinite; }
@keyframes pen {
  0% { transform: none; animation-timing-function: ease-in-out; }
  85% { transform: translate(4.26cqw, 1.18cqw); animation-timing-function: ease-out; }
  100% { transform: none; }
}

/* Asleep: three z's rise out of the sun, each on its own beat, and tip
   over with it. A light edge keeps the orange letters off the orange sky. */
.zzs { position: absolute; inset: 0; pointer-events: none; }
.z { position: absolute; height: auto; opacity: 0; filter: drop-shadow(0 0 calc(1.2 * var(--u)) rgba(255, 244, 232, .95)) drop-shadow(0 calc(1 * var(--u)) calc(2 * var(--u)) rgba(26, 16, 10, .55)); }
.z1 { left: 78.71cqw; top: 27.13cqw; width: calc(3.47cqw * var(--zs)); }
.z2 { left: 85.34cqw; top: 17.51cqw; width: calc(4.58cqw * var(--zs)); animation-delay: .5s; }
.z3 { left: 94.01cqw; top: 5.84cqw; width: calc(5.52cqw * var(--zs)); animation-delay: 1s; }
.mascot[data-mood="sleeping"] .z { animation-name: zzfly; animation-duration: 4s; animation-timing-function: linear; animation-iteration-count: infinite; }
@keyframes zzfly { 0% { opacity: 0; transform: none; } 15% { opacity: .85; } 100% { opacity: 0; transform: translate(6.6cqw, -16.1cqw); } }

/* Singing: the app's singing frame with its painted mouth taken out, and a
   mouth of our own in the same colours that whistles — a small round "o"
   between pursed lips that narrows and stretches like a changing note, and
   opens a little more when the song is loud (--lv, set by the script). Placed
   by the painted mouth: 42 x 50 at (316.5, 391.5) in the app's 634 px frame. */
.mouth {
  position: absolute; left: 49.92cqw; top: 61.75cqw;
  width: 6.62cqw; height: 7.89cqw; margin: -3.95cqw 0 0 -3.31cqw;
  border-radius: 50%; background: #703008; overflow: hidden; opacity: 0;
  box-shadow: 0 0 0 .75cqw rgba(196, 70, 10, .5);
  scale: calc(.62 + var(--lv, 0) * .45) calc(.66 + var(--lv, 0) * .4);
  transition: opacity .5s;
}
.mouth i { position: absolute; left: 24%; bottom: 4%; width: 52%; height: 44%; border-radius: 50%; background: #C2351B; }
.mascot[data-mood="playing"] .mouth { opacity: 1; animation: whistle .46s ease-in-out infinite alternate; }
@keyframes whistle { from { transform: scale(1.08, .9); } to { transform: scale(.86, 1.1) translateY(-4%); } }

/* Listening and singing: notes drift up beside the sun (not on it, so they
   do not sway with it) — slowly while it listens, three times as often
   while the song plays. */
.notes { position: absolute; inset: 0; pointer-events: none; }
.mnote { position: absolute; height: auto; opacity: 0; filter: drop-shadow(0 0 calc(1.2 * var(--u)) rgba(255, 244, 232, .95)) drop-shadow(0 calc(1 * var(--u)) calc(2 * var(--u)) rgba(26, 16, 10, .55)); }
.n1 { left: 8.07cqw; top: 49.27cqw; width: calc(7.11cqw * var(--ns)); --d: 5.2s; --w: 0s; }
.n2 { left: 83.95cqw; top: 23.78cqw; width: calc(8.97cqw * var(--ns)); --d: 6.1s; --w: .35s; }
.n3 { left: 92.18cqw; top: 53.02cqw; width: calc(5.87cqw * var(--ns)); --d: 5.6s; --w: .8s; }
.n4 { left: 18.28cqw; top: 20.82cqw; width: calc(4.94cqw * var(--ns)); --d: 6.8s; --w: 1.3s; }
.mascot[data-mood="playing"] .n1 { --d: 2.1s; }
.mascot[data-mood="playing"] .n2 { --d: 2.5s; }
.mascot[data-mood="playing"] .n3 { --d: 2.3s; }
.mascot[data-mood="playing"] .n4 { --d: 2.8s; }
.mascot[data-mood^="idle"] .mnote, .mascot[data-mood="playing"] .mnote { animation: notefly var(--d) ease-out var(--w) infinite; }
@keyframes notefly { 0% { opacity: 0; transform: rotate(-7deg); } 15% { opacity: .9; } 100% { opacity: 0; transform: translateY(-27.4cqw) rotate(11deg); } }

/* ---------- Heads-up display ---------- */

.hud { position: fixed; z-index: 5; color: var(--hud); font: 400 var(--fs-xs)/1.4 var(--mono); letter-spacing: .04em; transition: color .6s; }
.hud a { text-decoration: none; }

.hud-top {
  top: 0; left: 0; right: 0;
  display: flex; align-items: flex-start; justify-content: space-between; gap: calc(16 * var(--u));
  padding: max(calc(16 * var(--u)), env(safe-area-inset-top)) max(calc(16 * var(--u)), env(safe-area-inset-right)) 0 max(calc(16 * var(--u)), env(safe-area-inset-left));
  pointer-events: none;
}
.hud-top > * { pointer-events: auto; }
/* A veil under the top line, so text scrolling up does not run into it. */
.hud-top::before {
  content: "";
  position: absolute;
  inset: 0 0 calc(-34 * var(--u));
  z-index: -1;
  background: linear-gradient(var(--hud-veil), var(--hud-veil) 55%, transparent);
  pointer-events: none;
}
.brandrow { display: inline-flex; align-items: center; gap: calc(9 * var(--u)); font: 800 calc(17 * var(--u))/1 Inter, sans-serif; letter-spacing: -.01em; }
.hud-tag { margin: calc(6 * var(--u)) 0 0; color: var(--hud-dim); flex: 1; }
/* The clock: a size up on the rest of the heads-up line (Igor, 24.10: +10%). */
.clock { display: grid; justify-items: end; gap: calc(2 * var(--u)); font-size: calc(14.3 * var(--u)); transform-origin: 70% 60%; }
.clock-day { color: var(--hud-dim); text-transform: uppercase; }
.clock-t b { font: 600 clamp(calc(28.6 * var(--u)), 3.74vw, calc(44 * var(--u)))/1 var(--mono); letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.clock-t i { font-style: normal; margin-left: calc(6 * var(--u)); color: var(--hud-dim); }
.clock.ring .clock-t b { color: var(--hud-accent); }
.clock-t i:empty { display: none; } /* a 24-hour clock has no AM or PM */

/* The language: a small pill beside the clock that opens a list of languages,
   each written in its own language. The one in use carries the same short
   accent dash as the chapter in the side menu. */
.lang { position: relative; margin-left: auto; }
.brandrow, .lang, .clock { flex: none; white-space: nowrap; }
/* The narrowest phones: the brand, the language and an English clock with
   its PM only just fit side by side, so the globe goes and the gaps tighten. */
@media (max-width: 359px) { .hud-top { gap: calc(10 * var(--u)); } .lang-btn svg { display: none; } .lang-btn { padding-inline: calc(10 * var(--u)); } }
.no-js .lang { display: none; }
.lang-btn {
  position: relative;
  display: inline-flex; align-items: center; gap: calc(6 * var(--u));
  margin: 0; padding: calc(6 * var(--u)) calc(11 * var(--u)) calc(6 * var(--u)) calc(9 * var(--u));
  font: inherit; letter-spacing: .03em; color: inherit;
  background: var(--hud-pill); border: 0; border-radius: calc(999 * var(--u)); cursor: pointer;
  transition: transform 140ms cubic-bezier(.23, 1, .32, 1);
}
.lang-btn::after { content: ""; position: absolute; inset: calc(-8 * var(--u)) calc(-4 * var(--u)); } /* a 44 px tap */
/* A thin edge, so at night it reads as a button and not as a stray "EN". */
.lang-btn { box-shadow: inset 0 0 0 calc(1 * var(--u)) color-mix(in srgb, currentColor 28%, transparent); }
.lang-btn svg { width: calc(15 * var(--u)); height: calc(15 * var(--u)); fill: none; stroke: currentColor; stroke-width: 1.5; }
.lang-list {
  position: absolute; top: calc(100% + calc(10 * var(--u))); inset-inline-end: 0; z-index: 1;
  min-width: calc(172 * var(--u)); max-height: min(64vh, calc(540 * var(--u))); overflow: auto;
  margin: 0; padding: calc(6 * var(--u)); list-style: none;
  background: var(--hud-sheet); border-radius: calc(16 * var(--u));
  box-shadow: 0 calc(12 * var(--u)) calc(32 * var(--u)) rgba(10, 6, 3, .28);
}
.lang-list button {
  display: flex; align-items: center; justify-content: space-between; gap: calc(14 * var(--u));
  width: 100%; min-height: calc(40 * var(--u)); margin: 0; padding: 0 calc(12 * var(--u));
  font: inherit; font-size: calc(15 * var(--u)); letter-spacing: 0; color: var(--hud-dim); text-align: left;
  background: none; border: 0; border-radius: calc(10 * var(--u)); cursor: pointer;
  transition: color .15s, background .15s;
}
@media (hover: hover) and (pointer: fine) { .lang-list button:hover { color: var(--hud); background: var(--hud-pill); } }
@media (pointer: coarse) { .lang-list button { min-height: calc(44 * var(--u)); } }
.lang-list button[aria-current] { color: var(--hud); }
.lang-list button[aria-current]::after { content: ""; flex: none; width: calc(14 * var(--u)); height: calc(1.5 * var(--u)); background: var(--hud-accent); }
/* Until the page's words are in its language, nothing with words is shown. */
.lang-wait .intro, .lang-wait main, .lang-wait .hud { visibility: hidden; }
/* Seven o'clock: it buzzes side to side like a phone ringing on a table, in
   three bursts (the script switches .buzz on and off). */
.clock.buzz { animation: buzz .07s linear infinite; }
@keyframes buzz { 25% { transform: translateX(calc(-4 * var(--u))) rotate(-5deg); } 75% { transform: translateX(calc(4 * var(--u))) rotate(5deg); } }

.chapters {
  right: max(calc(16 * var(--u)), env(safe-area-inset-right));
  top: 50%;
  transform: translateY(-50%);
  display: grid;
  gap: calc(8 * var(--u));
  justify-items: end;
  padding: calc(10 * var(--u)) calc(12 * var(--u));
  /* The sky under the menu goes from dark brown to cream; the menu brings its own ground. */
  background: var(--hud-pill);
  transition: color .6s;
}
.chapters a { display: flex; gap: calc(10 * var(--u)); padding: calc(3 * var(--u)) 0; color: var(--hud-dim); transition: color .15s, translate .15s ease-out; }
.chapters a:focus-visible { color: var(--hud); }
@media (hover: hover) and (pointer: fine) { .chapters a:hover { color: var(--hud); translate: calc(-4 * var(--u)) 0; } }
@media (pointer: coarse) { .chapters { gap: 0; } .chapters a { padding: calc(11 * var(--u)) 0; } }
.chapters a.on { color: var(--hud); }
.chapters a.on::after { content: ""; width: calc(14 * var(--u)); height: calc(1.5 * var(--u)); margin-top: .65em; background: var(--hud-accent); }

.hud-bottom {
  left: 0; right: 0; bottom: 0;
  display: flex; align-items: center; justify-content: space-between; gap: calc(12 * var(--u));
  padding: 0 max(calc(16 * var(--u)), env(safe-area-inset-right)) max(calc(14 * var(--u)), env(safe-area-inset-bottom)) max(calc(16 * var(--u)), env(safe-area-inset-left));
  pointer-events: none;
}
.hud-bottom > * { pointer-events: auto; background: var(--hud-pill); padding: calc(6 * var(--u)) calc(10 * var(--u)); transition: transform 140ms cubic-bezier(.23, 1, .32, 1); }
.sound {
  position: relative;
  flex: none;
  white-space: nowrap;
  display: inline-flex; align-items: center; gap: calc(9 * var(--u));
  margin: 0;
  font: inherit; letter-spacing: inherit; color: inherit;
  border: 0; cursor: pointer;
}
/* The pill stays small; the area that takes a tap is 44 px tall. */
.sound::after { content: ""; position: absolute; inset: calc(-8 * var(--u)) calc(-4 * var(--u)); }
.eq { display: inline-flex; align-items: flex-end; gap: calc(2 * var(--u)); height: calc(12 * var(--u)); }
.eq i { width: calc(2 * var(--u)); height: calc(12 * var(--u)); background: currentColor; transform-origin: 50% 100%; transform: scaleY(.25); }
.sound[aria-pressed="true"] .eq i { animation: eq .9s ease-in-out infinite alternate; }
.sound[aria-pressed="true"] .eq i:nth-child(2) { animation-delay: -.3s; }
.sound[aria-pressed="true"] .eq i:nth-child(3) { animation-delay: -.6s; }
.sound[aria-pressed="true"] .eq i:nth-child(4) { animation-delay: -.15s; }
@keyframes eq { from { transform: scaleY(.25); } to { transform: none; } }
.where { position: relative; margin: 0; font: inherit; letter-spacing: inherit; color: var(--hud-dim); text-align: end; text-wrap: balance; border: 0; }
.where::before { content: ""; position: absolute; inset: calc(-8 * var(--u)) calc(-4 * var(--u)); } /* a 44 px tap, like Sound */
/* With the side menu showing the chapter, the label at the bottom right would
   repeat it: there it only says "Scroll to wake up" before the first scroll. */
@media (min-width: 1000px) { .where { pointer-events: none; } .scrolled .where { display: none; } }

.progress { position: fixed; z-index: 5; left: 0; right: 0; bottom: env(safe-area-inset-bottom, calc(0 * var(--u))); height: calc(2 * var(--u)); background: rgba(255, 255, 255, .08); }
.progress i { display: block; height: 100%; width: 100%; transform-origin: 0 50%; transform: scaleX(0); background: linear-gradient(90deg, var(--bar-from), var(--accent-soft) 70%, var(--bar-to)); }

@media (max-width: 999px) {
  .chapters { display: none; }
  /* Below the side menu's width the chapter label at the bottom opens the
     same menu as a sheet, within reach of the thumb. */
  .where { cursor: pointer; display: inline-flex; align-items: center; gap: calc(8 * var(--u)); }
  /* Here the label opens the chapters (its chevron says so); "↓" would say scroll. */
  .where-down { display: none; }
  .where::after { content: ""; width: calc(6 * var(--u)); height: calc(6 * var(--u)); border-right: calc(1.5 * var(--u)) solid currentColor; border-top: calc(1.5 * var(--u)) solid currentColor; transform: translateY(calc(2 * var(--u))) rotate(-45deg); flex: none; }
  .sheet-open .chapters {
    display: grid; gap: 0;
    top: auto; bottom: calc(calc(64 * var(--u)) + env(safe-area-inset-bottom)); transform: none;
    /* A phone on its side (or a page zoomed in) is shorter than the eight
       chapters: the sheet stops below the top line and scrolls inside. */
    max-height: calc(100vh - calc(152 * var(--u)) - env(safe-area-inset-top) - env(safe-area-inset-bottom));
    max-height: calc(100svh - calc(152 * var(--u)) - env(safe-area-inset-top) - env(safe-area-inset-bottom));
    overflow-y: auto; overscroll-behavior: contain;
    min-width: calc(210 * var(--u)); padding: calc(8 * var(--u)) calc(16 * var(--u));
    background: var(--hud-sheet);
    transform-origin: bottom right;
    transition: color .6s, opacity 180ms ease-out, transform 200ms cubic-bezier(.23, 1, .32, 1);
  }
  @starting-style { .sheet-open .chapters { opacity: 0; transform: translateY(calc(8 * var(--u))) scale(.97); } }
  .sheet-open .chapters a { min-height: calc(44 * var(--u)); align-items: center; justify-content: flex-end; padding: 0; }
  .sheet-open .where::after { transform: translateY(calc(-2 * var(--u))) rotate(135deg); }
}
@media (max-width: 700px) { .hud-tag { display: none; } }

/* ---------- Chapters ---------- */

main { position: relative; z-index: 1; }
.ch {
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  align-content: center;
  padding: calc(120 * var(--u)) max(calc(16 * var(--u)), 8vw) 26vh;
}
.ch:first-child { padding-top: calc(110 * var(--u)); }
#plans, #faq, #start { min-height: 0; padding-bottom: calc(80 * var(--u)); justify-items: start; } /* the night's left edge, kept all morning */
/* 11:04 holds still for a screen: the chapter is two screens tall and its
   panel, in a holder that sticks to the top, stays in the middle of the
   screen while the visitor scrolls through the second one. The alarm switch
   flips during the hold, so it cannot be scrolled past by accident. */
#set { display: block; align-content: start; height: 200vh; height: 200svh; min-height: 0; padding-top: 0; padding-bottom: 0; }
#set .hold { position: sticky; top: 0; height: 100vh; height: 100svh; display: grid; align-content: safe center; padding: calc(120 * var(--u)) 0 26vh; }
/* Where the chapter menu shows, the content stays out of its column. */
@media (min-width: 1000px) { .ch { padding-right: max(8vw, calc(190 * var(--u))); } }
#start { padding-bottom: 0; }

.panel {
  --c: var(--accent-soft);
  position: relative;
  width: min(calc(560 * var(--u)), 100%);
  padding: calc(26 * var(--u)) calc(26 * var(--u)) calc(28 * var(--u));
  background: var(--n-card);
  border: calc(1 * var(--u)) solid var(--n-line);
}
.panel.wide { width: min(calc(980 * var(--u)), 100%); }
.tone-day .panel { --c: var(--accent); background: var(--d-card); border-color: var(--d-line); color: var(--d-text); }

/* The reveal: the panel rises into place as it fades in. */
.js .panel { opacity: 0; transform: translateY(calc(22 * var(--u))); transition: opacity .9s var(--ease), transform 1.1s var(--ease); }
.js .panel.in { opacity: 1; transform: none; }
.js .panel .w { display: inline-block; opacity: 0; transform: translateY(.45em); transition: opacity .6s, transform .8s var(--ease); }
.js .panel.in .w { opacity: 1; transform: none; }

.label { margin: 0 0 calc(14 * var(--u)); font: 400 var(--fs-xs)/1.4 var(--mono); letter-spacing: .06em; text-transform: uppercase; color: var(--accent-soft); }
.tone-day .label { color: var(--accent-strong); }
h1, h2 { margin: 0 0 calc(14 * var(--u)); font-weight: 800; letter-spacing: -.025em; line-height: 1.08; text-wrap: balance; } /* 1.02 let Turkish İ and German Ü touch the line above */
h1 { font-size: clamp(calc(38 * var(--u)), 6vw, calc(70 * var(--u))); }
/* The first screen's card is wider on a computer, so its headline takes two
   lines, not three (Taste review 25.10); its sentence keeps a reading width. */
@media (min-width: 1280px) { #bed .panel { width: min(calc(780 * var(--u)), 100%); } }
#bed .lede { max-width: 36em; }
h2 { font-size: clamp(calc(30 * var(--u)), 4.2vw, calc(50 * var(--u))); }
.hl { color: inherit; } /* headings in one colour: an orange word read as a template (Taste review 25.10) */
.panel > p, .start p { margin: 0 0 calc(14 * var(--u)); color: var(--n-dim); }
.panel.wide > p, .start p { max-width: 65ch; }
.tone-day .panel > p, .tone-day .start p { color: var(--d-dim); }
.panel .lede { font-size: calc(20 * var(--u)); color: var(--n-text); opacity: .92; text-wrap: pretty; }
.small { font: 400 var(--fs-xs)/1.5 var(--mono); letter-spacing: .03em; }

/* ---------- Buttons ---------- */

.cta { display: flex; flex-wrap: wrap; gap: calc(10 * var(--u)); margin: calc(22 * var(--u)) 0 calc(14 * var(--u)); }
.btn {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  min-height: calc(46 * var(--u)); padding: calc(12 * var(--u)) calc(22 * var(--u));
  font: 600 calc(15 * var(--u))/1.2 Inter, -apple-system, sans-serif; letter-spacing: 0; text-decoration: none;
  text-align: center; text-wrap: balance; /* a long translation takes two even lines (Igor 25.10) */
  border: calc(1 * var(--u)) solid transparent; border-radius: calc(999 * var(--u));
  cursor: pointer;
  overflow: hidden;
  transition: transform 140ms cubic-bezier(.23, 1, .32, 1), background-color .15s, color .15s, border-color .15s;
}
.btn-main { background: var(--accent-strong); color: var(--on-accent); }
.btn-sound { gap: calc(8 * var(--u)); }
/* The speaker a size up and centred on the capitals, not on the line box (Igor, 24.10). */
.btn-sound svg { flex: none; width: calc(22 * var(--u)); height: calc(22 * var(--u)); margin-block: calc(-2 * var(--u)); translate: 0 calc(-.5 * var(--u)); fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.btn-main:focus-visible { background: var(--accent-strong-hover); }
.btn-flat { background: transparent; color: inherit; border-color: currentColor; border-color: color-mix(in srgb, currentColor 55%, transparent); }
.btn-flat:focus-visible { border-color: currentColor; }
@media (hover: hover) and (pointer: fine) {
  .btn-main:hover { background: var(--accent-strong-hover); }
  .btn-flat:hover { border-color: currentColor; }
}
.btn:active { transform: scale(.96); }
/* Taps: no grey flash from the phone, no wait for a double-tap zoom. */
html { -webkit-tap-highlight-color: transparent; }
button, a, summary { touch-action: manipulation; }
:focus-visible { outline: calc(2 * var(--u)) solid var(--accent-soft); outline-offset: calc(3 * var(--u)); }
/* On the cream of the morning the peach ring is too faint; it turns dark brown. */
.tone-day :focus-visible, :root[data-tone="day"] :is(.hud, .dock, .alarm-banner) :focus-visible { outline-color: var(--d-text); }

/* ---------- 11:04 — the alarm card ---------- */

.alarm-card {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: calc(2 * var(--u)) calc(16 * var(--u));
  margin-top: calc(20 * var(--u));
  padding: calc(16 * var(--u)) calc(18 * var(--u));
  background: rgba(255, 244, 232, .06);
  border: calc(1 * var(--u)) solid var(--n-line);
}
.ac-t { font: 600 calc(34 * var(--u))/1 var(--mono); font-variant-numeric: tabular-nums; letter-spacing: -.02em; color: var(--n-dim); transition: color .4s; }
.ac-t i { font-style: normal; font-size: calc(13 * var(--u)); margin-left: calc(6 * var(--u)); }
.ac-d { grid-column: 1; font: 400 var(--fs-xs)/1.4 var(--mono); color: var(--n-dim); letter-spacing: .04em; }
.switch { grid-column: 2; grid-row: 1 / span 2; width: calc(50 * var(--u)); height: calc(28 * var(--u)); border-radius: calc(14 * var(--u)); background: var(--switch-off); position: relative; transition: background .35s; }
.switch i { position: absolute; top: calc(3 * var(--u)); left: calc(3 * var(--u)); width: calc(22 * var(--u)); height: calc(22 * var(--u)); border-radius: 50%; background: var(--n-text); transition: transform .35s var(--ease); }
.alarm-card.on .switch { background: var(--accent-n); }
.alarm-card.on .switch i { transform: translateX(calc(22 * var(--u))); }
.alarm-card.on .ac-t { color: var(--n-text); }

/* The switch flips as the card nears the middle of the screen. First a
   spotlight: the rest of the panel dims, the card lifts and glows; then the
   flip, with a flash ring round the switch. */
#set { position: relative; }
.toggle-mark { position: absolute; left: 0; top: 10vh; width: calc(1 * var(--u)); height: calc(1 * var(--u)); pointer-events: none; }
.alarm-card { position: relative; transition: transform .5s var(--ease), border-color .5s; }
.alarm-card.cue { transform: scale(1.04); border-color: var(--accent-soft); }
.alarm-card::after { content: ""; position: absolute; inset: calc(-1 * var(--u)); border-radius: inherit; box-shadow: 0 0 0 calc(5 * var(--u)) rgba(255, 144, 82, .16), 0 calc(26 * var(--u)) calc(60 * var(--u)) calc(-18 * var(--u)) rgba(255, 144, 82, .6); opacity: 0; transition: opacity .5s; pointer-events: none; }
.alarm-card.cue::after { opacity: 1; }
#set .panel > :not(.alarm-card) { transition: opacity .5s; }
#set .panel.spot > :not(.alarm-card) { opacity: .28; }
.switch::before { content: ""; position: absolute; inset: calc(-3 * var(--u)); border-radius: inherit; border: calc(2 * var(--u)) solid rgba(255, 144, 82, .75); opacity: 0; pointer-events: none; }
.alarm-card.cue.on .switch::before { animation: flash .9s ease-out; }
@keyframes flash { from { opacity: 1; transform: none; } to { opacity: 0; transform: scale(1.5); } }

/* ---------- 6:41 — the pairs, as menu rows ---------- */

.pairs { list-style: none; margin: calc(18 * var(--u)) 0 0; padding: 0; display: grid; gap: calc(2 * var(--u)); }
.pairs li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: calc(14 * var(--u));
  padding: calc(10 * var(--u)) calc(12 * var(--u));
  border-left: calc(2 * var(--u)) solid var(--n-line);
}
.was { font: 400 calc(15 * var(--u))/1.45 var(--mono); color: var(--n-dim); }
.was::after { content: "  ↓"; color: var(--accent-soft); }
/* A calendar entry, then the line it became in the real song (Igor 25.10: concept A). */
.pairs-lines .got { font-size: clamp(calc(20 * var(--u)), 1.8vw, calc(24 * var(--u))); font-weight: 700; line-height: 1.25; letter-spacing: -.01em; }
.got { font-weight: 800; font-size: clamp(calc(24 * var(--u)), 2.4vw, calc(32 * var(--u))); line-height: 1.12; letter-spacing: -.02em; color: var(--n-text); text-wrap: balance; }

/* ---------- 7:00 — the song ---------- */

.player {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: calc(14 * var(--u)) calc(16 * var(--u));
  align-items: center;
  margin: calc(20 * var(--u)) 0 0;
  padding: calc(16 * var(--u));
  background: rgba(255, 255, 255, .55); /* one tone step, no frame inside the card */
}
.player figcaption { min-width: 0; }
.play {
  width: calc(76 * var(--u)); height: calc(76 * var(--u)); border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent-strong); color: var(--on-accent);
  border: 0; cursor: pointer; position: relative;
  transition: transform 140ms cubic-bezier(.23, 1, .32, 1), background-color .15s;
}
.play svg { width: calc(30 * var(--u)); height: calc(30 * var(--u)); }
@media (hover: hover) and (pointer: fine) { .play:hover { background: var(--accent-strong-hover); transform: scale(1.05); } }
.play::after { content: ""; position: absolute; inset: calc(-6 * var(--u)); border-radius: 50%; border: calc(2 * var(--u)) solid var(--accent); opacity: 0; }
.player.waiting .play::after { animation: ping 1.4s var(--ease) infinite; }
@keyframes ping { from { opacity: .7; transform: scale(.85); } to { opacity: 0; transform: scale(1.45); } }
.p-name { margin: 0 0 calc(4 * var(--u)); font-weight: 800; font-size: calc(20 * var(--u)); color: var(--d-text); }
.p-about { margin: 0; font-size: var(--fs-md); color: var(--d-dim); line-height: 1.5; }
.p-set { margin: 0 0 calc(6 * var(--u)); font-size: var(--fs-sm); font-weight: 600; letter-spacing: .01em; color: var(--accent-strong); } /* the song's settings, as the app shows them */
.bars { grid-column: 1 / -1; display: flex; align-items: flex-end; gap: calc(3 * var(--u)); height: calc(38 * var(--u)); }
.bars i { flex: 1; height: 100%; background: var(--accent); transform-origin: 50% 100%; transform: scaleY(.06); border-radius: calc(1 * var(--u)); opacity: .4; transition: opacity .4s; }
.singing .bars i { opacity: 1; } /* at rest: the song's shape, soft; playing: the live sound */
.seek { grid-column: 1 / -1; height: calc(2 * var(--u)); background: var(--d-line); }
.seek i { display: block; height: 100%; background: var(--accent); transform-origin: 0 50%; transform: scaleX(0); }
.lyrics { grid-column: 1 / -1; border-top: calc(1 * var(--u)) solid var(--d-line); padding-top: calc(10 * var(--u)); }
.lyrics summary { cursor: pointer; font: 400 var(--fs-xs)/1.4 var(--mono); letter-spacing: .06em; text-transform: uppercase; color: var(--accent-strong); padding: calc(10 * var(--u)) 0; }
.lyrics p { margin: calc(8 * var(--u)) 0 calc(4 * var(--u)); font-size: var(--fs-md); line-height: 1.6; color: var(--d-text); }
/* The words follow the song: the line being sung fills in word by word, the
   next one waits under it. The fill is an inline box, so a line that wraps
   fills its first row and then its second. */
.karaoke { display: none; }
.js .karaoke { display: grid; gap: calc(6 * var(--u)); grid-column: 1 / -1; align-content: start; padding: calc(4 * var(--u)) 0 calc(2 * var(--u)); }
.k-now { margin: 0; min-height: 2.6em; font-weight: 800; font-size: clamp(calc(24 * var(--u)), 2.4vw, calc(32 * var(--u))); line-height: 1.2; letter-spacing: -.01em; text-wrap: balance; }
.k-now .fill {
  --p: 0;
  background: linear-gradient(90deg, var(--accent-strong) calc(var(--p) * 100%), var(--d-dim) calc(var(--p) * 100%));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.k-now.enter { animation: k-in .35s var(--ease); }
@keyframes k-in { from { opacity: .2; transform: translateY(.35em); } }
.k-next { margin: 0; min-height: 1.5em; font-size: var(--fs-md); line-height: 1.5; color: var(--d-dim); }
.k-next.k-hint { font: 400 var(--fs-xs)/1.5 var(--mono); letter-spacing: .06em; text-transform: uppercase; color: var(--accent-strong); }
.lyrics .ln.now { color: var(--accent-strong); font-weight: 600; }
.js .player audio { display: none; }
.player audio { grid-column: 1 / -1; width: 100%; }

/* ---------- 7:05 — plans ---------- */

.plans { list-style: none; margin: calc(22 * var(--u)) 0 calc(18 * var(--u)); padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(260 * var(--u))), 1fr)); gap: calc(14 * var(--u)); }
.plan {
  --c: transparent;
  position: relative;
  padding: calc(22 * var(--u)) calc(22 * var(--u)) calc(18 * var(--u));
  background: rgba(255, 255, 255, .6);
}
.plan.pick { background: rgba(255, 144, 82, .14); } /* the yearly plan: one warmer step, no outline or badge */
.plan-n { margin: 0; font: 600 calc(12 * var(--u))/1.4 var(--mono); letter-spacing: .06em; text-transform: uppercase; color: var(--d-dim); }
.price { margin: calc(6 * var(--u)) 0 0; font: 600 calc(44 * var(--u))/1 var(--mono); letter-spacing: -.03em; color: var(--d-text); }
.per { margin: calc(6 * var(--u)) 0 calc(14 * var(--u)); font-size: var(--fs-md); color: var(--d-dim); }
.plan ul { margin: 0; padding: 0; list-style: none; display: grid; gap: calc(8 * var(--u)); font-size: calc(15 * var(--u)); color: var(--d-text); }

/* ---------- 7:12 — questions ---------- */

.faq { margin-top: calc(18 * var(--u)); border-top: calc(1 * var(--u)) solid var(--d-line); }
.faq details { border-bottom: calc(1 * var(--u)) solid var(--d-line); }
.faq summary {
  list-style: none;
  display: flex; gap: calc(14 * var(--u)); align-items: baseline;
  padding: calc(15 * var(--u)) calc(4 * var(--u));
  font-weight: 600; color: var(--d-text);
  cursor: pointer;
  transition: translate .15s ease-out, color .15s;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::before { content: "+"; font: 600 calc(15 * var(--u))/1 var(--mono); color: var(--accent); width: calc(12 * var(--u)); flex: none; transition: transform .3s var(--ease); }
.faq details[open] summary::before { transform: rotate(45deg); }
@media (hover: hover) and (pointer: fine) { .faq summary:hover { translate: calc(6 * var(--u)) 0; color: var(--accent-strong); } }
.faq details p { margin: 0; padding: 0 calc(4 * var(--u)) calc(18 * var(--u)) calc(30 * var(--u)); max-width: 65ch; color: var(--d-dim); }

/* ---------- 7:20 — start ---------- */

.start { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: calc(28 * var(--u)); align-items: center; }
.qr { margin: 0; text-align: center; font: 400 var(--fs-xs)/1.4 var(--mono); color: var(--d-dim); }
.qr img { display: block; width: calc(160 * var(--u)); height: auto; margin: 0 auto calc(8 * var(--u)); background: #fff; padding: calc(8 * var(--u)); }
@media (max-width: 760px) { .start { grid-template-columns: 1fr; } .qr { display: none; } }

footer { width: min(calc(980 * var(--u)), 100%); margin: calc(18 * var(--u)) 0 calc(calc(56 * var(--u)) + env(safe-area-inset-bottom)); /* room for the Sound pill, no more (Igor 25.10: no empty band at the end) */ padding: calc(18 * var(--u)) calc(22 * var(--u)) calc(10 * var(--u)); background: var(--d-card); border: calc(1 * var(--u)) solid var(--d-line); font: 400 var(--fs-xs)/1.6 var(--mono); color: var(--d-dim); }
footer p { margin: 0 0 calc(10 * var(--u)); display: flex; flex-wrap: wrap; gap: calc(12 * var(--u)) calc(24 * var(--u)); }
footer p.say { display: block; } /* a sentence, not a row of links: its full stop stays with the address */
footer p.attrib { display: block; margin: 0; font-size: var(--fs-xs); } /* the IP lookup's licence asks for this line on every page */
footer a { text-decoration: none; }
@media (hover: hover) and (pointer: fine) { footer a:hover { color: var(--accent-strong); } }
@media (pointer: coarse) { footer p { row-gap: 0; } footer a { padding-block: calc(12 * var(--u)); } }

/* ---------- The way in ---------- */

.lids { display: none; }
.js .lids { display: block; position: fixed; inset: 0; z-index: 20; }
.lid { position: absolute; left: 0; right: 0; height: 59%; transition: transform 1.25s cubic-bezier(.7, 0, .2, 1); }
.lid-top { background: linear-gradient(rgba(12, 8, 5, .58) 69%, rgba(12, 8, 5, 0)); }
.lid-bottom { background: linear-gradient(rgba(12, 8, 5, 0), rgba(12, 8, 5, .58) 31%); }
.lid-top { top: 0; }
.lid-bottom { bottom: 0; }
.intro {
  position: absolute; inset: 0;
  display: grid; place-content: center; justify-items: center; gap: calc(18 * var(--u));
  padding: calc(24 * var(--u));
  text-align: center;
  color: var(--n-text);
  transition: opacity .4s;
}
.intro-brand { margin: 0; font: 800 clamp(calc(40 * var(--u)), 8vw, calc(72 * var(--u)))/1 Inter, sans-serif; letter-spacing: -.02em; }
/* The door says what this is before it asks anything. */
.intro-promise { margin: calc(-6 * var(--u)) 0 calc(4 * var(--u)); max-width: 30ch; font-size: clamp(calc(19 * var(--u)), 2.6vw, calc(24 * var(--u))); line-height: 1.45; color: var(--n-text); text-wrap: balance; }
.loader { position: relative; width: min(calc(220 * var(--u)), 60vw); height: calc(2 * var(--u)); margin: 0; background: rgba(246, 231, 214, .14); }
.intro-go { display: grid; justify-items: center; gap: calc(10 * var(--u)); opacity: 0; transform: translateY(calc(8 * var(--u))); transition: opacity .5s, transform .6s var(--ease); pointer-events: none; }
.ready .intro-go { opacity: 1; transform: none; pointer-events: auto; }
.intro-go .btn { min-width: calc(250 * var(--u)); }
.intro-go .btn-flat { color: var(--n-text); }
.intro-hint { margin: calc(6 * var(--u)) 0 0; font: 400 var(--fs-xs)/1.4 var(--mono); color: var(--n-dim); }

/* Opening: a blink first — half open, shut, then all the way. */
.opening .intro { opacity: 0; pointer-events: none; }
.opening .lid-top { animation: lid-top 1.5s cubic-bezier(.6, 0, .2, 1) forwards; }
.opening .lid-bottom { animation: lid-bottom 1.5s cubic-bezier(.6, 0, .2, 1) forwards; }
@keyframes lid-top { 0% { transform: none; } 25% { transform: translateY(-22%); } 42% { transform: translateY(-4%); } 100% { transform: translateY(-101%); } }
@keyframes lid-bottom { 0% { transform: none; } 25% { transform: translateY(22%); } 42% { transform: translateY(4%); } 100% { transform: translateY(101%); } }
.open .lids { display: none; }

/* The door shows the night it opens on (Igor, 25.10, variant A of three):
   the lids are a see-through veil over the sky, the stars and the
   listening sun, and their inner edges fade out like the half-open lids of
   variant C, so no hard line crosses the screen as they part. The two fades
   overlap in the middle, a little lighter there, where the words are. The
   page's own words wait until the door opens. */
.locked main, .locked .hud, .locked .progress { visibility: hidden; }
/* Been here before: no door. */
.skipdoor .lids { display: none !important; }
/* Sound was on last time: the switch asks for one tap with a sonar ping —
   six slow pings, about 12 s (Igor, 24.10: longer than three quick ones). */
.sound::before { content: ""; position: absolute; inset: 0; border-radius: inherit; box-shadow: 0 0 0 calc(2 * var(--u)) var(--hud-accent); opacity: 0; pointer-events: none; }
.sound.nudge::before { animation: nudge 2s ease-out 6; }
@keyframes nudge { from { opacity: 1; transform: none; } to { opacity: 0; transform: scale(1.15, 1.6); } }

/* ---------- The look ----------
   No label over the first heading; the brand face everywhere. */
.loader::before { content: ""; position: absolute; inset: 0 auto 0 0; width: calc(var(--p, 0) * 100%); background: linear-gradient(90deg, var(--bar-from), var(--accent-soft)); }
#bed .label { display: none; }
.small, .intro-hint { font-family: Inter, -apple-system, sans-serif; font-size: calc(13 * var(--u)); letter-spacing: 0; }

/* Type: the brand face everywhere, the clock included. */
.hud, .label, .ac-d, .was,
.plan-n, .price, footer,
.qr, .k-next.k-hint, .lyrics summary,
.faq summary::before, .plan ul li::before {
  font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  letter-spacing: 0;
}
.hud { font-size: calc(13 * var(--u)); }
.clock-day, .plan-n, .k-next.k-hint, .lyrics summary { text-transform: none; }
.panel .label { position: absolute; width: calc(1 * var(--u)); height: calc(1 * var(--u)); margin: calc(-1 * var(--u)); overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* The clock in the top line is the one timekeeper: the cards' own times
   repeated it and on phones disagreed with it. Screen readers, for whom the
   clock is hidden, still hear each card's time (Taste review 25.10). */
.plan-n { font-size: calc(15 * var(--u)); font-weight: 600; }
.price { font-weight: 800; font-variant-numeric: tabular-nums; }
.js .price { white-space: nowrap; } /* never split; dawn.js shrinks a long one to fit */
.plan { min-width: 0; } /* a long one-line price must not widen its card past the screen */
.chapters, .hud-bottom > * { border-radius: calc(999 * var(--u)); }
.chapters { border-radius: calc(18 * var(--u)); }

/* Panels: rounded, a warmer ground, a soft shadow below. */
.panel { border-radius: calc(22 * var(--u)); background: rgba(40, 24, 14, .78); border-color: rgba(255, 170, 110, .16); box-shadow: 0 calc(30 * var(--u)) calc(70 * var(--u)) calc(-44 * var(--u)) rgba(0, 0, 0, .5); } /* neutral: the orange glow under every card read as a template */
.tone-day .panel { background: rgba(255, 248, 238, .84); border-color: rgba(255, 170, 110, .16); box-shadow: 0 calc(30 * var(--u)) calc(70 * var(--u)) calc(-44 * var(--u)) rgba(90, 50, 25, .22); }
.alarm-card, .player, .plan, footer { border-radius: calc(16 * var(--u)); }
/* The plan above, the song title under it, one pair after another with
   room between instead of rules (Taste review 25.10). */
.pairs { gap: calc(20 * var(--u)); }
.pairs li { grid-template-columns: 1fr; gap: calc(4 * var(--u)); border: 0; padding: 0; }


/* Seven o'clock, said the way a phone says it: an alarm card slides down to
   the very top of the screen, over the heads-up line, for five seconds. */
.alarm-banner {
  position: fixed; z-index: 7; left: 50%; top: calc(calc(10 * var(--u)) + env(safe-area-inset-top));
  width: min(calc(440 * var(--u)), calc(100vw - calc(24 * var(--u))));
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: calc(12 * var(--u));
  padding: calc(12 * var(--u)) calc(12 * var(--u)) calc(12 * var(--u)) calc(14 * var(--u));
  background: var(--hud-sheet); color: var(--hud);
  border: calc(1 * var(--u)) solid var(--d-line); border-radius: calc(18 * var(--u));
  box-shadow: 0 calc(18 * var(--u)) calc(40 * var(--u)) calc(-20 * var(--u)) rgba(46, 28, 18, .45);
  transform: translate(-50%, -150%); opacity: 0;
  transition: transform .6s var(--ease), opacity .4s;
}
.alarm-banner.show { transform: translate(-50%, 0); opacity: 1; }
.ab-app { width: calc(34 * var(--u)); height: calc(34 * var(--u)); border-radius: calc(8 * var(--u)); }
.ab-text { min-width: 0; }
.ab-top { margin: 0; display: flex; justify-content: space-between; gap: calc(8 * var(--u)); font: 400 calc(12 * var(--u))/1.3 Inter, sans-serif; color: var(--hud-dim); }
.ab-time { margin: calc(2 * var(--u)) 0 0; font: 600 calc(20 * var(--u))/1.1 var(--mono); font-variant-numeric: tabular-nums; }
.ab-name { margin: calc(2 * var(--u)) 0 0; font: 600 calc(15 * var(--u))/1.3 Inter, sans-serif; overflow-wrap: anywhere; }
.ab-play { min-height: calc(44 * var(--u)); padding: 0 calc(18 * var(--u)); border: 0; border-radius: calc(999 * var(--u)); background: var(--accent-strong); color: var(--on-accent); font: 600 calc(15 * var(--u))/1 Inter, sans-serif; cursor: pointer; }
@media (hover: hover) and (pointer: fine) { .ab-play:hover { background: var(--accent-strong-hover); } }
/* Words in the alarm card break only between words: «Будильни/к» at 320
   before (review 24.10). The narrowest phones get a smaller icon and button. */
.alarm-banner { overflow-wrap: normal; }
.ab-top span { white-space: nowrap; }
@media (max-width: 359px) {
  .alarm-banner { gap: calc(10 * var(--u)); padding-left: calc(12 * var(--u)); }
  .ab-app { width: calc(28 * var(--u)); height: calc(28 * var(--u)); }
  .ab-play { padding: 0 calc(12 * var(--u)); }
}
.sr-only { position: absolute; width: calc(1 * var(--u)); height: calc(1 * var(--u)); margin: calc(-1 * var(--u)); overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* The song's own small player, kept at the bottom left once the song has
   started (above the sound switch), so it can be paused from anywhere. It
   steps out of the way while the big player is on screen or the chapter
   sheet is open. */
.dock {
  position: fixed; z-index: 6;
  left: max(calc(16 * var(--u)), env(safe-area-inset-left));
  bottom: calc(max(calc(14 * var(--u)), env(safe-area-inset-bottom)) + calc(44 * var(--u)));
  display: flex; align-items: center; gap: calc(10 * var(--u));
  max-width: calc(100vw - calc(32 * var(--u)));
  padding: calc(6 * var(--u)) calc(16 * var(--u)) calc(6 * var(--u)) calc(6 * var(--u));
  background: var(--hud-sheet); color: var(--hud);
  border: calc(1 * var(--u)) solid var(--d-line); border-radius: calc(999 * var(--u));
  box-shadow: 0 calc(14 * var(--u)) calc(34 * var(--u)) calc(-18 * var(--u)) rgba(46, 28, 18, .5);
  opacity: 0; transform: translateY(calc(12 * var(--u))); pointer-events: none;
  transition: opacity 200ms ease-out, transform 250ms var(--ease);
}
.dock.show { opacity: 1; transform: none; pointer-events: auto; }
.dock.show.away, .sheet-open .dock.show { opacity: 0; transform: translateY(calc(12 * var(--u))); pointer-events: none; }
.dock-play { flex: none; display: grid; place-items: center; width: calc(40 * var(--u)); height: calc(40 * var(--u)); padding: 0; border: 0; border-radius: 50%; background: var(--accent-strong); color: var(--on-accent); cursor: pointer; }
@media (hover: hover) and (pointer: fine) { .dock-play:hover { background: var(--accent-strong-hover); } }
.dock-play svg { width: calc(18 * var(--u)); height: calc(18 * var(--u)); fill: currentColor; }
.dock-text { display: grid; gap: calc(1 * var(--u)); min-width: 0; }
.dock-name { font: 600 calc(13 * var(--u))/1.25 Inter, sans-serif; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dock-time { font: 400 calc(13 * var(--u))/1.2 var(--mono); color: var(--hud-dim); font-variant-numeric: tabular-nums; }
.dock-seek { position: absolute; left: calc(22 * var(--u)); right: calc(22 * var(--u)); bottom: calc(4 * var(--u)); height: calc(2 * var(--u)); border-radius: calc(1 * var(--u)); overflow: hidden; background: rgba(128, 90, 60, .18); }
.dock-seek i { display: block; height: 100%; transform-origin: 0 50%; transform: scaleX(0); background: var(--accent-strong); }
/* Close: a small round button on the corner; it stops the song and puts the
   player away until the song is started again. */
.dock-close { position: absolute; top: calc(-8 * var(--u)); right: calc(-8 * var(--u)); display: grid; place-items: center; width: calc(24 * var(--u)); height: calc(24 * var(--u)); padding: 0; border: calc(1 * var(--u)) solid var(--d-line); border-radius: 50%; background: var(--hud-sheet); color: var(--hud-dim); box-shadow: 0 calc(4 * var(--u)) calc(10 * var(--u)) calc(-4 * var(--u)) rgba(46, 28, 18, .5); cursor: pointer; }
.dock-close::after { content: ""; position: absolute; inset: calc(-10 * var(--u)); }
@media (hover: hover) and (pointer: fine) { .dock-close:hover { color: var(--hud); } }
/* The narrowest phones: «Three Thi…» told nothing; the time and the buttons stay. */
@media (max-width: 359px) { .dock-name { display: none; } }
/* On the narrowest phones the first screen keeps its beta button above the bottom bar. */
@media (max-width: 359px) { .panel .lede { font-size: calc(17 * var(--u)); } }
/* Every small control gives a little under the finger. */
.dock-play, .ab-play, .dock-close { transition: transform 140ms cubic-bezier(.23, 1, .32, 1); }
:is(.play, .dock-play, .ab-play, .dock-close, .sound, .lang-btn, .where):active { transform: scale(.96); }
.dock-close svg { width: calc(12 * var(--u)); height: calc(12 * var(--u)); fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; }

/* Seven o'clock: a swell of sunrise from below. */
.glow { position: absolute; inset: 0; opacity: 0; pointer-events: none; background: radial-gradient(90% 62% at 50% 100%, rgba(255, 200, 150, .85), rgba(255, 144, 82, .35) 45%, transparent 76%); }
.glow.on { animation: swell 2.8s var(--ease) forwards; }
@keyframes swell { 0% { opacity: 0; } 25% { opacity: 1; } 100% { opacity: 0; } }

/* 3:12: a note on the night table. */
.note { margin: calc(20 * var(--u)) 0 0; padding: calc(18 * var(--u)) calc(20 * var(--u)); border-radius: calc(16 * var(--u)); background: rgba(0, 0, 0, .2); }
.note-day { margin: 0 0 calc(8 * var(--u)); font-weight: 600; color: var(--n-text); }
.note ul { list-style: none; margin: 0 0 calc(12 * var(--u)); padding: 0; display: grid; gap: calc(6 * var(--u)); color: var(--n-dim); }
.note li { display: flex; gap: .3em; } /* a long line wraps beside the time, not under it */
.note li span { flex: none; display: inline-block; min-width: 5.6em; color: var(--accent-soft); font-weight: 600; font-variant-numeric: tabular-nums; }
.note-song { margin: 0; color: var(--n-text); }
.js .note > * { opacity: 0; transform: translateY(calc(8 * var(--u))); transition: opacity .8s var(--ease), transform 1s var(--ease); }
.js .panel.in .note > * { opacity: 1; transform: none; }
.js .panel.in .note > :nth-child(2) { transition-delay: .6s; }
.js .panel.in .note > :nth-child(3) { transition-delay: 1.3s; }


/* A phone held sideways gets the wide layout on a screen 390 px tall: a
   smaller heading and lede, and the veil under the bottom pills that phones
   have, so the words never run under them unreadable. */
@media (min-width: 768px) and (max-height: 500px) {
  h1 { font-size: clamp(calc(32 * var(--u)), 10vh, calc(50 * var(--u))); }
  .panel .lede { font-size: calc(17 * var(--u)); }
  .hud-bottom::before { content: ""; position: absolute; inset: calc(-36 * var(--u)) 0 0; z-index: -1; background: linear-gradient(transparent, var(--hud-veil) 62%); pointer-events: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .opening .lid-top, .opening .lid-bottom { animation: none; opacity: 0; transition: opacity .4s; }
  .m-body, .m-sway, .pen, .mnote, .mouth, .switch, .switch::before, .clock.buzz, .player.waiting .play::after, .sound[aria-pressed="true"] .eq i { animation: none !important; }
  .m-body { transition: none; }
  .mascot[data-mood="sleeping"] .z { animation: none; opacity: .85; }
  .js .panel { transition: opacity .3s; transform: none; }
  .k-now.enter { animation: none; }
  .sound.nudge::before { animation: none; }
  .sound.nudge { outline: calc(2 * var(--u)) solid var(--hud-accent); outline-offset: calc(2 * var(--u)); }
  .js .note > *, html.js .panel { transition: opacity .3s; transform: none; transition-delay: 0s !important; }
  .glow.on { animation: none; }
  .alarm-banner { transition: opacity .3s; transform: translate(-50%, 0); }
  .dock, .dock.show.away { transition: opacity .3s; transform: none; }
  .btn, .play, .chapters a, .faq summary, .switch i { transition: none; }
  .intro-go { transition: opacity .3s; } /* the door's buttons fade in, not pop */
  .btn:active, .play:hover, .intro-go { transform: none; }
  :is(.btn, .play, .dock-play, .ab-play, .dock-close, .sound, .lang-btn, .where):active { transform: none; opacity: .85; }
  .sheet-open .chapters { transition: opacity 150ms; }
  .chapters a:hover, .faq summary:hover { translate: none; }
}

/* ---------- Phones ----------
   The scene is the point, so the panels give it room: each chapter's panel
   sits high and the rest of the chapter is open sky to scroll through; the
   panels carry less text and more opacity, the mascot keeps a band above the
   bottom bar, and a veil keeps the bar readable. */
@media (max-width: 767px) {
  /* Less empty sky between chapters: a chapter is a little over a screen;
     only dawn keeps its open sky, where the sun comes up (Taste review
     25.10: the song arrived around screen 6.5 of 11.5). */
  .ch:not(#plans):not(#faq):not(#start) { min-height: 115svh; align-content: start; padding-top: 15vh; padding-bottom: 0; }
  #light { min-height: 150svh; }
  #bed { padding-top: calc(92 * var(--u)); min-height: 115svh; }
  .ch#set:not(#plans):not(#faq):not(#start) { min-height: 0; padding-top: 0; }
  #set .hold { padding: calc(76 * var(--u)) 0 calc(70 * var(--u)); }
  .pairs li:nth-child(n+4) { display: none; }
  .panel { background: rgba(26, 16, 10, .82); }
  .panel { background: rgba(40, 24, 14, .86); }
  .tone-day .panel, .tone-day .panel { background: rgba(255, 249, 241, .92); }
  /* A bigger sun on phones (Igor: it was too small at 76 px); on the narrowest
     screens it moves left of the dunes' gap just enough to stay 16 px inside. */
  :root { --sun: calc(112 * var(--u)); --sun-low: calc(calc(66 * var(--u)) + env(safe-area-inset-bottom)); }
  .mascot { left: min(calc(50% + 0.15 * max(110vw, calc(760 * var(--u)))), calc(100% - calc(72 * var(--u)))); }
  .mascot { --zs: 3.2; --ns: 2.3; }
  /* The song's small player leaves room for the mascot at the right. */
  .dock { max-width: min(calc(100vw - calc(168 * var(--u))), calc(50vw + calc(22 * var(--u)))); }
  .hud-bottom::before { content: ""; position: absolute; inset: calc(-36 * var(--u)) 0 0; z-index: -1; background: linear-gradient(transparent, var(--hud-veil) 62%); pointer-events: none; }
}

@media (max-width: 520px) {
  .ch { padding-left: calc(12 * var(--u)); padding-right: calc(12 * var(--u)); }
  .panel { padding: calc(22 * var(--u)) calc(18 * var(--u)) calc(22 * var(--u)); }
  .ac-t { font-size: calc(28 * var(--u)); }
  .intro-go .btn { min-width: 0; width: 100%; }
  /* The song's player: the play button and the title side by side, the
     words about the song under them at full width, not down a narrow column
     beside the button (review 24.10). */
  .player { display: flow-root; }
  .play { float: left; width: calc(64 * var(--u)); height: calc(64 * var(--u)); margin: 0 calc(14 * var(--u)) calc(12 * var(--u)) 0; }
  .p-name { min-height: calc(64 * var(--u)); display: flex; align-items: center; margin: 0; }
  .p-about { clear: left; }
  .player > :not(.play):not(figcaption) { clear: both; margin-top: calc(14 * var(--u)); }
}
