/* ═══════════════════════════════════════════════════════════════
   LIQUID GLASS — translucent surface material for the landing page.

   Frosted glass only reads as glass when there is something moving
   behind it, so this file ships two halves that depend on each other:

     1. .lg-ambient — a fixed layer of slow-drifting colour fields that
        sits behind every scene. It is the thing the glass refracts.
     2. .lg — the material itself: a translucent fill that blurs and
        saturates its backdrop, a rim that bends light at the edge, a
        specular highlight that tracks the pointer, and a soft cast
        shadow underneath.

   The terminal identity is kept: monospace type, hard grid, matrix
   green (pink on light). What changes is that panels stop being opaque
   paint and start being a material with depth. Radius is deliberately
   small (10px) — a refractive edge needs some curvature to read, and
   anything rounder stops looking like this site.

   Everything is scoped under .lg-page, which assets/liquid-glass.js puts
   on <body>. index.html writes .lg and .lg-label into its own markup;
   every other page gets .lg-auto and .lg-notch from that script, which
   finds its cards by reading computed style rather than by class name.
   ═══════════════════════════════════════════════════════════════ */

/* The ambient layer sits at z-index -1 so it lands above the canvas and
   below every piece of content, which means no page container needs a
   position or z-index of its own. That only works if body stops painting
   its own background: html and body both carry `background: var(--bg)`,
   and body's opaque fill is painted after negative-z descendants, so with
   it left in place the field is invisible — measured, not assumed.
   html keeps the colour, so the canvas is unchanged. */
body.lg-page { background: transparent; }

.lg-page {
  /* ─── Material ─── */
  /* Same curve as every other card on the site (theme-terminal.css owns the
     scale). A refractive edge needs curvature to read as glass at all, so
     this one is load-bearing rather than decorative. */
  --lg-radius: var(--r-lg);
  --lg-blur: 20px;
  --lg-saturate: 165%;

  /* Fill: dark green-tinted smoke. Alpha is the single most important
     number here — too opaque and the ambient behind it disappears, too
     sheer and body text loses contrast. 0.42 is the floor that still
     keeps --fg-muted legible over a bright blob. */
  --lg-fill: rgba(4, 9, 6, 0.46);
  --lg-fill-hover: rgba(6, 13, 8, 0.56);

  /* Rim: light catches the top-left edge and bounces off the bottom.
     The green in the highlight is what ties the material to the theme
     instead of looking like generic iOS frosting. */
  --lg-rim-hi: rgba(160, 255, 190, 0.42);
  --lg-rim-lo: rgba(0, 255, 65, 0.10);
  --lg-spec-top: rgba(190, 255, 210, 0.16);
  --lg-spec-bottom: rgba(0, 255, 65, 0.05);

  /* Pointer-tracked specular sheen. */
  --lg-sheen: rgba(180, 255, 200, 0.13);

  --lg-shadow: rgba(0, 0, 0, 0.55);
  --lg-shadow-hover: rgba(0, 0, 0, 0.65);

  /* ─── Ambient field hues (dark) ─── */
  --lg-blob-1: rgba(0, 255, 65, 0.13);
  --lg-blob-2: rgba(0, 170, 255, 0.10);
  --lg-blob-3: rgba(0, 130, 105, 0.12);
  --lg-blob-4: rgba(130, 120, 255, 0.07);
}

/* Light theme: white glass over paper. The highlight flips to pure
   white and the rim picks up ink rather than glow, because a green
   halo on white reads as a rendering artefact. */
:root[data-theme="light"] .lg-page {
  --lg-fill: rgba(255, 255, 255, 0.55);
  --lg-fill-hover: rgba(255, 255, 255, 0.72);

  --lg-rim-hi: rgba(255, 255, 255, 0.95);
  --lg-rim-lo: rgba(16, 17, 20, 0.10);
  --lg-spec-top: rgba(255, 255, 255, 0.85);
  --lg-spec-bottom: rgba(16, 17, 20, 0.035);

  --lg-sheen: rgba(255, 255, 255, 0.60);

  --lg-shadow: rgba(16, 17, 20, 0.13);
  --lg-shadow-hover: rgba(16, 17, 20, 0.18);

  --lg-blob-1: rgba(214, 0, 108, 0.10);
  --lg-blob-2: rgba(120, 80, 255, 0.085);
  --lg-blob-3: rgba(255, 140, 60, 0.09);
  --lg-blob-4: rgba(0, 170, 255, 0.08);
}

