/* Console menu, variant A "Kino" (docs/design/2026-10-18-menu-v2.md; Alex 18.10.: „sieht aus wie AI slop“ → study → „Neues Design
   gefällt mir sehr“, A). Rules this file keeps:
   - no vertical accent strokes and no coloured edge lines on panels (tests/no-accent-bars.test.js): hierarchy from type size and
     weight, space, light and depth
   - one text family (Lexend, variable 100–900) with a real contrast of weights; Unbounded only in the brand mark
   - near-black neutral ink instead of navy; colour comes from the games (their key art, their accent), not from the surface
   - focus = the element itself lights up (milk fill, a bright ring with a dark gap), grows on a spring; everything else recedes
   - motion on damped springs (--spring, sampled into linear() by menu.js), staggered text, a short blur-in
   Sizes use a 1080p raster: calc(var(--u) * 40) = 40 px on a 1080p TV, scaled on other screens; phones get their own raster below. */

/* Fonts: local files (SIL OFL 1.1, see assets/LICENSES.md), variable weights in one file each. */
@font-face {
  font-family: 'Unbounded';
  src: url('./fonts/unbounded.woff2') format('woff2');
  font-weight: 200 900;
  font-display: block;
}
@font-face {
  font-family: 'Lexend';
  src: url('./fonts/lexend.woff2') format('woff2');
  font-weight: 100 900;
  font-display: block;
}

:root {
  --space-deep: #07080c; /* neutral ink, no navy */
  --ink: #07080c;
  --space: #101117;
  --space-raised: #1a1b22;
  --milk: #f3ead8;
  --milk-dim: #aaa49a;
  --milk-2: rgba(243, 234, 216, .72);
  --milk-3: rgba(243, 234, 216, .46);
  --sun: #ffc76b;
  --sun-glow: rgba(255, 199, 107, .45);
  --nebula: #6fd6ff;
  --ember: #ff7a59;
  --aurora: #7cf0b2;
  --accent: #ffc76b;
  --glass: rgba(16, 17, 22, .84);
  --u: min(calc(100vh / 1080), calc(100vw / 1920));
  --font-brand: 'Unbounded', 'Avenir Next', 'Futura', 'Century Gothic', sans-serif;
  --font-display: 'Lexend', 'Avenir Next', 'Futura', 'Century Gothic', sans-serif;
  --font-text: 'Lexend', 'Avenir Next', 'Futura', 'Century Gothic', sans-serif;
  --ease: cubic-bezier(.2, .7, .2, 1);
  --out: cubic-bezier(.3, 0, .2, 1);
  --spring: cubic-bezier(.2, .9, .25, 1.12); /* replaced by a sampled damped spring (menu.js) where linear() works */
  --spring-soft: cubic-bezier(.2, .8, .2, 1);
  --t-focus: 180ms;
}

/* Japanese: Lexend only contains Latin letters, so kana and kanji come from the next font in the list. Until a free (SIL OFL)
   Japanese font ships with the console (proposal in tasks/cloud-reports/J.md), these are the console's own system fonts; the Latin
   font stays first, so numbers and names look the same in every language. */
:root:lang(ja) {
  --font-display: 'Lexend', 'Hiragino Sans', 'Yu Gothic', 'Meiryo', 'Noto Sans JP', 'Noto Sans CJK JP', sans-serif;
  --font-text: 'Lexend', 'Hiragino Sans', 'Yu Gothic', 'Meiryo', 'Noto Sans JP', 'Noto Sans CJK JP', sans-serif;
}
:lang(ja) { line-break: strict; }

* { box-sizing: border-box; }
html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--space-deep);
  color: var(--milk);
  font-family: var(--font-text);
  font-size: calc(var(--u) * 26);
  line-height: 1.3;
  -webkit-font-smoothing: antialiased;
  user-select: none;
}
#sky { position: fixed; inset: 0; width: 100vw; height: 100vh; display: block; }
h1, h2, p, ul, ol, dl, dd { margin: 0; padding: 0; }
ul, ol { list-style: none; }
svg { display: block; flex: none; }

/* Safe TV margins: 5 % on every side. */
#ui { position: fixed; inset: 5vh 5vw; }

/* ---------- screens fade over each other ---------- */
.layer {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 280ms var(--ease), visibility 0s linear 280ms;
}
body[data-screen="home"] #home,
body[data-screen="home"] #topbar,
body[data-screen="settings"] #topbar,
body[data-screen="wish"] #topbar, /* Bauen keeps the bar: always a way to the other areas (Alex 21.10.) */
body[data-screen="settings"] #settings,
body[data-screen="wish"] #wish,
body[data-screen="question"] #question,
body[data-screen="summary"] #summary,
body[data-screen="build"] #build,
body[data-screen="aiNotice"] #ai,
body[data-screen="consent"] #consent,
body[data-screen="rating"] #rating,
body.show-logo #boot-logo {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 460ms var(--ease) 140ms, visibility 0s;
}
body[data-screen="settings"] #home { opacity: .3; visibility: visible; }
body[data-screen="aiNotice"] #topbar, body[data-screen="consent"] #topbar, body[data-screen="rating"] #topbar { opacity: .5; visibility: visible; }

/* ---------- brand mark: a four-pointed spark in sunlight and the (placeholder) name ---------- */
.mark-glyph {
  display: inline-block;
  flex: none;
  width: .8em; height: .8em;
  background: var(--sun);
  clip-path: polygon(50% 0, 61% 39%, 100% 50%, 61% 61%, 50% 100%, 39% 61%, 0 50%, 39% 39%);
  filter: drop-shadow(0 0 .3em rgba(255, 199, 107, .6));
}

/* ---------- boot: the name in the light that ignites in the dark ---------- */
#boot-logo { display: grid; place-items: center; }
.logo {
  /* Placeholder product name (not decided yet). */
  display: flex;
  align-items: center;
  gap: .45em;
  font: 500 calc(var(--u) * 64)/1 var(--font-brand);
  letter-spacing: .06em;
  color: var(--milk);
  text-shadow: 0 0 calc(var(--u) * 28) rgba(255, 199, 107, .35);
  opacity: 0;
  filter: blur(8px);
  transition: letter-spacing 1600ms var(--out), opacity 900ms var(--out), filter 900ms var(--out);
}
body.show-logo .logo { letter-spacing: .01em; opacity: 1; filter: blur(0); }

/* ---------- top bar: brand, the three areas as round buttons, clock ---------- */
#topbar { bottom: auto; height: calc(var(--u) * 64); display: flex; align-items: center; gap: calc(var(--u) * 28); z-index: 3; }
.brand {
  display: flex;
  align-items: center;
  gap: calc(var(--u) * 14);
  margin-right: auto;
  font: 500 calc(var(--u) * 27)/1 var(--font-brand);
  letter-spacing: .01em;
  color: var(--milk);
}
#top { display: flex; gap: calc(var(--u) * 14); }
.top-item {
  position: relative;
  display: grid;
  place-items: center;
  width: calc(var(--u) * 64);
  height: calc(var(--u) * 64);
  border-radius: 50%;
  color: var(--milk);
  background: rgba(14, 15, 20, .5);
  cursor: pointer;
  transition: transform 460ms var(--spring), background var(--t-focus), color var(--t-focus);
}
.top-item svg { width: calc(var(--u) * 28); height: calc(var(--u) * 28); }
.top-label {
  position: absolute;
  top: calc(100% + var(--u) * 14);
  left: 50%;
  transform: translate(-50%, calc(var(--u) * -6));
  font-size: calc(var(--u) * 20);
  font-weight: 500;
  white-space: nowrap;
  color: var(--milk);
  text-shadow: 0 1px calc(var(--u) * 14) rgba(0, 0, 0, .6);
  opacity: 0;
  pointer-events: none;
  transition: opacity 180ms var(--out), transform 360ms var(--spring);
}
.top-item.is-focus { background: var(--milk); color: var(--ink); transform: scale(1.1); }
.top-item.is-focus .top-label { opacity: 1; transform: translate(-50%, 0); }
@media (hover: hover) { .top-item:hover .top-label { opacity: 1; transform: translate(-50%, 0); } .top-item:hover { background: rgba(243, 234, 216, .16); } }
#clock { margin-left: calc(var(--u) * 14); font-size: calc(var(--u) * 26); color: var(--milk-2); font-variant-numeric: tabular-nums; }

