/* ================================================================== fonts */
/* one variable font covers every sans weight the page uses */
@font-face { font-family: 'IBM Plex Sans'; src: url('../fonts/ibmplexsans.woff2') format('woff2'); font-weight: 400 600; font-display: swap; }
@font-face { font-family: 'IBM Plex Mono'; src: url('../fonts/ibmplexmono-400.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'IBM Plex Mono'; src: url('../fonts/ibmplexmono-500.woff2') format('woff2'); font-weight: 500; font-display: swap; }
@font-face { font-family: 'IBM Plex Mono'; src: url('../fonts/ibmplexmono-600.woff2') format('woff2'); font-weight: 600; font-display: swap; }

/* ================================================================= tokens
   Almost black, and one warm accent. The only warm light that moves in the scene
   is the combustion, so the interface borrows the same two colours rather than
   inventing a third: bone for anything the machine is doing, ember for anything
   the fire is doing. */
:root {
  color-scheme: dark;
  --ground: #07070a;
  --bone: #e9e4da;
  --bone-2: rgba(233, 228, 218, .62);
  --bone-3: rgba(233, 228, 218, .52);
  --ember: #ff6a24;
  --ember-2: #c2350c;
  --rule: rgba(233, 228, 218, .13);
  --mono: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
  --sans: 'IBM Plex Sans', system-ui, -apple-system, sans-serif;
  --ease: cubic-bezier(.16, 1, .3, 1);
  --ease-io: cubic-bezier(.65, 0, .35, 1);
}

* { box-sizing: border-box }
body {
  margin: 0; background: var(--ground); color: var(--bone);
  font: 400 14px/1.55 var(--sans); -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none }
:focus-visible { outline: 2px solid var(--ember); outline-offset: 3px }
.skip { position: fixed; left: 12px; top: -80px; z-index: 99; background: var(--bone); color: var(--ground); padding: 9px 14px; font: 500 12px var(--mono); transition: top .16s var(--ease) }
.skip:focus { top: 12px }

#view { position: fixed; inset: 0; width: 100%; height: 100%; display: block; z-index: 0; touch-action: pan-y }
/* The self-running demo's loop from 04 back to 00 (site.js): the engine and the
   copy dip to the ground in a quarter of a second, the page is put back to 00 while
   it is dark, and the closed engine fades up with its headline already in. Scrolled
   back in the light, the section closed in reverse and the accessories came back
   see-through over half a second of cut paint and no headline. */
#view, .story { transition: opacity .5s var(--ease) }
html.dip #view, html.dip .story, html.dip .camcard { opacity: 0; transition: opacity .25s ease-in }

/* the scroll track: five screens of nothing, purely to give the story length */
.track { position: relative; z-index: 1; pointer-events: none }
.track section { height: 100vh; height: 100dvh }

/* ================================================================= topbar */
.topbar {
  position: fixed; z-index: 6; top: 0; left: 0; right: 0; height: 56px;
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  padding: 0 clamp(16px, 2.4vw, 34px);
  background: linear-gradient(rgba(7, 7, 10, .80), transparent);
  font: 400 11px var(--mono); letter-spacing: .06em;
}
.mark { display: flex; align-items: center; gap: 10px }
.mark-glyph { color: var(--ember); display: grid; place-items: center }
.mark-txt { letter-spacing: .16em; text-transform: uppercase; font-weight: 500; font-size: 11.5px }
.mark-txt em { font-style: normal; color: var(--bone-3); margin-left: .38em }
/* says whose demo this is, including when it is framed on the Realm Systems site */
.mark-tag { padding-left: 10px; border-left: 1px solid var(--rule); color: var(--bone-2); font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase; white-space: nowrap }
.mark:hover .mark-txt, .mark:hover .mark-tag { color: var(--ember) }
.topbar-mid { margin: 0; color: var(--bone-3); letter-spacing: .1em; text-transform: uppercase; font-size: 10px; text-align: center }
.topbar-link { color: var(--bone-2); transition: color .18s var(--ease) }
.topbar-link:hover { color: var(--ember) }

/* ================================================================= chapter nav */
.chapnav { display: flex; align-items: center; gap: clamp(11px, 1.5vw, 22px); margin-left: auto }
.chapnum {
  position: relative; background: none; border: 0; padding: 4px 0; cursor: pointer;
  color: var(--bone-3); font: 400 11px var(--mono); letter-spacing: .1em;
  transition: color .3s var(--ease);
}
.chapnum::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -3px; height: 1px;
  background: var(--ember); transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .35s var(--ease);
}
.chapnum:hover { color: var(--bone-2) }
.chapnum.on { color: var(--bone) }
.chapnum.on::after { transform: scaleX(1) }

/* vertical caption down the left edge, as graphic texture */
.vert {
  position: fixed; z-index: 5; left: clamp(10px, 1.1vw, 18px); top: 50%;
  transform: rotate(180deg) translateY(50%); writing-mode: vertical-rl;
  margin: 0; letter-spacing: .3em; text-transform: uppercase; color: var(--bone-2); pointer-events: none; white-space: nowrap;
  /* the sans, not the mono: at this size the mono's dotted zero read as an 8, and
     "A0021 / 2.0 L" came out as "A8821 / 2.8 L" */
  font: 500 10.5px var(--sans); font-variant-numeric: lining-nums;
}

/* ================================================================= story */
/* The five chapters are all absolutely positioned, so this box has no intrinsic
   height and its translateY(-50%) used to resolve to nothing — the copy then grew
   downward from 40% of the screen and landed on the throttle controls. Giving it
   a real box and centring the copy inside it fixes the collision. */
.story {
  position: fixed; z-index: 4; left: clamp(34px, 5.2vw, 92px); top: 42%;
  transform: translateY(-50%); width: min(540px, 42vw); height: 58vh;
  pointer-events: none;
}
.chapter {
  position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: center;
  opacity: 0; transition: opacity .5s var(--ease), transform .5s var(--ease);
  will-change: opacity, transform;
}
/* the first headline paints with the page, before the script that runs the rest */
.chapter:first-child { opacity: 1 }
.kicker { display: flex; align-items: center; gap: 10px; margin: 0 0 18px; font: 400 10.5px var(--mono); letter-spacing: .2em; text-transform: uppercase; color: var(--bone-2) }
.dot { width: 5px; height: 5px; border-radius: 50%; background: var(--ember); flex: none; animation: blip 2.8s var(--ease-io) infinite }
@keyframes blip { 0%, 100% { opacity: 1 } 50% { opacity: .2 } }
.story h1, .story h2 {
  margin: 0; font-weight: 400; letter-spacing: -.045em; line-height: .96;
  font-size: clamp(34px, min(5.2vw, 8.6vh), 80px); text-wrap: balance;
  text-shadow: 0 2px 40px rgba(0, 0, 0, .8);
}
.story h1 em, .story h2 em { font-style: normal; color: var(--ember) }
.lede { margin: 20px 0 0; max-width: 36ch; font-size: 13.5px; line-height: 1.7; color: var(--bone-2); text-wrap: pretty }
.lede em { font-style: normal; color: var(--bone) }
/* where the curve and the ratio are on screen the copy invites you to move them;
   on a phone, where they are not, it points at the torque figure that is */
.lede .narrow { display: none }

/* ================================================================= readout */
.readout {
  position: fixed; z-index: 5; right: clamp(16px, 2.4vw, 34px); bottom: clamp(16px, 2.4vw, 30px);
  width: 268px; text-align: right;
}
.ro-top { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; align-items: baseline }
.ro-top div { display: flex; flex-direction: column; align-items: flex-end; gap: 3px }
.ro-top span { white-space: nowrap; letter-spacing: .1em }
.readout span, .controls .lab, .camcard h2, .controls .ro-grid span {
  font: 400 10.5px var(--mono); letter-spacing: .16em; text-transform: uppercase; color: var(--bone-3);
}
.readout b { font: 500 26px/1 var(--mono); letter-spacing: -.03em; font-variant-numeric: tabular-nums }
.readout small, .controls .ro-grid small { font: 400 10px var(--mono); color: var(--bone-3); margin-left: 3px }
.bar { display: block; height: 2px; margin: 10px 0 12px; background: rgba(233, 228, 218, .12); overflow: hidden }
.bar.thin { margin: 7px 0 12px }
.bar u { display: block; height: 100%; background: var(--ember); transform: scaleX(0); transform-origin: 100% 50%; transition: transform .1s linear }
.ro-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 9px 10px }
.ro-grid.tight { margin-top: 4px }
.ro-grid div { display: flex; flex-direction: column; align-items: flex-end; gap: 2px }
.ro-grid b { font: 500 12.5px var(--mono); color: var(--bone-2); font-variant-numeric: tabular-nums }
.ro-grid small { margin-left: 2px }
/* the second row is the engine map at full load, keyed and ruled off from the live row */
.readout .ro-key span { color: var(--bone-2) }
.readout .ro-key small { margin: 0 }
.readout .ro-key, .readout .ro-key ~ div { border-top: 1px solid var(--rule); padding-top: 7px }

