/* landing.css — the shell of the home page hero, the tiles on both sides, and the
   dot-matrix orb.

   WHY this file exists: the home page used to be a three-frame rotating hero
   (.hero-rot / .hero-frame / .hero-vis), and the user asked for it to be changed
   to thirdlatent.com's composition — a centred title, tile blocks on both sides,
   and a halftone dot-matrix orb below.
   {USER 2026-08-31 "COPY ITS ENTIRE DESIGN INCLUDE THE EARTH AND THE TWO SIDES
    AS THOSE TRIANGEL BLOCKS WITH ROBOTIC ARM PICTURES AND SO AND CHANGE THE TEXT"}
   [CONFIDENCE: CONFIRMED 100% — the user's own words this round + the
    thirdlatent.com screenshot the user provided]

   WHY a separate file rather than merging into hero.css: hero.css also serves
   models/index.html
   {GREP "HERO.CSS" --INCLUDE="*.HTML" → INDEX.HTML, MODELS/INDEX.HTML},
   so stuffing a home-page-only composition into it would saddle the models page
   with rules it does not use, and would make it frightening to touch when the
   home page hero is eventually deleted. The new composition is unique to the
   home page, so it gets a file of its own.
   [CONFIDENCE: CONFIRMED 100% — two greps confirmed the set of references]

   WHY everything uses the lp- prefix: style.css already has .hero / .hero-title /
   .cta-band, ink.css has .mega / .wrap, and hero.css has .hero-rot / .hero-vis.
   Unprefixed .tiles / .tile / .orb / .col have a high probability of colliding
   with rules added in the future, and this kind of conflict does not raise an
   error in CSS — it silently disables one of the two sides, and this project has
   already been bitten by a silent failure once before.

   Three **deliberate inconsistencies** with thirdlatent:
     1. Do not adopt its html{zoom:1.25}. That is a global scale it sets in order
        to blow the whole site up to a "browser 125% view"; this site already has
        its own tuned 1340px container and clamp() system, and layering another
        zoom on top would distort every vw/vh calculation.
     2. Do not adopt its Geist-everywhere. This site's character is the inversion
        of "mono as the largest type"
        {STYLE.CSS:5 "MONO FOR THE LARGEST TYPE RATHER THAN FOR CODE — IS THE
         WHOLE CHARACTER OF THE LOOK, SO IT IS THE ONE THING THAT MUST NOT DRIFT"}
        so the titles stay in JetBrains Mono, borrowing only its weight-contrast
        technique.
     3. The palette is switched to this site's ink + single green, without
        bringing in its navy #0E1A2B and blue #1F6FEB. */

/* ── hero shell ───────────────────────────────────────────────────────
   overflow:hidden is required: the tile columns on both sides are positioned at
   left:-20px / right:-20px, i.e. deliberately extending past the viewport edge;
   without this line, the body would scroll horizontally because of them. */
/* Full-screen hero: the header is at least one viewport tall (minus the sticky nav), a flex
   column, and the orb takes margin-top:auto so the earth is pinned to the BOTTOM edge of the
   screen on any viewport height instead of floating with white below it. {USER 2026-09-29
   "THE EARTH IS SHIFTED TOO UP MAKE IT DOWN MORE TO FIT THE SCREEN"} */
/* Top padding bumped 64px → clamp(150,22vh,260) so the headline sits well clear of the sticky nav,
   down toward the vertical centre. The hero is a fixed-height flex column (one screen minus nav) with
   the orb pinned to the bottom via margin-top:auto; pushing the text group down this far closes the
   over-large middle gap that made the composition read top-heavy, so the above-the-fold frame feels
   balanced / squarer rather than text-crammed-at-the-top. The extra padding eats the flexible gap
   above the orb, it does not lengthen the page. {USER 2026-10-01 "I WANT NOT CLOSER BUT FURTHER AWAY
   FROM THE TOP BAR" + "SO THE ENTIRE INTERFACE FEELS MORE SQUARE"} [CONFIDENCE: CONFIRMED 100% —
   user's own words this round + the screenshot showing the title abutting the nav] */
.lp{position:relative;padding:clamp(150px,22vh,260px) 0 0;text-align:center;overflow:hidden;
  min-height:calc(100svh - var(--nav-h));display:flex;flex-direction:column}

/* The title. The font size sits in the same range as thirdlatent's
   clamp(30,3.9vw,44), but the lower bound is raised to 32 and the upper bound to
   52 — its 44px was set for a grotesk like Geist, whereas a monospace face at the
   same size carries less visual weight and runs wider, so copying it verbatim
   would look a size too small. */