/* ---------- main menu: the shelf (state zone 'orbit') ----------
   The shelf runs from screen edge to screen edge (it starts outside the safe margin of #ui); home-view.js places every tile with
   --x / --s, the focused one big at the second place. */
#shelf {
  position: absolute;
  left: -5vw; right: -5vw;
  top: calc(var(--u) * 86);
  padding: calc(var(--u) * 24) 0;
  overflow: clip;
  z-index: 2;
  transition: top 520ms var(--spring-soft);
}
#home:has(#ideas.on) #shelf { top: calc(var(--u) * 146); }
#track { position: relative; }
#track.still .tile { transition: none; }
.tile {
  position: absolute;
  left: 0; top: 0;
  width: var(--wf);
  aspect-ratio: 16 / 9;
  border-radius: calc(var(--u) * 10);
  transform-origin: 0 0;
  transform: translate3d(var(--x, 0), 0, 0) scale(var(--s, 1));
  transition: transform 640ms var(--spring), opacity 400ms var(--out);
  will-change: transform;
  cursor: pointer;
}
.tile.is-off { opacity: 0; pointer-events: none; }
.tile-art, .tile-shade, .tile-sheen { position: absolute; inset: 0; border-radius: inherit; }
.tile-art { display: block; width: 100%; height: 100%; background: #111318; box-shadow: inset 0 1px 0 rgba(255, 255, 255, .12); }
.tile-shade { background: var(--ink); opacity: .42; transition: opacity 360ms var(--out); }
.tile.is-current .tile-shade { opacity: 0; }
body:not([data-screen="home"]) .tile-shade { opacity: .42; }
.tile-ring {
  position: absolute;
  inset: calc(var(--u) * -7);
  border-radius: calc(var(--u) * 16);
  box-shadow: 0 0 0 calc(var(--u) * 3) var(--milk), 0 0 calc(var(--u) * 46) calc(var(--u) * 2) color-mix(in srgb, var(--accent) 45%, transparent);
  opacity: 0;
  transform: scale(.985);
  transition: opacity 220ms var(--out), transform 520ms var(--spring);
  pointer-events: none;
}
.tile.is-focus .tile-ring { opacity: 1; transform: none; }
.tile-sheen { overflow: hidden; pointer-events: none; }
.tile-sheen::before {
  content: '';
  position: absolute;
  top: -20%; bottom: -20%;
  width: 38%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .16) 50%, transparent);
  transform: translateX(-140%) skewX(-12deg);
}
.tile.is-focus .tile-sheen::before { animation: sheen 1100ms var(--out) 120ms both; }
@keyframes sheen { to { transform: translateX(380%) skewX(-12deg); } }
.tile::after {
  content: '';
  position: absolute;
  inset: calc(var(--u) * -7);
  border-radius: calc(var(--u) * 16);
  box-shadow: 0 0 0 calc(var(--u) * 3) var(--milk);
  opacity: 0;
  pointer-events: none;
}
.tile.pulse::after { animation: pulse 620ms var(--out); }
@keyframes pulse { from { opacity: .9; transform: scale(1); } to { opacity: 0; transform: scale(1.14); } }
.tile-name {
  display: none;
  position: absolute;
  left: 7%; right: 7%; bottom: 9%;
  font: 600 calc(var(--wf) * .072)/1.08 var(--font-text);
  letter-spacing: -.02em;
  color: var(--milk);
  text-shadow: 0 1px 18px rgba(0, 0, 0, .35);
  overflow-wrap: anywhere;
}
.tile.no-art .tile-name, .tile-wish .tile-name { display: block; }
.tile-mark { position: absolute; left: 7%; top: 11%; width: calc(var(--wf) * .1); height: calc(var(--wf) * .1); color: var(--sun); filter: drop-shadow(0 0 10px rgba(255, 199, 107, .7)); }
.tile-mark svg { width: 100%; height: 100%; }

/* ---------- main menu: the focused game's details (bottom left) ---------- */
#hero { position: absolute; left: 0; bottom: calc(var(--u) * 72); max-width: calc(var(--u) * 1100); z-index: 2; }
#hero-meta { font-size: calc(var(--u) * 23); font-weight: 500; color: var(--milk-2); letter-spacing: .01em; }
#hero-title {
  margin-top: calc(var(--u) * 14);
  font: 600 calc(var(--u) * 100)/.98 var(--font-display);
  letter-spacing: -.04em;
  text-wrap: balance;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
  cursor: pointer;
}
#hero[data-long="1"] #hero-title { font-size: calc(var(--u) * 76); letter-spacing: -.035em; }
#hero-sub { margin-top: calc(var(--u) * 10); font: 300 calc(var(--u) * 44)/1.1 var(--font-display); letter-spacing: -.02em; color: rgba(243, 234, 216, .86); }
#hero-sub:empty { display: none; }
#hero-desc {
  margin-top: calc(var(--u) * 24);
  max-width: calc(var(--u) * 760);
  font: 300 calc(var(--u) * 27)/1.5 var(--font-text);
  color: var(--milk-2);
  text-wrap: pretty;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}
#home:has(#ideas.on) #hero-desc { -webkit-line-clamp: 2; }
#hero-desc:empty { display: none; }
/* "Nur auf der Konsole" on a phone (touch.js consoleOnly), "gemeldet" for a reported game */
#hero-note { margin-top: calc(var(--u) * 12); font-size: calc(var(--u) * 24); color: var(--ember); }
#hero-note:empty { display: none; }
#actions { display: flex; flex-wrap: wrap; gap: calc(var(--u) * 16); margin-top: calc(var(--u) * 38); }
/* actions as real buttons: the first (Spielen / Wünschen) is filled; focus = the button lights up with a ring and grows */
.act {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: calc(var(--u) * 14);
  height: calc(var(--u) * 76);
  padding: 0 calc(var(--u) * 38) 0 calc(var(--u) * 30);
  border-radius: 999px;
  font-size: calc(var(--u) * 28);
  font-weight: 500;
  color: var(--milk);
  background: rgba(30, 31, 36, .62);
  cursor: pointer;
  transition: transform 460ms var(--spring), background var(--t-focus), color var(--t-focus), box-shadow 220ms var(--out), opacity var(--t-focus);
}
.act svg { width: calc(var(--u) * 28); height: calc(var(--u) * 28); }
.act-primary { background: var(--milk); color: var(--ink); }
.act.is-focus {
  background: var(--milk);
  color: var(--ink);
  transform: scale(1.07);
  box-shadow: 0 0 0 calc(var(--u) * 4) var(--ink), 0 0 0 calc(var(--u) * 7) var(--milk), 0 calc(var(--u) * 10) calc(var(--u) * 56) color-mix(in srgb, var(--accent) 40%, transparent);
}
.act.is-off { opacity: .45; }
@media (hover: hover) { .act:not(.act-primary):not(.is-focus):hover { background: rgba(243, 234, 216, .16); } }
/* the details change line by line: out quickly, in on a spring with a short blur (staggered by --i) */
#hero.out > * { opacity: 0; transform: translateY(calc(var(--u) * -8)); transition: opacity 110ms var(--out), transform 130ms var(--out); }
#hero.in > * { animation: rise 760ms var(--spring) both; animation-delay: calc(var(--i, 0) * 50ms); }
@keyframes rise {
  from { opacity: 0; transform: translateY(calc(var(--u) * 22)); filter: blur(6px); }
  45% { opacity: 1; filter: blur(0); }
  to { opacity: 1; transform: none; filter: blur(0); }
}

