/* Keeplo coming-soon, dark throughout (owner E). The colour custom properties are js/core/palette.js keys in kebab
   case with the same values (checks/story.py holds them to it); every other colour mixes from them.
   Geist (OFL) is self-hosted, a stand-in until the brand picks a typeface. */
@font-face { font-family: "Geist"; src: url("fonts/geist-latin-wght.woff2") format("woff2"); font-weight: 100 900; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }

:root {
  --bg: #111111;
  --haze: #211815;
  --line-far: #352B28;
  --line-near: #4F4542;
  --line-top: #6E6560;
  --text: #ECE4E2;
  --text2: #B1A9A6;
  --text3: #8D8481;
  --letter: #F7F1EC;
  --orange: #F25A1E;
  --tom-core: #2A7195;
  --font: "Geist", system-ui, sans-serif;
  --ease: cubic-bezier(.16, 1, .3, 1);
  --edge: clamp(18px, 4vw, 56px);
  /* the wordmark's viewBox is 3.79 times as wide as high; its width also follows the screen height */
  --mark-w: min(78vw, 820px, calc((100svh - 300px) * 3.79));
  --mark-mid: 40svh;
  --k-w: clamp(130px, min(22vw, 32svh), 260px);   /* the hub's K */
  color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body { margin: 0; overflow: hidden; background: var(--bg); color: var(--text); font: 400 16px/1.5 var(--font);
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; -webkit-text-size-adjust: 100%; text-rendering: optimizeLegibility; }
::selection { background: var(--orange); color: var(--bg); }
:focus-visible { outline: 2px solid var(--orange); outline-offset: 4px; border-radius: 4px; }
p, h1 { margin: 0; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
/* the components set their own display, which would otherwise win over the hidden attribute */
[hidden] { display: none !important; }
/* every text the visitor reads on the hub is there in both languages; the head script and hub.js set html's lang.
   data-lang, not lang: text that only exists in one language can still say so in lang */
:root[lang="de"] [data-lang="en"], :root[lang="en"] [data-lang="de"] { display: none; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* the stage takes every one-finger gesture itself: swipe, hold and tap drive the story; pinch-zoom stays with the browser */
.stage { position: fixed; inset: 0; touch-action: pinch-zoom; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
.scene { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* between the 3D scene and the words: the text bands at the top and bottom stay dark whatever the scene does there,
   so every line keeps its contrast; the subjects stand between them */
.scrim { position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, color-mix(in srgb, var(--bg) 72%, transparent), transparent 15%, transparent 62%,
    color-mix(in srgb, var(--bg) 86%, transparent) 84%); }
html:not(.js) .scene, html:not(.js) .scrim, .flat .scene { display: none; }
.flat .stage { background: radial-gradient(120% 70% at 50% 110%, var(--haze), var(--bg) 70%); }

/* the story's clock line, set like an instrument's readout */
.clock { position: absolute; top: var(--edge); left: 50%; transform: translateX(-50%); display: flex; align-items: center; gap: 14px;
  font-size: .75rem; font-weight: 500; letter-spacing: .18em; text-transform: uppercase; font-variant-numeric: tabular-nums;
  color: var(--text2); white-space: nowrap; }
.clock:not(:empty)::before, .clock:not(:empty)::after { content: ""; width: 28px; height: 1px; background: var(--line-near); }

/* The hub: the K, each part named beside it. flight.js puts the hub's origin on the K's dot; choosing a part flies
   into it, the same way for every part. --u is one unit of the K's viewBox */
.hub { position: absolute; left: 0; top: 0; --u: calc(var(--k-w) / 134); }
/* the floor the chapters stand on, seen from above as the camera sees the hall at the hub, faint and only about the
   K: the stem's middle and the dot on its lines (32 units a cell), the dot where four cells' lines cross. 24 cells
   across, so the middle falls on a line of every fourth. The flight fades it with the names */
.hub-grid { position: absolute; --cell: calc(var(--u) * 32); width: calc(var(--cell) * 24); height: calc(var(--cell) * 24);
  left: calc(var(--cell) * -12); top: calc(var(--cell) * -12); pointer-events: none; }
.hub-grid::before { content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(to right, var(--line-near) 1px, transparent 1px) 0 0 / calc(var(--cell) * 4) calc(var(--cell) * 4),
    linear-gradient(to bottom, var(--line-near) 1px, transparent 1px) 0 0 / calc(var(--cell) * 4) calc(var(--cell) * 4),
    linear-gradient(to right, var(--line-far) 1px, transparent 1px) 0 0 / var(--cell) var(--cell),
    linear-gradient(to bottom, var(--line-far) 1px, transparent 1px) 0 0 / var(--cell) var(--cell);
  /* a mask reads only alpha: the colour is the palette's, its share of opacity is what counts */
  mask-image: radial-gradient(closest-side, var(--bg), color-mix(in srgb, var(--bg) 30%, transparent) 40%, transparent 72%); }
.hub-k { position: absolute; width: var(--k-w); height: auto; overflow: visible;
  /* the dot sits at (0, 0) of the viewBox -56 -80 134 160 */
  left: calc(var(--u) * -56); top: calc(var(--u) * -80);
  /* a flight grows the K about the centre of the part flown into, (--x, --y) in the viewBox (flight.js) */
  transform-origin: calc((var(--x, 0) + 56) / 134 * 100%) calc((var(--y, 0) + 80) / 160 * 100%); }
.hub-k path { fill: var(--letter); cursor: pointer; transition: fill-opacity .25s var(--ease); transform-box: fill-box; transform-origin: center; }
.hub-k .dot { fill: var(--orange); }
/* waiting: a wave runs through the K from left to right, the stem, the dot, then both arms, so each part reads as
   something to choose; pointing at the K holds it, the visitor has found it. It begins once the K has built itself
   (below), and as long after coming back from a story */
[data-route="hub"] .hub:not(.going) .hub-k path { animation: pulse 2.4s var(--ease) calc(var(--pulse-at, 0s) + 2.2s) infinite; }
.hub-k [data-to="turbos"] { --pulse-at: .25s; }
.hub-k [data-to="self-evolution"], .hub-k [data-to="onboarding"] { --pulse-at: .5s; }
.hub:has([data-to]:hover, .hub-link:focus-visible) .hub-k path { animation-play-state: paused; }
/* on the way into the Brain the K takes no pointer: a hover lighting another part would dim the stem as it grows */
.hub.going { pointer-events: none; }
@keyframes pulse { 0%, 25%, 100% { transform: none; } 12.5% { transform: scale(1.12); } }

/* The hub's arrival, once per page load: the floor fades up, the stem rises, the dot lights, the arms reach out of it,
   then the names and the line come in as a chapter's words do (ui.js), the wordmark and the language switch last. The
   first flight takes .arriving away (flight.js), so a part chosen while it builds stands whole at once and a story's
   way back plays none of it again; the pause ends it too, rather than stand the K still half built. Only elements that
   never change their display animate, so switching the language replays nothing */
.hub.arriving .hub-grid::before { animation: fade-in 2.4s var(--ease) backwards; }
.hub.arriving .hub-k path { animation: var(--in) 1.1s var(--ease) var(--in-at) backwards; }
[data-route="hub"] .hub.arriving:not(.going) .hub-k path {
  animation: var(--in) 1.1s var(--ease) var(--in-at) backwards, pulse 2.4s var(--ease) calc(var(--pulse-at, 0s) + 2.2s) infinite; }
.hub.arriving:has([data-to]:hover, .hub-link:focus-visible) .hub-k path { animation-play-state: running, paused; }
.hub-k .stem { --in: k-rise; --in-at: .2s; }
.hub-k .dot { --in: k-light; --in-at: .6s; }
.hub-k [data-to="self-evolution"] { --in: k-reach-up; --in-at: .8s; }
.hub-k [data-to="onboarding"] { --in: k-reach-down; --in-at: .9s; }
.hub.arriving .hub-link { animation: name-in 1s var(--ease) var(--in-at) backwards; }
.hub-link[data-to="brain"] { --in-at: 1.1s; }
.hub-link[data-to="turbos"] { --in-at: 1.2s; }
.hub-link[data-to="self-evolution"] { --in-at: 1.3s; }
.hub-link[data-to="onboarding"] { --in-at: 1.4s; }
.hub.arriving .hub-text { animation: name-in 1.2s var(--ease) 1.7s backwards; }
body:has(.hub.arriving) :is(.brand, .langs) { animation: fade-in 1.4s var(--ease) 1.6s backwards; }
/* no part is ever scaled to nothing, so each takes the pointer near where it will stand. In an svg's own transform a
   px is a unit of its viewBox */
@keyframes k-rise { from { opacity: 0; scale: 1 .2; } }
@keyframes k-light { from { opacity: 0; scale: .2; } }
@keyframes k-reach-up { from { opacity: 0; translate: -14px 14px; scale: .4; } }
@keyframes k-reach-down { from { opacity: 0; translate: -14px -14px; scale: .4; } }
/* the individual properties, beside each name's and the line's own transform */
@keyframes name-in { from { opacity: 0; filter: blur(6px); translate: 0 .4em; } }
@keyframes fade-in { from { opacity: 0; } }

/* each name at its part, in viewBox units from the dot, with a hairline from the part to it: the stem's left of it,
   the arms' right of their tips, the dot's in the K's opening. --lead is the hairline's length */
/* the names are set as the chapters' labels are (the clock, a card's head): small, tracked capitals, so the K stays the
   one big thing on the screen. A long name breaks into lines rather than run off a phone: the dot stands about
   mid-screen, so half the width less the arm's reach and the page's edge is the room beside the K */
.hub-names { --lead: 14; --gap: 7; }
.hub-link { position: absolute; width: max-content; max-width: calc(50vw - var(--u) * (78 + var(--lead) + var(--gap)) - var(--edge));
  font-size: clamp(.6875rem, .95vw, .8125rem); font-weight: 500; letter-spacing: .18em; text-transform: uppercase; line-height: 1.5;
  color: var(--text2); text-decoration: none; transform: translateY(-50%); transition: color .25s var(--ease); }
.hub-link::before { content: ""; position: absolute; top: calc(50% - .5px); width: calc(var(--u) * var(--lead)); height: 1px;
  right: calc(100% + var(--u) * var(--gap)); background: var(--lit, var(--line-top)); transition: background-color .25s var(--ease); }
.hub-link[data-to="brain"]::before { right: auto; left: calc(100% + var(--u) * var(--gap)); }
.hub-link[data-to="brain"] { left: calc(var(--u) * (-50 - var(--lead) - var(--gap))); top: 0; transform: translate(-100%, -50%); }
.hub-link[data-to="turbos"] { left: calc(var(--u) * (16 + var(--lead) * .7 + var(--gap))); top: 0; }
.hub-link[data-to="turbos"]::before { width: calc(var(--u) * var(--lead) * .7); }
.hub-link[data-to="self-evolution"] { left: calc(var(--u) * (78 + var(--lead) + var(--gap))); top: calc(var(--u) * -56.57); }
.hub-link[data-to="onboarding"] { left: calc(var(--u) * (78 + var(--lead) + var(--gap))); top: calc(var(--u) * 56.57); }
/* pointing at a part or its name lights both, and the hairline between them; the other parts step back */
.hub:has([data-to]:hover, .hub-link:focus-visible) [data-to] { fill-opacity: .3; color: var(--text3); }
.hub:has([data-to="brain"]:hover, [data-to="brain"]:focus-visible) [data-to="brain"],
.hub:has([data-to="self-evolution"]:hover, [data-to="self-evolution"]:focus-visible) [data-to="self-evolution"],
.hub:has([data-to="turbos"]:hover, [data-to="turbos"]:focus-visible) [data-to="turbos"],
.hub:has([data-to="onboarding"]:hover, [data-to="onboarding"]:focus-visible) [data-to="onboarding"] { fill-opacity: 1; color: var(--text); --lit: var(--orange); }
/* centred under the K's visible middle, 11 viewBox units right of its dot; set as the chapters' lines are, the ask
   a step quieter than what it asks of */
.hub-text { position: absolute; left: calc(var(--u) * 11); top: calc(var(--u) * 80 + 44px); transform: translateX(-50%);
  white-space: nowrap; font-size: clamp(1.3rem, 2.6vw, 2rem); font-weight: 450; letter-spacing: -0.04em; line-height: 1.1; color: var(--text); }
.hub-text .ask { color: var(--text3); }

/* the wordmark over the hub, there only while the hub is; it shows with the ui, as the hub does */
.brand { position: absolute; top: var(--edge); left: var(--edge); height: clamp(17px, 1.5vw, 22px); width: auto; overflow: visible;
  --ink: var(--letter); --accent: var(--orange); transition: opacity .5s var(--ease); }
body:not([data-route="hub"]) .brand { opacity: 0; }

/* a chapter without its demo yet: its name alone, just under where the K's dot stood (about .42 of the height). The
   whole screen is its window: flying in, it shows through the part's outline (flight.js) */
.chapter { position: absolute; inset: 0; background: var(--bg); }
/* it takes the focus when the chapter opens, so a screen reader reads its name; the focus ring would only clutter it */
.chapter h2:focus { outline: none; }
.chapter h2 { position: absolute; left: 50%; top: 50svh; transform: translateX(-50%); width: min(90vw, 980px); text-align: center;
  margin: 0; font-size: clamp(2rem, 6vw, 4.5rem); font-weight: 450; letter-spacing: -0.04em; line-height: 1.05; color: var(--text); }

.langs { position: absolute; top: var(--edge); right: var(--edge); display: flex; gap: 14px; font-size: .8125rem; letter-spacing: .08em; }
.langs button { color: var(--text3); transition: color .2s; }
.langs button:hover, .langs button[aria-pressed="true"] { color: var(--text); }

/* every line sits in the same place; ui.js reveals it word by word as the story plays. A line is only read: the Brain's
   stay in the page, unseen, while a chapter plays, and must not take the pointer from a chapter's own controls under
   them (Self-Evolution's slider) */
.lines p, .tview .tline { position: absolute; left: 50%; top: 80svh; transform: translate(-50%, -50%); width: min(90vw, 980px); text-align: center;
  font-size: clamp(1.5rem, min(4vw, 5.6svh), 3.2rem); font-weight: 450; letter-spacing: -0.04em; line-height: 1.08; text-wrap: balance;
  opacity: 0; pointer-events: none; }
.word { display: inline-block; white-space: pre; }

/* a chapter's words over its scene (story/lines.js): the line as the Brain's, each word coming in
   as theirs do; in the Turbos, Huber's name over its building. The whole screen is the chapter's window as the visitor
   flies in (flight.js); without WebGL it is the chapter, on the page's dark */
.tview { position: absolute; inset: 0; pointer-events: none; }
.flat .tview { background: var(--bg); }
.tview .tline { opacity: 1; }
.tview .word { animation: word-in .5s var(--ease) backwards; }
@keyframes word-in { from { opacity: 0; transform: translateY(.4em); filter: blur(6px); } }
.tview .tag { position: absolute; left: 0; top: 0; width: max-content; padding: .35em .7em; font-size: .8125rem; line-height: 1.3;
  color: var(--text); background: color-mix(in srgb, var(--haze) 80%, transparent); border: 1px solid var(--line-near);
  border-radius: .6em; opacity: 0; will-change: transform, opacity; }
/* a name pinned to the world (turbos/pins.js): the systems' and the Brain's quietly, Huber's ringed in orange while the
   Turbo has seen it; the Turbo's own name over it */
.tview .tag.quiet { padding: 0; background: none; border: 0; font-size: .75rem; font-weight: 500; letter-spacing: .14em;
  text-transform: uppercase; color: var(--text3); }
.tview .tag.hot { border-color: var(--orange); transition: border-color .4s var(--ease); }
/* your approval, over the Turbo */
.tview .tag.ok { margin-top: calc(-26 * var(--u)); }
.tview .tname { position: absolute; left: 0; top: 0; margin: calc(-26 * var(--u)) 0 0; width: max-content; opacity: 0;
  font-weight: 500; font-size: max(15px, calc(17 * var(--u))); color: var(--text); will-change: transform, opacity;
  /* a Turbo's name stands over buildings and their lit windows */
  text-shadow: 0 0 .5em var(--bg), 0 0 .2em var(--bg); }

/* the dashboard's glass, as the prototype's: --u is one unit of a 1280 × 800 frame */
.tview { --u: min(calc(100vw / 1280), calc(100svh / 800)); }
/* hidden, a card is gone for a screen reader too, once it has faded */
.tview .fade { opacity: 0; visibility: hidden; transition: opacity .5s var(--ease), visibility 0s .5s; }
.tview .fade.on { opacity: 1; visibility: visible; transition: opacity .5s var(--ease); }
.tview .glass { position: absolute; border: 1px solid var(--line-near); border-radius: calc(14 * var(--u));
  background: color-mix(in srgb, var(--haze) 82%, transparent); backdrop-filter: blur(6px);
  box-shadow: 0 0 calc(40 * var(--u)) color-mix(in srgb, var(--orange) 12%, transparent), inset 0 1px 0 color-mix(in srgb, var(--letter) 5%, transparent); }
.tview small { display: block; font-size: calc(12 * var(--u)); font-weight: 500; letter-spacing: .14em; text-transform: uppercase; color: var(--text3); }

/* the goal, typed, then drawn into the Turbo (turbos/dashboard.js) */
.tgoal { left: 7%; top: calc(440 * var(--u)); transform: translateY(-50%); width: calc(560 * var(--u)); padding: calc(14 * var(--u)) calc(18 * var(--u)); }
.tgoal small { margin-bottom: calc(4 * var(--u)); }
.tgoal.into { border-color: transparent; background: none; box-shadow: none; backdrop-filter: none; }
.tgoal.into small { visibility: hidden; }
/* it wraps where the card is narrower than the sentence (a phone held upright) */
.goal-text { display: inline-block; max-width: 100%; min-height: 1.2em; font-size: calc(20 * var(--u)); line-height: 1.3; color: var(--text); transform-origin: 0 50%; }
.caret { display: inline-block; width: 1px; height: 1em; vertical-align: -.15em; background: var(--text); margin-left: 2px; animation: blink 1s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }

/* the Turbo's draft: to all customers without the Brain, to Huber with it, each field with where it comes from */
.tdraft { right: calc(44 * var(--u)); top: 17svh; width: calc(450 * var(--u)); padding: calc(14 * var(--u)) calc(20 * var(--u));
  display: grid; gap: calc(10 * var(--u)); font-size: calc(15 * var(--u)); line-height: 1.3; }
.tdraft .head { font-size: calc(12 * var(--u)); font-weight: 500; letter-spacing: .12em; text-transform: uppercase; color: var(--text2); }
.tdraft .subject { font-size: calc(17 * var(--u)); color: var(--text); padding-bottom: calc(10 * var(--u)); border-bottom: 1px solid var(--line-far); }
.tdraft .fields { display: grid; grid-template-columns: auto 1fr auto; gap: calc(8 * var(--u)) calc(14 * var(--u)); align-items: baseline; }
.tdraft .row { display: contents; }
.tdraft .k { font-size: calc(13 * var(--u)); color: var(--text3); }
.tdraft .src { font-size: calc(12 * var(--u)); color: var(--text3); display: flex; align-items: center; gap: .45em; justify-self: end;
  white-space: nowrap; visibility: hidden; }
.tdraft .src::before { content: ""; width: .55em; height: .55em; border-radius: 50%; background: var(--orange); }
.tdraft .was { color: var(--text2); }
.tdraft .now { display: none; }
.tdraft .on .was { display: none; }
.tdraft .on .now { display: inline; animation: fill-in .6s var(--ease); }
.tdraft .fill.on .now { box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--orange) 85%, transparent); }
.tdraft .row:has(.fill.on) .src { visibility: visible; animation: fill-in .6s var(--ease); }
@keyframes fill-in { from { opacity: 0; } }

/* the approval: the button, and beside it whose turn it is. Once the time stands the status turns orange and nudges,
   and soon the button pulses: this is no video, the click is the visitor's */
.tdraft .actions { display: flex; align-items: center; gap: calc(16 * var(--u)); font-size: calc(13 * var(--u)); }
.tdraft .actions.on { pointer-events: auto; }
.approve { padding: calc(7 * var(--u)) calc(20 * var(--u)); border-radius: 999px; background: var(--orange); color: var(--bg);
  font-weight: 550; font-size: calc(15 * var(--u)); white-space: nowrap; transition: background-color .3s, color .3s, box-shadow .3s; }
.approve:hover { box-shadow: 0 0 calc(24 * var(--u)) color-mix(in srgb, var(--orange) 60%, transparent); }
.approve[aria-disabled="true"] { cursor: default; background: var(--line-far); color: var(--text2); box-shadow: none; }
.approve .done, .approve[aria-disabled="true"] .ask { display: none; }
.approve[aria-disabled="true"] .done { display: inline; }
.approve.hint { animation: hint 1.6s var(--ease) 1.2s infinite; }
@keyframes hint { 0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--orange) 70%, transparent); } 60% { box-shadow: 0 0 0 calc(14 * var(--u)) transparent; } }
.tdraft .status { display: inline-block; color: var(--text3); }
.tdraft .status.nudge { color: var(--orange); animation: nudge 1.6s var(--ease) .6s infinite; }
.tdraft .status.nudge::before { content: "← " / ""; }
@keyframes nudge { 30% { transform: translateX(calc(-5 * var(--u))); } 60% { transform: none; } }

