/* Copyright 2026 Satinbark Pty Ltd. All rights reserved. */

/* satinbark.com

   The one stylesheet, for the home page and the not-found page. The page is paper, and where the paper has come away in strips it shows what is under
   it: a field of the studio's blue-green. The sentence sits on that field at the top of
   the page, in paper, the way the mark sets its letters, and the page ends on the same
   field. Between the two the promises are a row of small tiles of the same blue-green,
   each of which opens its own panel.

   Nothing on the page meets anything else along a ruled line. The strips run from the
   very top, behind the wordmark; where a field ends they run on past its edge and are
   lost in the paper, and the last field carries the footer.

   The blue-green comes onto the page here, as the studio's D-029 allows.

   All of the motion is in this stylesheet, and none of it goes on by itself for more
   than five seconds: the first field opens, one band of light crosses it and the
   sentence arrives, and the object on the first tile, which is chosen when the page
   loads, plays its small act once. After that the page moves only in answer to the
   reader, who scrolls, points or chooses, and the strips move only to open the first
   field and close it again. That is what WCAG 2.2.2 asks of a page with no pause
   control. A reader who has asked for less motion gets the page open and still.

   The tiles are radio buttons with labels: no script, and the arrow keys move along
   the row.

   No colour, font size, line spacing, corner rounding, spacing or timing is written
   outside the tokens below, except where a comment says why: the lengths the spacing
   scale names as off it, and a high-contrast theme's own colours, since there the page
   gives way to the reader's palette. */

@property --enter {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}

@property --leave {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}

:root {
  color-scheme: light;

  --paper: #FBF9F5;
  --ink: #1B1814;
  --secondary: #5C5750;
  --tile-fill: #F1EDE5;
  --mark: #2F6460;
  --on-mark: var(--paper);
  /* The paper at nine parts in ten over the field, written out rather than mixed with
     color-mix(), which Safari before 16.2 cannot read: there the footer would fall
     back to ink on the field. */
  --on-mark-soft: #E7EAE6;

  /* The strips: three papers, the shade where a strip curls away at its edges, the
     shadow it throws on the field, and the light that crosses the first field. */
  --bark-1: var(--paper);
  --bark-2: var(--tile-fill);
  --bark-3: #E8E3DA;
  --curl: rgb(27 24 20 / 0.09);
  --cast: rgb(15 32 30 / 0.34);
  --sheen: rgb(251 249 245 / 0.08);

  --serif: ui-serif, "New York", "Iowan Old Style", Georgia, serif;
  --sans: -apple-system, system-ui, "SF Pro Text", "Helvetica Neue", Arial, sans-serif;

  /* The type scale. Six steps, and every piece of text on the page takes one of them:
     nothing is given a size of its own. Up to a phone's width the fourth step comes
     down to the fifth, so five sizes do the work there. The sentence's least size is never more than about a ninth of the window's
     width, so that a reader who has made the text larger on a phone still sees its
     longest words whole. At the usual text size the limit is never reached. */
  --step-display: clamp(min(2.125rem, 11vw), min(10vw, 1.6rem + 3vw), 5.5rem);
  --step-title: clamp(1.5rem, 1.25rem + 1vw, 2rem);
  --step-lead: clamp(1.3125rem, 1.1rem + 0.66vw, 1.625rem);
  --step-sub: clamp(1.0625rem, 0.6rem + 1.55vw, 1.375rem);
  --step-body: 1.0625rem;
  --step-small: 0.9375rem;

  /* Line spacing. Three steps, and every piece of text takes one of them: tight for
     headings, snug for short lines and larger text, loose for running text and the
     smallest lines. */
  --leading-tight: 1.1;
  --leading-snug: 1.4;
  --leading-loose: 1.6;

  /* The spacing scale. Eight steps, and every margin, padding and gap on the page takes
     one of them, or runs from one to another as the window grows, unless it is named
     below as off the scale. From the third on, each is about half as large again as
     the one before: the small steps space things inside a group, the middle ones a
     heading from what it heads, and the large ones one section from the next.

     Some lengths stay off it, because they are not space between things: the padding
     that makes each link a 44-point row; the room kept for the strips, above and
     below the sentence, which grows with the window's height as the strips do, and
     where they run on past a field (--run, after the first field and before the
     last); and the one-pixel lap that hides the seam over the footer. Of the room
     around the sentence, only its floor in a short window and the room over the
     sentence on a phone are steps. */
  --space-1: 0.5rem;
  --space-2: 1rem;
  --space-3: 1.5rem;
  --space-4: 2.25rem;
  --space-5: 3.5rem;
  --space-6: 5.5rem;
  --space-7: 8.5rem;
  --space-8: 14rem;

  /* Corner rounding. Three, each for its own job: the fine corners of the panel's
     pointer and of a link's focus ring; a tile's corners, as a share of its width,
     the way an app icon's are; and the panel's, which grows a little with the window. */
  --radius-fine: 0.1875rem;
  --radius-icon: 23%;
  --radius-panel: clamp(1.25rem, 3vw, 1.5rem);

  /* The margin at the sides of the page, and the gap between the tiles. */
  --gutter: clamp(var(--space-2), 6vw, var(--space-6));
  --side: max(var(--gutter), env(safe-area-inset-left, 0px));
  --gap: clamp(var(--space-1), 2.6vw, var(--space-3));
  --header: 4.25rem;

  /* How far the strips run on past the edge of a field before the paper has them. */
  --run: 7rem;

  /* How the strips hang: how much further the ones at the sides of the first field
     reach than the ones in the middle, and how ragged the line is. Each is a share of
     the field's height, in hundredths. */
  --drape: 78;
  --ragged: 9;

  /* The motion scale. Five lengths of time and three ways of moving, and everything
     that moves in time takes one of each. What moves with the scrolling keeps the
     reader's pace instead. Settle is for arriving and coming to rest, sway for going
     from rest to rest, and open for the first field drawing back.

     As the first field opens, each strip waits a share of a step more the nearer it
     sits to the side, so that the field opens from the middle outwards. The strips
     over the first app each wait a share of time 1, so that they do not part as one. */
  --time-1: 0.2s;
  --time-2: 0.45s;
  --time-3: 0.9s;
  --time-4: 1.5s;
  --time-5: 3s;

  --ease-settle: cubic-bezier(0.2, 0.7, 0.2, 1);
  --ease-sway: ease-in-out;
  --ease-open: cubic-bezier(0.65, 0, 0.2, 1);
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --paper: #1C1915;
    --ink: #F2EDE4;
    --secondary: #B8B0A4;
    --tile-fill: #26221C;
    --mark: #86BDB3;
    --on-mark-soft: #272925;
    --bark-3: #332F28;
    --curl: rgb(0 0 0 / 0.22);
    --cast: rgb(10 24 22 / 0.42);
    --sheen: rgb(255 255 255 / 0.16);
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--step-body);
  line-height: var(--leading-loose);
}