/* credits of the focused game (bottom right, above the hints): style, language, who built it, own figures – and the build budget */
#credits { position: absolute; right: 0; bottom: calc(var(--u) * 72); display: grid; justify-items: end; gap: calc(var(--u) * 22); max-width: calc(var(--u) * 600); z-index: 2; }
#hero-facts { display: grid; grid-template-columns: max-content auto; gap: calc(var(--u) * 8) calc(var(--u) * 18); align-items: center; }
#hero-facts dt { font-size: calc(var(--u) * 19); color: var(--milk-3); text-align: right; }
#hero-facts dd { display: flex; align-items: center; gap: calc(var(--u) * 10); font-size: calc(var(--u) * 22); color: var(--milk-2); }
#hero-facts dd svg { width: calc(var(--u) * 30); height: calc(var(--u) * 20); }
body:not([data-screen="home"]) #credits { opacity: 0; }

/* ---------- actions on the other screens as points of light (the main menu has real buttons, .act; these follow in plan step 4) ---------- */
.lightpoints { display: flex; flex-wrap: wrap; justify-content: center; gap: calc(var(--u) * 16); margin-top: calc(var(--u) * 28); }
.lightpoints.left { justify-content: flex-start; }
.lp {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--u) * 14);
  font-size: calc(var(--u) * 30);
  font-weight: 500;
  color: var(--milk-dim);
  cursor: pointer;
  transform-origin: left center;
  transition: color var(--t-focus) var(--ease), transform var(--t-focus) var(--ease);
}
.lp::before {
  content: '';
  width: calc(var(--u) * 14);
  height: calc(var(--u) * 14);
  border-radius: 50%;
  border: 2px solid rgba(243, 234, 216, .5);
  transition: background var(--t-focus), border-color var(--t-focus), box-shadow var(--t-focus);
}
.lp.is-primary::before { border-color: var(--sun); }
.lp.is-focus { color: var(--milk); transform: scale(1.1); }
.lp.is-focus::before {
  background: var(--sun);
  border-color: var(--sun);
  box-shadow: 0 0 0 calc(var(--u) * 6) rgba(255, 199, 107, .16), 0 0 calc(var(--u) * 24) calc(var(--u) * 4) var(--sun-glow);
  animation: breathe 2.4s ease-in-out infinite;
}
/* ---------- actions on the other screens: the main menu's buttons (.act) – Alex 20.10.: the screens behind „Ändern“ and the rating
   in the design of the menu. A pill of dark glass, the first (primary) action filled with milk; focus = milk with the ring, as .act. ---------- */
.lightpoints .lp {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: calc(var(--u) * 72);
  padding: 0 calc(var(--u) * 36);
  border-radius: 999px;
  font-size: calc(var(--u) * 28);
  font-weight: 500;
  color: var(--milk);
  background: rgba(30, 31, 36, .62);
  cursor: pointer;
  transition: transform 460ms var(--spring), background var(--t-focus), color var(--t-focus), box-shadow 220ms var(--out);
}
.lightpoints .lp::before { content: none; }
.lightpoints .lp.is-primary { background: var(--milk); color: var(--ink); }
.lightpoints .lp.is-focus {
  background: var(--milk);
  color: var(--ink);
  transform: scale(1.05);
  box-shadow: 0 0 0 calc(var(--u) * 4) var(--ink), 0 0 0 calc(var(--u) * 7) var(--milk), 0 calc(var(--u) * 10) calc(var(--u) * 56) color-mix(in srgb, var(--accent) 40%, transparent);
}
@media (hover: hover) { .lightpoints .lp:not(.is-primary):not(.is-focus):hover { background: rgba(243, 234, 216, .16); } }
@keyframes breathe { 50% { box-shadow: 0 0 0 calc(var(--u) * 10) rgba(255, 199, 107, .08), 0 0 calc(var(--u) * 30) calc(var(--u) * 6) var(--sun-glow); } }

/* ---------- Werft: text column on the left, the forming planet on the right ---------- */
.werft-text { right: auto; width: 46vw; }
.eyebrow {
  display: flex;
  align-items: center;
  gap: calc(var(--u) * 12);
  font: 500 calc(var(--u) * 23)/1 var(--font-display);
  letter-spacing: .01em;
  color: var(--milk-2);
  margin-bottom: calc(var(--u) * 26);
}
.eyebrow svg { width: calc(var(--u) * 30); height: calc(var(--u) * 30); }
.title { font: 600 calc(var(--u) * 60)/1.12 var(--font-display); letter-spacing: -.035em; margin-bottom: calc(var(--u) * 34); text-wrap: balance; }
.question { font: 500 calc(var(--u) * 36)/1.3 var(--font-text); margin-bottom: calc(var(--u) * 36); max-width: 40vw; }
.hint-line { font-size: calc(var(--u) * 24); color: var(--milk-dim); margin: calc(var(--u) * 34) 0 calc(var(--u) * 16); }
/* Notes under the wish field and in the summary: at least 22 px (STYLEGUIDE 3), milk instead of milk-dim and dark glass behind the
   text (STYLEGUIDE 4) – the light ring of the Werft planet may shine right behind them (prüfer 07.10.: grey 19 px text on the ring). */
#wish-note, #wish-ai {
  max-width: 46vw;
  margin: calc(var(--u) * 12) 0 0;
  padding: calc(var(--u) * 10) calc(var(--u) * 16);
  font-size: calc(var(--u) * 22);
  line-height: 1.4;
  color: var(--milk);
  background: rgba(14, 15, 20, .72);
  text-shadow: 0 0 calc(var(--u) * 12) rgba(4, 5, 8, .9);
}

/* Lanes: wide flat rows (suggestions, answers, settings, choices). No edge stroke: at rest a faint fill, focus = the row fills with
   light (milk, ink text) and grows a little on a spring (Alex 18.10.: „Oft nutzt du links neben den Textfeldern hochkantige Striche“). */
.lane {
  position: relative;
  display: flex;
  align-items: center;
  gap: calc(var(--u) * 18);
  width: 100%;
  min-height: calc(var(--u) * 84);
  margin-bottom: calc(var(--u) * 10);
  padding: calc(var(--u) * 14) calc(var(--u) * 30);
  font-size: calc(var(--u) * 32);
  color: var(--milk-2);
  background: rgba(243, 234, 216, .07);
  border-radius: calc(var(--u) * 20);
  cursor: pointer;
  transform-origin: left center;
  transition: transform 460ms var(--spring), color var(--t-focus) var(--ease), background var(--t-focus) var(--ease);
}
.lane svg { width: calc(var(--u) * 32); height: calc(var(--u) * 32); }
.lane-own svg { color: var(--nebula); }
.lane-surprise svg { color: var(--sun); }
.lane-own, .lane-surprise { font-size: calc(var(--u) * 28); min-height: calc(var(--u) * 72); }
.lane.is-focus { color: var(--ink); background: var(--milk); transform: scale(1.025); }
.lane.is-focus svg { color: var(--ink); }
@media (hover: hover) { .lane:not(.is-focus):not(.lane-input):hover { background: rgba(243, 234, 216, .13); } }
.lane.is-typing .lane-text { display: none; }
/* The own answer while typing: the menu's text field (dark glass, milk ring – never milk words on the milk of a focused lane, which hid
   the words, 20.10.) with its own button „Übernehmen“ on the right, the same pill as the menu's main button. */
.lane.lane-own.is-typing, .lane.lane-own.is-typing.is-focus {
  cursor: text;
  transform: none;
  color: var(--milk);
  background: rgba(30, 31, 36, .8);
  box-shadow: 0 0 0 calc(var(--u) * 4) var(--ink), 0 0 0 calc(var(--u) * 7) var(--milk);
}
.lane.lane-own.is-typing svg { color: var(--nebula); }
.lane.lane-own.is-typing textarea { flex: 1 1 auto; min-width: 0; font-size: calc(var(--u) * 28); }
.own-ok {
  flex: none;
  align-self: center;
  display: inline-flex;
  align-items: center;
  height: max(var(--tap, 0px), calc(var(--u) * 56));
  padding: 0 calc(var(--u) * 26);
  border-radius: 999px;
  font-size: calc(var(--u) * 24);
  font-weight: 500;
  color: var(--ink);
  background: var(--milk);
  cursor: pointer;
}

