/* Tenure — marketing site + door. Originally generated from MOCK-SITE.html.
   EDIT THIS FILE. The mock is superseded by the merged build and no longer
   round-trips: regenerating from it would undo the hero, the namespacing and
   the handoff. See CLAUDE.md, "The page is ONE DOCUMENT now".

   Everything is namespaced under #site or #door. Ten class names collide with
   the narrative (btn, close, done, ico, in, on, ppane, ppanes, ptabs, rt) and
   three of them are load-bearing on both sides: ptabs/ppane/ppanes are the
   beat-10 product panel AND the site's deployment tabs, and in/on/done drive
   the film-beat copy reveal. */
#site, #door, #sitetop{
  --tx:#FFFFFF; --tx2:rgba(255,255,255,.74); --tx3:rgba(255,255,255,.50);
  --amber:#F4C084; --sans:"Hanken Grotesk",system-ui,sans-serif;
  --mono:"Chivo Mono",ui-monospace,monospace;
  --display:"Newsreader",Georgia,serif; --dw:300; --dtrack:-.014em;
  --ground:#0E1214; --ground2:#161B1E; --line:rgba(255,255,255,.11);
  /* NO CUT CORNERS anywhere (Daniel, 5 Aug). --chamfer and the three .chamf-*
     utilities are gone rather than set to 0: left in place they are an
     invitation to reintroduce the detail. Everything that carried a clipped
     corner now carries a plain border-radius. */
  /* the site keeps its OWN gutter: the narrative's --gut caps the content box
     at 1180px, which is a rule about the film frame, not a scrolling page. */
  --gut:clamp(26px,5.5vw,104px);
}
#site h1,#site h2,#site h3,#site h4,#door h1,
#sitetop h1,#sitetop h2,#sitetop h3,#sitetop h4{font-family:var(--display);
  font-weight:var(--dw);letter-spacing:var(--dtrack);margin:0;text-wrap:balance}
#site p,#door p{margin:0}
#site{background:transparent;color:var(--tx);font-family:var(--sans);
  font-weight:300;font-size:17px;line-height:1.6;position:relative;z-index:20}
#site h1, #site h2, #site h3, #site h4{font-family:var(--display);font-weight:var(--dw);letter-spacing:var(--dtrack);
  margin:0;text-wrap:balance}
#site p{margin:0}
#site a{color:inherit}
/* ======================================================== SHARED FURNITURE */
#site .shell{max-width:1420px;margin:0 auto;padding-inline:var(--gut)}
/* the one repeated control ------------------------------------------------ */
#site .btn{display:inline-flex;align-items:center;gap:0;height:56px;cursor:pointer;
  font-family:var(--sans);font-size:15px;font-weight:500;letter-spacing:.005em;
  padding-left:26px;border-radius:13px;border:0;text-decoration:none;
  transition:filter .25s cubic-bezier(.2,.8,.25,1),transform .25s cubic-bezier(.2,.8,.25,1)}
#site .btn i{display:grid;place-items:center;width:50px;height:100%}
#site .btn svg{width:17px;height:17px;display:block}
#site .btn:hover{transform:translateY(-2px);filter:brightness(1.06)}
#site .btn.solid{background:var(--amber);color:#17120A}
#site .btn.ghost{background:rgba(216,224,228,.08);color:#fff;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.2)}
#site .btn:focus-visible{outline:2px solid var(--amber);outline-offset:3px}
/* ================================================================ THE NAV */
#site .nav{position:fixed;left:var(--gut);right:var(--gut);top:18px;height:70px;z-index:120;
  display:flex;align-items:center;justify-content:space-between;padding:0 7px 0 26px;
  background:rgba(216,224,228,.10);box-shadow:inset 0 0 0 1px rgba(255,255,255,.16);
  -webkit-backdrop-filter:blur(22px) saturate(130%);
  backdrop-filter:blur(22px) saturate(130%);
  border-radius:16px;
  transition:background-color .4s ease}
#site .nav.stuck{background:rgba(14,18,20,.86)}
/* the lockup is one asset now, so the gap and the separate type rule that used
   to hold the constructed mark next to the word are gone. The book fixes the
   space between mark and wordmark inside the artwork: "Do not respace." */
#site .brand{display:flex;align-items:center}
/* 12px, and that is a real 12px of letterform: the file is trimmed hard to the
   ink (measured, zero padding on all four sides), so the height set here IS the
   cap height. That is why 24 read as oversized next to 15px nav links whose own
   caps are around 10. The book's 30-40px guidance does not apply, since it is
   written for the horizontal LOCKUP, whose height is set by the mark sitting
   above and below the word.
   Downscaling 310px of source into 93px stays sharp; only upscaling aliases,
   which is the direction the book warns about. */
#site .brand img{display:block;height:12px;width:auto}
#site .nlinks{display:flex;gap:34px}
#site .nlinks a{color:rgba(255,255,255,.84);text-decoration:none;font-size:15px;font-weight:400;
  transition:color .25s}
#site .nlinks a:hover{color:var(--amber)}
#site .nav .btn{height:54px;font-size:14px;padding-left:22px}
#site .nav .btn i{width:44px}
#site .nact{display:flex;align-items:center;gap:10px}
/* Replay is a CONTROL, not a destination: it acts on the page rather than
   moving you through it, so it sits with the CTA and not in the link list.
   Its name lives in aria-label AND data-tip, because the tooltip below is
   decoration that a screen reader never sees. */
#site .replay{position:relative;appearance:none;border:0;cursor:pointer;
  width:40px;height:40px;display:grid;place-items:center;border-radius:11px;
  background:transparent;color:rgba(255,255,255,.72);
  transition:color .25s,background-color .25s}
#site .replay svg{width:19px;height:19px;display:block}
#site .replay:hover{color:#fff;background:rgba(255,255,255,.09)}
#site .replay:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
#site .replay::after{content:attr(data-tip);position:absolute;top:calc(100% + 12px);
  left:50%;transform:translate(-50%,-5px);white-space:nowrap;pointer-events:none;
  font-family:var(--sans);font-size:12.5px;font-weight:400;letter-spacing:.01em;
  color:#fff;background:rgba(14,18,20,.95);padding:7px 11px;border-radius:9px;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.14);
  opacity:0;transition:opacity .2s ease,transform .2s ease}
#site .replay:hover::after,#site .replay:focus-visible::after{
  opacity:1;transform:translate(-50%,0)}
@media (prefers-reduced-motion:reduce){
  #site .replay::after{transition:none}
}
/* =============================================================== THE HERO
   Full bleed. The inset frame is gone: it read as a page inside a page. */
#sitetop{position:relative;min-height:100svh;overflow:hidden;
  display:flex;flex-direction:column;justify-content:flex-start}
#sitetop .scene{position:absolute;inset:0;z-index:0}
#sitetop video, #sitetop .scene img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
/* The loop measures 167 mean luma and never drops below 160, so it needs a
   real grade or nothing on it reads. Vertical pass restores the reference's
   tonality (calm top, dark ground); the angled pass keeps the copy column
   quiet without flattening the whole frame. */
#sitetop .gv{position:absolute;inset:0;background:linear-gradient(180deg,
  rgba(11,15,17,.70) 0%,rgba(11,15,17,.40) 16%,rgba(11,15,17,.20) 36%,
  rgba(11,15,17,.55) 64%,rgba(13,17,19,.92) 86%,var(--ground) 100%)}
#sitetop .gd{position:absolute;inset:0;background:linear-gradient(96deg,
  rgba(11,15,17,.72) 0%,rgba(11,15,17,.30) 32%,rgba(11,15,17,0) 60%)}
/* ---- the scrim ------------------------------------------------------
   MEASURED, not judged by eye. The loop is a bright picture and it is
   brightest exactly where the copy has to sit: sampling 40 frames through
   object-fit:cover at 1600x1000 gives mean luma 188 under the eyebrow, 191
   under the mark, 203 under the headline and 220 under the paragraph, with
   worst-frame values 8-20 higher again. White text on 224 is 2.2:1, so this
   page was unreadable by arithmetic and not by taste.
   The radial is therefore centred LOW (46%, on the paragraph) rather than on
   the middle of the frame, and carries .54-.62 through the whole copy stack:
   AA body contrast needs .47 against the worst frame there. It falls to zero
   well inside the edges so there is no visible boundary anywhere. The vertical
   pass does the other two jobs: settle the nav at the top, and darken into the
   opaque sections below so the hero does not end on a hard line. */
