/* realityDebug() — site flow redesign
   Ported from new_site/design_handoff_site_flow (Site Flow.dc.html is the
   primary reference). One dark surface: hero -> menu -> reel / lab / email. */

@font-face {
  /* Fallback for platforms without system Helvetica Neue. */
  font-family: 'Helvetica';
  src: url('../fonts/helvetica.ttf') format('truetype');
  font-weight: normal;
  font-display: swap;
}

:root {
  --not-black: #1e1e1e;
  --bg-colour: #dfddd1;
  --overlay-bg: #1b1b1b;
  --hero-dark-ground: #0a0a0c; /* body ground behind dark hero sketches; Safari tints its bars from it */
  --menu-text: #e9e9de;
  --ink: #141311;
  --error: #ff6b5e;

  --ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
  --ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-entrance: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-cube: cubic-bezier(0.34, 1.2, 0.4, 1);

  --font: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;

  --frame-pad-y: 34px;
  --frame-pad-x: 40px;
  --pane-inset-x: 60px;
  --pane-inset-y: 70px;
  --logo-size: 70px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  width: 100%;
  height: 100%;
  overflow: hidden;
}

body {
  background: var(--bg-colour);
  font-family: var(--font);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}

/* Custom cursor replaces the native one on fine-pointer devices only. */
@media (hover: hover) and (pointer: fine) {
  body, a, button, input, textarea, [role="button"] { cursor: none; }
}

button {
  background: none;
  border: none;
  font-family: inherit;
  color: inherit;
}

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

.hero-bg {
  position: fixed;
  inset: 0;
  z-index: 1;
}

.hero-bg canvas { display: block; }

.hero-content {
  position: fixed;
  inset: 0;
  z-index: 2;
  padding: var(--frame-pad-y) var(--frame-pad-x);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  pointer-events: none;
}

.hero-logo-spacer {
  width: var(--logo-size);
  height: var(--logo-size);
}

.hero-headline {
  font-weight: 900;
  font-size: clamp(38px, 6.6vw, 66px);
  line-height: 0.9;
  letter-spacing: -0.02em;
  color: var(--ink);
}

/* Dark-ground hero sketches (meta.json "dark": true, applied by site.js as
   a body class). The headline and hamburger are near-black and sit straight
   on the sketch, so over a dark ground they have to flip to cream — ink on
   annuli's navy measures 1.00:1, i.e. invisible. The logo box carries its
   own --not-black background and reads on any ground, so it stays put.

   The hamburger is scoped :not(.menu-open) rather than left to source
   order: once the menu is open its own rule owns that colour, and the two
   selectors otherwise have identical specificity. */
body.hero-dark { background: var(--hero-dark-ground); }
body.hero-dark .hero-headline { color: var(--bg-colour); }
body.hero-dark:not(.menu-open) .hamburger span { background: var(--bg-colour); }

/* A hero sketch that is a picture of a screen draws the headline, the logo
   and the hamburger into its picture (site.js, RDB.heroChrome) and asks for
   the real ones to be hidden. They are still there: the headline is still a
   heading, and the hamburger still takes the click, under its drawn self.

   The headline stays hidden while the menu is open, as the overlay is over
   it anyway. The logo and the hamburger sit above the overlay and are the
   menu's own controls, so they come back the moment it opens, and on the way
   out they wait until the wipe has cleared them before giving way to the
   drawn ones (the delays; the other transitions are their rules', repeated). */
body.hero-owns-chrome .hero-headline { opacity: 0; }

body.hero-owns-chrome:not(.menu-open) .logo-box {
  opacity: 0;
  transition: transform 0.8s var(--ease-bounce),
              background-color 0.4s var(--ease-smooth),
              opacity 0.3s ease 0.5s;
}

body.hero-owns-chrome:not(.menu-open) .hamburger span {
  opacity: 0;
  transition: all 0.3s var(--ease-smooth), opacity 0.25s ease 0.4s;
}

/* ------------------------------------------------- under Safari's bars */

