/* ==========================================================
   /home-v2 (VLP-1198, split out to the folio system in VLP-1224) : the homepage
   layer only.

   WHAT THIS FILE OWNS
   Everything that is this page and no other: the hero and its search
   affordance, the console's lift and lean, the offer stage and its five
   stacked sentences, the closer, the homepage's own act seams by id, and the
   no-JS, static and reduced-motion restatements for exactly those moves.

   WHAT IT DEPENDS ON
   /folio.css, loaded first: tokens, reset, base type, the section formula,
   buttons, the nav, frames and the window device, the grids, the FAQ, the
   footer, the modal, the sticky CTA. This file adds to that layer and never
   restates it.

   LOAD ORDER
   critical fallback <style> -> /folio.css -> /home-v2.css -> /scrollcraft.css.
   The engine sheet is last so the page can override its tokens; folio.css
   restates every engine base rule it changes at a higher specificity.
   ========================================================== */

/* ---------------- hero ----------------
   Ink only, lifted by one very faint radial so the field is not a flat wall.
   No photograph: the product is the picture. */
.hero{position:relative;min-height:100svh}
/* The act is only a length. Everything the reader sees lives on the stage, which is what the
   engine sticks; when the hero is not pinned (phones, coarse pointers) the same block simply
   flows, because every rule here is on the stage rather than on the act. */
.hero-stage{display:flex;flex-direction:column;background:var(--ink);
  padding:calc(var(--nav-h) + var(--nav-inset) + 34px) 0 0}
.hero-stage::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
  background:radial-gradient(ellipse at 50% 0%,rgba(244,241,234,.06),transparent 60%)}
.hero-in{position:relative;z-index:1;width:100%;min-width:0;display:flex;flex-direction:column;align-items:center;text-align:center}
/* margin-inline:auto on a flex item cancels the cross-axis stretch, so a .wrap inside a stage
   shrinks to its content. The hero figure holds only absolutely positioned media and collapsed
   to nothing until this. */
.hero-stage>.stage.wrap,.offer-stage>.wrap,.closer-stage>.wrap{width:100%}
/* Line masks reserve descender room. Instrument Serif hangs its g, y and p a long way below the
   baseline, and the engine's default 0.14em shears them at this line-height. */
.hero h1 .sc-split--line{padding-bottom:.26em;margin-bottom:-.26em}
.hero h1{margin-top:22px}
/* balance, not the shared layer's pretty: pretty only rescues the last line, and at every width
   from 1280 down this sentence broke after "around your", stranding a determiner from its noun. */
.hero-lead{margin-top:20px;max-width:46ch;font-size:clamp(16px,1.4vw,18.5px);text-wrap:balance}
.hero-cta{margin-top:28px;display:flex;align-items:center;gap:22px;flex-wrap:wrap;justify-content:center}

/* the search affordance: the shape of the question, not a working field */
.hsearch{width:100%;max-width:640px;margin-top:34px;display:flex;align-items:center;gap:14px;
  min-height:58px;padding:0 8px 0 20px;border-radius:99px;border:1px solid var(--line-2);
  background:rgba(21,27,35,.72);cursor:pointer;text-align:left;
  transition:border-color .2s,background .2s}
.hsearch:hover{border-color:rgba(76,141,255,.42);background:rgba(21,27,35,.94)}
.hsearch-ico{color:var(--blue);display:flex;flex:none}
/* width:0 as well as min-width:0: without it the nowrap example text becomes the pill's
   min-content width and the whole hero column refuses to shrink on a small phone. */
.hsearch-ph{flex:1 1 0;width:0;min-width:0;color:var(--muted);font-size:15px;line-height:1.3;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hsearch-ph::after{content:"";display:inline-block;width:1px;height:1em;margin-left:2px;
  vertical-align:-.14em;background:var(--blue)}
html.hv-caret .hsearch-ph::after{animation:blink 1.1s steps(1,end) infinite}
@keyframes blink{50%{opacity:0}}
.hsearch-go{flex:none;width:38px;height:38px;border-radius:50%;background:rgba(76,141,255,.14);
  color:var(--blue);display:flex;align-items:center;justify-content:center;
  transition:background .2s,color .2s}
.hsearch:hover .hsearch-go{background:var(--blue);color:var(--ink)}
.hsearch-note{margin-top:16px;font-family:var(--mono);font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--dim)}
/* The pill and its note share one cue, so they arrive as one object. */
.hsearch-wrap{width:100%;min-width:0;display:flex;flex-direction:column;align-items:center}

