/* ==========================================================================
   LANDING — the public page at /
   --------------------------------------------------------------------------
   REBUILT alongside frontend/landing.js under SPEC_175. The previous sheet used
   `lp-` prefixes, which put every class it defined inside the reach of
   instrument.css's substring family and obsidian_orchid.css's suffix family
   (`-title`, `-label`, `-chip`, `-panel`, `-line`, …). Class names here are
   hyphen-free camelCase under `lnd`, which makes that entire family
   unmatchable by construction — the same reason the component kit uses
   `sgk`/`sgt`.

   Three classes are DELIBERATELY still `pk-`: `pk-live-stamp`, `pk-quote-price`
   and `pk-delta-value`. Those are exactly the cases where the substring
   contract is wanted — an amber live dot, tabular figures, a signed delta —
   and re-implementing them here would give the page a second visual language.
   See the class-naming contract in frontend/page_kit.js.

   LOADED AFTER instrument.css and pages.css. Shares the ground plane, the mark
   and the illustration language with static/pages_error.css, which
   frontend/pages_error.js attaches on both pages.

   DESIGN POSITION
   instrument.css's thesis is "restraint with hierarchy: one loud element per
   screen". Two things are loud here — the headline and the live board — and the
   board is loud because it is the argument. There is no gradient hero, no
   blurred colour blob and no gradient-clipped headline text: a purple-to-blue
   wash is the most recognisable tell of a generated page, and this product's
   entire position is that it is not one. Depth comes from a dot grid on the
   ground plane (item 25) and from the elevation ladder.

   NO RAW HEX. Both themes resolve through instrument.css's token remapping, so
   there is no theme block in this file and none is needed.
   ========================================================================== */

.lndMain { max-width: 1220px; padding-top: 0; padding-bottom: 0; }

/* ==========================================================================
   1 — HERO
   --------------------------------------------------------------------------
   AMBIENT LIGHT, NOT A HERO GRADIENT. The note above says a purple-to-blue wash
   is the most recognisable tell of a generated page, and that still holds — so
   what sits behind the headline is not a hero gradient. It is the same fixed
   light source instrument.css puts over the whole product (`--i-ambient`),
   brought down to hero scale: two very wide ellipses at 10% and 7% of the
   accent, mixed FROM `--i-orchid` rather than from the pre-baked
   `--i-accent-glow` literal, so it follows a reader's chosen accent
   (`data-accent="amber"` / `"cyber"`) and both themes instead of pinning the
   page to magenta.

   Ten percent is the whole argument. At that alpha it is a change in the
   quality of the black rather than a coloured shape, which is what the target
   look actually does — and it is behind type at ink-1 (17.6:1 on the void), so
   it cannot move body contrast off AA.

   NO PHOTOGRAPHY AND NO MOCK SCREENSHOT. The live board to the right of the
   headline is this product's own UI showing real quotes. Inventing a picture of
   a terminal would break the one rule this page exists to demonstrate.
   ========================================================================== */

.lndHero {
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(0, 0.98fr);
  gap: 56px;
  align-items: center;
  padding: 96px 0 88px;
  min-width: 0;
  /* Its own stacking context, so the wash below sits behind the hero's content
     and NOTHING else — no negative z-index escaping into the page, which is how
     an ambient layer ends up behind an opaque ancestor and disappears. */
  position: relative;
  isolation: isolate;
}

.lndHero::before {
  content: "";
  position: absolute;
  z-index: 0;
  pointer-events: none;
  left: 50%;
  top: -14%;
  width: min(1180px, 132%);
  aspect-ratio: 2 / 1;
  transform: translate(-50%, 0);
  background:
    radial-gradient(ellipse 58% 62% at 30% 42%,
      color-mix(in srgb, var(--i-orchid) 10%, transparent), transparent 70%),
    radial-gradient(ellipse 46% 54% at 74% 28%,
      color-mix(in srgb, var(--i-cyber) 7%, transparent), transparent 72%);
  animation: lndDrift 38s var(--i-ease-inout) infinite;
}

/* One cycle every 38 seconds and a 2.5% travel: below the threshold at which a
   reader notices motion at all, which is the point — it keeps the ground plane
   from reading as a flat fill without ever competing with the headline. The
   transform keeps the -50% centring in every keyframe; dropping it there is how
   a centred element snaps sideways on the first frame. */
@keyframes lndDrift {
  0%, 100% { transform: translate(-50%, 0) scale(1); }
  50%      { transform: translate(-50%, 2.5%) scale(1.07); }
}

.lndHeroCopy { position: relative; z-index: 1; min-width: 0; }

.lndEyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 22px;
  padding: 5px 12px;
  border: 1px solid color-mix(in srgb, var(--i-orchid) 34%, transparent);
  border-radius: var(--i-r-pill);
  background: var(--i-orchid-wash);
  color: var(--i-orchid-bright);
  font-size: var(--i-t-xs);
  letter-spacing: var(--i-track-label);
  text-transform: uppercase;
}

/* The one genuinely large thing on the page. clamp() rather than a media-query
   ladder so it degrades continuously instead of jumping at a breakpoint. */
/* ==========================================================================
   HERO ATMOSPHERE — the rings, the aurora, the grain

   THE DESIGN FILE SPECIFIED THIS AND IT WAS NEVER BUILT.
   Singularity_UI/aesthetics/LANDING_PAGE.md, "Rings (right 50%)":

     Outer:  conic gradient (gold), 38s rotation, clockwise
     Middle: lighter gradient, 22s, counter-clockwise
     Inner:  radial pulse, 5s loop

   The hero shipped with two static radial blobs instead, which is why it reads
   as a dark rectangle with text on it.

   EVERY LAYER ANIMATES `transform` OR `opacity` ON AN ELEMENT THAT IS ALREADY
   VISIBLE, never `opacity` from 0. A running animation pins its element at the
   `from` keyframe until a frame arrives, and frames are not guaranteed — a
   background tab throttles, a heavy paint stalls one. That failure once left a
   whole screen rendered, correct and invisible (CLAUDE.md hazard 5). A ring
   that never animates is a still ring; a ring that starts at opacity 0 is a
   missing ring.

   All of it is `pointer-events: none` and sits under the copy: this is
   atmosphere you notice on the second look, not a toy that interrupts the
   first. That distinction is why the cursor spotlight was removed.
   ========================================================================== */

