:root {
  --bg: #f3f0e8;              /* updated from the scene as night falls */
  --fg: #141414;
  --sans: "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, monospace;
  --gutter: clamp(16px, 4vw, 48px);
  /* a stop's photo before it is opened (.space-photo): 24vw and 340 px at most until the user's "enlarge the
     images" (2026-10-28) */
  --photo-thumb: clamp(120px, 32vw, 480px);
  /* the deck's type in its split view (deck.css), a screen to the view, sized for its tallest screen to fit the
     height its 112 px of padding leave; and the user's sentences, half as large again: the deck's ("Last year we
     ran 30+ events") and the terminal's intro alike (the user, 2026-10-28: "for the intro use the same size for
     the typo as for Last year") */
  --split-type: clamp(12px, min(1.5vw, calc((100svh - 112px) / 45)), 18px);
  --sentence-type: calc(1.5 * var(--split-type));
  /* the terminal's own type (.terminal): its prompts, and the password's on the way in (.access) */
  --terminal-type: clamp(14px, 1.5vw, 19px);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
}

html.to-terminal { --bg: #000; --fg: #f3f0e8; }   /* loading for the terminal (index.html), until the scene sets them */
/* and the header (the mark and the switches) not there yet: main.js fades it in, then the terminal types */
html.is-arriving .masthead,
html.is-arriving .visit { opacity: 0; }
/* and nothing else of the page until main.js has built it and taken it to its end (body.ready): before
   then the walk has no length, and the rooms page stood low on the black (its heading then, "After the
   stage"), with the plan's loading line in the corner (the user, 2026-10-27); a failure still says so */
html.is-arriving body:not(.ready) .rooms,
html.is-arriving body:not(.ready):not(.failed) .status { visibility: hidden; }
html.lenis, html.lenis body { height: auto; }
html.is-held { overflow: hidden; }   /* a touch's scrolling held at a photo (photoHold.js) */
.lenis.lenis-smooth { scroll-behavior: auto !important; }

#scene {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  display: block;
}

/* #track's height is set from TIMELINE_PAGES (config.js) at start-up */

.masthead {
  position: fixed;
  z-index: 7;   /* over the rooms page too */
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 18px var(--gutter);
  font: 500 11px/1.3 var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  pointer-events: none;
}
.masthead .mark { font-weight: 700; }

/* The visit's switches (visit.js): the tour (tour.js), photos opening by themselves, music, a voice. Small
   squares in the drawing's line, a pressed one inverted like the stop numbers. visit.js places them: in the plan's title
   block, then in the masthead; they glide between the two. */
.visit {
  position: fixed;
  z-index: 8;   /* over the masthead, which takes no clicks */
  display: flex;
  gap: 4px;
  transition: left 0.6s ease, top 0.6s ease;
}
.visit__switch,
.visit__logo,
.deck__icon,
.visit__home,
.logo-home {   /* the row's logo and its way home, the deck page's back and download (deck.css), the logo screen's way home (logo.css), drawn the same */
  width: 26px;
  height: 26px;
  padding: 4px;
  border: 1px solid var(--fg);
  background: transparent;
  color: var(--fg);
  cursor: pointer;
}
.visit__switch svg,
.deck__icon svg,
.visit__home svg,
.logo-home svg {
  display: block;
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: square;
}
.visit__switch .visit__eyes { fill: currentColor; stroke: none; }   /* the voice's eyes are shapes, not lines (eyes.js) */
/* the logo (index.html), a link to the logo screen: its lines 1 px like the icons', as at 16 px across the
   logo's own would be half a pixel */
.visit__logo svg { display: block; width: 100%; height: 100%; overflow: visible; }
.visit__logo :is(line, circle) { vector-effect: non-scaling-stroke; stroke-width: 1px; }
/* in the row, 2 px smaller than the deck's, their icons as large (the user, 2026-10-27): with the tour's
   button the row is 204 px, and still fits the title block's last row on a laptop's screen (204 px of room
   at 1280 x 720) */
.visit :is(.visit__switch, .visit__logo, .visit__home),
.logo-home { width: 24px; height: 24px; padding: 3px; }   /* the logo screen's way home, at the end of its row */
/* the way home (index.html) only in the header, 232 px with it: in the title block, where the row docks on the
   plan view (visit.js, is-docked), it would leave the row too long for its 204 px at 1280 x 720 */