/* the Self-Evolution chapter (self-evolution/self-evolution.js), drawn in 2D: its view covers the page's own picture
   once the arm is open, and only the slider takes the pointer */
.tview.se { background: var(--bg); }
.se-canvas, .se-layer { position: absolute; inset: 0; width: 100%; height: 100%; }
/* the pieces of the company the software cuts off: labelled cards, so it is clear before any word what falls away;
   .lost greys one out while it lies beside the window */
.se-piece { position: absolute; left: 0; top: 0; display: flex; align-items: center; gap: 8px; margin: 0; padding: 7px 12px 7px 10px;
  border: 1px solid color-mix(in srgb, var(--text) 55%, transparent); border-radius: 9px; white-space: nowrap;
  background: color-mix(in srgb, var(--haze) 94%, transparent); color: var(--letter); font-size: .8125rem; font-weight: 500; letter-spacing: -0.005em;
  box-shadow: 0 10px 26px color-mix(in srgb, var(--bg) 85%, transparent), 0 0 18px color-mix(in srgb, var(--text) 14%, transparent);
  transition: color .6s, border-color .6s, box-shadow .6s, filter .6s; }
/* a small page with a folded corner: something written down */
.se-piece::before { content: ""; flex: none; width: 10px; height: 13px; border-radius: 2px; background: currentColor; opacity: .85;
  clip-path: polygon(0 0, 65% 0, 100% 28%, 100% 100%, 0 100%); }