/* On an iPhone, Safari draws its status bar and its toolbar over the page as
   glass, and shows through them the document and nothing that is
   position: fixed. Worse, the first time a fixed element with a ground of
   its own covers the window, Safari paints the two bars a flat colour of its
   choosing and keeps them that way for as long as the page is open, whatever
   the page does next. So there (site.js, "hero bleed", which sets this class
   and these lengths) neither the hero nor the dark surface is fixed.

   The hero is laid in the document, as tall as the screen, and the document
   is scrolled so that its top is the screen's. The overlay is laid in the
   document too, over exactly the window, so that everything in it sits where
   it did; its ground is carried out past its box and under the bars by a
   shadow with no blur, and the wipe, which clips the shadow as it clips the
   rest, is given a radius that reaches the corners of the screen. */
html.hero-bleed .hero-bg {
  position: absolute;
  inset: 0 auto auto 0;
  width: 100%;
  height: var(--bleed-height);
}

html.hero-bleed .overlay {
  position: absolute;
  inset: var(--bleed-top) auto auto 0;
  width: 100%;
  height: var(--bleed-window);
  box-shadow: 0 0 0 300px var(--overlay-bg);
}

html.hero-bleed body.menu-open .overlay {
  clip-path: circle(var(--wipe-r, 190%) at var(--wipe-x, 92%) var(--wipe-y, 6%));
  -webkit-clip-path: circle(var(--wipe-r, 190%) at var(--wipe-x, 92%) var(--wipe-y, 6%));
}

/* Nothing of the body shows here, but Safari reads its colour to decide
   whether the clock goes in dark or light and which way to shade behind it.
   Left cream under the open menu, Safari 26 laid a pale haze over the top of
   the dark surface. */
html.hero-bleed body.menu-open { background: var(--overlay-bg); }

/* The lab's and the apps pane's headers stay put while their grids scroll,
   which everywhere else is position: sticky. Here it can't be. A sticky
   element with a ground of its own at the top of the window is one more
   thing Safari takes its bars' colour from, if it is showing as the page
   loads: arriving on either pane by link (index.html#apps) left the top bar
   plain once the menu was closed. So each scroller goes back in the flow,
   which leaves its shell as the header's containing block; the header is
   placed against the shell, where the scroller's contents pass under it, and
   is given a height that the scroller can leave clear for it. */
html.hero-bleed .lab-scroller,
html.hero-bleed .apps-scroller {
  --chrome-height: calc(24px + var(--logo-size) * 0.6 + 12px + 32px + 16px);
  position: static;
  height: 100%;
  padding-top: var(--chrome-height);
}

html.hero-bleed .lab-chrome,
html.hero-bleed .apps-chrome {
  position: absolute;
  top: 0;
  left: var(--pane-inset-x);
  right: var(--pane-inset-x);
  height: var(--chrome-height);
}

/* ------------------------------------------------------------ logo box */

/* Sits above the overlay (z-index) — must never hide behind the wipe. */
.logo-box {
  position: fixed;
  top: 24px;
  left: 24px;
  z-index: 30;
  width: var(--logo-size);
  height: var(--logo-size);
  background: var(--not-black);
  display: flex;
  align-items: center;
  justify-content: center;
  transform: scale(1);
  transform-origin: top left;
  transition: transform 0.8s var(--ease-bounce),
              background-color 0.4s var(--ease-smooth);
}

.logo-box svg {
  width: 60%;
  height: auto;
  fill: var(--bg-colour);
  transition: fill 0.4s var(--ease-smooth);
}

body.menu-open .logo-box {
  background: var(--bg-colour);
  transform: scale(0.6);
}

body.menu-open .logo-box svg { fill: var(--not-black); }

/* Fullscreen lab detail: give the logo more presence. */
body.menu-open.lab-detail-open .logo-box {
  transform: scale(0.85);
}

/* ----------------------------------------------------------- hamburger */

.hamburger {
  position: fixed;
  top: 24px;
  right: 24px;
  z-index: 30;
  width: 34px;
  height: 34px;
}

.hamburger span {
  position: absolute;
  left: 50%;
  width: 20px;
  height: 2px;
  background: var(--ink);
  transition: all 0.3s var(--ease-smooth);
}

.hamburger span:nth-child(1) { top: 30%; transform: translateX(-50%); }
.hamburger span:nth-child(2) { top: 50%; transform: translateX(-50%) translateY(-50%); }
.hamburger span:nth-child(3) { bottom: 30%; transform: translateX(-50%); }

