/* ==========================================================================
   JP Global Engineering — service pages
   Direction: THE INSTRUMENT ROOM.

   The rest of the site is a field at first light: bone paper, olive ink, warm
   sun. These four pages are the other half of the same company — the graphite
   room where the systems are drawn, wired and read. So the ground goes to a
   warm near-black, the type system stays exactly as it is (Fraunces for the
   headlines, Hanken for the reading, Plex Mono for anything a machine would
   have printed), and each service is given one restrained accent to live by.

   The accent is a variable, not a palette. Every rule below is written against
   --sv, so a page declares its colour once on <body> and the whole document
   follows. That is what stops four pages becoming four designs.
   ========================================================================== */

/* `.svblock` carries the same tokens as the body scope, so one graphite
   section can be dropped into a page that is otherwise bone — which is how the
   data-to-decision stage moved across to the Smart Agriculture page without
   restyling everything around it. */
body.svc,.svblock{
  --gr-0:#0D0F0B;      /* the ground */
  --gr-1:#12150F;      /* a band that steps forward */
  --gr-2:#191D14;      /* panels and cards */
  --gr-3:#222719;      /* a raised edge */
  --gr-text:#F2ECE1;   /* warm white, never pure */
  --gr-text-2:#A5A897;
  --gr-text-3:#8A8E77;   /* lifted to clear 4.5:1 on the ground: it carries
                            the small mono labels, which are under the large-text size */
  --gr-line:rgba(242,236,225,.13);
  --gr-line-2:rgba(242,236,225,.24);

  /* overridden per service, below */
  --sv:#C9A96B;
  --sv-soft:rgba(201,169,107,.16);
  --sv-glow:rgba(201,169,107,.42);

  background:var(--gr-0);
  color:var(--gr-text);
}
body.svc-solar,.svc-solar     {--sv:#E5A63F;--sv-soft:rgba(229,166,63,.15);--sv-glow:rgba(229,166,63,.40)}
body.svc-electrical,.svc-electrical{--sv:#9AA684;--sv-soft:rgba(154,166,132,.13);--sv-glow:rgba(154,166,132,.34)}
body.svc-greenhouse,.svc-greenhouse{--sv:#93B25C;--sv-soft:rgba(147,178,92,.14);--sv-glow:rgba(147,178,92,.38)}
body.svc-training,.svc-training  {--sv:#6FA3C8;--sv-soft:rgba(111,163,200,.14);--sv-glow:rgba(111,163,200,.38)}

.svblock{position:relative;overflow:visible;isolation:isolate;
  background:var(--gr-0);color:var(--gr-text)}
.svblock a{color:inherit}
.svblock .sec{background:var(--gr-0);color:var(--gr-text)}
.svblock .sec.alt{background:var(--gr-1)}
.svblock h1,.svblock h2,.svblock h3,.svblock h4{color:var(--gr-text)}
.svblock .kicker{color:var(--sv)}
.svblock .lede{color:var(--gr-text-2)}
.svblock .btn-2{border-color:var(--gr-line-2);color:var(--gr-text)}
.svblock .btn-2:hover{border-color:var(--gr-text)}
.svblock ::selection{background:var(--sv);color:#0D0F0B}

/* the dotted field over the whole site is tuned for bone; on graphite it needs
   to be light, or it reads as dirt on the screen */
body.svc .env::after{
  background-image:radial-gradient(rgba(242,236,225,.055) .5px,transparent .5px);
  opacity:.8;
}

/* ------------------------------ shared shell ------------------------------ */
body.svc main{background:var(--gr-0)}
body.svc .sec{background:var(--gr-0);color:var(--gr-text)}
body.svc .sec.alt{background:var(--gr-1)}
body.svc h1,body.svc h2,body.svc h3,body.svc h4{color:var(--gr-text)}
body.svc .kicker{color:var(--sv)}
body.svc .lede{color:var(--gr-text-2)}
body.svc .rule{background:var(--gr-line)}
body.svc .btn-2{border-color:var(--gr-line-2);color:var(--gr-text)}
body.svc .btn-2:hover{border-color:var(--gr-text)}
body.svc ::selection{background:var(--sv);color:#0D0F0B}

/* the top bar sits on the page, so it has to belong to it */
body.svc .nav{color:var(--gr-text)}
body.svc .nav.solid{
  background:rgba(13,15,11,.88);border-bottom-color:var(--gr-line);
  backdrop-filter:blur(18px) saturate(1.1);-webkit-backdrop-filter:blur(18px) saturate(1.1)}
body.svc .nav .brand img{filter:brightness(1.16)}
body.svc .nav .pg:hover,body.svc .nav .pg[aria-expanded="true"]{background:rgba(242,236,225,.12)}
body.svc .nav.menu-open{background:var(--gr-0);border-bottom-color:var(--gr-line);color:var(--gr-text)}

/* ------------------------------ landing hero ------------------------------ */
/* Two viewports tall with the frame stuck to the top of the first, so the
   opening camera move has somewhere to happen. Played over a single screenful
   it was always still moving when the section left, which is what made it feel
   rushed: the reader arrived at the next section mid-shot. */
.svhero{position:relative;min-height:200svh;overflow:visible;background:var(--gr-0)}
/* The copy sits at the foot of the hero, but it is pushed there with an auto
   margin rather than align-items:flex-end. The two look identical while the
   copy fits. When it does not — a long headline, a four line note, a short
   viewport — a flex-end item overflows upward, out of its own padding and
   under the bar, which is how the greenhouse kicker ended up sitting on the
   logo. An auto margin collapses to zero instead, so the overflow goes
   downward, where the section is already clipping it. */
.svheropin{
  position:sticky;top:0;height:100svh;min-height:560px;overflow:hidden;
  display:flex;align-items:flex-start;
  padding:calc(var(--nav-h) + 40px) var(--pad) clamp(56px,10vh,110px)}
/* the selector has to out-rank .svhero .wrap, which sets the margin shorthand
   further down and would otherwise reset this back to zero */
.svhero .svheropin > .wrap{margin-top:auto}
.svhero canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
.svheropin::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(13,15,11,.72) 0%,rgba(13,15,11,0) 34%,
             rgba(13,15,11,.35) 66%,rgba(13,15,11,.94) 100%)}
.svhero .wrap{position:relative;z-index:2;width:100%;max-width:var(--maxw);margin:0 auto}
.svhero .h1{
  font-size:clamp(2.8rem,7.6vw,6.6rem);line-height:.98;letter-spacing:-.03em;max-width:15ch;
  text-shadow:var(--tshadow)}
.svhero .lede{max-width:52ch;color:var(--gr-text-2)}
.svheronote{
  margin-top:clamp(34px,5vh,58px);padding-top:22px;border-top:1px solid var(--gr-line);
  display:flex;flex-wrap:wrap;gap:clamp(18px,4vw,54px);
  font-family:var(--mono);font-size:10.5px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--gr-text-3)}
.svheronote b{color:var(--sv);font-weight:400}

/* ------------------------------ the four service cards ------------------------------
   These are the only cards on the site that move in depth. Each one is a plane
   inside its own small perspective, tipped toward the pointer, with the layers
   inside it standing at different distances so the movement reads as depth and
   not as a wobble. Touch devices get none of it: there is no pointer to follow,
   and a card that tilts on tap just looks broken. */
.svcards{
  display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(14px,1.8vw,26px);
  margin-top:clamp(40px,6vh,72px)}
@media (max-width:900px){.svcards{grid-template-columns:1fr}}

.svcard{
  position:relative;display:block;text-decoration:none;color:inherit;
  border-radius:20px;overflow:hidden;isolation:isolate;
  background:var(--gr-2);border:1px solid var(--gr-line);
  min-height:clamp(360px,46vh,470px);
  perspective:900px;
  transition:border-color .5s var(--ease),box-shadow .6s var(--ease),
             transform .6s var(--ease),background .5s var(--ease)}
.svcard .plane{
  position:absolute;inset:0;transform-style:preserve-3d;
  transform:rotateX(calc(var(--ty,0) * -3.4deg)) rotateY(calc(var(--tx,0) * 4.2deg));
  transition:transform .5s var(--ease)}
.svcard .shot{position:absolute;inset:0;overflow:hidden}
.svcard .shot img{
  width:100%;height:100%;object-fit:cover;opacity:.34;
  transform:scale(1.08) translate3d(calc(var(--tx,0) * -9px),calc(var(--ty,0) * -9px),0);
  filter:grayscale(.35) contrast(1.06);
  transition:opacity .7s var(--ease),transform .7s var(--ease),filter .7s var(--ease)}
.svcard .shot::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(160deg,rgba(13,15,11,.42) 0%,rgba(13,15,11,.8) 52%,rgba(13,15,11,.96) 100%)}
.svcard .body{
  position:relative;height:100%;display:flex;flex-direction:column;justify-content:flex-end;
  padding:clamp(24px,3vw,38px);gap:12px;transform:translateZ(34px);
  /* the number is absolutely placed in this same corner, so the copy keeps a
     row clear for it however tall the card's own content grows */
  padding-top:calc(clamp(24px,3vw,38px) + 36px)}
.svcard .no{
  font-family:var(--mono);font-size:11px;letter-spacing:.2em;color:var(--sv);
  position:absolute;top:clamp(24px,3vw,38px);left:clamp(24px,3vw,38px);
  transform:translateZ(20px)}
.svcard h3{
  font-size:clamp(1.55rem,2.7vw,2.35rem);letter-spacing:-.02em;max-width:14ch;line-height:1.04}
.svcard p{color:var(--gr-text-2);font-size:.95rem;max-width:38ch}
/* the technical line only exists once the card is being looked at */
.svcard .spec{
  display:flex;flex-wrap:wrap;gap:6px 14px;margin-top:4px;
  font-family:var(--mono);font-size:10px;letter-spacing:.15em;text-transform:uppercase;
  color:var(--gr-text-3);
  opacity:0;transform:translateY(8px);
  transition:opacity .5s var(--ease),transform .5s var(--ease)}
.svcard .cta{
  margin-top:8px;font-family:var(--body);font-size:13px;font-weight:600;letter-spacing:.01em;
  color:var(--gr-text-3);display:inline-flex;align-items:center;gap:9px;
  transition:color .4s var(--ease),gap .4s var(--ease)}
.svcard .cta::after{content:"→";transition:transform .4s var(--ease)}
/* a hairline that draws itself along the top edge, the way a system comes up */
.svcard .lit{
  position:absolute;top:0;left:0;right:0;height:1px;background:var(--sv);
  transform:scaleX(0);transform-origin:0 50%;
  transition:transform .8s var(--ease)}

.svcard:hover,.svcard:focus-visible{
  border-color:var(--gr-line-2);background:var(--gr-3);
  transform:translateY(-4px);
  box-shadow:0 28px 70px -40px rgba(0,0,0,.9),0 0 0 1px var(--sv-soft)}
.svcard:hover .shot img,.svcard:focus-visible .shot img{
  opacity:.5;filter:grayscale(0) contrast(1.02);
  transform:scale(1.12) translate3d(calc(var(--tx,0) * -14px),calc(var(--ty,0) * -14px),0)}
.svcard:hover .spec,.svcard:focus-visible .spec{opacity:1;transform:none}
.svcard:hover .cta,.svcard:focus-visible .cta{color:var(--sv);gap:13px}
.svcard:hover .cta::after,.svcard:focus-visible .cta::after{transform:translateX(3px)}
.svcard:hover .lit,.svcard:focus-visible .lit{transform:none}

/* the one card with nothing behind it yet says so, and stops pretending */
.svcard.soon{background:transparent;border-style:dashed}
.svcard.soon .no,.svcard.soon .cta{color:var(--gr-text-3)}
.svcard.soon h3{color:var(--gr-text-2)}
.svcard.soon:hover{transform:none;box-shadow:none;background:rgba(242,236,225,.03)}
.svcard.soon .lit{display:none}
.svbadge{
  display:inline-flex;align-items:center;gap:8px;align-self:flex-start;
  font-family:var(--mono);font-size:10px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--gr-text-3);border:1px solid var(--gr-line);border-radius:999px;padding:6px 13px}
.svbadge::before{content:"";width:5px;height:5px;border-radius:50%;background:var(--gr-text-3)}

@media (hover:none){
  .svcard .plane{transform:none}
  .svcard .spec{opacity:1;transform:none}
  .svcard .cta{color:var(--sv)}
}

/* ------------------------------ a pinned 3D stage ------------------------------
   Every cinematic section on these pages is the same shape: a tall section, a
   stage stuck to the top of the viewport inside it, and a canvas that is handed
   a number from 0 to 1 for how far through that pinned stretch the reader is.

   overflow must stay visible here. .sec sets overflow:hidden, and a sticky child
   cannot pin inside a clipping ancestor — it silently scrolls away instead, and
   the scene animates off screen where nobody sees it. */
.svstage{
  position:relative;padding:0;overflow:visible;background:var(--gr-0);
  min-height:var(--travel,320svh)}
.svstage.tall{--travel:400svh}
.svstage.short{--travel:250svh}
.svpin{
  position:sticky;top:0;height:100svh;min-height:520px;overflow:hidden;
  display:grid;place-items:center}
.svpin canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
.svpin .veil{
  position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(120% 80% at 50% 46%,transparent 38%,rgba(13,15,11,.72) 100%)}

/* the copy that rides over a pinned scene */
/* Full height on purpose. It used to be a zero-height box centred in the frame,
   which meant the narrow-screen rule below positioned the copy against nothing
   and dropped it just above the middle instead of at the foot of the stage. */
.svover{
  position:absolute;left:50%;top:0;transform:translateX(-50%);
  height:100%;z-index:3;width:min(var(--maxw),100% - var(--pad)*2);
  pointer-events:none}
/* The scene behind this is detailed now, and detail is what makes overlaid
   type hard to read. Each caption carries its own gradient ground, fading out
   toward the middle of the frame so the model is never boxed in by a panel. */
.svover .step{
  position:absolute;left:0;top:50%;max-width:32ch;
  padding:20px clamp(30px,4vw,64px) 22px 0;
  transform:translateY(calc(-50% + 22px));
  background:linear-gradient(90deg,rgba(13,15,11,.9) 0%,rgba(13,15,11,.78) 46%,
             rgba(13,15,11,0) 100%);
  opacity:0;transition:opacity .6s var(--ease),transform .7s var(--ease)}
.svover .step.on{opacity:1;transform:translateY(-50%)}
.svover .step.right{
  left:auto;right:0;text-align:right;padding:20px 0 22px clamp(30px,4vw,64px);
  background:linear-gradient(270deg,rgba(13,15,11,.9) 0%,rgba(13,15,11,.78) 46%,
             rgba(13,15,11,0) 100%)}
.svover .step .kicker{margin-bottom:14px}
.svover .step.right .kicker{justify-content:flex-end}
.svover .step.right .kicker::before{order:2}
.svover .step h3{
  font-size:clamp(1.5rem,3vw,2.5rem);letter-spacing:-.02em;line-height:1.06;
  text-shadow:0 2px 30px rgba(13,15,11,.9)}
.svover .step p{
  margin-top:14px;color:var(--gr-text-2);font-size:.98rem;
  text-shadow:0 2px 18px rgba(13,15,11,.9)}
@media (max-width:820px){
  .svover .step,.svover .step.right{
    left:0;right:auto;text-align:left;top:auto;bottom:clamp(60px,10vh,110px);
    transform:translateY(18px);max-width:100%;padding:18px 0 20px;
    background:linear-gradient(0deg,rgba(13,15,11,.94) 0%,rgba(13,15,11,.8) 62%,
               rgba(13,15,11,0) 100%)}
  .svover .step.on{transform:none}
  .svover .step.right .kicker{justify-content:flex-start}
  .svover .step.right .kicker::before{order:0}
}

/* the caption a pinned scene keeps in the corner */
.svhud{
  position:absolute;left:var(--pad);right:var(--pad);bottom:clamp(26px,4vh,46px);
  z-index:3;display:flex;align-items:flex-end;justify-content:space-between;gap:20px;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--gr-text-3);pointer-events:none}