h1,
h2,
h3,
p {
  margin: 0;
}

a {
  color: inherit;
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}

/* Only where there is a pointer: a phone keeps a tapped link's hover until something
   else is tapped, which would leave it underlined after the reader has come back. */
@media (hover: hover) {
  a:hover {
    text-decoration-thickness: 2px;
  }
}

a:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
  border-radius: var(--radius-fine);
}

/* Words that are one idea, kept on one line: they go to the next line together, and
   break only if a whole line is too narrow for them, as it can be with the text made
   much larger on a phone. */
.keep {
  display: inline-block;
}

/* ---------------------------------------------------------------- header */

/* The wordmark and the one link lie on the strips at the top of the page. No strip is
   shorter than the header's one row is tall, so at the usual text size they are always
   on paper; with the text made much larger on a phone, Contact wraps down to where the
   strips end. */
.site-header {
  position: absolute;
  inset: 0 0 auto;
  z-index: 3;
  display: flex;
  /* With the text made much larger on a phone, Contact goes under the wordmark rather
     than past the edge of the screen. */
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0 var(--space-3);
  min-height: var(--header);
  padding-top: var(--space-1);
  padding-inline: var(--side);
}

.wordmark {
  display: inline-block;
  padding-block: 0.625rem;
  font-family: var(--serif);
  font-size: var(--step-lead);
  font-weight: 600;
  line-height: var(--leading-snug);
  letter-spacing: -0.01em;
  text-decoration-line: none;
}

/* The one link, in the wordmark's own face and a size below it. A 44-point row: the
   text is small, the target is not. */
.contact-link {
  padding-block: 0.625rem;
  font-family: var(--serif);
  font-size: var(--step-body);
  font-weight: 600;
  letter-spacing: -0.005em;
  text-decoration-line: none;
}

@media (hover: hover) {
  .contact-link:hover {
    text-decoration-line: underline;
  }
}

/* ---------------------------------------------------------------- the fields */

/* A field: the blue-green. Its strips may run past it above and below, but never out
   at the sides. */
.window,
.closing {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  color: var(--on-mark);
  text-align: center;
}

@supports (overflow: clip) {
  .window,
  .closing {
    overflow-x: clip;
    overflow-y: visible;
  }
}

.window {
  display: grid;
  place-items: center;
  /* The field fills the window up to 50rem tall. In a taller window it stops a little
     short of the bottom, so that the room around the sentence grows more slowly than
     the window and the sentence sits higher on the screen. It is never shorter than
     the sentence and its strips need (44rem), however short the window, so in a short
     window it runs on below the bottom of the screen. The room above and below the
     sentence is kept for the strips, and like them it grows with the window's height,
     so it is not on the spacing scale. */
  min-height: max(min(100svh, 50rem), 92svh, 44rem);
  padding: calc(var(--header) + 14svh) var(--gutter) 21svh;
  /* With one soft band of light, which crosses it slowly as the page opens. */
  background:
    linear-gradient(104deg, transparent 42%, var(--sheen) 50%, transparent 58%) 100% 0 / 320% 100% no-repeat,
    var(--mark);
}

.window-text {
  max-width: 100%;
}

.statement {
  font-family: var(--serif);
  /* Measured in its own ems, so it breaks into the same lines at every size. */
  max-width: min(100%, 10em);
  margin-inline: auto;
  font-size: var(--step-display);
  font-weight: 600;
  line-height: var(--leading-tight);
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.lede {
  max-width: 30ch;
  margin: var(--space-3) auto 0;
  color: var(--on-mark-soft);
  font-size: var(--step-sub);
  line-height: var(--leading-snug);
  text-wrap: balance;
}

/* A row of strips. It runs a little past its field at the sides, so that the strips at
   either end are cut off by the field's edge rather than ending beside it. --floor is
   the least any strip in the row reaches. */
.bark {
  position: absolute;
  right: -1.25rem;
  left: -1.25rem;
  z-index: 1;
  display: flex;
  pointer-events: none;
}

/* From the top of the page down into the first field. */
.high {
  --floor: calc(var(--header) + 2.25rem);
  top: -1.5rem;
  align-items: flex-start;
  height: calc(100% + 1.5rem);
}

/* From the paper under the first field up into it. */
.low {
  --floor: calc(var(--run) + 2.75rem);
  bottom: calc(var(--run) * -1);
  align-items: flex-end;
  height: calc(100% + var(--run));
}

/* From the paper above the last field down into it. */
.fringe {
  --floor: calc(var(--run) + 2.25rem);
  top: calc(var(--run) * -1);
  align-items: flex-start;
  height: calc(100% + var(--run));
}

/* A strip's length at rest comes from where it sits in the row; --enter and --leave
   carry it the rest of the way while the first field is opening or closing. */
.strip {
  --rest: calc(var(--floor) + 1% * (var(--edge) * var(--drape) + var(--j) * var(--ragged)));
  position: relative;
  flex: var(--w) 1 0;
  min-width: 0;
  height: calc(var(--rest) + (104% - var(--rest)) * max(var(--enter, 0), var(--leave, 0)));
  filter: drop-shadow(0 0.1875rem 0.3125rem var(--cast));
}

.low .strip {
  filter: drop-shadow(0 -0.125rem 0.3125rem var(--cast));
}

/* The paper itself, here and over the first app's tile: darker along both edges where
   it curls away, and cut on a slant at its free end. */
.strip::before,
.wrap span::before {
  content: "";
  position: absolute;
  inset: 0 -0.5px;
  background: linear-gradient(90deg, var(--curl), transparent 24%, transparent 74%, var(--curl)), var(--tone);
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--cr)), 0 calc(100% - var(--cl)));
}