body.menu-open .hamburger span { background: var(--menu-text); }
body.menu-open .hamburger span:nth-child(1) {
  top: 50%;
  bottom: auto;
  transform: translateX(-50%) translateY(-50%) rotate(45deg);
}
body.menu-open .hamburger span:nth-child(2) {
  opacity: 0;
  transform: translateX(-50%) translateY(-50%) scaleX(0);
}
body.menu-open .hamburger span:nth-child(3) {
  top: 50%;
  bottom: auto;
  transform: translateX(-50%) translateY(-50%) rotate(-45deg);
}

/* -------------------------------------------------------- menu overlay */

.overlay {
  position: fixed;
  inset: 0;
  z-index: 20;
  background: var(--overlay-bg);
  color: var(--menu-text);
  clip-path: circle(0% at var(--wipe-x, 92%) var(--wipe-y, 6%));
  -webkit-clip-path: circle(0% at var(--wipe-x, 92%) var(--wipe-y, 6%));
  transition: clip-path 0.6s var(--ease-bounce), -webkit-clip-path 0.6s var(--ease-bounce);
  pointer-events: none;
}

body.menu-open .overlay {
  clip-path: circle(150% at var(--wipe-x, 92%) var(--wipe-y, 6%));
  -webkit-clip-path: circle(150% at var(--wipe-x, 92%) var(--wipe-y, 6%));
  pointer-events: auto;
}

/* Panes morph in place on the shared dark surface: outgoing slides up and
   out, incoming rises from below with a 0.15s stagger. */
.pane {
  position: absolute;
  left: var(--pane-inset-x);
  right: var(--pane-inset-x);
  top: var(--pane-inset-y);
  bottom: var(--pane-inset-y);
  display: flex;
  flex-direction: column;
  justify-content: center;
  opacity: 0;
  transform: translateY(30px);
  transition: opacity 0.3s ease, transform 0.3s var(--ease-smooth);
  pointer-events: none;
}

.pane.is-active {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.5s ease 0.15s, transform 0.5s var(--ease-smooth) 0.15s;
  pointer-events: auto;
}

.pane.is-exiting {
  opacity: 0;
  transform: translateY(-30px);
}

.no-anim, .no-anim * { transition: none !important; }

/* ------------------------------------------------ to and from app pages */

/* An app's pages are documents of their own (apps/app.css), so a card in the
   apps pane leaves this surface and an app page's links return to it. Both
   are page loads, made to move as panes do; app.css says how, and why it is
   done with script.

   Leaving (site.js, leaveFor): the pane slides out as any outgoing pane
   does, and what sits over the surface goes with it, so the app's page
   arrives on bare dark. */
body.is-leaving .logo-box,
body.is-leaving .hamburger,
body.is-leaving .back-chevron {
  opacity: 0;
  transition: opacity 0.3s ease;
}

/* Arriving (site.js, arrive). The page that was left is dark, so the surface
   is up from the first frame: index.html's head sets this class before
   anything is painted, and site.js opens the menu for real, in one step, and
   takes the class off. From there either the pane that was asked for rises
   (index.html#apps), with no wipe between two dark pages, or the surface is
   wiped away to show the hero. The logo and hamburger wait for site.js, so
   they are never seen in their hero state on the dark. */
html.from-app body { background: var(--overlay-bg); }

html.from-app .overlay {
  /* Not fixed, even for these first frames: Safari on an iPhone would take
     its bars' colour from it and keep it ("under Safari's bars", above).
     Over a page that can't scroll it comes to the same place. */
  position: absolute;
  clip-path: none;
  -webkit-clip-path: none;
  transition: none;
}

html.from-app .logo-box,
html.from-app .hamburger { visibility: hidden; }

/* ------------------------------------------------------------ menu list */

.menu-item {
  display: block;
  width: fit-content;
  text-align: left;
  text-decoration: none;
  font-weight: bold;
  font-size: clamp(46px, 9.5vh, 88px);
  line-height: 0.95;
  letter-spacing: -0.02em;
  color: var(--menu-text);
  margin: 6px 0;
  transition: color 0.8s ease, -webkit-text-stroke 0.8s ease;
  -webkit-text-stroke: 0 var(--menu-text);
}

.menu-item:hover {
  color: transparent;
  -webkit-text-stroke: 1px var(--menu-text);
}

.menu-item.is-inert {
  opacity: 0.35;
  pointer-events: none;
}

/* --------------------------------------------------------- back chevron */

/* Stroke weight matches the hamburger's 2px bars; the padding takes the hit
   area past the 44px minimum without inflating the mark itself. */