.svhud b{color:var(--sv);font-weight:400}
.svhud .bar{
  flex:0 0 clamp(90px,16vw,220px);height:1px;background:var(--gr-line);position:relative}
.svhud .bar i{
  position:absolute;left:0;top:0;bottom:0;background:var(--sv);
  transform:scaleX(var(--p,0));transform-origin:0 50%;display:block}

/* the cue that tells a reader the scroll is the control */
.svcue{
  position:absolute;left:50%;bottom:clamp(18px,3vh,30px);transform:translateX(-50%);
  z-index:3;font-family:var(--mono);font-size:10px;letter-spacing:.24em;text-transform:uppercase;
  color:var(--gr-text-3);display:flex;align-items:center;gap:10px;pointer-events:none;
  transition:opacity .6s var(--ease)}
.svcue i{font-style:normal;animation:svbob 2.4s var(--ease) infinite}
@keyframes svbob{0%,100%{transform:translateY(0);opacity:.5}50%{transform:translateY(5px);opacity:1}}
.svcue.gone{opacity:0}

/* ------------------------------ exploded layers ------------------------------
   Six planes seen at a shallow angle, drawing apart as the reader scrolls. The
   separation is one custom property fed in by the scroll, so the whole diagram
   is six divs and no canvas: it prints, it copies, and a screen reader gets a
   list of the layers in order.

   Every plane is named on the plane. Without that the only layer a reader can
   identify is whichever one the side copy happens to be describing, and the
   other five are grey rectangles. The names sit to the left and the copy sits
   to the right, so the two can never land on each other.

   Each plan is drawn on one shared footprint: the probes on layer three sit
   where the bags on layer two are, and the radio links on four reach exactly
   those probes, so the stack lines up as one building when it closes. */
