/* ==========================================================================
   THE SYSTEM — page composition for /system. Named the-system.css, NOT
   system.css: /css/system.css is the shared design system every page loads.
   Two files one letter apart is a bad afternoon, hence the long name.

   Loads AFTER system.css and guarantee.css. Tokens, type, buttons, .sec,
   .wrap, .kicker, .label, the nav and the footer come from system.css; the
   entire guarantee band comes from guarantee.css, which the homepage loads
   too. Nothing here redefines them, and there are no hardcoded colours.

   The page is four sections: hero, the ninety days, the guarantee, the CTA.
   Only the first two are styled in this file. It used to also carry a
   dashboard mock, a three-way comparison table and a second guarantee
   written differently from the homepage's; all three are gone, along with
   the ~180 lines that styled them.

   GROUND RUN: ox → brown → the guarantee's own glow → cream. Inserting a
   section flips every ground below it, so read the run before adding one.
   ========================================================================== */

/* clip, not hidden — overflow:hidden on <body> makes it a scroll container
   and silently kills position:sticky on the header. */
body{overflow-x:clip}

/* ---- HERO ----------------------------------------------------------------
   Copy above, video below, one centred column. The video is the point of this
   page, so it is not pushed into a right-hand column where it ends up 400px
   wide on a laptop.

   GROUND. Cream, and the band below stays oxblood. Two dark bands stacked on
   each other can only ever be separated by a line; a light band against a dark
   one is separated by the whole band, which is the thing that was missing. It
   is also the same inversion the three trade heroes use, so /system is not a
   one-off.

   The video gains more from this than the copy does. A YouTube thumbnail is a
   photograph in a black frame, and a black frame on cream is a hole punched in
   the page — on the old near-black ground the embed's edges dissolved into the
   band and the only thing marking it out was a border we had to draw.

   Layers: a warm oxblood wash blooming off the top so the band is lit rather
   than flat, and a soft floor at the bottom so the cream does not stop dead at
   the seam.                                                                   */
.sys-hero{
  position:relative;overflow:hidden;isolation:isolate;
  background:
    radial-gradient(90% 70% at 50% -16%,color-mix(in srgb,var(--ox) 13%,transparent),transparent 68%),
    radial-gradient(72% 56% at 50% 108%,color-mix(in srgb,var(--ox) 10%,transparent),transparent 72%),
    var(--cream);
  padding:clamp(36px,3.4vw,50px) 0 clamp(34px,3.2vw,46px);
}
/* THE LIGHT. Two soft oxblood washes drifting against each other at different
   speeds and in opposite directions, so they never repeat inside a sitting.
   Slow — 26 and 34 seconds — because a fast gradient is a casino; this one is
   meant to be felt in peripheral vision rather than watched. Much fainter than
   the dark version needed: on cream, a wash you can clearly see is a stain.

   TRANSFORM AND OPACITY ONLY. Both run on the compositor, so a pair of
   minute-long loops under a full band costs nothing per frame. Animating the
   gradient stops themselves would repaint the whole band 60 times a second. */
.sys-hero::before{
  content:"";position:absolute;z-index:-1;pointer-events:none;
  inset:-30% -20%;
  background:
    radial-gradient(38% 42% at 26% 30%,
      color-mix(in srgb,var(--ox) 13%,transparent),transparent 68%),
    radial-gradient(44% 40% at 76% 66%,
      color-mix(in srgb,var(--accent) 62%,transparent),transparent 70%);
  filter:blur(30px);
  animation:sysDrift 26s var(--ease) infinite alternate;
}
.sys-hero .wrap::before{
  content:"";position:absolute;z-index:-1;pointer-events:none;
  inset:-60% -40%;
  background:
    radial-gradient(34% 36% at 78% 22%,
      color-mix(in srgb,var(--ox-2) 11%,transparent),transparent 66%),
    radial-gradient(40% 44% at 18% 80%,
      color-mix(in srgb,var(--accent) 52%,transparent),transparent 72%);
  filter:blur(36px);
  animation:sysDrift2 34s var(--ease) infinite alternate;
}
@keyframes sysDrift{
  from{transform:translate3d(-4%,-3%,0) scale(1);opacity:.8}
  to  {transform:translate3d(5%,4%,0) scale(1.18);opacity:1}
}
@keyframes sysDrift2{
  from{transform:translate3d(4%,2%,0) scale(1.12);opacity:.65}
  to  {transform:translate3d(-5%,-3%,0) scale(1);opacity:1}
}