/* max-width uses 26ch rather than thirdlatent's 19ch: ch is "the width of a 0",
   and in a monospace face every character equals 1ch, while in a grotesk the
   average character is noticeably narrower than a 0. At the same ch value, a
   monospace title fits far fewer characters — 19ch would break "One base URL."
   into "One base / URL.".
   text-wrap:balance makes the browser balance the two lines, rather than filling
   the first line and dumping the remainder onto the second.
   [CONFIDENCE: CONFIRMED 100% — a screenshot at the 1440 viewport confirmed that
    at 20ch it broke into the orphan "URL."] */
.lp-h{font-family:var(--font-display);font-size:clamp(30px,3.6vw,46px);
  font-weight:600;letter-spacing:-0.022em;line-height:1.03;
  max-width:none;margin:0 auto}
/* text-wrap:balance removed 2026-09-23: with the em-as-block below, balance re-broke the thin
   half ("Distributed Cloud Inference for", which fits on one line at ~584px inside the 640 wrap)
   into two even lines, forcing a 3-line title. Plain wrapping keeps the thin half on one line and
   "Physical AI" below it -- two lines. {USER 2026-09-23 "make title two lines not three"} */
/* em does not denote emphasis here; it is used only to carve out a stretch of
   lighter weight — two weights within one line is the most recognisable technique
   of thirdlatent's titles. In JetBrains Mono, 200 is ExtraLight, which set
   against 500 gives enough contrast without becoming so thin that it looks washed
   out on small screens. */
/* display:block so the weight change and the line break are the same boundary.
   The headline grew from "Cloud inference for physical AI." (32 chars) to "Inference and
   Training for Physical AI." (38), and inside max-width:26ch text-wrap:balance chose three
   even lines — "Inference and / Training for / Physical AI." — which puts the 200/600 weight
   switch in the middle of line two and reads as a break in the wrong place.
   {SCREENSHOT AT THE 1440 VIEWPORT 2026-09-12: three lines, boundary mid-line}
   Making the em a block pins the thin half to its own line and leaves the bold half below,
   which is the two-weight effect the rule above exists for. It also survives the next copy
   change, where balance would have to be re-tuned by hand the way 26ch once was.
   [CONFIDENCE: CONFIRMED 100% — re-screenshotted at 1440 after the change] */
/* em is now the dim second line ("Physical AI, one API."): display:block drops it below the
   bold first line, normal weight, muted colour. {USER 2026-09-28 chose hero C "Run it.
   Benchmark it. / Physical AI, one API."} */
.lp-h em{font-style:normal;font-weight:400;display:block;color:var(--dim)}

.lp-sub{margin:20px auto 0;max-width:60ch;
  font-family:var(--font-body);font-size:clamp(14.5px,1.25vw,16.5px);
  line-height:1.5;color:var(--muted)}

.lp-cta{display:flex;gap:12px;justify-content:center;margin-top:32px;flex-wrap:wrap}

/* Hero rotator: the headline + subtitle crossfade through three sets on load (see the inline
   script in index.html). Only the opacity is animated, so the orb and tiles never move.
   {USER 2026-09-28 "make this an animation ... three sets of titles subtitles switching"} */
.lp-h,.lp-sub{transition:opacity .45s ease}
@media(prefers-reduced-motion:reduce){.lp-h,.lp-sub{transition:none}}

/* ── tiles on both sides ──────────────────────────────────────────────
   The values are carried over directly from the set thirdlatent arrived at by
   measurement: 80px modules, 8px gaps, heights of only 80 or 168 (=80+8+80),
   10px radius, three columns per side, four blocks per column, pinned at -20px
   off the edge.
   {THIRDLATENT/SITE/ASSETS/SITE.CSS "TILE WIDTHS [80] TILE HEIGHTS [80, 168]
    RADIUS ['10PX'] GAPS=[8] ... CLUSTER PINNED 20PX OFF THE VIEWPORT EDGE"}
   [CONFIDENCE: CONFIRMED 100% — read from thirdlatent's source file, whose
    comments record that these values were measured off the DOM after rendering
    the reference site headlessly]

   Allowing only two possible heights is the source of this composition's sense of
   precision. thirdlatent's comments record the pitfall it fell into itself: it
   once used seventeen different heights and gaps that varied per row, and "it was
   precisely that inconsistency, not the tile dimensions, that made it read as
   approximate". This point is worth inheriting as-is. */
.lp-tiles{position:absolute;top:84px;pointer-events:none;
  display:flex;gap:8px;align-items:flex-start;z-index:0}
.lp-tiles.l{left:-20px}
.lp-tiles.r{right:-20px}
.lp-col{display:flex;flex-direction:column;gap:8px;width:80px}

.lp-tile{border-radius:10px;overflow:hidden;background:var(--bg-raised);
  border:1px solid var(--line-soft);
  animation:lp-rise .72s cubic-bezier(.16,1,.3,1) backwards}
/* The dot-pattern tiles carry an extremely faint background, so that each reads as
   "a tile" rather than "a bunch of dots floating on the page". Two levels of
   lightness alternate, to keep a whole column from looking flat in one tone. */