#sitetop .hscrim{position:absolute;inset:0;z-index:1;pointer-events:none;
  opacity:0;transition:opacity 1.8s ease;
  background:
    /* ONE WASH, no shape. It used to be two radials, and the inner one was a
       34% x 32% ellipse at 90% black sitting right on the lockup: dark enough
       and small enough to read as a deliberate vignette behind the logo, which
       is what Daniel spotted on 7 Aug. The wash still has to be here, and the
       numbers are not close. With it off, the loop runs 218 luma behind the
       lockup and 230 behind the paragraph, which puts white text at 1.2:1 and
       the mark at 1.4:1. That is the unreadable page he asked to fix in the
       first place.
       So the fix is the SHAPE, not the presence. One gradient wide enough that
       no edge of it lands inside the frame, and it reads as the picture being
       darker in the middle rather than as a patch laid over it.
       It is also better for the mark, not worse. The White variant's element 6
       (the base and the centre stem, 40% of the artwork) has NO FILL, so
       whatever is behind shows through the stem, and the book's requirement is
       that the backdrop be at one end of the range and EVEN. A tight radial
       centred on the lockup falls off hard ACROSS the mark; a broad one is flat
       over its 196px. Measured with the copy hidden, not assumed. */
    radial-gradient(116% 96% at 50% 40%,
      rgba(6,10,12,.72) 0%,rgba(6,10,12,.66) 26%,rgba(6,10,12,.50) 48%,
      rgba(6,10,12,.30) 70%,rgba(6,10,12,.12) 88%,rgba(6,10,12,0) 100%),
    linear-gradient(180deg,
      rgba(6,10,12,.34) 0%,rgba(6,10,12,.10) 22%,rgba(6,10,12,0) 42%,
      rgba(6,10,12,.16) 62%,rgba(8,12,14,.28) 76%,
      rgba(10,14,16,.52) 88%,rgba(13,17,19,.78) 100%)}

#sitetop .hwrap{position:relative;z-index:5;padding-top:118px;flex:1;display:flex;flex-direction:column}
/* the stack is optically centred in the space the cards leave, not parked
   under the nav: four short blocks pinned to the top read as a caption */
#sitetop .htitle{text-align:center;padding-inline:var(--gut);
  flex:1;display:flex;flex-direction:column;justify-content:center}
#sitetop .heyebrow{font-family:var(--sans);font-weight:400;font-size:13px;
  /* .76, not .66. Measured against the wash behind it, "INTRODUCING" was
     landing at 4.3:1 on two of three sampled frames, which is under AA for
     13px text. It was under before this scrim was reshaped, so this is not a
     consequence of that change, just the first time it was measured on its own
     rather than as part of a band. */
  letter-spacing:.26em;text-transform:uppercase;color:rgba(255,255,255,.76);
  margin:0 0 clamp(20px,2.4vw,34px)}
/* THE LOCKUP. Three brand rules are load-bearing here and each one killed
   something that used to be in this block:
   - "Never invert or apply a CSS filter, each variant is tuned to its surface."
     So the mask is gone and the Cream artwork is served as artwork.
   - "Do not add effects. No shadows, glows, bevels, outlines or strokes."
     So is the drop-shadow.
   - "Set an explicit height. Serve the matching density rather than letting the
     browser upscale. Flat tones alias badly when stretched." So the size is set
     on the HEIGHT, capped at the asset's native 96px, and srcset carries 2x/3x.
   The floor of 58px keeps the lockup at 229px wide on a phone, clear of the
   book's 170px minimum for this form. */
#sitetop .hlogo{position:relative;display:flex;justify-content:center;
  margin:0 0 clamp(24px,3vw,42px)}
/* sized on WIDTH now, because the stacked form is defined by its width in the
   book (150px minimum) and because `sizes` above is expressed in widths. The
   190px floor keeps a phone well clear of that minimum. */
#sitetop .hlogo img{display:block;position:relative;z-index:1;
  width:clamp(190px,22vw,300px);height:auto}
/* The wash the lockup needs lives in .hscrim as a second radial, NOT as a
   local ::before here. A tight element-sized wash did the job by the numbers
   and read as a soft-edged plate sitting on the film, with its boundary
   crossing the headline. Two radials in one layer blend; two layers on two
   elements meet at an edge. */
/* smaller (Daniel). It was the loudest thing on the page and it is not the
   thing being introduced; the lockup is. */
#sitetop .hline{font-family:var(--display);font-weight:var(--dw);
  font-size:clamp(30px,4.2vw,62px);line-height:1.06;letter-spacing:-.018em;
  color:#fff;margin:0 0 clamp(14px,1.6vw,24px)}
/* measure in `em`, which resolves against THIS element's own font-size. A `ch`
   or `em` cap set on an ancestor is measured against the ancestor's 17px and
   delivers a third of the column it claims — see CLAUDE.md. */
#sitetop .hsub{font-size:clamp(16.5px,1.35vw,19.5px);line-height:1.58;
  color:rgba(255,255,255,.88);max-width:32em;margin:0 auto;text-wrap:balance}
/* the three cards over the hero's bottom edge. THE FLIP: at rest each is laid
   back on its bottom edge and sits low; on hover it stands up and rises. The
   hinge is the bottom edge, not the centre, or it swings instead of standing. */
/* The carousel dots are a phone control. Declared HERE, above the 820px block
   that turns them on, because these two rules have the same specificity and
   source order is what decides: written after it, `display:none` won and the
   dots never appeared however correct the media query was. */
#sitetop .hdots{display:none}
#sitetop .hcards{position:relative;z-index:6;padding-inline:var(--gut);margin-top:auto;
  display:grid;grid-template-columns:repeat(3,1fr);gap:18px;
  perspective:1500px;perspective-origin:50% 130%}
/* FROSTED GLASS, and this reverses the note that used to sit below, so it is
   worth saying plainly what changed rather than quietly deleting it.
   That note banned backdrop-filter here after a Safari crash, and the stack it
   named was three things at once: a blur, a clip-path, and a 3D `perspective`
   context, all over playing video, all switching on in the same frame. Two of
   the three are now gone: no painted surface on the site is clipped any more
   (the only clip-path left is inset(50%) on a screen-reader span, which never
   composites), and the film and the loop no longer hold decoders at once. Blur
   is 18px rather than the nav's 22px for the same reason. If Safari falls over
   on this page again, this is the first thing to take back out. */
/* The cards are <a> now, one per section they argue, so the hero is also the
   table of contents. display:block because an anchor is inline by default and
   the height/padding below would do nothing. */
#sitetop .hcard{display:block;text-decoration:none;
  position:relative;height:270px;padding:26px 28px;overflow:hidden;border-radius:20px;
  cursor:pointer;transform-origin:50% 100%;transform:translateY(30px) rotateX(9deg);
  /* brightness() IS THE TRICK, and it is what finally made these read as glass.
     White copy needs a dark surface, and darkening with the scrim meant
     darkening the whole band — so the picture went flat everywhere down here
     and the cards had nothing bright to be glass against. Putting the
     darkening in the card's own BACKDROP filter makes it local: the scene
     around the cards stays lit, the film inside them is dimmed but still
     visibly moving, and the tints are then free to be almost nothing. */
  -webkit-backdrop-filter:blur(18px) saturate(122%) brightness(.76);
  backdrop-filter:blur(18px) saturate(122%) brightness(.76);
  transition:transform .55s cubic-bezier(.19,.86,.28,1),
             box-shadow .55s cubic-bezier(.19,.86,.28,1)}
#sitetop .hcard:hover, #sitetop .hcard:focus-visible{transform:translateY(-14px) rotateX(0deg);
  box-shadow:0 52px 84px -46px rgba(0,0,0,.95);outline:none}
#sitetop .hcard h3{font-size:28px;line-height:1.14;margin-bottom:9px}
/* 30ch was ~216px inside a card offering ~406px, so the measure was throwing
   the last word or two onto a third line while a third of the card sat empty.
   The card's own padding is the right constraint here; text-wrap:pretty is the
   belt and braces against an orphan at whatever width the grid lands on. */
#sitetop .hcard p{font-size:15.5px;line-height:1.5;max-width:44ch;text-wrap:pretty}
/* the destination, named. Every card carries one now: an unlabelled clickable
   card makes the reader guess where it goes, and these three are the page's
   navigation as much as its argument. */
#sitetop .hcard .more{position:absolute;left:28px;bottom:44px;font-size:13px;font-weight:500;
  border-bottom:1px solid rgba(255,255,255,.45);padding-bottom:2px;
  transition:border-color .25s ease}