/* THE SEAM. Cream meeting oxblood is already the hardest edge on the site, so
   there is nothing left to do but draw it cleanly: a solid accent rule on the
   last 3px of the hero. No fade. A fade is what made these two sections read
   as one in the first place. */
.sys-hero::after{
  content:"";position:absolute;z-index:1;inset:auto 0 0;height:3px;
  pointer-events:none;background:var(--ox);
}

/* Centred. The wrap carries the text-align and every block inside it gets an
   auto inline margin — centring the text without centring the boxes leaves
   the h1 and the lede in a left-hand column with centred words in them, which
   looks like a bug. */
.sys-hero>.wrap{position:relative;z-index:1;text-align:center}

/* ---- THE ENTRANCE --------------------------------------------------------
   Four objects rising in sequence: headline, lede, video, button. It is the
   page loading in the order you are meant to read it, and it lands on the
   embed — the thing the whole page exists to get pressed.

   `both` holds the start state before the delay elapses, which is what stops
   all four flashing at full opacity for one frame and then dropping back.
   Total run is 1.0s to the last object; past about 1.2s a visitor notices they
   are waiting for a website to finish being clever.

   CSS, not JS, and not scroll-triggered: this is above the fold on every
   screen, so there is nothing to trigger on.                                 */
.rise{animation:sysRise .7s var(--ease) both}
.sys-hero h1.rise           {animation-delay:.05s}
.sys-hero .lede.rise        {animation-delay:.17s}
.sys-hero .vsl.rise         {animation-delay:.29s}
.sys-hero .sys-hero-actions.rise{animation-delay:.44s}
@keyframes sysRise{
  from{opacity:0;transform:translate3d(0,26px,0)}
  to  {opacity:1;transform:none}
}

/* THE PHRASE. `90 days` is the promise and it was set identically to the six
   words in front of it. Accent, plus a rule that draws itself under the phrase
   once the headline has arrived.

   The underline is a pseudo-element scaled on the x axis, not a border or a
   background-size trick: transform is the only one of the three that animates
   on the compositor, and this runs while the rest of the hero is still moving.
   transform-origin:0 makes it draw left to right like a pen. */
.sys-hero h1 em{
  font-style:normal;position:relative;color:var(--ox);
  white-space:nowrap;
}
.sys-hero h1 em::after{
  content:"";position:absolute;left:0;right:.06em;bottom:-.1em;height:4px;
  background:linear-gradient(90deg,var(--ox),
    color-mix(in srgb,var(--ox) 22%,transparent));
  transform:scaleX(0);transform-origin:0 50%;
  animation:sysUnderline .72s var(--ease) .62s both;
}
@keyframes sysUnderline{from{transform:scaleX(0)}to{transform:scaleX(1)}}
/* ONE LINE, and the max-width is what enforces it. Every pixel the headline
   spends on a second line is a pixel off the video, and the video is the page.
   31 characters at 48px sits inside the wrap on anything wider than a tablet;
   below that the clamp drops it and it wraps to two, which is fine because the
   viewport is tall relative to the embed there. */
.sys-hero h1{
  max-width:30ch;margin-inline:auto;
  font-size:clamp(34px,3.8vw,50px);line-height:1.04;letter-spacing:-.03em;
  color:var(--ink);
}
/* One line. The lede's whole job is to say what pressing play gets you; the
   argument it used to make is the video's argument to make. */
.sys-hero .lede{max-width:52ch;margin:16px auto 0;color:var(--ink-2)}

/* ---- VSL -----------------------------------------------------------------
   aspect-ratio on the wrapper, not the iframe, so the box holds its height
   before the embed loads and the buttons under it don't jump on a slow
   connection. YouTube's own chrome is the play affordance; nothing is drawn
   on top of it.                                                              */