.svlayers{
  /* Absolute, not in flow. .svpin is a grid, and a second in-flow child takes
     a second row: the diagram got the top half of the frame and the copy got
     the bottom half, where it ran off the screen. */
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:min(940px,92vw);height:clamp(340px,52vh,500px);
  perspective:1800px;perspective-origin:50% 50%;pointer-events:none}
.svlayers .layer{
  position:absolute;left:50%;top:50%;width:min(500px,54vw);height:min(268px,29vw);
  margin:calc(min(268px,29vw) / -2) 0 0 calc(min(500px,54vw) / -2);
  transform-style:preserve-3d;
  /* The gap has to beat the plane's own foreshortened height or the sheets land
     on one another, and the whole stack has to stay inside the frame, so it is
     tied to viewport height rather than fixed. */
  transform:translateY(calc((var(--i) - 2.5) * (24px + var(--t,0) * clamp(72px,10.8vh,112px))))
            translateZ(calc((var(--i) - 2.5) * var(--t,0) * -22px))}
.svlayers .pl{
  position:absolute;inset:0;border-radius:14px;
  border:1px solid var(--gr-line-2);background:rgba(23,27,19,.72);
  color:rgba(242,236,225,.5);
  /* 74deg foreshortened the planes so far that the plan on each one collapsed
     to a smear; this still reads as a horizontal layer but shows enough of the
     face for the drawing on it to be legible */
  transform:rotateX(62deg);
  box-shadow:0 30px 60px -40px rgba(0,0,0,.9);
  transition:border-color .5s var(--ease),background .5s var(--ease),
             box-shadow .5s var(--ease),color .5s var(--ease)}
