/* ==========================================================================
   Hemisphere Lens — hemisphere-pathology.ca

   Palette inherited from the sibling property hemisphere-intelligence.ca so the
   two read as one product family. Wordmark, tagline and the "L" ring mark are
   preserved from docs/lens-promo-video-brief.md.

   Type is Inter only. No monospace, no micro-labels above sections, no chips,
   no accent dots. A section is a heading, a lead, and its content.
   ========================================================================== */

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 200;
  font-display: swap;
  src: url('assets/fonts/inter-latin-200-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('assets/fonts/inter-latin-400-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('assets/fonts/inter-latin-600-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('assets/fonts/inter-latin-700-normal.woff2') format('woff2');
}

:root {
  --bg: #1a0d14;
  --surface: #21121b;
  --text: #f1e7ec;
  --dim: #c3a8b4;

  --border: rgba(200, 110, 145, 0.24);
  --border-soft: rgba(200, 110, 145, 0.14);
  --tint: rgba(212, 130, 165, 0.08);

  --blue: #4285f4;
  --green: #34a853;
  --yellow: #fbbc05;

  --sans: 'Inter', -apple-system, 'system-ui', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  --gutter: clamp(1.25rem, 4vw, 2.5rem);
  --measure: 1180px;
  --nav-h: 64px;

  --radius: 14px;
  --pill: 999px;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 1rem);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img,
svg,
video {
  max-width: 100%;
  display: block;
}

img {
  height: auto;
}

h1,
h2,
h3 {
  margin: 0;
  text-wrap: balance;
}

p {
  margin: 0;
  text-wrap: pretty;
}

a {
  color: inherit;
}

/* ---------- WebGL backdrop ---------- */
#bg {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.2s var(--ease);
}

/* Deliberately recessive — it is a backdrop, never competition for the copy. */
#bg.is-ready {
  opacity: 1;
}

/* Everything else sits above the canvas. */
.nav,
main,
footer {
  position: relative;
  z-index: 1;
}

/* ---------- Accessibility ---------- */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  padding: 0.75rem 1.25rem;
  background: var(--text);
  color: var(--surface);
  border-radius: 0 0 var(--radius) 0;
  font-size: 0.875rem;
  font-weight: 600;
}
.skip-link:focus {
  left: 0;
}

:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------- Layout ---------- */
.wrap {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.center {
  text-align: center;
}

.s {
  padding-block: clamp(6rem, 15vh, 11rem);
  position: relative;
}

/* A soft well behind the copy so it stays legible over the moving field. */
.s::before {
  content: '';
  position: absolute;
  inset: -8% -5%;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    ellipse 66% 58% at 50% 50%,
    rgba(26, 13, 20, 0.86) 0%,
    rgba(26, 13, 20, 0.8) 42%,
    rgba(26, 13, 20, 0.35) 72%,
    transparent 88%
  );
}

/* The intro's type is large and bold, so let the brand mark read through. */
.intro::before {
  background: radial-gradient(
    ellipse 58% 50% at 50% 50%,
    rgba(26, 13, 20, 0.6) 0%,
    rgba(26, 13, 20, 0.46) 46%,
    rgba(26, 13, 20, 0.2) 74%,
    transparent 90%
  );
}

/* ==========================================================================
   Nav
   ========================================================================== */
/* Matched to the bar on hemisphere-intelligence.ca: full bleed, 24px of edge,
   transparent over a 12px blur, one hairline underneath. */
.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  background: transparent;
  border-bottom: 1px solid var(--border);
  box-shadow:
    rgba(14, 4, 10, 0.55) 0 2px 8px 0,
    rgba(14, 4, 10, 0.4) 0 4px 16px 0;
}