.low .strip::before,
.wrap.lower span::before {
  clip-path: polygon(0 var(--cl), 100% var(--cr), 100% 100%, 0 100%);
}

/* Where the strips run on past a field, the paper takes them: they thin out over the
   length of the run until there is only the page. */
.window::after,
.closing::before {
  content: "";
  position: absolute;
  right: 0;
  left: 0;
  z-index: 2;
  /* A little longer than the run, so the shadow at a strip's far end is covered too. */
  height: calc(var(--run) + 1rem);
  pointer-events: none;
}

.window::after {
  top: 100%;
  background: linear-gradient(to bottom, transparent, var(--paper) calc(var(--run) * 0.88));
}

.closing::before {
  bottom: 100%;
  background: linear-gradient(to top, transparent, var(--paper) calc(var(--run) * 0.88));
}

/* ---------------------------------------------------------------- welcome */

.welcome {
  padding: calc(var(--run) + clamp(var(--space-3), 5svh, var(--space-5))) var(--side) clamp(var(--space-5), 14svh, var(--space-7));
}

.passage {
  max-width: 36ch;
  margin-inline: auto;
  font-family: var(--serif);
  font-size: var(--step-lead);
  line-height: var(--leading-snug);
  letter-spacing: -0.012em;
  text-align: center;
  text-wrap: pretty;
}

/* ---------------------------------------------------------------- the promises */

.shelf {
  max-width: calc(47rem + 2 * var(--gutter));
  margin-inline: auto;
  padding: 0 var(--side) calc(var(--run) + clamp(var(--space-5), 10svh, var(--space-6)));
}

.shelf h2 {
  font-family: var(--serif);
  font-size: var(--step-title);
  font-weight: 600;
  line-height: var(--leading-tight);
  letter-spacing: -0.01em;
  text-align: center;
}

.shelf-intro {
  margin-top: var(--space-1);
  color: var(--secondary);
  text-align: center;
  text-wrap: balance;
}

.dock {
  display: grid;
  margin-top: var(--space-4);
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--gap);
}

/* The radio buttons are there for the keyboard and for assistive technology; the tiles
   are their labels. Each lies unseen over its own tile and name, inside the label, so
   that a screen reader's cursor frames the tile it is reading, and a finger feeling
   along the row with VoiceOver finds the button where the tile is. The pointer passes
   through to the label. Each button is described by its panel's text
   (aria-describedby in the page), so a screen reader reads the promise with the
   button, though the panel is hidden until it is chosen. */
.pick {
  position: absolute;
  inset: 0;
  margin: 0;
  -webkit-appearance: none;
  appearance: none;
  opacity: 0;
  pointer-events: none;
}

/* Every label is as tall as the row, so each button covers the same height. */
.slot {
  position: relative;
  display: grid;
  align-content: start;
  justify-items: center;
  gap: var(--space-2);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}

/* A tile is a small field of its own: an opening in the paper, with the paper's shadow
   falling into it along the top. */
.tile {
  display: grid;
  place-items: center;
  width: 100%;
  max-width: 7rem;
  aspect-ratio: 1;
  border-radius: var(--radius-icon);
  background: var(--mark);
  color: var(--on-mark);
  box-shadow: inset 0 0.125rem 0.3125rem var(--cast);
}

/* The first app's place: a small field still under its paper. Its strips nearly meet
   across it, part a little when the tile is pointed at, and draw back when it is
   chosen, as the strips at the top of the page do. --open runs from 0 to 1. */
.kept {
  --open: 0;
  position: relative;
  overflow: hidden;
}

.wrap {
  position: absolute;
  inset: 0 -4%;
  display: flex;
}

.wrap.upper {
  top: -6%;
  align-items: flex-start;
}

.wrap.lower {
  bottom: -6%;
  align-items: flex-end;
}

.wrap span {
  position: relative;
  flex: var(--w) 1 0;
  min-width: 0;
  height: calc(var(--h) - var(--open) * var(--o));
  filter: drop-shadow(0 0.0625rem 0.125rem var(--cast));
}