/* Text fields (wish, change, notes, report). Alex 12.10. and again 20.10.: „Die Freitextfelder sehen immer noch aus wie AI slop“ –
   „Es soll einfach das Design passender zum Menü haben“. The field is made of the main menu's own parts: the dark glass of its round
   buttons (.act), the same large rounded shape, and on focus the same milk ring as a focused button. No point of light, no underline.
   It is a textarea that grows with the words (grow.js) – the one-line field cut long wishes off („…über die Schul|“). */
.lane.lane-input {
  cursor: text;
  align-items: flex-start;
  padding: calc(var(--u) * 20) calc(var(--u) * 30);
  background: rgba(30, 31, 36, .62);
  border-radius: calc(var(--u) * 30);
  box-shadow: inset 0 0 0 1px rgba(243, 234, 216, .1);
  transition: box-shadow 220ms var(--out), background var(--t-focus);
}
.lane.lane-input textarea, .lane.lane-input input { text-shadow: none; }
.lane.lane-input.is-focus {
  transform: none;
  color: var(--milk);
  background: rgba(30, 31, 36, .8);
  box-shadow: 0 0 0 calc(var(--u) * 4) var(--ink), 0 0 0 calc(var(--u) * 7) var(--milk), 0 calc(var(--u) * 10) calc(var(--u) * 56) color-mix(in srgb, var(--accent) 30%, transparent);
}
@media (hover: hover) { .lane.lane-input:not(.is-focus):hover { background: rgba(43, 44, 50, .7); } }
input, textarea {
  all: unset;
  width: 100%;
  font: 400 calc(var(--u) * 32)/1.35 var(--font-text);
  color: var(--milk);
  caret-color: var(--sun);
  user-select: text;
}
textarea {
  display: block;
  resize: none;
  field-sizing: content;
  min-height: 1.35em;
  max-height: 5.4em;   /* four lines, then it scrolls inside the field */
  overflow-y: auto;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
input::placeholder, textarea::placeholder { color: var(--milk-dim); opacity: .75; }

/* summary – the action row never leaves the safe margin (prüfer 07.10.: with a long wish and five answers it ended at 1042 of
   1080 px). A column: the parts above the row keep their size, only the answers may shrink (and are cut with …, never silently);
   the row follows the content and stops at the bottom of the safe area, with room below for the toast (e.g. after "Nein"). The wish
   quote takes at most 3 lines (2 with four or more answers), every answer one question line and two answer lines (one line with
   four or more). tests/summary-layout.test.js measures the worst case in two sizes and in French. */
#summary { display: flex; flex-direction: column; padding-bottom: calc(var(--u) * 96); }
#summary > * { flex: none; }
#summary .eyebrow { margin-bottom: calc(var(--u) * 14); }
#summary .title { margin-bottom: calc(var(--u) * 22); }
.wish-quote {
  max-width: 42vw;
  margin: 0 0 calc(var(--u) * 18);
  font-size: calc(var(--u) * 30);
  color: var(--milk);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
  text-shadow: 0 0 calc(var(--u) * 14) rgba(4, 5, 8, .9);
}
#summary[data-rows="4"] .wish-quote, #summary[data-rows="5"] .wish-quote { -webkit-line-clamp: 2; }
/* the list is the one part that gives way; its left padding keeps the glow of the bullets inside the clipping edge */
#sum-lines { flex: 0 1 auto; min-height: 0; overflow: hidden; margin-left: calc(var(--u) * -14); padding-left: calc(var(--u) * 14); }
#sum-lines li {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  padding: calc(var(--u) * 5) 0 calc(var(--u) * 5) calc(var(--u) * 30);
}
#sum-own, #sum-note, #sum-time {
  max-width: 42vw;
  padding: calc(var(--u) * 8) calc(var(--u) * 16);
  font-size: calc(var(--u) * 22);
  line-height: 1.4;
  color: var(--milk);
  background: rgba(14, 15, 20, .72);
  text-shadow: 0 0 calc(var(--u) * 12) rgba(4, 5, 8, .9);
}
/* After "Nein" to the order question: what that means, while wish and answers stay (an empty line is hidden). */
#sum-note { margin: calc(var(--u) * 10) 0 0; }
#sum-note:empty { display: none; }
/* The question before the paid build (state.js CONFIRM_ACTIONS): read before the second press, so a size larger. */
#sum-note.is-ask { font-size: calc(var(--u) * 26); color: var(--sun); }
#sum-time { margin: calc(var(--u) * 10) 0 0; }
#sum-time:empty { display: none; }
/* Brand or character of another company in the wish: said before saving (names.js). */
#sum-own { margin: calc(var(--u) * 10) 0 0; }
#sum-own:empty { display: none; }
.question.is-thinking { animation: thinking 1.8s ease-in-out infinite; }
@keyframes thinking { 50% { opacity: .55; } }
body.reduced .question.is-thinking { animation: none; }
#sum-lines li::before {
  content: '';
  position: absolute;
  left: 0; top: calc(var(--u) * 21);
  width: calc(var(--u) * 8); height: calc(var(--u) * 8);
  border-radius: 50%;
  background: var(--sun);
  box-shadow: 0 0 calc(var(--u) * 10) var(--sun-glow);
}
.sum-q, .sum-a { text-shadow: 0 0 calc(var(--u) * 14) rgba(4, 5, 8, .9); }
.sum-q { font-size: calc(var(--u) * 22); color: var(--milk-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sum-a {
  font-size: calc(var(--u) * 30);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
#summary[data-rows="4"] .sum-a, #summary[data-rows="5"] .sum-a, #summary[data-rows="6"] .sum-a { -webkit-line-clamp: 1; font-size: calc(var(--u) * 28); }
/* Six rows (five answers and the hint about another company's name): the quote shrinks to one line and the spacing gets tighter, so that "Bauen" still stays in the
   picture with the time note below (tests/wish-path-summary.test.js, six languages, two sizes). */
#summary[data-rows="6"] .wish-quote { -webkit-line-clamp: 1; margin-bottom: calc(var(--u) * 10); }
#summary[data-rows="6"] .title { margin-bottom: calc(var(--u) * 12); }
#summary[data-rows="6"] #sum-lines li { padding-top: calc(var(--u) * 2); padding-bottom: calc(var(--u) * 2); }
#summary[data-rows="6"] #sum-lines li::before { top: calc(var(--u) * 18); }
#sum-actions { margin-top: calc(var(--u) * 24); }
/* Dense (seven rows and more: the three look questions are always asked since 19.10., so this is the usual summary – with the old
   two lines per answer the last answer was cut off, 55 px on a laptop, 82 px on the TV): a quiet table, one line per answer – the
   question dim on the left, the answer on the right. Smaller and tighter than the roomy list, the hints stay at 22 u; the whole
   answer is in the row's tooltip. Not on an upright phone (up to 600 px wide): there the screen scrolls and the answers keep their two lines. */
@media (min-width: 601px) {
  #summary[data-dense="1"] .title { font-size: calc(var(--u) * 52); margin-bottom: calc(var(--u) * 8); }
  #summary[data-dense="1"] .eyebrow { margin-bottom: calc(var(--u) * 8); }
  #summary[data-dense="1"] .wish-quote { -webkit-line-clamp: 1; margin-bottom: calc(var(--u) * 6); font-size: calc(var(--u) * 26); }
  #summary[data-dense="1"] #sum-lines li {
    grid-template-columns: minmax(0, 38%) minmax(0, 1fr);
    column-gap: calc(var(--u) * 16);
    align-items: baseline;
    padding-top: 0;
    padding-bottom: calc(var(--u) * 4);
  }
  #summary[data-dense="1"] #sum-lines li::before { top: calc(var(--u) * 12); }
  #summary[data-dense="1"] .sum-q { font-size: calc(var(--u) * 22); line-height: 1.3; }
  #summary[data-dense="1"] .sum-a { -webkit-line-clamp: 1; font-size: calc(var(--u) * 26); line-height: 1.25; }
  #summary[data-dense="1"] .sum-a:only-child { grid-column: 1 / -1; }
  #summary[data-dense="1"] #sum-actions { margin-top: calc(var(--u) * 14); }
  /* the table may reach further to the right (over the picture of the game; the text has its shadow) */
  #summary[data-dense="1"] { width: 58vw; }
}

/* build */
#build { display: flex; flex-direction: column; align-items: center; justify-content: flex-end; text-align: center; padding-bottom: 6vh; }
#build-log { margin-bottom: calc(var(--u) * 18); }
#build-log li { font-size: calc(var(--u) * 24); color: var(--milk-dim); opacity: .7; line-height: 1.6; }
#build-now { max-width: calc(var(--u) * 1100); font: 500 calc(var(--u) * 36)/1.3 var(--font-text); text-shadow: 0 0 calc(var(--u) * 20) rgba(4, 5, 8, .9); }
#build-now.is-done { font-family: var(--font-display); font-weight: 600; color: var(--aurora); }
#build-time { margin-top: calc(var(--u) * 14); font-size: calc(var(--u) * 28); color: var(--aurora); }
#build-info { max-width: calc(var(--u) * 980); margin-top: calc(var(--u) * 10); font-size: calc(var(--u) * 24); line-height: 1.5; color: var(--milk-dim); }
#build-time:empty, #build-info:empty { display: none; }
/* the focused button grows by 5 % to the right: room enough that its ring never touches the next one (prüfer 25.10.: 8 px overlap) */
#build-actions { gap: calc(var(--u) * 40); }
.study-note { position: absolute; left: 0; top: 0; font-size: calc(var(--u) * 22); color: var(--milk-dim); opacity: .7; }

/* settings: one dark glass panel on the right, the main menu dimmed behind it */
#settings .panel {
  position: absolute;
  right: 0; top: 14vh;
  width: 40vw;
  padding: calc(var(--u) * 44) calc(var(--u) * 48);
  background: var(--glass);
  border-radius: calc(var(--u) * 30);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .08);
}
.setting { justify-content: space-between; background: transparent; }
.setting-value { color: var(--sun); font-size: calc(var(--u) * 28); transition: color var(--t-focus); }
.lane.is-focus .setting-value { color: rgba(7, 8, 12, .62); }