.se-piece.lost { color: var(--text3); border-color: var(--line-near); border-style: dashed; box-shadow: 0 6px 16px color-mix(in srgb, var(--bg) 70%, transparent); filter: saturate(0); }
/* the approver, one of the company's people: blue is the person a chapter is about (spec §1), orange stays Keeplo's.
   It glows while it gives a yes, and the check lands where the yes goes */
.se-approver { position: absolute; left: 0; top: 0; display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%;
  background: var(--tom-core); border: 2px solid var(--letter); box-shadow: 0 0 0 0 color-mix(in srgb, var(--tom-core) 60%, transparent);
  opacity: 0; transition: opacity .6s var(--ease), box-shadow .3s; }
.se-approver.on { opacity: 1; }
.se-approver.giving { box-shadow: 0 0 0 7px color-mix(in srgb, var(--tom-core) 35%, transparent), 0 0 24px color-mix(in srgb, var(--tom-core) 80%, transparent); }
.se-approver svg { width: 18px; height: 18px; fill: var(--letter); }
.se-tick { position: absolute; left: 0; top: 0; display: grid; place-items: center; width: 24px; height: 24px; margin: 0; border-radius: 50%;
  background: var(--tom-core); color: var(--letter); font-size: .8125rem; font-weight: 600;
  box-shadow: 0 0 14px color-mix(in srgb, var(--tom-core) 70%, transparent); }
