/* Generated by site/build.ts from site/page-src/wall.css. Do not edit. */
/* The homepage wall: the dark room, the pool, the stage and its approach, and
 * the closing call to action. */

/* The pointer light's place and how far it has come up, which script writes
 * on the wall root on every frame the light moves. Registered so that they
 * do not inherit: a new value reaches the root and the one box that asks for
 * it by name, and is never handed down through the room. */
@property --wall-light-x {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}

@property --wall-light-y {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}

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

/* How far the pointer light reaches onto card borders at this moment, which
 * script reads from the wall root. Registered as a length so that script
 * reads it in pixels, and not to inherit: it changes as the wall arrives and
 * leaves, and an inheriting value would restyle the whole wall each time. */
@property --wall-light-reach {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}

@layer discern.components {
  body {
    display: flex;
    min-block-size: 100svh;
    margin: 0;
    flex-direction: column;
    background: var(--discern-color-canvas);
  }

  main,
  .wall-frame,
  .wall-host {
    display: grid;
  }

  main {
    flex: 1;
  }

  /* The room is set into the page with a margin of the page's own dark
   * canvas all round it, so it reads as one object the page holds, not as a
   * band the header and footer were cut against. */
  .wall-frame {
    padding: clamp(0.375rem, 0.8vw, 0.75rem);
  }

  /* The surface every face in the room is made of: a near-black that is a
   * little lighter at its head than at its foot. A card, a lens chip, and
   * the sheet a card opens into all end on the one foot. The sheet is the
   * card grown and nearer the reader, so its head is a step lighter than a
   * card's, and the box that carries the one into the other takes the color
   * halfway between the two heads. They are declared on the page's root,
   * where the pictures of a view transition can read them. */
  :root {
    --wall-face-foot: oklch(15.5% 0.008 265);
    --wall-face-head: oklch(19.5% 0.008 265);
    --wall-sheet-head: oklch(20.5% 0.008 265);
  }

  /* The wall is one dark room on a page that is dark for every visitor. It
   * owns its colors and reads none of them from the site's theme. Every
   * tunable value arrives as a --wall-<name> custom property in this
   * element's inline style. */
  .wall {
    --wall-canvas-lch: 10.5% 0.008 265;
    --wall-canvas: oklch(var(--wall-canvas-lch));
    --wall-ink: oklch(100% 0 0 / 0.94);
    --wall-ink-muted: oklch(100% 0 0 / 0.66);
    --wall-ink-faint: oklch(100% 0 0 / 0.56);
    --wall-focus: oklch(85% 0.12 255);

    /* The pointer light at rest: nowhere, and dark. */
    --wall-light-x: 0px;
    --wall-light-y: 0px;
    --wall-light-on: 0;

    /* How far from the pointer light a card's border can catch it, and how
     * far the light reaches now: no card takes it until the wall is near. */
    --wall-light-throw: calc(var(--wall-light-radius) * 0.434);
    --wall-light-reach: 0px;

    /* The room's side padding, which full-width sections reach back across. */
    --wall-gutter: clamp(0.75rem, 1.6vw, 1.5rem);

    position: relative;
    isolation: isolate;
    display: grid;

    /* One column that may be narrower than the longest word in it, so a
     * narrow or zoomed page wraps its words instead of cutting them. */
    grid-template-columns: minmax(0, 1fr);
    align-content: start;
    min-inline-size: 0;
    padding-inline: var(--wall-gutter);
    border-radius: clamp(1rem, 2vw, 1.75rem);

    /* The far plane projects past the room on three sides. Clipping it here
     * keeps the page exactly as wide and as tall as its layout. */
    overflow: clip;
    color: var(--wall-ink);
    font-family: var(--discern-font-ui);
    font-size: 0.95rem;
    line-height: 1.5;

    /* From the top: the room's own light from above, a vignette down both
     * sides, and the canvas. */
    background:
      radial-gradient(
      80rem 44rem at 50% -14rem,
      oklch(36% 0.08 258 / 0.42),
      transparent 70%
    ),
      linear-gradient(
      90deg,
      oklch(0% 0 0 / 0.5),
      transparent 16%,
      transparent 84%,
      oklch(0% 0 0 / 0.5)
    ),
      var(--wall-canvas);
    box-shadow: inset 0 0 0 1px oklch(100% 0 0 / 0.07);
  }

  /* The pointer light on the canvas: one soft disc under everything the room
   * holds, carried to wherever the light is. Following the pointer moves
   * this one box and changes how far up it is. It changes brightness only,
   * lays out nothing, and no card is restyled for it. The disc is painted
   * into the room's own layer: given a layer of its own, the browser lifts
   * every card off the canvas into a second layer the size of the wall.
   *
   * The disc anchors no scroll. A browser holds the page still under a
   * reader by picking a box in view and scrolling after it when it moves,
   * and WebKit would pick this one, the first box in the room, and scroll
   * the page after the light. */
  .wall::before {
    --wall-light-x: inherit;
    --wall-light-y: inherit;
    --wall-light-on: inherit;

    position: absolute;
    inset: 0 auto auto 0;
    z-index: -1;
    overflow-anchor: none;
    inline-size: calc(var(--wall-light-radius) * 1.24);
    block-size: calc(var(--wall-light-radius) * 1.24);
    margin: calc(var(--wall-light-radius) * -0.62) 0 0
      calc(var(--wall-light-radius) * -0.62);
    background: radial-gradient(
      closest-side,
      oklch(100% 0 0 / calc(0.055 * var(--wall-light-strength))),
      transparent
    );
    opacity: var(--wall-light-on);
    translate: var(--wall-light-x) var(--wall-light-y);
    pointer-events: none;
    content: "";
  }

  /* Near, card borders catch the light too, out to its full throw. That
   * needs a pointer to follow, which a touch screen does not promise. */
  @media (hover: hover) {
    .wall[data-wall-near] {
      --wall-light-reach: var(--wall-light-throw);
    }
  }

  /* Fine grain over the whole room, cards included, so its large dark
   * gradients do not band. One tile the browser draws once and repeats. */
  .wall::after {
    position: absolute;
    inset: 0;
    z-index: 6;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='192' height='192'%3E%3Cfilter id='n' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1.4 -0.2'/%3E%3C/filter%3E%3Crect width='192' height='192' filter='url(%23n)'/%3E%3C/svg%3E");
    background-size: 12rem 12rem;
    opacity: var(--wall-grain);
    pointer-events: none;
    content: "";
  }

  /* Selected words keep their own color, on a wash of the room's blue. The
   * site's selection colors are made for the site's own surfaces, and put
   * white on the room's white button. They also read the site's tokens,
   * which the browser works out afresh for every element it restyles, so a
   * selection style that reads one makes every restyle in the room several
   * times dearer. These colors are written out and read none. */
  .wall::selection,
  .wall ::selection {
    color: currentcolor;
    background: oklch(72% 0.13 258 / 0.3);
  }

  /* A cluster's accent: its hue at the room's one lightness and chroma.
   * Whatever carries a hue of its own works its accent out from it here: a
   * card, the sheet a card opens into, and a dot on a lens chip. */
  .wall-card,
  .wall-open,
  .wall-chip-hue {
    --wall-accent: oklch(80% var(--wall-chroma) var(--wall-hue));
  }

  .wall :where(h1, h2, p, ul, li) {
    margin: 0;
    font: inherit;
    letter-spacing: inherit;
    color: inherit;
  }

  .wall :where(button) {
    font: inherit;
    letter-spacing: inherit;
    color: inherit;
  }

  .wall :where(a, button, [tabindex]):focus-visible {
    outline: 2px solid var(--wall-focus);
    outline-offset: 3px;
  }

  /* Read by assistive technology and never drawn: the lens's status, and
   * the link past the cards until it holds the focus. */
  .wall-lens-status,
  .wall-skip:not(:focus) {
    position: absolute;
    inset: 0 auto auto 0;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    min-block-size: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* The pool: the upright, readable center of the first viewport. It sits
   * above the stage, so nothing the stage projects can cross its words. */
  .wall-pool {
    position: relative;
    z-index: 1;
    display: grid;
    align-content: center;
    justify-items: center;
    padding-block: clamp(2.75rem, 8vh, 5.5rem) clamp(2rem, 5vh, 3.25rem);
    text-align: center;
  }

  .wall-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.28rem 0.8rem;
    border: 1px solid oklch(100% 0 0 / 0.1);
    border-radius: 999px;
    font-size: 0.8rem;
    color: var(--wall-ink-muted);
    background: oklch(100% 0 0 / 0.035);
  }

  .wall-name {
    font-family: var(--discern-font-mono);
    color: var(--wall-ink);
  }

  /* The headline takes the pool's whole width and breaks only where it must,
   * into lines of like length. Its light falls off toward its foot. A mask
   * does it, so the text keeps one solid color for contrast and for forced
   * colors. The mask clips at the box, so the box is padded to hold the
   * descenders. Wrapped over two lines the fall-off is slight, so the second
   * line is not read as the lesser one; on one line it is deeper. */
  .wall-headline {
    margin-block: 1.4rem -0.14em;
    padding-block-end: 0.14em;
    font-family: var(--discern-font-marketing);
    font-size: clamp(2.9rem, 6.6vw, 6.75rem);
    font-weight: 600;
    line-height: 0.98;
    letter-spacing: -0.045em;
    text-wrap: balance;

    /* A room narrower than the longest word breaks the word. */
    overflow-wrap: anywhere;
    mask-image: linear-gradient(
      180deg,
      oklch(0% 0 0) 55%,
      oklch(0% 0 0 / 0.86)
    );
  }

  /* Under a headline that wraps, the line below it wraps as well, so it is
   * never the wider of the two. */
  .wall-category {
    max-inline-size: 30ch;
    margin-block-start: clamp(1rem, 2.4vh, 1.5rem);
    font-size: clamp(1.1rem, 1.45vw, 1.4rem);
    line-height: 1.35;
    letter-spacing: -0.012em;
    color: var(--wall-ink-muted);
    text-wrap: balance;
  }

  .wall-actions {
    margin-block-start: clamp(1.4rem, 3.4vh, 2.1rem);
  }

  .wall-cta {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.78rem 1.3rem;

    /* Unseen here; forced colors and print draw it as the button's outline. */
    border: 1px solid transparent;
    border-radius: 0.75rem;
    font-weight: 550;
    letter-spacing: -0.005em;
    text-decoration: none;
    color: oklch(13% 0 0);
    background: oklch(100% 0 0 / 0.94);
    box-shadow:
      0 0 0 1px oklch(100% 0 0 / 0.14),
      0 0.75rem 2.5rem -0.75rem oklch(78% 0.12 258 / 0.55);
  }

  .wall-cta:hover {
    background: oklch(100% 0 0);
  }

  .wall-facts {
    margin-block-start: 1rem;
    font-size: 0.82rem;
    color: var(--wall-ink-faint);
  }

  /* The stage: the lens bar and the plane the cards lie on. */
  .wall-stage {
    position: relative;
    inline-size: 100%;
    max-inline-size: 118rem;
    margin-inline: auto;
  }

  /* The link past the cards is the stage's first control. It takes no room
   * and is drawn only while it holds the focus: one light object just above
   * the head of the wall, clear of the lens bar. */
  .wall-skip {
    position: absolute;
    inset-block-end: calc(100% + 0.25rem);
    inset-inline-start: 0;
    z-index: 6;
    display: inline-flex;
    align-items: center;
    min-block-size: 2rem;
    padding: 0 0.9375rem;
    border: 1px solid transparent;
    border-radius: 999px;
    font-size: 0.84rem;
    font-weight: 550;
    line-height: 1;
    text-decoration: none;
    color: oklch(15% 0 0);
    background: oklch(95% 0 0);
  }

  /* The lens bar stays with the reader down the wall. Behind it the canvas
   * is solid and then fades, so the cards pass under it and none is cut. */
  .wall-controls {
    position: sticky;
    inset-block-start: 0;
    z-index: 5;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.5rem 1rem;
    padding-block: 0.875rem 1.5rem;
    pointer-events: none;
  }

  .wall-controls > * {
    pointer-events: auto;
  }

  .wall-controls::before {
    position: absolute;
    inset: 0 -50vw;
    z-index: -1;
    background: linear-gradient(
      180deg,
      var(--wall-canvas) 70%,
      oklch(var(--wall-canvas-lch) / 0)
    );
    content: "";
  }

  /* The bar arrives whole when the controls come alive. An element shown
   * through its parent's visibility must not transition that visibility
   * itself: under reduced motion the design system gives every transition a
   * token duration, and each level of the bar would then appear a frame after
   * the one above it. Neither box here has a transition of its own, and the
   * lens stylesheet says the same of what the bar holds. */
  .wall-controls,
  .wall-controls::before {
    transition: none;
  }

  /* On a short screen, or a page zoomed until it is one, a pinned bar would
   * take a third of the view. There it stays at the head of the wall. */
  @media (max-height: 30rem) {
    .wall-controls {
      position: static;
    }
  }

  /* Controls need script. Their space is kept, so nothing shifts on hydration. */
  .wall:not([data-wall-live]) .wall-controls {
    visibility: hidden;
  }

  /* The pause control exists only while the plane drifts, and the plane
   * drifts only while it is far. It takes the corner of the far view, where
   * the lens bar has not yet arrived. */
  .wall-stage > .wall-pause {
    position: absolute;
    inset-block-start: 0.875rem;
    inset-inline-start: 0;
    z-index: 5;
  }

  .wall[data-wall-near] .wall-stage > .wall-pause {
    display: none;
  }

  /* The plane keeps the list's margin inside itself. The list starts above
   * the plane's top edge, and that edge, which the far view hinges on, stays
   * where it is. */
  .wall-plane {
    display: flow-root;
  }

  /* The wall: a masonry in DOM order, so focus order and reading order agree.
   * A lens re-sorts the list under the reader. No card in it anchors the
   * page's scroll, or the page would follow one card to its new place.
   *
   * The list is one stacking context. A layer the browser composites beside
   * it, as the far view's horizon is beneath the cards, then lifts the list
   * as one layer. Left open, WebKit lifts each card over that layer into a
   * layer of its own, and it draws a card lifted out of a multi-column list
   * in the wrong column.
   *
   * Every card carries the gap above it inside its own line, the first row
   * included, so the list pulls up by one gap. A card is a whole line, so
   * one line may stand alone at the head or the foot of a column. */
  .wall-list {
    columns: 4 16.5rem;
    column-gap: var(--wall-gap);
    margin-block-start: calc(var(--wall-gap) * -1);
    padding: 0;
    overflow-anchor: none;
    list-style: none;
    isolation: isolate;
    orphans: 1;
    widows: 1;
  }

  @media (min-width: 105rem) {
    .wall-list {
      columns: 5 16.5rem;
    }
  }

  .wall-closing {
    position: relative;
    display: grid;
    justify-items: center;
    margin-inline: calc(var(--wall-gutter) * -1);
    padding: clamp(3rem, 8vh, 5rem) 1.5rem clamp(5.5rem, 17vh, 9.5rem);
    text-align: center;
    background: radial-gradient(
      64rem 26rem at 50% 100%,
      oklch(36% 0.08 258 / 0.4),
      transparent 70%
    );
  }

  /* The link past the cards hands this heading the focus, and the page
   * comes to rest with the section's own margin above it. */
  .wall-closing-title {
    border-radius: 0.5rem;
    font-family: var(--discern-font-marketing);
    font-size: clamp(2rem, 4.2vw, 3.5rem);
    font-weight: 600;
    line-height: 1.04;
    letter-spacing: -0.04em;
    scroll-margin-block-start: clamp(3rem, 8vh, 5rem);
  }

  .wall-closing-title:focus-visible {
    outline-offset: 0.5rem;
  }

  .wall-closing-line {
    margin-block-start: 1rem;
    font-size: clamp(1rem, 1.2vw, 1.15rem);
    color: var(--wall-ink-muted);
  }

  /* Entrance: the wall fades in once, as a whole, with no script. */
  @keyframes wall-enter {
    from {
      opacity: 0;
    }
  }

  @media screen and (prefers-reduced-motion: no-preference) {
    .wall-plane {
      animation: wall-enter 0.9s cubic-bezier(0.2, 0.8, 0.2, 1) backwards;
    }
  }

  /* From here the pool is wide enough for the headline on one line, and the
   * line below it takes one line as well. */
  @media (min-width: 34rem) {
    .wall-headline {
      mask-image: linear-gradient(
        180deg,
        oklch(0% 0 0) 45%,
        oklch(0% 0 0 / 0.68)
      );
    }

    .wall-category {
      max-inline-size: none;
    }
  }

  @media (min-width: 60rem) {
    .wall-pool {
      min-block-size: 50svh;
    }
  }

  /* The approach. In the first viewport the plane is a floor seen from above
   * its near edge: hinged along its top, tilted until the far rows meet a
   * horizon under the pool, and set back so those rows are small. Scrolling
   * the pool out of the viewport brings the plane upright and forward as one
   * rigid body. The pool's own exit times it, so the wall is flat the moment
   * its top reaches the top of the viewport, on the compositor, with no
   * script and from the first paint.
   *
   * The stage marks the wall root data-wall-near once the pool is gone, and
   * every rule here stands down in that state: a flat plane carries no
   * transform at all. Phones, reduced motion, forced colors, print, and
   * browsers without scroll-driven animations never leave it.
   *
   * Every rule here stands down, too, under the keyboard's focus, with no
   * script: the stage while that focus is anywhere on it, the plane while it
   * is on a card or on the link past the cards, and the lens bar while it is
   * in the bar. A card the keyboard reaches is then at its reading size
   * where it lies, so the browser scrolls to it as it would on any page.
   * Script marks the root near once that focus is on the stage, which lays
   * the plane flat under a focused lens chip as well, and keeps the mark
   * until the focus leaves the stage. A pointer's press takes the focus
   * without the keyboard's mark, and these rules alone would tilt the plane
   * away under the press.
   *
   * Each rule looks for that focus from the box it styles. A rule that
   * looked from the wall root instead would have the browser restyle the
   * whole wall at every step of the keyboard, and so would one that styled
   * every child of a box by no name. */
  @keyframes wall-approach {
    from {
      transform: translateZ(
        calc(
          var(--wall-perspective) * 1svh * (var(--wall-far-scale) - 1) /
          var(--wall-far-scale)
        )
      )
        rotateX(var(--wall-far-tilt));
    }

    to {
      transform: translateZ(0) rotateX(0deg);
    }
  }

  @keyframes wall-far-only {
    from {
      opacity: 1;
    }

    to {
      opacity: 0;
    }
  }

  /* The lens bar comes in over the last of the approach and goes out as the
   * closing section comes in. It only fades: unseen, it is still there for
   * the keyboard and for assistive technology. What it holds takes no press
   * until it is half seen. A keyword has no halfway, so it changes at the
   * middle of the same stretch the fade covers. */
  @keyframes wall-arrive {
    from,
    84% {
      opacity: 0;
    }

    to {
      opacity: 1;
    }
  }

  @keyframes wall-arrive-press {
    from,
    84% {
      pointer-events: none;
    }

    to {
      pointer-events: auto;
    }
  }

  @keyframes wall-leave {
    to {
      opacity: 0;
    }
  }

  @keyframes wall-leave-press {
    from {
      pointer-events: auto;
    }

    to {
      pointer-events: none;
    }
  }

  /* A slow sway of the point the floor recedes to. The far rows travel about
   * the knob's distance each way, nearer rows less, and anything at the
   * hinge's depth not at all, so a flat plane cannot drift. */
  @keyframes wall-drift {
    from {
      perspective-origin: calc(50% - var(--wall-drift) * 2)
        calc(var(--wall-vanish) * -1svh);
    }

    to {
      perspective-origin: calc(50% + var(--wall-drift) * 2)
        calc(var(--wall-vanish) * -1svh);
    }
  }

  /* At the foot of the wall the lens bar has nothing left to sort, and on
   * some screens the page ends with the bar cut by the viewport's edge. So
   * it fades out as the closing section comes in, and is gone while the
   * section's top is still well clear of the bar. Keyboard focus inside the
   * bar shows it whole wherever the page stands, and so does a press on it:
   * a pointer takes the focus from the keyboard as it presses a chip, and a
   * bar that went out under the press would lose the click. */
  @supports (animation-timeline: view()) and (timeline-scope: --wall-closing) {
    .wall {
      timeline-scope: --wall-closing;
    }

    .wall-closing {
      view-timeline: --wall-closing block;
    }

    .wall-controls:not(:has(:focus-visible, :active)) {
      animation: wall-leave linear both;
      animation-timeline: --wall-closing;
      animation-range: entry 30% entry 80%;
    }

    .wall-controls:not(:has(:focus-visible, :active)) .wall-lens {
      animation: wall-leave-press linear both;
      animation-timeline: --wall-closing;
      animation-range: entry 30% entry 80%;
    }
  }

  @supports (animation-timeline: view()) and (timeline-scope: --wall-pool) {
    @media screen and (min-width: 60rem) and (min-height: 37.5rem) and (hover:
      hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) and
      (forced-colors: none) {
      .wall {
        timeline-scope: --wall-pool, --wall-closing;
      }

      /* The stage reads this name to learn that the approach is staged. */
      .wall-pool {
        view-timeline: --wall-pool block;
      }

      .wall:not([data-wall-near]) .wall-stage:not(:has(:focus-visible:not(.wall-pause))) {
        perspective: calc(var(--wall-perspective) * 1svh);
        perspective-origin: 50% calc(var(--wall-vanish) * -1svh);
      }

      .wall:not([data-wall-near]) .wall-plane:not(:has(:focus-visible), .wall-skip:focus-visible ~ *) {
        position: relative;
        transform-origin: 50% 0;
        animation:
          wall-enter 0.9s cubic-bezier(0.2, 0.8, 0.2, 1) backwards,
          wall-approach linear both;
        animation-timeline: auto, --wall-pool;
        animation-range: normal, exit 0% exit 100%;
      }

      /* Light on the horizon: a low, wide glow lying on the floor's own plane
       * across its far edge, so it foreshortens with the floor. Both atmosphere
       * layers stay transparent until their scroll timeline supplies progress;
       * wall-far-only owns their visible opacity. */
      .wall:not([data-wall-near]) .wall-plane:not(:has(:focus-visible), .wall-skip:focus-visible ~ *)::before {
        position: absolute;
        inset: -22rem -34rem auto;
        z-index: -1;
        block-size: 52rem;
        background: radial-gradient(
          closest-side,
          oklch(66% 0.14 258 / calc(0.55 * var(--wall-horizon))),
          oklch(50% 0.12 262 / calc(0.2 * var(--wall-horizon))) 45%,
          transparent
        );
        opacity: 0;
        animation: wall-far-only linear both;
        animation-timeline: --wall-pool;
        animation-range: exit 0% exit 80%;
        pointer-events: none;
        content: "";
      }

      /* Haze: the far rows sink into the canvas the farther off they lie. The
       * list draws it, over its own cards and inside its own stacking
       * context, so the face a card raises under the pointer stands clear of
       * it. The plane places it: the list is not positioned. The list looks
       * for keyboard focus from its own box, as the plane does from its own. */
      .wall:not([data-wall-near]) .wall-plane:not(.wall-skip:focus-visible ~ *) > .wall-list:not(:has(:focus-visible))::after {
        position: absolute;
        inset: -1rem -1rem auto;
        block-size: 44rem;
        background: linear-gradient(
          180deg,
          oklch(var(--wall-canvas-lch) / var(--wall-haze)) 12%,
          oklch(var(--wall-canvas-lch) / 0)
        );
        opacity: 0;
        animation: wall-far-only linear both;
        animation-timeline: --wall-pool;
        animation-range: exit 0% exit 80%;
        pointer-events: none;
        content: "";
      }

      .wall[data-wall-live]:not([data-wall-near]) .wall-controls:not(:has(:focus-visible)) {
        animation: wall-arrive linear both;
        animation-timeline: --wall-pool;
        animation-range: exit 0% exit 100%;
      }

      .wall[data-wall-live]:not([data-wall-near]) .wall-controls:not(:has(:focus-visible)) .wall-lens {
        animation: wall-arrive-press linear both;
        animation-timeline: --wall-pool;
        animation-range: exit 0% exit 100%;
      }

      .wall[data-wall-drift]:not([data-wall-near]) .wall-stage:not(:has(:focus-visible:not(.wall-pause))) {
        animation: wall-drift 16s ease-in-out infinite alternate;
      }

      .wall[data-wall-drift][data-wall-paused]:not([data-wall-near]) .wall-stage:not(:has(:focus-visible:not(.wall-pause))) {
        animation-play-state: paused;
      }
    }
  }

  /* Forced colors drop every gradient: the room's light, its grain, and the
   * fade behind the lens bar. The bar gets a solid backing in the system's
   * own canvas and a rule along its foot instead, so cards pass under it and
   * no chip is left sitting on a card's words. */
  @media (forced-colors: active) {
    .wall-headline {
      mask-image: none;
    }

    .wall::before,
    .wall::after {
      display: none;
    }

    .wall-controls {
      padding-block-end: 0.875rem;
    }

    .wall-controls::before {
      border-block-end: 1px solid CanvasText;
      background: Canvas;
    }
  }

  /* A reader who asks for more contrast gets the room's quieter inks nearer
   * to its full ink. */
  @media (prefers-contrast: more) {
    .wall {
      --wall-ink-muted: oklch(100% 0 0 / 0.86);
      --wall-ink-faint: oklch(100% 0 0 / 0.8);
    }
  }

  /* On paper the page is the room alone, as a plain sheet: dark ink, no
   * light, and no controls. Paper is light, so the page takes the light
   * scheme's system colors and gives up the site's canvas, and no dark
   * margin frames the sheet. The room keeps a light surface of its own, so
   * its ink stays readable whether or not the reader prints backgrounds.
   * The header and footer take their inks from the page's dark theme, which
   * paper cannot carry, so they stay off the page. */
  @media print {
    html {
      color-scheme: light;
    }

    html,
    body {
      background: none;
    }

    body > :not(main) {
      display: none;
    }

    .wall-frame {
      padding: 0;
    }

    .wall {
      --wall-ink: CanvasText;
      --wall-ink-muted: CanvasText;
      --wall-ink-faint: CanvasText;

      border-radius: 0;
      background: Canvas;
      box-shadow: none;
    }

    .wall::before,
    .wall::after,
    .wall-skip,
    .wall-controls {
      display: none;
    }

    .wall-pool {
      min-block-size: 0;
    }

    /* Paper has no layers, so a card there is a block with the gap under
     * it, and the list starts where the plane does. */
    .wall-list {
      margin-block-start: 0;
    }

    .wall-headline {
      mask-image: none;
    }

    .wall-eyebrow,
    .wall-cta {
      border-color: CanvasText;
      color: CanvasText;
      background: none;
      box-shadow: none;
    }

    .wall-closing {
      background: none;
    }
  }
}