/* ---------- learning loop: consent and rating (task D2) ----------
   Same language as the settings: one dark glass panel on the right, the game's picture stays behind it. */
#ai .panel, #consent .panel, #rating .panel {
  position: absolute;
  right: 0; top: 7vh;
  width: 52vw;
  padding: calc(var(--u) * 36) calc(var(--u) * 48) calc(var(--u) * 28);
  background: var(--glass);
  border-radius: calc(var(--u) * 30);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .08);
}
#ai .eyebrow, #consent .eyebrow { margin-bottom: calc(var(--u) * 18); }
#ai .title, #consent .title { font-size: calc(var(--u) * 44); margin-bottom: calc(var(--u) * 18); }
/* The order question (test phase) sits on the left: the finished planet of the summary stays on the right. */
.draft-note {
  margin-left: auto;
  padding-left: calc(var(--u) * 16);
  font: 400 calc(var(--u) * 22)/1 var(--font-text);
  letter-spacing: 0;
  color: var(--ember);
}
.consent-text { font-size: calc(var(--u) * 26); color: var(--milk); margin-bottom: calc(var(--u) * 10); }
.consent-kids {
  font-size: calc(var(--u) * 24);
  color: var(--nebula);
  margin: calc(var(--u) * 4) 0 calc(var(--u) * 20);
  padding-left: calc(var(--u) * 16);
}
/* Parent tick above Yes/No ("16 or older, or a parent agrees"): a square box that stays empty until the player sets it – filled
   green with a check when set. It does not belong to either answer; "Ja" waits for it. */
.consent-parent { position: relative; margin: 0 0 calc(var(--u) * 20); font-size: calc(var(--u) * 26); }
.consent-parent::before { width: calc(var(--u) * 28); height: calc(var(--u) * 28); border-radius: 4px; flex: none; }
.consent-parent.is-on { color: var(--milk); }
.consent-parent.is-on::before { background: var(--aurora); border-color: var(--aurora); }
.consent-parent.is-on::after {
  content: '';
  position: absolute;
  left: calc(var(--u) * 9);
  top: 50%;
  width: calc(var(--u) * 8);
  height: calc(var(--u) * 15);
  border: solid var(--space-deep);
  border-width: 0 3px 3px 0;
  transform: translateY(-62%) rotate(45deg);
}
/* Yes and No: the very same lane, same size, same weight – no colour or order trick decides for the player. */
.lane-choice { font-size: calc(var(--u) * 30); min-height: calc(var(--u) * 72); margin-bottom: calc(var(--u) * 10); }

/* Rating (Alex 12.10., iPhone on its side: „bei den Bewertungsfeldern muss man kurbeln … man übersieht schnell die
   Verbesserungs-Textfelder“): every step fits one screen. The sizes that decide the height are tokens on #rating – the TV values
   here, the phone values in the phone blocks below; tests/menu-rating-layout.test.js adds them up against the screen height. */
#rating {
  --r-pad-t: calc(var(--u) * 36); --r-pad-b: calc(var(--u) * 40);
  --r-eyebrow: calc(var(--u) * 22); --r-eyebrow-gap: calc(var(--u) * 26);
  --r-title: calc(var(--u) * 48); --r-title-gap: calc(var(--u) * 28);
  --r-orb: calc(var(--u) * 150); --r-orb-label: calc(var(--u) * 30); --r-orb-gap: calc(var(--u) * 18);
  --r-gap: calc(var(--u) * 48);
  --r-row: calc(var(--u) * 72); --r-topic: calc(var(--u) * 22); --r-label-w: calc(var(--u) * 210);
  --r-better: calc(var(--u) * 30); --r-better-gap: calc(var(--u) * 36);
}
#rating.is-notes { --r-title: calc(var(--u) * 40); --r-title-gap: calc(var(--u) * 18); }
#rating .panel { top: 14vh; width: 50vw; padding-top: var(--r-pad-t); padding-bottom: var(--r-pad-b); }
#rating .eyebrow { flex-wrap: nowrap; font-size: var(--r-eyebrow); margin-bottom: var(--r-eyebrow-gap); }
#rating .eyebrow svg { width: calc(var(--r-eyebrow) * 1.3); height: calc(var(--r-eyebrow) * 1.3); }
#rating .title { font-size: var(--r-title); line-height: 1.2; margin-bottom: var(--r-title-gap); }
.step-note { margin-left: auto; font: 400 calc(var(--u) * 22)/1 var(--font-text); letter-spacing: 0; color: var(--milk-dim); white-space: nowrap; }
#rating-game { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#rating-orbs { display: flex; gap: calc(var(--u) * 36); margin: var(--r-orb-gap) 0 0; }
#rating-skip { margin-top: var(--r-gap); }
#rating-orbs[hidden], #rating-notes[hidden], #rating-skip[hidden] { display: none; }

/* Notes after the rating: one constellation instead of two clouds of chips. The topics stand in a row; under each one a point
   for „gut war“ and one for „nicht so gut war“, joined by a thin thread of light – a topic is never both, so a column lights at
   most one point (green = good, red = not so good). The row label lights up with the row that has the focus. Below: its own
   question and the line to write on, then Senden / Überspringen – the words can no longer hide below the fold. */