/* the one interaction, where the line stands, and above the footer; the line is quiet while it shows */
.se-time { position: absolute; left: 50%; bottom: calc(var(--edge) + 40px); transform: translateX(-50%); width: min(90vw, 620px); text-align: center; pointer-events: auto; }
.se-time p { margin: 0; }
.se-time-hint { font-size: clamp(1.15rem, min(2.6vw, 3.6svh), 1.9rem); font-weight: 450; letter-spacing: -0.03em; color: var(--text); text-wrap: balance; }
.se-time .se-time-now { margin-top: 10px; font-size: .9375rem; font-weight: 500; color: var(--orange); font-variant-numeric: tabular-nums; }
.se-time-label { display: block; font-size: .6875rem; letter-spacing: .14em; text-transform: uppercase; color: var(--text3); }
.se-time input { width: 100%; margin: 4px 0 2px; appearance: none; -webkit-appearance: none; background: none; height: 28px; cursor: grab; }
.se-time input:disabled { cursor: default; }
.se-time input::-webkit-slider-runnable-track { height: 2px; background: linear-gradient(to right, var(--orange), var(--line-top)); border-radius: 2px; }
.se-time input::-moz-range-track { height: 2px; background: linear-gradient(to right, var(--orange), var(--line-top)); }
.se-time input::-webkit-slider-thumb { -webkit-appearance: none; width: 22px; height: 22px; margin-top: -10px; border-radius: 50%; background: var(--orange);
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--orange) 22%, transparent), 0 0 18px color-mix(in srgb, var(--orange) 60%, transparent); }
.se-time input::-moz-range-thumb { width: 22px; height: 22px; border: 0; border-radius: 50%; background: var(--orange); }
.se-next { margin-top: 12px; padding: 8px 18px; border: 1px solid var(--orange); border-radius: 999px; color: var(--text); font-size: .875rem; }
.se-next::after { content: " →" / ""; }
.se-next:hover { background: color-mix(in srgb, var(--orange) 18%, transparent); }
/* the outlook, marked so nobody takes it for today */
.se-outlook { position: absolute; left: 50%; top: calc(var(--edge) + 4px); transform: translateX(-50%); margin: 0; padding: 4px 14px;
  border: 1px dashed var(--text3); border-radius: 999px; font-size: .75rem; letter-spacing: .14em; text-transform: uppercase; color: var(--text2); }
