/* EOTAK, product pages. Page-specific art only: everything structural
   (tokens, nav, buttons, reveal) is core.css, and the section grammar
   (.fb / .state / .chain / .chapter / .dl / .apps / .glow) is style.css.

   The homepage's signature is the live contour field. A product page
   deliberately does not run it: the product photograph is the hero and the
   only atmosphere is one slow copper bloom behind it. */

/* =========================================================
   PRODUCT HERO
   Same pull-up under the sticky nav as the homepage hero, so
   the two pages start on the same beat.
   ========================================================= */
.p-hero{position:relative;width:100vw;max-width:100vw;margin-left:calc(50% - 50vw);
  margin-top:calc(-1 * var(--navh));
  padding-top:clamp(96px,10vh,132px);padding-bottom:clamp(28px,4vh,44px);
  background:linear-gradient(180deg,rgba(var(--ovr-rgb),.022) 0%,rgba(var(--ovr-rgb),0) 46%),var(--bg)}

/* the one atmospheric device on the page: a single copper bloom, one hue,
   ending on an explicit zero-alpha stop of that same hue. It drifts very
   slowly and stops dead under prefers-reduced-motion (core.css). */
.p-bloom{position:absolute;z-index:0;pointer-events:none;border-radius:50%;
  right:-6%;top:-14%;width:min(1180px,92vw);height:min(760px,78vh);
  filter:blur(70px);
  background:radial-gradient(closest-side,
    rgba(var(--cop-rgb),.30) 0%,
    rgba(var(--cop-rgb),.18) 34%,
    rgba(var(--cop-rgb),.07) 62%,
    rgba(var(--cop-rgb),.02) 82%,
    rgba(var(--cop-rgb),0) 100%);
  animation:p-drift 32s var(--e-out) infinite alternate}
:root[data-theme="light"] .p-bloom{filter:blur(80px);
  background:radial-gradient(closest-side,
    rgba(var(--cop-rgb),.17) 0%,
    rgba(var(--cop-rgb),.10) 36%,
    rgba(var(--cop-rgb),.04) 64%,
    rgba(var(--cop-rgb),.012) 84%,
    rgba(var(--cop-rgb),0) 100%)}
@keyframes p-drift{
  from{transform:translate3d(0,0,0) scale(1)}
  to{transform:translate3d(-3.5%,2.5%,0) scale(1.07)}
}
@media (prefers-reduced-motion:reduce){ .p-bloom{animation:none} }

.p-hero-in{position:relative;z-index:3;max-width:var(--wrap);margin:0 auto}
.p-hero-grid{display:grid;grid-template-columns:1.02fr .98fr;
  gap:clamp(28px,5vw,80px);align-items:center;padding:0 var(--sp7)}
.p-hero-copy{min-width:0}
/* MARS leads with a landscape screenshot rather than a phone or a cut-out, so its
   hero runs as one column with the frame full width beneath it. .p-hero-grid is what
   normally supplies the gutter inset; without a grid the copy would sit 48px left of
   every chapter below it, which measures as a misalignment even though it looks
   deliberate. This restores the same inset. */
.p-hero-solo{padding:0 var(--sp7)}
.p-hero-solo .lede{max-width:56ch}
.p-hero h1{margin-top:clamp(14px,2.2vh,22px);text-shadow:var(--hero-sh)}
.p-hero .lede{margin-top:clamp(16px,2.4vh,26px);max-width:42ch;text-shadow:var(--hero-sh)}

/* breadcrumb */
.crumb{font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--mute);display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  margin-bottom:clamp(20px,3vh,30px)}
.crumb a{color:var(--mute)}
.crumb a:hover{color:var(--accent-txt)}
.crumb span[aria-current]{color:var(--fg2)}

/* price block. This is a quoted, backordered product: the figure is real,
   the availability is a placeholder until someone confirms it, and it is
   marked as one rather than dressed up as fact. */
.p-buy{display:flex;align-items:flex-end;gap:clamp(18px,3vw,34px);flex-wrap:wrap;
  margin-top:clamp(24px,3.6vh,38px);padding-top:clamp(20px,3vh,28px);
  border-top:1px solid var(--line)}
.p-buy .price{font-size:clamp(34px,3.8vw,52px);letter-spacing:-.042em}
.p-flag{display:inline-block;font-size:10.5px;letter-spacing:.16em;
  color:var(--accent-txt);border:1px dashed rgba(var(--cop4-rgb),.55);
  border-radius:999px;padding:6px 12px;white-space:nowrap}