#rating.is-notes .panel { top: 7vh; width: 66vw; }
.notes-grid {
  display: grid;
  grid-template-columns: var(--r-label-w) repeat(6, minmax(0, 1fr)); /* 6 = TOPICS.length (console/consent.js, tested) */
  align-items: center;
  column-gap: calc(var(--u) * 8);
}
.notes-topics, .notes-grid .chips { display: contents; }
.notes-topic {
  align-self: end;
  padding-bottom: calc(var(--u) * 6);
  font: 400 var(--r-topic)/1.15 var(--font-text);
  color: var(--milk);
  text-align: center;
  hyphens: auto;
  overflow-wrap: break-word;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.notes-label {
  font: 500 calc(var(--r-topic) * .85)/1.15 var(--font-display);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--milk-dim);
  transition: color var(--t-focus) var(--ease);
}
.notes-label-good:has(+ .chips .is-focus) { color: var(--aurora); }
.notes-label-bad:has(+ .chips .is-focus) { color: var(--ember); }
.notes-grid .chip {
  position: relative;
  justify-content: center;
  min-height: var(--r-row);
  transform-origin: center;
}
.notes-grid .chip::before {
  position: relative;
  z-index: 1;
  width: calc(var(--r-topic) * 1.1);
  height: calc(var(--r-topic) * 1.1);
  background: var(--space-deep);
  transition: background var(--t-focus), border-color var(--t-focus), box-shadow var(--t-focus), transform var(--t-focus) var(--ease);
}
/* the thread between the two points of a topic */
.notes-grid .chip::after { content: ''; position: absolute; left: 50%; width: 1px; background: rgba(243, 234, 216, .22); }
.chips-good .chip::after { top: 50%; bottom: 0; }
.chips-bad .chip::after { top: 0; bottom: 50%; }
.notes-grid .lp.is-focus { transform: none; }
.notes-grid .lp.is-focus::before { transform: scale(1.25); }
.chips-good .lp.is-on::before { background: var(--aurora); border-color: var(--aurora); box-shadow: 0 0 calc(var(--u) * 16) rgba(124, 240, 178, .45); }
.chips-bad .lp.is-on::before { background: var(--ember); border-color: var(--ember); box-shadow: 0 0 calc(var(--u) * 16) rgba(255, 122, 89, .45); }
/* chosen and focused: the colour stays, the sunlight is the ring around it */
.chips-good .lp.is-on.is-focus::before, .chips-bad .lp.is-on.is-focus::before { box-shadow: 0 0 0 calc(var(--u) * 5) var(--space-deep), 0 0 0 calc(var(--u) * 7) var(--sun), 0 0 calc(var(--u) * 24) calc(var(--u) * 4) var(--sun-glow); }
.notes-better {
  margin: var(--r-better-gap) 0 calc(var(--u) * 4);
  font: 600 var(--r-better)/1.2 var(--font-display);
  letter-spacing: -.01em;
  color: var(--milk);
  transition: color var(--t-focus) var(--ease);
}
.notes-better:has(+ .notes-write #notes-field.is-focus) { color: var(--sun); }
#notes-field { min-height: var(--r-row); margin: 0; }
#notes-field input { font-size: calc(var(--u) * 30); }
#notes-actions { margin-top: var(--r-gap); }
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* Three celestial bodies, not tiles: a round body with the glyph, the word below. Focus = sunlight (larger, halo, breathing ring). */
.orb { display: flex; flex-direction: column; align-items: center; gap: var(--r-orb-gap); width: calc(var(--u) * 230); cursor: pointer; color: var(--milk-dim); transition: color var(--t-focus) var(--ease); }
.orb-body {
  display: grid;
  place-items: center;
  width: var(--r-orb);
  height: var(--r-orb);
  border-radius: 50%;
  border: 2px solid rgba(243, 234, 216, .35);
  background: rgba(14, 15, 20, .7);
  transition: transform var(--t-focus) var(--ease), border-color var(--t-focus), box-shadow var(--t-focus), color var(--t-focus);
}
.orb-body svg { width: calc(var(--r-orb) * .56); height: calc(var(--r-orb) * .56); }
.orb-label { font: 500 var(--r-orb-label)/1.2 var(--font-text); text-align: center; }
.orb.is-focus { color: var(--milk); }
.orb.is-focus .orb-body {
  transform: scale(1.1);
  color: var(--sun);
  border-color: var(--sun);
  box-shadow: 0 0 0 calc(var(--u) * 8) rgba(255, 199, 107, .14), 0 0 calc(var(--u) * 40) calc(var(--u) * 6) var(--sun-glow);
  animation: breathe 2.4s ease-in-out infinite;
}

/* toast + controller hints */
#toast {
  position: absolute;
  left: 0; bottom: 0;
  max-width: 50vw;
  padding: calc(var(--u) * 16) calc(var(--u) * 26);
  font-size: calc(var(--u) * 26);
  background: var(--glass);
  border-radius: 6px;
  opacity: 0;
  pointer-events: none; /* a toast never takes a click meant for the buttons under it */
  transform: translateY(calc(var(--u) * 12));
  transition: opacity 260ms var(--ease), transform 260ms var(--ease);
}
#toast.show { opacity: 1; transform: none; }
#hints { position: absolute; right: 0; bottom: 0; display: flex; gap: calc(var(--u) * 34); font-size: calc(var(--u) * 22); color: var(--milk-dim); }
.hint { display: inline-flex; align-items: center; gap: calc(var(--u) * 10); }
.btn {
  display: inline-grid;
  place-items: center;
  min-width: calc(var(--u) * 34);
  height: calc(var(--u) * 34);
  padding: 0 calc(var(--u) * 8);
  border: 2px solid rgba(169, 165, 184, .7);
  border-radius: calc(var(--u) * 17);
  font: 600 calc(var(--u) * 16)/1 var(--font-display);
  color: var(--milk);
}
.btn.key { font-family: var(--font-text); font-weight: 500; border-radius: calc(var(--u) * 6); }
/* keyboard: "Enter / Space" – two key caps, a thin slash between them (hints.js) */
.key-or { margin: 0 calc(var(--u) * -4); opacity: .6; }

/* fade through the dark (screen changes with reduced motion, leaving for a game) */
#veil { position: fixed; inset: 0; background: var(--space-deep); opacity: 0; pointer-events: none; transition: opacity 140ms linear; }
#veil.on { opacity: 1; }
#veil.slow { transition-duration: 520ms; transition-delay: 80ms; }

/* ---------- reduced motion: no movement, only fades ---------- */
body.reduced .lane, body.reduced .lp, body.reduced .act, body.reduced .top-item, body.reduced #toast { transition-property: opacity, color, background; }
body.reduced .lane.is-focus { transform: none; }
body.reduced .lp.is-focus { transform: none; }
body.reduced .orb-body { transition-property: border-color, box-shadow, color; }
body.reduced .orb.is-focus .orb-body { transform: none; animation: none; }
body.reduced .lp.is-focus::before, body.reduced .lane.lane-input.is-focus::before { animation: none; }
body.reduced .notes-grid .lp.is-focus::before { transform: none; }
body.reduced .act.is-focus, body.reduced .top-item.is-focus { transform: none; }
body.reduced .tile { transition: transform 1ms, opacity 200ms; }
body.reduced .tile-sheen::before, body.reduced .tile.pulse::after { animation: none; }
body.reduced #hero.in > * { animation: fade 220ms var(--out) both; }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
body.reduced .logo { transition: opacity 300ms; letter-spacing: .01em; filter: none; }
body.reduced #shelf { transition: none; }

/* without WebGL the menu still works on plain ink */
body.no-webgl #sky { display: none; }

/* ---------- touch: the menu by finger (Alex 12.10., iPhone 15 Pro as a home-screen app) ----------
   Comes in addition to keyboard and controller and changes nothing for them. Every tap counts at once (no double-tap zoom, so no
   300 ms wait); on the main menu the page never scrolls or zooms under the finger – a swipe there moves one tile (menu.js,
   touch.js). The phone raster and layouts follow below; touch.js PHONE_QUERY / PORTRAIT_QUERY / LANDSCAPE_QUERY are the same queries. */