/* the chapter's name and its line, before the way out */
.se-closing { position: absolute; left: 50%; bottom: 16svh; transform: translateX(-50%); width: min(90vw, 900px); text-align: center; }
.se-closing h2 { margin: 0; font-size: clamp(2.2rem, 6vw, 4.4rem); font-weight: 500; letter-spacing: -0.045em; line-height: 1; color: var(--letter); }
.se-closing p { margin: .7em 0 0; font-size: clamp(1rem, 2vw, 1.35rem); color: var(--text2); letter-spacing: -0.01em; }

/* a screen held upright: the draft and the goal card across the top, the scene between them and the line */
@media (max-aspect-ratio: 9/10) {
  .tview { --u: calc(100vw / 440); }
  /* the scene stands between the draft and the line: the draft keeps short, the Turbo's name already stood over it */
  .tdraft { left: var(--edge); right: var(--edge); width: auto; top: 16svh; padding: calc(10 * var(--u)) calc(16 * var(--u)); gap: calc(6 * var(--u)); }
  .tdraft .head { display: none; }
  .tdraft .subject { padding-bottom: calc(6 * var(--u)); }
  .tdraft .fields { row-gap: calc(5 * var(--u)); }
  .tgoal { left: var(--edge); right: var(--edge); width: auto; top: 25svh; }
}
/* a phone held sideways: little height, so the type follows the height. Self-Evolution's shape stands left of the
   middle (self-evolution/shape.js, the same query), its slider and its name beside it */
