/* ============================================================================
   HYDRA — a warm twilight doorway for Agent T.
   Direction: a deep dusk sky with a warm gold horizon and a teal / iris / gold
   aurora that lights only when you arrive. A single frosted-glass key-card,
   perfectly centred, floating in the light.
   Signature July-2026 stack (distinct from the other six doorways):
     · CSS @property registered custom-props (animated <angle> hue-wheel)
     · View Transitions API morph (::view-transition-*)
     · dual WebGL2 shaders (aurora curtain + thin-film iridescence)
     · SVG feSpecularLighting gloss + Canvas2D gradient-mesh
   Strict-CSP: no inline styles; every dynamic value arrives via setProperty/class.
   ========================================================================== */

@font-face {
  font-family: "Fredoka";
  src: url("/wall/p7/fredoka-var.woff2") format("woff2");
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}

/* registered angle prop — the whole point of the tilt-back demo:
   a real animatable <angle> custom property (CSS @property, baseline 2024+). */
@property --hydra-hue {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

:root {
  /* aurora trine */
  --aqua: #40e5d0;
  --iris: #8b7bff;
  --gold: #ffc98a;
  --rose: #ff8bb5;

  /* twilight surface + ink */
  --sky-0: #070b18;
  --sky-1: #0b1022;
  --sky-2: #141a33;
  --ink:   #f3f1ff;   /* AAA on the glass */
  --ink-2: #c3bfe0;   /* >= 4.5:1 on the glass */
  --ink-3: #8f8ab5;
  --line:  rgba(180, 170, 230, 0.20);

  /* frosted-dark glass */
  --glass:      rgba(30, 32, 60, 0.44);
  --glass-edge: rgba(200, 205, 255, 0.30);
  --glass-blur: 26px;

  /* warm CTA — dark ink on the gold keeps it AA in every aurora state */
  --cta-ink: #1a1230;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --energy: 0;        /* driven by JS as you type: 0 → 1 */
  --px: 0;            /* pointer parallax, -1 → 1 */
  --py: 0;
  --tilt: 0;          /* 0 → 1 parallax activation */
}

* { box-sizing: border-box; }
html, body { height: 100%; }

body {
  margin: 0;
  min-height: 100dvh;
  font-family: "Fredoka", ui-rounded, "SF Pro Rounded", "Segoe UI", system-ui, sans-serif;
  color: var(--ink);
  background: var(--sky-1);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow: hidden;
}

.skip {
  position: fixed;
  top: 12px; left: 50%;
  translate: -50% -160%;
  z-index: 60;
  padding: 10px 18px;
  border-radius: 999px;
  background: #fff;
  color: #16112c;
  font-weight: 600;
  text-decoration: none;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
  transition: translate 0.25s var(--ease);
}
.skip:focus-visible { translate: -50% 0; }

/* ---- Base twilight sky (GPU-free floor; always visible, mobile-safe) -------- */
.sky {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background:
    radial-gradient(140% 100% at 50% 118%, rgba(255, 190, 130, 0.34) 0%, rgba(255,150,120,0) 44%),
    radial-gradient(120% 90% at 50% -12%, #1b2247 0%, rgba(27,34,71,0) 60%),
    linear-gradient(180deg, var(--sky-0) 0%, var(--sky-1) 46%, var(--sky-2) 100%);
}
.veil {
  position: absolute;
  width: 78vmax; height: 78vmax;
  border-radius: 50%;
  filter: blur(70px);
  opacity: 0.5;
  mix-blend-mode: screen;
  will-change: transform;
}
.v1 { background: radial-gradient(circle, var(--aqua) 0%, rgba(64,229,208,0) 62%); top: -30vmax; left: -18vmax; animation: drift1 26s var(--ease) infinite alternate; }
.v2 { background: radial-gradient(circle, var(--iris) 0%, rgba(139,123,255,0) 62%); top: -14vmax; right: -22vmax; animation: drift2 31s var(--ease) infinite alternate; }
.v3 { background: radial-gradient(circle, var(--rose) 0%, rgba(255,139,181,0) 62%); bottom: -24vmax; left: 8vmax; animation: drift3 35s var(--ease) infinite alternate; }
.horizon {
  position: absolute;
  left: -10%; right: -10%; bottom: -14vmax;
  height: 46vmax;
  background: radial-gradient(60% 100% at 50% 100%, rgba(255, 201, 138, 0.55) 0%, rgba(255,180,120,0) 70%);
  filter: blur(24px);
  opacity: 0.75;
}

@keyframes drift1 { from { transform: translate(0,0) scale(1); } to { transform: translate(18vmax, 12vmax) scale(1.2); } }
@keyframes drift2 { from { transform: translate(0,0) scale(1.05); } to { transform: translate(-16vmax, 16vmax) scale(0.88); } }
@keyframes drift3 { from { transform: translate(0,0) scale(1); } to { transform: translate(12vmax, -14vmax) scale(1.22); } }

/* ---- WebGL2 aurora-curtain (tilt-right) ---- */
.curtain {
  position: fixed;
  inset: 0;
  z-index: 1;
  width: 100%; height: 100%;
  display: block;
  opacity: 0;
  transition: opacity 1.1s ease;
}
.gpu-live .curtain { opacity: 1; }
.gpu-live .sky .veil { opacity: 0.34; }   /* the shader carries the light; keep a warm floor */

/* ---- Canvas2D gradient-mesh (shake) — hidden until it shimmers ---- */
.mesh {
  position: fixed;
  inset: 0;
  z-index: 2;
  width: 100%; height: 100%;
  display: block;
  opacity: 0;
  mix-blend-mode: screen;
  transition: opacity 0.5s ease;
  pointer-events: none;
}
.mesh.on { opacity: 0.6; }

/* ---- CSS frosted-glass slabs (tilt-left) ---- */
.frost {
  position: fixed;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.6s var(--ease);
}
.frost.on { opacity: 1; }
.slab {
  position: absolute;
  border-radius: 26px;
  border: 1px solid rgba(210, 214, 255, 0.22);
  -webkit-backdrop-filter: blur(16px) saturate(150%);
  backdrop-filter: blur(16px) saturate(150%);
  background: rgba(255, 255, 255, 0.05);
  box-shadow: 0 20px 60px -30px rgba(0,0,0,0.6);
}
.slab.s1 { width: 40vw; height: 26vh; top: 12%;  left: -22vw; transform: rotate(-9deg); }
.slab.s2 { width: 30vw; height: 40vh; top: 30%;  right: -20vw; transform: rotate(7deg); }
.slab.s3 { width: 46vw; height: 20vh; bottom: 8%; left: -26vw; transform: rotate(4deg); }
.frost.on .slab.s1 { animation: sweepR 3.2s var(--ease); }
.frost.on .slab.s2 { animation: sweepL 3.6s var(--ease); }
.frost.on .slab.s3 { animation: sweepR 3.9s var(--ease); }
@keyframes sweepR { from { transform: translateX(0) rotate(-9deg); } 50% { transform: translateX(150vw) rotate(-4deg); } from, to { } }
@keyframes sweepL { from { transform: translateX(0) rotate(7deg); } 50% { transform: translateX(-150vw) rotate(2deg); } }

/* film grain — keeps gradients banding-free */
.grain {
  position: fixed;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  opacity: 0.055;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---- Stage & composition — a clean 3-row grid, gate always centred ---- */
.stage {
  position: relative;
  z-index: 5;
  min-height: 100dvh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: clamp(16px, 3vh, 34px);
  padding: clamp(18px, 4vw, 44px);
  padding-top: max(clamp(18px, 4vw, 44px), env(safe-area-inset-top));
  padding-bottom: max(clamp(18px, 3vh, 30px), env(safe-area-inset-bottom));
  align-items: center;
  justify-items: center;
}

/* ---- Brand + conic hue-wheel (tilt-back) ---- */
.brand {
  justify-self: center;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 9px 18px 9px 12px;
  border-radius: 999px;
  background: var(--glass);
  border: 1px solid var(--glass-edge);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  backdrop-filter: blur(14px) saturate(140%);
  box-shadow: 0 10px 30px -12px rgba(0,0,0,0.6);
  position: relative;
}
.huewheel {
  position: absolute;
  left: 6px; top: 50%;
  width: 34px; height: 34px;
  translate: 0 -50%;
  border-radius: 50%;
  background: conic-gradient(from var(--hydra-hue),
     var(--aqua), var(--iris), var(--gold), var(--rose), var(--aqua));
  -webkit-mask: radial-gradient(closest-side, transparent 58%, #000 62%);
  mask: radial-gradient(closest-side, transparent 58%, #000 62%);
  opacity: 0.85;
  filter: blur(0.3px);
  animation: hue-idle 18s linear infinite;
}
.huewheel.spin { animation: hue-burst 1.5s var(--ease); }
@keyframes hue-idle  { to { --hydra-hue: 360deg; } }
@keyframes hue-burst { from { --hydra-hue: 0deg; } to { --hydra-hue: 1440deg; } }

.mark { position: relative; width: 34px; height: 24px; display: block; }
.mark svg { width: 100%; height: 100%; overflow: visible; filter: drop-shadow(0 2px 8px rgba(0,0,0,0.4)); }
.wordmark {
  font-weight: 600;
  font-size: 21px;
  letter-spacing: 0.18em;
  color: var(--ink);
}

/* ---- Parallax deck (tap-and-hold) ---- */
.deck {
  justify-self: center;
  align-self: center;
  width: min(93vw, 500px);
  position: relative;
  perspective: 1100px;
  transform-style: preserve-3d;
}
.echo {
  position: absolute;
  inset: 0;
  border-radius: 30px;
  border: 1px solid rgba(200, 205, 255, 0.14);
  background: rgba(255, 255, 255, 0.03);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  opacity: calc(0.35 + var(--tilt) * 0.4);
  transition: opacity 0.5s var(--ease);
  pointer-events: none;
}
.echo1 { transform: translate3d(calc(var(--px) * 22px), calc(var(--py) * 22px), -60px) scale(0.985); }
.echo2 { transform: translate3d(calc(var(--px) * 40px), calc(var(--py) * 40px), -120px) scale(0.97); }

/* ---- The glass key-card (the signature) ---- */
.card {
  position: relative;
  border-radius: 30px;
  background: var(--glass);
  border: 1px solid var(--glass-edge);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(160%);
  backdrop-filter: blur(var(--glass-blur)) saturate(160%);
  box-shadow:
    0 1px 0 rgba(255,255,255,0.35) inset,
    0 40px 100px -34px rgba(0, 0, 0, 0.66),
    0 14px 44px -26px rgba(0, 0, 0, 0.6);
  isolation: isolate;
  overflow: hidden;
  transform: rotateX(calc(var(--py) * -6deg * var(--tilt)))
             rotateY(calc(var(--px) * 6deg * var(--tilt)))
             translateZ(0);
  transition: transform 0.18s var(--ease);
  animation: cardIn 1s var(--ease) both;
  view-transition-name: hydra-card;
}
.card-body {
  position: relative;
  z-index: 3;
  padding: clamp(26px, 4vw, 44px);
}
/* iridescent rim — a hair of aurora caught on the glass edge */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 30px;
  padding: 1px;
  background: linear-gradient(135deg, var(--aqua), var(--iris) 48%, var(--gold) 86%);
  opacity: 0.55;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
  z-index: 4;
}
@keyframes cardIn {
  from { opacity: 0; transform: translateY(22px) scale(0.975); }
  to   { opacity: 1; }
}

/* iridescence canvas (click-hold) + specular sheen (tilt-forward), both behind text */
.iris {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%; height: 100%;
  opacity: 0;
  mix-blend-mode: screen;
  transition: opacity 0.6s ease;
  pointer-events: none;
}
.iris.on { opacity: 0.85; }
.sheen {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%; height: 100%;
  opacity: 0;
  mix-blend-mode: screen;
  transition: opacity 0.5s ease;
  pointer-events: none;
}
.sheen.on { opacity: 0.9; }

/* ---- Card content ---- */
.eyebrow {
  margin: 0 0 14px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.16em;
  color: var(--aqua);
}
.title {
  margin: 0 0 12px;
  font-size: clamp(25px, 5.4vw, 35px);
  line-height: 1.14;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.title .soft {
  background: linear-gradient(100deg, var(--aqua), var(--iris) 52%, var(--gold));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.lede {
  margin: 0 0 26px;
  font-size: 15.5px;
  line-height: 1.55;
  font-weight: 400;
  color: var(--ink-2);
  max-width: 44ch;
}

/* ---- Form: a single centred pill, input + button perfectly aligned ---- */
.key { margin: 0; }
.key-label {
  display: block;
  margin-bottom: 9px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
}
.field {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 7px 7px 18px;
  border-radius: 18px;
  background: rgba(12, 14, 30, 0.5);
  border: 1.5px solid var(--line);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25) inset;
  transition: border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.field-glow {
  position: absolute;
  inset: -2px;
  border-radius: 20px;
  pointer-events: none;
  opacity: calc(0.12 + var(--energy) * 0.8);
  background: linear-gradient(100deg, var(--aqua), var(--iris) 50%, var(--gold));
  filter: blur(12px);
  z-index: -1;
  transition: opacity 0.4s var(--ease);
}
.field:focus-within {
  border-color: transparent;
  box-shadow: 0 0 0 2px rgba(139, 123, 255, 0.6), 0 2px 10px rgba(0,0,0,0.25) inset;
}
.key-input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: transparent;
  outline: none;
  font: inherit;
  font-size: 17px;
  font-weight: 500;
  letter-spacing: 0.14em;
  color: var(--ink);
  padding: 12px 0;
}
.key-input::placeholder { color: #7a749c; letter-spacing: 0.2em; }

.submit {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 48px;
  padding: 0 22px;
  border: 0;
  border-radius: 13px;
  cursor: pointer;
  font: inherit;
  font-size: 16px;
  font-weight: 600;
  color: var(--cta-ink);
  background: linear-gradient(135deg, var(--gold), var(--rose) 92%);
  box-shadow: 0 10px 26px -8px rgba(255, 160, 140, 0.6);
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease), filter 0.2s var(--ease);
}
.submit:hover { transform: translateY(-1px); box-shadow: 0 14px 30px -8px rgba(255, 160, 140, 0.75); filter: saturate(1.08) brightness(1.03); }
.submit:active { transform: translateY(0) scale(0.985); }
.submit:disabled { opacity: 0.5; cursor: default; transform: none; box-shadow: none; }
.arw { width: 20px; height: 20px; transition: transform 0.25s var(--ease); }
.submit:hover .arw { transform: translateX(3px); }
.submit-text { line-height: 1; }

.verdict {
  margin: 14px 2px 0;
  min-height: 1.2em;
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--ink-2);
}
.verdict.is-deny { color: #ff9db8; }
.verdict.is-ok   { color: #6fe6c2; }

/* tenets — the View-Transitions alt state (double-tap) */
.tenets {
  display: grid;
  gap: 10px;
  margin: 20px 0 0;
}
.tenets[hidden] { display: none; }
.tenet {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--ink-2);
}
.dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; box-shadow: 0 0 12px currentColor; }
.d1 { background: var(--aqua); color: var(--aqua); }
.d2 { background: var(--iris); color: var(--iris); }
.d3 { background: var(--gold); color: var(--gold); }

.rest {
  margin: 22px 0 0;
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.02em;
  color: var(--ink-3);
}

/* ---- Dock row (sensor grant + gesture cue) ---- */
.dockrow {
  justify-self: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  text-align: center;
  max-width: min(92vw, 520px);
}
.sensor {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid var(--glass-edge);
  background: var(--glass);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: transform 0.2s var(--ease), border-color 0.2s var(--ease);
}
.sensor[hidden] { display: none; }
.sensor:hover { transform: translateY(-1px); border-color: var(--aqua); }
.cue {
  margin: 0;
  font-size: 12px;
  font-weight: 400;
  line-height: 1.5;
  color: var(--ink-3);
  transition: color 0.3s ease;
}
.cue.flash { color: var(--aqua); }

/* ---- Focus ring (keyboard) ---- */
:focus-visible { outline: 3px solid rgba(139, 123, 255, 0.7); outline-offset: 3px; border-radius: 6px; }
.submit:focus-visible { outline-offset: 4px; }

/* ---- Denied: a gentle glass shudder ---- */
.deny .card { animation: shudder 0.5s var(--ease); }
@keyframes shudder {
  10%, 90% { transform: translateX(-2px); }
  20%, 80% { transform: translateX(4px); }
  30%, 50%, 70% { transform: translateX(-7px); }
  40%, 60% { transform: translateX(7px); }
}

/* ---- Crossing: the card lifts into the light ---- */
.crossing .card { animation: lift 1.9s var(--ease) forwards; }
.crossing .stage { pointer-events: none; }
@keyframes lift {
  0%   { opacity: 1; transform: none; filter: blur(0); }
  55%  { opacity: 1; transform: translateY(-6px) scale(1.015); }
  100% { opacity: 0; transform: translateY(-32px) scale(1.06); filter: blur(9px); }
}
.crossing .brand, .crossing .rest, .crossing .dockrow { transition: opacity 0.8s ease; opacity: 0; }

/* ---- View Transitions morph (double-tap) ---- */
::view-transition-old(hydra-card),
::view-transition-new(hydra-card) {
  animation-duration: 0.45s;
  animation-timing-function: var(--ease);
}

/* ---- Responsive: portrait, landscape, desktop ---- */
@media (max-width: 560px) {
  .stage { gap: clamp(12px, 2.2vh, 24px); }
  .title { font-size: clamp(23px, 7.4vw, 30px); }
  .lede { margin-bottom: 22px; }
}
/* very short viewports (mobile landscape) — keep everything on-screen */
@media (max-height: 520px) {
  .stage { grid-template-rows: auto 1fr; align-content: center; }
  .brand { padding-top: 7px; padding-bottom: 7px; }
  .lede { display: none; }
  .card-body { padding: clamp(18px, 3vw, 26px); }
  .title { margin-bottom: 10px; font-size: clamp(21px, 4.4vh, 27px); }
  .dockrow { display: none; }
  .rest { margin-top: 16px; }
}
@media (max-height: 400px) {
  .brand { display: none; }
}

/* ---- Reduced motion: freeze all ambient movement to a calm still ---- */
@media (prefers-reduced-motion: reduce) {
  .veil, .huewheel, .slab { animation: none !important; }
  .card { animation: none; }
  .curtain, .mesh, .frost, .iris, .sheen { transition: none; }
  .submit, .arw, .skip, .field, .field-glow, .echo { transition: none; }
  .deny .card, .crossing .card { animation: none; }
  .crossing .card { opacity: 0; transform: translateY(-20px); transition: opacity 0.3s, transform 0.3s; }
  ::view-transition-old(hydra-card), ::view-transition-new(hydra-card) { animation: none; }
}

/* exit veil: the LAST painted frame before leaving must match the app's dark canvas (#0b0d12) so the
   browser never shows a bright frame between documents — photosensitivity mandate, applies to every exit */
.exit-veil{ position:fixed; inset:0; z-index:2147483000; background:#0b0d12; opacity:0; pointer-events:none; transition:opacity .3s ease; }
.exit-veil.is-on{ opacity:1; }
@media (prefers-reduced-motion: reduce){ .exit-veil{ transition:none; } }


/* =========================================================================================================
   BIND PORT - THE CHIP'S LANE, AND THE KEYBOARD'S OWN VIEWPORT STATE
   PORT-NOTES STEP 7 - R319/§312 SESSION-BIND, piece portals-p4p5p6p7. ASL v2 Laws 1, 3, 4, 5 and 11;
   brief items 6, 26, 27, 28 and 33.

   Everything above this line is the host's: the scene, the type, the copy, the colours, the key form's
   markup. This block is the one thing bind.com puts on the door that the host never had -
   wall/shared/motion.css, which fixes the shared sensor chip to the block-end corner of the VIEWPORT at
   calc(14px + env(safe-area-inset-bottom)). A fixed element does not scroll, so a document that scrolls
   underneath it can never end above it, and the profile ASL Law 11 names - Keyboard-open, 390 x 430 - is
   exactly where a door's key row lands in the corner the chip is fixed in.

   THE LANE is PORT-NOTES STEP 7's own string, and it is a reservation, not a restyle: the chip is never
   moved, shrunk, hidden or dropped to make the room. 52px is the chip's tallest measured box (44px at 390
   and above, 52px at 320 and 344 where its armed line wraps to two); 14px is the inset the chip already
   sits at, and 14px more is the gutter between the two; the safe-area inset is added again because the
   chip's own position carries it. tests/portal-gate.mjs re-measures the real chip at both widths on every
   run, so a chip that ever grows reddens the arm instead of quietly eating a row.

   THE SHELL IS THE SCROLL REGION (ASL Law 4). The document is clipped and <body> scrolls, so the scrolling
   box's block-end edge IS the lane's block-start edge by construction - no scroll offset exists that can
   park the key row under the chip. The scene layers stay fixed to the whole viewport and are unchanged:
   only the door's own content column ends higher.
   ========================================================================================================= */
:root { --b-lane: calc(52px + 28px + env(safe-area-inset-bottom, 0px)); }

html { overflow: hidden; }
body {
  /* the host's own `min-height: 100dvh` is the viewport, and a min-height outranks a height: it has to be
     released here or the shell keeps the whole screen and the lane is a promise the layout never keeps. */
  min-block-size: 0;
  block-size: calc(100dvh - var(--b-lane));
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--glass-edge) transparent;
}


/* SAFE CENTRING (ASL Law 8: reading order survives reflow). The shell can scroll now, and a centred column
   that outgrows its scrollport puts its own START out of reach - no scroll offset can go above zero.
   MEASURED on p4, the widest-typed of the four, before this rule went in: at 1440x900 the shell is 820 px,
   the content 1069, and the brand row sat at y -80. Every door whose content can outgrow its shell has the
   same shape available to it, so all four carry the keyword; it changes nothing at any size where the door
   fits. */
.stage { min-block-size: 100%; align-items: safe center; align-content: safe center; }

/* ASL Law 5 and estate L6, measured at 390 x 844 pointer:coarse: the sensor pill is 35 CSS px tall and
   the key field 44.4 - the pill is under the floor and the field is inside a rounding of it. */
@media (pointer: coarse) {
  .sensor { min-block-size: 44px; }
  .key-input { min-block-size: 44px; }
}

/* Enter sits beside the field at every width this door is rendered at. */
.key-input { scroll-margin-block: 16px 28px; }


/* =========================================================================================================
   BIND PORT - THE ASL v2 SECTION 5 MATRIX, ROW BY ROW   (R319/S312 SESSION-BIND, piece portals-p4p5p6p7)
   Brief items 26, 27, 28, 34, 35, 36. Nothing here is taste: every rule below was written against a named
   offender that tests/matrix.mjs printed on a real render of THIS door, and the run that named it is in
   evidence/portals-p4p5p6p7-r1/. The host never ran the matrix on these seven pages; bind.com does.
   ========================================================================================================= */

/* SAFE AREA (section 5 assertion 6). The harness's rule is geometric: no fixed element's CONTENT box may
   lie inside an inset band, and its own selection record names the escape - an element that pads with
   env(safe-area-inset-*) declares that its content clears the band. These layers are the scene: aria-hidden,
   pointer-events:none, painted, never read and never tapped. Padding is free for a box whose paint is a
   background or whose children are positioned against its padding box (that box does not move). It is NOT
   free for a <canvas>: the bitmap is scaled into the content box, so on a device that reports a notch the
   decorative field is rescaled by up to (47+34)/844 = 9.6 per cent in the block axis and by nothing at all
   on every device that reports no inset. That rescale was measured and accepted; the alternative was to
   leave the layers full-bleed and hand back thirty-five red rows on a rule the estate treats as a build
   failure. Nothing readable and nothing tappable is inside either band - the first flow text and every
   control are recorded per row in matrix-results.json. */
.sky, .curtain, .mesh, .frost, .grain {
  padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px)
           env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
}

/* THE SKIP LINK, AND THE KEYBOARD-OPEN PROFILE. The harness refuses a FIXED element parked entirely outside
   the viewport, because at 390x430 a fixed element the layout has forgotten is exactly what strands a
   control. A skip link parked off-screen until focus is the standard pattern and it is kept - as an
   ABSOLUTE element, which is what p5's own host already does, so it belongs to the document that scrolls
   rather than to the viewport the chip is fixed to. Its offsets, its colours and its copy do not change. */
.skip { position: absolute; }

@media (pointer: coarse) {
  .skip { display: inline-flex; align-items: center; min-block-size: 44px; }
  .sensor { min-inline-size: 44px; }
}

@media (forced-colors: active) {
  .skip, .key-input, .submit, .sensor { border: 1px solid ButtonBorder; }
  .skip { text-decoration: underline; }
}


/* ZOOM 200% / ASL Law 3 (zero horizontal overflow). MEASURED at 195x422, which is what mobileM becomes at
   200% zoom: .deck is width: min(93vw, 500px) = 181 px, and it lives inside a .stage whose own padding
   leaves 159. The deck ran 4 px past the body's client width and took the document with it. The vw term is
   the host's and stays - it is what keeps the card off the edges on a phone - but it is now bounded by the
   space the deck is actually given. That takes TWO declarations, not one: the stage's implicit column is
   auto-sized, so it grew to the deck's 181 px and a max-inline-size of 100% resolved against the column
   the deck had just widened. minmax(0, 1fr) is the column the container really has. Same clamp on the
   two other vw-sized rows, for the same reason. */
.stage { grid-template-columns: minmax(0, 1fr); }
.deck, .dockrow, .cue { max-inline-size: 100%; }

/* THE HINGE (section 5, foldable spanned: nothing critical inside it). Last in the file on purpose: the
   zoom clamp above also names .deck and .dockrow, and a later rule of equal specificity wins whatever
   media query it sits in - the first draft of this file put the hinge first and the clamp silently
   undid it. A viewport-segment query, which ASL Law 2 names as page-shell, not a width. */
@media (horizontal-viewport-segments: 2) {
  .deck { max-inline-size: 44%; margin-inline: 4% auto; }
  .brand, .dockrow { max-inline-size: 44%; margin-inline: 4% auto; }
  /* the skip link is centred on this door - left: 50% with a -50% translate - so it straddled the fold at
     x 486.5..627.6 against a hinge at 552..562. MEASURED, and it is the only control that did: the deck,
     the brand and the dock row had already moved. It joins them in the first segment; the focused state
     keeps its own offset. */
  .skip { left: 4%; translate: 0 -160%; }
  .skip:focus-visible { translate: 0 0; }
}