/* THE PURGE DELETES THIS ENTIRE LAYER UNLESS IT IS EXEMPTED, and the way it
   does so is invisible.

   skin.css section 3 sets `background-image: none !important` and
   `border-radius: 0 !important` on `#page-root [class][class]`. A
   conic-gradient IS a background-image, and a ring is a border-radius — so the
   purge does not merely dim these layers, it removes every one of them and
   leaves the markup in place. First render after building them: byte-identical
   to the hero without them.

   Same shape as the display face losing to the body face in the same sheet:
   the thing that erases the design is a blanket rule written for a different
   problem, in the file that loads last, and nothing downstream can see it
   happening. `#page-root .lndAtmos [class][class]` is (1,3,0), which clears
   the purge's (1,2,0). Scoped to this one decorative subtree, so the purge
   keeps flattening every panel it was written for. */
#page-root .lndAtmos[class][class],
#page-root .lndAtmos [class][class] {
  background-image: revert-layer !important;
  border-radius: revert-layer !important;
  border-width: revert-layer !important;
  box-shadow: revert-layer !important;
}

/* `revert-layer` on an unlayered sheet reverts to the previous origin, which
   is not what is wanted here — the values are restated explicitly so the
   declarations above cannot silently resolve to nothing. */
#page-root .lndRing[class][class] { border-radius: 50% !important; }
#page-root .lndAurora[class][class] { border-radius: 50% !important; }