.back-chevron {
  position: absolute;
  bottom: 20px;
  left: 24px;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--menu-text);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
  padding: 12px 16px;
  mix-blend-mode: difference;
}

.back-chevron svg {
  width: 22px;
  height: 22px;
  display: block;
}

.back-chevron.is-visible {
  opacity: 1;
  pointer-events: auto;
}

/* In lab detail the chevron collides with the sketch title/description
   at bottom-left; the explicit "all experiments" control replaces it. */
body.lab-detail-open .back-chevron.is-visible {
  opacity: 0;
  pointer-events: none;
}

/* ----------------------------------------------------------------- reel */

.reel-gate { max-width: 420px; }

.reel-error-label {
  font-size: 11px;
  letter-spacing: 0.1em;
  color: var(--error);
  margin-bottom: 14px;
  display: none;
}

.reel-headline {
  font-weight: 900;
  font-size: clamp(26px, 4vw, 34px);
  line-height: 1.05;
  letter-spacing: -0.01em;
  color: #f8f8f4;
  margin-bottom: 24px;
}

.reel-input-row {
  display: flex;
  align-items: center;
  gap: 14px;
  border-bottom: 1px solid rgba(242, 242, 238, 0.3);
  padding-bottom: 12px;
  transition: border-color 0.25s ease;
}

.reel-input-row input {
  flex: 1;
  background: transparent;
  border: none;
  outline: none;
  color: #f2f2ee;
  font-family: var(--font);
  font-size: 16px;
  letter-spacing: 0.05em;
}

.reel-input-row input::placeholder { color: rgba(233, 233, 222, 0.35); }

.reel-submit {
  font-size: 20px;
  opacity: 0.6;
  color: #f2f2ee;
  transition: opacity 0.2s ease;
}

.reel-submit:hover { opacity: 1; }

.pane-reel[data-state="error"] .reel-error-label { display: block; }
.pane-reel[data-state="error"] .reel-input-row { border-bottom-color: var(--error); }
.pane-reel[data-state="error"] .reel-input-row input { color: var(--error); }

.reel-gate.shake { animation: gate-shake 0.4s var(--ease-smooth); }

@keyframes gate-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-10px); }
  40% { transform: translateX(8px); }
  60% { transform: translateX(-6px); }
  80% { transform: translateX(4px); }
}

.reel-player-wrap {
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}

.pane-reel[data-state="unlocked"] .reel-gate { display: none; }
.pane-reel[data-state="unlocked"] .reel-player-wrap { display: flex; }

.reel-player {
  position: relative;
  width: min(100%, calc((100vh - 220px) * 16 / 9));
  aspect-ratio: 16 / 9;
  background: var(--ink);
  border: 1px solid rgba(242, 242, 238, 0.15);
}

.reel-player video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: var(--ink);
}

.reel-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: rgba(242, 242, 238, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.3s ease, background 0.2s ease;
  z-index: 2;
}

.reel-play:hover { background: rgba(242, 242, 238, 0.2); }

.reel-play::after {
  content: '';
  width: 0;
  height: 0;
  border-top: 11px solid transparent;
  border-bottom: 11px solid transparent;
  border-left: 18px solid #f2f2ee;
  margin-left: 4px;
}

.reel-player.is-playing .reel-play { opacity: 0; pointer-events: none; }

.reel-progress {
  position: absolute;
  bottom: 14px;
  left: 14px;
  right: 14px;
  height: 3px;
  background: rgba(242, 242, 238, 0.15);
  z-index: 2;
}

.reel-progress-fill {
  width: 0;
  height: 100%;
  background: #f2f2ee;
}

.reel-session-note {
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--menu-text);
  opacity: 0.5;
  align-self: flex-end;
}

/* ------------------------------------------------------------------ lab */

/* The lab grid scrolls inside a full-overlay shell so the shared-element
   tile expansion can fill the whole frame without being clipped. */
.lab-shell {
  position: absolute;
  inset: 0;
  display: block;
  justify-content: flex-start;
}

.lab-scroller {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 0 var(--pane-inset-x) var(--pane-inset-y);
  scrollbar-width: none;
  touch-action: pan-y;
}

.lab-scroller::-webkit-scrollbar { display: none; }

@media (hover: hover) and (pointer: fine) {
  .lab-scroller { cursor: none; }
}