#sitetop .hcard:hover .more,#sitetop .hcard:focus-visible .more{border-bottom-color:#fff}
#sitetop .hcard:focus-visible{outline:2px solid var(--amber);outline-offset:3px}
#sitetop .hcard .art{position:absolute;right:-16px;bottom:-18px;width:170px;pointer-events:none}
/* THE THREE TINTS, and why they are all light-on-dark now.
   The first pass kept the reference's dark/sage/WHITE progression and the two
   light cards therefore carried dark copy. Dark copy needs its surface to stay
   LIGHT, so those cards had to sit near .82 alpha over a picture that swings
   from 200 luma to near black, and at .82 nothing reads as glass: Daniel's
   report was simply "not seeing the frosted glass effect", and he was right.
   The alpha was doing all the work and there was none left to spend.
   The fix is to change what the glass sits ON rather than what it is made of.
   The scrim now takes this band down to roughly 60 luma, which is dark and, as
   importantly, CONSISTENT — and against a dark backdrop a pale tint can be very
   transparent and still hold white text. So all three are white-on-glass at
   .22-.36, which is four times more transparent than before, and the row keeps
   its identity through hue and weight instead of through ink colour.
   One thing worth knowing before reaching for more blur: the loop behind these
   is already soft, so the blur radius contributes almost nothing here. What
   reads as glass on this page is the transparency, not the smear. */
/* With brightness() doing the darkening, these are HUE ONLY: .10-.20, which is
   in the same range as the nav Daniel pointed at. The three keep their identity
   through colour and through how bright a rim each carries, not through opacity.
   The pale card is third rather than white because white cannot hold white
   copy, and dark copy on a transparent card fails the moment the film behind it
   goes dark. */
#sitetop .hcard.k1{background:linear-gradient(168deg,rgba(96,126,119,.13) 0%,
  rgba(52,74,69,.15) 52%,rgba(40,58,54,.09) 100%);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.15),0 30px 60px -40px rgba(0,0,0,.9)}
#sitetop .hcard.k1 p{color:var(--tx2)}
#sitetop .hcard.k2{background:linear-gradient(168deg,rgba(168,196,183,.12) 0%,
  rgba(130,164,153,.13) 52%,rgba(106,138,129,.08) 100%);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.26),0 30px 60px -40px rgba(0,0,0,.9)}
#sitetop .hcard.k2 p{color:var(--tx2)}
#sitetop .hcard.k3{background:linear-gradient(168deg,rgba(235,243,239,.13) 0%,
  rgba(214,228,222,.13) 52%,rgba(196,212,205,.08) 100%);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.42),0 30px 60px -40px rgba(0,0,0,.9)}
#sitetop .hcard.k3 p{color:var(--tx2)}
/* One column on a phone. Three columns at 430px gives each card ~120px, which
   sets every heading one word per line and clips the copy. The flip goes with
   them: a laid-back card in a single column just reads as misaligned. */
/* ============================================================== SECTIONS */
#site .sec{padding-block:clamp(84px,11vw,150px);position:relative}
#site .sec + .sec{border-top:1px solid var(--line)}

/* ---------------------------------------------- THE LIGHT SURFACE --------
   Everything from the hero to the footer was one dark value, which is what
   made the lower half read as bland: seven sections of identical shape on
   identical ground, with no reason for the eye to register a new one starting.
   This is the brand's PRIMARY pairing and it was going completely unused.
   Copper Pine on Paper opens the book's colour section, and every value below
   is lifted from its published ratios rather than picked by eye.
   It works by re-declaring the custom properties, so every rule already written
   for the dark sections comes along unchanged. Only declarations that hard-code
   a colour need an override, and those are the six below. */
#site .sec.paper{
  --tx:#12352A;               /* wordmark green, 12.45:1 on Paper */
  --tx2:#22523D;              /* Deep Pine,       8.33:1, AA body */
  --tx3:#386C51;              /* Mid Pine,        5.69:1, AA body */
  --amber:#854F0B;            /* the book's amber for light ground, 6.9:1 */
  --line:rgba(18,53,42,.15);
  --ground:#FBF6EE;           /* Paper */
  --ground2:#F2ECE1;
  color:var(--tx);
}
/* No hairline where the value changes: the tonal step IS the division, and a
   rule on top of it reads as a seam. */
#site .sec.paper,#site .sec.paper + .sec{border-top:0}
#site .sec.paper .dtabs button:hover{background:rgba(18,53,42,.06)}
#site .sec.paper .dtabs button.on{color:#FBF6EE;background:#22523D}
#site .sec.paper .cap .ico{color:#22523D;background:rgba(34,82,61,.08);
  box-shadow:inset 0 0 0 1px rgba(34,82,61,.22)}
#site .sec.paper .btn.solid{background:#22523D;color:#FBF6EE}
#site .sec.paper .btn.ghost{color:var(--tx);background:rgba(18,53,42,.05);
  box-shadow:inset 0 0 0 1px rgba(18,53,42,.18)}
#site .sec h2{font-size:clamp(34px,4.6vw,66px);line-height:1.04;max-width:15em}
#site .lede{font-size:19px;line-height:1.62;color:var(--tx2);max-width:62ch;margin-top:22px}
/* The section intro sets the heading against its lede rather than stacking
   both on the left. Stacked, every section left two fifths of the page empty
   and the whole run read as unfinished; the heading also has to stay short to
   hold its measure, which fights the lede wanting room. */
#site .intro{display:grid;gap:10px clamp(30px,5vw,72px);align-items:end}
/* the claim: a statement, the four risks under it, and the answer as a filled
   card beside them. The card is DEEP PINE — the book's primary colour, which
   until now the site only ever used as ink. It is the third surface value on
   the page and the reason this section no longer needs a dark half. */
#site .claim{display:grid;gap:clamp(34px,4vw,54px);grid-template-columns:1fr}
#site .answer.pine{
  --tx:#FBF6EE; --tx2:rgba(251,246,238,.80); --line:rgba(251,246,238,.20);
  background:#22523D;color:var(--tx);
  padding:clamp(30px,3.4vw,44px);border-radius:22px}
#site .answer.pine h3{font-size:clamp(25px,2.5vw,34px);line-height:1.14;
  margin-bottom:16px}
#site .answer.pine p{font-size:17px;line-height:1.58;color:var(--tx2);max-width:26em}
#site .answer.pine .ansfig{display:block;width:100%;max-width:460px;height:auto;
  margin-top:clamp(26px,3vw,40px);color:var(--tx2)}
@media (min-width:900px){
  #site .claim{grid-template-columns:1.05fr .95fr;
    column-gap:clamp(34px,5vw,72px);row-gap:clamp(38px,4vw,56px);align-items:start}
  #site .claim h2{grid-column:1;grid-row:1;max-width:11em}
  #site .claim .cmp{grid-column:1;grid-row:2;margin-top:0}
  #site .claim .answer{grid-column:2;grid-row:1 / span 2;align-self:start}
}
/* ---- the renting / owning comparison --------------------------------------
   Replaces the one-column `.risks` list. Same four complaints, now each with
   its answer on the same row.
   The type is smaller than the list's 19-24px on purpose. A list of four
   declarations wants to be big, because reading it IS the argument; a
   comparison wants to be scannable, and at 24px two columns of it is four
   lines a cell and the eye cannot cross the row. */
#site .cmp{width:100%;border-collapse:collapse;
  margin-top:clamp(30px,3.6vw,48px);border-top:1px solid var(--line)}
#site .cmp caption{position:absolute;width:1px;height:1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap}
#site .cmp th{text-align:left;font-family:var(--mono);font-weight:400;
  font-size:11.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--tx3);padding:14px 0 13px;border-bottom:1px solid var(--line)}
#site .cmp td{padding:17px 0;border-bottom:1px solid var(--line);
  font-size:clamp(16px,1.25vw,18.5px);line-height:1.36;
  letter-spacing:-.004em;vertical-align:top}
/* The left column is the problem and the right column is the answer, so they
   are not the same colour. Equal weight reads as a feature matrix; this is an
   argument with a side. */
#site .cmp td:first-child{color:var(--tx2)}
#site .cmp td:last-child{color:var(--tx);font-weight:500}
#site .cmp th:first-child,#site .cmp td:first-child{width:50%;padding-right:26px}
#site .cmp th:last-child,#site .cmp td:last-child{padding-left:26px;
  border-left:1px solid var(--line)}
/* ---- section eyebrows: the chapter frame ----------------------------------
   A quiet role label above every section headline, so the page reads as an
   authored sequence instead of six identical drops into a heading. Inside the
   h2 on purpose (a block span), so no section's grid placement moves.
   MUTED, not amber: amber is reserved for module labels like the incl grid, so
   the two levels stay distinct. Inherits --tx3, which each surface redefines,
   so it adapts to paper and dark without a per-surface rule. */
#site .sec h2 .s-eyebrow{display:block;font-family:var(--mono);font-weight:400;
  font-size:12px;letter-spacing:.2em;text-transform:uppercase;color:var(--tx3);
  line-height:1;margin-bottom:clamp(14px,1.5vw,20px)}
/* ---- what's included: the spec-sheet grid above the tabs -------------------
   Texture on purpose. The prose sections are one idea in a lot of air; this is
   sixteen anchors in a tight grid, which is the variation the page was missing.
   Terse by rule: chips, never sentences. The moment a chip needs a comma it is
   doing too much. */
