/* ground.css — the box the blobby field lives in, on every page.

   Lifted verbatim out of index.html on 2026-09-04, same ruling and same reason
   as ground.js: these rules were settled against Phil's eye over an evening and
   a second page is not a licence to re-derive them. Pairs with ground.js.

   ONE thing is new here, and it is the reason the file exists at all: index's
   .hero already carried position:relative (it needed it for the plate's
   perspective). No other page does, and .heroground is absolutely positioned —
   without a positioned ancestor the field escapes its block and lays itself
   over the whole document. So the containment is declared here, for both names
   a page uses for its top block. */

/* THE CONTAINING BLOCK. .hero on the service and utility pages, .pagehead on
   the case studies and work, .guidehero on the guide — three names already in
   the markup for one thing, adopted rather than renamed across twenty pages.
   index.html declares this itself as well; the
   duplicate is harmless and left alone rather than pulled out of a page that is
   already proved. */
.hero, .pagehead, .guidehero{position:relative}

/* THE FIELD BELONGS TO THE HERO'S CONTENT, NOT ITS PADDING. It used to hang
   26px PAST the hero, which was fine when the next section was flat paper.
   Once the offer became a band, that left the lowest row nearly touching the
   chapter edge — Phil: "the header background grid seems a bit close to the
   highlighted next section." Not-overlapping is not the same as clear.
   So the field now ends where the hero's copy ends, and the hero's own
   bottom padding (--s-5 + 32) is the air before the next chapter. 104px of
   clearance, 78px of it still there at full lean (the ground's tilt shift
   is 26px). The lattice is an SVG on preserveAspectRatio meet, so a shorter
   box scales the whole creature down rather than cropping a row off it. */
/* THE BLEED IS BOUNDED BY THE ROOM THERE IS FOR IT.

   It was a flat -12vw, and that is a number rather than a bound. Measured on
   the SHIPPED homepage, before any of today's work: the field runs off the left
   of the page and you can push the whole site sideways — 66px at 1100, 80px at
   900, 64px at 768. Not theoretical; `scrollLeft` takes, and a hunt for what is
   out there returns .heroground and nothing else. index.html carries
   `body{overflow-x:clip}` and it does NOT contain this. Only three of the
   twenty-one pages carry that rule anyway, so leaning on it was never going to
   hold site-wide.

   Derive it instead. The shell is 1024px wide with 28px of padding, so the
   hero's left edge sits at (100vw - 1024px)/2 + 28px, and that is exactly how
   much room the field has to bleed into before it leaves the page. Below
   1024px the shell stops shrinking away from the edge and the room is just the
   padding. So:

       bleed = min(12vw, max(28px, (100vw - 1024px)/2 + 28px))

   which is 172.8px at 1440 (the full -12vw, unchanged, 63px of margin left),
   66px at 1100, and 28px at 900 — the field reaching the viewport edge at every
   width and never passing it. The design intent is untouched wherever there was
   ever room for it; what goes away is the part that was hanging off the page.

   Caveat worth writing down rather than hiding: 100vw includes the scrollbar on
   platforms that reserve one, so this can overshoot by half a scrollbar there.
   Measured clean on overlay scrollbars at 1440/1100/900/768. */
.heroground{--bleed:min(12vw, max(28px, calc((100vw - 1024px)/2 + 28px)));
     position:absolute;top:0;
     right:calc(-1 * var(--bleed));left:calc(-1 * var(--bleed));
     bottom:calc(var(--s-5) + 32px);
     z-index:0;pointer-events:none;
     transform-style:preserve-3d;will-change:transform;
     transition:transform .7s cubic-bezier(.22,.61,.36,1)}
.heroground.tracking{transition:none}
.heroground svg{width:100%;height:100%;display:block}
.heroground rect{transition:opacity .42s linear}

@media (prefers-reduced-motion: reduce){
     .heroground{transform:none !important;transition:none}
     .heroground rect{transition:none}}

/* THE COPY SITS ABOVE THE GROUND. index gets this from its own .herogrid rule;
   the case studies and the pages without a grid need it stated. Anything that
   is not the field itself comes forward one layer. */
.hero > *:not(.heroground), .pagehead > *:not(.heroground),
.guidehero > *:not(.heroground){position:relative;z-index:1}

/* ONE GROUND PER BOX — PROPOSED, THEN OVERRULED, AND THE REASONING IS KEPT.

   I stood the field down on phones wherever a page names a world, because below
   720px the world becomes a full-bleed layer behind the copy (world.css, Phil
   2026-09-03: "it can even go under the text, right?") — so the world is already
   the ground there, and the field on top of it puts two grids of blocks at
   different scales in one 390px box. Caught on services.html with the fountain
   wearing a second grid.

   Phil, 2026-09-04, looking at it: "in phone mode, you're not showing the moving
   background blocks?" His call, and it is the right one to make by eye — the
   collision I measured is a coin toss decided by the random walk, and he has
   seen both faces of it. The field stays on every page at every width.

   Left written down rather than deleted, because the collision is real when the
   walk lands on the drawing, and whoever revisits this should know it was seen
   and ruled on, not missed. */
@media(max-width:720px){
  /* AND ON A PHONE THE FIELD STOPS AT THE SHELL, bleed formula or not. The
     formula above bottoms out at 28px, which is the desktop shell padding; the
     phone's is 20px, so it would hang 8px off each edge for no gain. There is
     no room at 390 for a bleed to register as anything but a crop. */
  .heroground{left:0;right:0}
}

/* THE 404, WHICH HAS NO HERO TO SIT IN.

   Every other page bounds the field with a top block: the field ends where the
   copy ends and the block's own bottom padding is the air before the next
   chapter. 404.html has no nav, no shell and no hero — just a centred 560px
   column in the middle of an empty viewport — so there is no band to bound, and
   the honest geometry is the viewport itself.

   Phil ruled the background onto every page; this is the one page where "every
   page" needed a decision rather than a copy-paste, so it is called out rather
   than buried. The argument for it being here at all is in the page's own copy:
   "The rest of the site is holding." A page that is missing, on ground that
   plainly is not, says that better than the sentence does alone. */
body.groundpage{position:relative;min-height:100vh}
body.groundpage > .heroground{top:0;left:0;right:0;bottom:0}
/* AND THE COPY COMES FORWARD. Caught by looking, not by the gate: 404's <main>
   is a static flex item, and a static sibling paints UNDER a positioned one, so
   the field went straight over the headline. The other three containers get this
   from the rule above; body.groundpage needs it stated because its child is
   <main> and not a .herogrid. */
body.groundpage > *:not(.heroground){position:relative;z-index:1}
@media(max-width:720px){ body.groundpage > .heroground{left:0;right:0} }