.nav-inner {
  width: 100%;
  padding-inline: clamp(1rem, 2.4vw, 1.5rem);
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.nav-brand {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  text-decoration: none;
  margin-right: auto;
  min-width: 0;
}

.nav-brand img {
  width: 32px;
  height: 32px;
  flex: none;
}

.nav-word {
  font-size: clamp(0.9375rem, 2.4vw, 1.5rem);
  font-weight: 200;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.3em;
  padding: 0.6875rem 1.375rem;
  border-radius: var(--pill);
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  border: 1px solid transparent;
  cursor: pointer;
  transition:
    background-color 0.25s var(--ease),
    border-color 0.25s var(--ease);
}

.btn-solid {
  background: var(--text);
  color: var(--surface);
}
.btn-solid:hover {
  background: #fff;
}

.btn-outline {
  background: rgba(26, 13, 20, 0.5);
  color: var(--text);
  border-color: var(--border);
}
.btn-outline:hover {
  background: var(--tint);
  border-color: rgba(200, 110, 145, 0.45);
}

.btn-lg {
  padding: 0.8125rem 1.75rem;
  font-size: 0.9375rem;
}

/* ==========================================================================
   1 · Intro
   ========================================================================== */
.intro {
  min-height: calc(100svh - var(--nav-h));
  display: flex;
  align-items: center;
  padding-block: clamp(4rem, 10vh, 7rem);
}

.wordmark {
  font-weight: 200;
  font-size: clamp(1rem, 2.4vw, 1.5rem);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-indent: 0.2em;
}

.tagline {
  font-weight: 200;
  font-size: clamp(0.8125rem, 1.6vw, 1rem);
  letter-spacing: 0.04em;
  color: var(--dim);
  text-transform: lowercase;
  margin-top: 0.75rem;
}

/* Two-column hero: copy left, the "L" mark and wordmark right. */
.intro-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}

.intro-copy {
  min-width: 0;
}

.intro .lead {
  margin-top: clamp(1.5rem, 3vw, 2rem);
}

.intro-mark {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.intro-mark img {
  width: clamp(170px, 28vw, 300px);
  animation: mark-in 1.4s var(--ease) both;
}

.intro-mark .wordmark {
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
}

@keyframes mark-in {
  from {
    opacity: 0;
    scale: 0.94;
    filter: blur(6px);
  }
  to {
    opacity: 1;
    scale: 1;
    filter: blur(0);
  }
}

.intro h1 {
  font-size: clamp(2.25rem, 7vw, 5rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.03;
}

.lines {
  list-style: none;
  padding: 0;
  margin: clamp(2rem, 4vw, 2.75rem) 0 0;
  max-width: 46ch;
  color: var(--dim);
  font-size: clamp(1rem, 1.7vw, 1.25rem);
  line-height: 1.85;
}

.kicker {
  margin-top: clamp(1.75rem, 3.5vw, 2.5rem);
  font-size: clamp(1.0625rem, 2vw, 1.375rem);
  font-weight: 600;
}

.cta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: clamp(2rem, 4vw, 2.75rem);
}

.center .cta {
  justify-content: center;
}

.note {
  margin-top: 1.5rem;
  font-size: 0.875rem;
  color: var(--dim);
}

.note a {
  color: var(--text);
  text-underline-offset: 4px;
}

/* ==========================================================================
   Section headings + beats
   ========================================================================== */
.s h2 {
  font-size: clamp(1.875rem, 5vw, 3.25rem);
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1.08;
  max-width: 20ch;
}

.center h2 {
  margin-inline: auto;
}

.lead {
  margin-top: clamp(1.25rem, 2.5vw, 1.75rem);
  max-width: 58ch;
  font-size: clamp(1rem, 1.6vw, 1.1875rem);
  color: var(--dim);
}

.center .lead {
  margin-inline: auto;
}

.lead em {
  font-style: normal;
  color: var(--text);
  font-weight: 600;
}

.beats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 1rem;
  margin-top: clamp(3rem, 6vw, 4.5rem);
}

.beat {
  background: rgba(33, 18, 27, 0.72);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 1.75rem 1.625rem;
}

.beat.wide {
  grid-column: 1 / -1;
}

.beat h3 {
  font-size: 1.125rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.35;
}

.beat p {
  color: var(--dim);
  font-size: 0.9375rem;
  margin-top: 0.875rem;
}

/* ==========================================================================
   The radial dial — the real viewer component
   ========================================================================== */