/* the drawing takes its colour from the plane, so the live layer lights its own
   plan rather than being outlined and left blank inside */
.svlayers .pl svg{
  position:absolute;inset:8px;width:calc(100% - 16px);height:calc(100% - 16px);
  overflow:visible}
.svlayers .layer.on .pl{
  border-color:var(--sv);background:rgba(34,40,24,.82);color:var(--sv);
  box-shadow:0 34px 80px -30px var(--sv-glow)}

/* the name of the plane: upright, never rotated with it, and always readable */
.svlayers .lb{
  position:absolute;right:calc(100% + clamp(12px,1.6vw,30px));top:50%;
  transform:translateY(-50%);
  display:flex;align-items:baseline;gap:9px;white-space:nowrap;
  font-family:var(--mono);font-size:clamp(9.5px,0.78vw,11.5px);
  letter-spacing:.16em;text-transform:uppercase;
  color:var(--gr-text-3);
  /* Closed, the six names pile up on top of each other. They fade in with the
     separation that gives them somewhere to sit; the live one is always shown,
     because that is the layer the copy is talking about. */
  opacity:calc(var(--t,0) * 1.8 - 0.2);
  transition:color .45s var(--ease)}
.svlayers .lb i{font-style:normal;opacity:.55}
/* a rule running from the name to the edge of its plane, so it is obvious which
   name belongs to which sheet */