/* ================================================================= controls */
.controls { position: fixed; z-index: 5; left: clamp(34px, 5.2vw, 92px); bottom: clamp(16px, 2.4vw, 30px); width: min(300px, 40vw) }
.ctl-row { display: flex; align-items: stretch; gap: 12px; margin-bottom: 10px }
.ctl-side { display: flex; flex-direction: column; justify-content: space-between; gap: 6px; flex: 1; min-width: 0 }
.ctl-side .lab { margin: 0 }

/* A pedal you hold, because a throttle is something you press, not something you
   drag a handle along. Also on the space bar. */
.pedal {
  flex: none; width: 86px; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 3px; padding: 10px 8px; cursor: pointer;
  background: rgba(255, 106, 36, .07); border: 1px solid rgba(255, 106, 36, .32);
  color: var(--bone); transition: background .12s var(--ease), border-color .12s var(--ease), transform .12s var(--ease);
  touch-action: none; user-select: none; -webkit-user-select: none;
}
.pedal b { font: 500 10.5px var(--mono); letter-spacing: .1em; text-transform: uppercase }
.pedal i { font: 400 10px var(--mono); font-style: normal; letter-spacing: .18em; text-transform: uppercase; color: var(--ember); opacity: .8 }
.pedal:hover { background: rgba(255, 106, 36, .13); border-color: rgba(255, 106, 36, .55) }
.pedal.down { background: var(--ember); border-color: var(--ember); color: #140800; transform: translateY(1px) }
.pedal.down i { color: #140800; opacity: .9 }

/* Live output meters, beside the pedal rather than across the screen. */
.out { margin: 12px 0 14px; display: flex; flex-direction: column; gap: 7px }
.out-row { display: flex; align-items: center; gap: 9px }
.out-row span { flex: none; width: 58px; font: 400 10px var(--mono); letter-spacing: .14em; text-transform: uppercase; color: var(--bone-3) }
.out-row .bar { flex: 1; height: 3px }
.out-row b { flex: none; min-width: 46px; text-align: right; font: 500 12px var(--mono); color: var(--bone); font-variant-numeric: tabular-nums }
.controls .bar u { transform-origin: 0 50% }
.out-row .bar u { background: linear-gradient(90deg, rgba(255, 106, 36, .55), var(--ember)) }

.ro-note { margin: 0 0 8px; font: 400 10px var(--mono); letter-spacing: .16em; text-transform: uppercase; color: var(--bone-3) }

.hint { position: fixed; z-index: 5; left: 50%; bottom: 28px; transform: translateX(-50%); margin: 0; white-space: nowrap; font: 400 10.5px/1.6 var(--mono); letter-spacing: .04em; color: var(--bone-3); pointer-events: none; opacity: 0; transition: opacity .2s var(--ease) }
/* The hint and the scroll cue share the bottom centre and hand over the way the
   chapter copy does: the outgoing one goes in a fifth of a second and the incoming
   one waits a third of a second, so the two are never half up on top of each other
   (a cross-fade read "Drag to turn SCROLL ck a piston"). */
.hint.show { opacity: 1; transition: opacity .5s var(--ease) .3s }
/* a close-up runs the block off the bottom of the screen, under where the hint and
   the stamp sit, so they step aside for it (site.js sets body.crop) */
body.crop .hint.show, body.crop .stamp { opacity: 0 }
/* frozen (or reduced motion), a drag walks the crank rather than turning the view */
.hint .when-held, body.held .hint .when-run { display: none }
body.held .hint .when-held { display: inline }
#readout:focus { outline: none }
#readout:focus-visible { outline: 1px solid var(--ember); outline-offset: 8px }
.hint { text-shadow: 0 1px 8px #07070a, 0 0 2px #07070a }
.run {
  flex: none; padding: 9px 15px; background: none; border: 1px solid var(--rule);
  color: var(--bone); font: 400 10.5px var(--mono); letter-spacing: .1em; text-transform: uppercase;
  cursor: pointer; transition: border-color .2s var(--ease), color .2s var(--ease), background .2s var(--ease);
}
.run:hover { border-color: var(--ember); color: var(--ember) }
.lab { display: flex; justify-content: space-between; gap: 10px; margin: 14px 0 6px }
.lab b { font-weight: 500; color: var(--bone-2); font-variant-numeric: tabular-nums }
.controls .ro-grid { grid-template-columns: repeat(3, 1fr); margin-top: 10px; text-align: left }
.controls .ro-grid div { align-items: flex-start }

input[type=range] { -webkit-appearance: none; appearance: none; display: block; width: 100%; height: 20px; margin: 0; background: transparent; cursor: ew-resize }
input[type=range]::-webkit-slider-runnable-track { height: 1px; background: var(--rule) }
input[type=range]::-moz-range-track { height: 1px; background: var(--rule) }
input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 2px; height: 15px; margin-top: -7px;
  border: 0; border-radius: 0; background: var(--ember);
}
input[type=range]::-moz-range-thumb { width: 2px; height: 15px; border: 0; border-radius: 0; background: var(--ember) }
input[type=range]:focus-visible { outline: 1px solid var(--ember); outline-offset: 4px }
input[type=range]:focus-visible::-webkit-slider-thumb { background: var(--bone) }

/* ================================================================= cam card */
/* Top right, under the topbar, so the right column reads card-then-readout at any
   height instead of the card sliding down into the numbers on shorter screens. */
.camcard { position: fixed; z-index: 5; right: clamp(16px, 2.4vw, 34px); top: 76px; width: 340px; padding: 12px 14px 14px; background: rgba(7, 7, 10, .72); border: 1px solid var(--rule); opacity: 0; transition: opacity .6s var(--ease) }
.camcard.show { opacity: 1 }
.camcard h2 { margin: 0 0 10px; text-align: right; display: flex; justify-content: flex-end; gap: 10px; align-items: baseline; flex-wrap: wrap }
.camcard h2 b { font: 500 10.5px var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--ember) }
#diagram, .chart { display: block; width: 100%; background: rgba(233, 228, 218, .022); border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule) }
#diagram { height: 164px }
.chart { height: 62px; margin-top: 12px }
.cap { margin: 8px 0 0; font: 400 10.5px/1.6 var(--mono); letter-spacing: .04em; color: var(--bone-3); text-align: right }
/* legend and cam card in one: each trace's swatch on the row that times it */
.events { margin: 10px 0 0; display: grid; gap: 4px }
.events div { display: flex; justify-content: space-between; align-items: baseline; gap: 12px }
.events dt { display: flex; align-items: center; gap: 8px; font: 400 10.5px var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--bone-3); white-space: nowrap }
.events dd { margin: 0; font: 400 10.5px var(--mono); letter-spacing: .02em; color: var(--bone-2); font-variant-numeric: tabular-nums; white-space: nowrap }
.sw { flex: none; width: 12px; height: 2px; align-self: center }
.sw-in { background: #96c8ff }
.sw-ex { background: #ff6e32 }
.sw-pi { background: #e2ded4 }
.sw-pr { height: 7px; background: rgba(255, 120, 50, .30); border-top: 1px solid rgba(255, 140, 70, .9) }

/* ================================================================= furniture */
.cue { position: fixed; z-index: 5; left: 50%; bottom: 26px; transform: translateX(-50%); margin: 0; display: flex; align-items: center; gap: 12px; font: 400 10.5px var(--mono); letter-spacing: .28em; text-transform: uppercase; color: var(--bone-3); pointer-events: none; transition: opacity .5s var(--ease) .3s }
.cue i { display: block; width: 54px; height: 1px; background: linear-gradient(90deg, var(--bone-3), transparent) }
.cue.gone { opacity: 0; transition: opacity .2s var(--ease) }
.ro-slow { margin: -4px 0 12px; font: 400 10px/1.45 var(--mono); letter-spacing: .04em; color: var(--bone-3) }
.ro-slow span { font: inherit; letter-spacing: inherit; text-transform: none; color: inherit }
.ro-slow .nw { white-space: nowrap }
.ro-slow .when-held { display: none }
/* Frozen (the Freeze button, or prefers-reduced-motion): the figures are the
   simulation's state where it stopped, so they are dimmed and labelled as held
   rather than left looking live beside a crank that is not turning. */
.readout.held .ro-top b { opacity: .45 }
.readout.held .ro-slow .when-run { display: none }
.readout.held .ro-slow .when-held { display: inline; color: var(--ember) }
.stamp { position: fixed; z-index: 5; left: 50%; bottom: 8px; transform: translateX(-50%); margin: 0; font: 400 10px var(--mono); letter-spacing: .04em; color: rgba(233, 228, 218, .5); white-space: nowrap; pointer-events: none; transition: opacity .5s var(--ease) }

/* ================================================================= boot */
/* The curtain covers only the canvas: the headline and the instruments paint at
   once, over it, while the engine's shaders compile underneath. Its line sits in
   the middle of the engine's stage (site.js measures it), not on the copy. */
.boot {
  position: fixed; inset: 0; z-index: 1;
  background: var(--ground); color: var(--bone-3);
  font: 400 11px/1.8 var(--mono); letter-spacing: .3em; text-transform: uppercase;
  transition: opacity .6s var(--ease);
}
.boot span {
  position: absolute; left: var(--bx, 50%); top: var(--by, 50%); transform: translate(-50%, -50%);
  width: max-content; max-width: var(--bw, 90vw); text-align: center;
  animation: blip 2.8s var(--ease-io) infinite;
}
.boot.gone { opacity: 0; pointer-events: none }
/* the line goes at once, so it never ghosts across the engine as the curtain fades */
.boot.gone span { animation: none; opacity: 0 }
/* nothing is being built any more: the line holds still and offers a reload */
.boot.failed span { animation: none; color: var(--bone-2); letter-spacing: .16em }
.boot.failed a { color: var(--ember); text-decoration: underline; text-underline-offset: 3px; margin-left: .6em }

/* ================================================================ responsive */
/* Under 1180px the hint drops its last clause and fits between the pedal and the
   readout, so the 1164px frame on the Realm site still says the engine can be
   turned and a piston followed. Under 1100px it would crowd the pedal. */
@media (max-width: 1180px) {
  .stamp, .hint-more { display: none }
  .story { width: min(460px, 52vw) }
  .camcard { width: 300px }
  .readout { width: 236px }
}
@media (max-width: 1099px) { .hint { display: none } }

/* Short desktop viewports (1280x720, and the 1164x629 frame on the Realm Systems
   site): the copy anchors under the topbar instead of centring on the screen, and
   the controls keep only what the pedal needs. The readout already shows the rest. */
@media (min-width: 901px) and (max-height: 880px) {
  .story { top: 70px; bottom: 214px; height: auto; transform: none }
  .chapter { justify-content: flex-start }
  .kicker { margin-bottom: 12px }
  .lede { margin-top: 14px; font-size: 13px; line-height: 1.6 }
  .controls .ctl-side .lab, #r-throttle, .controls .bar.thin, .ro-note, .controls .ro-grid { display: none }
  .ctl-side { justify-content: flex-start }
  .out { margin: 10px 0 6px }
  .lab { margin: 8px 0 4px }
  .camcard { top: 70px }
  .camcard .chart + .cap { display: none }
  .camcard { padding-bottom: 10px }
  .camcard h2 { margin-bottom: 6px }
  /* following a piston, its line replaces the title rather than wrapping under it
     and pushing the card down into the readout */
  .camcard.focused .cc-title { display: none }
  /* the curve's own label takes the top of the chart (site.js, drawChart) */
  .chart { height: 46px; margin-top: 8px }
  #diagram { height: 112px }
  .events { margin-top: 8px; gap: 1px }
  .events dt, .events dd { line-height: 14px }
  .readout { width: 268px }
}
@media (min-width: 901px) and (max-height: 660px) {
  .lede { max-width: 30ch; font-size: 12.5px }
  .stamp { display: none }
  .hint, .cue { bottom: 10px }
}

/* Phones and narrow tablets: copy at the top, the pedal and the live figures at the
   bottom, and the engine in the clear band between them (site.js measures it). */
@media (max-width: 900px) {
  .topbar-mid, .vert, .camcard, .cue, .stamp, .hint { display: none }
  .story { left: 20px; right: 20px; width: auto; top: 70px; bottom: auto; height: auto; transform: none }
  .chapter { position: absolute; inset: 0 0 auto 0; justify-content: flex-start }
  .story h1, .story h2 { font-size: clamp(32px, 8.8vw, 54px) }
  .kicker { margin-bottom: 14px }
  .lede { margin-top: 14px; font-size: 13px; line-height: 1.6; max-width: 60ch }
  .readout { left: 20px; right: 20px; width: auto; bottom: 14px; text-align: left }
  .readout .ro-grid { display: none }
  .readout .bar { margin: 8px 0 0 }
  .ro-slow { margin: 8px 0 0 }
  .ro-top div { align-items: flex-start }
  .bar u { transform-origin: 0 50% }
  /* a few pixels of air above the pedal, so the sump never sits on its edge */
  .controls { left: 20px; right: 20px; width: auto; bottom: 122px; padding-top: 6px }
  .controls .ctl-side .lab, #r-throttle, .controls .bar.thin, .out, .ro-note, .controls .ro-grid { display: none }
  .ctl-side { justify-content: flex-start }
  .lede .wide { display: none }
  .lede .narrow { display: inline }
}
/* Upright phones: the controls and figures sit over the floor the engine stands on,
   so a scrim from the top of the controls down (site.js measures it) keeps their
   text on near-black however the floor is lit. Not in the small frame, where the
   engine runs down beside the pedal. */
@media (max-width: 900px) and (min-height: 481px) {
  body::after {
    content: ''; position: fixed; z-index: 3; left: 0; right: 0; bottom: 0; height: var(--scrim, 0px);
    background: linear-gradient(rgba(7, 7, 10, 0), rgba(7, 7, 10, .84) 22px, rgba(7, 7, 10, .92));
    pointer-events: none;
  }
}
/* Short phones held upright (360x640, 375x667): tighter copy, and the compression
   ratio gives its row to the engine. Without it the clear band for the machine
   was under a fifth of the screen. */
@media (max-width: 900px) and (max-height: 720px) {
  .story { top: 60px }
  .kicker { margin-bottom: 10px }
  .story h1, .story h2 { font-size: clamp(28px, 8vw, 40px) }
  .lede { margin-top: 10px; font-size: 12.5px; line-height: 1.5 }
  .controls > .lab, #r-cr { display: none }
  .ctl-row { margin-bottom: 0 }
}
@media (max-width: 560px) {
  .ro-top b { font-size: 21px }
  .topbar-link, .mark-tag { display: none }
}

/* Framed on the Realm Systems 3D page, that page is the one this link points to;
   framed on another Realm page (the home page), it leads there (site.js, link3d). */
html.framed:not(.link3d) .topbar-link { display: none }
/* Framed, a desktop browser's 15px scrollbar ran down the right edge inside the
   host's drawn screen, which read as a raw embed rather than a device. The chapter
   nav and the scroll cue already say where the visitor is. (site.js measures the
   stage from the canvas, so a standalone scrollbar is taken off the width too.) */
html.framed { scrollbar-width: none }
html.framed::-webkit-scrollbar { display: none }

/* Very short viewports: the 340x230 frame on a phone, and phones held sideways.
   The engine, one line and the chapter nav, rather than a squashed desktop. */
@media (max-height: 480px) {
  .topbar { height: 38px; padding: 0 12px }
  .mark-txt, .mark-tag, .topbar-link, .vert, .cue, .stamp, .hint, .camcard, .controls, .readout { display: none }
  .chapnav { gap: 14px }
  .story { left: 12px; right: 12px; width: auto; top: 40px; bottom: auto; height: auto; transform: none }
  .chapter { position: absolute; inset: 0 0 auto 0; justify-content: flex-start }
  .kicker, .lede, .story br { display: none }
  .story h1, .story h2 {
    font-size: clamp(15px, 5vh, 22px); line-height: 1.25; letter-spacing: -.01em;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
}
/* the 340px phone frame still has room to say whose demo this is */
@media (max-height: 480px) and (min-width: 330px) { .mark-txt { display: inline } }
/* The 340px phone frame: the headline in a narrow column down the left and a small
   pedal under it (the Realm page's caption says hold the throttle to rev it), so
   the engine gets the whole right side at full height instead of a strip under a
   full-width title. */
@media (max-height: 480px) and (max-width: 599px) {
  /* the readout it skips to is not shown here, and the link covered the headline */
  .skip { display: none }
  .topbar { height: 34px; padding: 0 10px }
  .story { left: 10px; right: auto; width: 40%; top: 40px }
  .story h1, .story h2 { font-size: 16px; line-height: 1.18; white-space: normal; overflow: visible }
  .controls { display: block; left: 10px; right: auto; bottom: 10px; width: auto; padding-top: 0 }
  .controls > :not(.ctl-row), .ctl-side { display: none }
  .ctl-row { margin: 0 }
  .pedal { width: auto; flex-direction: row; gap: 7px; padding: 7px 10px }
  /* On 04, "Nothing here is a picture of a number", the live figures it means sit
     under the headline in the copy's own column, so the engine keeps its side. */
  html.at4 .readout { display: block; left: 10px; right: auto; top: auto; bottom: 52px; width: 38%; text-align: left }
  html.at4 .readout .ro-grid, html.at4 .readout .bar, html.at4 .ro-slow, html.at4 .ro-top span { display: none }
  html.at4 .ro-top { display: flex; flex-direction: column; gap: 3px }
  html.at4 .ro-top div { flex-direction: row; align-items: baseline; gap: 5px }
  html.at4 .ro-top b { font-size: 15px }
}
/* sideways phones have the width for the pedal and the three live figures */
@media (max-height: 480px) and (min-width: 600px) {
  .mark-txt { display: inline }
  .controls { display: block; left: 12px; right: auto; bottom: 10px; width: auto; padding-top: 0 }
  .controls > :not(.ctl-row), .ctl-side { display: none }
  .ctl-row { margin: 0 }
  .pedal { width: 80px; padding: 7px 6px }
  .readout { display: block; left: auto; right: 12px; bottom: 10px; width: auto; text-align: right }
  .readout .ro-grid, .readout .bar, .ro-top span { display: none }
  .ro-top { display: flex; gap: 16px; justify-content: flex-end }
  .ro-top div { flex-direction: row; align-items: baseline; gap: 3px }
  .ro-top b { font-size: 18px }
  .ro-slow { margin-top: 4px }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition-duration: .01ms !important }
}