#page-root .lndRing--outer[class][class] {
  background-image: conic-gradient(from 0deg,
    transparent 0deg,
    color-mix(in srgb, var(--i-accent, #e1ad66) 55%, transparent) 70deg,
    transparent 150deg,
    color-mix(in srgb, var(--i-accent, #e1ad66) 30%, transparent) 250deg,
    transparent 330deg) !important;
}

#page-root .lndRing--mid[class][class] {
  background-image: conic-gradient(from 180deg,
    transparent 0deg,
    color-mix(in srgb, var(--i-accent-bright, #facb8d) 42%, transparent) 90deg,
    transparent 200deg) !important;
}

#page-root .lndRing--core[class][class] {
  background-image: radial-gradient(circle,
    color-mix(in srgb, var(--i-accent, #e1ad66) 22%, transparent),
    transparent 70%) !important;
}

#page-root .lndAurora--a[class][class] {
  background-image: radial-gradient(circle,
    color-mix(in srgb, var(--i-accent, #e1ad66) 16%, transparent), transparent 62%) !important;
}

#page-root .lndAurora--b[class][class] {
  background-image: radial-gradient(circle,
    color-mix(in srgb, var(--i-bull, #4fb286) 13%, transparent), transparent 64%) !important;
}

@keyframes lndSpin      { to   { transform: rotate(360deg); } }
@keyframes lndSpinBack  { to   { transform: rotate(-360deg); } }
@keyframes lndPulse     { 0%, 100% { transform: scale(1);    opacity: 0.55; }
                          50%      { transform: scale(1.14); opacity: 0.9; } }
@keyframes lndFloat     { 0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
                          50%      { transform: translate3d(3%, -2.5%, 0) scale(1.1); } }
@keyframes lndFloatAlt  { 0%, 100% { transform: translate3d(0, 0, 0) scale(1.05); }
                          50%      { transform: translate3d(-4%, 3%, 0) scale(0.93); } }

.lndAtmos {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
  /* Contains the oversized rings without clipping the hero's own layout. */
  contain: paint;
}

/* The rings sit over the right half, behind the live watchlist panel, exactly
   where the design file puts them. `aspect-ratio: 1` keeps them circular at
   every width without a second measurement. */
.lndRing {
  position: absolute;
  top: 50%;
  left: 72%;
  aspect-ratio: 1;
  border-radius: 50%;
  transform-origin: 50% 50%;
  translate: -50% -50%;
  will-change: transform;
}

.lndRing--outer {
  width: min(52vw, 720px);
  background: conic-gradient(from 0deg,
    transparent 0deg,
    color-mix(in srgb, var(--i-accent, #e1ad66) 55%, transparent) 70deg,
    transparent 150deg,
    color-mix(in srgb, var(--i-accent, #e1ad66) 30%, transparent) 250deg,
    transparent 330deg);
  /* A ring, not a disc: the mask cuts the middle out so the gradient reads as
     a stroke sweeping around rather than a spinning pie. */
  mask: radial-gradient(circle, transparent 61%, #000 62%, #000 65%, transparent 66%);
  -webkit-mask: radial-gradient(circle, transparent 61%, #000 62%, #000 65%, transparent 66%);
  animation: lndSpin 38s linear infinite;
  opacity: 0.75;
}

.lndRing--mid {
  width: min(38vw, 520px);
  background: conic-gradient(from 180deg,
    transparent 0deg,
    color-mix(in srgb, var(--i-accent-bright, #facb8d) 42%, transparent) 90deg,
    transparent 200deg);
  mask: radial-gradient(circle, transparent 70%, #000 71%, #000 73%, transparent 74%);
  -webkit-mask: radial-gradient(circle, transparent 70%, #000 71%, #000 73%, transparent 74%);
  animation: lndSpinBack 22s linear infinite;
  opacity: 0.7;
}

.lndRing--core {
  width: min(28vw, 380px);
  background: radial-gradient(circle,
    color-mix(in srgb, var(--i-accent, #e1ad66) 22%, transparent),
    transparent 70%);
  filter: blur(18px);
  animation: lndPulse 5s ease-in-out infinite;
}

/* Two drifting colour fields, counter-phase so the ground never sits still and
   never pulses in unison with the rings. */
.lndAurora {
  position: absolute;
  border-radius: 50%;
  filter: blur(64px);
  will-change: transform;
}

.lndAurora--a {
  left: -12%; top: -26%;
  width: 56vw; aspect-ratio: 1;
  background: radial-gradient(circle,
    color-mix(in srgb, var(--i-accent, #e1ad66) 16%, transparent), transparent 62%);
  animation: lndFloat 26s ease-in-out infinite;
}

.lndAurora--b {
  right: -16%; bottom: -30%;
  width: 50vw; aspect-ratio: 1;
  background: radial-gradient(circle,
    color-mix(in srgb, var(--i-bull, #4fb286) 13%, transparent), transparent 64%);
  animation: lndFloatAlt 31s ease-in-out infinite;
}

/* Fractal grain, inline so it needs no network. Static by design — animated
   grain is nausea, not texture. */
.lndGrain {
  position: absolute;
  inset: 0;
  opacity: 0.055;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/></filter><rect width='160' height='160' filter='url(%23n)'/></svg>");
}

/* THE LEDE WAS UNREADABLE OVER THE BRIGHTEST PART OF THE CANDLE TAPE, and
   adding rings behind it would have made that worse. A scrim under the copy
   column only — not over the whole hero, which would flatten the atmosphere
   this section exists to create. */
.lndHeroCopy {
  position: relative;
  z-index: 2;
}

.lndHeroCopy::before {
  content: "";
  position: absolute;
  inset: -32px -48px -32px -40px;
  z-index: -1;
  background: radial-gradient(ellipse at 30% 45%,
    rgba(0, 0, 0, 0.82) 0%,
    rgba(0, 0, 0, 0.62) 45%,
    transparent 78%);
  pointer-events: none;
}

/* Motion is atmosphere, and atmosphere is the first thing to drop when someone
   has asked for less of it. The layers stay — a still ring is still design. */
@media (prefers-reduced-motion: reduce) {
  .lndRing, .lndAurora { animation: none !important; }
}

/* THE DISPLAY FACE IS THE DESIGN FILE'S, NOT THIS SHEET'S.
   Singularity_UI/Design.md: "Display (headings): Instrument Serif, italic, 400
   weight". This rule carried weight 600 in the body face, and the measured
   result was that the page's largest line rendered in Barlow upright — the one
   typographic gesture that distinguishes this product from a generic dashboard,
   absent from the first thing anyone sees.

   Weight and tracking move with the face, they are not preferences: Instrument
   Serif italic at 600 is a synthesised bold of a face that has no bold, and
   -0.035em was tuned for Barlow's sidebearings, not for a serif's. Both are the
   spec's own values. */
/* SPECIFICITY, MEASURED RATHER THAN GUESSED. `.lndH1 { font-family: ...
   !important }` at (0,1,0) lost: font-style and font-weight from the same block
   applied and font-family did not, which is the signature of a MORE SPECIFIC
   rule setting only that one property. `--font-heading` is defined in no
   stylesheet in this build, so the var() fallback was never the problem.

   `#page-root h1.lndH1[class]` is (1,2,1) — the same escalation idiom this
   codebase already uses for `a[href].pk-card`, and enough to clear the
   `#page-root [class][class]` shape at (1,2,0) that skin.css writes from. */
#page-root h1.lndH1[class] {
  font-family: "Instrument Serif", Georgia, serif !important;
}

.lndH1 {
  margin: 0 0 24px;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(38px, 6vw, 68px) !important;
  line-height: 1.02;
  letter-spacing: -0.025em;
  color: var(--i-ink-1);
  text-wrap: balance;
  overflow-wrap: break-word;
}

/* The emphasised run is marked by colour and a hairline, not by a clipped
   gradient. A gradient here would be the single most generic thing on the
   page and it would also break the moment a reader picks a different accent.

   `font-style` is no longer reset to normal: the whole line is italic now, so
   un-italicising the emphasised run would make the emphasis read as a mistake
   rather than as emphasis. Colour and the underline carry it on their own. */
.lndH1 em {
  font-style: italic;
  color: var(--i-orchid-bright);
  box-shadow: inset 0 -2px 0 0 color-mix(in srgb, var(--i-orchid) 45%, transparent);
}

.lndLede {
  margin: 0 0 32px !important;
  max-width: 56ch;
  font-size: var(--i-t-lg) !important;
  line-height: var(--i-lh-body);
  color: var(--i-ink-2) !important;
}

.lndHeroHint {
  margin: 18px 0 0 !important;
  max-width: 54ch;
  font-size: var(--i-t-sm) !important;
  color: var(--i-ink-3) !important;
  line-height: 1.55;
}

/* ==========================================================================
   2 — BUTTONS
   One loud action per band; everything else is a quiet control.
   ========================================================================== */

.lndActions { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
.lndActionsAfter { margin-top: 24px; }

.lndBtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: 11px 20px;
  border: 1px solid var(--i-hair-strong);
  border-radius: var(--i-r-control);
  background: var(--i-control-bg);
  color: var(--i-ink-1);
  font-family: inherit;
  font-size: var(--i-t-body);
  font-weight: 500;
  text-decoration: none;
  text-align: center;
  cursor: pointer;
  transition: background var(--i-dur-fast) var(--i-ease-out),
              border-color var(--i-dur-fast) var(--i-ease-out);
}
.lndBtn:hover { background: var(--i-control-bg-hover); border-color: var(--i-accent-edge-soft); }

.lndBtn.primary {
  padding: 11px 24px;
  border-color: var(--i-accent-edge);
  background: var(--i-gradient-primary);
  color: var(--i-ink-on-accent);
  box-shadow: var(--i-btn-primary-shadow);
}
.lndBtn.primary:hover { box-shadow: var(--i-btn-primary-shadow-hover); }

/* --focus-ring is an OUTLINE SHORTHAND in instrument.css. Consumed as one.
   Redefining it as a box-shadow anywhere deletes the focus ring on every
   element in the product that reads it. */
.lndBtn:focus-visible,
.lndFigCell:focus-visible,
.lndWsCard:focus-visible,
.lndBoardRow:focus-visible,
.lndBoardOpen:focus-visible,
.lndRefresh:focus-visible,
.lndSrcName:focus-visible,
.lndBoardSrc:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
}

/* ==========================================================================
   3 — THE LIVE PROOF BOARD
   Real quotes, one route, one timestamp, and a provenance line that is the
   product claim rather than a footnote.
   ========================================================================== */

.lndBoard {
  min-width: 0;
  position: relative;
  z-index: 1;
  border: 1px solid var(--i-hair);
  border-radius: var(--i-r-panel);
  background: var(--i-surface-1);
  /* Elevated above the ground plane so it reads as an instrument sitting on the
     page rather than as a section of it. */
  box-shadow: var(--i-elev-3);
  overflow: hidden;
}

.lndBoardHead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 13px 18px;
  border-bottom: 1px solid var(--i-hair);
  background: var(--i-field-bg);
}

.lndBoardWhat { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.lndBoardName {
  color: var(--i-ink-1);
  font-size: var(--i-t-sm);
  font-weight: 600;
  letter-spacing: var(--i-track-tight);
}

.lndBoardOpen {
  flex: 0 0 auto;
  font-family: var(--oo-font-data);
  font-size: var(--i-t-xs);
  letter-spacing: 0.08em;
  color: var(--i-orchid-bright);
  border: 1px solid color-mix(in srgb, var(--i-orchid) 40%, transparent);
  border-radius: var(--i-r-pill);
  background: var(--i-orchid-wash);
  padding: 4px 11px;
  text-decoration: none;
  white-space: nowrap;
}
.lndBoardOpen:hover { border-color: var(--i-orchid); color: var(--i-ink-1); }

.lndBoardRows { min-height: 172px; }

.lndBoardRow {
  display: grid;
  grid-template-columns: minmax(0, 74px) minmax(0, 1fr) minmax(0, 108px) minmax(0, 92px);
  align-items: center;
  gap: 14px;
  padding: 13px 18px;
  border-bottom: 1px solid var(--i-hair);
  text-decoration: none;
  /* Not cosmetic. A block-level <a> with no colour set keeps the user agent's
     link colour, and every descendant that does not set its own inherits it —
     a computed-style sweep on the previous build found 15 elements resolving to
     Chrome's dark-mode #9E9EFF, a hue this design system does not contain. */
  color: inherit;
  transition: background var(--i-dur-fast) var(--i-ease-out);
}
.lndBoardRow:last-child { border-bottom: none; }
.lndBoardRow:hover { background: var(--i-row-hover); }

.lndBoardSym {
  font-family: var(--oo-font-data);
  font-size: var(--i-t-body);
  font-weight: 500;
  letter-spacing: 0.05em;
  color: var(--i-ink-1);
}
.lndBoardSpark { height: 34px; min-width: 0; }
.lndBoardFigs { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; min-width: 0; }
/* ink-3, not ink-4. ink-4 is 3.03:1 on the void — it is the RULE colour, and
   volume is a figure a reader is meant to be able to read. ink-3 is 5.70:1 and
   clears AA. */
.lndBoardVol {
  font-size: var(--i-t-xs);
  color: var(--i-ink-3);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.lndBoardEmpty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 26px 22px 30px;
  text-align: center;
}
.lndBoardEmptyText {
  margin: 0 !important;
  max-width: 40ch;
  font-size: var(--i-t-sm) !important;
  color: var(--i-ink-3) !important;
  line-height: 1.55;
}

/* --- provenance foot ------------------------------------------------------ */

.lndBoardFoot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 11px 18px 13px;
  border-top: 1px solid var(--i-hair);
  background: var(--i-wash-faint);
}

.lndBoardNote {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px;
  min-width: 0;
  font-size: 11px;
  line-height: 1.5;
}
.lndBoardNoteKey {
  font-size: var(--i-t-xs);
  letter-spacing: var(--i-track-label);
  text-transform: uppercase;
  color: var(--i-ink-3);
}
.lndBoardSrc { color: var(--i-ink-2); text-decoration: none; overflow-wrap: anywhere; }
a.lndBoardSrc { border-bottom: 1px solid var(--i-hair-strong); }
a.lndBoardSrc:hover { color: var(--i-orchid-bright); border-bottom-color: var(--i-orchid); }
.lndDot { color: var(--i-ink-4); }

.lndRefresh {
  flex: 0 0 auto;
  min-height: 30px;
  padding: 4px 12px;
  border: 1px solid var(--i-hair-strong);
  border-radius: var(--i-r-pill);
  background: var(--i-control-bg);
  color: var(--i-ink-2);
  font-family: inherit;
  font-size: var(--i-t-xs);
  letter-spacing: var(--i-track-label);
  text-transform: uppercase;
  cursor: pointer;
  transition: background var(--i-dur-fast) var(--i-ease-out);
}
.lndRefresh:hover { background: var(--i-control-bg-hover); color: var(--i-ink-1); }

/* ==========================================================================
   4 — COUNTED, NOT CLAIMED
   Four figures. Three are locked by tests/test_landing_counts.py; the fourth is
   counted live in the browser. Each cell links to the page where the reader can
   check it, which is the only reason to publish a number at all.
   ========================================================================== */

/* THE 1px-GAP-OVER-A-BACKGROUND TRICK IS GONE, and it had to go rather than be
   fixed. It draws a rule by leaving a 1px gap between cells and letting the
   CONTAINER'S BACKGROUND show through — which requires the container to have a
   background and the cells to be opaque. Both are `background-color:
   transparent !important` inside `#page-root`, imposed by skin.css's nested-
   fill purge at roughly (1,18,0). Hazard 24: no honest selector wins that
   ladder, and the rules simply never rendered.

   Real borders instead. They lose only to the (1,2,0) border purge, which
   skin.css §4b beats at (1,3,0) — see the long note there. */
/* Answer 274b: separate boxes, so the grid gains a real gap. The old
   `gap: 0` existed to let adjacent cells share one divider line; boxes do
   not share edges. */
.lndFigs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
  gap: 12px;
  margin: 0 0 96px;
}

.lndFigCell {
  display: block;
  padding: 26px 22px;
  min-width: 0;
  color: inherit;
  text-decoration: none;
  transition: background var(--i-dur-fast) var(--i-ease-out);
}
.lndFigCell:hover { background: var(--i-surface-1); }

.lndFig {
  display: block;
  font-family: var(--oo-font-data);
  font-size: 34px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.028em;
  color: var(--i-ink-1);
  font-variant-numeric: tabular-nums;
  min-height: 34px;
}
.lndFigName { display: block; margin-top: 9px; color: var(--i-ink-2); font-size: var(--i-t-sm); line-height: 1.45; }
.lndFigNote { display: block; margin-top: 6px; color: var(--i-ink-3); font-size: 11px; line-height: 1.45; }

/* ==========================================================================
   5 — SECTIONS
   ========================================================================== */

/* 96px between bands. A landing page's job is to let a reader decide whether to
   keep going, and the decision is made at the gap — 40px reads as one long
   document, 96px reads as five separate claims. */
.lndSection { padding: 0 0 96px; min-width: 0; }

.lndSectionHead { max-width: 68ch; margin: 0 0 32px; }
.lndSectionHead h2 {
  margin: 0 0 12px;
  font-size: clamp(26px, 3.4vw, 38px) !important;
  letter-spacing: -0.028em;
  line-height: 1.12;
  color: var(--i-ink-1);
}
.lndSectionHead p {
  margin: 0 !important;
  font-size: var(--i-t-md) !important;
  color: var(--i-ink-2) !important;
  line-height: var(--i-lh-body);
}

/* --- workspaces ---------------------------------------------------------- */

.lndWsGrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 16px;
}

.lndWsCard {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 24px;
  min-width: 0;
  border: 1px solid var(--i-hair);
  border-radius: var(--i-r-card);
  background: var(--i-surface-1);
  color: inherit;
  text-decoration: none;
  transition: border-color var(--i-dur-fast) var(--i-ease-out),
              background var(--i-dur-fast) var(--i-ease-out),
              box-shadow var(--i-dur-fast) var(--i-ease-out),
              transform var(--i-dur-fast) var(--i-ease-out);
}
/* The lift. 2px and one elevation step — the card is picked up off the ground
   plane, it does not jump. Anything larger and a grid of nine of them turns
   into a game of whack-a-mole under a moving cursor. */
.lndWsCard:hover {
  border-color: var(--i-accent-edge-soft);
  background: var(--i-surface-2);
  transform: translateY(-2px);
  box-shadow: var(--i-elev-2);
}

.lndWsTop { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.lndWsName {
  font-size: var(--i-t-md);
  font-weight: 600;
  color: var(--i-ink-1);
  letter-spacing: var(--i-track-tight);
}
.lndWsCount {
  font-family: var(--oo-font-data);
  font-size: var(--i-t-sm);
  color: var(--i-orchid-bright);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.lndWsWhat { margin: 0 !important; font-size: var(--i-t-sm) !important; color: var(--i-ink-2) !important; line-height: 1.55; }
.lndWsCodes { display: flex; flex-wrap: wrap; gap: 5px; margin-top: auto; padding-top: 4px; }
.lndCode {
  font-family: var(--oo-font-data);
  font-size: 10.5px;
  letter-spacing: 0.05em;
  color: var(--i-ink-3);
  border: 1px solid var(--i-hair-strong);
  border-radius: var(--i-r-chip);
  background: var(--i-field-bg);
  padding: 3px 7px;
}

/* --- sources ------------------------------------------------------------- */

.lndSrcGrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(232px, 100%), 1fr));
  gap: 12px;
}

.lndSrc {
  display: block;
  padding: 16px 17px;
  border: 1px solid var(--i-hair);
  border-radius: var(--i-r-card);
  background: var(--i-surface-1);
  min-width: 0;
  transition: border-color var(--i-dur-fast) var(--i-ease-out),
              background var(--i-dur-fast) var(--i-ease-out),
              box-shadow var(--i-dur-fast) var(--i-ease-out),
              transform var(--i-dur-fast) var(--i-ease-out);
}
/* A source card is a smaller object than a workspace card, so it lifts less.
   Elevation that ignores the size of the thing being lifted is what makes a
   page feel assembled from other people's components. */
.lndSrc:hover {
  border-color: var(--i-hair-strong);
  background: var(--i-surface-2);
  transform: translateY(-1px);
  box-shadow: var(--i-elev-1);
}
.lndSrcTop { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 5px; }
.lndSrcName { color: var(--i-ink-1); font-weight: 600; font-size: var(--i-t-sm); text-decoration: none; }
.lndSrcName:hover { color: var(--i-orchid-bright); text-decoration: underline; text-underline-offset: 2px; }
.lndSrcWhat { margin: 0 !important; font-size: 11.5px !important; color: var(--i-ink-3) !important; line-height: 1.5; }

.lndKeyless {
  font-family: var(--oo-font-data);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--i-bull);
  border: 1px solid color-mix(in srgb, var(--i-bull) 34%, transparent);
  background: var(--i-bull-wash);
  border-radius: var(--i-r-pill);
  padding: 2px 7px;
  white-space: nowrap;
}

/* --- honest limits ------------------------------------------------------- */

.lndLimits {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(290px, 100%), 1fr));
  gap: 14px;
}
.lndLimit {
  padding: 20px;
  border: 1px solid var(--i-hair);
  border-left: 2px solid var(--i-amber);
  border-radius: var(--i-r-card);
  background: var(--i-surface-1);
  min-width: 0;
}
.lndLimitHead {
  margin: 0 0 7px;
  font-size: var(--i-t-body) !important;
  font-weight: 600;
  color: var(--i-ink-1);
  line-height: 1.35;
}
.lndLimitBody { margin: 0 !important; font-size: var(--i-t-sm) !important; color: var(--i-ink-2) !important; line-height: 1.55; }

/* ==========================================================================
   6 — CLOSING BAND
   The previous version put a radial orchid wash behind this band. It is a dot
   grid now, for the same reason the hero is: a coloured glow is decoration that
   every generated page already has, and the grid is the product's own
   vocabulary.
   ========================================================================== */

.lndClose {
  border: 1px solid var(--i-hair);
  border-radius: var(--i-r-panel);
  background: var(--i-surface-1);
  box-shadow: var(--i-elev-2);
  padding: 64px 32px 68px;
  text-align: center;
  margin-bottom: 96px;
}
.lndCloseMark { display: flex; justify-content: center; margin-bottom: 18px; }
.lndCloseHead {
  margin: 0 0 12px;
  font-size: clamp(22px, 3vw, 30px) !important;
  letter-spacing: -0.024em;
  color: var(--i-ink-1);
}
.lndCloseBody {
  margin: 0 auto 26px !important;
  max-width: 58ch;
  font-size: var(--i-t-md) !important;
  color: var(--i-ink-2) !important;
  line-height: 1.6;
}
.lndClose .lndActions { justify-content: center; }

/* ==========================================================================
   7 — MOTION
   Nothing exceeds 300ms and nothing animates on load. Both switches are
   honoured: the OS preference and the in-app `data-motion` setting.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .lndBtn, .lndBoardRow, .lndWsCard, .lndSrc, .lndFigCell, .lndRefresh { transition: none; }
  /* The drift stops; the wash stays. Removing the gradient too would change the
     page's colour for a reader who asked for less motion, which is not what
     they asked for. */
  .lndHero::before { animation: none; }
  .lndWsCard:hover, .lndSrc:hover { transform: none; }
}
:root[data-motion="reduced"] .lndBtn,
:root[data-motion="reduced"] .lndBoardRow,
:root[data-motion="reduced"] .lndWsCard,
:root[data-motion="reduced"] .lndSrc,
:root[data-motion="reduced"] .lndFigCell,
:root[data-motion="reduced"] .lndRefresh { transition: none; }
:root[data-motion="reduced"] .lndHero::before { animation: none; }
:root[data-motion="reduced"] .lndWsCard:hover,
:root[data-motion="reduced"] .lndSrc:hover { transform: none; }

/* ==========================================================================
   8 — RESPONSIVE
   The small-screen LAYOUT MODEL lives in static/mobile.css — bottom nav, safe
   areas, stacking, tables, pull-to-refresh. What remains here is only what is
   specific to this page at that size.
   ========================================================================== */

@media (max-width: 980px) {
  .lndHero { grid-template-columns: minmax(0, 1fr); gap: 40px; padding: 56px 0 64px; }
  .lndFigs { margin-bottom: 64px; }
  .lndSection { padding-bottom: 64px; }
  .lndClose { padding: 48px 24px 48px; margin-bottom: 64px; }
}

@media (max-width: 767px) {
  .lndHero { padding: 32px 0 48px; }
  /* At this width the wash is wider than the column it lights and reads as a
     smudge at the top of the page rather than as depth. */
  .lndHero::before { width: 150%; top: -8%; }
  .lndBoardRow { grid-template-columns: minmax(0, 68px) minmax(0, 1fr) minmax(0, 92px); }
  /* The sparkline is the first thing to go: at 320px it is 40px wide and says
     nothing that the signed change beside it does not say better. */
  .lndBoardSpark { display: none; }
  .lndFigs { grid-template-columns: minmax(0, 1fr); margin-bottom: 44px; }
  .lndFigCell { padding: 20px 18px; }
  .lndFig { font-size: 29px; min-height: 29px; }
  .lndActions { gap: 9px; }
  .lndBtn { width: 100%; }
  .lndSection { padding-bottom: 48px; }
}

/* ==========================================================================
   9 — THE FUNCTION WALL AND THE SCREEN MINIATURES  (landing remodel round 2)

   aesthetics/LANDING_PAGE.md: "Function Set (70 Codes)" and "Screen
   Miniatures (4 Cards)". Both are designed WITH the purge, not against it:
   edges are `outline` (which the purge does not touch) rather than border,
   pills keep their fill through the nested-purge's [class*="Pill"] exclusion,
   and everything drawn inside the miniatures is SVG fill, which is not a
   background. Radius on the pills comes from skin.css 3b via [data-chip].
   ========================================================================== */

.lndFnWall {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 8px;
}

.lndFnPill {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 9px 12px;
  min-width: 0;
  background: var(--i-surface-1);
  outline: 1px solid var(--i-hair);
  outline-offset: -1px;
  color: inherit;
  text-decoration: none;
  transition: background var(--i-dur-fast) var(--i-ease-out),
              outline-color var(--i-dur-fast) var(--i-ease-out);
}
.lndFnPill:hover { background: var(--i-surface-2, var(--i-surface-1)); outline-color: var(--i-accent, var(--mi-gold, #E1AD66)); }

.lndFnCode {
  font-family: var(--oo-font-data);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--i-accent, var(--mi-gold, #E1AD66));
}

.lndFnName {
  /* display:block is LOAD-BEARING: a span is inline by default, and an
     inline box ignores overflow/text-overflow entirely — measured on the
     first tall render, every long screen name escaped its pill and ran into
     the neighbouring column. */
  display: block;
  font-size: 11px;
  color: var(--i-ink-3);
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.lndFnPill { overflow: hidden; }

/* --- miniatures ----------------------------------------------------------- */

.lndMiniGridOuter {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: 14px;
}

.lndMini {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 18px;
  min-width: 0;
  outline: 1px solid var(--i-hair);
  outline-offset: -1px;
  color: inherit;
  text-decoration: none;
  transition: outline-color var(--i-dur-fast) var(--i-ease-out);
}
.lndMini:hover { outline-color: var(--i-accent, var(--mi-gold, #E1AD66)); }

.lndMiniHead { display: flex; align-items: baseline; gap: 10px; }
.lndMiniTitle { font-size: var(--i-t-sm); color: var(--i-ink-2); }

.lndMiniSvg { width: 100%; height: 120px; display: block; }

.lndMiniNote { font-size: 11px; color: var(--i-ink-3); line-height: 1.4; }

.lndMiniFoot {
  margin: 18px 0 0;
  max-width: 72ch;
  font-size: 12px;
  color: var(--i-ink-3);
  line-height: 1.5;
}

/* SVG paint. `fill`/`stroke` are not backgrounds or borders; the purge does
   not touch them, and the tokens resolve per theme. */
.lndCdlWick { stroke: var(--i-ink-3); stroke-width: 1; }
.lndCdlWick.up { stroke: var(--i-bull); }
.lndCdlWick.down { stroke: var(--i-bear); }
.lndCdlBody.up { fill: var(--i-bull); }
.lndCdlBody.down { fill: var(--i-bear); }

.lndMoCell { fill: var(--i-surface-1); }
.lndMoCell.up { fill: var(--i-bull); fill-opacity: 0.34; }
.lndMoCell.down { fill: var(--i-bear); fill-opacity: 0.34; }
.lndMoText {
  fill: var(--i-ink-2);
  font-family: var(--oo-font-data);
  font-size: 12px;
}

.lndMiniLine {
  stroke: var(--i-accent, var(--mi-gold, #E1AD66));
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

.lndVolBar.up { fill: var(--i-bull); fill-opacity: 0.75; }
.lndVolBar.down { fill: var(--i-bear); fill-opacity: 0.75; }

/* The wall and the minis under reduced motion: no transitions to suppress
   beyond the shared rule above; both render complete with no frames. */

/* ==========================================================================
   10 — THE INTERACTIVE FIELD  (frontend/hero_field.js)

   The canvas sits at the very bottom of the hero's stack: behind the ring
   layer, the copy and the live board. It is decoration and nothing else —
   pointer-events off so it never steals a click from the board's links,
   aria-hidden so a screen reader is not told about a canvas with no data.

   THE PURGE CANNOT REACH IT, and that is worth stating rather than
   discovering. skin.css nulls background-image on `#page-root [class][class]`;
   a canvas paints through its 2D context, not through a background, so the
   artwork survives a rule that has silently erased two design systems in
   this build. The size properties below are the only thing CSS contributes.
   ========================================================================== */

#page-root .lndField[class][class] {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
  /* Screen blend so the ember glow ADDS to the ground rather than sitting
     on it as a grey film. Light mode gets multiply for the same reason in
     reverse — an additive glow on a cream page is invisible. */
  mix-blend-mode: screen;
  opacity: 0.92;
}

/* MEASURED on the first light-mode render:  turned every ember
   glow into a grey smudge — a radial gold-to-transparent gradient multiplied
   onto cream darkens toward neutral, which is the opposite of a glow. The
   strokes are gold and the ground is cream, so NORMAL blend is already the
   right arithmetic; only the weight needs taking down. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) #page-root .lndField[class][class] {
    mix-blend-mode: normal;
    opacity: 0.4;
  }
}
:root[data-theme="light"] #page-root .lndField[class][class] {
  mix-blend-mode: normal;
  opacity: 0.4;
}

/* The ring layer and the copy both need to sit above the canvas. .lndHeroCopy
   already declares z-index 1; the atmosphere never did, because until now
   nothing was under it. */
#page-root .lndAtmos[class][class] { z-index: 1; }
#page-root .lndBoard[class][class] { position: relative; z-index: 2; }

/* A reader who asked for stillness gets the painted composition and no loop
   (hero_field.js checks the same query before starting). Nothing to disable
   here — this is the record that the case was considered. */

/* ==========================================================================
   11 — THE BOARD HOLDS ITS GROUND AGAINST THE FIELD

   Measured on the first field render: the live watchlist — the one element
   on this page that carries REAL FIGURES — was reading through three layers
   of ring, ember and candle tape at once. That inverts the whole argument of
   the page. Atmosphere is atmosphere; the data is the point.

   TWO MECHANISMS, BECAUSE ONE IS NOT ENOUGH AGAINST THE PURGE.
   skin.css nulls `background-color` on nested classed elements at
   `#page-root [class][class] [class][class]` = (1,4,0) !important, and it
   loads AFTER this sheet, so a tie loses. The fill below is restated at
   (1,5,0) !important to win outright. `backdrop-filter` needs none of that —
   it is not a property the purge touches — so it does the work even if a
   future rule outruns the specificity ladder again.
   ========================================================================== */

/* MEASURED, AFTER THE (1,5,0) VERSION OF THIS RULE LOST: the board's
   computed background-color was still `rgba(0, 0, 0, 0)`.

   The purge's nested-fill rule is not (1,4,0). It carries FOURTEEN `:not()`
   clauses (mark/Mark/dot/Dot/badge/Badge/pill/Pill/hit/Hit/highlight/
   Highlight/match/Match), and each `:not()` ADDS its argument's specificity —
   so it lands near (1,18,0) !important. No honest selector wins that, and
   writing eighteen `[class]`es to try is how a stylesheet becomes unreadable.

   So the scrim uses a property the purge does not name at all.
   `backdrop-filter: brightness()` darkens what is BEHIND the element without
   the element having a background at all, which is exactly the requirement:
   the live figures stop competing with the ember field, and no fill can be
   stripped because there is no fill. */
#page-root .lndBoard[class][class] {
  backdrop-filter: blur(10px) brightness(0.34) saturate(0.85);
  padding: 20px 22px;
  outline: 1px solid color-mix(in srgb, var(--i-accent, #e1ad66) 26%, transparent);
  outline-offset: -1px;
}

/* Light mode inverts the requirement: the ground is cream and the field
   multiplies onto it at half opacity, so the board needs LIFTING off the
   backdrop rather than darkening. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) #page-root .lndBoard[class][class] {
    backdrop-filter: blur(12px) brightness(1.05) saturate(0.92);
  }
}
:root[data-theme="light"] #page-root .lndBoard[class][class] {
  backdrop-filter: blur(12px) brightness(1.05) saturate(0.92);
}

/* The copy column gets a softer version of the same treatment — a wash that
   fades out to the right rather than a panel, so the headline still sits ON
   the field rather than in a box on top of it. */
#page-root .lndHeroCopy[class]::before {
  content: "";
  position: absolute;
  inset: -34px -80px -34px -60px;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(ellipse 76% 62% at 26% 46%,
      color-mix(in srgb, var(--i-void) 88%, transparent) 0%,
      color-mix(in srgb, var(--i-void) 62%, transparent) 46%,
      transparent 78%);
}

/* CTA buttons stopped reading as buttons once the purge took their borders.
   `outline` is the fix that survives it — same reason the function wall and
   the miniatures use outline for their edges. */
#page-root .lndBtn[class][class] {
  outline: 1px solid color-mix(in srgb, var(--i-accent, #e1ad66) 40%, transparent);
  outline-offset: -1px;
  padding: 10px 18px;
}

#page-root .lndBtn[class][class].primary {
  outline-color: var(--i-accent, #e1ad66);
  background-color: color-mix(in srgb, var(--i-accent, #e1ad66) 15%, transparent) !important;
}

#page-root .lndBtn[class][class]:hover {
  outline-color: var(--i-accent, #e1ad66);
}

/* ==========================================================================
   THE WORKSPACE LIST (9d) — five lines where five cards used to be.
   ========================================================================== */

#page-root .lndWsList {
  list-style: none;
  margin: 0 0 34px;
  padding: 0;
  display: grid;
  gap: 1px;
}

#page-root .lndWsLine {
  display: grid;
  grid-template-columns: minmax(120px, 0.9fr) 44px minmax(0, 3fr);
  gap: 14px;
  align-items: baseline;
  padding: 11px 0;
  border-bottom: 1px solid color-mix(in srgb, var(--i-ink-3, #8d8781) 18%, transparent);
}

#page-root .lndWsList .lndWsName[class] {
  font-family: var(--mi-display, Georgia, serif);
  font-size: var(--i-t-md);
  color: var(--i-ink-1) !important;
  text-decoration: none !important;
}
#page-root .lndWsList .lndWsName[class]:hover { color: var(--i-accent, #e1ad66) !important; }

#page-root .lndWsList .lndWsCount[class] {
  font-family: var(--mi-fig, ui-monospace, monospace);
  font-size: var(--i-t-sm);
  color: var(--i-ink-3) !important;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

#page-root .lndWsList .lndWsWhat[class] {
  font-size: var(--i-t-sm);
  line-height: 1.5;
  color: var(--i-ink-2) !important;
}

@media (max-width: 767px) {
  #page-root .lndWsLine { grid-template-columns: minmax(0, 1fr) 40px; }
  #page-root .lndWsList .lndWsWhat[class] { grid-column: 1 / -1; }
  #page-root .lndPlanGrid { grid-template-columns: minmax(0, 1fr); }
  #page-root .lndPlanPrice { font-size: 26px; }
}

/* ==========================================================================
   TECHNOLOGY, SECURITY AND FAQ (answers 295c, 296c, 285b)
   Rows rather than cards: these are lists of statements, and a grid of boxes
   would make six sentences look like six products.
   ========================================================================== */
.lndTech { display: flex; flex-direction: column; margin: 0 0 24px; }

.lndTechRow {
  display: grid;
  grid-template-columns: minmax(150px, 210px) minmax(0, 1fr);
  gap: 20px;
  padding: 16px 0;
  border-bottom: 1px solid var(--i-hair);
  align-items: baseline;
}
.lndTechRow:last-child { border-bottom: 0; }

.lndTechName {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--i-ink-1);
}
.lndTechWhat { font-size: 14px; line-height: 1.6; color: var(--i-ink-2); }

.lndSecLinks { display: flex; flex-wrap: wrap; gap: 20px; }

.lndFaq { display: flex; flex-direction: column; margin: 0 0 20px; }
.lndFaqRow { padding: 18px 0; border-bottom: 1px solid var(--i-hair); }
.lndFaqRow:last-child { border-bottom: 0; }
.lndFaqQ { margin: 0 0 6px; font-size: 15px; font-weight: 600; color: var(--i-ink-1); }
.lndFaqA { margin: 0; font-size: 14px; line-height: 1.62; color: var(--i-ink-2); max-width: 78ch; }

.lndSectionNote { margin: 0; font-size: 13px; color: var(--i-ink-3); }

@media (max-width: 720px) {
  .lndTechRow { grid-template-columns: minmax(0, 1fr); gap: 5px; }
}