#site .incl{margin-top:clamp(30px,3.6vw,46px);display:grid;gap:1px;
  grid-template-columns:1fr;background:var(--line);
  border:1px solid var(--line);border-radius:16px;overflow:hidden}
#site .incl-col{background:var(--ground);padding:clamp(22px,2.4vw,30px)}
#site .incl-h{display:block;font-family:var(--mono);font-size:11px;
  letter-spacing:.2em;text-transform:uppercase;color:var(--amber);
  margin-bottom:16px}
#site .incl-col ul{list-style:none;margin:0;padding:0;display:flex;
  flex-direction:column;gap:10px}
#site .incl-col li{font-size:15.5px;line-height:1.25;color:var(--tx);
  letter-spacing:-.006em;padding-left:16px;position:relative}
/* a hairline tick, not a bullet: quieter, and it reads as a checklist of what
   is in the box rather than a list of features being sold */
#site .incl-col li::before{content:"";position:absolute;left:0;top:.5em;
  width:7px;height:1px;background:var(--tx3)}
@media (min-width:680px){#site .incl{grid-template-columns:1fr 1fr}}
@media (min-width:980px){#site .incl{grid-template-columns:repeat(4,1fr)}}
/* what gets deployed: the four products, tabbed. Same content the client
   already signed off on for beat 10. */
#site .prods{margin-top:clamp(38px,5vw,60px)}
#site .dtabs{display:flex;flex-wrap:wrap;gap:6px;border-bottom:1px solid var(--line);
  padding-bottom:14px;margin-bottom:34px}
#site .dtabs button{appearance:none;cursor:pointer;font-family:var(--sans);font-size:15px;
  font-weight:500;padding:10px 16px;border-radius:10px;border:0;background:transparent;
  color:var(--tx3);transition:background-color .28s,color .28s}
#site .dtabs button:hover{color:var(--tx);background:rgba(255,255,255,.05)}
#site .dtabs button.on{color:#17120A;background:var(--amber)}
#site .dtabs button:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
/* Each pane leads with an image and one plain sentence saying what the thing
   is. Stock (Unsplash), and chosen to be the METAPHOR rather than the product:
   racked hardware, a card catalogue, a colonnade, a vault face. None of them
   shows an office, a person or a screen, so none can be mistaken for a customer
   or for a product shot that does not exist yet. They carry real alt text
   because they are content, not texture.
   The film frames that were briefly here are gone (Daniel: do not re-use them
   this way). The one film still that stays is the ownership block's, which is
   a backdrop for a pull quote rather than an illustration of a feature. */
/* DIAGRAMS, not photographs. The four things being described here are
   structural, so they can be drawn rather than alluded to: a boundary with the
   model inside it, loose documents becoming one indexed body, one sequence run
   three times, an org chart cut by a permission line. A photograph of a server
   could only ever be a metaphor for the first of those.
   Every stroke is currentColor, so the same file works on Paper and on the dark
   ground with no second asset and no filter. They carry a full sentence as
   aria-label, because unlike the photographs they are making a point. */
#site .dpane .shot{position:relative;margin:0;border-radius:18px;overflow:hidden;
  aspect-ratio:16/9;box-shadow:inset 0 0 0 1px var(--line);background:var(--ground2);
  display:grid;place-items:center;padding:clamp(20px,3.4vw,44px)}
#site .dpane .shot .dgm{width:100%;height:auto;max-height:100%;display:block;
  color:var(--tx2)}
/* the definition. Bigger and whiter than the capabilities under it, because it
   is the answer to "what IS this" and they are the answer to "what does it do" */
#site .dpane .def{margin:0;font-size:19px;line-height:1.55;
  color:var(--tx);max-width:24em}
#site .dpanes{display:grid}
#site .dpane{grid-area:1/1;display:grid;gap:26px 40px;grid-template-columns:1fr;
  opacity:0;visibility:hidden;transform:translateY(6px);
  transition:opacity .32s ease,transform .32s cubic-bezier(.2,.8,.25,1),visibility 0s linear .32s}
#site .dpane.on{opacity:1;visibility:visible;transform:none;transition-delay:0s}
#site .cap{display:grid;grid-template-columns:auto 1fr;gap:14px;align-items:start}
#site .cap .ico{width:34px;height:34px;border-radius:9px;display:grid;place-items:center;flex:0 0 auto;
  background:rgba(127,195,205,.10);box-shadow:inset 0 0 0 1px rgba(127,195,205,.24);
  color:var(--teal)}
#site .cap .ico svg{width:17px;height:17px;display:block}
#site .cap h4{font-size:21px;line-height:1.3;margin-bottom:5px}
#site .cap p{font-size:16px;line-height:1.55;color:var(--tx2);max-width:44ch}
/* how a deployment works: a real sequence, so the numbers carry information */
/* ---- the process, as a flow ----------------------------------------
   Four cards left to right with a connector between them. The connector is a
   ::before on each card after the first rather than a separate element, so the
   count is never wrong and it disappears by itself when the row wraps.
   The number is the accent and the only thing that varies at a glance, so the
   direction reads before any of the words do. */
#site .flow{list-style:none;padding:0;margin:clamp(38px,5vw,58px) 0 0;
  display:grid;gap:18px;grid-template-columns:1fr}
#site .fstep{position:relative;padding:26px 26px 26px;border-radius:18px;
  background:var(--ground2);box-shadow:inset 0 0 0 1px var(--line);
  display:flex;flex-direction:column}
#site .fstep .fn{display:block;font-family:var(--mono);font-size:12px;
  letter-spacing:.16em;color:var(--amber);margin-bottom:16px}
#site .fstep .fico{width:34px;height:34px;display:block;margin-bottom:16px;
  color:var(--tx2)}
#site .fstep h3{font-size:20px;line-height:1.2;margin-bottom:8px}
#site .fstep p{font-size:15.5px;line-height:1.5;color:var(--tx2)}
/* the duration is the anchor. Pinned to the card bottom (margin-top:auto) so
   the five line up across cards of different text length, on a hairline so it
   reads as a fact about the phase, not another sentence. */
#site .fstep .fdur{margin-top:auto;padding-top:16px;font-family:var(--mono);
  font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--tx3)}
@media (min-width:900px){
  #site .flow{grid-template-columns:repeat(5,1fr);gap:clamp(14px,1.5vw,22px)}
  /* the connector: a hairline into the gap with a chevron on its end. Drawn
     from the LEFT edge of each card but the first, so it sits in the gutter
     that already exists rather than needing one. */
  #site .fstep + .fstep::before{content:"";position:absolute;
    left:calc(-1 * clamp(18px,2.2vw,30px));top:44px;
    width:clamp(18px,2.2vw,30px);height:1px;background:var(--line)}
  #site .fstep + .fstep::after{content:"";position:absolute;
    left:-7px;top:40px;width:7px;height:7px;
    border-top:1px solid var(--line);border-right:1px solid var(--line);
    transform:rotate(45deg)}
}
#site .fits{margin-top:clamp(34px,4vw,52px);display:grid;gap:1px;background:var(--line);
  border-radius:18px;overflow:hidden;box-shadow:inset 0 0 0 1px var(--line)}
#site .fit{background:var(--ground);padding:30px 32px}
#site .fit h3{font-size:23px;margin-bottom:8px}
#site .fit p{color:var(--tx2);font-size:16.5px;line-height:1.56;max-width:42ch}
/* ownership: the pull statement, set large, against the film */
/* FULL BLEED. It was a rounded card inset inside a dark section, which read as
   an island rather than a moment and gave the long dark run no relief at all. */
#site .sec.bleed{padding-block:0}
#site .own{position:relative;overflow:hidden;margin-top:0;
  min-height:clamp(420px,44vw,560px);display:grid;align-content:center;
  padding:clamp(64px,8vw,110px) max(var(--gut),calc((100vw - 1420px) / 2 + var(--gut)))}
#site .own video, #site .own img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0}
/* also on the charcoal axis: this one said rgba(8,16,13) and was the last
   green-black left on the dark side. Held further across the frame too, since
   the copy column is wider than it was. */
#site .own .g{position:absolute;inset:0;z-index:1;background:linear-gradient(100deg,
  rgba(10,14,16,.95) 0%,rgba(10,14,16,.90) 44%,rgba(10,14,16,.56) 74%,rgba(10,14,16,.22) 100%)}
/* NO CAP ON THE BLOCK. max-width:24em here resolved against .in's own 17px, so
   the column was 408px — and the h2 inside renders at 62px, which is a measure
   of under seven characters. That is what broke "One / deployment, / not an /
   indefinite / subscription." across five lines and made the copy feel
   squeezed into a corner. The measure belongs on each element, in its own em.
   CLAUDE.md has this exact trap written down; I walked into it anyway. */