.wrap.upper span:nth-child(1) { --w: 1.1; --h: 50%; --o: 30%; --d: 0.3; --cl: 0.1rem; --cr: 0.3rem; --tone: var(--bark-2); }
.wrap.upper span:nth-child(2) { --w: 0.8; --h: 45%; --o: 33%; --d: 0; --cl: 0.28rem; --cr: 0.06rem; --tone: var(--bark-1); }
.wrap.upper span:nth-child(3) { --w: 1.25; --h: 52%; --o: 38%; --d: 0.5; --cl: 0.05rem; --cr: 0.26rem; --tone: var(--bark-3); }
.wrap.upper span:nth-child(4) { --w: 0.9; --h: 46%; --o: 31%; --d: 0.15; --cl: 0.24rem; --cr: 0.1rem; --tone: var(--bark-1); }
.wrap.upper span:nth-child(5) { --w: 1; --h: 49%; --o: 28%; --d: 0.4; --cl: 0.08rem; --cr: 0.3rem; --tone: var(--bark-2); }
.wrap.lower span:nth-child(1) { --w: 0.9; --h: 47%; --o: 29%; --d: 0.2; --cl: 0.26rem; --cr: 0.08rem; --tone: var(--bark-1); }
.wrap.lower span:nth-child(2) { --w: 1.2; --h: 51%; --o: 36%; --d: 0.45; --cl: 0.06rem; --cr: 0.28rem; --tone: var(--bark-3); }
.wrap.lower span:nth-child(3) { --w: 0.85; --h: 44%; --o: 32%; --d: 0; --cl: 0.3rem; --cr: 0.12rem; --tone: var(--bark-2); }
.wrap.lower span:nth-child(4) { --w: 1.15; --h: 50%; --o: 35%; --d: 0.35; --cl: 0.1rem; --cr: 0.24rem; --tone: var(--bark-1); }
.wrap.lower span:nth-child(5) { --w: 0.95; --h: 46%; --o: 30%; --d: 0.1; --cl: 0.22rem; --cr: 0.05rem; --tone: var(--bark-2); }