.visit.is-docked .visit__home { display: none; }
.visit__switch[aria-pressed="true"] { background: var(--fg); color: var(--bg); }
/* the tour's: a play while it is off, a pause while it plays */
.visit__tour[aria-pressed="true"] .visit__play,
.visit__tour:not([aria-pressed="true"]) .visit__pause { display: none; }
.visit__switch:disabled { cursor: default; }   /* drawn like the others (the user, 2026-10-25): its tooltip says why it is off */
/* The music's level, after its switch (musicControls.js): a plain line with a round on it for its cursor,
   lines and round only (the user, 2026-10-28; it was a hairline drawn heavier up to a square cap), live
   while the music is on. 36 px in the row (it was 64, then 40): with the logo and the tour in it, the row
   still fits the title block's last row on a laptop's screen (above). */
.visit__level {
  --line: linear-gradient(var(--fg), var(--fg)) 0 50% / 100% 1px no-repeat;
  appearance: none;
  -webkit-appearance: none;
  width: 36px;
  height: 24px;
  margin: 0;
  background: transparent;
  cursor: pointer;
}
.visit__level::-webkit-slider-runnable-track { height: 24px; background: var(--line); }
.visit__level::-moz-range-track { height: 24px; background: var(--line); }
.visit__level::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 10px;
  height: 10px;
  margin-top: 7px;   /* in the middle of the track's 24 px */
  border: 0;
  border-radius: 50%;
  background: var(--fg);
}
.visit__level::-moz-range-thumb { width: 10px; height: 10px; border: 0; border-radius: 50%; background: var(--fg); }
.visit__level:disabled,
.visit__track:disabled { opacity: 0.35; }   /* the music's own controls, dimmed while it is off */
.visit__level:disabled { cursor: default; }
/* not on a phone: the masthead has no room for it beside the mark, and there the phone's own buttons set the
   level (an iPhone ignores a page's volume altogether) */
@media (max-width: 600px) {
  .visit__level { display: none; }
}
/* nor, on the narrowest phones, the next track: with the tour's button the row ran 23 px over the mark at
   320 px wide (the user, 2026-10-28: hidden at 360 px and under); with the way home too, 4 px from it at 375,
   so 380 px and under now (32 px clear at 375) */
@media (max-width: 380px) {
  html:not(.on-logo) .visit .visit__track { display: none; }
}
.visit:not(.is-placed) { visibility: hidden; }   /* until visit.js first places them */
.visit.is-instant { transition: none; }
/* The logo screen open over the walkthrough (logo.css, logoScreen.js): the page held still under it, and of
   the row only the music, its switch, next track and level, in the screen's top corner 12 px in, white on
   its black (the user, 2026-10-28: "so i can play music during the intro"; the same controls as the walk's,
   so they cannot tell two stories), and after them, a step apart, the screen's way home (logo.css) */
html.on-logo { overflow: hidden; }
html.on-logo .visit {
  --bg: #000;
  --fg: #ffffff;
  z-index: 9;               /* over the logo screen */
  left: auto !important;    /* over where visit.js places the row */
  right: 48px;              /* the way home's 24 px, 12 px in, and 12 px between */
  top: 12px !important;
  transition: none;
  visibility: visible;
}
html.on-logo .visit > :not([data-mode="music"], .visit__track, .visit__level) { display: none; }
html.on-logo .visit__level { width: 64px; }   /* nothing holds it shorter there (in the walk, the title block) */
@media (prefers-reduced-motion: reduce) {
  .visit { transition: none; }
}