.vsl{
  position:relative;aspect-ratio:16/9;
  /* As wide as the wrap allows, then capped by what is actually left on the
     screen. Everything else in the hero (padding, one-line headline, lede,
     gaps, button) costs a fixed ~344px, so the embed takes the rest and the
     hero fits a screen at any height rather than only at 1440x900. The max()
     floor matters: on a landscape phone the vh term goes negative, and a
     negative max-width is a hidden video. */
  max-width:min(1100px,max(320px,calc((100vh - 344px) * 16 / 9)));
  margin:clamp(24px,2.6vw,34px) auto 0;
  background:var(--ox-deep);
  border:1px solid color-mix(in srgb,var(--ox) 34%,transparent);
  /* Two shadows doing two jobs. The dark one drops the embed off the page —
     it is the one thing on the screen you are supposed to touch, and on cream
     a real cast shadow is what makes an object sit above the paper. The second
     is an oxblood halo that breathes just outside the frame. */
  box-shadow:
    0 30px 64px -26px color-mix(in srgb,var(--ink) 46%,transparent),
    0 0 0 1px color-mix(in srgb,var(--ink) 9%,transparent),
    0 0 58px -14px color-mix(in srgb,var(--ox) 26%,transparent);
  transition:box-shadow .5s var(--ease),border-color .5s var(--ease);
}
/* The halo. A blurred accent rectangle sitting BEHIND the embed and pulsing
   on scale and opacity only, so the whole thing stays on the compositor. It is
   under the iframe (z-index:-1 inside the .vsl stacking context), which means
   it can never intercept the click that this entire page is built around.

   6 seconds, and only between .55 and 1 opacity. A pulse you can consciously
   watch is a distraction from the video; this one is only really visible in
   peripheral vision, which is exactly where an invitation belongs. */
.vsl::before{
  content:"";position:absolute;z-index:-1;inset:-14px;pointer-events:none;
  background:radial-gradient(60% 60% at 50% 50%,
    color-mix(in srgb,var(--ox) 40%,transparent),transparent 72%);
  filter:blur(24px);
  animation:sysHalo 6s var(--ease) infinite alternate;
}
@keyframes sysHalo{
  from{opacity:.5;transform:scale(.98)}
  to  {opacity:1;transform:scale(1.04)}
}
/* Pointer only. A hover lift on a touch screen fires on tap and reads as lag
   on the thing you just pressed. */
@media (hover:hover){
  .vsl:hover{
    border-color:var(--ox);
    box-shadow:
      0 38px 80px -26px color-mix(in srgb,var(--ink) 56%,transparent),
      0 0 0 1px color-mix(in srgb,var(--ox) 22%,transparent),
      0 0 86px -12px color-mix(in srgb,var(--ox) 44%,transparent);
  }
}
.vsl iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}

/* One guard for the whole hero. Everything above animates; with reduced motion
   requested, every element still has to land in its finished state, which is
   why these are `animation:none` on elements whose keyframes end at the
   natural value — and an explicit scaleX(1) on the underline, whose finished
   state is not its authored one. */
@media (prefers-reduced-motion:reduce){
  .sys-hero::before,.sys-hero .wrap::before,.vsl::before,.rise{animation:none}
  .sys-hero h1 em::after{animation:none;transform:scaleX(1)}
  .vsl{transition:none}
}
.sys-hero-actions{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:clamp(16px,3vw,26px);margin-top:clamp(20px,2.2vw,28px);
}
/* The default .btn is cream on oxblood, which on a cream ground is a button
   you cannot see. Inverted here, and the hover states have to be restated in
   full: these selectors are (0,2,0), the same weight as .btn:hover in
   system.css, and they come later in the cascade, so anything not repeated
   simply stops painting. */
.sys-hero .btn{background:var(--ox);color:var(--cream);border-color:var(--ox)}
.sys-hero .btn:hover{background:var(--ink);border-color:var(--ink);color:var(--cream)}
/* There is no line of meta copy under the button. The button is the last
   thing in the hero, full stop — a qualifier printed underneath it is an
   objection nobody had raised yet, and it was the only thing between the
   call to action and the fold. */