/* ---------------- this page's seams ----------------
   The two that matter most, by id so the value survives the hero and the close being demoted to
   flow on a phone or under reduced motion. #product's heading is the caption the console earns
   as it slides off the top; #how's eyebrow has to arrive before the emptied offer stage has
   finished leaving. Both land inside a third of a viewport of the un-pin. */
#product{padding-top:calc(var(--sec-pad) * .5)}
#how{padding-top:calc(var(--sec-pad) * .5)}
/* The statement after the steps carries one mono line under its subhead. The reset zeroes every
   margin, so without this the price line sits flush against the paragraph above it; .head is a
   centred flex column with no gap of its own. This is spacing for a line of copy, nothing else. */
#after .fine{margin-top:24px}
/* And the last question has to hand over to the close, not to half a screen of ground. */
#faq{padding-bottom:calc(var(--sec-pad) * .62)}
/* Except when nothing is pinned. Both of those numbers pay for travel the reader is watching:
   an offer stage emptying as it slides off, and a closer rising into its own pin. In the static
   state (?static=1, no script, no engine) there is no travel to pay for, and the same numbers
   read as two short gaps in a page whose every other chapter is separated by .86 of the rhythm:
   the offer's own CTA ends 80px above "How it works", where the rest of the page uses 227px.
   #product keeps its tight seam in every state, because there the heading really is the
   console's caption and the closeness is the point. */
html.hv-static #how{padding-top:var(--sec-pad)}
html.hv-static #faq{padding-bottom:var(--sec-pad)}
/* The offer's own box goes with them. The shared layer zeroes the padding of any pinned section
   in every state, and the stage then carries a top padding that exists only to clear the fixed
   nav pill while the stage is stuck under it. With nothing stuck, that is not a seam, it is a
   leftover: give the offer the section rhythm on both sides so it sits in the page like the
   chapters either side of it. */
html.hv-static .offer-stage{padding:var(--sec-pad) 0}