@media (max-height: 460px) and (min-aspect-ratio: 9/10) {
  .tview { --u: calc(100svh / 520); }
  .tgoal { top: 32svh; }
  .se-time, .se-closing { left: auto; right: var(--edge); top: 40svh; bottom: auto; width: min(44vw, 380px); transform: translateY(-50%); }
  .se-time-hint { font-size: 1.05rem; }
  .se-closing h2 { font-size: 2.2rem; }
}

/* what three of the people at work know: a quiet label over each one's head, placed by ui.js */
.tags .tag { position: absolute; left: 0; top: 0; width: max-content; max-width: min(80vw, 340px); padding: .35em .7em;
  font-size: .8125rem; line-height: 1.3; color: var(--text); background: color-mix(in srgb, var(--haze) 80%, transparent);
  border: 1px solid var(--line-near); border-radius: .6em; opacity: 0; pointer-events: none; will-change: transform, opacity; }
/* a process's name, on its orange arc over the Brain */
.tags .flow { border-color: color-mix(in srgb, var(--orange) 60%, var(--line-near)); }

/* Keeplo's last answer as it lifts from where Tom's phone stood to the closing line. --k scales it as one piece (its
   type and every length are in em), so its lines break the same way all the way */
.card { position: absolute; left: 0; top: 0; --k: 1; font-size: calc(13px * var(--k)); line-height: 1.4;
  width: calc(clamp(260px, 26vw, 340px) * var(--k)); padding: .95em; display: grid;
  opacity: 0; pointer-events: none; will-change: transform, opacity; }
/* a message in Tom's chat and in the card: his in his blue, Keeplo's with an orange edge */
.card-question { justify-self: end; max-width: 85%; background: var(--tom-core); color: var(--letter); padding: .5em .75em; border-radius: .85em .85em .25em .85em; }
.card-answer { --bubble: 1; max-width: 92%; padding: .5em .75em; color: var(--text);
  background: color-mix(in srgb, var(--line-far) calc(100% * var(--bubble)), transparent);
  border-left: 2px solid color-mix(in srgb, var(--orange) calc(100% * var(--bubble)), transparent); border-radius: .25em .85em .85em .25em; }

/* chapter 8: the colleagues' questions over the heads of those who ask; the tail points at them */
.say { position: absolute; left: 0; top: 0; opacity: 0; pointer-events: none; white-space: nowrap;
  font-size: 14px; line-height: 1.35; color: var(--text); padding: .55em .85em; border-radius: .95em;
  background: color-mix(in srgb, var(--haze) 80%, var(--line-far)); border: 1px solid var(--line-near); will-change: transform, opacity; }
.say::after { content: ""; position: absolute; left: 50%; bottom: -.42em; width: .8em; height: .8em; background: inherit;
  border: inherit; border-top: 0; border-left: 0; transform: translateX(-50%) rotate(45deg); }

/* Tom's phone: his Teams chat with Keeplo, beside the Brain so the answer can be seen coming down into it. On a wide
   screen it stands right of the middle and the Brain left; on a tall one below the Brain. A soft dark halo, not a
   dimmed screen, so the hall and the Brain stay in sight */
.tomui { position: absolute; inset: 0; pointer-events: none; visibility: hidden; --phone-x: 70%; }
.tom-phone { position: absolute; left: var(--phone-x); top: 12svh; margin-left: calc(clamp(300px, 27vw, 390px) / -2);
  width: clamp(300px, 27vw, 390px); height: min(60svh, 640px); border-radius: 2.2em;
  font-size: 15px; line-height: 1.42; transform-origin: 50% 50%; will-change: transform, opacity;
  background: color-mix(in srgb, var(--haze) 94%, transparent); border: 1px solid var(--line-near);
  box-shadow: 0 0 5em 2.5em color-mix(in srgb, var(--bg) 75%, transparent), 0 0 3em color-mix(in srgb, var(--tom-core) 18%, transparent),
    inset 0 1px 0 color-mix(in srgb, var(--letter) 6%, transparent); }