html { touch-action: manipulation; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; }
#sky, #home, #topbar, #boot-logo, #hints { touch-action: none; }
.lp.is-off { opacity: .45; }
/* the phone keyboard's microphone can type the wish (touch only) */
#wish-voice {
  display: none;
  max-width: 46vw;
  margin: calc(var(--u) * 10) 0 0;
  padding: calc(var(--u) * 6) calc(var(--u) * 16);
  font-size: calc(var(--u) * 22);
  line-height: 1.4;
  color: var(--milk);
  text-shadow: 0 0 calc(var(--u) * 12) rgba(4, 5, 8, .9);
}
body[data-device="touch"] #wish-voice { display: block; }
/* "Zurück" without Esc or B: dark glass with one sunlit edge (styleguide §4), the glyph from glyphs.js, at least 48 px high */
#back-btn {
  position: absolute;
  left: 0; bottom: 0;
  display: none;
  align-items: center;
  gap: calc(var(--u) * 12);
  min-width: 48px;
  min-height: 48px;
  margin: 0;
  padding: 0 calc(var(--u) * 30) 0 calc(var(--u) * 22);
  font: 500 calc(var(--u) * 28)/1 var(--font-text);
  color: var(--milk);
  background: var(--glass);
  border: 0;
  border-radius: 6px;
  cursor: pointer;
  transition: background var(--t-focus) var(--ease);
}
#back-btn svg { width: calc(var(--u) * 34); height: calc(var(--u) * 34); color: var(--sun); }
#back-btn:active { background: rgba(255, 199, 107, .2); }
body[data-device="touch"][data-back="1"] #back-btn { display: inline-flex; }
body[data-device="touch"][data-back="1"] #toast { bottom: calc(48px + var(--u) * 16); }

/* ---------- phones: own raster, safe areas, screens that scroll instead of cutting ----------
   The TV raster (1080 p) makes everything about a fifth of its size on an upright iPhone. Here 640 raster units span the short
   side: 26 units of text = 16 px on an iPhone 15 Pro (393 pt), a light lane 52 px, hints 13.5 px – in both orientations. */
@media (pointer: coarse) and (max-width: 600px), (pointer: coarse) and (max-height: 600px) {
  :root {
    --u: calc(min(100vw, 100vh) / 640);
    --safe-t: max(env(safe-area-inset-top), 12px);
    --safe-r: max(env(safe-area-inset-right), 16px);
    --safe-b: max(env(safe-area-inset-bottom), 10px);
    --safe-l: max(env(safe-area-inset-left), 16px);
    --bar: 56px; /* bottom bar: "Zurück" on the left, the hints on the right; the screens end above it */
    --tap: 48px; /* smallest tap target (Apple: 44 pt) */
  }
  /* inside the notch, the rounded corners and the home bar */
  #ui { inset: var(--safe-t) var(--safe-r) var(--safe-b) var(--safe-l); }
  /* every screen ends above the bottom bar and scrolls when it is longer (consent text, many answers, the open keyboard) */
  .layer { bottom: var(--bar); overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; touch-action: pan-y; }
  #home, #topbar, #boot-logo { overflow: visible; }
  .eyebrow { flex-wrap: wrap; row-gap: 6px; }

  /* tap targets: never smaller than a fingertip; a focused lane lights up but does not slide out of the screen */
  .top-item { min-height: 44px; }
  .lp { min-height: var(--tap); }
  .lane { min-height: max(var(--tap), calc(var(--u) * 84)); }
  .lane-own, .lane-surprise, .lane-choice { min-height: var(--tap); }
  .lane.is-focus { transform: none; }
  /* buttons (Bauen, „Sag mir Bescheid, wenn es fertig ist“ …): never wider than the column, a long label wraps; the focus ring
     shows the focus without growing to the right over the screen edge (25.10.: the notify button ended 6 px before the glass) */
  .lightpoints .lp { max-width: 100%; height: auto; min-height: var(--tap); padding: 10px 22px; text-align: center; }
  .lightpoints .lp.is-focus { transform: none; }
  /* below 16 px Safari zooms into a text field when it gets the focus */
  input, #notes-field input { font-size: max(16px, calc(var(--u) * 30)); }

  /* bottom bar, toast above it */
  #hints { height: var(--bar); align-items: center; gap: 16px; font-size: max(13px, calc(var(--u) * 22)); }
  #back-btn { bottom: calc((var(--bar) - var(--tap)) / 2); min-height: var(--tap); font-size: max(16px, calc(var(--u) * 28)); }
  #back-btn svg { width: 22px; height: 22px; }
  #toast, body[data-device="touch"][data-back="1"] #toast { bottom: calc(var(--bar) + 8px); font-size: max(15px, calc(var(--u) * 26)); }

  /* main menu: the shelf runs from screen edge to screen edge (outside the safe margins), the credits make room */
  #shelf { left: calc(-1 * var(--safe-l)); right: calc(-1 * var(--safe-r)); }
  .top-item { width: 44px; height: 44px; }
  .top-item svg { width: 21px; height: 21px; }
  .top-label { display: none; }
  .brand { font-size: 16px; gap: 8px; }
  #clock { display: none; }
  #hero-facts { display: none; }

  /* panels (settings, consent, rating, order question) flow in their screen, so a long text scrolls instead of running out */
  #settings .panel, #ai .panel, #consent .panel, #rating .panel, #rating.is-notes .panel { position: relative; top: auto; right: auto; left: auto; margin: 0 0 0 auto; }
  #settings { padding-top: 56px; }
  .setting { flex-wrap: wrap; }
  /* consent and rating come without the top bar on a phone (there is no room above the panel) */
  body[data-screen="aiNotice"] #topbar, body[data-screen="consent"] #topbar, body[data-screen="rating"] #topbar { opacity: 0; visibility: hidden; }

  /* summary: the answers are not squeezed any more – the screen scrolls, and „Bauen“/„Ändern“ stay pinned at its bottom edge
     (25.10.: with nine answers on 390 × 844 the row lay below the screen, a finger did not know there was more). The answers and
     the quote get their full lines back here (the TV limits by row count above would cut them to one line); build: the text
     sits low, but stays reachable */
  #summary { padding-bottom: 0; }
  #sum-lines { flex: none; overflow: visible; }
  #summary { scroll-padding-bottom: calc(var(--tap) + var(--u) * 48); }
  #summary .wish-quote, #summary[data-rows] .wish-quote { display: block; -webkit-line-clamp: none; }
  #summary .sum-a, #summary[data-rows] .sum-a { -webkit-line-clamp: 3; font-size: calc(var(--u) * 30); }
  #summary .sum-q { white-space: normal; }
  #sum-actions {
    position: sticky; bottom: 0; z-index: 2;
    margin-top: calc(var(--u) * 16);
    padding: calc(var(--u) * 22) 8px calc(var(--u) * 10); /* 8 px: the focus ring of „Bauen“ is not cut by the screen's edge */
    background: rgb(4, 5, 8); /* flat dark glass (STYLEGUIDE §4), opaque: no answer shows through behind „Bauen“ (prüfer 25.10.) */
  }
  /* how long it takes stands right under the wish, in the first picture (prüfer 25.10.: at the end of the list nobody saw it);
     the answers follow, then the notes and the buttons */
  #sum-lines { order: 1; }
  #sum-own, #sum-note, #summary .budget, #sum-actions { order: 2; }
  #sum-time { margin: 0 0 calc(var(--u) * 14); }
  #build { justify-content: flex-start; padding-bottom: 12px; }
  #build-log { margin-top: auto; }
}

/* Upright phone (the main case): brand and three round buttons on top, the game's picture in the upper part (backdrop.js), its
   details above the shelf, the shelf at the bottom with the focused tile big; the Werft's text column starts under the top bar. */