#site .own .in{position:relative;z-index:2;max-width:none}
#site .own h2{font-size:clamp(32px,4.4vw,62px);line-height:1.06;max-width:9em}
#site .own p{margin-top:20px;color:var(--tx2);font-size:clamp(17px,1.35vw,19px);
  line-height:1.6;max-width:33em}
/* the diagram, on its own surface. It cannot sit straight on the photograph:
   the frame behind this half means luma 79 and peaks at 155, and the trees are
   striated, so 1.4px lines disappear into them whatever the mean says. Frosted
   rather than a flat fill, and brightness() rather than a page-wide scrim, so
   it darkens only where it is and the film still reads through it. */
#site .own .fig{position:relative;z-index:2;margin:0;
  padding:clamp(20px,2.3vw,32px);border-radius:22px;
  background:rgba(10,14,16,.30);
  -webkit-backdrop-filter:blur(16px) saturate(116%) brightness(.60);
  backdrop-filter:blur(16px) saturate(116%) brightness(.60);
  box-shadow:inset 0 0 0 1px rgba(241,227,206,.15)}
#site .own .fig .dgm{width:100%;height:auto;display:block;color:rgba(241,227,206,.86)}
/* ---- FAQ accordion --------------------------------------------------------
   Follows the paper personas, so restore a divider (paper+.sec zeroes it) and
   the eyebrow does the rest of the chapter separation. Native <details>: the
   answers are closed until asked for, which keeps seven Q&As scannable instead
   of a wall. */
#site .sec.faq{border-top:1px solid var(--line)}
#site .qas{margin-top:clamp(30px,3.6vw,46px);max-width:820px;
  border-top:1px solid var(--line)}
#site .qa{border-bottom:1px solid var(--line)}
#site .qa summary{list-style:none;cursor:pointer;display:flex;
  justify-content:space-between;align-items:baseline;gap:24px;
  padding:clamp(18px,2vw,24px) 0;
  font-family:var(--display);font-weight:var(--dw);
  font-size:clamp(19px,1.7vw,23px);line-height:1.25;letter-spacing:-.008em;
  color:var(--tx)}
#site .qa summary::-webkit-details-marker{display:none}
#site .qa summary:hover{color:var(--tx2)}
#site .qa summary:focus-visible{outline:2px solid var(--amber);outline-offset:3px}
#site .qa .chev{flex:0 0 auto;width:20px;height:20px;color:var(--tx3);
  margin-top:.2em;transition:transform .25s ease}
#site .qa[open] .chev{transform:rotate(180deg)}
#site .qa p{margin:0 0 clamp(20px,2.2vw,26px);max-width:64ch;
  font-size:16.5px;line-height:1.62;color:var(--tx2)}
@media (prefers-reduced-motion:reduce){#site .qa .chev{transition:none}}
/* the close */
/* CENTRED. The close is the one section that is not making an argument, it is
   making an offer, and an offer set hard left with a column of empty page
   beside it reads like a footnote. Only the block centres: the labels and
   inputs stay left-aligned, because centred form fields are unreadable. */
#site .close{text-align:center}
#site .close h2{max-width:13em;margin-inline:auto}
#site .tform{margin-inline:auto;text-align:left}
#site .tform .frow.last{justify-content:center}
#site .fnote{text-align:center}
/* ---- the form -------------------------------------------------------
   Four fields and nothing else. Every field added to a form like this costs
   completions, and the only thing needed to start the conversation the close
   is actually asking for is a name, a way to reply and a sentence of context. */
#site .tform{margin-top:clamp(30px,3.4vw,44px);max-width:660px;display:grid;gap:16px}
/* the "sent" panel replaces the form (Daniel). Hidden until success; the
   `hidden` attribute is enforced explicitly in case a global rule sets display. */
#site .tform[hidden],#site .tsent[hidden]{display:none}
#site .tsent{display:flex;flex-direction:column;align-items:center;gap:18px;
  text-align:center;outline:none;padding:clamp(30px,5vw,64px) 0}
#site .tsent svg{width:44px;height:44px;color:var(--amber)}
#site .tsent p{margin:0;max-width:16em;font-family:var(--display);
  font-weight:var(--dw);font-size:clamp(23px,3vw,33px);line-height:1.2;
  letter-spacing:-.01em;color:var(--tx)}
#site .tform .frow{display:grid;gap:16px;grid-template-columns:1fr}
/* the honeypot is off-screen, not display:none (some bots skip hidden fields) */
#site .tform .hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
#site .tform label{display:grid;gap:7px}
#site .tform label span{font-size:13.5px;letter-spacing:.01em;color:var(--tx2)}
#site .tform input,#site .tform textarea{
  font-family:var(--sans);font-size:16px;font-weight:300;line-height:1.5;
  color:var(--tx);background:rgba(255,255,255,.045);border:0;border-radius:12px;
  padding:13px 15px;width:100%;resize:vertical;
  box-shadow:inset 0 0 0 1px var(--line);transition:box-shadow .22s,background-color .22s}
#site .tform input:hover,#site .tform textarea:hover{background:rgba(255,255,255,.07)}
#site .tform input:focus,#site .tform textarea:focus{outline:none;
  background:rgba(255,255,255,.08);box-shadow:inset 0 0 0 1px var(--amber)}
/* the invalid state only appears AFTER a submit attempt. :invalid on its own
   marks every required field red before the reader has typed a character. */
#site .tform.tried input:invalid,#site .tform.tried textarea:invalid{
  box-shadow:inset 0 0 0 1px #E08A6A}
#site .tform .frow.last{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-top:4px}
#site .tform button{cursor:pointer}
#site .fnote{font-size:14px;line-height:1.5;color:var(--tx2);min-height:1.2em}
#site .fnote.bad{color:#E9A184}
@media (min-width:640px){
  #site .tform .frow{grid-template-columns:1fr 1fr}
  #site .tform .frow.last{grid-template-columns:none}
}
/* NOT a flex container. It was one back when the two spans were its direct
   children; with a .shell between them the shell became a lone flex ITEM,
   shrank to its 486px of content and its auto margins centred that in the
   viewport. The row lives on .shell now, where the children actually are. */
#site footer{border-top:1px solid var(--line);padding-block:34px;
  font-size:14px;color:var(--tx3)}
#site footer .shell{display:flex;justify-content:space-between;
  align-items:flex-end;gap:24px;flex-wrap:wrap}
#site .fbrand{display:grid;gap:15px;justify-items:start}
#site .fmark{display:block;height:16px;width:auto;opacity:.92}
#site .fmail,#site .fbrand span{font-size:14px;color:var(--tx3);letter-spacing:.01em}
#site .fmail{font-family:var(--mono)}
/* the send link only exists once a valid form has been submitted */
#site .fsend{color:var(--amber);text-decoration:none;
  border-bottom:1px solid currentColor;padding-bottom:1px}
/* ================================================================ THE DOOR
   Scaled well down from the last pass: the mark was 74px, the headline ran to
   86px and the buttons were 74px tall, which made a loading screen shout
   louder than the site it was loading. */
/* THE COLD OPEN. The door is Act I's first frame, not a screen in front of it.
   Act I opens on #070B0C with white SANS copy set LEFT over the cloud plate and
   no accent anywhere; the door used to be green, centred, serif and amber, and
   those four mismatches at once are what made the handoff feel like a cut.
   Everything here is measured against that opening, including the ground
   colour, which is Act I's exact value rather than the site's green. */
#door{position:relative;min-height:100svh;overflow:hidden;background:#070B0C}
/* The plate is BLURRED until the reader commits, then resolves as the film
   takes over: the door is the scene out of focus, and "Discover Tenure" pulls
   focus. scale(1.08) is not decoration — a blur samples past the element's
   edges and leaves a soft vignette of background all round it, so the plate
   has to overscan by more than the blur radius. */
#door .plate{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:.92;
  filter:blur(22px);transform:scale(1.08);
  transition:filter 1.15s cubic-bezier(.22,.75,.2,1),transform 1.15s cubic-bezier(.22,.75,.2,1)}
#door.go .plate{filter:blur(0);transform:scale(1)}
/* the copy leaves as the picture arrives */
#door .dtop, #door .dinner{transition:opacity .5s ease,transform .6s cubic-bezier(.22,.75,.2,1)}
#door.go .dtop{opacity:0}
#door.go .dinner{opacity:0;transform:translate(-50%,-56%)}
/* The scrim follows the copy. It was angled to quiet a LEFT column; with the
   block centred it has to pool in the middle instead, or the darkest part of
   the frame sits where there is nothing to read. */