/* ---- SECTION HEADS -------------------------------------------------------
   One shape for every section on the page: label, h2, lede.                  */
.sys-head{max-width:64ch}
.sys-head h2{margin:10px 0 0;max-width:20ch}
.sys-head .lede{margin-top:18px;max-width:60ch}

/* ---- THE NINETY DAYS -----------------------------------------------------
   The band's own ground, and it has to be *visibly* its own. The previous
   version was --brown under low-opacity washes, which put it within a few
   percent of the near-black hero directly above it: scrolling out of the hero
   you never crossed an edge, so two separate ideas read as one long page. The
   base is --ox now (the lightest of the three reds) with the vignette doing
   the darkening at the corners, so the middle of the band is clearly lighter
   than the hero floor that meets it.                                         */
.days-sec{
  position:relative;overflow:hidden;
  background:
    radial-gradient(84% 62% at 50% -6%,color-mix(in srgb,var(--ox-2) 92%,transparent),transparent 72%),
    radial-gradient(58% 48% at 88% 100%,color-mix(in srgb,var(--ox-2) 54%,transparent),transparent 76%),
    radial-gradient(120% 100% at 50% 44%,transparent 38%,color-mix(in srgb,var(--ox-deep) 86%,transparent) 100%),
    var(--ox);
}
/* Light spilling down off the cream hero above. No hairline here — the hero's
   own last 3px already draw the edge, and a second line under it would read as
   a rendering seam. */
.days-sec::before{
  content:"";position:absolute;z-index:0;inset:0 0 auto;height:260px;
  pointer-events:none;
  background:linear-gradient(to bottom,
    color-mix(in srgb,var(--accent) 13%,transparent),transparent 72%);
}
.days-sec>.wrap{position:relative;z-index:1}

/* A size up from .sys-head's default and the subject in accent. This is the
   one h2 on the page and it was set at the same weight as a card title two
   rows below it. `ninety days` is the phrase the whole section is about, so
   it is the part that carries the colour. */
.days-head h2{
  max-width:22ch;font-size:clamp(32px,4.2vw,52px);
  line-height:1.02;letter-spacing:-.035em;
}
.days-head h2 em{font-style:normal;color:var(--accent);position:relative;white-space:nowrap}
/* Same drawn rule the hero h1 uses, so the two headlines are recognisably the
   same treatment, but scrubbed by scroll position instead of fired on load —
   the h1 is above the fold and this one is not. */
.days-head h2 em::after{
  content:"";position:absolute;left:0;right:.06em;bottom:-.08em;height:4px;
  background:linear-gradient(90deg,var(--accent),
    color-mix(in srgb,var(--accent) 24%,transparent));
}
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .days-head h2 em::after{
      transform:scaleX(0);transform-origin:0 50%;
      animation:sysUnderline 1s linear both;
      animation-timeline:view();
      animation-range:entry 10% cover 24%;
    }
  }
}

/* Four photo cards. There is no connecting rail any more: the rail existed to
   make four blocks of text read as a sequence, and four dated photographs do
   that far harder than a hairline did. It also had to be positioned at a
   fixed offset from the top of each card, which stops being possible the
   moment the cards start with an image.                                      */
.stages{
  --shot-h:clamp(150px,15vw,208px);
  display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(16px,2.2vw,30px);margin-top:clamp(32px,4vw,48px);
}
/* margin:0 is load-bearing — the UA sheet gives <figure> 1em 40px, which takes
   80px out of the card before anything else is measured. Same trap as
   .trade-shot and .trade-tile in trade.css. */
/* ROUNDED, LIFTED, AND OFF THE LINE. The row used to be four hard-cornered
   rectangles with their tops at exactly the same y, which is as rigid as a
   layout gets: a ruler with pictures on it.

   Three changes, none of them decoration for its own sake:
     1. A radius, so the frames read as objects rather than as holes cut in the
        page. Same 8px the buttons use.
     2. A cast shadow. The cards sit ON the band now, which is what gives the
        row any depth at all in a section with no other z-axis.
     3. The stagger below, which is the one that actually kills the rigidity.
   margin:0 is load-bearing — the UA sheet gives <figure> 1em 40px, which takes
   80px out of the card before anything else is measured. Same trap as
   .trade-shot and .trade-tile in trade.css. */