.lab-chrome {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--overlay-bg);
  /* Clears the (scaled-down) logo box pinned at 24px/24px. */
  padding: calc(24px + var(--logo-size) * 0.6 + 12px) 0 16px;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}

.lab-title {
  font-weight: 900;
  font-size: 26px;
  letter-spacing: -0.01em;
  color: #efece4;
}

.lab-count {
  font-size: 11px;
  letter-spacing: 0.1em;
  opacity: 0.45;
  color: #efece4;
  text-transform: uppercase;
}

.lab-grid {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px 22px;
  padding-top: 6px;
  transition: opacity 0.35s ease;
}

.lab-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 8px;
  transform-origin: center center;
}

.lab-tile-mount {
  width: 100%;
  aspect-ratio: 4 / 3;
  background: #0a0a0a;
  position: relative;
  overflow: hidden;
}

.lab-tile-mount canvas {
  width: 100% !important;
  height: 100% !important;
  display: block;
}

.lab-tile-num {
  font-size: 9px;
  letter-spacing: 0.1em;
  opacity: 0.4;
  color: #efece4;
}

.lab-tile-title {
  font-weight: 700;
  font-size: 14px;
  letter-spacing: -0.005em;
  color: #f4f2eb;
}

.lab-tile.tile-zooming {
  z-index: 30;
  transition: transform 0.56s cubic-bezier(0.65, 0, 0.35, 1);
}

.lab-tile.tile-zooming .lab-tile-num,
.lab-tile.tile-zooming .lab-tile-title { opacity: 0; transition: opacity 0.2s ease; }

.lab-tile.tile-scatter {
  transition: opacity 0.35s ease var(--scatter-delay, 0ms),
              transform 0.4s var(--ease-smooth) var(--scatter-delay, 0ms);
}

.lab-shell.grid-hidden .lab-scroller { opacity: 0; pointer-events: none; }

/* Lab detail: 3D cube carousel filling the whole overlay. */
.lab-detail {
  position: absolute;
  inset: 0;
  z-index: 25;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.lab-detail.is-active {
  opacity: 1;
  pointer-events: auto;
}

.cube-scene {
  position: absolute;
  inset: 0;
  perspective: 1400px;
  overflow: hidden;
}

.cube {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transition: transform 0.55s var(--ease-cube);
}

.cube-face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  background: var(--overlay-bg);
  overflow: hidden;
}

.cube-face canvas { display: block; }

.lab-detail-nav {
  position: absolute;
  top: 0;
  width: 50%;
  height: 100%;
  z-index: 3;
}

.lab-detail-nav.prev { left: 0; }
.lab-detail-nav.next { right: 0; }

/* Route back to the lab grid — the handoff's "all experiments" control. */
.lab-detail-back {
  position: absolute;
  top: calc(24px + var(--logo-size) * 0.85 + 22px);
  left: 26px;
  z-index: 5;
  font-size: 14px;
  letter-spacing: 0.04em;
  color: #f2f2ee;
  /* Inverts over light sketch faces, stays cream over dark. */
  mix-blend-mode: difference;
  opacity: 0.8;
  transition: opacity 0.25s ease, transform 0.25s ease;
}

.lab-detail-back:hover {
  opacity: 1;
  transform: translateX(-4px);
}

.lab-detail-text {
  position: absolute;
  left: 40px;
  bottom: 30px;
  z-index: 5;
  max-width: min(560px, calc(100% - 80px));
  color: #f2f2ee;
  pointer-events: none;
  /* Inverts over light sketch faces (e.g. foliage), stays cream over dark. */
  mix-blend-mode: difference;
}

.lab-detail-title {
  font-weight: bold;
  font-size: 22px;
}

/* Description comes from the sketch's meta.json sidecar. */
.lab-detail-desc {
  margin-top: 6px;
  font-size: 14px;
  line-height: 1.45;
  opacity: 0.78;
}

.lab-detail-desc:empty {
  display: none;
}

/* ----------------------------------------------------------------- apps */

/* Same full-overlay scrolling shell as the lab, minus the shared-element
   expansion: an app card leaves the surface for its own page (the store
   needs real URLs) rather than morphing in place. How that page load is
   made to move is under "to and from app pages", above. */
.apps-shell {
  position: absolute;
  inset: 0;
  display: block;
  justify-content: flex-start;
}

.apps-scroller {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 0 var(--pane-inset-x) var(--pane-inset-y);
  scrollbar-width: none;
  touch-action: pan-y;
}