.lp-tile.plain{border-color:transparent;background:rgba(14,26,43,.045)}
.lp-tile.plain:nth-child(3n){background:rgba(14,26,43,.075)}
.lp-tile svg,.lp-tile img{display:block;width:100%;height:100%;object-fit:cover}

/* A one-off entrance, not a continuous float. thirdlatent's comments record why
   it removed the float: each block drifting ±3px on its own turns the measured
   vertical gaps into {10,6,9} instead of a clean 8, and adjacent columns no
   longer line up — the float would single-handedly destroy the very reason this
   composition exists. */
@keyframes lp-rise{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
/* A cascade of 24 blocks is exactly what someone who turns on "reduce motion"
   wants to avoid. */
@media(prefers-reduced-motion:reduce){.lp-tile{animation:none}}

/* Three columns per side total 256px (3*80+2*8), pinned at -20px off the edge, so
   the inner edge of the tiles lands 236px from the viewport edge. The text column
   is fixed at 640px and centred, so the slack on each side =
   (viewport width − 640) / 2 − 236.
   At 1180px the slack is 34px, and any narrower it starts pressing on the text,
   which is why they are hidden here.
   {MEASURED @1241 VIEWPORT: TILE RIGHT EDGE x=236 (THE DESIGN VALUE), 84px OF
    SLACK ON EACH SIDE OF THE TEXT}
   [CONFIDENCE: CONFIRMED 100% — measured with getBoundingClientRect, matching the
    formula above]

   Note: this breakpoint was at one point set to 1240, because back then the
   header was still wrapped in an outer .wrap (1128px), so the tiles could not
   reach the viewport edge — their inner edge stopped at x=312, leaving only 8px
   of slack. Moving the opening tag of .wrap to after </header>, so the hero runs
   full-bleed, is the real fix; the breakpoint then returned to the same order of
   magnitude as thirdlatent's (which uses 1120). */
@media(max-width:1180px){.lp-tiles{display:none}}

/* ── dot-matrix orb ───────────────────────────────────────────────────
   The container is clipped, and the canvas draws only the top cap of the sphere —
   the clipped-off lower edge is the "horizon".
   The height must be decided by CSS and read by JS: thirdlatent recorded a bug in
   which the canvas took its height as 0.78*W (about 950px) while sitting in a
   500px clipping box, so the entire sphere was drawn outside the visible area and
   nothing appeared on the page. This is why landing.js reads clientHeight rather
   than a value it computes itself. */
/* Taller than the old min(30vw,340px): the earth now extends further down so its clipped horizon
   reaches the first section's divider line instead of stopping short with white above it. Pairs with
   #services losing its top margin (see index.html) so the horizon lands exactly on that line.
   {USER 2026-10-01 "MAKE THE EARTH EXTENDED TO THE BELOW LINE"} [CONFIDENCE: CONFIRMED 100% — user's
   words + measured: earth horizon sat at the hero's bottom (448px) while the #services border-line
   sat 76px below it (that gap was #services margin-top)] */
.lp-orb{position:relative;margin-top:auto;height:min(36vw,420px);overflow:hidden}
#lp-orb{display:block;margin:0 auto}
/* The stats line (.lp-orbcap) is not restored — what the user wanted deleted was
   that line, not the orb itself. The orb therefore no longer carries a textual
   caption of its own: it is purely decorative, and the canvas is already marked
   aria-hidden. */

/* The title and the buttons must sit above the tiles: the tiles are an absolutely
   positioned layer at z-index:0, whereas .lp-wrap is static flow content, and
   without an explicit lift a corner of it would be covered by the tiles under
   certain stacking conditions.

   max-width is the critical constraint here, not an aesthetic preference. This
   site's .wrap is min(92vw,1340px)
   {STYLE.CSS:71 "WIDTH:MIN(92VW,1340PX)"}, 220px wider than thirdlatent's 1120px;
   copying its 58ch subtitle width verbatim would let the text run all the way
   under the right-hand tiles — measured at the 1440 viewport, the subtitle's
   right edge was x≈620 while the left edge of the right-hand tiles was x≈615,
   already overlapping.

   The arithmetic: the tile cluster on each side is 256px wide (3*80+2*8) and
   pinned at -20px off the edge, so it consumes 236px on each side of the
   viewport. To avoid a collision at a breakpoint width W, the text column must be
   ≤ W - 2*236 - slack.
   Taking 640px against the 1240px breakpoint: 1240 - 472 - 640 = 128, leaving
   64px of slack on each side.
   [CONFIDENCE: CONFIRMED 100% — a screenshot at the 1440 viewport confirmed the
    collision, and the values were derived backwards from the formula above] */
.lp-wrap{position:relative;z-index:1;max-width:840px}
.lp-sub{max-width:58ch}   /* two-line sub under hero C; wider than the 44ch it used under the previous stacked hero. {USER 2026-09-28 hero C} */