.svlayers .lb::after{
  content:"";position:absolute;left:calc(100% + 6px);top:50%;
  width:clamp(8px,1.2vw,22px);height:1px;background:currentColor;opacity:.5}
.svlayers .layer.on .lb{color:var(--sv);opacity:1}
.svlayers .layer.on .lb i{opacity:1}

@media (max-width:900px){
  /* the copy drops to the bottom of the frame on narrow screens, so the stack
     moves up out of its way and the plane narrows to leave room for its name */
  .svlayers{width:min(460px,94vw);height:clamp(260px,38vh,360px);top:40%}
  .svlayers .layer{width:min(300px,58vw);height:min(175px,33.8vw);
    margin:calc(min(175px,33.8vw) / -2) 0 0 calc(min(300px,58vw) / -2);
    transform:translateY(calc((var(--i) - 2.5) * (16px + var(--t,0) * clamp(44px,7vh,64px))))
              translateZ(calc((var(--i) - 2.5) * var(--t,0) * -12px))}
  .svlayers .lb{font-size:9.5px;letter-spacing:.08em;gap:0;
    right:calc(100% + 9px)}
  .svlayers .lb b{display:none}
  .svlayers .lb i{opacity:.8}
  .svlayers .lb::after{display:none}
}

/* ------------------------------ blueprint plate ------------------------------ */
.svplate{
  border:1px solid var(--gr-line);border-radius:16px;background:rgba(25,29,20,.72);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  padding:clamp(18px,2.2vw,26px)}
.svplate .hd{
  font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--sv);margin-bottom:12px}
.svrow{
  display:flex;justify-content:space-between;gap:18px;padding:9px 0;
  border-top:1px solid var(--gr-line);font-size:.9rem}
.svrow:first-of-type{border-top:0}
.svrow dt{color:var(--gr-text-3);font-family:var(--mono);font-size:10.5px;
  letter-spacing:.13em;text-transform:uppercase}
.svrow dd{margin:0;color:var(--gr-text);text-align:right;font-variant-numeric:tabular-nums}

/* ------------------------------ the solutions orbit ------------------------------
   Eleven nodes on a ring the reader can turn. They are real links in the DOM,
   placed by transform rather than drawn, so every one of them is reachable by
   keyboard and readable by a screen reader — which is the whole reason this is
   not a canvas. */
.svorbit{
  position:relative;margin-top:clamp(44px,7vh,86px);
  height:clamp(460px,64vh,640px);
  perspective:1400px;perspective-origin:50% 48%}
.svorbit .ring{position:absolute;inset:0;transform-style:preserve-3d}
.svorbit .core{
  position:absolute;left:50%;top:50%;width:clamp(150px,17vw,220px);height:clamp(150px,17vw,220px);
  margin:calc(clamp(150px,17vw,220px) / -2) 0 0 calc(clamp(150px,17vw,220px) / -2);
  border-radius:50%;display:grid;place-items:center;text-align:center;
  background:radial-gradient(circle at 42% 36%,var(--sv-soft),transparent 68%);
  border:1px solid var(--gr-line);pointer-events:none}
.svorbit .core::before{
  content:"";position:absolute;inset:-14%;border-radius:50%;
  border:1px solid var(--gr-line);opacity:.5}
.svorbit .core .n{
  font-family:var(--display);font-size:clamp(2rem,4vw,3rem);line-height:1;color:var(--sv)}
.svorbit .core .l{
  font-family:var(--mono);font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--gr-text-3);margin-top:8px}
.svnode{
  position:absolute;left:50%;top:50%;width:clamp(148px,15vw,186px);
  margin-left:calc(clamp(148px,15vw,186px) / -2);
  transform:translate3d(var(--x,0),var(--y,0),var(--z,0)) scale(var(--s,1));
  opacity:var(--o,1);z-index:var(--zi,1);
  text-decoration:none;color:inherit;
  padding:12px 14px;border-radius:13px;
  background:rgba(25,29,20,.86);border:1px solid var(--gr-line);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  transition:border-color .4s var(--ease),background .4s var(--ease)}
.svnode .t{
  font-family:var(--body);font-size:12.5px;font-weight:500;line-height:1.25;
  display:block;margin-top:2px}
.svnode .k{
  font-family:var(--mono);font-size:9px;letter-spacing:.17em;text-transform:uppercase;
  color:var(--sv);opacity:.75}
.svnode .d{
  display:block;margin-top:8px;font-size:11.5px;line-height:1.4;color:var(--gr-text-2);
  max-height:0;opacity:0;overflow:hidden;
  transition:max-height .45s var(--ease),opacity .35s var(--ease)}
.svnode:hover,.svnode:focus-visible{
  border-color:var(--sv);background:rgba(34,39,25,.94)}
.svnode:hover .d,.svnode:focus-visible .d{max-height:60px;opacity:1}
.svorbit .grab{
  position:absolute;left:50%;bottom:0;transform:translateX(-50%);
  font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--gr-text-3)}