/* ───────────────────────────────────────────────────────────────
   1. The ambient field — what the glass has to look at.

   Four large radial fields drift on long, mutually prime durations so
   the composition never visibly loops. They are painted at low alpha
   and then blurred hard, which is cheaper than it looks: the layer is
   composited once and the panels above simply sample it.
   ─────────────────────────────────────────────────────────────── */
.lg-ambient {
  position: fixed;
  inset: -20vmax;              /* overscan so drifting blobs never expose an edge */
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
  /* Its own stacking context, so the blur never bleeds into the nav. */
  isolation: isolate;
}
.lg-ambient span {
  position: absolute;
  display: block;
  border-radius: 50%;
  filter: blur(60px);
  will-change: transform;
}
.lg-ambient .b1 {
  width: 46vmax; height: 46vmax; left: 4%; top: 6%;
  background: radial-gradient(circle, var(--lg-blob-1) 0%, transparent 68%);
  animation: lg-drift-1 34s ease-in-out infinite alternate;
}
.lg-ambient .b2 {
  width: 40vmax; height: 40vmax; right: 2%; top: 22%;
  background: radial-gradient(circle, var(--lg-blob-2) 0%, transparent 68%);
  animation: lg-drift-2 43s ease-in-out infinite alternate;
}
.lg-ambient .b3 {
  width: 52vmax; height: 52vmax; left: 24%; bottom: 2%;
  background: radial-gradient(circle, var(--lg-blob-3) 0%, transparent 70%);
  animation: lg-drift-3 51s ease-in-out infinite alternate;
}
.lg-ambient .b4 {
  width: 34vmax; height: 34vmax; right: 18%; bottom: 12%;
  background: radial-gradient(circle, var(--lg-blob-4) 0%, transparent 66%);
  animation: lg-drift-4 39s ease-in-out infinite alternate;
}

@keyframes lg-drift-1 {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(14vmax, 8vmax, 0) scale(1.18); }
}
@keyframes lg-drift-2 {
  from { transform: translate3d(0, 0, 0) scale(1.1); }
  to   { transform: translate3d(-12vmax, 12vmax, 0) scale(0.92); }
}
@keyframes lg-drift-3 {
  from { transform: translate3d(0, 0, 0) scale(0.95); }
  to   { transform: translate3d(10vmax, -10vmax, 0) scale(1.15); }
}
@keyframes lg-drift-4 {
  from { transform: translate3d(0, 0, 0) scale(1.05); }
  to   { transform: translate3d(-9vmax, -7vmax, 0) scale(0.9); }
}

/* A faint grid printed on top of the fields. It gives the blur
   something with structure to distort, which is what separates
   "glass" from "a translucent rectangle". */
.lg-ambient::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, rgba(var(--accent-rgb), 0.055) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(var(--accent-rgb), 0.055) 1px, transparent 1px);
  background-size: 54px 54px;
  mask-image: radial-gradient(ellipse at 50% 45%, #000 0%, transparent 72%);
  -webkit-mask-image: radial-gradient(ellipse at 50% 45%, #000 0%, transparent 72%);
}
:root[data-theme="light"] .lg-ambient::after {
  background-image:
    linear-gradient(to right, rgba(16, 17, 20, 0.045) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(16, 17, 20, 0.045) 1px, transparent 1px);
}

/* Scenes and their content ride above the ambient layer. Only the
   stacking order is touched here: every one of these already carries a
   `position` that the page layout depends on (the scenes are fixed and
   crossfade in place), so overriding it would flatten the page. */
.lg-page main { position: relative; z-index: 2; }
.lg-page .scene { z-index: 2; }
.lg-page .scene.active { z-index: 3; }

/* The scenes used to paint their own opaque backgrounds, which would
   cover the field entirely. */
.lg-page .scene.how { background: transparent; border-top: none; }

/* ───────────────────────────────────────────────────────────────
   2. The material.
   ─────────────────────────────────────────────────────────────── */
.lg {
  position: relative;
  isolation: isolate;
  background: var(--lg-fill);
  border: none;
  border-radius: var(--lg-radius);
  backdrop-filter: blur(var(--lg-blur)) saturate(var(--lg-saturate));
  -webkit-backdrop-filter: blur(var(--lg-blur)) saturate(var(--lg-saturate));
  box-shadow:
    inset 0 1px 0 0 var(--lg-spec-top),
    inset 0 -1px 0 0 var(--lg-spec-bottom),
    0 16px 38px -14px var(--lg-shadow);
  transition: background-color 0.28s ease, box-shadow 0.28s ease, transform 0.28s ease;
}

/* The rim. Two jobs in one pseudo-element: a gradient hairline border
   (the mask-composite trick, since border-image cannot do rounded
   corners), and — because it also carries its own backdrop-filter —
   an extra bend of the backdrop in the outermost 1px, which is how a
   real lens edge behaves. */
.lg::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(
    145deg,
    var(--lg-rim-hi) 0%,
    transparent 38%,
    transparent 62%,
    var(--lg-rim-lo) 100%
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
  z-index: 1;
}

/* The sheen. A soft highlight anchored to the pointer (assets/
   liquid-glass.js writes --lg-mx / --lg-my). With no pointer it rests
   at the top-left, which is where the rim gradient says the light is
   coming from, so the card still looks lit on touch devices. */
.lg::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(
    circle 220px at var(--lg-mx, 18%) var(--lg-my, 0%),
    var(--lg-sheen) 0%,
    transparent 62%
  );
  opacity: 0.85;
  pointer-events: none;
  transition: opacity 0.3s ease;
  z-index: 0;
}

