/* The palette is slot's own theme defaults, the ones System/theme.txt overrides. */
:root{
  --housing:#242429;
  --recess:#1a1a1d;
  --opening:#050508;
  /* The page sits between opening and recess: dark enough to stay slot's, light
     enough that a black shell still has an edge against it. */
  --page:#1b1b21;
  --edge:#4d4d57;

  --ink:#f4f5f9;
  --muted:#bcbdc9;
  --rule:#3a3a46;

  /* Overwritten on load by whichever colourway comes up. Silver is the fallback for a
     page that ran with scripting off, so the device is never uncoloured. */
  --shell-light:#e2e5e9;
  --shell-base:#b8bcc2;
  --shell-shade:#7e838b;
  --btn:#c2c6cc;
  --btn-hi:#e9ecf0;
  --etch:rgba(0,0,0,.46);
}

*{box-sizing:border-box}
/* No overflow-x guard here on purpose. The hero glow is sized to stay inside the
   viewport at every width (measured), and the guide's pinned device needs a root
   that has not been turned into a scroll container: Safari drops position:sticky
   when it has. */
html{-webkit-text-size-adjust:100%}
body{
  margin:0;
  background:var(--page);
  color:var(--ink);
  font:400 18px/1.68 "Open Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  -webkit-font-smoothing:antialiased;
}
a{color:var(--ink)}
h1,h2{line-height:1.15;letter-spacing:-.02em;margin:0}
code,kbd{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
/* A chip, the way a backtick reads in Discord. A typeface change alone was not enough
   separation at this size. .88em because monospace sets larger than the body face at
   the same px, and the vertical padding stays small so an inline chip cannot push into
   the line above it. */
code{
  background:var(--opening);
  border-radius:5px;
  padding:.14em .4em;
  font-size:.88em;
  color:var(--ink);
}

.wrap{max-width:900px;margin:0 auto;padding:0 24px}

/* ---------------------------------------------------------------- tabs --- */

/* The navigation is a row of tabs rather than seventeen screens in a column, so the page
   moves only when it is asked to. The masthead sticks, which is what lets a panel taller
   than the screen be scrolled without losing the way out of it. */
:root{--mast-h:60px}
/* The dropdown hangs off this, so it is the containing block for it. */
.mast{
  position:sticky;
  top:0;
  z-index:40;
  display:grid;
  grid-template-columns:1fr minmax(0,auto) 1fr;
  align-items:center;
  gap:clamp(12px,3vw,32px);
  min-height:var(--mast-h);
  padding:0 clamp(16px,3vw,32px);
  background:color-mix(in srgb,var(--page) 88%,transparent);
  backdrop-filter:blur(10px);
  border-bottom:1px solid var(--rule);
}
.mast-mark{
  font-weight:700;
  font-size:22px;
  color:var(--ink);
  text-decoration:none;
  letter-spacing:-.02em;
  justify-self:start;
}
.tabs,.subtabs{
  display:flex;
  gap:2px;
  /* A phone cannot fit six labels across, and wrapping them would push the panels down the
     page by a whole row. The strip scrolls instead, which is the one place this page still
     scrolls sideways on purpose. */
  overflow-x:auto;
  scrollbar-width:none;
}
.tabs::-webkit-scrollbar,.subtabs::-webkit-scrollbar{display:none}
/* Centred while the row fits, packed to the start once it does not. Plain `center` on an
   overflowing flex row pushes the first items off the scrollable origin, where no amount of
   scrolling reaches them: on a phone that stranded the first tab behind the left edge. The
   plain value stays first for anything that does not know `safe`. */
.tabs{justify-content:center;justify-content:safe center}
.tab,.subtab{
  flex:0 0 auto;
  appearance:none;
  background:none;
  border:0;
  font:inherit;
  color:var(--muted);
  cursor:pointer;
  white-space:nowrap;
  border-radius:8px;
  transition:color .2s ease,background .2s ease;
}
.tab{padding:9px 14px;font-size:16px;font-weight:600}
/* The studio is its own page, so it sits in the row as a link rather than a tab. */
a.tab{text-decoration:none}
.tab:hover,.subtab:hover{color:var(--ink)}
.tab[aria-selected=true]{color:var(--ink);background:var(--rule)}
.tab:focus-visible,.subtab:focus-visible{outline:2px solid var(--ink);outline-offset:2px}

/* The second row belongs to its panel, not to the page, so it is quieter than the first
   and sits under the heading it subdivides. */
/* Not drawn side by side, where the row of tabs fits and needs nothing to open it. */
.menu-btn{
  display:none;
  appearance:none;
  background:none;
  border:1px solid var(--rule);
  border-radius:8px;
  width:40px;
  height:36px;
  place-items:center;
  color:var(--ink);
  cursor:pointer;
  justify-self:end;
}
.menu-btn:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.menu-bars,.menu-bars::before,.menu-bars::after{
  display:block;
  width:17px;
  height:2px;
  border-radius:2px;
  background:currentColor;
}
.menu-bars{position:relative}
.menu-bars::before,.menu-bars::after{content:"";position:absolute;left:0}
.menu-bars::before{top:-6px}
.menu-bars::after{top:6px}

.subtabs{margin:0 0 22px;gap:4px;border-bottom:1px solid var(--rule)}
.subtab{padding:8px 12px;font-size:15px;border-radius:8px 8px 0 0;margin-bottom:-1px}
.subtab[aria-selected=true]{color:var(--ink);box-shadow:inset 0 -2px 0 var(--ink)}

/* A panel is at least a screen, so a short one like the credits does not leave the masthead
   stranded over a band of nothing. Taller ones simply scroll, which is now the only
   scrolling on the page. */
.panel{
  min-height:calc(100vh - var(--mast-h));
  min-height:calc(100dvh - var(--mast-h));
}
[hidden]{display:none!important}

/* The masthead sticks, so the browser's own jump to a hash on load put the target underneath
   it. Every id that can be linked to keeps the masthead's height clear above it. */
.panel,.subpanel,.step{scroll-margin-top:calc(var(--mast-h) + 12px)}


/* The steps of the install, numbered, because unlike the guide these are done in order. */
/* The same block the reference and the questions stand in, so the panels do not each
   start at a different height as the tabs are stepped through. */
.install{padding:clamp(26px,4vh,52px) 0}
.install h2{margin-bottom:clamp(16px,2.4vh,26px)}
.install-steps{list-style:none;counter-reset:step;margin:0;padding:0;max-width:64ch}
.install-steps li{counter-increment:step;position:relative;padding:0 0 22px 52px}
.install-steps li::before{
  content:counter(step);
  position:absolute;
  left:0;
  top:-2px;
  width:30px;
  height:30px;
  display:grid;
  place-items:center;
  border-radius:50%;
  border:1px solid var(--rule);
  color:var(--ink);
  font-size:15px;
  font-weight:600;
}
.install-steps h3{margin:0 0 6px;font-size:21px;color:var(--ink)}
.install-steps p{margin:0;color:var(--muted);line-height:1.65}
.install-steps p + p{margin-top:10px}
.install-steps a{color:var(--ink)}
.install-note{
  max-width:64ch;
  margin:4px 0 0;
  padding-top:16px;
  border-top:1px solid var(--rule);
  color:var(--muted);
}

/* ---------------------------------------------------------------- hero --- */

.hero{
  max-width:1060px;
  margin:0 auto;
  padding:24px;
  display:flex;
  align-items:center;
  justify-content:center;
  gap:clamp(40px,7vw,92px);
}
.hero-copy{flex:0 1 auto;min-width:0}

.wordmark{
  font-size:clamp(56px,9vw,88px);
  font-weight:700;
  letter-spacing:-.045em;
}
.tagline{
  font-size:clamp(19px,2.4vw,23px);
  color:var(--ink);
  margin:18px 0 0;
  max-width:30ch;
}
.hero-copy p.sub{color:var(--muted);margin:16px 0 0;max-width:42ch}

.actions{display:flex;flex-wrap:wrap;gap:12px;margin-top:34px}
.btn{
  display:inline-block;
  padding:13px 22px;
  border-radius:8px;
  font-weight:600;
  font-size:16px;
  text-decoration:none;
  background:var(--ink);
  color:var(--opening);
  border:1px solid var(--ink);
  transition:transform .12s ease,background .12s ease;
}
.btn:hover{transform:translateY(-1px)}
.btn.ghost{background:transparent;color:var(--ink);border-color:var(--rule)}
.btn.ghost:hover{border-color:var(--edge)}

/* -------------------------------------------------------------- device --- */

.hero-device{
  position:relative;
  flex:0 0 auto;
  --dw:clamp(210px,29vw,320px);
  /* The two halves are not the same thickness. 23.9mm shut, split one third to the
     screen half and two thirds to the button half: 7.97mm and 15.93mm, which against
     the 82mm width is 9.7% and 19.4%. Every face measures off these. */
  width:var(--dw);
  /* Its own box, held whether or not the device is standing in it. Side by side the device
     leaves the flow to travel down into the guide, and without this the wrapper collapses
     and takes the hero's layout with it. 820x1555 is the artwork: the lid's 725 over the
     deck's 830. */
  aspect-ratio:820 / 1555;
  /* No perspective property here. A perspective establishes the containing block for any
     fixed-position descendant, which would pin the travelling device to this wrapper
     instead of to the viewport. It moves onto the device itself, via the transform
     function, same as the guide, and for a related reason. */
}
/* A soft pool of light behind the shell, so a silver device is not floating on
   black with a hard edge. */
.hero-device::after{
  content:'';
  position:absolute;
  /* Kept inside the device's own column: 8% of the widest it gets still lands
     short of the viewport at every width the hero has a layout for. */
  inset:-16% -8%;
  z-index:0;
  background:radial-gradient(58% 40% at 50% 66%,rgba(255,255,255,.09),transparent 70%);
  pointer-events:none;
  /* Goes with the device. The pool of light belongs under the shell, not to the empty
     column it leaves behind. */
  opacity:var(--glow,1);
}
/* Defined once, off-layout, and instantiated by <use>. */
.device-defs{position:absolute;width:0;height:0;overflow:hidden}

.device{position:relative;z-index:2;transform-style:preserve-3d;
  --depth-lid:calc(var(--dw) * .097);
  --depth-deck:calc(var(--dw) * .194)}
.dv-lid,.dv-deck{position:relative;transform-style:preserve-3d}
/* The hinge axis is the centre of the barrel, 55 units below the lid's bottom edge,
   which is 107.6% of the lid's own height. Pivoting on the edge instead leaves a shut
   lid sitting 11mm high, hovering above the deck face it should rest on. Every pose
   that swings the lid uses it. */
.dv-lid{transform-origin:50% 107.6%}
.dv-front>svg,.dv-deck>svg{display:block;width:100%;height:auto}

/* Two faces, so the lid can start shut. `flat` on the front matters: it flattens the
   screen overlays into the face, so hiding the face's backface hides them with it
   instead of leaving a video floating in mid air while the lid is closed. */
.dv-front,.dv-back{backface-visibility:hidden;-webkit-backface-visibility:hidden;transform-style:flat}
/* Positioned, so the screen overlays resolve against the face and get flattened into
   it. Without this they fall back to .dv-lid, stay in its 3D context, and go on
   showing the carousel through the back of a shut lid. */
.dv-front{position:relative;transform:translateZ(.6px)}
/* translateZ is applied before the flip, so a positive value lands the face a full
   depth BEHIND the front. At .6px it sat almost on top of it and the walls enclosed
   nothing, which is why an opening lid read as a hollow box. */
.dv-back{position:absolute;inset:0;transform:rotateX(180deg) translateZ(var(--depth-lid))}
.dv-back svg{display:block;width:100%;height:100%}
/* The lid's shadow falling on the deck. Sits a hair proud so a preserve-3d parent
   cannot flip a coin over whether it paints above the deck art or below it. */
.dv-ao{position:absolute;left:0;right:0;top:0;height:30%;pointer-events:none;
  transform:translateZ(.3px);
  background:linear-gradient(rgba(0,0,0,.5),rgba(0,0,0,.16) 55%,rgba(0,0,0,0))}

/* Straight on, both halves flat. What the documentation section wants. The perspective
   comes from the device rather than the stage; see the note on .guide-stage. */
.pose-flat{transform:perspective(calc(var(--dw) * 2.5))}
.pose-flat .dv-lid{transform:none}

/* Nothing in this pose turns on Y, so the side walls, the top edge and the lid's back are
   all exactly edge-on or exactly behind the front, and every one of them relies on
   backface culling at precisely 90 or 180 degrees to vanish. That is the one place
   rasterisers disagree: it culls under software rendering and can draw under GPU
   compositing, which puts the lid's back face above the open lid as a pale trapezoid with
   a second hinge barrel under it. A face that cannot legitimately be seen here should not
   be drawn at all, rather than drawn and hoped away. The hero keeps all of them: it
   genuinely turns, so they sit at angles where the answer is not a coin flip. */
.pose-flat .dv-edge,
.pose-flat .f3d,
.pose-flat .dv-back{display:none}
/* Except folded over, where the back of the lid is the face you are looking at.
   Its own shape, not the box it happens to be stretched into: `inset:0` took the height
   from .dv-lid and `preserveAspectRatio="none"` then stretched the art to whatever that
   was, so a lid box off by anything at all came out elongated. Pinning the top and giving
   it the art's own ratio makes it the right shape no matter what the parent measures.
   The translateZ goes too: it existed to stand the back off the front by the lid's
   thickness, and nothing in this pose shows a thickness; the walls that would are hidden
   above. That leaves one rotation on the lid and nothing offset in Z. */
.guide-stage .device.is-shut .dv-back,
.guide-stage .device.is-swinging .dv-back{
  display:block;
  bottom:auto;
  aspect-ratio:820/725;
  transform:rotateX(180deg);
}

/* Three quarters, lid swinging open on load and settling at 16 degrees. */
/* rotateZ is listed first so it applies to the finished 3D composite rather than
   before it. 6.6 is measured, not guessed: the projected screen's top edge sits at
   -6.59 degrees without it. Perspective makes the screen a trapezoid, so its left
   edge cannot come vertical at the same time; the horizon wins, because the carousel
   inside it is a row of carts on a shelf line. */
/* The perspective rides in the transform; see the note on .hero-device. It has to be a
   multiple of the device's width rather than a fixed length, so the projection is the same
   shape at every size: 750px was 2.5x a 300px device, and the closer the viewer the more
   violently the turned faces foreshorten. */
.pose-hero{transform:perspective(calc(var(--dw) * 2.5)) rotateZ(13deg) rotateX(6deg) rotateY(-27deg)}
/* The lid's opening animation outranks an inline style while it runs, so it is switched off
   the moment the device starts travelling; otherwise the lid holds its animated angle
   while the rest of the device flattens. */
.pose-hero.no-lid-anim .dv-lid{animation:none}
.pose-hero .dv-lid{
  transform:rotateX(-22deg);
  /* `backwards` so the lid holds shut through the delay rather than sitting open and
     then snapping closed to start. -178 rather than -180 keeps it a hair off the
     deck's plane, which is otherwise a coin flip over which one paints on top. */
  animation:lid-open 1.5s cubic-bezier(.3,.86,.36,1) .4s backwards;
}
@keyframes lid-open{from{transform:rotateX(-178deg)}to{transform:rotateX(-22deg)}}


/* The device is 23.9mm thick shut, so each half is about 12mm: 14.6% of the 82mm
   width. These are the faces you see once it is turned, and without them the halves
   are two cards. Each is inset by roughly its corner radius so a square face does not
   poke out past a rounded corner. */
/* Each wall carries a 180 degree flip about an axis lying in its own plane. That
   leaves it exactly where it was but turns its front face outward, which is what makes
   backface culling do the right thing: the near wall draws, the far one is dropped.
   Without the flip the fronts pointed inward and culling removed both. */
.f3d{position:absolute;backface-visibility:hidden;
  background:linear-gradient(rgba(0,0,0,.5),rgba(0,0,0,.3)),
             linear-gradient(180deg,var(--shell-shade),var(--shell-base))}
/* The walls run the full side now and round off at the ends instead of stopping
   square against a rounded corner. The vertical radii are the shell's own corner
   radii as a fraction of the wall's height: lid 60 and 30 units of 725, deck 25 and
   80 of 830. Horizontal is 100%, so each end is an ellipse the wall's full depth. */
.side-l,.side-r{top:0;height:100%;width:9.7%;
  border-radius:100% 100% 100% 100% / 8.3% 8.3% 4.1% 4.1%}
.side-l{left:0;transform-origin:0 50%;transform:rotateY(90deg) rotateX(180deg)}
.side-r{right:0;transform-origin:100% 50%;transform:rotateY(-90deg) rotateX(180deg)}
/* The barrel is part of the lower half, not a fitting bolted to it, so the deck's
   side runs the whole way: rounded at the top by the barrel's own radius (55 of 830),
   straight down the body, rounded out at the bottom corner (80 of 830). A separate
   cap sat at the barrel's shallower depth and read as a lozenge floating in the gap
   between the two walls. */
.deck-l,.deck-r{top:0;height:100%;width:19.4%;
  border-radius:100% 100% 100% 100% / 6.6% 6.6% 9.6% 9.6%}
.dv-bottom{left:9%;width:82%;bottom:0;height:19.2%;
  transform-origin:50% 100%;transform:rotateX(90deg) rotateY(180deg);
  background:linear-gradient(rgba(0,0,0,.58),rgba(0,0,0,.42)),
             linear-gradient(90deg,var(--shell-shade),var(--shell-base))}

/* The lid's top edge. Half the 23.9mm closed thickness against the lid's 72.5mm
   height is 16.5%, which is what stops a tipped lid reading as paper. */
.dv-edge{
  position:absolute;left:2.5%;right:2.5%;top:0;height:11%;
  transform-origin:50% 0;
  /* Negative: in CSS +Y is down and +Z is toward the viewer, so rotateX(90deg) swings
     the far edge forward and the slab floats above the lid. -90 sends it back. */
  transform:rotateX(-90deg) rotateY(180deg);
  background:linear-gradient(var(--shell-base),var(--shell-shade));
  border-radius:5px 5px 0 0;
  backface-visibility:hidden;
}

/* The SVG paints a black rect at exactly these coordinates, so both overlays land on
   black and a rounding error at the edge is black on black rather than shell colour
   bleeding through. 726x484 at 47,109 in the lid's own 820x725 viewBox: the panel's measured 3:2. */
.screen-box{
  position:absolute;
  left:5.7317%;
  top:15.0345%;
  width:88.5366%;
  height:66.7586%;

  border-radius:4px;
  overflow:hidden;
  background:var(--opening);
  backface-visibility:hidden;
  -webkit-backface-visibility:hidden;
}
.guide-screen,.hero-screen{
  z-index:5;
  opacity:0;
  transition:opacity .45s ease;
  /* `fill`, not `cover`. Both give the same picture here (the box is exactly 3:2 and
     so are the clips), but `cover` has to derive a fit from the video's intrinsic size,
     and any frame where that size is not yet known is a frame drawn at the wrong offset
     which then snaps into place. `fill` stretches to the box and asks nothing about the
     source, so there is no fit to get wrong. The cost is that a clip which is NOT 720x480
     would distort rather than crop, which is why the size is stated in media/README.md. */
  object-fit:fill;
  border:0;
  /* The element also carries width="720" height="480". Without an intrinsic size a
     video is 300x150 until its metadata arrives, and object-fit:cover crops a 2:1
     source into a 3:2 box quite differently from a 3:2 one, which is the frame that
     appears wrong and then snaps into place.

     translateZ(0) puts it in its own layer up front. A video inside a preserve-3d
     chain is composited separately, and it can land before the ancestors' transform
     has been applied to it, which shows as the picture sitting off to one side of the
     screen for a frame. Promoting it early makes that ordering fixed. */
  transform:translateZ(0);
}

/* -------------------------------------------------------------- content --- */

h2{font-size:clamp(26px,3.4vw,34px);margin-bottom:8px}
/* Prose caps at 68ch. The wrap stays wide so tables and code blocks still have room;
   only the running text is measured. */
section p,.credits p,section p{margin:0 0 18px}
section p:last-child{margin-bottom:0}


kbd{
  display:inline-block;
  padding:2px 7px;
  font-size:14px;
  line-height:1.5;
  border-radius:5px;
  background:#2b2b33;
  border:1px solid var(--rule);
  border-bottom-width:2px;
  color:var(--ink);
  white-space:nowrap;
}
/* A chord in running text is one instruction. Chips are inline blocks, which the line
   breaker will split around even with no-break spaces between them. */
.chord{white-space:nowrap}






/* ---------------------------------------------------------- reference --- */

/* The full control set, one list per sub-tab: anywhere, on the carousel, in game, in the
   switcher. Laid out as a table across the full width of the column: the inputs form a left
   rail you can run your eye down and the actions read across from them, with a rule under
   every row so a binding that wraps to two lines still reads as one row rather than as two.
   The rules replace an earlier layout that let the chips carry the structure alone, which
   worked at four rows and stopped working at eight. */
.reference{padding:clamp(26px,4vh,52px) 0}
/* The same 900px column every other panel stands in. Widened to 1040 it started 70px further
   left than the panels either side of it, so stepping along the tabs shifted the page under
   you. The table fills whichever column it is given, and 900 is what the page sets. */
.reference h2{margin-bottom:22px}
.reference h3,.faq h3{
  font-size:16px;
  font-weight:700;
  letter-spacing:.09em;
  text-transform:uppercase;
  color:var(--muted);
  margin:36px 0 14px;
}
.reference h3:first-of-type,.faq h3:first-of-type{margin-top:0}
/* The chips set small next to 19px text; the guide's own are read one at a time, these in
   a column you scan. */
.reference kbd{font-size:15px;padding:3px 8px}
.keys{margin:0;width:100%;border-top:1px solid var(--rule)}
.key{
  display:grid;
  grid-template-columns:minmax(0,17rem) minmax(0,1fr);
  gap:10px 32px;
  align-items:baseline;
  padding:13px 2px;
  font-size:19px;
  border-bottom:1px solid var(--rule);
}
.key dt{min-width:0}
.key dd{margin:0;color:var(--muted);min-width:0}

/* ---------------------------------------------------------------- faq --- */

/* Sized by its own questions. It was a centred 100dvh snap target, which on a phone
   made it 1133px of content centred in an 844px window: both ends permanently cropped
   and no way to scroll to them. */
.faq{padding:clamp(26px,4vh,52px) 0}
.faq h2{margin-bottom:22px}
.faq dl{margin:0}
.faq .qa{margin:0 0 26px}
.faq .qa:last-child{margin-bottom:0}
.faq dt{font-weight:600;font-size:20px;color:var(--ink);margin-bottom:7px}
.faq dd{margin:0;font-size:19px;line-height:1.7;color:var(--muted)}

/* No rule above the credits. The only dividers on the page are the ones between guide
   entries, and only stacked; the two endnotes are held apart by their own padding. */
.endnote{
  padding:clamp(26px,4vh,52px) 0;
  font-size:20px;
  line-height:1.7;
  color:var(--muted);
}
.endnote h2{color:var(--ink);margin-bottom:22px}
/* At 20px the 900px wrap runs to about 85 characters a line. */
.endnote p{max-width:64ch;margin:0 0 18px}
.endnote p:last-child{margin-bottom:0}
.endnote a{color:var(--ink)}

/* --------------------------------------------------------- device parts --- */

/* The gradient stops read the colourway rather than being rewritten, so switching
   shells is six custom properties and cannot miss one. */
.sl{stop-color:var(--shell-light)}
.sb{stop-color:var(--shell-base)}
.ss{stop-color:var(--shell-shade)}
.bh{stop-color:var(--btn-hi)}
.bb{stop-color:var(--btn)}

/* Strokes are in viewBox units, where 1 unit is 0.1 mm. */
.rim{stroke:var(--shell-light);stroke-opacity:.8;stroke-width:3}
.lens{fill:var(--shell-light);fill-opacity:.30;stroke:#000;stroke-opacity:.17;stroke-width:3}
.bumper circle{fill:var(--shell-shade);fill-opacity:.22;stroke:var(--shell-light);stroke-opacity:.35;stroke-width:2}
/* A dish is a shadow plus a lit rim, not a dark disc: on the black shell a dark disc
   is invisible and the recess disappears with it. */
.dish{fill:#000;fill-opacity:.10;stroke:var(--shell-light);stroke-opacity:.5;stroke-width:4}
.dishIn{fill:none;stroke:#000;stroke-opacity:.18;stroke-width:4}
.lensEdge{stroke:var(--shell-light);stroke-opacity:.85;stroke-width:4}
.lensInner{stroke:#000;stroke-opacity:.35;stroke-width:5}
.crossEdge{fill:var(--etch);opacity:.28}
.dimple{fill:#000;fill-opacity:.15}
.seam path{stroke:#000;stroke-opacity:.28;stroke-width:3}
/* Power. Lit whenever the screen beside it is, so it is drawn on rather than dark. */
.ledOn{fill:#6fd39b}
.ledGlow{fill:#6fd39b;opacity:.22}
.ledOff{fill:var(--etch);opacity:.5}
.face circle{fill:url(#btnGrad);stroke:var(--etch);stroke-opacity:.32;stroke-width:3}
.face text,.glyph{fill:var(--etch);font-family:"Open Sans",sans-serif;font-weight:600;text-anchor:middle}
.face text{font-size:32px}
.micro text{fill:var(--etch);font:600 20px "Open Sans",sans-serif;letter-spacing:2.5px;text-anchor:middle}
.holes circle{fill:var(--etch);opacity:.7}

/* ------------------------------------------------------------- guide --- */

.sr-only{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}

/* The device is pinned and straight on while the steps run past it, so one screen
   carries the whole guide instead of six devices scrolling by. */
.guide{
  max-width:1160px;
  margin:0 auto;
  padding:clamp(16px,2.5vh,44px) 24px;
  display:grid;
  /* The stage sizes to the device; the copy column is a fixed 46ch and does not. Sized to its
     content instead, the column was as wide as whichever step was showing, so paging from a
     long step to a short one pulled the column in by up to 179px and slid the device across
     the panel with it. A track that does not move is what makes the page turn look like the
     words changing rather than the layout rearranging.
     Fractions were no better: the stage column came out wider than the device standing in it
     and the copy column wider than the measure the copy keeps, so the two blocks were pushed
     apart by a gutter neither of them owned and the pair sat left of centre. */
  grid-template-columns:auto 44ch;
  justify-content:center;
  gap:clamp(28px,5vw,72px);
  align-items:center;
}
.guide-stage{
  /* Sized off viewport HEIGHT, because the stage is 100vh and the device is nearly
     twice as tall as it is wide, so height is what runs out first. A width cap alone made
     it shrink against the view as the screen grew: 73% of the height at 1280x800 but
     58% at 1920x1080. 41vh holds it at about 78% everywhere. The clamp is only there to
     stop it outgrowing its own grid column. */
  --dw:min(35vh,clamp(240px,27vw,370px));
  position:sticky;
  top:calc(var(--mast-h) + clamp(16px,3vh,40px));
  display:flex;
  align-items:center;
  justify-content:center;
  /* No perspective here. This element is position:sticky, and a sticky box that also
     establishes a perspective and holds a preserve-3d subtree is the combination that has
     the compositor painting the device's layer at an offset the layout never had: the
     duplicate lid, floating clear of where the element actually is. The DOM measures
     correctly throughout, which is why it only ever showed on a real GPU and never under
     the software rasteriser here. The perspective moves to the device instead, via the
     transform function, which gives its children the same projection without the sticky
     ancestor establishing one. */
}
.guide-stage .device{width:var(--dw)}
/* Held back until the hero's device has finished travelling down to it. display, not
   visibility: the artwork's flake texture is drawn through an SVG filter, which renders
   into its own surface and keeps painting through a hidden ancestor; it showed as a dark
   textured slab sitting where the device was going to land. */
.guide-stage .device.is-waiting{display:none}

/* The lid step shuts the device where it stands. Same hinge and the same angle the
   hero opens from, so the two read as one mechanism. -178 rather than -180 keeps the
   lid a hair off the deck's plane, which is otherwise a coin flip over which paints
   on top. The screen goes with it: the front face's backface is hidden, so a shut lid
   shows its outside rather than a video playing through the plastic. */
.guide-stage .dv-lid,.guide-stage .device{transition:transform 1.15s cubic-bezier(.45,.05,.3,1)}
/* Folding the lid down leaves the shut silhouette in the bottom half of a box that is
   still full height, so it sinks out of the stage's centre. Its visible mass runs from
   the hinge at 725 to 1560 of 1555 units, centred at about 73%, and this lifts it the
   23% that puts it back on the middle. The perspective rides along, since replacing the
   transform outright would drop it. */
.guide-stage .device.is-shut{transform:perspective(calc(var(--dw) * 2.5)) translateY(-23%)}
/* Set for one frame when the lid should arrive already shut rather than swing shut. */
.guide-stage .device.no-swing,
.guide-stage .device.no-swing .dv-lid{transition:none}
.guide-stage .device.is-shut .dv-lid{transform:rotateX(-178deg)}
@media (prefers-reduced-motion:reduce){.guide-stage .dv-lid{transition:none}}

/* One step at a time, stepped through rather than listed. Six at once asked the reader to
   work out which of them the device was showing; one leaves no question.
   A min-height so the shortest step and the longest do not move the controls under them. */
/* The copy and the controls that move it are one column beside the device, so the grid gets
   two children rather than three and the stepper cannot wrap under the artwork. The copy
   stays ranged left, where a wrapped line starts where the last one did; only the page
   turner is centred, so it reads as a control under the step rather than as more of it. */
/* Capped to the measure the copy already keeps. Left at the column's full width the centred
   page turner centred on the column rather than on the text above it, landing 58px to the
   right of it and reading as misaligned rather than as centred. */
.guide-body{min-width:0;max-width:44ch}
/* Room for the tallest step, so the controls under it hold still as the steps are paged
   through instead of walking up and down. Measured at 201px against a 115px shortest, with a
   little over: this is the one number here that a longer paragraph can invalidate, and when it
   does the page turner starts stepping down the page on whichever step outgrew it.
   The step is centred in that room. Held to the top instead, every step shorter than the
   tallest left its slack in one lump above the page turner, which read as a hole. */
.guide-steps{
  list-style:none;
  margin:0;
  padding:0;
  min-height:210px;
  display:flex;
  align-items:center;
}
.guide-steps .step{width:100%}
/* Without scripting nothing is ever marked active, so the first step stands by structure and
   the guide still reads. `is-live` is set once the script has taken the list over, and from
   then on the active step is the only one shown. */
.step{display:none}
.step:first-child{display:block}
.guide-steps.is-live .step{display:none}
.guide-steps.is-live .step.is-active{display:block}
.step h3{margin:0 0 10px;font-size:clamp(21px,2.4vw,27px);letter-spacing:-.01em}
.step p{margin:0;line-height:1.6}

.stepper{
  display:flex;
  align-items:center;
  justify-content:center;
  gap:16px;
  margin-top:8px;
  padding-top:18px;
  border-top:1px solid var(--rule);
}
.step-nav{
  appearance:none;
  width:40px;
  height:40px;
  display:grid;
  place-items:center;
  border:1px solid var(--rule);
  border-radius:50%;
  background:none;
  color:var(--ink);
  font-size:17px;
  line-height:1;
  cursor:pointer;
  transition:background .2s ease,opacity .2s ease;
}
.step-nav:hover:not(:disabled){background:var(--rule)}
.step-nav:disabled{opacity:.3;cursor:default}
.step-nav:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.step-count{margin:0;color:var(--muted);font-size:15px;font-variant-numeric:tabular-nums}

@media (max-width:880px){
  /* One gap between sections, set once. Each section carried its own desktop padding,
     9vh here and 11vh there, so the joins below the guide were paying two of them: 169px of
     nothing between the reference and the questions on an 844px screen. */
  :root{--gap-section:clamp(34px,5vh,52px)}
  .reference,.faq,.endnote{padding:var(--gap-section) 0}

  /* Stacked, the device goes above the list rather than beside it. It is shown rather than
     hidden, which is the opposite of what this layout used to do: the six per-step panels
     it used to fall back on are gone, so the pinned screen is now the only place a clip is
     ever drawn, at every width. Sticky under the masthead so it stays put while the step
     being pressed is further down the list. */
  .guide{display:block;padding:var(--gap-section) 24px}
  /* Not sticky. Pinned under the masthead it painted over the step below it: on the longest
     step the copy scrolls to reach the page turner, and the heading went under the artwork on
     the way. The device leads the panel and scrolls away with it, which is what a phone does
     with everything else on the page. */
  .guide-stage{
    --dw:min(48vw,196px);
    /* Explicitly static, not merely left out: the rule above sets sticky for the side by side
       layout, so dropping the declaration here inherited it rather than turning it off, and
       the pinned artwork painted over the heading of the step underneath it. */
    position:static;
    margin:0 auto clamp(18px,3vh,30px);
  }
  .guide-steps{min-height:150px}
  .step h3{font-size:21px}
  .step p{line-height:1.58}
  /* Every <br> on the page separates one keybinding from the next, not one clause from the
     next, so the lines either side want a little air. Narrow, they also wrap, and without
     this a two-line binding and the next binding are the same distance apart, so the break
     stops reading as a break. A <br> has no box of its own, so generated content and
     display:block are what let a margin take. */
  .step p br,
  .faq dd br{content:"";display:block;margin-top:7px}

}

@media (prefers-reduced-motion:reduce){.step{opacity:1}}

/* ------------------------------------------------------------- narrower --- */

@media (max-width:880px){
  /* Stretch, not flex-start: a column flex item at flex-start sizes to its max-content
     width, so the copy stopped wrapping and ran off the right edge. */
  /* The whole hero has to land inside one screen on the smallest phone still in use
     (an iPhone SE is 375x667), so the device is sized off viewport HEIGHT as well as width.
     Width alone let it grow to 415px tall on a 667px screen and pushed the buttons 13px
     past the fold. The gap and the bottom padding give back the rest. */
  /* Centred on a phone: the device sits above the copy rather than beside it, so the wordmark,
     the line under it and the two buttons all hang off the same axis the artwork is already on.
     Ranged left they read as leaning away from it. */
  .hero{flex-direction:column;align-items:stretch;padding:24px 24px 36px;gap:clamp(22px,4vh,40px)}
  .hero-copy{width:100%;text-align:center}
  .actions{justify-content:center}
  /* --dw, never width: the walls, the lid's back and its top edge are all calc'd off
     --dw, so overriding width alone left a 270px device wearing a 210px thickness.
     The device leads on a phone; the copy reads under it. */
  /* The projected silhouette runs about 2.1x --dw tall once the pose is applied, so the
     height cap is what actually keeps it on screen; the width cap keeps it off the edges. */
  .hero-device{--dw:min(168px,38vw,24vh);align-self:center;order:-1}
  .tagline,.hero-copy p.sub{max-width:none}

  /* Set for the phone, where the 20px credits and 19px answers were running to barely
     six words a line. */
  .faq dt{font-size:19px}
  .faq dd{font-size:18px}
  .endnote{font-size:18px}

  /* The mark at one end, the button that opens the sections at the other, and the sections
     themselves in a list under the masthead. Every one of them is on screen and a full row
     wide once it is open, where the strip showed two of six and scrolled for the rest. */
  .mast{padding:0 14px;gap:12px;grid-template-columns:1fr auto}
  .mast-mark{font-size:19px}
  .menu-btn{display:grid}
  .tabs{
    position:absolute;
    top:100%;
    left:0;
    right:0;
    display:none;
    flex-direction:column;
    justify-content:flex-start;
    gap:2px;
    padding:8px;
    overflow:visible;
    background:var(--page);
    border-bottom:1px solid var(--rule);
    /* Over the panel it covers, and dark enough underneath to read against the artwork the
       guide puts directly below the masthead. */
    box-shadow:0 18px 34px rgba(0,0,0,.55);
  }
  .tabs.is-open{display:flex}
  .tab{width:100%;text-align:left;padding:13px 14px;font-size:16px;border-radius:8px}

  /* Stacked: three chips and their separators do not fit a column beside the action at
     this width, so the input goes above what it does. */
  .key{grid-template-columns:1fr;gap:4px;padding:12px 2px;font-size:18px}
  .install h2{text-align:center}
  .install-note{text-align:center;margin-left:auto;margin-right:auto}

  .reference h3{margin-top:32px}
}
/* Shorter than an iPhone SE: the 2016 one is 320x568, and a phone held sideways lands
   here too. The height cap alone cannot save it: at that width the device is pinned by
   46vw, not by height, so the width cap comes in and the copy gives up a little of its
   own scale. Everything above stays untouched at 375x667. */
/* Short and narrow: the screen on its own, which is what the stacked layout showed before the
   guide became a stepper. The device is nearly twice as tall as it is wide, and on a short
   screen that height is the whole problem. In pose-flat the lid is already the screen in its
   own moulded surround, with the walls and the lid's back culled, so dropping the deck leaves
   exactly the panel the old per-step cards drew by hand. A tall phone keeps the whole device,
   where it fits with room to spare. */
@media (max-width:880px) and (max-height:700px){
  .guide-stage .dv-deck{display:none}
  /* With the deck gone the lid is only 1.13 times as wide as it is tall, so the height that
     forced the whole device to be small is no longer the constraint and the screen can take
     the column. Against the viewport less the guide's own 24px gutters rather than a plain
     vw, or the panel runs wider than the space it is padded into. */
  .guide-stage{--dw:min(calc(100vw - 56px),380px)}
  /* Nothing to fold onto once the deck has gone, and a lid folding over its own back with no
     body under it reads as a mistake. So the lid step does not fold: it shows the outside of
     the lid instead, which is the face you are looking at when the thing is shut and has no
     screen on it at all. A dark screen in its surround said the display was off; the closed
     lid says the lid is closed, which is what the step is about.
     The back has to hold the box once the front is gone, so it comes out of the absolute
     position it sits in while it is a face on a 3D object, and loses the rotateX that exists
     only to turn it away until the lid folds. */
  .guide-stage .device.is-shut,
  .guide-stage .device.is-shut .dv-lid{transform:none}
  .guide-stage .device.is-shut .dv-front{display:none}
  .guide-stage .device.is-shut .dv-back{
    display:block;
    position:relative;
    inset:auto;
    width:100%;
    aspect-ratio:820/725;
    transform:none;
  }
}

@media (max-width:880px) and (max-height:620px){
  .hero-device{--dw:min(148px,34vw,22vh)}
  .guide-steps{min-height:132px}
  .wordmark{font-size:clamp(42px,12vw,56px)}
  .tagline{margin-top:12px}
  .actions{margin-top:22px}
}

@media (prefers-reduced-motion:reduce){
  *{transition:none!important;animation:none!important}
}