.glyph {
  display: block;
  width: 62%;
  height: auto;
  overflow: visible;
  fill: none;
  stroke: currentColor;
  stroke-width: 3.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.move {
  transform-box: fill-box;
  transform-origin: 50% 50%;
}

.tile-name {
  color: var(--secondary);
  font-size: var(--step-small);
  line-height: var(--leading-snug);
  text-align: center;
  text-wrap: balance;
  transition: color var(--time-1) var(--ease-settle);
}

@media (hover: hover) {
  .slot:hover .tile {
    scale: 1.05;
  }

  .slot:hover .tile-name {
    color: var(--ink);
  }

  .slot:hover .kept {
    --open: 0.3;
  }

  /* Pointed at, each object begins its own small act and holds there, as the first
     app's paper parts a little: the coin starts to turn, the eye shuts tighter, the
     phone is picked up, the case is lifted by its handle. Chosen, each plays the act
     through. The pose is a transform, so it never fights the act, which moves the
     same object by its own translate, rotate and scale. */
  .slot:hover .coin {
    transform: scaleX(0.72);
  }

  .slot:hover .eye {
    transform: translateY(3px) scaleY(0.68);
  }

  .slot:hover .phone {
    transform: rotate(-9deg);
  }

  .slot:hover .case {
    transform: translateY(-8%) rotate(-5deg);
  }
}

/* The chosen opening is a little wider than the rest. This comes after the hover rules,
   so that pointing at the chosen tile leaves it as it is. */
.pick:checked ~ .tile {
  scale: 1.1;
}

.pick:checked ~ .kept {
  --open: 1;
}

.pick:checked ~ .tile-name {
  color: var(--ink);
}

.pick:focus-visible ~ .tile {
  outline: 3px solid var(--ink);
  outline-offset: 4px;
}

/* Pressed, a tile gives a little. This comes last, since a mouse is always over the
   tile it presses. */
.slot:active .tile {
  scale: 0.96;
}

.panels {
  position: relative;
  display: grid;
  gap: var(--space-4);
  margin-top: var(--space-3);
  padding: clamp(var(--space-3), 4.5vw, var(--space-4));
  border-radius: var(--radius-panel);
  background: var(--tile-fill);
}

.panel {
  display: grid;
  align-content: start;
  gap: var(--space-1);
}

.panel h3 {
  font-family: var(--serif);
  font-size: var(--step-lead);
  font-weight: 600;
  line-height: var(--leading-tight);
  letter-spacing: -0.012em;
}

.panel p {
  max-width: 36rem;
  text-wrap: pretty;
}

@supports not selector(:has(*)) {
  .dock {
    display: none;
  }
}

@supports selector(:has(*)) {
  .shelf:has(#open-customer:checked) { --at: 0; }
  .shelf:has(#open-watching:checked) { --at: 1; }
  .shelf:has(#open-device:checked) { --at: 2; }
  .shelf:has(#open-take:checked) { --at: 3; }
  .shelf:has(#open-app:checked) { --at: 4; }

  /* The panel's pointer sits under the chosen tile and slides along with the choice. */
  .panels::before {
    content: "";
    position: absolute;
    top: -0.5rem;
    left: calc(var(--at) * (100% + var(--gap)) / 5 + (100% - 4 * var(--gap)) / 10);
    width: 1.125rem;
    height: 1.125rem;
    border-radius: var(--radius-fine);
    background: var(--tile-fill);
    translate: -50% 0;
    rotate: 45deg;
  }

  /* The panels share one place, so the page does not move as the choice changes. How
     one gives way to the next is under "motion" below. */
  .panel {
    grid-area: 1 / 1;
    visibility: hidden;
    opacity: 0;
  }

  .shelf:has(#open-customer:checked) #customer,
  .shelf:has(#open-watching:checked) #watching,
  .shelf:has(#open-device:checked) #device,
  .shelf:has(#open-take:checked) #take,
  .shelf:has(#open-app:checked) #app {
    visibility: visible;
    opacity: 1;
  }
}

/* ---------------------------------------------------------------- the last field */

/* The page ends still: no light crosses this field, and its strips hang at rest, as
   long at the sides as in the middle. */
.closing {
  --edge: 0;
  --ragged: 15;
  padding: clamp(var(--space-7), 30svh, var(--space-8)) var(--side) clamp(var(--space-5), 11svh, var(--space-6));
  background: var(--mark);
}

.closing-text {
  display: grid;
  justify-items: center;
  gap: var(--space-1);
}

.closing :is(h1, h2) {
  color: var(--on-mark-soft);
  font-size: var(--step-small);
  font-weight: 600;
}

.closing p {
  max-width: 28rem;
  color: var(--on-mark-soft);
  font-size: var(--step-sub);
  line-height: var(--leading-snug);
  text-wrap: balance;
}

.closing .headline {
  max-width: none;
  color: var(--on-mark);
  font-family: var(--serif);
  font-size: var(--step-title);
  font-weight: 600;
  line-height: var(--leading-tight);
  letter-spacing: -0.02em;
  overflow-wrap: anywhere;
}

/* A link here is padded out to a 44-point target, as the header's are. */
.headline a {
  display: inline-block;
  padding-block: 0.625rem;
  text-decoration-thickness: 0.05em;
  text-underline-offset: 0.14em;
}

@media (hover: hover) {
  .headline a:hover {
    text-decoration-thickness: 0.09em;
  }
}

/* The footer is the same ground as the field above it. It laps over the field's last
   pixel, so no seam shows where a height falls between two pixels. */
.site-footer {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-1) var(--space-3);
  margin-top: -1px;
  padding: calc(var(--space-3) + 1px) var(--side) max(var(--space-4), env(safe-area-inset-bottom, 0px));
  background: var(--mark);
  color: var(--on-mark-soft);
  font-size: var(--step-small);
}

/* ---------------------------------------------------------------- not found */

/* The not-found page is the last field alone: the header on paper, the field's strips
   hanging from the paper below it, and the field running down to the footer however
   tall the window is. */
.lost {
  display: flex;
  flex-direction: column;
  min-height: 100svh;
}

.lost main {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding-top: calc(var(--header) + var(--space-3));
}

.lost .closing {
  display: grid;
  flex: 1;
  place-items: center;
}

/* ---------------------------------------------------------------- motion */

/* Everything that moves does so here, so a reader who has asked for less motion gets
   the page still: a choice simply changes. */
@media (prefers-reduced-motion: no-preference) {
  /* One band of light crosses the first field, once. */
  .window {
    animation: light var(--time-5) var(--ease-sway) var(--time-3) 1 both;
  }

  @supports (animation-timeline: scroll()) {
    /* The first field opens from the middle outwards when the page loads, and its
       strips come back down over it as the page is scrolled away. Open or closed, they
       hang still: they move only to open and close.

       The closing runs from 22% to 96% of a window's scrolling. A window shorter than
       the field's least height (44rem) adds the difference to both ends, since there
       the field runs on below the screen: the strips wait until the reader has seen
       the whole sentence and the line under it. */
    .window .strip {
      animation:
        open var(--time-4) var(--ease-open) calc(var(--time-1) + var(--edge) * var(--time-2)) backwards,
        close linear both;
      animation-timeline: auto, scroll(root block);
      animation-range: normal, calc(max(100svh, 44rem) - 78svh) calc(max(100svh, 44rem) - 4svh);
    }

    .window-text {
      animation: arrive var(--time-3) var(--ease-settle) var(--time-3) backwards;
    }
  }

  /* A tile answers, its object takes its pose, and the first app's paper parts, each
     strip a share of time 1 after the last. */
  .tile {
    transition: scale var(--time-2) var(--ease-settle);
  }

  .move {
    transition: transform var(--time-2) var(--ease-settle);
  }

  .wrap span {
    transition: height var(--time-3) var(--ease-settle) calc(var(--d) * var(--time-1));
  }

  /* Each object does one small thing of its own when it is chosen. */
  .pick:checked ~ .tile .coin {
    animation: spin var(--time-3) var(--ease-settle);
  }

  .pick:checked ~ .tile .eye {
    animation: nod var(--time-3) var(--ease-settle);
  }

  .pick:checked ~ .tile .phone {
    animation: rock var(--time-3) var(--ease-sway);
  }

  .pick:checked ~ .tile .case {
    animation: hop var(--time-3) var(--ease-sway);
  }

  /* The pointer slides along to the chosen tile, and the old panel fades as the new
     one rises into its place. */
  @supports selector(:has(*)) {
    .panels::before {
      transition: left var(--time-2) var(--ease-settle);
    }

    .panel {
      translate: 0 0.5rem;
      transition: opacity var(--time-1) var(--ease-settle), translate var(--time-1) var(--ease-settle), visibility 0s var(--ease-settle) var(--time-1);
    }

    .shelf:has(#open-customer:checked) #customer,
    .shelf:has(#open-watching:checked) #watching,
    .shelf:has(#open-device:checked) #device,
    .shelf:has(#open-take:checked) #take,
    .shelf:has(#open-app:checked) #app {
      translate: 0 0;
      /* The new panel starts in halfway through the old one's fade. */
      transition: opacity var(--time-1) var(--ease-settle) calc(var(--time-1) / 2), translate var(--time-2) var(--ease-settle) calc(var(--time-1) / 2), visibility 0s;
    }
  }
}

@keyframes light {
  from { background-position: 100% 0, 0 0; }
  to { background-position: 0% 0, 0 0; }
}

@keyframes open {
  from { --enter: 1; }
}

@keyframes close {
  to { --leave: 1; }
}

@keyframes arrive {
  from {
    opacity: 0;
    translate: 0 1rem;
  }
}

@keyframes spin {
  0%, 50%, 100% { scale: 1 1; }
  25%, 75% { scale: 0.06 1; }
}

@keyframes nod {
  0%, 100% { translate: 0 0; scale: 1 1; }
  35% { translate: 0 3px; scale: 1 0.78; }
  65% { translate: 0 -1px; scale: 1 1.04; }
}

@keyframes rock {
  0%, 100% { rotate: 0deg; }
  25% { rotate: -12deg; }
  55% { rotate: 8deg; }
  80% { rotate: -3deg; }
}

@keyframes hop {
  0%, 100% { translate: 0 0; rotate: 0deg; }
  30% { translate: 0 -6px; rotate: -5deg; }
  55% { translate: 0 0; rotate: 0deg; }
  72% { translate: 0 -2px; }
}

/* ---------------------------------------------------------------- contrast */

/* A reader who has asked for more contrast (Increase Contrast, on Apple's devices)
   gets the soft text on the fields at full strength. */
@media (prefers-contrast: more) {
  :root {
    --on-mark-soft: var(--on-mark);
  }
}

/* In a high-contrast theme the reader's own colours replace the page's and the
   backgrounds go, so the fields and the strips would turn to blank page with stray
   shadows, and the tiles and the panel would lose their edges. The strips step out,
   and what the colours said is drawn in lines, in the theme's own colours: a line
   round each tile, a heavier one round the chosen tile, and a line round the panel. */
@media (forced-colors: active) {
  .bark,
  .wrap,
  .panels::before {
    display: none;
  }

  .tile {
    border: 1px solid CanvasText;
  }

  .pick:checked ~ .tile {
    border: 3px solid Highlight;
  }

  .panels {
    border: 1px solid CanvasText;
  }
}

/* ---------------------------------------------------------------- narrow */

/* On a phone the sentence needs the whole width, and in a short window it needs the
   whole height, so in either the strips stay short all the way across. */
@media (max-width: 48rem), (max-height: 34rem) {
  :root {
    --drape: 8;
    --ragged: 8;
    --run: 5.5rem;
  }

  /* Here the field is 92% of the window, or 44rem in a window too short for that,
     and the padding over the sentence is the header and one step however tall the
     window is, so that a tall phone puts the sentence nearer the top of the screen
     instead of leaving the field empty above it. The sentence is centred in the room
     left below that padding. */
  .window {
    min-height: max(92svh, 44rem);
    padding-block: calc(var(--header) + var(--space-6)) max(19svh, var(--space-7));
  }
}

/* On a phone every second strip of the first field and every third of the last step
   out as well, so the rest keep their breadth. */
@media (max-width: 48rem) {
  .window .strip:nth-child(even) {
    display: none;
  }

  .closing .strip:nth-child(3n) {
    display: none;
  }
}

/* Five names will not fit under five tiles on a phone, so the names give way and the
   open panel's own title says which one is open. They stay there for a screen reader. */
@media (max-width: 40rem) {
  .tile-name {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* The tiles stand close together here, so the focus ring is drawn closer in. */
  .pick:focus-visible ~ .tile {
    outline-width: 2px;
    outline-offset: 2px;
  }
}

/* ---------------------------------------------------------------- the strips, one by one

   Each strip's breadth (--w), how near the side of the row it sits (--edge, 0 in the
   middle and 1 at either side), its share of the ragged line (--j), the slant of its
   free end (--cl, --cr) and its paper (--tone). The numbers were drawn once at random
   and are kept as they fell. */

.high .strip:nth-child(1) { --w: 1.11; --edge: 0.883; --j: 0.03; --cl: 0.67rem; --cr: 0.83rem; --tone: var(--bark-2); }
.high .strip:nth-child(2) { --w: 1.22; --edge: 0.669; --j: 0.00; --cl: 0.72rem; --cr: 1.21rem; --tone: var(--bark-1); }
.high .strip:nth-child(3) { --w: 1.62; --edge: 0.459; --j: 0.71; --cl: 0.09rem; --cr: 1.00rem; --tone: var(--bark-2); }
.high .strip:nth-child(4) { --w: 1.12; --edge: 0.306; --j: 0.11; --cl: 0.89rem; --cr: 0.28rem; --tone: var(--bark-1); }
.high .strip:nth-child(5) { --w: 1.17; --edge: 0.207; --j: 0.47; --cl: 0.82rem; --cr: 1.01rem; --tone: var(--bark-2); }
.high .strip:nth-child(6) { --w: 1.25; --edge: 0.130; --j: 0.34; --cl: 1.20rem; --cr: 0.17rem; --tone: var(--bark-1); }
.high .strip:nth-child(7) { --w: 0.82; --edge: 0.082; --j: 0.01; --cl: 0.24rem; --cr: 0.66rem; --tone: var(--bark-1); }
.high .strip:nth-child(8) { --w: 1.17; --edge: 0.049; --j: 0.42; --cl: 0.00rem; --cr: 1.12rem; --tone: var(--bark-3); }
.high .strip:nth-child(9) { --w: 1.3; --edge: 0.022; --j: 0.30; --cl: 1.11rem; --cr: 0.83rem; --tone: var(--bark-1); }
.high .strip:nth-child(10) { --w: 1.48; --edge: 0.007; --j: 0.04; --cl: 0.79rem; --cr: 1.08rem; --tone: var(--bark-2); }
.high .strip:nth-child(11) { --w: 0.72; --edge: 0.002; --j: 0.07; --cl: 0.78rem; --cr: 0.48rem; --tone: var(--bark-2); }
.high .strip:nth-child(12) { --w: 0.95; --edge: 0.000; --j: 0.13; --cl: 0.50rem; --cr: 0.82rem; --tone: var(--bark-2); }
.high .strip:nth-child(13) { --w: 0.72; --edge: 0.000; --j: 0.91; --cl: 0.96rem; --cr: 1.22rem; --tone: var(--bark-1); }
.high .strip:nth-child(14) { --w: 1.49; --edge: 0.000; --j: 0.69; --cl: 0.06rem; --cr: 0.14rem; --tone: var(--bark-3); }
.high .strip:nth-child(15) { --w: 1.37; --edge: 0.003; --j: 0.96; --cl: 1.07rem; --cr: 0.78rem; --tone: var(--bark-2); }
.high .strip:nth-child(16) { --w: 0.67; --edge: 0.009; --j: 0.52; --cl: 0.62rem; --cr: 0.85rem; --tone: var(--bark-3); }
.high .strip:nth-child(17) { --w: 1.68; --edge: 0.022; --j: 0.61; --cl: 0.02rem; --cr: 0.35rem; --tone: var(--bark-2); }
.high .strip:nth-child(18) { --w: 1.66; --edge: 0.062; --j: 0.25; --cl: 1.26rem; --cr: 0.12rem; --tone: var(--bark-1); }
.high .strip:nth-child(19) { --w: 1.33; --edge: 0.125; --j: 0.89; --cl: 0.76rem; --cr: 0.18rem; --tone: var(--bark-1); }
.high .strip:nth-child(20) { --w: 1.28; --edge: 0.208; --j: 0.92; --cl: 0.04rem; --cr: 0.78rem; --tone: var(--bark-1); }
.high .strip:nth-child(21) { --w: 0.79; --edge: 0.296; --j: 0.48; --cl: 0.10rem; --cr: 0.71rem; --tone: var(--bark-1); }
.high .strip:nth-child(22) { --w: 0.64; --edge: 0.369; --j: 0.90; --cl: 1.19rem; --cr: 0.46rem; --tone: var(--bark-2); }
.high .strip:nth-child(23) { --w: 1.19; --edge: 0.480; --j: 0.90; --cl: 1.12rem; --cr: 0.74rem; --tone: var(--bark-3); }
.high .strip:nth-child(24) { --w: 0.68; --edge: 0.615; --j: 0.66; --cl: 0.12rem; --cr: 0.15rem; --tone: var(--bark-2); }
.high .strip:nth-child(25) { --w: 0.83; --edge: 0.742; --j: 0.88; --cl: 0.76rem; --cr: 0.57rem; --tone: var(--bark-3); }
.high .strip:nth-child(26) { --w: 0.88; --edge: 0.907; --j: 0.08; --cl: 0.63rem; --cr: 0.30rem; --tone: var(--bark-1); }

.low .strip:nth-child(1) { --w: 1.62; --edge: 0.836; --j: 0.76; --cl: 0.41rem; --cr: 0.11rem; --tone: var(--bark-2); }
.low .strip:nth-child(2) { --w: 1.64; --edge: 0.565; --j: 0.18; --cl: 0.21rem; --cr: 1.04rem; --tone: var(--bark-3); }
.low .strip:nth-child(3) { --w: 1.58; --edge: 0.363; --j: 0.32; --cl: 0.13rem; --cr: 0.05rem; --tone: var(--bark-2); }
.low .strip:nth-child(4) { --w: 0.71; --edge: 0.254; --j: 0.94; --cl: 1.17rem; --cr: 0.70rem; --tone: var(--bark-2); }
.low .strip:nth-child(5) { --w: 1.26; --edge: 0.180; --j: 0.55; --cl: 0.92rem; --cr: 1.08rem; --tone: var(--bark-1); }
.low .strip:nth-child(6) { --w: 1.08; --edge: 0.114; --j: 0.33; --cl: 0.50rem; --cr: 0.58rem; --tone: var(--bark-1); }
.low .strip:nth-child(7) { --w: 1.19; --edge: 0.068; --j: 0.06; --cl: 0.89rem; --cr: 1.27rem; --tone: var(--bark-1); }
.low .strip:nth-child(8) { --w: 0.76; --edge: 0.040; --j: 0.54; --cl: 1.27rem; --cr: 0.49rem; --tone: var(--bark-1); }
.low .strip:nth-child(9) { --w: 0.83; --edge: 0.024; --j: 0.04; --cl: 0.60rem; --cr: 0.38rem; --tone: var(--bark-1); }
.low .strip:nth-child(10) { --w: 1.1; --edge: 0.012; --j: 0.10; --cl: 1.06rem; --cr: 0.33rem; --tone: var(--bark-2); }
.low .strip:nth-child(11) { --w: 0.86; --edge: 0.004; --j: 0.16; --cl: 0.54rem; --cr: 0.21rem; --tone: var(--bark-3); }
.low .strip:nth-child(12) { --w: 1.11; --edge: 0.001; --j: 0.69; --cl: 0.83rem; --cr: 0.31rem; --tone: var(--bark-2); }
.low .strip:nth-child(13) { --w: 0.65; --edge: 0.000; --j: 0.43; --cl: 0.07rem; --cr: 0.37rem; --tone: var(--bark-1); }
.low .strip:nth-child(14) { --w: 0.71; --edge: 0.000; --j: 0.63; --cl: 0.32rem; --cr: 1.24rem; --tone: var(--bark-1); }
.low .strip:nth-child(15) { --w: 1.39; --edge: 0.000; --j: 0.34; --cl: 1.24rem; --cr: 1.04rem; --tone: var(--bark-2); }
.low .strip:nth-child(16) { --w: 1.07; --edge: 0.002; --j: 0.00; --cl: 1.13rem; --cr: 0.26rem; --tone: var(--bark-1); }
.low .strip:nth-child(17) { --w: 1.17; --edge: 0.007; --j: 0.17; --cl: 0.91rem; --cr: 0.62rem; --tone: var(--bark-3); }
.low .strip:nth-child(18) { --w: 1.41; --edge: 0.022; --j: 0.72; --cl: 1.29rem; --cr: 0.29rem; --tone: var(--bark-1); }
.low .strip:nth-child(19) { --w: 1.01; --edge: 0.047; --j: 0.86; --cl: 0.79rem; --cr: 0.38rem; --tone: var(--bark-2); }
.low .strip:nth-child(20) { --w: 0.68; --edge: 0.072; --j: 0.41; --cl: 0.21rem; --cr: 0.06rem; --tone: var(--bark-2); }
.low .strip:nth-child(21) { --w: 1.47; --edge: 0.117; --j: 0.76; --cl: 0.50rem; --cr: 1.16rem; --tone: var(--bark-1); }
.low .strip:nth-child(22) { --w: 1.26; --edge: 0.198; --j: 0.50; --cl: 0.74rem; --cr: 0.57rem; --tone: var(--bark-1); }
.low .strip:nth-child(23) { --w: 1.33; --edge: 0.304; --j: 0.26; --cl: 0.82rem; --cr: 0.06rem; --tone: var(--bark-1); }
.low .strip:nth-child(24) { --w: 1.29; --edge: 0.446; --j: 0.28; --cl: 0.12rem; --cr: 0.96rem; --tone: var(--bark-2); }
.low .strip:nth-child(25) { --w: 1.67; --edge: 0.656; --j: 0.61; --cl: 0.91rem; --cr: 0.79rem; --tone: var(--bark-1); }
.low .strip:nth-child(26) { --w: 1.01; --edge: 0.895; --j: 0.98; --cl: 0.79rem; --cr: 0.18rem; --tone: var(--bark-2); }

.fringe .strip:nth-child(1) { --w: 1.36; --j: 0.83; --cl: 0.04rem; --cr: 0.68rem; --tone: var(--bark-1); }
.fringe .strip:nth-child(2) { --w: 0.72; --j: 0.51; --cl: 0.47rem; --cr: 0.92rem; --tone: var(--bark-1); }
.fringe .strip:nth-child(3) { --w: 1.29; --j: 0.02; --cl: 0.95rem; --cr: 1.17rem; --tone: var(--bark-1); }
.fringe .strip:nth-child(4) { --w: 1.53; --j: 0.74; --cl: 0.39rem; --cr: 0.05rem; --tone: var(--bark-2); }
.fringe .strip:nth-child(5) { --w: 1.52; --j: 0.72; --cl: 0.06rem; --cr: 0.58rem; --tone: var(--bark-3); }
.fringe .strip:nth-child(6) { --w: 1.18; --j: 0.65; --cl: 0.17rem; --cr: 0.46rem; --tone: var(--bark-1); }
.fringe .strip:nth-child(7) { --w: 1.3; --j: 1.00; --cl: 0.32rem; --cr: 0.69rem; --tone: var(--bark-2); }
.fringe .strip:nth-child(8) { --w: 1.02; --j: 0.03; --cl: 0.15rem; --cr: 0.22rem; --tone: var(--bark-3); }
.fringe .strip:nth-child(9) { --w: 1.19; --j: 0.52; --cl: 0.73rem; --cr: 0.07rem; --tone: var(--bark-1); }
.fringe .strip:nth-child(10) { --w: 0.74; --j: 0.40; --cl: 0.06rem; --cr: 1.07rem; --tone: var(--bark-2); }
.fringe .strip:nth-child(11) { --w: 1.36; --j: 0.90; --cl: 1.20rem; --cr: 0.05rem; --tone: var(--bark-3); }
.fringe .strip:nth-child(12) { --w: 1.27; --j: 0.67; --cl: 0.01rem; --cr: 0.35rem; --tone: var(--bark-3); }
.fringe .strip:nth-child(13) { --w: 0.92; --j: 0.87; --cl: 1.29rem; --cr: 1.08rem; --tone: var(--bark-2); }
.fringe .strip:nth-child(14) { --w: 1.03; --j: 0.97; --cl: 1.10rem; --cr: 0.63rem; --tone: var(--bark-1); }
.fringe .strip:nth-child(15) { --w: 1.42; --j: 0.92; --cl: 1.03rem; --cr: 0.93rem; --tone: var(--bark-2); }
.fringe .strip:nth-child(16) { --w: 1.1; --j: 0.65; --cl: 0.95rem; --cr: 1.22rem; --tone: var(--bark-3); }
.fringe .strip:nth-child(17) { --w: 1.66; --j: 0.58; --cl: 0.48rem; --cr: 1.21rem; --tone: var(--bark-1); }
.fringe .strip:nth-child(18) { --w: 1.67; --j: 0.17; --cl: 1.23rem; --cr: 0.81rem; --tone: var(--bark-1); }
.fringe .strip:nth-child(19) { --w: 1.53; --j: 0.27; --cl: 0.71rem; --cr: 1.23rem; --tone: var(--bark-1); }
.fringe .strip:nth-child(20) { --w: 0.72; --j: 0.33; --cl: 0.71rem; --cr: 1.24rem; --tone: var(--bark-1); }
.fringe .strip:nth-child(21) { --w: 0.7; --j: 0.39; --cl: 0.65rem; --cr: 0.35rem; --tone: var(--bark-1); }
.fringe .strip:nth-child(22) { --w: 0.93; --j: 0.83; --cl: 0.83rem; --cr: 1.27rem; --tone: var(--bark-1); }
.fringe .strip:nth-child(23) { --w: 1.01; --j: 0.25; --cl: 0.15rem; --cr: 0.20rem; --tone: var(--bark-1); }
.fringe .strip:nth-child(24) { --w: 1.38; --j: 0.26; --cl: 0.18rem; --cr: 0.84rem; --tone: var(--bark-3); }