@media (max-width:760px){.svorbit{display:none}}
/* the same eleven, as a list, where the ring cannot go */
.svlist{
  display:none;grid-template-columns:1fr;gap:1px;margin-top:34px;
  background:var(--gr-line);border:1px solid var(--gr-line);border-radius:14px;overflow:hidden}
.svlist a{
  background:var(--gr-1);padding:15px 17px;text-decoration:none;color:inherit;display:block}
.svlist a .k{
  font-family:var(--mono);font-size:9px;letter-spacing:.17em;text-transform:uppercase;color:var(--sv)}
.svlist a .t{display:block;font-size:14px;font-weight:500;margin-top:3px}
.svlist a .d{display:block;font-size:12px;color:var(--gr-text-2);margin-top:5px}
/* after the base rule, or the display:none above it wins on equal specificity
   and the eleven solutions vanish on exactly the screens that need the list */
@media (max-width:760px){.svlist{display:grid}}

/* ------------------------------ product chapters ------------------------------
   Three products, one pinned stage, the scroll moving between them. Each plate
   is held at its own distance and only the one in front is readable, which is
   the difference between a showcase and three pictures in a row. */
.svprod{position:relative;min-height:300svh;overflow:visible;background:var(--gr-1)}
.svprodpin{
  position:sticky;top:0;height:100svh;min-height:560px;overflow:hidden;
  display:grid;align-items:center;
  grid-template-columns:minmax(0,1fr);padding:0 var(--pad)}
.svprodpin .inner{
  width:100%;max-width:var(--maxw);margin:0 auto;
  display:grid;grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);
  gap:clamp(24px,4vw,70px);align-items:center}
@media (max-width:900px){
  .svprodpin .inner{grid-template-columns:1fr;gap:20px}
}
.svshelf{position:relative;height:clamp(300px,52vh,520px);perspective:1300px}
.svitem{
  position:absolute;inset:0;display:grid;place-items:center;
  transform:translate3d(0,var(--iy,0),var(--iz,0)) scale(var(--is,1));
  opacity:var(--io,0);transition:none;pointer-events:none}
.svitem img{
  max-height:100%;width:auto;object-fit:contain;
  filter:drop-shadow(0 40px 60px rgba(0,0,0,.7))}
.svitem::before{
  content:"";position:absolute;left:50%;top:50%;width:110%;padding-bottom:110%;
  transform:translate(-50%,-50%);border-radius:50%;z-index:-1;
  background:radial-gradient(circle,var(--sv-soft),transparent 62%)}
.svcopy{position:relative;min-height:clamp(280px,42vh,400px)}
.svcopy .pane{
  position:absolute;inset:0;display:flex;flex-direction:column;justify-content:center;
  opacity:0;transform:translateY(20px);pointer-events:none;
  transition:opacity .5s var(--ease),transform .6s var(--ease)}
.svcopy .pane.on{opacity:1;transform:none;pointer-events:auto}
.svcopy .pane .no{
  font-family:var(--mono);font-size:11px;letter-spacing:.2em;color:var(--sv);margin-bottom:14px}
.svcopy .pane h3{font-size:clamp(1.7rem,3.3vw,2.7rem);letter-spacing:-.022em;line-height:1.03}
.svcopy .pane .sub{
  margin-top:12px;color:var(--gr-text-2);font-size:1rem;max-width:44ch}
.svfeat{list-style:none;padding:0;margin:24px 0 0;display:grid;gap:1px;
  background:var(--gr-line);border-top:1px solid var(--gr-line);
  border-bottom:1px solid var(--gr-line)}
.svfeat li{
  background:var(--gr-1);padding:11px 0;font-size:.92rem;color:var(--gr-text-2);
  display:flex;align-items:baseline;gap:12px}
.svfeat li::before{
  content:"";flex:0 0 auto;width:5px;height:5px;border-radius:50%;background:var(--sv);
  transform:translateY(-2px)}
.svsrc{
  margin-top:18px;font-family:var(--mono);font-size:9.5px;letter-spacing:.15em;
  text-transform:uppercase;color:var(--gr-text-3)}

/* ------------------------------ a picture beside its readings ------------------------------ */
.svsplit{
  margin-top:clamp(40px,6vh,72px);display:grid;
  grid-template-columns:minmax(0,1.04fr) minmax(0,.96fr);
  gap:clamp(20px,3vw,48px);align-items:start;perspective:1100px}
@media (max-width:900px){.svsplit{grid-template-columns:1fr}}
.svframe{
  position:relative;margin:0;border-radius:18px;overflow:hidden;
  background:var(--gr-2);border:1px solid var(--gr-line);
  transform:translate3d(0,calc(var(--f,0) * -22px),0);
  transition:transform .9s var(--ease)}
.svframe img{width:100%;height:auto;display:block}
.svframe figcaption{
  position:absolute;left:0;right:0;bottom:0;padding:34px 16px 13px;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.15em;text-transform:uppercase;
  color:var(--gr-text);background:linear-gradient(180deg,transparent,rgba(13,15,11,.94))}
.svstack{display:grid;gap:clamp(10px,1.4vw,16px)}
.svstack .svplate{
  transform:translate3d(0,calc(var(--f,0) * var(--k,1) * -16px),0);
  transition:transform .9s var(--ease)}