.dial-beat {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(360px, 1.15fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: center;
  padding: clamp(1.75rem, 3.5vw, 2.75rem);
}

.dial-copy h3 {
  font-size: clamp(1.25rem, 2.4vw, 1.625rem);
}

.dial-copy p {
  margin-top: 1rem;
}

.dial-hint {
  color: var(--text);
  font-size: 0.875rem;
  opacity: 0.75;
}

.dial-stage {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  /* The dial is dark glass in the app; give it a slide-ish ground so the
     furniture and ticks read the way they do over tissue. */
  background: #f4eff1;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: clamp(0.75rem, 2vw, 1.5rem);
  overflow: hidden;
  min-height: 340px;
}

/* the slide the dial sits on */
.smear {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 0;
}

/* keeps the bright field from fighting the page, and frames the dial */
.dial-stage::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(circle at 50% 48%, transparent 46%, rgba(20, 10, 16, 0.42) 100%);
}

.dial {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: 620px;
}

.dial-svg {
  width: 100%;
  height: auto;
  display: block;
  overflow: visible;
  touch-action: none;
}

.dial-puck {
  cursor: pointer;
  transition: transform 0.18s var(--ease);
  transform-box: fill-box;
  transform-origin: center;
}

.dial-puck:focus {
  outline: none;
}

.dial-puck:focus-visible circle {
  stroke: var(--blue);
  stroke-width: 2.5;
}

.dial-label {
  font-family: var(--sans);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.16em;
  fill: rgba(234, 242, 244, 0.72);
  pointer-events: none;
  user-select: none;
}

.dial-puck.is-hot .dial-label {
  fill: #eaf2f4;
}

.dial-hub-label {
  font-family: var(--sans);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 0.14em;
  fill: #eaf2f4;
  pointer-events: none;
  user-select: none;
}

.dial-hub-sub {
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.22em;
  fill: rgba(234, 242, 244, 0.5);
  pointer-events: none;
  user-select: none;
}

.dial-sublabel {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  fill: rgba(234, 242, 244, 0.86);
  pointer-events: none;
  user-select: none;
}

.dial-subitem.drops {
  animation: dropIn 0.26s cubic-bezier(0.18, 0.9, 0.24, 1.12) both;
  transform-box: fill-box;
  transform-origin: center;
}

@keyframes dropIn {
  from {
    opacity: 0;
    transform: scale(0.72);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

@media (max-width: 900px) {
  .dial-beat {
    grid-template-columns: 1fr;
  }
}

.dial-dots {
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: 0.2em;
  fill: rgba(234, 242, 244, 0.58);
  pointer-events: none;
  user-select: none;
}

/* ==========================================================================
   5 · Ownership — the struck fee list
   ========================================================================== */
.struck {
  list-style: none;
  padding: 0;
  margin: clamp(2.5rem, 5vw, 3.5rem) 0 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  align-items: flex-start;
}

.struck li {
  position: relative;
  font-size: clamp(1.125rem, 2.6vw, 1.75rem);
  color: var(--dim);
  opacity: 0.6;
  padding-inline: 0.25rem;
}

.struck li::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 52%;
  height: 2px;
  background: currentColor;
  border-radius: 2px;
  /* Default drawn, so the lines still read as struck out with JS disabled. */
  transform: scaleX(1);
  transform-origin: left center;
  transition: transform 0.7s var(--ease) var(--d, 0ms);
}

/* Once the reveal script has claimed the list, hold the strike back until the
   list scrolls into view, then draw it. */
.struck.reveal:not(.is-in) li::after {
  transform: scaleX(0);
}

.statement {
  margin-top: clamp(2rem, 4vw, 2.75rem);
  font-size: clamp(1.375rem, 3.6vw, 2.25rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
  max-width: 22ch;
}

/* ==========================================================================
   Close
   ========================================================================== */
.leaf {
  display: inline-block;
  vertical-align: -0.08em;
  width: 0.78em;
  height: 0.78em;
  margin-left: 0.18em;
  color: #d94a3d;
}
.close h2 {
  max-width: 18ch;
}

/* ==========================================================================
   Footer
   ========================================================================== */
footer {
  border-top: 1px solid var(--border-soft);
  padding-block: clamp(2.5rem, 5vw, 4rem);
  background: rgba(26, 13, 20, 0.86);
}

.footer-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 2rem clamp(2rem, 6vw, 5rem);
  justify-content: space-between;
  align-items: flex-start;
}

.wordmark.small {
  font-size: 0.875rem;
}

.tagline.small {
  font-size: 0.8125rem;
  margin-top: 0.5rem;
}

.family {
  margin-top: 1.5rem;
  font-size: 0.875rem;
  color: var(--dim);
}

.family a {
  color: var(--dim);
  text-underline-offset: 3px;
}

.family a:hover,
.family .is-current {
  color: var(--text);
}

.footer-meta {
  font-size: 0.8125rem;
  color: var(--dim);
  max-width: 52ch;
}

.footer-meta p + p {
  margin-top: 0.625rem;
}

.footer-meta a {
  color: var(--text);
}

/* ==========================================================================
   Motion
   ========================================================================== */
.reveal {
  opacity: 0;
  translate: 0 20px;
  transition:
    opacity 0.85s var(--ease) var(--d, 0ms),
    translate 0.85s var(--ease) var(--d, 0ms);
}

.reveal.is-in {
  opacity: 1;
  translate: 0 0;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-delay: 0ms !important;
    transition-duration: 0.001ms !important;
  }
  .reveal {
    opacity: 1;
    translate: none;
  }
  .struck li::after {
    transform: scaleX(1);
  }
}