.p-note{font-size:10px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--mute);margin-top:clamp(16px,2.4vh,22px)}

/* the cut-out. Nothing in this chain clips, so the glow's falloff runs to
   its own zero-alpha edge. */
.p-fig{position:relative;display:flex;align-items:center;justify-content:center;
  overflow:visible;min-height:clamp(240px,44vh,470px);z-index:2}
.p-fig img{position:relative;z-index:2;width:auto;height:auto;max-width:100%;
  max-height:clamp(250px,50vh,520px);object-fit:contain;
  filter:drop-shadow(0 34px 66px rgba(var(--sh-rgb),.62))}
:root[data-theme="light"] .p-fig img{filter:drop-shadow(0 26px 50px rgba(var(--sh-rgb),.42))}
/* A hero holding two cut-outs: they sit side by side and each carries its own cap so
   the pair reads as one product. Caps are max-height, and no image here may take
   width/height attributes -- the CSS sizes them and a surviving height hint stretches. */
.p-fig:has(img + img){gap:clamp(14px,2vw,28px);flex-wrap:wrap}
/* Both caps come down so the pair sits side by side in the 584px figure column.
   Left at the single-image cap they totalled 611px, wrapped to a stack, and took the
   hero to 1,127px against ~500px on the two sibling product pages, which are clones of
   this one. [src$="vice-core.png"] is exact on purpose: [src*="vice-core"] also matches
   vice-core-2. */
.p-fig img[src$="vice-core.png"]{max-height:clamp(210px,42vh,430px)}
.p-fig img[src*="vice-core-2"]{max-height:clamp(165px,28vh,300px)}
.p-hero .hero-rail{margin-top:clamp(34px,5vh,60px)}

/* =========================================================
   WHAT IT DOES, hairline columns, no cards
   ========================================================= */
.p-does{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(24px,4vw,64px);margin-top:clamp(34px,5.5vh,66px)}
.p-does > div{border-top:1px solid var(--line);padding-top:clamp(18px,2.6vh,26px);
  background:radial-gradient(120% 60% at 50% 0%,rgba(var(--ovr-rgb),.035),rgba(var(--ovr-rgb),0) 68%)}
.p-does .t{font-size:clamp(18px,1.8vw,23px);font-weight:650;letter-spacing:-.024em}
.p-does p{margin-top:10px;color:var(--mute);font-size:15px;line-height:1.62;max-width:34ch}

/* =========================================================
   SOFTWARE PAGES, the hero figure is a phone screen, not a cut-out,
   so it takes a frame instead of a drop-shadowed silhouette, and the
   price block is replaced by store badges.
   ========================================================= */
/* beacon-home.webp is only 230x498; the shared cap would upscale it into mush,
   so this one is pinned to its own native height. Re-tune if the asset is replaced. */
.p-fig.screen img[src*="beacon"]{max-height:498px}
.p-fig.screen img{max-height:clamp(300px,58vh,560px);border-radius:18px;
  border:1px solid var(--line2);filter:none;
  box-shadow:0 30px 70px rgba(var(--sh-rgb),.6)}
.p-stores{display:flex;gap:14px;align-items:center;flex-wrap:wrap;
  margin-top:clamp(22px,3.4vh,34px)}
.p-stores a{display:inline-flex;border-radius:9px;
  transition:opacity var(--d-hover) var(--e-out)}
.p-stores a:hover{opacity:.82}
.p-stores img{height:46px;width:auto;display:block}
@media (max-width:520px){ .p-stores img{height:40px} }

/* =========================================================
   MARS, THE TOPOGRAPHIC GROUND
   A static contour texture laid over the page's black, not the homepage's
   WebGL field. `assets/img/topo-tile.png` is a 1024px seamless tile generated
   from periodic fbm noise (see CLAUDE.md); it is one 296KB image, costs no
   GPU, needs no fallback and cannot be mistaken for live data.

   The layer is fixed, so the contours sit still while the page moves over
   them. It is masked vertically: strongest behind the hero, almost gone
   through the middle where screenshots need clean ground, back again at the
   closer.
   ========================================================= */