#door .g{position:absolute;inset:0;background:
  radial-gradient(74% 62% at 50% 50%,rgba(7,11,12,.86),rgba(7,11,12,.30) 62%,rgba(7,11,12,0) 100%),
  linear-gradient(rgba(7,11,12,.62),rgba(7,11,12,.28) 40%,rgba(7,11,12,.72));
  transition:opacity .9s ease}
#door.go .g{opacity:.35}
#door .dtop{position:absolute;left:var(--gut);right:var(--gut);top:34px;z-index:5;
  display:flex;justify-content:space-between;align-items:center;gap:20px}
/* was letterspaced mono type standing in for the wordmark. It is the real
   artwork now, so the tracking comes from the file: "never set other words in
   it", and by the same token do not re-space it. */
#door .dwm{display:block;height:18px;width:auto}
#door .dnote{font-family:var(--mono);font-size:10px;letter-spacing:.24em;text-transform:uppercase;
  color:var(--tx3)}
/* Centred on the screen, still set LEFT. The block sits in the middle of the
   viewport and the type is ragged-right inside it, which keeps the reading edge
   of a left-aligned column without stranding it against the glass. */
#door .dinner{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:5;
  width:min(560px,100% - var(--gut)*2);text-align:left}
/* Act I's face, not the site's serif. The film speaks Hanken Grotesk and the
   door is the film's first frame. */
#door .dh{font-family:var(--sans);font-weight:300;font-size:clamp(30px,3.5vw,48px);
  line-height:1.16;letter-spacing:-.022em;margin-bottom:34px}
/* The cycling word sits on its OWN line so its changing width never reflows the
   line above it, and the line has a fixed height so a word that wraps on a
   narrow screen cannot shunt the loader and buttons below it. */
/* The word arrives a LETTER AT A TIME, the way a model streams a reply: each
   character fades up out of a small blur, ~26ms apart, with a caret riding the
   end. The caret does not blink — a steady mark reads as "still writing" and
   this project has hard rules about flicker. */
#door .dcycle{display:block;position:relative;height:1.22em;margin-top:.1em}
/* The cycling word is the SITE's serif while the line above it is the FILM's
   sans. That is the bridge: the door speaks Act I's language, and the one word
   naming what you get control over speaks the brand's.
   The size is MEASURED, and it needs its own clamp rather than an em
   multiplier. Newsreader carries an optical-size axis, so its x-height as a
   fraction of font-size is NOT constant: solving for an x-height match against
   Hanken Grotesk 300 at each end of the headline's clamp gives 1.0899 at 30px
   and 1.0317 at 48px. One `em` value cannot hold both, so this clamp mirrors
   `clamp(30px,3.5vw,48px)` scaled by the multiplier measured at each end.
   x-height is the governing metric because every cycling word is lowercase.
   Measure it with canvas `actualBoundingBoxAscent` at the size that actually
   ships. Two other instruments lied here: `Range.getBoundingClientRect`
   returns the line box rather than glyph ink, and a canvas reading taken at
   100px does not predict a 46px one for a face with an opsz axis. */
#door .dcycle .w{position:absolute;left:0;right:0;top:0;
  color:var(--amber);font-family:var(--display);font-weight:600;
  font-size:clamp(32.7px,3.74vw,49.5px);letter-spacing:-.008em;
  white-space:pre;                     /* "client records" keeps its space */
  visibility:hidden;opacity:1;
  transition:opacity .3s ease}
#door .dcycle .w.on{visibility:visible}
#door .dcycle .w.out{opacity:0}
/* inline-block so each glyph can carry its own transform; the delay is set
   per character in JS so the stagger scales with word length rather than
   being a fixed animation. */
#door .dcycle .w i{display:inline-block;font-style:normal;
  opacity:0;transform:translateY(.18em);filter:blur(4px);
  transition:opacity .24s ease,transform .24s cubic-bezier(.2,.8,.25,1),filter .24s ease}
#door .dcycle .w.in i{opacity:1;transform:none;filter:blur(0)}
#door .dcycle .car{display:inline-block;width:.06em;height:.78em;margin-left:.06em;
  background:var(--amber);vertical-align:-.06em;opacity:0;
  transition:opacity .3s ease}
#door .dcycle .w.in .car{opacity:.9}
#door .dcycle .w.done .car{opacity:0}
/* the loader is CONTAINED under the copy, not run across the page */
#door .dload{display:flex;align-items:center;gap:14px;margin-bottom:32px;
  max-width:min(420px,100%)}
#door .dprog{position:relative;flex:1;height:1px;background:rgba(255,255,255,.17)}
/* scaleX, not width: the fill updates several times a second and a transform
   is composited where a width change is a layout pass. */
#door .dprog i{position:absolute;left:0;top:-1px;height:2px;background:#fff;
  border-radius:2px;width:100%;transform:scaleX(0);transform-origin:0 50%;
  transition:transform .22s linear}
#door .dstat{font-family:var(--mono);font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--tx3);flex:0 0 auto;min-width:4.4em;text-align:right}
#door .dchoices{display:flex;align-items:center;gap:20px;flex-wrap:wrap}
/* White, not amber: the accent on this screen is the cycling word alone, and a
   second warm object would put Act III's temperature on Act I's first frame.
   (The clip-path:none that used to be here is redundant now that nothing on the
   site is clipped at all.) */
#door .btn{height:50px;font-size:15px;padding-left:26px;border-radius:12px}
#door .btn.solid{background:#fff;color:#0A1112}
#door .btn i{width:44px}
#door .btn svg{width:15px;height:15px}
/* #btn-film lives in #door, so scoping this to #site meant it never matched and
   "Discover Tenure" looked live for the whole five-second count. */
#site .btn.wait,#door .btn.wait{opacity:.4;pointer-events:none}
#door .dskip{appearance:none;background:none;border:0;cursor:pointer;font-family:var(--sans);
  font-size:14px;font-weight:400;color:var(--tx3);padding:6px 10px;border-radius:8px;
  transition:color .25s}
#door .dskip:hover{color:var(--tx)}
#door .dskip:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
/* ---- the phone menu -------------------------------------------------------
   The burger and its sheet exist only below 1000px, which is the same line at
   which .nlinks goes. Above it not one rule here applies and the desktop bar is
   byte for byte what it was. */