.svstack .svplate:nth-child(2){--k:1.7}
.svstack .svplate:nth-child(3){--k:2.3}
.svplate .svfeat{margin-top:0;border-top:0;border-bottom:0;background:transparent;gap:0}
.svplate .svfeat li,.svtile .svfeat li{background:transparent;padding:7px 0}
.svplate .svfeat li + li{border-top:1px solid var(--gr-line)}

/* ------------------------------ numbers that float ------------------------------ */
.svnums{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  gap:clamp(16px,2.4vw,34px);margin-top:clamp(44px,7vh,78px);perspective:1000px}
.svnum{
  position:relative;padding:clamp(24px,3vw,38px) clamp(20px,2.4vw,30px);
  border:1px solid var(--gr-line);border-radius:18px;background:var(--gr-2);
  transform:translate3d(0,calc(var(--f,0) * -14px),calc(var(--f,0) * 34px));
  transition:transform .8s var(--ease),border-color .5s var(--ease)}
.svnum:hover{border-color:var(--sv)}
.svnum .v{
  font-family:var(--display);font-weight:300;line-height:.86;letter-spacing:-.04em;
  font-size:clamp(3.6rem,8vw,6.4rem);color:var(--sv);font-variant-numeric:tabular-nums}
.svnum .u{
  font-family:var(--mono);font-size:11px;letter-spacing:.22em;text-transform:uppercase;
  color:var(--gr-text);margin-top:10px}
.svnum .l{
  margin-top:10px;font-size:.88rem;color:var(--gr-text-2);line-height:1.45;max-width:22ch}
.svnum.free .v{font-size:clamp(2.6rem,5.4vw,4.2rem)}

/* ------------------------------ process timeline ------------------------------ */
.svsteps{
  margin-top:clamp(44px,7vh,80px);display:grid;gap:1px;background:var(--gr-line);
  border-top:1px solid var(--gr-line);border-bottom:1px solid var(--gr-line)}
.svstep{
  background:var(--gr-0);display:grid;
  grid-template-columns:clamp(56px,7vw,96px) minmax(0,1fr) minmax(0,1.15fr);
  gap:clamp(14px,3vw,40px);align-items:start;padding:clamp(20px,3vw,34px) 0;
  transition:background .5s var(--ease)}
.svstep:hover{background:var(--gr-1)}
.svstep .no{
  font-family:var(--mono);font-size:11px;letter-spacing:.18em;color:var(--sv);padding-top:5px}
.svstep h3{font-size:clamp(1.05rem,1.8vw,1.45rem);letter-spacing:-.012em}
.svstep p{color:var(--gr-text-2);font-size:.94rem;max-width:52ch}
@media (max-width:820px){
  .svstep{grid-template-columns:44px minmax(0,1fr);gap:14px}
  .svstep p{grid-column:2}
}

/* ------------------------------ photo bands ------------------------------
   Real photographs, given depth by the scroll rather than by a border. Each
   figure is pushed a different distance, so passing them feels like moving
   through a room instead of past a wall. */
.svshots{
  margin-top:clamp(44px,7vh,80px);
  display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(10px,1.4vw,20px);
  perspective:1200px}
.svshot{
  position:relative;margin:0;border-radius:14px;overflow:hidden;
  background:var(--gr-2);border:1px solid var(--gr-line);
  aspect-ratio:4/5;
  transform:translate3d(0,calc(var(--f,0) * var(--k,1) * -26px),0);
  transition:transform .9s var(--ease),border-color .5s var(--ease)}
.svshot:nth-child(2){--k:1.7}
.svshot:nth-child(3){--k:.6}
.svshot:nth-child(4){--k:1.35}
.svshot img{
  width:100%;height:100%;object-fit:cover;
  filter:saturate(.94) contrast(1.04);
  transition:transform 1.6s var(--ease)}
.svshot:hover{border-color:var(--gr-line-2)}
.svshot:hover img{transform:scale(1.05)}
.svshot figcaption{
  position:absolute;left:0;right:0;bottom:0;padding:34px 14px 13px;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--gr-text);
  background:linear-gradient(180deg,transparent,rgba(13,15,11,.94))}
@media (max-width:860px){.svshots{grid-template-columns:repeat(2,1fr)}}

/* a wider, editorial version for the greenhouse and training pages */
.svmosaic{
  margin-top:clamp(44px,7vh,80px);display:grid;grid-template-columns:repeat(6,1fr);
  gap:clamp(10px,1.4vw,18px)}
.svmosaic figure{
  position:relative;margin:0;border-radius:16px;overflow:hidden;background:var(--gr-2);
  border:1px solid var(--gr-line);
  transform:translate3d(0,calc(var(--f,0) * var(--k,1) * -24px),0);
  transition:transform .9s var(--ease)}
.svmosaic figure img{width:100%;height:100%;object-fit:cover;transition:transform 1.6s var(--ease)}
.svmosaic figure:hover img{transform:scale(1.05)}
.svmosaic figcaption{
  position:absolute;left:0;right:0;bottom:0;padding:40px 16px 15px;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--gr-text);
  background:linear-gradient(180deg,transparent,rgba(13,15,11,.94))}