/* Keep real content above both decorative layers. */
.lg > * { position: relative; z-index: 2; }

.lg:hover {
  background: var(--lg-fill-hover);
  box-shadow:
    inset 0 1px 0 0 var(--lg-spec-top),
    inset 0 -1px 0 0 var(--lg-spec-bottom),
    0 22px 46px -14px var(--lg-shadow-hover);
}

/* ───────────────────────────────────────────────────────────────
   3. Glass chrome — nav and buttons on the landing page.
   ─────────────────────────────────────────────────────────────── */
.lg-page nav.top {
  background: var(--lg-fill);
  backdrop-filter: blur(22px) saturate(var(--lg-saturate));
  -webkit-backdrop-filter: blur(22px) saturate(var(--lg-saturate));
  border-bottom: 1px solid transparent;
  border-image: linear-gradient(90deg, transparent, var(--lg-rim-hi), transparent) 1;
}
/* On white, a white rim is no rim: the bar would float with no edge at all.
   Ink it instead. */
:root[data-theme="light"] .lg-page nav.top {
  border-image: linear-gradient(90deg, transparent, rgba(16, 17, 20, 0.16), transparent) 1;
}

.lg-page .cta.primary {
  border-radius: var(--lg-radius);
  box-shadow:
    inset 0 1px 0 0 rgba(255, 255, 255, 0.30),
    0 0 20px var(--accent-glow),
    0 10px 24px -10px var(--lg-shadow);
}
.lg-page .cta.ghost {
  border-radius: var(--lg-radius);
  border-color: transparent;
  background: var(--lg-fill);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  box-shadow:
    inset 0 0 0 1px var(--lg-rim-lo),
    inset 0 1px 0 0 var(--lg-spec-top),
    0 8px 20px -10px var(--lg-shadow);
}
.lg-page .cta.ghost:hover {
  background: var(--lg-fill-hover);
  box-shadow:
    inset 0 0 0 1px var(--lg-rim-hi),
    inset 0 1px 0 0 var(--lg-spec-top),
    0 12px 26px -10px var(--lg-shadow-hover);
}

/* The scene dots read as small glass beads rather than flat circles. */
.lg-page .scene-nav .dot {
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  background: var(--lg-fill);
}

/* ───────────────────────────────────────────────────────────────
   4. Panel labels.

   The terminal cards notch their label into the top border with an
   opaque chip (`─[ SEALED ]─` painted over the line). An opaque chip
   on a translucent panel is exactly the seam that breaks the illusion,
   so on glass the label becomes an inset pill instead.
   ─────────────────────────────────────────────────────────────── */
.lg-label {
  display: inline-block;
  margin-bottom: 0.75rem;
  padding: 0.16rem 0.5rem;
  border-radius: 999px;
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  background: rgba(var(--accent-rgb), 0.10);
  box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0.22);
}
:root[data-theme="light"] .lg-label {
  color: var(--accent);
  background: rgba(var(--accent-rgb), 0.07);
  box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0.18);
}