.status {
  position: fixed;
  left: var(--gutter);
  bottom: var(--gutter);
  margin: 0;
  font: 400 12px/1.4 var(--mono);
  letter-spacing: 0.08em;
}
body.ready .status { display: none; }
body.failed .status { color: #b00020; }

.caption {
  position: fixed;
  left: var(--gutter);
  bottom: var(--gutter);
  max-width: min(560px, calc(100vw - 2 * var(--gutter)));
  opacity: 0;
  pointer-events: none;
}
.caption p { margin: 0; }

/* the title in the logo's block letters, drawn in ink on a canvas (blockLetters.js, drawBlockTitle) */
.caption--title h1 { margin: 0; }
.block-title {
  display: block;
  width: clamp(280px, 40vw, 520px);   /* clear of the plan beside it */
  max-width: 100%;
  height: auto;
}
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
/* the room's name in the title's own type (bold sans, tight), not the mono of the lines under it */
.caption--stop .stop,
.room .stop {
  display: flex;
  align-items: center;
  gap: 14px;
  font: 700 clamp(30px, 4.6vw, 56px)/1 var(--sans);
  letter-spacing: -0.03em;
  margin-bottom: 10px;
}
/* beside the name's first line, centred on it (the name's line is 1 em, the square 0.6 em: 0.2 em, 0.4 of its own
   font, above it), so a name wrapped on a phone keeps it there rather than between its lines */
.caption--stop .num {
  display: inline-grid;
  place-items: center;
  align-self: flex-start;
  margin-top: 0.4em;
  width: 1.2em;
  height: 1.2em;
  font-size: 0.5em;
  background: var(--fg);
  color: var(--bg);
}
/* the digit's line trimmed to the digit itself (cap height to baseline), so the square centres the digit,
   not the font's whole line box with its room for accents and descenders, which sat it low */
.caption--stop .num > span {
  line-height: 1;
  text-box: trim-both cap alphabetic;
}
.caption--stop p,
.room__legend { font: 400 13px/1.5 var(--mono); letter-spacing: 0.06em; }
/* a caption's lines, a stop's name with them, wrap before the corner photo's column (on a phone they would run
   under it) */
.caption--stop p { max-width: calc(100vw - 2 * var(--gutter) - var(--photo-thumb) - 16px); }

/* a halo in the page's own colour: lost on the drawing, it keeps the text legible over bright
   footage (the Box truss runs right under the masthead) */
.masthead,
.caption { text-shadow: 0 0 2px var(--bg), 0 0 10px var(--bg); }
.caption--stop .num { text-shadow: none; }
/* the lines under a stop's name, and a room's legend, in black on a white box each, the number square's colours,
   so they stand out on the drawing, the footage and the photos (the user, 2026-10-28: the stops', then the
   rooms'); no halo, which would blur dark letters on the white. Each unfolds and types itself out as its stop
   arrives or its room faces the viewer (typedBoxes.js) */
.caption--stop p:not(.stop),
.room__legend {
  width: fit-content;
  padding: 2px 6px;
  background: var(--fg);
  color: var(--bg);
  text-shadow: none;
}
.caption--stop p:not(.stop) + p,
.room__legend + .room__legend { margin-top: 4px; }

/* A stop's photos of the real space (spacePhoto.js): a framed thumbnail in the bottom-right corner that a
   click grows out of that corner into a large view, the photo inside easing back from a slight zoom as its
   frame opens, like a camera settling. With more than one photo, an arrow under the frame swaps them, the
   frame easing to each one's shape. spacePhoto.js sets --photo-aspect (the current photo's width over height)
   and --photo-px (its width in pixels: never shown larger than it is). */
.space-photo {
  --photo-ease: cubic-bezier(0.16, 1, 0.3, 1);
  position: fixed;
  right: var(--gutter);
  bottom: var(--gutter);
  z-index: 5;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  opacity: 0;
  pointer-events: none;
}
.space-photo.is-shown { pointer-events: auto; }
.space-photo__frame {
  /* the large view: the screen's width less its margins, 1040 px at most, the photo's own width at most, and
     short enough to leave the masthead and the arrow row clear */
  --photo-open: min(calc(100vw - 2 * var(--gutter)), 1040px, var(--photo-px), calc((100vh - 170px) * var(--photo-aspect)));
  --photo-width: var(--photo-thumb);
  position: relative;
  width: var(--photo-width);
  height: calc(var(--photo-width) / var(--photo-aspect));
  padding: 0;
  border: 1px solid var(--fg);
  background: #000;
  overflow: hidden;
  cursor: zoom-in;
  transition: width 750ms var(--photo-ease), height 750ms var(--photo-ease);
}
.space-photo.is-open .space-photo__frame { --photo-width: var(--photo-open); cursor: zoom-out; }
/* In the visit's photo mode, and on the tour, the scroll sizes the frame (spacePhoto.js sets --grow, 0..1,
   eased): it eases with the scroll alone, and its large view stops short of the stop's caption on the left
   (--caption-room), so the stop's name stays in view; on a phone the caption runs the width, and the photo
   may too (the user, 2026-10-28: grown to the full large view a click opens, they took too much). Closed by
   hand, it eases back on its own; opened by hand, it takes the full large view as ever. */
.space-photo { --caption-room: 400px; }
@media (max-width: 700px) {
  .space-photo { --caption-room: calc(-1 * var(--gutter)); }
}
.space-photo.is-scrubbed .space-photo__frame {
  --photo-grown: min(var(--photo-open), max(var(--photo-thumb), 100vw - 3 * var(--gutter) - var(--caption-room)));
  --photo-width: calc(var(--photo-thumb) + (var(--photo-grown) - var(--photo-thumb)) * var(--grow, 0));
  transition: none;
}
.space-photo.is-scrubbed.is-dismissed .space-photo__frame { transition: width 750ms var(--photo-ease), height 750ms var(--photo-ease); }
.space-photo.is-scrubbed.is-open .space-photo__frame {
  --photo-width: var(--photo-open);
  transition: width 750ms var(--photo-ease), height 750ms var(--photo-ease);
}
.space-photo.is-grown .space-photo__frame { cursor: zoom-out; }
.space-photo__frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 500ms ease, transform 900ms var(--photo-ease);
}
.space-photo__frame img.is-current { opacity: 1; }
.space-photo:not(.is-open) .space-photo__frame:hover img { transform: scale(1.04); }
.space-photo__frame img.is-settling { animation: photo-settle 900ms var(--photo-ease); }
@keyframes photo-settle { from { transform: scale(1.18); } to { transform: scale(1); } }
/* the corner mark, square like the stop numbers: open it, or close it */
.space-photo__frame::after {
  content: "↗";
  position: absolute;
  right: 0;
  bottom: 0;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  font: 700 12px/1 var(--mono);
  background: var(--fg);
  color: var(--bg);
}
.space-photo.is-open .space-photo__frame::after,
.space-photo.is-grown .space-photo__frame::after { content: "✕"; }
/* under the frame: which photo this is, and the arrow to the next */
.space-photo__nav {
  display: flex;
  align-items: center;
  gap: 10px;
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.14em;
  color: var(--fg);
  text-shadow: 0 0 2px var(--bg), 0 0 10px var(--bg);
}
.space-photo__next {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: var(--fg);
  color: var(--bg);
  font: 700 14px/1 var(--mono);
  cursor: pointer;
}
@media (prefers-reduced-motion: reduce) {
  .space-photo__frame, .space-photo__frame img { transition: none; }
  .space-photo__frame img.is-settling { animation: none; }
}