/* ---------------- the hero frame ---------------- */
.frame-hero{aspect-ratio:16/10}
.frame-hero .poster{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.frame-hero .clip{position:relative;z-index:1;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity 600ms var(--ease-out);background:var(--surface)}
.frame-hero .clip.is-playing,html.no-js .frame-hero .clip{opacity:1}
.stage-closer{max-width:900px;margin:64px auto 0}

/* ---------------- the offer ---------------- */
/* Five sentences, centred in one column, each separated by a hairline that spans it. The
   column is narrower than the section so the lines break where the sentence breaks. */
.sec-offer .lines{margin-top:52px;max-width:860px;margin-left:auto;margin-right:auto}
.line{font-size:clamp(22px,2.9vw,40px);line-height:1.18;letter-spacing:-.025em;font-weight:500;
  color:var(--text);text-align:center;text-wrap:balance;padding:24px 0;
  border-top:1px solid var(--line)}
.line:first-child{border-top:0;padding-top:0}

/* ---------------- closer ----------------
   The hero's formula again, so the last screen repeats the first. */
/* clip, not hidden: an overflow:hidden ancestor turns into the scrollport a sticky stage
   measures itself against, and the pin stops engaging. */
.sec-closer{border-top:1px solid var(--line);padding-bottom:0;overflow:clip}
.closer-in{max-width:820px;margin:0 auto;text-align:center;display:flex;flex-direction:column;align-items:center}
.closer-in .display{margin-top:22px}
.closer-in .lead{margin-top:20px;text-align:center;margin-left:auto;margin-right:auto}
.closer-in .inline-cta{margin-top:32px}
/* The closer carries the hero's own frame, held still, so the exit repeats the entrance.
   The fade only takes the bottom third: the search results above it have to stay readable. */
.stage-closer{position:relative;perspective:1500px}
/* The window's bottom edge is the page's edge: the footer's own hairline sits on it. A gradient
   that is still translucent when it gets there cuts the console through whatever row happens to be
   under it, and a screenshot cut mid-row reads as a rendering fault rather than as a crop. So the
   fade reaches solid ground well before the edge and holds it: whatever the console is showing,
   the cut lands on ink. */
.stage-closer::after{content:"";position:absolute;left:0;right:0;bottom:0;height:38%;z-index:3;
  pointer-events:none;background:linear-gradient(180deg,transparent,rgba(11,15,20,.62) 42%,var(--ink) 91%,var(--ink))}

/* ---------------- motion ---------------- */
/* --- the lift ---
   Two nested transforms on purpose. The lean follows the pointer, and needs a transition or it
   tracks the mouse with no weight; the lift is written from --sc-p every frame, and a transition
   on it would make the console lag the hand. One element cannot have both. */
.hero-lean{transform-style:preserve-3d;
  transform:rotateX(calc((var(--sc-my,.5) - .5) * -2.4deg)) rotateY(calc((var(--sc-mx,.5) - .5) * 2.6deg));
  transition:transform 620ms var(--ease-out)}
.hero-lift,.closer-lift{
  /* --sc-p defaults to 1 so the plane is already level before the engine writes anything, and
     stays level for a browser that never runs the script. */
  --l:clamp(0,calc(var(--sc-p,1) / .6),1);
  transform-origin:50% 100%;
  transform:rotateX(calc((1 - var(--l)) * 9deg))
            scale(calc(.96 + .04 * var(--l)))
            translate3d(0,calc((1 - var(--l)) * 40px),0)}
/* The hero's console does not merely level, it travels: it starts where the first screen shows
   it, a tilted plane whose top edge is most of a screen down, and arrives level and full with
   its top 24px under the nav pill. --hero-rise is that distance, measured from the real layout
   by home-v2.js rather than hardcoded at one viewport. Two ramps, not one: the plane straightens
   by p = 0.72 and finishes arriving by p = 0.85, so it reads as a console standing up as it
   comes rather than as one flat rectangle sliding, and the last 15% of the travel is a hold. */
.hero-lift{
  --l:clamp(0,calc(var(--sc-p,1) / .72),1);
  --u:clamp(0,calc(var(--sc-p,1) / .85),1);
  transform:rotateX(calc((1 - var(--l)) * 9deg))
            scale(calc(.96 + .04 * var(--u)))
            translate3d(0,calc((1 - var(--u)) * 40px - var(--u) * var(--hero-rise,0px)),0)}
/* The copy greets, then gets out of the console's way: it drifts up while its cues ramp out, so
   the two moves are one gesture rather than a fade over a rise. The drift lives on the block,
   which no cue owns; a cue writes transform on its own element, and stacking a second transform
   there would silently discard one of them. */
.hero-in{transform:translate3d(0,calc(clamp(0,calc(var(--sc-p,0) / .5),1) * -90px),0)}

/* --- this page's windows ---
   The hero and closer screenshots are cut to their frame exactly, so the window has to be made:
   a small scale gives the picture room to travel without ever showing an edge. The scale costs
   width as well as height, and the hero console now finishes the act filling the stage, where
   1.1 ate the first characters of every label in the sidebar. 1.05 halves that and still leaves
   more than thirty pixels of vertical travel once both crops are clamped to the real overflow.
   folio.css states the .frame-still half of this for every other page; the pair is restated here
   because the hero shares it. */
.frame-hero .media,.frame-still .media{position:absolute;inset:0;transform-origin:50% 50%;
  --w-s:1.05;--w-from:16px;--w-to:-16px;
  transform:translate3d(0,var(--w-y,0px),0) scale(var(--w-s,1))}
/* The hero is the exception: its motion is the lift, and the act ends with the console filling
   the stage, where any pan cuts the app's own header bar off the top of the picture. Scale 1
   means no overflow, and a window with no overflow never pans. */
.frame-hero .media{--w-s:1;--w-from:0px;--w-to:0px}

/* --- the offer: the peak --- */
.offer-stage{display:flex;flex-direction:column;justify-content:center;background:var(--ink);
  padding:calc(var(--nav-h) + var(--nav-inset) + 26px) 0 46px}
.offer-stage .act-mark{margin-bottom:20px}
.offer-stage .head .display{font-size:clamp(30px,3.6vw,50px)}
.offer-stage .lines{margin-top:34px}
.offer-stage .line{font-size:clamp(21px,2.5vw,34px)}
.offer-stage .inline-cta{margin-top:32px}
/* Stacked in one box, not down a column. Five sentences crossing over in the same place is the
   beat; five rows lit one at a time marches the reader's eye down the screen and leaves a hole
   above whichever one is lit. The hairline column is the static layout, and it comes back
   whenever the stage is not actually pinned (no script, ?static=1, a capture tool). */
.offer-stage.sc-stage .lines{position:relative;min-height:clamp(112px,19vh,180px)}
/* Centred with the `translate` property, not with flex and not with `transform`. Flex turns each
   run of text either side of <b class="price"> or <span class="nb"> into its own anonymous item
   and the sentence comes apart; transform is what the engine writes on a cue element. */
.offer-stage.sc-stage .line{position:absolute;left:0;right:0;top:50%;translate:0 -50%;
  margin:0;padding:0;border-top:0}

/* --- the close --- */
.closer-stage{display:flex;flex-direction:column;background:var(--ink);
  padding:calc(var(--nav-h) + var(--nav-inset) + 24px) 0 0}
.closer-stage .closer-in .display{font-size:clamp(30px,3.4vw,50px)}
.closer-stage .stage-closer{margin-top:auto;max-width:780px;padding-top:34px}
/* The frame is cut by the bottom of the stage rather than by its own fade, so the fade moves to
   the stage edge; otherwise the window ends on a hard line. */
.closer-stage.sc-stage .stage-closer::after{display:none}
/* The fade has to reach solid ink on the gutter BETWEEN two rows, not part way through one: a
   console that dims out half way down a transcript row reads as a rendering fault, and a fade
   that is still translucent at the footer's hairline is the guillotine the crop was meant to
   avoid. The stop below is the row boundary measured on this page's own console at 1440. */
.closer-stage.sc-stage::after{content:"";position:absolute;left:0;right:0;bottom:0;height:26%;
  z-index:3;pointer-events:none;
  background:linear-gradient(180deg,transparent,rgba(11,15,20,.6) 34%,var(--ink) 66%,var(--ink))}

/* --- the landing ---
   A greet cue is already at full opacity when the act begins, so the engine has nothing to
   animate on the one screen every visitor sees. One CSS animation, played once, gives the hero
   its arrival; animation-fill-mode is backwards only, so the engine's inline values take over
   the instant it ends and scroll owns the element from then on. */
@keyframes hv-rise{from{opacity:0;transform:translate3d(0,112%,0)}}
@keyframes hv-greet{from{opacity:0;transform:translate3d(0,14px,0)}}
@media(prefers-reduced-motion:no-preference){
  .hero h1 .sc-split__i{animation:hv-rise 980ms var(--ease-out) backwards}
  .hero h1 .sc-split--line:nth-child(2) .sc-split__i{animation-delay:100ms}
  .hero h1 .sc-split--line:nth-child(3) .sc-split__i{animation-delay:200ms}
  .hero-in>[data-sc-cue]{animation:hv-greet 720ms var(--ease-out) backwards}
  .hero-in>h1[data-sc-cue]{animation:none}
  .hero-in>.chip{animation-delay:40ms}
  .hero-in>.hero-lead{animation-delay:420ms}
  .hero-in>.hero-cta{animation-delay:530ms}
  .hero-in>.hsearch-wrap{animation-delay:630ms}
}

/* will-change is written by the script only while a window is near the viewport. The lifts get
   none: a standing will-change on a surface that moves for one act holds a compositor layer for
   the life of the page, and the per-frame transform promotes them on its own while they move. */
/* Inside the pin the console is the act's destination, so it is sized to fill the held stage
   once it arrives: as wide as the page's own column, and capped by the viewport's height so a
   short screen never ends the travel with the frame running off the bottom. 130px is the nav
   pill, its inset, the 24px gap under it and a breath at the foot; 1.6 is the frame's 16/10. */
.hero-stage.sc-stage>.stage.wrap{
  max-width:min(1240px,calc((100svh - 130px) * 1.6 + 64px));
  padding-top:38px;margin-top:0}

/* If the script never runs, or a capture tool asks for the static page, nothing may stay
   invisible and nothing may sit mid-animation. folio.css covers the cues, reveals and staggers;
   these are this page's own moves. */
html.no-js .hero-lean,html.hv-static .hero-lean,
html.no-js .hero-lift,html.hv-static .hero-lift,
html.no-js .hero-in,html.hv-static .hero-in,
html.no-js .closer-lift,html.hv-static .closer-lift{transform:none;transition:none}
html.no-js .frame-hero .media,html.hv-static .frame-hero .media,
html.no-js .frame-still .media,html.hv-static .frame-still .media{transform:none}
html.no-js .hero-in>[data-sc-cue],html.hv-static .hero-in>[data-sc-cue],
html.no-js .hero h1 .sc-split__i,html.hv-static .hero h1 .sc-split__i{animation:none}

/* ---------------- reduced motion ----------------
   Everything renders in its finished state, the clip holds on its poster, and
   the placeholder shows one example and stops. */
@media(prefers-reduced-motion:reduce){
  .frame-hero .clip{opacity:1;transition:none}
  .hsearch-ph::after,html.hv-caret .hsearch-ph::after{animation:none}
  .hsearch{transition:none}
  /* Fewer and gentler, not zero: the engine keeps the opacity that carries comprehension and
     drops every position change. These are this page's own position changes. */
  .hero-lean,.hero-lift,.hero-in,.closer-lift{transform:none;transition:none}
  .frame-hero .media,.frame-still .media{transform:none}
  /* The hero and the close are demoted to flow under reduce, so the pinned-only console size
     never applies and the frame is the ordinary column width. Restated rather than inherited,
     because .sc-stage is what carries that rule and a flow act never gets the class. */
  .hero-stage>.stage.wrap{max-width:none}
  .hero h1 .sc-split__i{animation:none}
}

@media(max-width:760px) and (prefers-reduced-motion:reduce){
  .frame-hero .media,.frame-still .media{transform:scale(var(--w-s,1))}
}

/* ---------------- responsive ---------------- */
@media(max-width:900px){
  /* The hero and the close are flow here, so their progress is not a pin's progress and the
     lift would arrive half-resolved. The window still pans. */
  .hero-lean,.hero-lift,.hero-in,.closer-lift{transform:none}
}
@media(max-width:760px){
  .hero-stage{padding-top:calc(var(--nav-h) + var(--nav-inset) + 34px)}
  .hero h1{margin-top:18px}
  .hero-lead{margin-top:16px}
  .hero-cta{margin-top:24px;gap:16px;flex-direction:column;width:100%}
  .hero-cta .btn{width:100%;justify-content:center;min-height:48px}
  .hsearch{margin-top:26px;min-height:52px;padding-left:16px;gap:10px}
  .hsearch-ph{font-size:13.5px}
  .hsearch-go{width:34px;height:34px}
  .hsearch-note{margin-top:14px;font-size:10px;letter-spacing:.12em}
  .stage-closer{margin-top:36px}
  /* On a phone a whole 1600px console is unreadable at 335px: the hero frame crops to the
     result column instead of shrinking the entire application to a smudge. */
  .frame-hero,.frame-still{aspect-ratio:4/5}
  /* On a phone a whole 1600px console is unreadable at 348px: every label renders at four or
     five pixels. The frame keeps its crop and the picture inside it is magnified 2.2x about the
     results column, so the quote, the timecode and the Open moment control are the picture. The
     scale rides .media, which the poster, the clip and the still all share, so the crossfade
     still lines up frame for frame. */
  .frame-hero .media,.frame-still .media{--w-s:2.2;transform-origin:6% 31%}
  /* transform:none cancels the pan under no-JS, ?static=1 and reduced motion. On a phone it would
     cancel the crop with it, and the crop is legibility rather than motion, so the scale comes
     back here without the pan. */
  html.no-js .frame-hero .media,html.hv-static .frame-hero .media,
  html.no-js .frame-still .media,html.hv-static .frame-still .media{transform:scale(var(--w-s,1))}
  .frame-hero .poster,.frame-hero .clip,.frame-still img{object-position:50% 0}
  .offer-stage{padding:calc(var(--nav-h) + var(--nav-inset) + 16px) 0 30px}
  .offer-stage .lines{margin-top:26px}
  .offer-stage .line{padding:13px 0}
  .sec-offer .lines{margin-top:34px}
  .line{padding:16px 0;max-width:none;font-size:clamp(21px,5.4vw,26px)}
  .frame-hero{border-radius:12px}
}

/* The principles panel is taller than the library window beside it; let that window fill its
   card instead of leaving a band of empty surface under the screenshot. */
#storage .shot-library{aspect-ratio:auto;flex:1 1 auto;min-height:340px}
@media(max-width:900px){#storage .shot-library{aspect-ratio:16/9;min-height:0}}

/* --- the phone crop for the projects console ---
   At 350px wide the whole 1600px application renders every label at four or five pixels. The
   frame keeps its phone source and crops to the part the claim above it is about: the Projects
   header and the first row of shoot cards, with their names, IDs and counts legible. .frame-crop
   in folio.css opts the window into the same mechanism .shot already uses; the pan still runs,
   because the enlargement leaves a real overflow for it. */
@media(max-width:760px){
  .hv-crop-projects{aspect-ratio:4/3;--zoom:300%;--sx:-53%;--sy:-24%;--w-from:0px;--w-to:-44px}
}

/* --- the hero when nothing is pinned ---
   100svh is the pinned stage's own height: the act holds a whole screen and the copy sits in the
   middle of it. Take the pin away, which ?static=1, reduced motion, a coarse pointer and any
   width under 900px all do, and that same screen becomes a fixed measure the copy no longer
   fills, so the fold opened on a band of ground and closed on another one before the next
   section. Unpinned, the hero is as tall as the hero. .sc-act--pinned and .sc-stage are the two
   classes the engine adds to a pinned act and its stage, so this is exactly "not pinned". */
.hero:not(.sc-act--pinned){min-height:0}
.hero-stage:not(.sc-stage){min-height:0}

/* ---------------- type floors on a phone ----------------
   Body copy to 15.5px, mono captions to 11px, the fine print that carries the terms to 12px.
   folio.css sets the shared floors; these are the sizes this page authors itself. */
@media(max-width:760px){
  .hsearch-ph{font-size:15.5px}
  .hsearch-note{font-size:11px;letter-spacing:.14em}
}

/* The two entity definitions, linked from the storage statement. */
.entity-links{margin-top:18px;display:flex;flex-wrap:wrap;gap:12px 28px}

/* ============================ WORKFLOW & PRODUCTS (VLP-2396) ============================
   #workflow is #storage's pair again; its left card carries a Traceframe trail drawn in
   markup, each row lit in turn like the rules beside it. #products reuses the #product
   window with its own crop. */
.tf-trail{margin:24px 0 0;flex:1 1 auto;display:flex;flex-direction:column}
.tf-trail ol{list-style:none;margin:0;padding:0;border:1px solid var(--line-2);border-radius:12px;
  overflow:hidden;background:rgba(244,241,234,.015)}
.tf-trail li{position:relative;display:grid;grid-template-columns:96px minmax(0,1fr) auto;align-items:center;
  gap:14px;padding:16px 18px}
.tf-trail li+li{border-top:1px solid var(--line)}
.tf-trail li+li::before{content:"";position:absolute;left:30px;top:-7px;width:1px;height:14px;background:var(--blue)}
.tf-k{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--dim)}
.tf-v{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text);font-size:14.5px}
.tf-s{font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--blue);
  padding:4px 9px;border:1px solid rgba(76,141,255,.35);border-radius:999px}
.tf-trail li:first-child .tf-s{color:var(--muted);border-color:var(--line-2)}
.tf-trail .cap{margin-top:auto;padding-top:18px;text-align:left}
#workflow .card{padding-bottom:26px}
.hv-crop-airview{--w-from:0px;--w-to:-84px}
#products .more{margin-top:48px}
@media(max-width:760px){
  .tf-trail li{grid-template-columns:78px minmax(0,1fr);padding:14px}
  .tf-s{display:none}
}
.hv-pillar-link{justify-content:center;margin-top:40px}
/* VLP-2403: each hands-on rule and the Traceframe card link to the offering's own page. */
#workflow a.rk{text-decoration:none;display:inline-flex;align-items:center;gap:8px;transition:color .2s}
#workflow a.rk::after{content:"\2192";color:var(--blue);transform:translateX(0);transition:transform .25s var(--ease-out)}
#workflow a.rk:hover{color:var(--blue)}
#workflow a.rk:hover::after{transform:translateX(4px)}
#workflow h3 a{color:inherit;text-decoration:none}
#workflow .card>.mlink{margin-top:18px;align-self:flex-start}