/* ───────────────────────────────────────────────────────────────
   5. The rest of the site.

   index.html hand-writes .lg onto the panels it wants. Every other page
   gets .lg-auto from liquid-glass.js, which finds its cards by computed
   style. The material is the same; what differs is that here it has to
   take a background and a border away from a rule the page already set.

   The doubled class is deliberate. Page styles live in a <style> block
   further down the same <head>, so a page rule at equal specificity wins
   the tie on order. `.lg-page .lg-auto.lg-auto` is 0,3,0, which clears
   the .panel[data-label] / .card.featured class of selector without
   reaching for !important and without having to know what each page
   named its cards.
   ─────────────────────────────────────────────────────────────── */
.lg-page .lg-auto.lg-auto {
  isolation: isolate;
  background: var(--lg-fill);
  border-color: transparent;
  border-radius: var(--lg-radius);
  backdrop-filter: blur(var(--lg-blur)) saturate(var(--lg-saturate));
  -webkit-backdrop-filter: blur(var(--lg-blur)) saturate(var(--lg-saturate));
  box-shadow:
    inset 0 0 0 1px var(--lg-rim-lo),
    inset 0 1px 0 0 var(--lg-spec-top),
    inset 0 -1px 0 0 var(--lg-spec-bottom),
    0 16px 38px -14px var(--lg-shadow);
}

/* ::after is inset:0 against the card, so the card has to be a containing
   block. Most are static and get this class from liquid-glass.js. The ones
   the page positioned itself already qualify and are left alone: writing
   position:relative over a fixed overlay takes it out of the viewport. */
.lg-page .lg-auto.lg-rel { position: relative; }

/* The transition is withheld until the frame after tagging, and only then
   handed out by liquid-glass.js. Declared on the base rule it animates the
   very first application too, so every page load showed a third of a second
   of each card fading from its old opaque paint into glass. Caught because
   the audit kept reading one card at rgba(0,0,0,0.976): mid-fade. */
.lg-page .lg-auto.lg-lit {
  transition: background-color 0.28s ease, box-shadow 0.28s ease;
}

/* The rim and the sheen, same two pseudo-elements as .lg. Kept as a
   separate rule so a page that already uses ::before on its cards for a
   notched label is not silently overwritten — .lg-notch below moves that
   label out of the way first. */
.lg-page .lg-auto::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(
    circle 220px at var(--lg-mx, 18%) var(--lg-my, 0%),
    var(--lg-sheen) 0%,
    transparent 62%
  );
  opacity: 0.85;
  pointer-events: none;
  z-index: 0;
}
.lg-page .lg-auto > * { position: relative; z-index: 2; }

.lg-page .lg-auto:hover {
  background: var(--lg-fill-hover);
  box-shadow:
    inset 0 0 0 1px var(--lg-rim-hi),
    inset 0 1px 0 0 var(--lg-spec-top),
    inset 0 -1px 0 0 var(--lg-spec-bottom),
    0 22px 46px -14px var(--lg-shadow-hover);
}

/* Glass inside glass. Blurring a backdrop that is already blurred buys
   nothing and stacking two fills makes the inner card muddy, so a nested
   card keeps only the rim that separates it from its parent. */
.lg-page .lg-auto.lg-nested.lg-nested {
  background: rgba(var(--accent-rgb), 0.03);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: inset 0 0 0 1px var(--lg-rim-lo);
}
:root[data-theme="light"] .lg-page .lg-auto.lg-nested.lg-nested {
  background: rgba(16, 17, 20, 0.028);
}
.lg-page .lg-auto.lg-nested:hover {
  background: rgba(var(--accent-rgb), 0.055);
  box-shadow: inset 0 0 0 1px var(--lg-rim-hi);
}
:root[data-theme="light"] .lg-page .lg-auto.lg-nested:hover {
  background: rgba(16, 17, 20, 0.05);
}

/* ─── Notched labels ───
   The terminal panels print their title into a gap in their own top
   border: `─[ SEALED ]─` in an opaque chip painted over the line. The
   chip has to be opaque to hide the line, and an opaque chip straddling
   the edge of a translucent panel is the one seam that gives the whole
   material away. On glass there is no drawn line to hide, so the label
   moves inside and becomes a pill, which is what index.html does by hand
   with .lg-label.

   The chip stays exactly where the page put it. Taking it out of absolute
   positioning and letting it sit in the flow looked right in the abstract
   and was wrong in practice: several of these cards are grid or flex
   containers, so a static ::before becomes a grid item and stretches to
   fill a whole cell. On credits.html the balance label turned into an
   empty 420px pill. So only the paint changes — the opaque chip becomes a
   small glass pill that blurs whatever it straddles, which reads as a tag
   clipped to the rim instead of a patch covering a seam.

   liquid-glass.js tags these by reading ::before content, not by class:
   the classes that carry them (.card, .badge, .panel, form.term-form)
   mean different things on different pages. */