/* After the Stage: the rooms for the rest of the day, on a black page that rises over the end of the walk
   (the footage sinks into it). The view then stays on the screen while the rooms turn past on a ring,
   right to left, each its name over its photo (the user, 2026-10-25), with no heading (2026-10-27).
   Scrolling down the runway turns the ring (rooms.js), and each room's photo develops out of the black as
   it comes round to face the viewer, its lights first, its text following (rooms.js sets --in, 0..1). */
.rooms {
  position: relative;
  z-index: 6;   /* over the walk's captions and photos, under the masthead */
  padding-top: 70vh;
  background: linear-gradient(to bottom, transparent, #000 45vh);
  color: var(--fg);
}
/* what is scrolled while the view stays: a screen for the pinned view, and a screen and a half per turn of
   the ring (--turns, from rooms.js: each room in, and the last one away; it was one screen until the user's
   "switching from one to another too fast", 2026-10-28) */
.rooms__runway { height: calc(100svh + var(--turns) * 150vh); }
.rooms__pin {
  /* a room's width: inside the gutters, no wider than the smallest room photo's own pixels (--photo-max, from
     rooms.js: the green room's, 596 px), so none is shown larger than it is, and short enough for its photo (16:9
     at most), its name and its legend to fit the screen's height in its middle, clear of the masthead (360 px for
     those and a margin). It was three quarters of that photo, 447 px, as at full size and above the small ones had
     looked bad; the user asked for them larger on a laptop, then, shown as large as the screen let them (up to
     960 px), for less (2026-11-02: "reduce the size the quality is not good enough to be soo zoomed"). */
  --card: min(100% - 2 * var(--gutter), var(--photo-max), (100svh - 360px) * 16 / 9);
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;   /* the ring's rooms beyond the screen's sides */
}
/* the ring's frame, the whole screen: rooms.js sets its perspective, and places each room round the ring */
.rooms__track {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}
/* a room: its name over its photo and its line under it, a legend (the user, 2026-10-27), all three
   together in the screen's middle (the same day: they stood low, under the heading; then the whole block,
   not the photo alone) */
.room {
  --in: 0;
  --lit: clamp(0, (var(--in) - 0.45) / 0.55, 1);   /* its name, legend and frame: only as it comes to face the viewer */
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc((100% - var(--card)) / 2);
  width: var(--card);
  backface-visibility: hidden;   /* a room turned past the ring's side */
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.room__photo {
  margin: 0;
  /* no frame on a room turned off to the side: it would leave an outline in the black */
  border: 1px solid color-mix(in srgb, var(--fg) calc(var(--lit) * 100%), transparent);
  overflow: hidden;
  background: #000;
}
.room__photo img {
  display: block;
  width: 100%;
  height: auto;
  /* out of the black, its brightest parts first, settling from a slight zoom */
  filter: brightness(var(--in)) contrast(calc(1 + (1 - var(--in)) * 1.5));
  transform: scale(calc(1.12 - 0.12 * var(--in)));
}
.room .stop,
.room__legend { opacity: var(--lit); }
/* a room's name on one line (the user, 2026-10-25: never "Private / meetings"), and with no number (the
   stops' are the walk's): rooms.js turns all the names down together to the size the longest fits the room at */
.room .stop {
  white-space: nowrap;
  margin: 0 0 16px;   /* over its photo, and none over it: the block is centred on what shows */
}
/* its legend, close under the photo as a caption's line is under its name, and larger than a caption's,
   to read on the photo's page */
.room__legend {
  margin: 10px 0 0;
  font-size: 16px;
}
@media (prefers-reduced-motion: reduce) {
  .room { --in: 1 !important; }
}

/* After the last room: the summit's own terminal, in the pinned view's black once the room has turned
   away (rooms.js). It types itself out like a terminal (terminal.js): each part shows as its turn comes
   (.is-on), a line's text a character at a time (--shown characters of it), the logo a row at a time
   (--shown of its --rows), the cursor at the end of the line being typed, and blinking once it waits. */
.terminal {
  position: absolute;
  inset: 0;
  padding: max(96px, 16vh) var(--gutter) 0;
  color: var(--fg);
  font: 400 var(--terminal-type)/1.5 var(--mono);
}
.terminal p { margin: 0 0 1.2em; }
/* a destination's screen (terminal.js, `why`): its page in the middle of the screen, in one column, so the
   prompt under its last paragraph starts where the paragraph does (the user, 2026-10-26) */
.terminal:not([data-showing="ready"]) {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.2em;
  padding-block: 72px;   /* clear of the masthead, both ways */
}
.terminal:not([data-showing="ready"]) > * { width: min(64ch, 100%); margin-inline: auto; }
.terminal:not([data-showing="ready"]) p,
.terminal:not([data-showing="ready"]) .terminal__prompt { margin-block: 0; }   /* the column's gap instead: centred on the text */
.terminal__reply:empty { display: none; }
.terminal__dim { color: color-mix(in srgb, var(--fg) 55%, transparent); }
.terminal__part { visibility: hidden; }
.terminal__part.is-on { visibility: visible; }
.terminal__text { max-width: 64ch; }
.terminal__whole { white-space: nowrap; }   /* words kept on one line (the intro's "now speak, listen and act.", "the people") */
/* The way in past the logo screen (index.html, .access; access.js): TBot's intro, as large as the deck's sentences
   (above), on its own black over the logo screen, under the screen's music and over all else; then, for a browser
   not let in yet, the password under his last line. It was the terminal's intro: its column as wide as its longest
   line in that type ("Agents, devices and robots now speak, listen and act.", 53 characters; in the terminal's 64ch
   of its own smaller type it broke after "robots" on a laptop, the user, 2026-11-01: "can you put it on the same
   line on laptop"), TBot beside each line, in the middle of its height (access.js brings him down to there). Where
   the screen is too narrow for him and the intro's widest unbroken words ("now speak, listen and act."), he stands
   over the line instead, at its start: below 390px, as in the intro's 18px type there they need 382 (a 375px
   phone; a 390px one has him beside it). */
.access {
  --fg: #f3f0e8;   /* the night's white, the terminal's (config.js PALETTE.paper): no walk is there yet to set it */
  --tbot: calc(2.8em * 1070 / 1008);   /* TBot's width: two of its lines tall, in his face's proportions */
  --tbot-gap: 0.8em;
  position: fixed;
  inset: 0;
  z-index: 8;   /* over the logo screen (logo.css), which comes before it; the screen's music over both */
  padding: 72px var(--gutter);
  background: #000;
  color: var(--fg);
  font: 400 var(--sentence-type)/1.4 var(--mono);
}
.access:not([hidden]) {
  display: grid;
  grid-template-columns: var(--tbot) minmax(0, 54ch);
  column-gap: var(--tbot-gap);
  row-gap: 1.2em;
  align-content: center;
  justify-content: center;
  align-items: center;
}
.access p { margin: 0; }
.access > .terminal__text { grid-area: 1 / 2; text-wrap: balance; }   /* its short lines, wrapped on a phone, in even halves */
.access__tbot {
  grid-area: 1 / 1;
  display: block;
  width: var(--tbot);
  height: auto;
  aspect-ratio: 1070 / 1008;
}
/* the password, under the line: what is typed does not show (a password field, invisible over the line), the
   cursor waiting after the prompt; the server's answer under it, its line kept, so nothing moves as it comes. Both
   in the terminal's own type, as its prompt is, smaller than TBot's lines (the user, 2026-11-02: "put enter your
   password smaller"; it was as large as them). */
.access__prompt,
.access__reply { font-size: var(--terminal-type); }
.access__prompt { grid-area: 2 / 2; position: relative; cursor: text; }
.access__input {
  position: absolute;
  inset: 0;
  width: 100%;
  opacity: 0;
  border: 0;
  padding: 0;
  font-size: 16px;   /* a phone zooms in on a smaller field */
}
.access__reply { grid-area: 3 / 2; min-height: 1.4em; }
@media (max-width: 389px) {
  .access:not([hidden]) { grid-template-columns: minmax(0, 1fr); }
  .access > .terminal__text { grid-area: 2 / 1; }
  .access__prompt { grid-area: 3 / 1; }
  .access__reply { grid-area: 4 / 1; }
}
/* text typed where it will stand (typed.js: the terminal's paragraphs, the captions' and rooms' boxes): all its
   characters in place from the start, each shown once typed, so its lines wrap once; the cursor floats after
   the last one typed, taking no room in the line */
.typed-char { position: relative; visibility: hidden; }
.typed-char.is-typed { visibility: visible; }
.typed-char > :is(.terminal__cursor, .typed-cursor) { position: absolute; top: 0; left: 100%; visibility: visible; }
.typed-char > .is-before { left: 0; margin-left: 0; }
.terminal__type {
  display: inline-block;
  vertical-align: bottom;
  overflow: hidden;
  white-space: pre;   /* a prompt's trailing space, which the answer comes after */
  width: calc(var(--shown, 0) * 1ch);
}
.terminal__rows { clip-path: inset(0 0 calc(100% - 100% * var(--shown, 0) / var(--rows)) 0); }   /* printed output */
.terminal__logo { margin: 1.6em 0 1.8em; }
.terminal__logo canvas {
  display: block;
  width: min(100%, max(280px, 62vw), 1000px);
  height: auto;
  filter: drop-shadow(0 0 0.35em color-mix(in srgb, var(--fg) 55%, transparent));   /* a screen's glow */
}
/* the walker's answer on the last line (terminal.js), unseen, as a password is: the input is invisible over
   the line, so it takes keys and taps, and the cursor waits after the prompt; a destination there is not
   shows under it */
.terminal__prompt { position: relative; margin: 0 0 1.2em; cursor: text; }
.terminal__input {
  position: absolute;
  inset: 0;
  width: 100%;
  opacity: 0;
  border: 0;
  padding: 0;
  font-size: 16px;   /* a phone zooms in on a smaller field */
}

/* the black the page goes through when the terminal takes it back to the plan (main.js) */
.veil {
  position: fixed;
  inset: 0;
  z-index: 10;   /* over the masthead and the switches */
  background: #000;
  opacity: 0;
  pointer-events: none;
}
/* a terminal's block cursor: the terminal's, in the night's white, blinking once it waits; a box's (typedBoxes.js)
   in its text's black, there only while it types */
.terminal__cursor,
.typed-cursor {
  display: inline-block;
  width: 0.6em;
  height: 1.15em;
  margin-left: 0.15em;
  vertical-align: text-bottom;
}
.terminal__cursor {
  background: var(--fg);
  animation: terminal-blink 1.1s steps(1) infinite;
}
.typed-cursor { background: currentColor; }
.terminal.is-typing .terminal__cursor { animation: none; }   /* solid while keys are going */
@keyframes terminal-blink { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .terminal__cursor { animation: none; }
}

@media (max-width: 600px) {
  .masthead .meta { display: none; }
}
/* and at 340 px and under, the mark on two lines, THE NEXT / INTERFACE: on one, the row with the way home ran
   23 px over it at 320 px wide */
@media (max-width: 340px) {
  .masthead .mark { max-width: 10ch; }
}