.svmosaic .w3{grid-column:span 3;aspect-ratio:16/11}
.svmosaic .w2{grid-column:span 2;aspect-ratio:4/5}
.svmosaic .w2.wide{aspect-ratio:4/3}
.svmosaic figure:nth-child(2){--k:1.7}
.svmosaic figure:nth-child(3){--k:.55}
.svmosaic figure:nth-child(4){--k:1.4}
.svmosaic figure:nth-child(5){--k:.85}
@media (max-width:860px){
  .svmosaic{grid-template-columns:repeat(2,1fr)}
  .svmosaic .w3,.svmosaic .w2{grid-column:span 1;aspect-ratio:4/5}
}

/* ------------------------------ what we share / who it is for ------------------------------ */
.svgrid{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(228px,1fr));
  gap:clamp(12px,1.6vw,20px);margin-top:clamp(40px,6vh,74px);perspective:1100px}
.svtile{
  position:relative;padding:clamp(22px,2.6vw,32px);border-radius:16px;
  background:var(--gr-2);border:1px solid var(--gr-line);
  transform:translate3d(0,calc(var(--f,0) * var(--k,1) * -18px),calc(var(--f,0) * 20px));
  transition:transform .9s var(--ease),border-color .5s var(--ease),background .5s var(--ease)}
.svtile:nth-child(even){--k:1.6}
.svtile:nth-child(3n){--k:.7}
.svtile:hover{border-color:var(--sv);background:var(--gr-3)}
.svtile .ic{
  width:38px;height:38px;margin-bottom:18px;color:var(--sv)}
.svtile .ic svg{width:100%;height:100%;display:block}
.svtile h3{font-size:clamp(1.02rem,1.5vw,1.2rem);letter-spacing:-.01em;line-height:1.2}
.svtile p{margin-top:9px;font-size:.88rem;color:var(--gr-text-2);line-height:1.5}

/* ------------------------------ the closing band ------------------------------ */
.svcloser{
  position:relative;overflow:hidden;
  padding:clamp(96px,16vh,190px) var(--pad) clamp(110px,17vh,200px);
  background:var(--gr-0)}
.svcloser .bg{
  position:absolute;inset:0;z-index:0;overflow:hidden;
  background-size:cover;background-position:center;
  opacity:.34;filter:saturate(.86) contrast(1.04)}
/* a film behind the last band, sitting on the still that is also its poster:
   if the video never loads, never decodes, or motion is turned off, the frame
   underneath is already the right picture */
.svcloser .bg video{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;
  opacity:0;transition:opacity 1.2s var(--ease)}
.svcloser .bg video.on{opacity:1}
.svcloser::after{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(180deg,rgba(13,15,11,.92),rgba(13,15,11,.62) 44%,rgba(13,15,11,.97)),
             radial-gradient(70% 60% at 50% 108%,var(--sv-soft),transparent 70%)}
.svcloser .wrap{position:relative;z-index:2}
.svcloser .h2{font-size:clamp(2.3rem,5.4vw,4.4rem);max-width:15ch;letter-spacing:-.028em}

/* ------------------------------ the placeholder page ------------------------------ */
.svsoon{
  min-height:calc(100svh - 0px);display:grid;place-items:center;
  padding:calc(var(--nav-h) + 60px) var(--pad) clamp(110px,16vh,180px);
  text-align:center;position:relative;overflow:hidden}
.svsoon canvas{position:absolute;inset:0;width:100%;height:100%;opacity:.5}
.svsoon .wrap{position:relative;z-index:2;max-width:62ch}
.svsoon .h1{margin:0 auto;max-width:16ch;font-size:clamp(2.4rem,6vw,4.6rem)}
.svsoon .lede{margin-left:auto;margin-right:auto}
.svsoon .kicker{justify-content:center}
.svsoon .btnrow{justify-content:center;margin-top:40px}

/* ------------------------------ motion off ------------------------------
   Everything above degrades to a plain, readable, scrollable page: the pinned
   stages let go, the canvases are hidden behind their poster colours, and every
   step of every story is simply present at once. Nothing is lost but the film. */
@media (prefers-reduced-motion: reduce){
  .svstage,.svprod,.svhero{min-height:0!important}
  .svpin,.svprodpin{position:static;height:auto;min-height:0;padding-top:clamp(60px,9vh,110px);
    padding-bottom:clamp(60px,9vh,110px)}
  .svheropin{position:static;height:auto;min-height:70svh}
  .svpin canvas,.svsoon canvas,.svhero canvas{display:none}
  /* a stage that was only ever a picture has nothing left to say once the
     picture is gone, so it goes rather than leaving a gap in the page */
  .svstage.visualonly{display:none}
  .svover{position:static}
  .svover .step,.svover .step.right{
    position:static;opacity:1;transform:none;max-width:52ch;margin:0 0 34px;text-align:left}
  .svhud,.svcue{display:none}
  .svshelf{height:auto;display:grid;gap:22px;margin-bottom:30px}
  .svitem{position:static;opacity:1!important;transform:none!important}
  .svitem img{max-height:280px}
  .svcopy{min-height:0;display:grid;gap:40px}
  .svcopy .pane{position:static;opacity:1;transform:none;pointer-events:auto}
  .svnum,.svshot,.svtile,.svmosaic figure{transform:none!important}
  .svcard .plane{transform:none!important}
  .svcue i{animation:none}
  .svcloser .bg video{display:none}
}