.apps-scroller::-webkit-scrollbar { display: none; }

@media (hover: hover) and (pointer: fine) {
  .apps-scroller { cursor: none; }
}

.apps-chrome {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--overlay-bg);
  /* Clears the (scaled-down) logo box pinned at 24px/24px. */
  padding: calc(24px + var(--logo-size) * 0.6 + 12px) 0 16px;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}

/* Scaled to sit a step below the radial menu item that opens this pane
   (clamp(46px, 9.5vh, 88px)) rather than a step above body copy — at 26px it
   read as a caption on a mostly empty surface. */
.apps-title {
  font-weight: 900;
  font-size: clamp(38px, 5.5vh, 60px);
  line-height: 0.95;
  letter-spacing: -0.02em;
  color: #efece4;
}

.apps-count {
  font-size: 11px;
  letter-spacing: 0.1em;
  opacity: 0.45;
  color: #efece4;
  text-transform: uppercase;
}

/* One block per platform. Sections are built by JS and only appear when they
   hold at least one app, so a platform you haven't shipped for costs nothing. */
.apps-section { padding-top: 6px; }

.apps-section + .apps-section { padding-top: 38px; }

.apps-section-title {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #efece4;
  opacity: 0.55;
  padding-bottom: 14px;
  border-bottom: 1px solid #2e2d29;
  margin-bottom: 18px;
}

/* One card per row: a section rarely holds many apps, and a full-width row
   keeps the platform rules reading as the divisions of the page. */
.apps-grid {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
}

/* The card is a box with links in it: the name's link covers the whole card
   (.app-name::after), and the guide link sits above that cover. */
.app-card {
  position: relative;
  display: flex;
  gap: 18px;
  align-items: flex-start;
  padding: 18px;
  text-decoration: none;
  border: 1px solid #2e2d29;
  border-radius: 3px;
  transition: border-color 0.35s ease, background 0.35s ease,
              transform 0.35s var(--ease-smooth);
}

.app-card:hover {
  border-color: #55534c;
  background: #201f1d;
  transform: translateY(-2px);
}

.app-card-icon {
  width: 64px;
  height: 64px;
  flex: none;
  border-radius: 14px;
  background: #0a0a0a;
  object-fit: cover;
}

/* min-width:0 lets a long tagline wrap instead of stretching the grid cell. */
.app-card-text { min-width: 0; }

.app-name {
  display: block;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.005em;
  color: #f4f2eb;
  text-decoration: none;
  margin-bottom: 4px;
}

.app-name::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 3px;
}