/* ==========================================================================
   Responsive
   ========================================================================== */
@media (max-width: 900px) {
  .intro-grid {
    grid-template-columns: 1fr;
    text-align: center;
  }
  .intro-copy {
    order: 2;
  }
  .intro-mark {
    order: 1;
  }
  .intro .cta {
    justify-content: center;
  }
  .intro .lead,
  .lines {
    margin-inline: auto;
  }
}

@media (max-width: 620px) {
  .nav .btn span,
  .nav-word span,
  .nav-brand + .btn-outline {
    display: none;
  }
  .nav-inner {
    gap: 0.75rem;
  }
  .beats {
    grid-template-columns: 1fr;
  }
}

/* ==========================================================================
   Print
   ========================================================================== */
@media print {
  body {
    background: #fff;
    color: #000;
  }
  #bg,
  .nav {
    display: none !important;
  }
  .beat {
    background: none;
    border-color: #ccc;
  }
}

/* ==========================================================================
   Portal — three products, three spheres of tiles.

   Each product's mark idles as a sphere of tiles in the air above the names.
   Choosing a name brings its sphere forward, flattens it into a grid and
   resolves the mark inside it. The page is locked to one screen; nothing
   scrolls, and the field behind it is drawn by portal.js.
   ========================================================================== */
html:has(body.portal-page) {
  overflow: hidden;
}

body.portal-page {
  height: 100svh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

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

.stage {
  flex: 1;
  min-height: 0;
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  padding: 0 var(--gutter) clamp(0.5rem, 2vh, 1.25rem);
}

/* The air the marks live in. Measured, never drawn. */
.scene {
  flex: 1 1 auto;
  min-height: clamp(9rem, 30vh, 26rem);
}

.picker {
  flex: none;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(0.75rem, 2.4vh, 1.5rem);
}

/* Keeps the type crisp where the field passes behind it. Kept inside the
   layout box on purpose — bleeding sideways makes the page scrollable, and a
   scrolled page slides out from under the marks, which are placed by measuring
   it. */
.picker::before {
  content: '';
  position: absolute;
  inset: -22% 0 -40%;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    ellipse 76% 60% at 50% 46%,
    rgba(26, 13, 20, 0.86) 0%,
    rgba(26, 13, 20, 0.66) 44%,
    rgba(26, 13, 20, 0.24) 72%,
    transparent 86%
  );
}

/* ---------- the three names ---------- */
.apps {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: clamp(1.25rem, 4.4vw, 3.25rem);
  list-style: none;
  margin: 0;
  padding: 0;
}