.stage-shot{
  position:relative;margin:0;overflow:hidden;
  border:1px solid color-mix(in srgb,var(--sand) 13%,transparent);
  border-radius:10px;
  background:var(--ox-deep);
  box-shadow:
    0 2px 6px -3px color-mix(in srgb,var(--ink) 70%,transparent),
    0 18px 34px -20px color-mix(in srgb,var(--ink) 80%,transparent);
  transition:border-color .45s var(--ease),box-shadow .45s var(--ease);
}
/* THE STAGGER. Cards 2 and 4 ride low, so the four tops sit on two levels
   instead of one. A margin, not a transform: a transform would leave the
   cards overlapping the heading's whitespace budget while the grid still
   measured them flush, and the section's height has to stay honest.

   It drops to 0 at 1000 where the grid goes 2-up, because at two columns the
   stagger stops reading as rhythm and starts reading as a broken row. */
.stages .stage:nth-child(even){margin-top:clamp(14px,1.8vw,26px)}
@media (max-width:1000px){.stages .stage:nth-child(even){margin-top:0}}
/* The cards arrive one after another as the band comes up the screen, which
   is the thing that makes a row of four read as a sequence rather than a grid.
   animation-timeline is behind @supports on purpose: where it is unsupported
   the rule never applies and the cards are simply there, which is the correct
   fallback. Never gate this on JS — the content must not depend on it. */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .stage{
      animation:stageIn .8s var(--ease) both;
      animation-timeline:view();
      animation-range:entry 4% cover 26%;
    }
    .stages .stage:nth-child(2){animation-range:entry 4% cover 30%}
    .stages .stage:nth-child(3){animation-range:entry 4% cover 34%}
    .stages .stage:nth-child(4){animation-range:entry 4% cover 38%}
  }
}
@keyframes stageIn{
  from{opacity:0;transform:translate3d(0,34px,0)}
  to  {opacity:1;transform:none}
}
/* All four source files are tall portraits going into a ~270x208 landscape
   box, which is a heavy crop: object-fit:cover throws away roughly two thirds
   of the frame's height. Centred, that lands on empty sky in two of them and
   on the subject's knees in a third, so each card sets its own --pos below.
   The fallback is centre, which is right for a photo nobody has tuned yet. */
.stage-shot img{
  display:block;width:100%;height:var(--shot-h);object-fit:cover;
  object-position:var(--pos,50% 50%);
  /* --zoom is a second crop control for the two shots that were taken from
     further back than the others. object-position can only slide the frame
     around; it cannot make a man standing 40 feet away read at the same size
     as one photographed at arm's length, and four cards in a row where one
     subject is a third the size of the others looks like a mistake. The figure
     already clips, so scaling inside it is free. */
  transform:scale(var(--zoom,1));transform-origin:var(--pos,50% 50%);
  /* These are daylight photographs dropped onto a warm dark page. Straight out
     of the file the greens and skies fight the palette; knocking the
     saturation back and lifting contrast lets them sit in it. */
  filter:saturate(.72) contrast(1.06) brightness(.92);
  transition:transform .6s var(--ease),filter .6s var(--ease);
}
/* Hover pushes the zoom a step further and lets the daylight back into the
   photograph. The scale is on the same property the crop already uses, so
   hovering cannot shift the framing — only tighten it. */
@media (hover:hover){
  .stage:hover .stage-shot{
    border-color:color-mix(in srgb,var(--accent) 58%,transparent);
    box-shadow:
      0 4px 10px -4px color-mix(in srgb,var(--ink) 74%,transparent),
      0 26px 46px -22px color-mix(in srgb,var(--ink) 84%,transparent),
      0 0 40px -10px color-mix(in srgb,var(--accent) 38%,transparent);
  }
  .stage:hover .stage-shot img{
    transform:scale(calc(var(--zoom,1) * 1.06));
    filter:saturate(.86) contrast(1.06) brightness(1);
  }
}
/* Tuned per photograph against the actual crop at 1440. In order:
   01 the HVAC tech kneeling at the condenser — face sits high in the frame
   02 the two-man roofing crew on the deck — shot from the ground and from far
      enough back that the pair are small; zoomed onto the near man
   03 the HVAC tech on the gauges — face is near the top edge
   04 the roofer walking the ridge — two thirds of that file is open sky, and
      the sky is the one genuinely saturated blue in the set, so the crop is
      pushed down onto the roofline and tightened */