@media (pointer: coarse) and (max-width: 600px) and (orientation: portrait) {
  #topbar { height: 44px; gap: 8px; }
  #top { gap: 8px; }
  .logo { font-size: 26px; }

  #shelf { top: auto; bottom: 0; padding: 12px 0; }
  #home:has(#ideas.on) #shelf { top: auto; }
  .tile { top: auto; bottom: 0; transform-origin: 0 100%; border-radius: 10px; }
  .tile-ring { inset: -5px; border-radius: 14px; box-shadow: 0 0 0 2px var(--milk), 0 0 28px 2px color-mix(in srgb, var(--accent) 45%, transparent); }
  .tile::after { inset: -5px; border-radius: 14px; box-shadow: 0 0 0 2px var(--milk); }
  .tile-name { font-size: 14px; }
  /* above the shelf: its tile is min(184 px, 47 vw) wide (home-view.js), 16:9, with 12 px padding above and below */
  #hero { left: 0; right: 0; bottom: calc(min(184px, 47vw) * 9 / 16 + 40px); max-width: none; }
  #hero-meta { font-size: 13px; }
  #hero-title, #hero[data-long="1"] #hero-title { margin-top: 8px; font-size: 38px; letter-spacing: -.035em; }
  #hero[data-long="1"] #hero-title { font-size: 30px; }
  #hero-sub { margin-top: 6px; font-size: 20px; }
  #hero-desc { margin-top: 10px; max-width: none; font-size: 15px; line-height: 1.45; }
  #hero-note { font-size: 14px; }
  #actions { flex-wrap: nowrap; gap: 10px; margin-top: 18px; }
  .act { height: 52px; padding: 0 14px; gap: 8px; font-size: 17px; justify-content: center; }
  .act svg { width: 20px; height: 20px; }
  .act-primary { flex: 1 1 auto; padding: 0 22px; }
  .act:not(.act-primary) { flex: none; width: 52px; padding: 0; }
  .act:not(.act-primary) .act-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .act.is-focus { transform: scale(1.04); box-shadow: 0 0 0 3px var(--ink), 0 0 0 5px var(--milk); }
  /* the build budget (only with "Neues Spiel wünschen" focused) stands under the top bar */
  #credits { left: 0; right: 0; top: 56px; bottom: auto; max-width: none; justify-items: stretch; }

  /* Werft, questions, summary, change: one full-width column under the planet (NDC y 0.64), scrolling */
  .werft-text { top: calc(33vh - var(--safe-t)); right: 0; width: auto; }
  /* „Ändern“ and „Melden“ have no forming planet above them: they start at the top and scroll inside when the words are long
     (20.10.: from 33vh the „Ändern“ button was cut off under the hints). */
  #change.werft-text, #report.werft-text, #figure.werft-text { top: 0; bottom: var(--bar, 0px); overflow-y: auto; overscroll-behavior: contain; }
  .title { font-size: calc(var(--u) * 46); margin-bottom: calc(var(--u) * 24); }
  .question { font-size: calc(var(--u) * 32); margin-bottom: calc(var(--u) * 24); }
  .question, #wish-note, #wish-ai, #wish-voice, .wish-quote, #sum-own, #sum-note, #sum-time { max-width: none; }
  #build-now, #build-info { max-width: 100%; }

  /* panels: the whole width */
  /* the whole width (the layer is a flex column that shrank a width:auto panel to its content: the rating topics were cut to „Gr a…“, 20.10.) */
  #settings .panel, #ai .panel, #consent .panel { width: 100%; margin: 0; padding: 22px 18px 18px; }
  #ai .title, #consent .title { font-size: calc(var(--u) * 40); }
  /* rating upright: one column; the notes turn on their side – a topic per row, its „gut“ and „nicht so gut“ points in two
     columns on a horizontal thread (the row model of the keys stays: up/down = good/not so good, left/right = topic) */
  #rating { --r-pad-t: 16px; --r-pad-b: 14px; --r-eyebrow: 14px; --r-eyebrow-gap: 12px; --r-title: 24px; --r-title-gap: 14px;
    --r-orb: 86px; --r-orb-label: 16px; --r-orb-gap: 10px; --r-gap: 10px; --r-row: var(--tap); --r-topic: 15px; --r-label-w: 96px;
    --r-better: 17px; --r-better-gap: 12px; }
  /* notes: six rows of points – at Apple's 44 pt so that a small iPhone (375 × 667) needs no scrolling either */
  #rating.is-notes { --r-title: 20px; --r-title-gap: 10px; --r-row: 44px; }
  #rating .panel, #rating.is-notes .panel { width: 100%; margin: 0; padding: var(--r-pad-t) 18px var(--r-pad-b); } /* the TV's 66vw of the notes step was 259 px here */
  #rating-orbs { gap: 8px; justify-content: space-between; }
  .orb { flex: 1 1 0; width: auto; min-width: 0; }
  .notes-grid { grid-auto-flow: column; grid-template-columns: minmax(0, 1fr) var(--r-label-w) var(--r-label-w); grid-template-rows: auto repeat(6, auto); column-gap: 0; }
  .notes-topic { align-self: center; padding: 0 10px 0 0; text-align: left; }
  .notes-label { align-self: end; padding-bottom: 6px; text-align: center; }
  .chips-good .chip::after, .chips-bad .chip::after { top: 50%; bottom: auto; width: auto; height: 1px; }
  .chips-good .chip::after { left: 50%; right: 0; }
  .chips-bad .chip::after { left: 0; right: 50%; }

  #toast { right: 0; max-width: none; }
}

/* Phone on its side: the TV layout with smaller type, so the shelf, the title and the buttons fit the low screen. */
@media (pointer: coarse) and (max-height: 600px) and (orientation: landscape) {
  #shelf { top: 46px; padding: 10px 0; }
  #home:has(#ideas.on) #shelf { top: 86px; }
  #hero { bottom: 0; max-width: 62vw; }
  #hero-meta { font-size: 12px; }
  #hero-title, #hero[data-long="1"] #hero-title { margin-top: 4px; font-size: 30px; }
  #hero-sub { margin-top: 2px; font-size: 16px; }
  #hero-desc { margin-top: 6px; font-size: 13px; -webkit-line-clamp: 1; }
  #actions { gap: 8px; margin-top: 10px; }
  .act { height: 44px; padding: 0 16px 0 12px; gap: 6px; font-size: 15px; }
  .act svg { width: 18px; height: 18px; }
  .act.is-focus { box-shadow: 0 0 0 3px var(--ink), 0 0 0 5px var(--milk); }
  #credits { bottom: 0; }
  #settings .panel { width: 50vw; }
  #toast { max-width: 60vw; }
  /* rating on its side (iPhone 15 Pro: 304 px between the safe top and the bottom bar – Alex 12.10. had to scroll): smaller type
     and orbs, the notes across the whole width, the text line with Senden / Überspringen in one row right under its question */
  #rating { --r-pad-t: 10px; --r-pad-b: 8px; --r-eyebrow: 12px; --r-eyebrow-gap: 4px; --r-title: 20px; --r-title-gap: 6px;
    --r-orb: 72px; --r-orb-label: 15px; --r-orb-gap: 6px; --r-gap: 6px; --r-row: var(--tap); --r-topic: 12px; --r-label-w: 84px;
    --r-better: 13px; --r-better-gap: 8px; }
  #rating.is-notes { --r-title: 18px; --r-title-gap: 6px; }
  #rating .panel { width: 60vw; padding: var(--r-pad-t) 18px var(--r-pad-b) 20px; }
  #rating.is-notes .panel { width: 100%; }
  #rating .step-note { font-size: 12px; }
  .notes-write { display: flex; align-items: center; gap: 18px; }
  #notes-field { flex: 1 1 auto; min-width: 0; }
  #notes-actions { flex: none; margin-top: 0; gap: 22px; }
}