.tom-screen { position: absolute; inset: 1.1em; display: grid; grid-template-rows: auto 1fr; gap: .8em; }
.tom-msgs { display: flex; flex-direction: column; justify-content: flex-end; gap: .7em; overflow: hidden; }
/* a message is closed until tom.js opens it */
.tom-msgs > * { --open: 0; opacity: 0; max-height: calc(var(--open) * 9em); overflow: hidden; flex: none; }
.tom-msgs .card-question { align-self: flex-end; }
.tom-msgs .card-answer { align-self: flex-start; }
.tom-a2 { border-left-color: var(--text3); }
.tom-chip { align-self: flex-start; display: flex; align-items: center; gap: .5em; font-size: .88em; color: var(--text);
  padding: .35em .8em; border: 1px solid var(--orange); border-radius: 2em; }
.tom-chip::before { content: ""; width: .5em; height: .5em; border-radius: 50%; background: var(--orange); }
/* the line from the source, opened in the chat under its chip */
.tom-snip { align-self: stretch; display: grid; gap: .15em; padding: .55em .8em; font-size: .88em; border-radius: .6em;
  border: 1px solid var(--orange); background: color-mix(in srgb, var(--orange) 13%, transparent); }
.tom-snip span { color: var(--text2); }
.tom-snip b { font-weight: 500; color: var(--text); }
.tom-typing { align-self: flex-start; display: flex; align-items: center; gap: .6em; padding: .55em .8em; font-size: .88em;
  color: var(--text2); background: var(--line-far); border-radius: .25em .85em .85em .25em; }
.tom-contact { display: flex; align-items: center; gap: .7em; padding: .6em .75em; border: 1px solid var(--line-near); border-radius: .9em; }
.tom-contact .who { display: grid; flex: 1; line-height: 1.25; }
.tom-contact .who b { font-weight: 500; }
.tom-contact .who span { font-size: .82em; color: var(--text2); }
.tom-contact .write { font-size: .85em; padding: .35em .8em; border-radius: 1em; color: var(--letter); background: var(--line-far); }
.tom-dot { width: 1.7em; height: 1.7em; border-radius: 50%; display: block; flex: none;
  background: radial-gradient(circle, var(--letter) 0 30%, transparent 32%), color-mix(in srgb, var(--letter) 14%, transparent);
  box-shadow: 0 0 .7em color-mix(in srgb, var(--letter) 50%, transparent); }
/* the chat's head: who writes, and that it is Teams; no Teams logo (Microsoft's trademark rules) */
.tom-head { display: flex; align-items: center; gap: .7em; padding-bottom: .75em; border-bottom: 1px solid var(--line-far); }
.tom-head > span:last-child { display: grid; line-height: 1.25; }
.tom-head b { font-weight: 500; color: var(--text); }
.tom-head small { font-size: .78em; color: var(--text2); }
.tom-avatar { width: 2.2em; height: 2.2em; border-radius: .55em; flex: none; }
/* the trademark notice, bottom middle, while the phone is open */
.tom-marks { position: absolute; left: 50%; bottom: 1.5rem; transform: translateX(-50%); margin: 0; opacity: 0;
  width: max-content; max-width: calc(100vw - 2rem); text-align: center; font-size: 11px; color: var(--text3); }
/* "Keeplo denkt nach": the K sent in Morse while Keeplo works on an answer (keeplo-company design/logo/marke/animation).
   ITU-R M.1677-1 timing: one unit 120 ms, dash 3, dot 1, a unit's gap inside the letter, the seven-unit word gap
   before K repeats (16 units, 1.92 s). Lit: dash 0-360 ms, dot 480-600 ms, dash 720-1080 ms, each with a 40 ms edge */
.keeplo-denkt { display: inline-flex; align-items: center; gap: 6px; flex: none; }
.keeplo-denkt i { display: block; height: 6px; border-radius: 3px; background: var(--text2); animation: 1.92s linear infinite; opacity: .25; }
.keeplo-denkt .d1, .keeplo-denkt .d2 { width: 18px; }
.keeplo-denkt .dt { width: 6px; background: var(--orange); animation-name: keeplo-punkt; }
.keeplo-denkt .d1 { animation-name: keeplo-strich-1; }
.keeplo-denkt .d2 { animation-name: keeplo-strich-2; }
@keyframes keeplo-strich-1 { 0% { opacity: .25; } 2.1%, 18.75% { opacity: 1; } 20.8%, 100% { opacity: .25; } }
@keyframes keeplo-punkt { 0%, 25% { opacity: .25; } 27.1%, 31.25% { opacity: 1; } 33.3%, 100% { opacity: .25; } }
@keyframes keeplo-strich-2 { 0%, 37.5% { opacity: .25; } 39.6%, 56.25% { opacity: 1; } 58.3%, 100% { opacity: .25; } }

/* the closing; without script this is the whole page: the wordmark, the h1 and the footer */
.closing { position: absolute; left: 50%; top: calc(var(--mark-mid) - var(--mark-w) / 7.7); transform: translateX(-50%); width: min(92vw, 900px);
  display: grid; justify-items: center; gap: 18px; text-align: center; }
.mark { width: var(--mark-w); --ink: var(--letter); --accent: var(--orange); }
.mark svg { display: block; width: 100%; height: auto; overflow: visible; }
h1 { font-size: clamp(1.35rem, 2.8vw, 2.1rem); font-weight: 400; letter-spacing: -0.03em; line-height: 1.2; color: var(--text); text-wrap: balance; }
/* with script the 3D wordmark stands in the svg's place (flat mode draws the svg), and the line arrives with the story */
.js .mark { visibility: hidden; }
.js .flat .mark { visibility: visible; }
.js .closing { pointer-events: none; }
.js .closing h1 { opacity: 0; }
.footer { position: absolute; left: var(--edge); right: var(--edge); bottom: var(--edge); display: grid; grid-template-columns: 1fr auto;
  align-items: end; gap: 16px; color: var(--text3); font-size: .8125rem; letter-spacing: .01em; }