.app {
  display: block;
  position: relative;
  padding-bottom: 0.3em;
  text-decoration: none;
  color: var(--text);
  font-size: clamp(1.0625rem, 4vw, 2.625rem);
  font-weight: 200;
  letter-spacing: 0.18em;
  /* the tracking hangs off the last letter; pull it back so the row centres */
  margin-right: -0.18em;
  text-transform: uppercase;
  line-height: 1.15;
  white-space: nowrap;
  opacity: 0.6;
  cursor: pointer;
  transition:
    opacity 0.45s var(--ease),
    scale 0.5s var(--ease),
    translate 0.45s var(--ease),
    text-shadow 0.45s var(--ease);
}

/* A short tick under each one, so it reads as something you can take. It runs
   out to the width of the word when that word is chosen. The 0.18em is the
   tracking hanging off the last letter — discounted so the rule lines up with
   the glyphs, not with the space after them. */
.app::after {
  content: '';
  position: absolute;
  left: calc(50% - 0.09em);
  translate: -50% 0;
  bottom: 0;
  width: 1.5em;
  height: 1px;
  background: currentColor;
  opacity: 0.3;
  transition:
    width 0.55s var(--ease),
    opacity 0.45s var(--ease);
}

/* while one is chosen the other two shrink back out of its way */
.apps.has-sel .app {
  opacity: 0.18;
  scale: 0.84;
}

/* the chosen one lights up */
.apps .app.is-on,
.apps .app:focus-visible {
  opacity: 1;
  scale: 1.06;
  translate: 0 -2px;
  text-shadow:
    0 0 28px rgba(241, 231, 236, 0.34),
    0 0 6px rgba(241, 231, 236, 0.22);
}

.apps .app.is-on::after,
.apps .app:focus-visible::after,
.app:hover::after {
  width: calc(100% - 0.18em);
  opacity: 1;
}

.app.is-soon {
  cursor: default;
}

/* ---------- the line under them ---------- */
.readout {
  position: relative;
  width: 100%;
  max-width: 54ch;
  /* fixed, so swapping never moves the names */
  height: clamp(6.75rem, 15vh, 8.25rem);
}

.panel {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  text-align: center;
  opacity: 0;
  translate: 0 6px;
  pointer-events: none;
  transition:
    opacity 0.35s var(--ease),
    translate 0.35s var(--ease);
}

.panel.is-on {
  opacity: 1;
  translate: 0 0;
  pointer-events: auto;
}

.panel-desc {
  color: var(--dim);
  font-size: clamp(0.8125rem, 1.25vw, 0.9375rem);
  line-height: 1.55;
  max-width: 46ch;
}

/* The resting line is one line against a box sized for three, so centre it —
   it then sits midway between the names and the footer. The product panels
   stay top-aligned, keeping each description tight under its name. */
.panel-rest {
  justify-content: center;
}

.panel-rest .panel-desc {
  text-transform: lowercase;
  letter-spacing: 0.06em;
  font-weight: 200;
}

/* the same chip the nav uses */
.panel-go {
  margin-top: 0.125rem;
  padding: 0.5625rem 1.25rem;
  font-size: 0.8125rem;
}

.panel-go::after {
  content: '\2192';
}

/* nothing to go to yet */
.panel-go.is-soon {
  color: var(--dim);
  border-color: var(--border-soft);
  background: transparent;
  cursor: default;
}

.panel-go.is-soon::after {
  content: '';
}

/* ---------- compact footer so the page fits one screen ---------- */
.portal-foot {
  flex: none;
  padding: 0.75rem var(--gutter) 1.125rem;
  text-align: center;
  font-size: 0.6875rem;
  color: var(--dim);
  position: relative;
  z-index: 1;
}

@media (max-width: 720px) {
  .apps {
    flex-direction: column;
    align-items: center;
    gap: clamp(0.375rem, 1.8vh, 0.875rem);
  }
  .app {
    font-size: clamp(1.25rem, 6.4vw, 2rem);
  }
  .scene {
    min-height: clamp(7rem, 22vh, 18rem);
  }
  .readout {
    height: clamp(5.5rem, 15vh, 7.5rem);
  }
}

@media (prefers-reduced-motion: reduce) {
  .app,
  .panel {
    transition-duration: 0.001ms !important;
  }
}