.app-name:focus-visible { outline: none; }
.app-name:focus-visible::after { outline: 2px solid #efece4; outline-offset: 2px; }

.app-tagline {
  font-size: 13px;
  line-height: 1.5;
  color: #a5a29a;
}

.app-links {
  display: flex;
  align-items: baseline;
  gap: 18px;
  margin-top: 10px;
}

.app-go {
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #a5a29a;
  opacity: 0;
  transition: opacity 0.35s ease;
}

/* Always shown, where "View" waits for a hover: it is the one link on the
   card that the card's own size doesn't make obvious. The padding makes it
   a thumb's height to tap without moving the text. */
.app-guide {
  position: relative;
  z-index: 1;
  padding: 10px 0;
  margin: -10px 0;
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #efece4;
  text-decoration: underline;
  text-decoration-color: #55534c;
  text-underline-offset: 3px;
  transition: text-decoration-color 0.35s ease;
}

.app-guide:hover { text-decoration-color: #efece4; }
.app-guide:focus-visible { outline: 2px solid #efece4; outline-offset: 3px; }

.app-card:hover .app-go { opacity: 1; }

/* Shown only when discovery returns nothing — hidden by JS as soon as at
   least one app lands. */
.apps-empty {
  display: none;
  color: #a5a29a;
  font-size: 14px;
  padding: 4px 0 40px;
}

.apps-empty.is-visible { display: block; }

/* ---------------------------------------------------------------- email */

.email-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 30px;
  align-items: center;
  width: 100%;
}

.email-headline {
  font-weight: bold;
  font-size: clamp(34px, 4.6vw, 52px);
  line-height: 1.02;
  letter-spacing: -0.015em;
  color: #f8f8f4;
}

.email-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.em-label {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.45;
  margin-bottom: 6px;
  display: block;
  color: #f2f2ee;
}

.em-input {
  background: transparent;
  border: none;
  border-bottom: 1px solid rgba(242, 242, 238, 0.25);
  color: #f2f2ee;
  font-family: var(--font);
  font-size: 16px;
  padding: 8px 0;
  width: 100%;
  outline: none;
  resize: none;
  transition: border-color 0.25s ease;
}

.em-input:focus { border-bottom-color: var(--menu-text); }

textarea.em-input {
  padding-bottom: 26px;
  overflow: hidden;
  line-height: 1.4;
}

.email-submit {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 4px;
  align-self: flex-start;
  transition: opacity 0.2s ease;
}

.email-submit:hover { opacity: 0.7; }

.email-submit[disabled] { opacity: 0.4; pointer-events: none; }

.email-submit .label {
  font-weight: bold;
  font-size: 15px;
  color: #f2f2ee;
}

.email-submit .arrow {
  font-size: 18px;
  color: #f2f2ee;
}

.email-status {
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--menu-text);
  opacity: 0;
  transition: opacity 0.3s ease;
  min-height: 14px;
}

.email-status.is-visible { opacity: 0.8; }
.email-status.is-error { color: var(--error); }

/* Staggered entrance — replayed every time the pane becomes active. */
.pane-email [data-reveal] {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.5s ease var(--d, 0s),
              transform 0.5s var(--ease-entrance) var(--d, 0s);
}

.pane-email [data-reveal="headline"] { transform: translateY(-20px); transition-duration: 0.6s, 0.6s; }

.pane-email.revealed [data-reveal] {
  opacity: 1;
  transform: translateY(0);
}

/* --------------------------------------------------------------- cursor */

.cursor {
  position: fixed;
  left: 0;
  top: 0;
  width: 40px;
  height: 40px;
  border: 3.5px solid var(--not-black);
  border-radius: 50%;
  pointer-events: none;
  z-index: 100;
  opacity: 0;
  transform: translate(-50%, -50%);
  transition: opacity 0.3s ease, width 0.2s ease, height 0.2s ease,
              border-color 0.3s ease, box-shadow 0.3s ease;
  mix-blend-mode: difference;
  will-change: left, top;
}

.cursor.is-visible { opacity: 0.6; }
.cursor.is-clicking { width: 30px; height: 30px; }

/* Menu surfaces are dark — the difference-blended ink stroke computes to
   near-black there, so invert to a cream stroke. Hairline ink edges keep
   it legible over the light cube faces and reel player inside the menu. */
body.menu-open .cursor {
  border-color: var(--menu-text);
  mix-blend-mode: normal;
  box-shadow: 0 0 0 1px rgba(20, 19, 17, 0.5),
              inset 0 0 0 1px rgba(20, 19, 17, 0.5);
}

body.menu-open .cursor.is-visible { opacity: 0.85; }

@media (hover: none), (pointer: coarse) {
  .cursor { display: none; }

  /* No hover to reveal it, so it would only ever be reserved dead space
     under the tagline. The whole card is tappable regardless. */
  .app-go { display: none; }
}

/* ------------------------------------------------------------ responsive */

@media (max-width: 860px) {
  :root {
    --pane-inset-x: 32px;
    --pane-inset-y: 56px;
    --frame-pad-y: 24px;
    --frame-pad-x: 24px;
    --logo-size: 56px;
  }

  .lab-grid { grid-template-columns: repeat(2, 1fr); }
  .menu-item { font-size: clamp(40px, 8.5vh, 72px); }
}

@media (max-width: 720px) {
  .email-split {
    grid-template-columns: 1fr;
    gap: 26px;
    align-items: start;
  }

  /* Keep the email pane usable with the on-screen keyboard, and start it
     below the logo box. */
  .pane-email {
    justify-content: flex-start;
    padding-top: 20px;
    overflow-y: auto;
  }
}

@media (max-width: 480px) {
  :root {
    --pane-inset-x: 24px;
    --pane-inset-y: 48px;
  }

  .lab-grid { grid-template-columns: 1fr; }
  .lab-detail-text { left: 24px; bottom: 24px; max-width: calc(100% - 48px); }
  .lab-detail-title { font-size: 18px; }
  .lab-detail-desc { font-size: 13px; }
  .hero-headline { font-size: clamp(24px, 7vw, 34px); }
  .menu-item { font-size: clamp(36px, 7vh, 56px); }
}

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