.controls { justify-self: end; display: flex; gap: 22px; }
.controls :is(a, button), .legal-links a { color: var(--text2); text-decoration: underline; text-decoration-color: var(--line-top); text-underline-offset: .3em;
  transition: color .2s, text-decoration-color .2s; }
.controls :is(a, button):hover, .legal-links a:hover { color: var(--text); text-decoration-color: var(--text2); }
/* the legal links stand in the middle of the page, under the hub and on the page without script. In a chapter, or
   once the Brain's story has left the hub's picture, they go, so nothing in the story has to make room for them;
   "Übersicht" leads back to them in one step */
.legal-links { position: absolute; left: 50%; bottom: 0; transform: translateX(-50%); display: flex; gap: 22px; }
body:is([data-route]:not([data-route="hub"]), :not([data-chapter="0"])) .legal-links { display: none; }

/* Impressum and Datenschutz: plain reading pages in the site's type and colours, scrolling like any page */
body.legal { height: auto; overflow: auto; padding: var(--edge); }
.legal :is(header, main, footer) { max-width: 42rem; margin: 0 auto; }
.legal main { padding: clamp(32px, 8vw, 72px) 0; }
.legal h1 { margin-bottom: 1rem; }
.legal h2 { font-size: 1.0625rem; font-weight: 500; letter-spacing: -0.01em; color: var(--text); margin: 2.4em 0 .5em; }
.legal h3 { font-size: 1rem; font-weight: 500; color: var(--text); margin: 1.6em 0 .4em; }
.legal main :is(p, ul) { margin: 0 0 1em; color: var(--text2); overflow-wrap: break-word; }
.legal main ul { padding-left: 1.2em; }
.legal footer { display: flex; gap: 22px; font-size: .8125rem; }
.legal a { color: var(--text); text-decoration: underline; text-decoration-color: var(--line-top); text-underline-offset: .3em;
  transition: color .2s, text-decoration-color .2s; }
.legal a:hover { text-decoration-color: var(--text2); }
.legal :is(header, footer) a { color: var(--text2); }
.legal :is(header, footer) a:hover, .legal footer a[aria-current] { color: var(--text); }

.paused #pause .when-running, body:not(.paused) #pause .when-paused { display: none; }

/* paused: everything that moves on its own stands still */
.paused *, .paused *::before, .paused *::after { animation-play-state: paused !important; }

@media (max-width: 640px) {
  :root { --mark-w: min(86vw, calc((100svh - 300px) * 3.79)); }
  /* little room beside the K: the names stand at their parts without the hairlines, tracked less */
  .hub-names { --lead: 0; --gap: 1; }
  /* "Offboarding" is one word and cannot break: on the narrowest phones the names shrink with the screen */
  .hub-link { font-size: min(.6875rem, 2.9vw); letter-spacing: .1em; }
  /* the line keeps to one line on the narrowest phones too, inside the page's edge */
  .hub-text { font-size: min(1.3rem, 5.6vw); }
  .hub-link::before { display: none; }
  .footer { font-size: .75rem; row-gap: 12px; }
  /* no room between the status line and Pause: the links take a centred row of their own below them */
  .legal-links { position: static; transform: none; grid-row: 2; grid-column: 1 / -1; justify-self: center; }
  .lines p, .tview .tline { top: 72svh; }
  .scrim { background: linear-gradient(to bottom, color-mix(in srgb, var(--bg) 72%, transparent), transparent 14%, transparent 56%,
    color-mix(in srgb, var(--bg) 88%, transparent) 76%); }
}
@media (max-height: 460px) {
  /* a landscape phone: a smaller mark and tighter closing, so the line stays above the footer */
  :root { --mark-w: min(56vw, calc((100svh - 240px) * 3.79)); --mark-mid: 32svh; --k-w: 90px; --edge: 14px; }
  .closing { gap: 10px; }
  /* the shots keep their subjects within 10-68% of the height; the line starts below that band and grows down
     towards the footer */
  .lines p, .tview .tline { top: 69svh; transform: translateX(-50%); font-size: clamp(1.2rem, 3.4vw, 2rem); }
  /* the card's smaller, wider form, so it fits between the clock band and the line */
  .card { font-size: calc(11px * var(--k)); width: calc(clamp(280px, 40vw, 340px) * var(--k)); padding: .8em; }
  /* Tom's phone, shorter and smaller, above the line; its notice under the footer, the one free band */
  .tom-phone { top: 10svh; height: 56svh; font-size: 12px; }
  .tom-marks { bottom: 0; font-size: 10px; line-height: 1.2; }
  .hub-text { top: calc(var(--k-w) * 80 / 134 + 16px); }
}
/* a tall screen: the phone below the Brain, shorter, so it stays clear of the line under it */
@media (orientation: portrait) {
  .tomui { --phone-x: 50%; }
  .tom-phone { top: 35svh; height: min(32svh, 480px); font-size: 14px; }
  .tom-marks { bottom: 3.6rem; }
}
@media (prefers-reduced-motion: reduce) {
  .keeplo-denkt i { animation-name: none; opacity: .6; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
}