.stages .stage:nth-child(1) .stage-shot img{--pos:52% 40%}
.stages .stage:nth-child(2) .stage-shot img{--pos:32% 62%;--zoom:2.1}
.stages .stage:nth-child(3) .stage-shot img{--pos:46% 26%}
.stages .stage:nth-child(4) .stage-shot img{--pos:47% 46%;--zoom:1.2}
/* A warm wash over the photo so all four read as one set regardless of what
   the light was doing on the day, plus a floor under the chip so the chip is
   never fighting a bright patch of sky. */
.stage-shot::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(to top,color-mix(in srgb,var(--ox-deep) 82%,transparent) 0%,
      transparent 52%),
    linear-gradient(0deg,color-mix(in srgb,var(--ox) 26%,transparent),
      color-mix(in srgb,var(--ox) 26%,transparent));
}

/* THE DAY RANGE. The loudest element in the section. Filled accent with ink
   text — ~13:1, and the only solid accent block on the page outside a button,
   which is the point: a skimmer who reads nothing else reads these four.
   z-index clears the ::after wash above. */
.stage-when{
  /* Inset and rounded now, not welded into the bottom-left corner. A square
     chip flush to two edges of a square frame is the single most rigid thing
     in the row; floating it off the corner by 10px turns it into a label ON
     the photograph instead of a notch cut out of it. */
  position:absolute;z-index:1;left:10px;bottom:10px;
  padding:7px 13px 6px;border-radius:6px;
  background:var(--accent);color:var(--ink);
  box-shadow:0 4px 12px -4px color-mix(in srgb,var(--ink) 74%,transparent);
  font-weight:900;font-size:12.5px;letter-spacing:.11em;text-transform:uppercase;
  font-variant-numeric:tabular-nums;white-space:nowrap;
}
/* The last card is the outcome, not another step — the whole frame is lit
   rather than the chip being restyled, so the four chips stay identical and
   comparable. */
.stage--end .stage-shot{
  border-color:color-mix(in srgb,var(--accent) 46%,transparent);
  /* The payoff card gets a standing glow rather than a different chip or a
     different border weight, so the four frames stay comparable while the eye
     still knows where the row is going. */
  box-shadow:
    0 2px 6px -3px color-mix(in srgb,var(--ink) 70%,transparent),
    0 18px 34px -20px color-mix(in srgb,var(--ink) 80%,transparent),
    0 0 42px -14px color-mix(in srgb,var(--accent) 40%,transparent);
}

/* The step number, paired with a short accent rule. It was a lone 11px grey
   line doing nothing but taking up a row; the rule beside it is what makes
   each card start with a mark instead of with grey text. */
.stage-n{
  display:flex;align-items:center;gap:9px;margin-top:16px;
  font-weight:800;font-size:11px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--accent);font-variant-numeric:tabular-nums;
}
.stage-n::after{
  content:"";flex:0 0 auto;width:22px;height:1px;
  background:linear-gradient(90deg,
    color-mix(in srgb,var(--accent) 70%,transparent),transparent);
}
.stage h3{margin:6px 0 .45em;font-size:clamp(17px,1.7vw,21px);line-height:1.2}
.stage p{margin:0;font-size:14.5px;line-height:1.6;color:var(--sand-2)}

/* Two-up before one-up. Four cards stacked on a tablet is a very long section
   for four sentences, and the photos hold their crop fine at half width. */
@media (max-width:1000px){.stages{grid-template-columns:repeat(2,minmax(0,1fr));gap:clamp(20px,3vw,30px)}}
@media (max-width:600px){
  .stages{grid-template-columns:1fr;--shot-h:190px}
}