.topo-bg{position:fixed;inset:0;z-index:0;pointer-events:none;
  background-image:url(../assets/img/topo-tile.png);
  background-repeat:repeat;background-size:660px 660px;
  opacity:.86;
  /* the layer is fixed, so this mask maps to the VIEWPORT, not the document: it is a
     standing vignette on every screenful, not a page-position fade. Keep it gentle or
     it reads as a band that never moves while everything else scrolls past it. */
  -webkit-mask-image:radial-gradient(130% 105% at 50% 42%,#000 0%,rgba(0,0,0,.82) 58%,rgba(0,0,0,.55) 100%);
          mask-image:radial-gradient(130% 105% at 50% 42%,#000 0%,rgba(0,0,0,.82) 58%,rgba(0,0,0,.55) 100%)}
/* On paper the tile's light copper all but vanishes, so it is darkened into an ink
   rather than faded further: brightness() pulls the same hue down toward the
   `--accent-txt` end of the ramp, which is the legal ink on this ground. */
:root[data-theme="light"] .topo-bg{opacity:.72;filter:brightness(.40) saturate(1.2)}
@media (max-width:760px){ .topo-bg{background-size:430px 430px;opacity:.75} }

/* the hero must not paint its own opaque ground or it hides the texture */
.p-hero.topo{background:linear-gradient(180deg,rgba(var(--ovr-rgb),.022) 0%,rgba(var(--ovr-rgb),0) 46%)}
/* only the content wrapper, a blanket `> *` here re-positions .p-bloom and
   .grain, which are absolute by design, and drops them into flow: the hero
   grew 480px before this was caught */
.p-hero.topo > .p-hero-in{position:relative;z-index:2}

/* a closing plate on the same texture, with one copper bloom behind the type */
/* NO overflow:hidden here. The bloom is 150% of this box by design so that it fades
   out past the section's own edges; clipping it produced a hard rectangular cut-off
   exactly like the one the VICE product glows had. The gradient already ends on an
   explicit zero-alpha stop of its own hue (style.css), so nothing needs clipping. */
.topo-close{position:relative;text-align:center;
  width:100vw;max-width:100vw;margin-left:calc(50% - 50vw);
  min-height:clamp(300px,42vh,420px);display:flex;align-items:center;justify-content:center}
.topo-close .glow{width:min(1000px,92%);height:190%}
.topo-close .in{position:relative;z-index:4;padding:clamp(46px,7vh,74px) var(--sp7);
  max-width:var(--wrap)}
.topo-close h2,.topo-close .quiet{text-shadow:var(--hero-sh)}

/* a mid-page plate, shorter than the homepage's so the page stays compact */
.p-plate{height:clamp(300px,44vh,480px)}

/* =========================================================
   THE RECORD BAND, one section doing the work of two.
   `01 What it replays` and the "You already have the data." plate used to be
   separate full-height sections, one after the other, for 955px between them.
   Merged into a single band, the photograph is the section's BACKGROUND, with
   the statement and the three things it replays sitting over it.
   ========================================================= */
.rec-band{position:relative}
.rec-bg{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden;
  width:100vw;max-width:100vw;left:50%;transform:translateX(-50%)}
/* The photograph dissolves rather than ending. Its own alpha is masked out toward
   the edges, so the page ground, and the contour texture standing on it, shows
   through instead of the image stopping at a rectangle. A scrim cannot do this: a
   scrim paints ON TOP in the ground colour, hiding the very texture the image is
   meant to blend into.

   The radii must be <= 50% / 50% of the box, or the falloff never reaches zero
   inside it and the edges stay hard. A first attempt at 102% x 116% simply looked
   like an ordinary rectangular photo with a slight dark border. */
.rec-bg img{display:block;width:100%;height:100%;object-fit:cover;
  object-position:center 20%;filter:var(--img-filter-deep);
  -webkit-mask-image:radial-gradient(50% 58% at 50% 48%,#000 26%,
     rgba(0,0,0,.92) 52%,rgba(0,0,0,.34) 80%,rgba(0,0,0,0) 100%);
          mask-image:radial-gradient(50% 58% at 50% 48%,#000 26%,
     rgba(0,0,0,.92) 52%,rgba(0,0,0,.34) 80%,rgba(0,0,0,0) 100%)}
/* a reading scrim weighted to the copy side, itself faded top and bottom so it
   does not paint a hard band back over the texture */
.rec-bg::after{content:"";position:absolute;inset:0;background:
  linear-gradient(90deg,rgba(var(--blk-rgb),.80) 0%,rgba(var(--blk-rgb),.42) 42%,
                  rgba(var(--blk-rgb),.06) 74%,rgba(var(--blk-rgb),0) 100%);
  -webkit-mask-image:linear-gradient(180deg,rgba(0,0,0,0) 0%,#000 24%,#000 76%,rgba(0,0,0,0) 100%);
          mask-image:linear-gradient(180deg,rgba(0,0,0,0) 0%,#000 24%,#000 76%,rgba(0,0,0,0) 100%)}
.rec-band .wrap{position:relative;z-index:2}
.rec-band h2,.rec-band .quiet,.rec-band .p-does .t,.rec-band .p-does p{
  text-shadow:var(--hero-sh)}
/* On paper the deep filter BRIGHTENS a photograph (brightness 1.1), so the same
   treatment that reads as a dark plate on the near-black ground becomes a pale
   one that dark body copy cannot sit on. Light theme knocks the image back and
   leans the reading scrim much harder. */
:root[data-theme="light"] .rec-bg img{filter:saturate(.42) contrast(.92) brightness(1.16) opacity(.62)}
:root[data-theme="light"] .rec-bg::after{background:
  linear-gradient(90deg,rgba(var(--blk-rgb),.93) 0%,rgba(var(--blk-rgb),.74) 44%,
                  rgba(var(--blk-rgb),.42) 76%,rgba(var(--blk-rgb),.18) 100%)}

/* A portrait screenshot in the side-by-side hero. The MARS hero works because its
   capture is landscape; the ATAK one is 1080x2340 and renders 1,497px tall in the
   same slot, burying the copy. Capped and cropped to the map region, which is the
   part that makes the point anyway. */
.mars-hero .win img.tall{max-height:clamp(340px,52vh,520px);
  object-fit:cover;object-position:center 40%}

/* =========================================================
   SMARTAK, THE CIRCUIT GROUND
   MARS gets contours because it is the map product. SmarTak is a wire format,
   so its ground says interface, not terrain: `assets/img/circuit-tile.png`, a
   1024px seamless tile of orthogonal routing traces and vias at 1.6% ink
   coverage, generated the same way as the contour tile (see CLAUDE.md).
   Same mechanics as .topo-bg, fixed, vignette-masked, darkened into an ink on
   paper rather than merely faded.
   ========================================================= */
.circuit-bg{position:fixed;inset:0;z-index:0;pointer-events:none;
  background-image:url(../assets/img/circuit-tile.png);
  background-repeat:repeat;background-size:620px 620px;opacity:.9;
  -webkit-mask-image:radial-gradient(126% 104% at 50% 40%,#000 0%,rgba(0,0,0,.8) 58%,rgba(0,0,0,.5) 100%);
          mask-image:radial-gradient(126% 104% at 50% 40%,#000 0%,rgba(0,0,0,.8) 58%,rgba(0,0,0,.5) 100%)}
:root[data-theme="light"] .circuit-bg{opacity:.75;filter:brightness(.42) saturate(1.15)}
@media (max-width:760px){ .circuit-bg{background-size:400px 400px;opacity:.8} }

/* =========================================================
   THE ENCODER, what the WnA code actually claims, drawn.
   An earlier pass drew 32 cells in a row. It looked like a data type, not like
   an idea: the claim is not "there are 32 bits", it is "three lookups collapse
   into one integer". Three inputs converging on one field says that; a row of
   squares says nothing, and inviting the reader to count boundaries in it
   implies field widths the documentation does not publish.
   ========================================================= */
.encoder{padding:clamp(18px,2.6vw,30px)}
.encoder svg{display:block;width:100%;height:auto}
.encoder .ebox{fill:var(--bg3);stroke:var(--line2);stroke-width:1}
.encoder .eout{fill:var(--bg2);stroke:rgba(var(--cop4-rgb),.55);stroke-width:1.5}
.encoder .ewire{fill:none;stroke:rgba(var(--cop-rgb),.75);stroke-width:1.5}
.encoder .enode{fill:var(--accent)}
.encoder .elab{font-family:var(--font-mono);font-size:10.5px;letter-spacing:.16em;
  text-transform:uppercase;fill:var(--mute)}
.encoder .ename{font-family:var(--font-mono);font-size:17px;letter-spacing:.02em;
  fill:var(--fg);font-variant-numeric:tabular-nums}
.encoder .etype{font-family:var(--font-mono);font-size:10.5px;letter-spacing:.2em;
  text-transform:uppercase;fill:var(--accent-txt)}

/* =========================================================
   TWO CHAPTERS SIDE BY SIDE
   Stacked, `Working the timeline` and `What you take out` were most of the page's
   height; as peers they read faster and the pair costs ~700px less. Their headings
   drop a size step, or "Working the timeline" wraps while its peer does not.
   ========================================================= */
.ch-pair{display:grid;grid-template-columns:1fr 1fr;gap:clamp(34px,5vw,84px);
  align-items:start}
.ch-pair .chapter{margin-top:0}
.ch-pair .ch-head h3{font-size:clamp(27px,2.7vw,42px)}
.ch-pair .dl{margin-top:clamp(22px,3.4vh,34px)}
.ch-pair .dl > div{grid-template-columns:1fr;gap:7px;padding:clamp(13px,1.9vh,18px) 0}
.ch-pair .dl .nm{font-size:clamp(15px,1.5vw,18px)}
.ch-pair .dl .ds{font-size:14.5px;max-width:48ch}
@media (max-width:980px){
  .ch-pair{grid-template-columns:1fr;gap:clamp(46px,7vh,78px)}
}

/* =========================================================
   THE CONSOLE WINDOW, borrowed from the console variant: a title bar,
   the plate, and a telemetry strip beneath it. It gives a screenshot the
   frame of the application it came out of instead of floating it on the page.

   Every value inside a .win-tele is READ OFF THE SCREENSHOT ABOVE IT.
   Inventing telemetry is banned in this build; if you swap an image, retype
   the strip from the new one or delete it.

   No backdrop-filter here, unlike the console variant. That variant's panels
   sit over a busy backdrop; these sit on flat near-black, where a backdrop
   filter renders nothing at all and only costs a compositing layer.
   ========================================================= */
.win{position:relative;border-radius:var(--r-lg);overflow:hidden;background:var(--bg2);
  border:1px solid rgba(var(--cop4-rgb),.26);
  box-shadow:var(--lit),0 40px 90px -40px rgba(var(--sh-rgb),.95),
             0 0 90px -34px rgba(var(--cop-rgb),.42)}
.win-bar{display:flex;align-items:center;gap:12px;padding:11px clamp(14px,1.6vw,20px);
  border-bottom:1px solid var(--hair2);background:var(--surf-bar);
  font-family:var(--font-mono);font-size:9.5px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--mute);font-variant-numeric:tabular-nums}
.win-bar .dot{width:6px;height:6px;border-radius:50%;background:var(--cop3);flex:none;
  box-shadow:0 0 10px rgba(var(--cop3-rgb),.9)}
.win-bar .ttl{color:var(--fg2);letter-spacing:.18em}
.win-bar .right{margin-left:auto;text-align:right}
/* height:auto is load-bearing. The <img> carries width/height attributes for aspect
   ratio, and those are presentation hints: this rule's width wins, the hint's height
   survives, and the picture stretches vertically. It happened here on first render. */
.win img{width:100%;height:auto;display:block}
.win-tele{font-family:var(--font-mono);font-size:10px;letter-spacing:.1em;color:var(--mute);
  padding:10px clamp(14px,1.6vw,20px);border-top:1px solid var(--hair2);background:var(--bg3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-variant-numeric:tabular-nums}
.win-tele b{color:var(--accent-txt);font-weight:500}
@media (max-width:640px){
  .win-bar span:not(.dot):not(.ttl):not(.right){display:none}
  .win-tele{font-size:9px;letter-spacing:.06em}
}

/* the scale beat: two windows, deliberately off-level so the pair reads as a
   range rather than a comparison table */
.mars-scale{display:grid;grid-template-columns:1fr 1fr;gap:clamp(24px,3.4vw,54px);
  align-items:start;margin-top:clamp(32px,5vh,60px)}
.mars-scale > *:first-child{transform:translateY(-10px)}
.mars-scale > *:last-child{transform:translateY(18px)}
.scale-rail{display:flex;align-items:center;gap:clamp(14px,2.4vw,30px);flex-wrap:wrap;
  margin-top:clamp(56px,8vh,104px);padding-top:clamp(20px,3vh,28px);
  border-top:1px solid var(--hair2);font-family:var(--font-mono);font-size:10.5px;
  letter-spacing:.2em;text-transform:uppercase;color:var(--mute);
  font-variant-numeric:tabular-nums}
.scale-rail .amt{font-family:var(--font-body);font-size:clamp(19px,2.1vw,27px);
  font-weight:700;letter-spacing:-.022em;color:var(--fg);text-transform:none}
.scale-rail .bar{flex:1 1 60px;height:1px;min-width:40px;
  background:linear-gradient(90deg,rgba(var(--cop-rgb),.75),rgba(var(--cop-rgb),.14))}
@media (max-width:900px){
  .mars-scale{grid-template-columns:1fr;gap:clamp(26px,5vh,44px)}
  .mars-scale > *:first-child,.mars-scale > *:last-child{transform:none}
}

/* =========================================================
   THE PLUGIN CHAPTER, one phone screen beside three pillars.
   Braveheart is how a module reaches ATAK, so this sits between
   "The module" and the spec table on every product page.
   ========================================================= */
.p-plugin{display:grid;grid-template-columns:minmax(0,.8fr) minmax(0,1.2fr);
  gap:clamp(30px,5vw,72px);align-items:start;margin-top:clamp(30px,5vh,58px)}
.p-shot{position:relative;margin:0;display:flex;flex-direction:column;align-items:center}
.p-shot .glow{width:172%;height:110%;top:44%}
/* width/height attributes on the <img> are for aspect ratio only; the stylesheet
   sizes by width, so height must be released explicitly or the screen stretches */
.p-shot img{position:relative;z-index:2;width:100%;height:auto;max-width:290px;
  border-radius:16px;border:1px solid var(--line2);
  box-shadow:0 26px 60px rgba(var(--sh-rgb),.55)}
.p-shot figcaption{position:relative;z-index:2;margin-top:15px;font-family:var(--font-mono);
  font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--mute)}
.p-plugin .dl{margin-top:0}
/* the pillar column is ~700px, not the full measure: the shared .dl label rail
   (minmax(150px,22%)) squeezes these longer labels onto three lines, so stack
   label over description here instead of fighting it with shorter words */
.p-plugin .dl > div{grid-template-columns:1fr;gap:9px}
.p-plugin .dl .ds{max-width:58ch}

/* =========================================================
   SPECIFICATIONS, key/value rails. Space Grotesk is proportional,
   so every figure column carries tabular-nums.
   ========================================================= */
.spec{margin-top:clamp(30px,5vh,58px)}
.spec > div{display:grid;grid-template-columns:minmax(160px,25%) 1fr;
  gap:clamp(16px,3vw,52px);align-items:baseline;
  padding:clamp(14px,2.1vh,20px) 0;border-top:1px solid var(--hair2)}
.spec > div:last-child{border-bottom:1px solid var(--hair2)}
.spec dt{font-family:var(--font-mono);font-size:10.5px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--mute);font-variant-numeric:tabular-nums}
.spec dd{margin:0;font-size:clamp(15px,1.35vw,17px);line-height:1.55;color:var(--fg2);
  font-variant-numeric:tabular-nums;max-width:58ch}
.spec dd .p-flag{margin-left:4px;vertical-align:baseline}

/* in the box */
.p-box{margin-top:clamp(42px,7vh,84px)}
.p-boxlist{list-style:none;padding:0;margin:clamp(16px,2.4vh,22px) 0 0;
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(18px,3vw,44px)}
.p-boxlist li{border-top:1px solid var(--line);padding-top:clamp(14px,2vh,20px);
  display:flex;align-items:baseline;gap:14px}
.p-boxlist .n{font-family:var(--font-mono);font-size:10px;letter-spacing:.24em;
  color:var(--accent-txt);font-variant-numeric:tabular-nums;flex:none}
.p-boxlist .t{font-size:clamp(15px,1.4vw,18px);font-weight:600;letter-spacing:-.02em}

/* =========================================================
   CLOSER, one plate, centerd, no contour field
   ========================================================= */
.p-close{position:relative;width:100vw;max-width:100vw;margin-left:calc(50% - 50vw);
  min-height:clamp(440px,62vh,660px);display:flex;align-items:center;justify-content:center;
  text-align:center;overflow:hidden}
.p-close > img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:var(--img-filter-deep);z-index:0}
.p-close .fade{position:absolute;inset:0;z-index:1;background:
  linear-gradient(180deg,rgba(var(--blk-rgb),var(--fade-edge)) 0%,rgba(var(--blk-rgb),calc(var(--fade-mid) * .8)) 34%,rgba(var(--blk-rgb),calc(var(--fade-mid) * .9)) 62%,rgba(var(--blk-rgb),var(--fade-edge)) 100%),
  radial-gradient(70% 62% at 50% 52%,rgba(var(--blk-rgb),.70),rgba(var(--blk-rgb),.34))}
.p-close .in{position:relative;z-index:4;padding:clamp(56px,9vh,90px) var(--sp7);
  max-width:var(--wrap)}
.p-close h2,.p-close .quiet{text-shadow:var(--hero-sh)}

/* =========================================================
   RESPONSIVE
   ========================================================= */
@media (max-width:1100px){
  .p-hero-grid{grid-template-columns:1fr;gap:clamp(24px,5vh,44px);
    padding-left:var(--sp5);padding-right:var(--sp5)}
  .p-hero .lede{max-width:56ch}
  .p-fig{min-height:0;order:2}
  .p-does{grid-template-columns:1fr;gap:var(--sp5)}
  .p-does p{max-width:56ch}
  .p-boxlist{grid-template-columns:1fr}
  .p-close .in{padding-left:var(--sp5);padding-right:var(--sp5)}
  .p-bloom{right:-18%;top:-8%;width:min(880px,116vw)}
}
@media (max-width:900px){
  .p-plugin{grid-template-columns:1fr;gap:clamp(26px,5vh,44px)}
  .p-shot img{max-width:240px}
}
@media (max-width:760px){
  .spec > div{grid-template-columns:1fr;gap:7px}
  .spec dd{max-width:none}
  .p-buy{gap:16px}
}
@media (max-width:640px){
  .p-hero{padding-top:clamp(76px,11vh,108px)}
  .p-fig img{max-height:clamp(210px,34vh,320px)}
  .p-close{min-height:clamp(400px,58vh,520px)}
}

/* =========================================================
   MARS, VERTICAL RHYTHM
   The site's default section padding is clamp(96px,13vh,190px) top AND bottom,
   which on a page with six sections is over 2,000px of air. This page halves it
   and tightens the chapter gaps with it. Nothing else on the site changes.
   ========================================================= */
.mars-page .sec{padding:clamp(40px,5vh,72px) 0}
.mars-page .chapter{margin-top:clamp(34px,4.5vh,68px)}
.mars-page .ch-note{margin-top:clamp(14px,2vh,22px)}
.mars-page .p-does{margin-top:clamp(26px,3.6vh,44px)}
.mars-page .dl{margin-top:clamp(20px,3vh,32px)}
.mars-page .ch-pair{margin-top:clamp(34px,4.5vh,68px)}
.mars-page .mars-scale{margin-top:clamp(24px,3.4vh,44px)}
.mars-page .scale-rail{margin-top:clamp(28px,3.6vh,50px);padding-top:clamp(14px,2vh,20px)}
.mars-page .p-hero{padding-top:clamp(72px,7.5vh,100px);padding-bottom:clamp(18px,2.4vh,28px)}
/* The screenshot sits beside the copy, not under it. Stacked, the hero was 1,425px, a third of the page before a word of it had been read. Side by side it is under
   half that, and the window still renders wide enough for the app to be legible. */
.mars-hero{display:grid;grid-template-columns:minmax(0,.86fr) minmax(0,1.14fr);
  gap:clamp(26px,3.4vw,56px);align-items:center;padding:0 var(--sp7)}
.mars-hero .win{margin:0}
.mars-hero .p-hero-copy{padding:0}
@media (max-width:1040px){
  .mars-hero{grid-template-columns:1fr;gap:clamp(28px,4vh,44px)}
}
.mars-page .p-hero .hero-rail{margin-top:clamp(24px,3.4vh,40px)}
.mars-page .p-plate{height:clamp(280px,40vh,430px)}
/* the hero screenshot is the money shot but it is 1723x1017; capped and cropped
   from the centre it keeps both panels and the transport while giving back ~180px */
/* DO NOT cover-crop the hero screenshot to save height. It was tried at three
   anchor points: the application UI is dense and edge-anchored, so every crop
   takes the playback pill off the top, the transport off the bottom, or the panel
   headers off both. It renders as a broken screenshot. The height on this page
   comes from section padding and the paired chapters instead. */
.mars-page .topo-close{min-height:clamp(300px,42vh,420px)}

.mars-page .rec-band .p-does{margin-top:clamp(30px,4.4vh,54px)}