.lg-page .lg-notch.lg-notch::before {
  border-radius: 999px;
  padding: 0.06rem 0.55rem;
  background: rgba(var(--accent-rgb), 0.12);
  box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0.26);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
}
:root[data-theme="light"] .lg-page .lg-notch.lg-notch::before {
  background: rgba(var(--accent-rgb), 0.09);
  box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0.20);
}

/* ─── Chrome ───
   The bar and its dropdown, on every page rather than just the landing.
   nav.top paints its own background from --bg-elevated; over a drifting
   field that has to become glass too or the page reads as two materials
   stacked on each other. */
.lg-page nav.top .links {
  background: var(--lg-fill);
  backdrop-filter: blur(22px) saturate(var(--lg-saturate));
  -webkit-backdrop-filter: blur(22px) saturate(var(--lg-saturate));
}

/* ───────────────────────────────────────────────────────────────
   6. Graceful degradation.

   Without backdrop-filter there is no glass, only an unreadably sheer
   rectangle. Fall back to the opaque terminal panel.
   ─────────────────────────────────────────────────────────────── */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .lg,
  .lg-page .lg-auto.lg-auto,
  .lg-page nav.top,
  .lg-page nav.top .links,
  .lg-page .cta.ghost {
    background: var(--panel-bg);
    box-shadow: inset 0 0 0 1px var(--border-strong);
  }
  .lg-ambient { display: none; }
  /* No field behind the glass means nothing to hide, so the chips go
     back to being flat opaque notches. */
  .lg-page .lg-notch.lg-notch::before {
    border-radius: 0;
    background: var(--panel-bg);
    box-shadow: none;
  }
}

/* Motion is decoration here: the material still reads with the fields
   parked. Honour the OS setting. */
@media (prefers-reduced-motion: reduce) {
  .lg-ambient span { animation: none; }
  .lg,
  .lg-page .lg-auto.lg-lit { transition: none; }
}

/* Mobile: heavy blur over a full-screen animated layer is the one
   combination that drops frames on phones. Cut the blur radius, park
   the fields, and lean on the fill instead. */
@media (max-width: 720px) {
  .lg-page {
    --lg-blur: 12px;
    --lg-fill: rgba(6, 12, 8, 0.58);
  }
  :root[data-theme="light"] .lg-page { --lg-fill: rgba(255, 255, 255, 0.72); }
  .lg-ambient span { animation: none; filter: blur(48px); }
  .lg::after,
  .lg-page .lg-auto::after { display: none; }
}

/* The nav dropdown stops being chrome below the nav breakpoint.

   On a wide screen `.links` is a row of text sitting inside the bar, and
   glassing it matches the bar it lives in. Under 760px the same element
   becomes a full-width menu that hangs below the bar and floats over
   whatever the page is showing, and the glass rule turned it into an
   unreadable sheet: the menu items and the page text underneath were drawn
   on top of each other.

   The blur cannot save it either, because nav.top carries its own
   backdrop-filter. An element with a backdrop-filter is a backdrop root, so
   a descendant's backdrop-filter can only sample what is painted inside the
   ancestor's box. The dropdown hangs outside that box, and behind the
   overhang there is nothing in its backdrop root to blur. The filter is a
   no-op there and all that survives is a 0.58 alpha fill over live text.

   So the menu goes solid, and the rim and the drop shadow carry the
   layering instead. Matched to the nav breakpoint, not the 720px
   performance one, or the menu is still glass between 721 and 760. */
@media (max-width: 760px) {
  .lg-page nav.top .links {
    background: var(--panel-bg);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    box-shadow:
      inset 0 0 0 1px var(--border-strong),
      0 16px 32px -8px rgba(0, 0, 0, 0.7);
  }
  /* A black drop shadow on a white sheet reads as dirt rather than depth. */
  :root[data-theme="light"] .lg-page nav.top .links {
    box-shadow:
      inset 0 0 0 1px var(--border-strong),
      0 16px 32px -8px rgba(16, 17, 20, 0.18);
  }
}