#site .nburger{display:none}
#site .nsheet{display:none}
@media (max-width:1000px){
  #site .nlinks{display:none}
  /* 46px, not 40: this and .replay were the only two controls on the page under
     the 44px touch minimum. Nothing above 1000px sees either number. */
  #site .nburger{display:grid;place-items:center;appearance:none;border:0;cursor:pointer;
    width:46px;height:46px;border-radius:12px;background:rgba(255,255,255,.06);
    color:rgba(255,255,255,.86);padding:0}
  #site .nburger svg{width:22px;height:22px;display:block}
  #site .nburger:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
  /* The bar has to sit ABOVE the sheet, or the only way to shut the sheet is
     the thing the sheet is covering. It also becomes the close button, so the
     icon swaps with the state rather than needing a second control. */
  #site .nav{z-index:140}
  #site .nburger .i-shut{display:none}
  #site .nburger[aria-expanded="true"] .i-open{display:none}
  #site .nburger[aria-expanded="true"] .i-shut{display:block}
  /* the wordmark stays legible over the sheet, the rest of the bar goes: a
     replay icon next to an open menu that already lists it is noise */
  #site .nav[data-menu="open"]{background:transparent;backdrop-filter:none;
    -webkit-backdrop-filter:none;border-color:transparent}
  #site .nav[data-menu="open"] .replay{display:none}
  #site .replay{width:46px;height:46px}
  /* The tabs are 40px tall by default and that is under the touch minimum. This
     sits at 1000px rather than with the rest of the phone pass at 820, because
     a phone in LANDSCAPE is 852 wide: the 820 rules stop applying and the same
     five buttons went back to 40. Same device, same thumb. */
  #site .dtabs button{min-height:44px;padding-block:11px}
  /* the tooltip is a hover affordance and a phone has no hover; the sheet
     carries the same control as a labelled row instead */
  #site .replay::after{display:none}
  /* The CTA in the bar is 54px tall and ~150px wide next to a wordmark, a
     burger and a replay icon on a 393px screen. The sheet carries it, so the
     bar keeps the mark and the controls. */
  #site .nav .btn.solid{display:none}

  #site .nsheet{display:block;position:fixed;inset:0;z-index:130;
    background:rgba(9,13,15,.72);
    -webkit-backdrop-filter:blur(22px) saturate(115%) brightness(.68);
    backdrop-filter:blur(22px) saturate(115%) brightness(.68);
    opacity:0;pointer-events:none;transition:opacity .28s ease}
  #site .nsheet[hidden]{display:none}
  #site .nsheet.open{opacity:1;pointer-events:auto}
  #site .nsheet-in{position:absolute;left:0;right:0;top:0;bottom:0;
    display:flex;flex-direction:column;justify-content:center;gap:6px;
    padding:104px var(--gut) 40px}
  #site .nsheet a{color:var(--tx);text-decoration:none;font-family:var(--display);
    font-size:clamp(28px,7.4vw,38px);line-height:1.18;padding:14px 0;
    border-bottom:1px solid rgba(255,255,255,.10)}
  #site .nsheet .nsheet-cta{font-family:var(--sans);font-size:15px;border-bottom:0;
    margin-top:26px;align-self:flex-start;height:54px;padding-left:24px}
  #site .nsheet-replay{appearance:none;background:none;border:0;cursor:pointer;
    font-family:var(--sans);font-size:15px;color:var(--tx3);text-align:left;
    padding:16px 0 0;min-height:44px}
  #site .nsheet a:focus-visible,#site .nsheet-replay:focus-visible{
    outline:2px solid var(--amber);outline-offset:3px}
}
@media (prefers-reduced-motion:reduce){
  #site .nsheet{transition:none}
}
@media (max-width:1100px){
  /* the copy stack is centred, so it survives a narrow window on its own; only
     the top pad has to come off, because the nav shrinks with the viewport */
  #sitetop .hwrap{padding-top:96px}
}
@media (max-width:820px){
  /* THE TOP OF THE PAGE, sized for a phone rather than scaled down from a
     desktop. Measured at 393x852 before this: the fixed bar ends at y88 and the
     eyebrow started at y84, so the first thing on the page was tucked under the
     nav; the lockup ran 190x116; and the whole hero came to 948px on an 852px
     screen, so nothing below the paragraph was on the first view.
     84px of top padding was the desktop bar's height carried down. The bar is
     18px from the top and 70px tall, so anything under 108 collides. */
  #sitetop .hwrap{padding-top:124px}
  #sitetop .heyebrow{font-size:11px;letter-spacing:.2em;margin-bottom:4px}
  /* The lockup is the thing being introduced, but at 190px wide and 116 tall it
     was taking a fifth of the screen before a word was read. 150px is the brand
     book's own stated minimum for the stacked form, and 158 keeps clear of it. */
  #sitetop .hlogo img{width:158px}
  #sitetop .hlogo{margin-bottom:18px}
  #sitetop .hline{font-size:clamp(27px,8.4vw,34px);margin-bottom:12px}
  #sitetop .hsub{max-width:30em;font-size:15.5px;line-height:1.5}
  /* Room for the first card to show its top edge on the first screen: a card
     that starts below the fold with no part of it visible does not read as
     "there is more", it reads as the end of the page. */
  /* ---- THE CARDS ARE A CAROUSEL ON A PHONE (Daniel, 7 Aug) ----------------
     Stacked, the three of them ran to nearly three screens and the reader had
     to scroll past all of it to reach the argument. One at a time, snapped, with
     the next one peeking so it is obvious there is more.
     margin-top:auto parks them on the hero's bottom edge, which on a phone
     resolves to zero slack and put the first card's border hard against the
     last line of the paragraph. */
  #sitetop .hcards{margin-top:26px;display:flex;grid-template-columns:none;
    gap:12px;overflow-x:auto;overscroll-behavior-x:contain;
    scroll-snap-type:x mandatory;scrollbar-width:none;padding-block:2px}
  #sitetop .hcards::-webkit-scrollbar{display:none}
  #sitetop .hcard{padding:20px 22px;flex:0 0 84%;scroll-snap-align:center}
  /* THE MISSING BOTTOM EDGE. On desktop the cards deliberately sit on the
     hero's bottom edge; stacked on a phone that reads as the card being cut off
     by the section below it. Measured: the last card's bottom was the section's
     bottom, to the pixel. */
  #sitetop .hdots{display:flex;justify-content:center;gap:0;margin:18px 0 44px}
  /* THE BUTTON IS THE TAP TARGET AND THE DOT IS DRAWN INSIDE IT. The first
     version was a 7px button with a 44px ::before pinned over it, and the hit
     areas of three dots 16px apart overlapped by 28px each: hit-tested, a tap
     on the middle of dot 2 landed on dot 3, because the later sibling paints
     on top. Sizing the buttons themselves makes the targets tile instead. */
  #sitetop .hdots button{appearance:none;border:0;padding:0;cursor:pointer;
    background:none;width:34px;height:44px;position:relative}
  #sitetop .hdots button::after{content:"";position:absolute;left:50%;top:50%;
    width:7px;height:7px;margin:-3.5px 0 0 -3.5px;border-radius:50%;
    background:rgba(255,255,255,.30);
    transition:background .3s ease,transform .3s ease}
  #sitetop .hdots button.on::after{background:rgba(255,255,255,.92);
    transform:scale(1.25)}
  #sitetop .hcard h3{font-size:21px}
  #sitetop .hcard p{font-size:15px;line-height:1.5}
}
@media (max-width:820px){
  #sitetop .hcards{grid-template-columns:1fr;gap:12px;perspective:none}
  #sitetop .hcard{height:auto;min-height:0;padding:22px 24px;transform:none}
  #sitetop .hcard:hover, #sitetop .hcard:focus-visible{transform:translateY(-4px)}
  #sitetop .hcard h3{font-size:23px}
  #sitetop .hcard p{max-width:none}
  #sitetop .hcard .more{position:static;display:inline-block;margin-top:14px}
  #sitetop .hcard .art{display:none}
}
/* ---- the rest of the phone pass -------------------------------------------
   All of it under 820px, so nothing here can reach the desktop layout. */
@media (max-width:820px){
  /* THE NAV IS FIXED AND 70px TALL, and every in-page link lands its target at
     scroll position zero, so each section heading arrived tucked under the bar.
     On desktop the sections are tall enough that it reads as tight; on a phone
     "What we deliver" was clipped by it. scroll-margin-top is the right tool:
     it moves where the scroll STOPS, not where the section is. */
  #site .sec, #site .sec.bleed, #sitetop{scroll-margin-top:96px}

  /* Five tabs wrapped to three ragged rows, which stops reading as a tab bar
     and starts reading as a broken list. One row that scrolls sideways is the
     phone convention, and it keeps the set legible as a set. */
  #site .dtabs{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;
    -webkit-overflow-scrolling:touch;scroll-snap-type:x proximity;
    margin-inline:calc(var(--gut) * -1);padding-inline:var(--gut)}
  #site .dtabs::-webkit-scrollbar{display:none}
  #site .dtabs button{flex:0 0 auto;scroll-snap-align:start}

  /* The figure's last grid row is 1fr so it fills the tallest pane. Stacked,
     there is nothing to fill against and the 480x300 drawing sat in a box with
     a lot of dead air under it. Let it be its own height on a phone. */
  #site .dpane .shot{min-height:0;aspect-ratio:16/10;padding:18px}

  /* THE COMPARISON RESTACKS ON A PHONE. Two columns of 160px is four or five
     words a line and the row stops being readable across, which defeats the
     only reason the table exists. Each row becomes one block: the complaint,
     then its answer, labelled. The <table> markup stays, so it is still
     tabular data to a screen reader. */
  #site .cmp,#site .cmp tbody,#site .cmp tr,#site .cmp td{display:block;width:auto}
  #site .cmp thead{position:absolute;width:1px;height:1px;overflow:hidden;
    clip:rect(0 0 0 0)}
  #site .cmp tr{padding:18px 0;border-bottom:1px solid var(--line)}
  #site .cmp tr:last-child{border-bottom:0}
  /* the desktop 50% and the side padding are on :first-child, which outranks a
     plain `#site .cmp td` rule however late it is declared */
  #site .cmp td,#site .cmp td:first-child,#site .cmp td:last-child{
    width:auto;padding:0;border:0}
  /* just the gap. An indent and a left rule were here too and the reset below
     cancels both, so they were dead declarations pretending to be a design. */
  #site .cmp td+td{margin-top:9px}
  /* the labels the hidden header row would otherwise have carried */
  #site .cmp td::before{content:attr(data-l);display:block;font-family:var(--mono);
    font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;
    color:var(--tx3);margin-bottom:5px}

  /* The form is the one place a phone keyboard is involved. 16px minimum on the
     inputs, because iOS zooms the whole page in on any field below it and the
     reader is then left scrolled sideways on a page that has no sideways. */
  #site .tform input, #site .tform textarea, #site .tform select{font-size:16px}
  #site .tform .btn{width:100%;justify-content:space-between}
}
@media (min-width:940px){
  #site .intro{grid-template-columns:1.1fr 1fr}
  #site .intro .lede{margin-top:0}
}
@media (min-width:900px){
}
/* Two columns, with the frame spanning the full height of the right-hand stack.
   nth-child, not nth-of-type: the children are figure, p, div, div, so counting
   by type would make the first .cap "div 1" and quietly place it in row 1 on
   top of the definition. */
@media (min-width:900px){
  #site .dpane{grid-template-columns:.92fr 1fr;
    grid-template-rows:auto auto auto 1fr;align-items:start;gap:22px 52px}
  /* aspect-ratio off here: side by side the figure should match the height of
     the copy beside it, not impose one of its own. min-height covers the
     shortest pane, whose text column is barely taller than two lines.
     The LAST row is 1fr, not auto, and that matters once the panes are uneven:
     they are stacked on one grid area, so the tallest sets the height of all
     five, and with every row auto the four shorter ones left their figure at
     its own height with dead space under it. 1fr hands the slack to the last
     row, which the figure spans. */
  #site .dpane .shot{grid-column:1;grid-row:1 / span 4;
    align-self:stretch;aspect-ratio:auto;min-height:300px}
  #site .dpane .def{grid-column:2;grid-row:1}
  #site .dpane > :nth-child(3){grid-column:2;grid-row:2}
  #site .dpane > :nth-child(4){grid-column:2;grid-row:3}
  #site .dpane > :nth-child(5){grid-column:2;grid-row:4}
}
@media (min-width:900px){
  #site .fits{grid-template-columns:1fr 1fr}
}
/* ownership goes side by side. The img and the .g gradient are absolutely
   positioned, so they take no grid cell and the two columns are .in and .fig. */
@media (min-width:900px){
  #site .own{grid-template-columns:minmax(0,1.06fr) minmax(0,.94fr);
    align-items:center;gap:clamp(36px,4.6vw,76px)}
}
@media (prefers-reduced-motion:reduce){
  #door .dcycle .w i{opacity:1;transform:none;filter:none;transition:none}
  #door .dcycle .car{display:none}
}
@media (prefers-reduced-motion:reduce){
  #sitetop .hcard{transform:none;transition:none}
  #sitetop .hcard:hover{transform:translateY(-4px)}
  #site .dpane{transition:none}
  #door .dprog i{transition:none}
}

/* ---------------------------------------------------- handoff and modes ---
   The hero is TRANSPARENT so the narrative's fixed #loopv shows through it and
   every section below is opaque so it paints over that same running video.
   One element, never restarted: last frame of the film, first frame of the
   site. That is the whole handoff mechanism. */
#site .sec,#site footer{background:var(--ground);position:relative;z-index:1}
/* The hero must be its OWN stacking context. Without one it has z-index:auto,
   so its glass cards (z 6) and the sections below (z 1) are siblings in the
   root context: the cards paint over the sections and, being translucent by
   design, show the first section's copy straight through themselves. In the
   mock there was nothing behind them and the bug could not appear. */
#sitetop{background:transparent;position:relative;z-index:2;isolation:isolate}

/* the nav arrives WITH the hero. It is fixed, so on the film path it would
   otherwise float over every beat from the moment the site exists. */
#site .nav{opacity:0;transform:translateY(-16px);pointer-events:none;
  transition:opacity .6s ease,transform .7s cubic-bezier(.2,.8,.25,1),
             background-color .4s ease}
#site .nav.here{opacity:1;transform:none;pointer-events:auto}

/* the door sits above the narrative's canvas and video layers (z 1-20) */
#door{position:fixed;inset:0;z-index:400;min-height:100svh}
#door.gone{opacity:0;pointer-events:none;transition:opacity .7s ease}
/* No door on a phone, and no way back into an experience that is not offered
   there: the replay control goes with it, in the bar and in the sheet. */
html.phone #door{display:none!important}
html.phone #site .replay,html.phone #site .nsheet-replay{display:none}
html.door-open,html.door-open body{overflow:hidden;height:100%}
#site{display:none}
html.show-site #site{display:block}
/* Skipping REMOVES the narrative rather than scrolling past it: left in place,
   scrolling up from the site lands in a dead act with no copy and no camera.
   Its canvas and chrome go with it, or the cloud paints over the site's hero
   and the film's wordmark and scroll cue sit on top of the marketing page. */
/* Both "skipped" and "site-only" hide the NARRATIVE BEATS but keep the last
   section, because that section is now the top of the site. Hiding all of
   #act would take the hero with it and leave the page starting on its
   second screen. The canvas and the film chrome go either way. */
html.skipped #act > section:not(:last-child),
html.site-only #act > section:not(:last-child),
html.skipped #sky,html.skipped #nogl,html.skipped .top,html.skipped #scue,
html.skipped #tips,html.skipped #rtips,
html.site-only #sky,html.site-only #nogl,html.site-only .top,
html.site-only #scue,html.site-only #tips,html.site-only #rtips{display:none}
/* on the skip path nothing ever sets .in, so the assembled state is the
   resting state there */
html.skipped #sitetop .htitle,html.skipped #sitetop .hcards,
html.skipped #sitetop .hscrim{
  opacity:1;transform:none;transition:none}

/* ------------------------------------------------- the handoff, assembled
   #sitetop is the last narrative section and the top of the site at once. Its
   parts arrive in sequence as the close comes on, so leaving beat 10 reads as
   the site building itself over the film rather than the film being replaced
   by a page. The narrative already puts `.in` on this section, so the reveal
   rides machinery that is tuned and verified rather than a second timer. */
#sitetop{position:relative;min-height:100svh;width:100%;
  display:flex;flex-direction:column;justify-content:flex-start;overflow:visible}
/* Slower and further apart. WHEN it arrives is right; it was landing in about
   1.2s all told, which reads as a snap rather than an assembly. Roughly double
   the durations and treble the spread between them. */
#sitetop .htitle,#sitetop .hcards{
  opacity:0;transform:translateY(34px);
  transition:opacity 1.5s cubic-bezier(.16,.7,.2,1),transform 1.8s cubic-bezier(.16,.7,.2,1)}
/* the scrim LEADS, by a beat. The frame settles first and the words arrive onto
   a picture that is already calm; bringing them up together reads as the copy
   dragging a panel on behind it. */
.beat.close.assembled #sitetop .hscrim{opacity:1}
.beat.close.assembled #sitetop .htitle{opacity:1;transform:none;transition-delay:.55s}
/* the cards keep their own laid-back rest pose, so only opacity is animated
   here — overriding transform would flatten the flip they are posed for */
.beat.close.assembled #sitetop .hcards{opacity:1;transform:none;transition-delay:1.25s}

/* the close is a narrative beat, so it still carries the film's centring rules;
   the site's top needs the full width instead */
.beat.close#sitetop-host,.beat.close:has(#sitetop){display:block;padding:0}

/* ---------------------------------------------- #sitetop lives in #act -----
   It is the site's top but it sits inside a narrative <section>, so it inherits
   the film's rules: centred flex, the 1180-capped film gutter, and the
   narrative's own link colour. Those are all correct for a beat and all wrong
   for a page header, so they are undone here rather than by loosening the
   narrative. */
.beat.close:has(#sitetop){display:block;padding:0;height:auto;min-height:100svh;
  text-align:left;align-items:stretch}
#sitetop{text-align:left}
#sitetop a{color:inherit}
#sitetop .htitle{text-align:center}
#sitetop .spec,#sitetop .benefit{text-align:left}
/* the film's own chrome has no place once the site has assembled */
html.site-only .top{display:none}
html.site-arriving .top,html.site-arriving #scue{opacity:0;
  transition:opacity .5s ease;pointer-events:none}

/* Snap is the NARRATIVE's. The frame loop used to hold it off, but that loop
   now bails once the reader is on the site — which handed control straight back
   to `html{scroll-snap-type:y mandatory}` in the narrative's stylesheet and put
   mandatory snapping on an ordinary scrolling page. This is the only place that
   can turn it off once nothing is driving it per frame. */
html.site-only,html.skipped{scroll-snap-type:none !important}

/* the door is frosted glass over the LIVE scene, not a picture of it */
html.door-open #sky{filter:blur(22px) saturate(.85) brightness(.72);
  transform:scale(1.06);transition:filter 1.15s cubic-bezier(.22,.75,.2,1),
  transform 1.15s cubic-bezier(.22,.75,.2,1)}
#sky{transition:filter 1.15s cubic-bezier(.22,.75,.2,1),
  transform 1.15s cubic-bezier(.22,.75,.2,1)}

/* The assembly is driven POSITIONALLY by site.js, not by the narrative's `.in`.
   Two bugs came from `.in`: it waits on the film finishing its 9-second travel
   to the last chapter, so the nav arrived on scroll and the rest of the site
   turned up about ten seconds later; and it is removed again as soon as the
   beat index moves on, so scrolling back up found the header there and every
   element gone. `.assembled` is set once and never cleared, because by then
   this is the top of a web page rather than a beat that fades. */
