/* /styles/global.css */
/* ==========================================================================
   Design system — measured from the reference layout at 1440px.
   Colours, type scale, spacing and motion curves are all measured values.

   Breakpoints — the page uses four and only four:
     1280   the 1200 rail plus its 2x40 gutter stops fitting
     1100   three- and four-across rows drop to two
      900   everything stacks; section padding 96/40 -> 72/24
      600   phone: padding 56/--gutter, single column
   Section sheets write them as `max-width:1279px / 1100px / 900px / 600px`.
   The two sheets that also carry a `min-width` branch (hero, header) pair it
   as 899/900 so the two never both apply.

   The card photographs live in styles/wells.css, which build.js must link
   LAST, after every section sheet — see the header of that file.
   ========================================================================== */

/* ---- Fonts ------------------------------------------------------------- */
/* Only the weights the page actually draws: Sentient 300 (display),
   Onest 400/500 (body, labels, buttons), Inter 500 (customer wordmarks). */
@font-face{font-family:Sentient;src:url("/assets/fonts/sentient-300.woff2?v=e9cae46d") format("woff2");font-weight:300;font-style:normal;font-display:swap}
@font-face{font-family:Onest;src:url("/assets/fonts/onest-400.woff2?v=3bde8d38") format("woff2");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:Onest;src:url("/assets/fonts/onest-500.woff2?v=653ecd75") format("woff2");font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:Inter;src:url("/assets/fonts/inter-500.woff2?v=52394584") format("woff2");font-weight:500;font-style:normal;font-display:swap}

/* ---- Tokens ------------------------------------------------------------ */
:root{
  /* surfaces */
  --page:      #fbfaf6;   /* page background             */
  --panel:     #f4f2ec;   /* raised / tinted section bg  */
  --soft:      #ece9e0;   /* hairline fills, chips       */
  --sand:      #e7e3d9;   /* deeper sand, photo fallback */
  /* ink */
  --ink:       #1c1a15;   /* primary text, dark buttons  */
  --ink-hover: #2e2b24;   /* the one hover step on ink   */
  --muted:     #56524a;   /* secondary text              */
  --faint:     #8c887e;   /* tertiary text               */
  --on-dark:   #fbfaf6;   /* text on --ink               */
  /* lines */
  --line:        rgba(28,26,21,.08);
  --line-header: #e4e4e1;             /* the header's hairline */

  /* shadows — the reference draws exactly two */
  --shadow-card: 0 1px 3px rgba(0,0,0,.03), 0 4px 16px rgba(0,0,0,.04);
  --shadow-pop:  0 1px 3px rgba(0,0,0,.03), 0 4px 16px rgba(0,0,0,.06);

  /* type families */
  --font-display: Sentient, ui-serif, Georgia, serif;
  --font-body:    Onest, ui-sans-serif, system-ui, sans-serif;
  --font-brand:   Inter, ui-sans-serif, system-ui, sans-serif;

  /* layout */
  --container: 1200px;    /* the rail every section aligns to */
  --gutter:    20px;      /* phone side padding (<=600)       */
  --header-h:  64px;      /* the fixed bar's height           */

  /* radii — the scale the page actually draws */
  --r-4:  4px;
  --r-6:  6px;
  --r-8:  8px;
  --r-10: 10px;
  --r-12: 12px;
  --r-16: 16px;
  --r-pill: 999px;

  /* the one world swatch still in use: sky blue thinning to the page */
  --sky-wash: linear-gradient(160deg, #bcd9f2 0%, #dfe9ec 55%, #ede9de 100%);

  /* motion — measured: spring(duration 1.2s, bounce 0.1); appear travels
     y:16px -> 0 with opacity .001 -> 1. Bezier below fits that spring. */
  --appear-dur: 1.2s;
  --appear-ease: cubic-bezier(.22,.61,.28,1);
  --hover-dur: .28s;
  --hover-ease: cubic-bezier(.4,0,.2,1);
}

/* ---- Reset ------------------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body,h1,h2,h3,h4,h5,h6,p,figure,figcaption,blockquote,dl,dd,ul,ol{margin:0;padding:0}
ul[class],ol[class]{list-style:none}
/* height:auto keeps the ratio when max-width clamps an <img> that carries
   width/height attributes — without it those images squash. */
img,svg,video{display:block;max-width:100%}
img,video{height:auto}
button,input,select,textarea{font:inherit;color:inherit}
button{background:none;border:0;cursor:pointer}
a{color:inherit;text-decoration:none}
h1,h2,h3,h4,h5,h6{font-weight:inherit;font-size:inherit}

/* ---- Base -------------------------------------------------------------- */
body{
  background:var(--page);
  color:var(--ink);
  font-family:var(--font-body);
  font-size:16px;
  line-height:1.45;
  /* nothing in the current copy is long enough to overflow 320px, but there is
     no overflow-x:hidden anywhere to catch one that is. */
  overflow-wrap:break-word;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  font-feature-settings:normal;
  text-rendering:auto;
}

/* anything linkable clears the fixed bar when it is jumped to */
[id]{scroll-margin-top:calc(var(--header-h) + 16px)}

/* ---- Type scale ---------------------------------------------------------
   Measured at 1440: 56/58.8/-2.8, 48/50.4/-2.4, 40/46/-2, 40/50/-2. The
   steps are written fluid so no section has to restate them at 900 and 600:
   each clamp resolves to its measured maximum from ~1100px up (xl reaches 56
   at 1091, lg 48 at 1102, md/num 40 at 1440 exactly), and the tracking is the
   measured -.05em at every size. Line height is the measured ratio. */
.t-display-xl{font-family:var(--font-display);font-weight:300;font-size:clamp(36px,2rem + 2.2vw,56px); line-height:1.05;letter-spacing:-.05em;color:var(--ink)}
.t-display-lg{font-family:var(--font-display);font-weight:300;font-size:clamp(32px,1.9rem + 1.6vw,48px);line-height:1.05;letter-spacing:-.05em;color:var(--ink)}
.t-display-md{font-family:var(--font-display);font-weight:300;font-size:clamp(28px,1.6rem + 1vw,40px);  line-height:1.15;letter-spacing:-.05em;color:var(--ink)}
.t-num       {font-family:var(--font-display);font-weight:300;font-size:clamp(32px,1.6rem + 1vw,40px);  line-height:1.25;letter-spacing:-.05em;color:var(--ink)}

.t-h3        {font-family:var(--font-body);font-weight:400;font-size:20px;line-height:27px;letter-spacing:-.4px;color:var(--ink)}
.t-h4        {font-family:var(--font-body);font-weight:400;font-size:18px;line-height:25.2px;color:var(--ink)}
.t-body      {font-family:var(--font-body);font-weight:400;font-size:16px;line-height:23.2px;color:var(--muted)}
.t-sm        {font-family:var(--font-body);font-weight:400;font-size:14px;line-height:21px;color:var(--muted)}
.t-sm-strong {font-family:var(--font-body);font-weight:500;font-size:14px;line-height:21px;color:var(--ink)}
.t-brand     {font-family:var(--font-brand);font-weight:500;font-size:18px;line-height:21.6px;letter-spacing:-.54px;color:var(--ink)}
/* an inline link inside body copy (the reset removes underlines from every a) */
.t-link      {color:var(--ink);text-decoration:underline;text-decoration-color:rgba(28,26,21,.35);text-underline-offset:.15em;transition:text-decoration-color .15s var(--hover-ease)}
.t-link:hover{text-decoration-color:var(--ink)}

/* display headings mix ink + muted words: <em> marks the muted run */
.t-display-xl em,.t-display-lg em,.t-display-md em{font-style:normal;color:var(--muted)}

/* headings wrap evenly, so a hand-placed <br> that leaves a long second line (or a
   phone width that does) never strands one word ("matching.", "in.") on a line */
h1,h2,h3,h4,.t-display-xl,.t-display-lg,.t-display-md{text-wrap:balance}

/* the hand-placed line breaks in the display headlines are set for the wide
   measure; on a phone the copy wraps on its own */
@media (max-width:600px){
  .t-display-lg br,.t-display-xl br{display:none}
  /* the hidden break must still separate the words */
  .t-display-lg br+em::before,.t-display-xl br+em::before{content:" "}
}

/* ---- Layout primitives -------------------------------------------------- */
/* Gutterless, as measured: the 40px side gutter comes from each section's own
   `padding: 96px 40px`, so content lands at x=120 in a 1440 viewport. */
.container{width:100%;max-width:var(--container);margin-inline:auto}
/* Every band on the site shares this rhythm; it used to be restated in
   17 section sheets. A sheet that needs different padding overrides it
   wholesale (hero, page-hero, footer, prc-plans, prc-hero) — and must
   override all three steps, not just the base, because this file loads
   first and its media rules would otherwise win at 900 and 600. */
.section{position:relative;padding:96px 40px}
@media (max-width:900px){.section{padding:72px 24px}}
@media (max-width:600px){.section{padding:56px var(--gutter)}}
/* a second page that opens on a normal section, not the hero, still clears
   the fixed bar */
main > .section:first-child:not(.hero){padding-top:calc(var(--header-h) + 32px)}

/* Eyebrow label that opens every section.
   Measured: Onest 15/19.5 --muted, a 10x5 pill marker, 6px gap, 2px left inset. */
.eyebrow{
  display:inline-flex;align-items:center;gap:6px;
  padding-left:2px;
  font-family:var(--font-body);font-weight:400;font-size:15px;line-height:19.5px;
  color:var(--muted);
}
.eyebrow::before{content:"";width:10px;height:5px;border-radius:var(--r-pill);background:var(--muted);flex:none}

/* ---- Noise ---------------------------------------------------------------
   One grain layer for every panel that takes one (features cards, the sticky
   media wells, the use-case screens). Sits on top of whatever fills the
   panel, takes the panel's own corner radius, and is tuned per section with
   --noise-opacity / --noise-blend. */
.noise{
  position:absolute;
  inset:0;
  border-radius:inherit;
  pointer-events:none;
  opacity:var(--noise-opacity,.05);
  mix-blend-mode:var(--noise-blend,normal);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:160px 160px;
}

/* ---- Buttons ------------------------------------------------------------
   Style measured from sentira.framer.website and translated to this palette:
   44 tall, r12, padding 10px 20px, 16/500 with -0.04em tracking (they use
   Geist; we use Onest), no border, no shadow. Two fills:
   · primary    ink on page (their white-on-black, inverted)
   · secondary  6% ink tint (their 10% white) with a 16px round ink coin
                holding a 7px arrow at the end
   · light      page fill with ink text, for use ON dark or photo surfaces
                (this is their primary, un-inverted)
   · ghost      no fill, muted text — nav links, "Log in"
   Hover: the label blur-swaps — the resting copy blurs out and lifts, a
   second copy blurs in from below (their Text 1 / Text 2 pair). Mark up as
   <a class="btn btn--primary"><span class="btn__text" data-label="Book a demo"><span class="btn__l">Book a demo</span></span></a>
   - the inner span is the real (accessible) label; ::after draws the copy.
   Sizes: .btn--sm is 40 tall / 8px 16px / 15px for header use. */
.btn{
  position:relative;display:inline-flex;align-items:center;justify-content:center;gap:8px;
  height:44px;padding:10px 20px;border-radius:var(--r-12);border:0;
  font-family:var(--font-body);font-weight:500;font-size:16px;line-height:24px;letter-spacing:-.04em;
  white-space:nowrap;cursor:pointer;text-decoration:none;
  transition:background-color var(--hover-dur) var(--hover-ease),
             color var(--hover-dur) var(--hover-ease),
             opacity var(--hover-dur) var(--hover-ease);
}
.btn--sm{height:40px;padding:8px 16px;font-size:16px;line-height:24px;border-radius:var(--r-12)}

.btn--primary{background:var(--ink);color:var(--on-dark)}
.btn--primary:hover{background:var(--ink-hover)}
.btn--secondary{background:rgba(28,26,21,.06);color:var(--ink)}
.btn--secondary:hover{background:rgba(28,26,21,.1)}
.btn--ghost{background:transparent;color:var(--muted)}
.btn--ghost:hover{background:rgba(28,26,21,.06);color:var(--ink)}

/* label blur-swap */
.btn__text{
  position:relative;display:block;overflow:hidden;
}
.btn__l{
  display:block;
  transition:transform .32s var(--hover-ease),filter .32s var(--hover-ease),opacity .32s var(--hover-ease);
}
.btn__text::after{
  content:attr(data-label);position:absolute;inset:0;
  transform:translateY(60%);filter:blur(5px);opacity:0;
  transition:transform .32s var(--hover-ease),filter .32s var(--hover-ease),opacity .32s var(--hover-ease);
}
.btn:hover .btn__l,.btn:focus-visible .btn__l{transform:translateY(-60%);filter:blur(5px);opacity:0}
.btn:hover .btn__text::after,.btn:focus-visible .btn__text::after{transform:none;filter:none;opacity:1}


/* bare north-east arrow, for buttons that lead to another page but do not
   take the coin — on a filled .btn--primary an ink coin would disappear into
   the fill. Same path and same travel as the coin above, and as the feature
   cards and explore links, so one mark means "this leaves the page" across
   the whole site. */
.btn__go{flex:none;transition:transform .32s var(--hover-ease)}
.btn:hover .btn__go,
.btn:focus-visible .btn__go{transform:translate(3px,-3px)}


/* The hero pair, over the photo. There used to be generic .btn--light and
   .btn--on-dark variants here; nothing ever used them and they were removed.
   They only apply from 900 up — below that the hero stacks onto the page and
   both buttons go back to the ink-on-page pair — which is why the markup
   keeps btn--primary / btn--secondary and these recolour on top. Kept here,
   next to the button system, rather than in hero.css, so the fills stay in
   one file.

   The secondary was rgba(255,255,255,.16) with no blur, on the stated
   reasoning that "the picture behind them is already darkened by the card's
   scrim". There is no scrim — see the live-layout block in hero.css — so a
   translucent white pill with white type sat straight on the photograph. On
   hero-tv-wide.webp that is a sunlit hillside: 118/255 average luminance
   behind the button, giving white text about 1.6:1 where 4.5:1 is the floor.

   It now takes the same treatment the search bar in the hero demo already
   uses over this same picture (html[data-text="light"] .sp-search__bar in
   hero.css): a dark translucent fill over an 18px backdrop blur, with a white
   inset hairline. The blur is what does the work — it flattens whatever is
   behind the pill into an even tone, so the label holds up wherever the copy
   lands on the photo, and the two elements read as one family. Keep the two
   in step: if the bar's treatment changes, change this with it. */
@media (min-width:900px){
  .hero__cta{background:var(--page);color:var(--ink)}
  .hero__cta:hover{background:#fff}
  .hero__cta2{
    background:rgba(28,26,21,.38);
    color:#fff;
    box-shadow:inset 0 0 0 1px rgba(255,255,255,.12),0 8px 32px rgba(28,26,21,.18);
    -webkit-backdrop-filter:blur(18px) saturate(1.3);
    backdrop-filter:blur(18px) saturate(1.3);
  }
  .hero__cta2:hover{background:rgba(28,26,21,.5)}
}

@media (prefers-reduced-motion:reduce){
  .btn__l,.btn__text::after,.btn__go{transition:none}
  .btn:hover .btn__l{transform:none;filter:none;opacity:1}
  .btn:hover .btn__text::after{opacity:0}
  .btn:hover .btn__go,.btn:focus-visible .btn__go{transform:none}
}

/* ---- Skip link ----------------------------------------------------------
   build.js emits <a class="skip-link" href="#main"> as the first thing in the
   body. It is clipped rather than display:none so it keeps its place in the tab
   order, and takes the page's --page pill on :focus-visible. z-index 20 clears
   the fixed .header (z-index 10, header.css). */
.skip-link{
  position:fixed;
  top:12px;
  left:12px;
  z-index:20;
  /* clipped, not hidden: still focusable, still read in order */
  width:1px;height:1px;overflow:hidden;
  clip:rect(0 0 0 0);
  clip-path:inset(50%);
  white-space:nowrap;
}
.skip-link:focus-visible{
  width:auto;height:auto;overflow:visible;
  clip:auto;
  clip-path:none;
  padding:10px 16px;
  border-radius:var(--r-pill);
  background:var(--page);
  color:var(--ink);
  box-shadow:var(--shadow-card);
  font-family:var(--font-body);font-weight:500;font-size:15px;line-height:19.5px;
}

/* ---- Focus --------------------------------------------------------------
   One ring for the whole page. :where() keeps it at zero specificity, so a
   control that draws its own corner radius (.btn, .header__link, ...) keeps
   it, and a surface that needs a different colour — white over the hero
   photo, see header.css — can override with a single class. */
:where(a,button,summary,[tabindex]):focus-visible{
  outline:2px solid var(--ink);
  outline-offset:2px;
  border-radius:var(--r-6);
}

/* ---- Appear engine ------------------------------------------------------ */
/* Measured: initial {opacity:.001, y:16px}, spring 1.2s bounce .1,
   stagger delays 0.05s .. 0.4s. Some runs add a 3px blur (split headlines).

   The two HIDDEN base rules are scoped to html.js — build.js puts an inline
   script at the very top of <head> that adds that class — because only
   scripts/main.js ever adds .is-in. Without JS the class is never set, so an
   unscoped base rule would leave the whole page invisible; scoped, no-JS simply
   gets the finished state. .is-in and the reduced-motion override stay
   unscoped: they are the visible state and must win wherever they apply — which
   is why the scope is written :where(html.js), at zero specificity, so these two
   rules weigh exactly what they weighed before and the cascade is unchanged. */
:where(html.js) [data-appear]{
  opacity:.001;
  /* Measured travel: 32px everywhere except the hero, which uses 16px.
     Override with --appear-y on the element or a section wrapper. */
  transform:translateY(var(--appear-y,32px));
  transition:opacity var(--appear-dur) var(--appear-ease),
             transform var(--appear-dur) var(--appear-ease),
             filter var(--appear-dur) var(--appear-ease);
  transition-delay:var(--appear-delay,.05s);
}
:where(html.js) [data-appear="blur"]{filter:blur(3px)}
[data-appear].is-in{opacity:1;transform:none;filter:none}

@media (prefers-reduced-motion:reduce){
  [data-appear]{opacity:1;transform:none;filter:none;transition:none}
  /* stop everything: the duration clamp alone still leaves infinite
     animations (the two marquees) running */
  *{animation-duration:.01ms!important;transition-duration:.01ms!important;animation:none!important}
}

/* /styles/header.css */
/* ==========================================================================
   Header / primary nav — the template's bar, measured at 1440x900:

   bar          1440 x --header-h (64; template: 76), position:fixed,
                z-index 10, solid var(--page), padding 10px 40px 9px +
                the 1px --line-header hairline. Past 8px of scroll
                (.is-stuck) it stays flush to the top, narrows to the 1200
                rail plus 24px each side, goes --panel grey and rounds its
                two bottom corners.
   inner rail   1200 x 44 at x=120, flex space-between
   brand        150 wide: 24x24 mark + 6 gap + Onest 20/500 -.02em wordmark
   centre       flex 1, links centred, gap 32: 44-tall links, padding 10/16,
                r8, Onest 15/400 --muted, hover fill --panel
   actions      ghost "Log in" + primary CTA, both .btn--sm (40 tall), gap 4
   dropdown     240-wide panel under the Product trigger, flush left
   burger       under 900 only: 40x40, two 16px bars -> cross
   drawer       under 900 only: full-width --page panel under the bar,
                sliding down 200ms; scripts/drawer.js owns the state
   ========================================================================== */

.header{
  position:fixed;
  inset:0 0 auto 0;
  z-index:10;
  height:var(--header-h);
  /* the bar is centred by the flex parent, not margin:auto, so its width can
     animate between the full strip and the stuck tab */
  display:flex;
  justify-content:center;
}

.header__bar{
  display:flex;
  align-items:center;
  justify-content:center;
  width:100%;
  max-width:100%;
  height:var(--header-h);
  /* 9px bottom + the 1px hairline keeps the box at 64 and the rail at y 10..54 */
  padding:10px 40px 9px;
  background:var(--page);
  border:0;
  border-bottom:1px solid var(--line-header);
  border-radius:0;
  margin:0;
  /* the edge-mode fade (below) runs on this curve */
  transition:background-color .25s var(--hover-ease),
             border-color .25s var(--hover-ease),
             border-radius .25s var(--hover-ease),
             box-shadow .25s var(--hover-ease),
             max-width .25s var(--hover-ease),
             padding .25s var(--hover-ease);
}

/* Stuck (scripts/main.js adds .is-stuck past 8px of scroll): the bar stays
   flush with the top edge, rounds its two bottom corners and takes the --panel
   grey. From 1280 up it also narrows to the page rail (--container) plus a
   24px overhang each side, with the same 24px as inner padding: the logo,
   links and buttons stay exactly where they were on the full strip (the rail
   is centred in both), and the tab's edges sit just outside the section
   content below. Under 1280 the strip stays full width, because narrowing
   it there would push the rail's contents. */
.header.is-stuck .header__bar{
  background:var(--panel);
  border-bottom-color:var(--line-header);
  border-radius:0 0 var(--r-16) var(--r-16);
  box-shadow:var(--shadow-card);
}
@media (min-width:1280px){
  .header.is-stuck .header__bar{
    max-width:calc(var(--container) + 48px);
    padding-inline:24px;
  }
}
/* the CTA is white in every state: over the hero, on the --page strip and on
   the grey tab, where the hairline and shadow lift it off the surface */
.header__actions .btn--primary{
  background:#fff;
  color:var(--ink);
  box-shadow:0 0 0 1px var(--line), 0 1px 2px rgba(0,0,0,.05);
}
.header__actions .btn--primary:hover{background:#fff;box-shadow:0 0 0 1px var(--line), 0 2px 6px rgba(0,0,0,.1)}
.header.is-stuck .header__actions .btn--ghost{color:var(--ink)}

/* on the grey tab the links' resting --page fill would show as pale pills:
   they sit flat, and hover/open take the next tint down */
.header.is-stuck .header__link,
.header.is-stuck .header__trigger{background:transparent}
.header.is-stuck .header__link:hover,
.header.is-stuck .header__link:focus-visible,
.header.is-stuck .header__item--drop:hover:not(.is-closed) .header__trigger,
.header.is-stuck .header__item--drop:focus-within:not(.is-closed) .header__trigger,
.header.is-stuck .header__item--drop.is-open .header__trigger{background:var(--soft)}
.header.is-stuck .header__actions .btn--ghost:hover{background:var(--soft)}

.header__inner{
  display:flex;
  align-items:center;
  justify-content:space-between;
  width:100%;
  max-width:var(--container);
  margin-inline:auto;
  height:44px;
}

/* ---- brand -------------------------------------------------------------- */
.header__brand{
  display:flex;
  align-items:center;
  justify-content:flex-start;
  flex:0 0 150px;
  width:150px;
  height:40px;
}
.header__logo{
  display:inline-flex;
  align-items:baseline;   /* the mark is a letter: it sits on the baseline */
  gap:5px;                /* .16em: a letter sidebearing, not a word space */
  height:40px;
}
.header__mark{
  display:inline-block;
  flex:none;
  width:22px;                        /* = cap height of the 31px wordmark */
  height:22px;
  color:var(--ink);                  /* the mark is fill:currentColor */
}
.header__mark svg{display:block}
/* 31px against the nav's 16px label: the brand has to outrank the menu.
   The lockup measures 128px, inside the 150 brand rail; the 40px line sits
   inside .header__inner's 44, so the bar stays 64. */
.header__wordmark{
  font-family:var(--font-body);
  font-weight:500;
  font-size:31px;
  line-height:40px;
  letter-spacing:-.02em;
  color:var(--ink);
  white-space:nowrap;
}

/* ---- right rail: nav + actions ------------------------------------------ */
/* ---- centre band: links centred in the leftover width ------------------ */
.header__centre{
  display:flex;
  align-items:center;
  justify-content:center;
  flex:1 0 0;
  min-width:0;
  height:44px;
}
.header__right{
  display:flex;
  align-items:center;
  justify-content:flex-end;
  flex:0 0 auto;
}
.header__actions{display:flex;align-items:center;gap:4px}
.header__nav{
  display:flex;
  align-items:center;
  justify-content:center;
  gap:4px;
  height:44px;
}
.header__item{display:flex;align-items:center}

/* nav link: 44 tall, padding 10/16, r8; --panel fill + ink label on hover */
.header__link{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:6px;
  height:44px;
  padding:10px 16px;
  border-radius:var(--r-8);
  background:var(--page);
  transition:background-color .15s var(--hover-ease);
}
.header__link:hover,
.header__link:focus-visible{background:var(--panel)}
.header__label{
  font-family:var(--font-body);
  font-weight:500;
  font-size:16px;
  line-height:20px;
  color:var(--ink);
  white-space:nowrap;
  transition:color .15s var(--hover-ease);
}
.header__link:hover .header__label,
.header__link:focus-visible .header__label{color:var(--ink)}

/* ---- dropdown trigger --------------------------------------------------- */
/* the drop's own token: the distance from the bar to its panel, used by the
   panel's top offset and by the transparent bridge that spans it */
.header__item--drop{position:relative;--panel-gap:18px}

.header__trigger{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:6px;
  height:39.5px;
  padding:10px 12px;
  border-radius:var(--r-8);
  background:var(--page);
  transition:background-color .25s var(--hover-ease);
}
.header__item--drop:hover:not(.is-closed) .header__trigger,
.header__item--drop:focus-within:not(.is-closed) .header__trigger,
.header__item--drop.is-open .header__trigger{background:var(--panel)}
.header__trigger .header__label{transition:color .35s var(--hover-ease)}
.header__chevron{
  flex:none;
  width:8px;
  height:8px;
  color:var(--muted);
  transition:color .35s var(--hover-ease),transform .25s var(--hover-ease);
}
/* the chevron points at the panel: down while closed, flipped up once the
   drop is open, on the same three states that light the trigger below */
.header__item--drop:hover:not(.is-closed) .header__chevron,
.header__item--drop:focus-within:not(.is-closed) .header__chevron,
.header__item--drop.is-open .header__chevron{transform:rotate(180deg)}
.header__item--drop:hover:not(.is-closed) .header__label,
.header__item--drop:focus-within:not(.is-closed) .header__label,
.header__item--drop.is-open .header__label,
.header__item--drop:hover:not(.is-closed) .header__chevron,
.header__item--drop:focus-within:not(.is-closed) .header__chevron,
.header__item--drop.is-open .header__chevron{color:var(--ink)}

/* ---- dropdown panel ----------------------------------------------------- */
/* 240 wide, opened flush with the trigger's left edge and 8px below the bar:
   the trigger sits at y 14..46 inside a 60px bar, so 100% + 22px = y 68.
   The trigger is the first item of the right rail, and Solutions/Resources/
   Pricing + the 22px gap + both buttons keep ~500px of rail to its right, so a
   240-wide panel never reaches the viewport edge; the max-width below is a
   belt-and-braces guard for very narrow rails.
   Open motion: opacity 0 -> 1 and scale .9 -> 1 from the top-left, ~170ms. */
.header__panel{
  position:absolute;
  top:calc(100% + var(--panel-gap));
  left:0;
  right:auto;
  width:240px;
  max-width:calc(100vw - 48px);
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:0;
  padding:8px;
  border-radius:var(--r-12);
  background:var(--page);
  box-shadow:0 4px 16px rgba(0,0,0,.04);

  opacity:0;
  visibility:hidden;
  pointer-events:none;
  transform:scale(.9);
  transform-origin:top left;
  transition:opacity .17s cubic-bezier(.4,.65,.35,1),
             transform .17s cubic-bezier(.4,.65,.35,1),
             visibility 0s linear .17s;
}

/* The panel sits --panel-gap below the trigger, and that gap is empty: the
   pointer leaves the <li> on its way down, which fires mouseleave, marks the
   dropdown closed (scripts/dropdown.js) and drops pointer-events — so the
   links could never be reached with a mouse. This bridges the gap with a
   transparent strip belonging to the panel itself, so the pointer stays
   inside the <li> the whole way. It inherits the panel's pointer-events, so
   it is inert while the panel is closed and cannot swallow clicks on the bar
   behind it. */
.header__panel::before{
  content:"";
  position:absolute;
  left:0;
  right:0;
  top:calc(var(--panel-gap) * -1);
  height:var(--panel-gap);
}
.header__item--drop:hover:not(.is-closed) .header__panel,
.header__item--drop:focus-within:not(.is-closed) .header__panel,
.header__item--drop.is-open .header__panel{
  opacity:1;
  visibility:visible;
  pointer-events:auto;
  transform:scale(1);
  transition:opacity .17s cubic-bezier(.4,.65,.35,1),
             transform .17s cubic-bezier(.4,.65,.35,1),
             visibility 0s;
}

/* the panel is a plain <ul>; its rows are the flex children now */
.header__panel > li{display:flex;width:100%}

.header__panel-item{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:4px;
  width:224px;
  padding:10px 12px 8px;      /* -> 59.1 tall */
  border-radius:var(--r-8);
  background:var(--page);
  transition:background-color .15s var(--hover-ease);
}
.header__panel-item:hover,
.header__panel-item:focus-visible{background:var(--panel)}

.header__panel-row{
  display:flex;
  flex-direction:row;
  align-items:flex-start;
  gap:12px;
  width:200px;
}
.header__panel-icon{
  display:flex;
  align-items:center;
  flex:none;
  width:14px;
  height:17px;
  padding-top:3px;
  border-radius:var(--r-4);
  color:var(--ink);
}
.header__panel-text{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:2px;
  width:174px;
}
.header__panel-title{
  display:block;
  font-family:var(--font-body);
  font-weight:400;
  font-size:15px;
  line-height:19.5px;
  color:var(--ink);
  width:100%;
}
.header__panel-sub{
  display:block;
  font-family:var(--font-body);
  font-weight:400;
  font-size:14px;
  line-height:19.6px;
  color:var(--muted);
  width:100%;
}

/* ---- actions ------------------------------------------------------------ */
/* Both controls are global .btn--sm (40 tall, r10) — see the Buttons block in
   styles/global.css for the blur-swap label markup. */
.header__actions{
  display:flex;
  flex-direction:row;
  align-items:center;
  justify-content:flex-end;
  gap:8px;
  flex:0 0 auto;
  height:40px;
}

/* ---- over the hero card (data-bleed: edge) -------------------------------
   getfernand.com's idiom: the hero card starts at y=0 and runs under the
   fixed header, which is transparent with white type until the page scrolls
   (main.js adds .is-stuck past 8px), then settles back to the solid --page
   bar with its hairline. The card carries no scrim (by decision — see the
   live-layout block in hero.css), so the white bar type reads against the
   picture itself. */
@media (min-width:900px){
  /* the fade runs on .header__bar's own transition */
  html[data-bleed="edge"] .header:not(.is-stuck) .header__bar{background:transparent;border-bottom-color:transparent}
  html[data-bleed="edge"] .header:not(.is-stuck) .header__wordmark,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__mark,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__label,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__globe,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__chevron{color:#fff}
  html[data-bleed="edge"] .header:not(.is-stuck) .header__link,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__trigger{background:transparent}
  html[data-bleed="edge"] .header:not(.is-stuck) .header__link:hover,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__link:focus-visible,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__item--drop:hover:not(.is-closed) .header__trigger,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__item--drop:focus-within:not(.is-closed) .header__trigger,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__item--drop.is-open .header__trigger{background:rgba(255,255,255,.14)}
  html[data-bleed="edge"] .header:not(.is-stuck) .header__item--drop:hover:not(.is-closed) .header__label,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__item--drop:hover:not(.is-closed) .header__chevron,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__item--drop.is-open .header__label,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__item--drop:hover:not(.is-closed) .header__globe,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__item--drop.is-open .header__globe,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__item--drop.is-open .header__chevron{color:#fff}
  html[data-bleed="edge"] .header:not(.is-stuck) .header__actions .btn--ghost{color:#fff}
  html[data-bleed="edge"] .header:not(.is-stuck) .header__actions .btn--ghost:hover{background:rgba(255,255,255,.14);color:#fff}
  /* The burger only exists under 900 and this block only applies from 900 up,
     so these two are inert today. They are written anyway so the white-on-photo
     treatment is complete if the edge preset ever reaches the phone width. */
  html[data-bleed="edge"] .header:not(.is-stuck) .header__burger-bars::before,
  html[data-bleed="edge"] .header:not(.is-stuck) .header__burger-bars::after{background:#fff}
  html[data-bleed="edge"] .header:not(.is-stuck) .header__burger:hover{background:rgba(255,255,255,.14)}
  html[data-bleed="edge"] .header:not(.is-stuck) a:focus-visible,
  html[data-bleed="edge"] .header:not(.is-stuck) button:focus-visible{outline-color:#fff}
}

/* focus: the global ring (global.css). Over the hero photo the bar is
   transparent with white type, so the ring flips to white — see the
   data-bleed block above. */

/* ---- burger -------------------------------------------------------------
   Hidden from 900 up, where .header__centre carries the nav. Two 16px bars
   8px apart that rotate into a cross when the drawer is open; scripts/drawer.js
   puts .is-open on the button alongside aria-expanded. */
.header__burger{
  display:none;
  align-items:center;
  justify-content:center;
  flex:none;
  width:44px;
  height:44px;
  margin-left:4px;
  border-radius:var(--r-10);
  background:transparent;
  color:var(--ink);
  transition:background-color .15s var(--hover-ease);
}
.header__burger:hover{background:var(--panel)}

.header__burger-bars{
  position:relative;
  display:block;
  width:16px;
  height:9.5px;
}
.header__burger-bars::before,
.header__burger-bars::after{
  content:"";
  position:absolute;
  left:0;
  width:16px;
  height:1.5px;
  border-radius:1px;
  background:currentColor;
  transition:top .2s var(--hover-ease),transform .2s var(--hover-ease);
}
.header__burger-bars::before{top:0}
.header__burger-bars::after{top:8px}
.header__burger.is-open .header__burger-bars::before{top:4px;transform:rotate(45deg)}
.header__burger.is-open .header__burger-bars::after{top:4px;transform:rotate(-45deg)}

/* ---- mobile drawer -------------------------------------------------------
   A full-width --page panel hanging under the bar. It is a sibling of
   .header__bar inside the fixed .header, so top:100% is the bar's own bottom
   edge. */
.header__drawer{
  position:absolute;
  top:100%;
  left:0;
  right:0;
  /* 100vh is the LARGE viewport on mobile Safari, so with the URL bar
     showing the box believes it is taller than the visible area and the
     bottom actions sit under the chrome, unreachable. dvh tracks the
     real box; the vh line stays as the fallback. */
  max-height:calc(100vh - var(--header-h) - 24px);
  max-height:calc(100dvh - var(--header-h) - 24px);
  overflow-y:auto;
  overscroll-behavior:contain;
  background:var(--page);
  border-bottom:1px solid var(--line-header);
  box-shadow:var(--shadow-pop);

  opacity:0;
  transform:translateY(-12px);
  transition:opacity .2s var(--hover-ease),
             transform .2s var(--hover-ease);
}
.header__drawer[hidden]{display:none}
.header__drawer.is-open{opacity:1;transform:none}
/* the open drawer continues the bar, so the bar's rounded bottom corners and
   hairline move down to the drawer's own bottom edge */
body.is-drawer-open .header.is-stuck .header__bar{border-radius:0;box-shadow:none}
.header.is-stuck .header__drawer{border-radius:0 0 var(--r-16) var(--r-16)}

.header__drawer-inner{
  display:flex;
  flex-direction:column;
  gap:20px;
  padding:20px 24px 24px;
}
.header__drawer-label{
  font-family:var(--font-body);
  font-weight:400;
  font-size:13px;
  line-height:19.5px;
  color:var(--faint);
}
.header__drawer-label + .header__drawer-list{margin-top:-12px}
.header__drawer-list{
  display:flex;
  flex-direction:column;
  gap:2px;
}
.header__drawer-link{
  display:block;
  padding:10px 12px;
  margin-inline:-12px;
  border-radius:var(--r-8);
  font-family:var(--font-body);
  font-weight:400;
  font-size:17px;
  line-height:24px;
  color:var(--ink);
  transition:background-color .15s var(--hover-ease);
}
.header__drawer-link:hover,
.header__drawer-link:focus-visible{background:var(--panel)}

.header__drawer-actions{
  display:flex;
  flex-direction:column;
  gap:8px;
  padding-top:4px;
}
.header__drawer-actions .btn{width:100%}

/* body scroll lock while the drawer is open (scripts/drawer.js).
   overflow:hidden on body alone does not hold on iOS Safari, and dropping
   the scrollbar shifts the page sideways on a narrow desktop window, so
   lock the root too and reserve the gutter. */
html{scrollbar-gutter:stable}
body.is-drawer-open{overflow:hidden}
html:has(body.is-drawer-open){overflow:hidden}

/* ---- responsive --------------------------------------------------------- */
@media (max-width:899px){
  .header__bar{padding:10px 24px 9px}
  .header__centre{display:none}          /* nav collapses out; the drawer replaces it */
  /* min-width:0 gives the rail somewhere to give: without it the brand's
     min-content floor is the full nowrap wordmark, and with no
     overflow-x:hidden anywhere a longer CTA label becomes a real
     horizontal scrollbar on every page. */
  .header__brand{flex:1 1 auto;width:auto;min-width:0}
  .header__logo{min-width:0;overflow:hidden}
  .header__burger{display:inline-flex}
}
@media (max-width:600px){
  .header__bar{padding:10px var(--gutter) 9px}
  .header__actions .btn--ghost{display:none}   /* "Log in" drops out — it is in the drawer */
  .header__actions .btn--sm{padding:8px 14px}
  .header__drawer-inner{padding:16px var(--gutter) 20px}
}
/* the drawer never opens from 900 up: the centre band is back */
@media (min-width:900px){
  .header__drawer{display:none}
}

@media (prefers-reduced-motion:reduce){
  .header__panel{transition:opacity .01ms}
  .header__chevron{transition:color .35s var(--hover-ease)}
  .header__drawer,.header__burger-bars::before,.header__burger-bars::after{transition:none}
}

/* ---------------------------------------------------------------------------
   Language selector

   Lives in the right rail, so the panel hangs off the right edge — the base
   .header__panel opens leftwards and would run off the viewport here.

   Hidden under 900 along with the centre nav: the drawer already carries a
   language link, and the rail at that width is down to the burger and the
   trial button.
   --------------------------------------------------------------------------- */
.header__lang{
  display:inline-flex;
  align-items:center;
}

.header__lang-trigger{
  gap:4px;
  padding:10px;
}

/* The globe stands in for .header__label here — it is the control, not an
   ornament — so it takes the label's ink and the label's transition. The
   chevron beside it keeps its own --muted from .header__chevron, which is
   what every other trigger in this bar does. */
.header__globe{
  display:block;
  flex:none;
  color:var(--ink);
  transition:color .15s var(--hover-ease);
}

.header__panel--lang{
  left:auto;
  right:0;
  width:168px;
  transform-origin:top right;
}

/* One line each, not the stacked title + description the nav panels use. */
.header__panel-item--lang{
  flex-direction:row;
  align-items:center;
  justify-content:space-between;
  width:152px;
  padding:9px 12px;
  font-family:var(--font-body);
  font-size:15px;
  color:var(--ink);
}

/* The language you are already reading. Marked, not hidden: a chooser that
   drops the current option leaves you unable to tell where you are. */
.header__panel-item--lang[aria-current]{
  color:var(--muted);
}
.header__panel-item--lang[aria-current]::after{
  content:"";
  width:14px;height:14px;
  flex:none;
  background:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath d='M2.8 7.4 5.6 10.2 11.2 4.2' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath d='M2.8 7.4 5.6 10.2 11.2 4.2' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;
}

@media (max-width:900px){
  .header__lang{display:none}
}

/* /styles/hero.css */
/* ==========================================================================
   Hero — all numbers measured from the reference at 1440x900.

   The page ships ONE hero layout, fixed by the attributes build.js writes on
   <html> (data-hero="wide" data-text="light" data-bleed="edge"
   data-logos="inside"): from 900 up, a picture card that runs the full width
   of the window, flush with its top and 12px from its sides and bottom, with
   the headline block and the sourcing demo sitting on it in light type and
   the customer logos pulled up onto its foot. See the block at the end of
   this file. Below 900 the card and the copy stack, the copy first, and the
   type goes back to ink on the page.

   Measured base geometry (the template's 45/55 split, still the fallback the
   stacked layout is built from):
   section 1440x900 · padding (header + 20)/40/64 · container 1200 (x=120)
   left column 540x616 (centred, gap 32, pad-bottom 32)
   headline stack gap 24 · badge 265x21 · h1 540x117.6 · lead 400x75.6
   (lead + scope line nested at gap 8, see .hero__lede)
   CTA 127x44 (r10) · visual 660x616 (r16) · ticker 1200x112 (pad 32)
   viewport 1136x48 · group gap 72, loop gap 64
   The sourcing demo (scripts/hero.js) is parked behind data-demo="off".
   ========================================================================== */

.hero{
  /* the hero is the one band whose appear blocks travel 16px, not the 32px
     used everywhere below it */
  --appear-y:16px;
  position:relative;
  display:flex;
  min-height:max(800px,100vh);
  padding:calc(var(--header-h) + 20px) 40px 64px;
  overflow:hidden;
  background:var(--page);
}

.hero__container{
  width:100%;
  max-width:var(--container);
  margin-inline:auto;
  display:flex;
  flex-direction:column;
  align-items:center;
}

/* content row: 1200 x 628 (12px top pad + 616 columns) */
.hero__content{
  width:100%;
  flex:1 0 auto;
  display:flex;
  flex-direction:row;
  align-items:flex-start;
  justify-content:space-between;
  padding-top:12px;
}

/* ---- left column — 540 x 616, content centred vertically ---------------- */
.hero__left{
  flex:none;
  width:45%;
  height:clamp(516px,calc(100vh - 284px),700px);
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  justify-content:center;
  gap:32px;
  padding-bottom:32px;
  text-align:left;
}

.hero__headline{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:24px;
}
/* display headline — 540 wide, two 58.8px lines */
.hero__title{
  width:100%;
  max-width:540px;
  margin:0;
}
.hero__word{display:inline-block}

/* paragraph + scope line as one block. The headline stack's own gap is 24,
   which is the right distance from a 56px display line but far too much
   between a paragraph and its one-line qualifier, so they are nested and
   spaced at 8 instead. */
.hero__lede{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:8px;
}

/* supporting paragraph — 400 wide, three 25.2px lines */
.hero__lead{
  width:100%;
  max-width:400px;
  font-family:var(--font-body);
  font-weight:400;
  font-size:18px;
  line-height:25.2px;
  color:var(--muted);
}

/* scope line — the quiet qualifier under the paragraph. Type is the .t-sm
   utility; only the measure and the on-photo colour are set here. It takes
   the lead's measure (the .hero__lede block is as wide as its widest child,
   so 400 here and 440 under 900) and the sentence runs to about 380 at 14px,
   so it holds one line on the card and folds to two on a phone. */
.hero__scope{width:100%}

/* CTA row: the global .btn pair (see global.css); wraps on narrow phones */
.hero__actions{
  display:flex;
  align-items:center;
  flex-wrap:wrap;
  gap:8px;
}

/* ---- right visual — 660 x 616 rounded card, the illustration covers it -- */
.hero__visual{
  position:relative;
  width:55%;
  height:clamp(516px,calc(100vh - 284px),700px);
  border-radius:var(--r-16);
  overflow:hidden;
  flex:none;
  background:var(--sand);
}
/* the photo fills the card */
.hero__visual-bg{
  position:absolute;
  inset:0;
}
.hero__visual-bg img{
  width:100%;
  height:100%;
  object-fit:cover;
  object-position:50% 50%;
}
/* demo parked: data-demo="off" on the section hides it (scripts/hero.js also
   bails out on that attribute) */
.hero[data-demo="off"] .hero__demo,
.hero[data-demo="off"] .sp-search__toggle{display:none}

/* ==========================================================================
   Sourcing demo — the imported animation, rebuilt out of this page's parts.

   Kept from the import: the clock and every timing (type 62ms/char, press at
   3.0s, scan 3.2s, list opens 4.4s, a match every 2.6s, folds at 12.9s), the
   three faces of the puck (arrow / globe / cross), the scan strip that opens
   under the bar before the list does, the list stepping open, the portraits
   resolving top-down, the reason popping around each selection change.

   The surfaces are the reference's, measured rather than guessed
   (tools/archive/vocab.js, tools/archive/vocab2.js). What that survey settled:
   · the reference draws NO borders anywhere — 0 elements with a border width.
     Dividers are 1px filled rects, so that is what the separator is here.
   · it has NO uppercase text and NO letter-spaced labels. The status and the
     reason label are therefore sentence case in the page's own eyebrow idiom:
     a 10x5 pill plus Onest 14/21 --muted.
   · it has NO pill-shaped text chips. The one chip it does have is 63x22, r6,
     padding 5px 10px, Onest 12/12 500 on --ink — which is the score chip here.
   · its largest ink surface is a 356x44 button; there is no big dark panel in
     this design system. The list is therefore a light --panel card, not the
     import's ink one.
   · its motion is the spring (--appear-ease) and the 280ms hover curve, so the
     import's stepped pixel timing becomes those two curves, and the pixel
     arrow / block caret become the page's own stroke arrow and 1.5px caret.
   · its only shadow is --shadow-card (and --shadow-pop, the same shadow one
     step deeper), which is what both surfaces carry.
   · radii in use are 16/12/10/6 (--r-16 .. --r-6); this card uses 16 (list),
     12 (bar), 10 (rows, puck) and 6 (chips) and nothing else.
   ========================================================================== */
.hero__demo{
  position:absolute;
  z-index:2;
  left:auto;
  right:120px; /* centred in the card's right 660 */
  top:168px; /* (700-616)/2 + the reference's 126 */
  width:420px;
}
.sp-search{position:relative}

/* ---- bar: the page surface at r12, on the reference's shadow ----------- */
.sp-search__bar{
  position:relative;
  z-index:2;
  display:flex;
  align-items:center;
  gap:10px;
  height:52px;
  padding:3px 3px 3px 16px;
  border-radius:var(--r-12);
  background:var(--page);
  box-shadow:var(--shadow-card);
}
.sp-search__query{
  flex:1 1 auto;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;
  font-family:var(--font-body);font-weight:400;font-size:14px;line-height:21px;color:var(--ink);
}
.sp-search__query:empty::before{content:attr(data-placeholder);color:var(--faint)}
/* caret: a 1.5px rule on the page's own rhythm; blinks while resting, holds
   steady while typing (the import's caret does the same) */
.is-anim .sp-search__query::after{
  content:"";display:inline-block;width:1.5px;height:15px;margin-left:2px;vertical-align:-2px;
  background:var(--ink);animation:sp-caret 1.06s steps(1,end) infinite;
}
.is-typing .sp-search__query::after{animation:none;opacity:1}
.is-searching .sp-search__query::after,.is-open .sp-search__query::after{animation:none;opacity:0}
@keyframes sp-caret{0%,100%{opacity:1}50%{opacity:0}}

/* ---- puck: the page's 44-tall ink control, squared to 46 at r10 --------- */
.sp-search__puck{
  position:relative;flex:none;width:46px;height:46px;border-radius:var(--r-10);background:var(--ink);
  display:flex;align-items:center;justify-content:center;overflow:hidden;
  transition:transform .28s var(--hover-ease);
}
/* the click. The page's buttons take a --page wash on hover (10%); the press
   is that wash, stronger, with the puck sinking — quick in, eased out, so it
   reads as a press and a release rather than a flicker */
.sp-search__puck::after{
  content:"";position:absolute;inset:0;border-radius:inherit;background:var(--page);
  opacity:0;pointer-events:none;transition:opacity .28s var(--hover-ease);
}
.is-pressed .sp-search__puck{transform:scale(.88);transition-duration:.1s}
.is-pressed .sp-search__puck::after{opacity:.18;transition-duration:.1s}

/* The puck is a button with three faces. At rest and while the brief is
   typed it is the page's stroke arrow, the same one the badge and buttons
   use. It is pressed, and while the search loads the arrow gives way to the
   globe — the "Thinking Logos" sphere in its thinking state (scripts/orb.js).
   Once the profiles are in, the puck is the close button. Each face fades
   and travels on the hover curve, the way the page's own button arrow
   slides on hover. */
.sp-search__arrow,.sp-search__orb,.sp-search__x{
  position:absolute;left:50%;top:50%;
  transition:opacity .2s var(--hover-ease),transform .28s var(--hover-ease);
}
.sp-search__arrow{width:16px;height:16px;margin:-8px 0 0 -8px;color:var(--on-dark)}
.sp-search__orb{width:40px;height:40px;margin:-20px 0 0 -20px;opacity:0;transform:scale(.7)}
/* the close: the FAQ's own glyph — two round-capped bars — turned to a
   cross. It arrives the way the FAQ icon does, by rotating into place. */
.sp-search__x{width:15px;height:15px;margin:-7.5px 0 0 -7.5px;color:var(--on-dark);opacity:0;transform:rotate(0deg) scale(.6);overflow:visible}
.sp-search__x line{stroke:currentColor;stroke-width:2.2;stroke-linecap:round}

/* loading: the arrow steps out, the globe steps in */
.is-loading .sp-search__arrow{opacity:0;transform:translateX(6px)}
.is-loading .sp-search__orb{opacity:1;transform:none}

/* open: the cross replaces the globe */
.is-open .sp-search__arrow{opacity:0;transform:translateX(6px)}
.is-open .sp-search__x{opacity:1;transform:rotate(45deg);transition-delay:.1s,.1s}

/* ---- list: a --panel card at r16, stepping open under the bar ----------- */
.sp-search__drop{
  position:absolute;left:0;right:0;top:calc(100% - 14px);z-index:1;
  padding:22px 8px 8px;border-radius:var(--r-16);background:var(--panel);color:var(--ink);
  box-shadow:var(--shadow-pop);
  overflow:hidden;
  pointer-events:none;
  transition:height .34s var(--hover-ease),transform .34s var(--hover-ease),opacity .1s .2s linear;
}
/* The fold is a real height, not a clip-path: with the frosted glass
   (backdrop-filter, below) Chromium does not clip the blurred backdrop to an
   animating clip-path, so the corners rendered square for the length of each
   step. A height with overflow:hidden keeps the box's own border-radius.
   hero.js measures the card's natural height (--sp-drop-h) and the reason's
   (--sp-reason-h) and sets both on .sp-search. */
/* folded */
.is-anim .sp-search__drop{opacity:0;transform:translateY(-10px);height:0}
/* scanning: a 58px strip — just the status line, pulsing */
.is-anim.is-searching .sp-search__drop{
  opacity:1;transform:none;height:58px;
  transition:height .3s var(--hover-ease),transform .3s var(--hover-ease),opacity .05s linear;
}
/* open: down to the rows; the reason's height stays folded until a row is
   selected */
.is-anim.is-open .sp-search__drop{
  opacity:1;transform:none;height:calc(var(--sp-drop-h,auto) - var(--sp-reason-h,0px));
  transition:height .55s var(--appear-ease),transform .55s var(--appear-ease),opacity .05s linear;
}
/* selected: the card grows to take the reason */
.is-anim.is-open.is-selected .sp-search__drop{
  height:var(--sp-drop-h,auto);
  transition:height .4s var(--appear-ease),transform .4s var(--appear-ease),opacity .05s linear;
}
/* while hero.js measures, the card takes its natural height */
.sp-search.is-measuring .sp-search__drop{height:auto!important;transition:none!important}

/* status line: the section eyebrow, verbatim — 10x5 pill, Onest 14/21 muted */
.sp-search__status{
  display:flex;align-items:center;gap:6px;margin:0;padding:2px 10px 10px;
  font-family:var(--font-body);font-weight:400;font-size:14px;line-height:21px;
  color:var(--muted);white-space:pre;
}
.sp-search__status-bar{display:block;flex:none;width:10px;height:5px;border-radius:var(--r-pill);background:var(--muted)}
.is-searching .sp-search__status-bar{animation:sp-pulse 1.05s var(--hover-ease) infinite}
@keyframes sp-pulse{0%,100%{opacity:1}50%{opacity:.35}}

.sp-search__rows{display:flex;flex-direction:column;gap:2px}
.sp-search__row{
  display:flex;align-items:center;gap:12px;padding:8px 10px;border-radius:var(--r-10);
  transition:opacity .34s var(--hover-ease),transform .34s var(--hover-ease),
             background-color .28s var(--hover-ease);
}
.is-anim .sp-search__row{opacity:0;transform:translateY(-6px)}
.is-anim.is-open .sp-search__row{opacity:1;transform:none}
.is-open .sp-search__row:nth-child(1){transition-delay:.05s}
.is-open .sp-search__row:nth-child(2){transition-delay:.17s}
.is-open .sp-search__row:nth-child(3){transition-delay:.29s}
.sp-search__row.is-sel{background:var(--page);transition-delay:0s}

.sp-search__idx{
  flex:none;width:18px;
  font-family:var(--font-body);font-weight:400;font-size:14px;line-height:21px;color:var(--faint);
}
.sp-search__face{
  position:relative;flex:none;width:36px;height:36px;border-radius:var(--r-pill);overflow:hidden;
  background:var(--soft);
}
.sp-search__face img{
  display:block;width:100%;height:100%;object-fit:cover;object-position:50% 30%;
  /* resolves with the same blur the page's split headlines use; hero.js steps
     --face-blur down as each row lands */
  filter:blur(var(--face-blur,0px));
  transition:filter .12s linear;
}
.sp-search__who{display:flex;flex-direction:column;gap:0;flex:1 1 auto;min-width:0}
/* the reference's own two text styles: t-sm-strong over t-sm */
.sp-search__who b{
  font-family:var(--font-body);font-weight:500;font-size:14px;line-height:21px;
  color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.sp-search__who span{
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-family:var(--font-body);font-weight:400;font-size:14px;line-height:21px;color:var(--muted);
}
/* score chip: the reference's only chip — 22 tall, r6, 5px 10px, Onest 12/12 500.
   It swaps, it does not fade: a crossfade between ink-on-page and
   muted-on-soft passes through grey-on-grey. */
.sp-search__score{
  flex:none;padding:5px 10px;border-radius:var(--r-6);background:var(--soft);
  font-family:var(--font-body);font-weight:500;font-size:12px;line-height:12px;color:var(--muted);
}
.sp-search__row.is-sel .sp-search__score{background:var(--ink);color:var(--on-dark)}

/* the reason for the selected match; pops on each selection change.
   The rule above it is a 1px fill, because the reference draws no borders. */
.sp-search__reason{
  position:relative;margin:10px 10px 4px;padding:14px 0 4px;
  transition:opacity .3s var(--hover-ease),transform .3s var(--hover-ease);
}
.sp-search__reason::before{
  content:"";position:absolute;left:0;right:0;top:0;height:1px;background:var(--line);
}
.sp-search__reason-label{
  display:block;margin-bottom:2px;
  font-family:var(--font-body);font-weight:400;font-size:14px;line-height:21px;color:var(--faint);
}
.sp-search__reason p{
  font-family:var(--font-body);font-weight:400;font-size:14px;line-height:21px;color:var(--muted);
}
.is-anim .sp-search__reason{opacity:0;transform:translateY(4px)}
.is-anim.is-selected .sp-search__reason{opacity:1;transform:none;transition-delay:.2s}
.is-anim.is-swap .sp-search__reason{opacity:0;transform:translateY(3px);transition-duration:.15s;transition-delay:0s}
.sp-search.is-paused *,.sp-search.is-paused *::after{animation-play-state:paused!important;transition:none!important}

/* pause control: the page's chip, parked in the panel corner (outside
   .sp-search, so it can never overlap the list) */
.sp-search__toggle{
  position:absolute;right:16px;bottom:16px;z-index:3;
  display:inline-flex;align-items:center;gap:6px;
  padding:5px 10px;border-radius:var(--r-6);background:rgba(251,250,246,.86);
  font-family:var(--font-body);font-weight:500;font-size:12px;line-height:12px;color:var(--muted);
  transition:background-color var(--hover-dur) var(--hover-ease),color var(--hover-dur) var(--hover-ease);
}
.sp-search__toggle[hidden]{display:none}
.sp-search__toggle:hover{background:var(--page);color:var(--ink)}
.sp-search__toggle:focus-visible{outline:2px solid var(--page);outline-offset:2px}
.sp-search__toggle-icon{width:7px;height:8px;border-inline:2px solid currentColor}
/* paused: the two bars become the play triangle. scripts/hero.js carries the
   state on aria-pressed (the label is copy, and copy is not a selector). */
.sp-search__toggle[aria-pressed="true"] .sp-search__toggle-icon{
  border:0;background:currentColor;clip-path:polygon(0 0,100% 50%,0 100%);
}

/* ---- the demo on the photo (data-text: light) -----------------------------
   On the light-type hero the demo stops being a page-coloured widget and
   becomes dark glass, the same material as the "Book a demo" button and the
   header's hover states (translucent white on the picture, blurred behind).
   The puck flips to the primary button's page-on-ink inversion, so the one
   solid control matches the one solid button; the globe is the same canvas,
   inverted. Everything else is white at the page's own opacity steps
   (.86 lead / .72 muted / .5 faint). */
html[data-text="light"] .sp-search__bar{
  background:rgba(28,26,21,.38);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.12),0 8px 32px rgba(28,26,21,.18);
  -webkit-backdrop-filter:blur(18px) saturate(1.3);
  backdrop-filter:blur(18px) saturate(1.3);
}
html[data-text="light"] .sp-search__query{color:#fff}
html[data-text="light"] .sp-search__query:empty::before{color:rgba(255,255,255,.55)}
html[data-text="light"] .is-anim .sp-search__query::after{background:#fff}

html[data-text="light"] .sp-search__puck{background:var(--page);box-shadow:0 1px 2px rgba(28,26,21,.12)}
html[data-text="light"] .sp-search__puck::after{background:var(--ink)}
html[data-text="light"] .is-pressed .sp-search__puck::after{opacity:.1}
html[data-text="light"] .sp-search__arrow,
html[data-text="light"] .sp-search__x{color:var(--ink)}
html[data-text="light"] .sp-search__orb{filter:invert(1)}

html[data-text="light"] .sp-search__drop{
  background:rgba(28,26,21,.5);color:#fff;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.1),0 12px 40px rgba(28,26,21,.22);
  -webkit-backdrop-filter:blur(22px) saturate(1.3);
  backdrop-filter:blur(22px) saturate(1.3);
}
html[data-text="light"] .sp-search__status{color:rgba(255,255,255,.72)}
html[data-text="light"] .sp-search__status-bar{background:rgba(255,255,255,.72)}
html[data-text="light"] .sp-search__row.is-sel{background:rgba(255,255,255,.1)}
html[data-text="light"] .sp-search__idx{color:rgba(255,255,255,.45)}
html[data-text="light"] .sp-search__face{background:rgba(255,255,255,.16)}
html[data-text="light"] .sp-search__who b{color:#fff}
html[data-text="light"] .sp-search__who span{color:rgba(255,255,255,.66)}
html[data-text="light"] .sp-search__score{background:rgba(255,255,255,.12);color:rgba(255,255,255,.8)}
html[data-text="light"] .sp-search__row.is-sel .sp-search__score{background:var(--page);color:var(--ink)}
html[data-text="light"] .sp-search__reason::before{background:rgba(255,255,255,.14)}
html[data-text="light"] .sp-search__reason-label{color:rgba(255,255,255,.5)}
html[data-text="light"] .sp-search__reason p{color:rgba(255,255,255,.8)}

html[data-text="light"] .sp-search__toggle{
  background:rgba(28,26,21,.36);color:rgba(255,255,255,.8);
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
}
html[data-text="light"] .sp-search__toggle:hover{background:rgba(28,26,21,.5);color:#fff}

/* ---- source wordmark ticker — 1200 x 112 ------------------------------
   The marks are assignment sources the product scans, not customers; the
   customer marks live in sections/testimonials.html. See the caption note in
   sections/hero.html. */
.hero__ticker{
  width:100%;
  max-width:var(--container);
  margin-inline:auto;
  height:auto;
  padding:32px;
  display:flex;
  flex-wrap:wrap;
  gap:12px;
  align-items:center;
}
/* the two caption lines are one block: who the product is for, then where
   the wordmarks come from. Full width, so below 900 they take a row of
   their own above the strip instead of squeezing it. */
.hero__ticker-captions{
  width:100%;
  display:flex;
  flex-direction:column;
  gap:4px;
}
/* caption over the strip — only shown with logos: inside (spartan idiom) */
.hero__ticker-caption{
  display:none;
  max-width:300px;
  margin:0;
  font-family:var(--font-body);
  font-weight:400;
  font-size:14px;
  line-height:19.6px;
  color:#fff;
}
.hero__ticker-viewport{
  position:relative;
  width:100%;
  height:48px;
  display:flex;
  align-items:center;
  overflow:hidden;
  /* the leading and trailing wordmarks fade out at the edges */
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 96px,#000 calc(100% - 96px),transparent 100%);
  mask-image:linear-gradient(to right,transparent 0,#000 96px,#000 calc(100% - 96px),transparent 100%);
}
.hero__ticker-track{
  display:flex;
  gap:64px;
  align-items:center;
  will-change:transform;
}
/* measured drift: 20px/s leftwards; --hero-ticker-loop = group width + 64 */
.hero__ticker-track.is-running{animation:hero-ticker var(--hero-ticker-dur,66s) linear infinite}
@keyframes hero-ticker{from{transform:translateX(0)}to{transform:translateX(calc(var(--hero-ticker-loop,1316px) * -1))}}

.hero__ticker-group{
  flex:none;
  display:flex;
  align-items:center;
  gap:72px;
  height:35px;
}
.hero__logo{
  display:flex;
  align-items:center;
  gap:8px;
  height:28px;
  color:#000;
  opacity:.75;
}
.hero__logo svg{flex:none}
.hero__logo img{display:block} /* sized by the width/height attributes */

/* ---- responsive ----------------------------------------------------------
   Under 900 the hero stacks the way every other section does: the copy first,
   then the picture card at the desktop card's ratio, ink type on the page. */
@media (max-width:899px){
  .hero{min-height:0;padding:calc(var(--header-h) + 20px) 24px 64px}
  .hero__content{flex-direction:column;align-items:stretch;gap:0}
  .hero__left{width:100%;height:auto;padding-bottom:32px}
  /* the headline's break is the <br> in the markup, which global.css keeps
     down to 600 and drops below it — nothing to do here */
  .hero__title{max-width:none}
  .hero__lead{max-width:440px}
  /* full-width card at the desktop card's ratio, so the square art crops the same way */
  .hero__visual{width:100%;height:auto;aspect-ratio:660 / 616;border-radius:var(--r-12)}
  /* inset, not translateX(-50%): the appear engine ends on transform:none and
     would cancel a centring transform */
  .hero__demo{left:24px;right:24px;top:72px;width:auto;max-width:420px;margin-inline:auto}
  .hero__ticker{padding:32px 0}
}

@media (max-width:600px){
  .hero{padding:72px var(--gutter) 40px}
  /* The demo is absolute, so it adds nothing to the card's height — but the
     card is ratio-locked and the demo's height is content-driven, so on a
     phone the ranked list and the whole "why" panel fell outside the card's
     overflow:hidden. Below 600 the demo sits in flow and the card grows with
     it; .hero__visual-bg is inset:0 so the photo still fills whatever height
     that comes to. */
  .hero__visual{aspect-ratio:auto;height:auto;padding:52px 16px 16px}
  .hero__demo{position:static;width:auto;max-width:none;margin-inline:0}
  /* the drop is absolute inside .sp-search too, so the demo alone going static
     is not enough — the card would collapse to the bar. In flow here, and the
     -14px tuck replaces the top:calc(100% - 14px) offset. hero.js drives the
     fold with an explicit height, which animates the same either way. */
  .sp-search__drop{position:static;margin-top:-14px}
  .sp-search__bar{gap:6px;padding-left:12px}
  .sp-search__row{gap:8px;padding-inline:6px}
  .sp-search__idx{display:none}
  /* "Scanning marketplaces and career sites" is ~260px against ~204px of box
     at 320; white-space:pre on the base rule clipped the tail. */
  .sp-search__status{padding-inline:6px;white-space:normal}
  .hero__ticker{height:auto;padding:28px 0}
  .hero__ticker-group{gap:48px}
  /* the 96px edge fades covered 192 of 280px at 320, leaving the wordmarks as
     ghosts; scale the fade to the viewport here. */
  .hero__ticker-viewport{
    -webkit-mask-image:linear-gradient(to right,transparent 0,#000 24px,#000 calc(100% - 24px),transparent 100%);
    mask-image:linear-gradient(to right,transparent 0,#000 24px,#000 calc(100% - 24px),transparent 100%);
  }
}

/* ==========================================================================
   The live layout (900 and up) — one mode, three borrowed idioms, fixed by
   the attributes build.js writes on <html>:

     data-hero="wide"      the card takes the whole rail and the headline
                           block sits ON it, top-left, in light type
     data-bleed="edge"     spartanai.framer.website's card: flush with the top
                           of the window, 12px from its sides and bottom
                           (r20 on the lower corners), running up under the
                           fixed header, which goes transparent over it
                           (styles/header.css) — getfernand.com's idiom
     data-logos="inside"   spartanai's foot: the card is a full viewport tall
                           and the logo strip is pulled up onto it, captioned,
                           over a darkening gradient across its lower 45%
     data-text="light"     the type on the card is the page colour, not ink

   The art is object-fit:cover, centred — no masks or offsets — so any picture
   can go in the card. What sits on the card keeps to the page's 1200 rail
   (the header's edges): inset = (card width - rail) / 2, never under 40.
   ========================================================================== */
@media (min-width:900px){
  .hero{padding:0 12px 12px}
  .hero__container{max-width:none}
  .hero__content{position:relative;padding-top:0}

  /* the card: the whole window, one viewport tall minus its 12px foot */
  .hero__visual{
    width:100%;
    height:calc(100vh - 12px);
    min-height:700px;
    border-radius:0 0 20px 20px;   /* one-off: only the lower corners are cut */
  }

  /* No scrim over the top of the picture: it runs at full brightness, by
     decision. Nothing darkens the band the transparent header bar and the
     headline block sit on — their legibility rides on the picture itself.
     (The headline is solid --on-dark, its <em> run .92 and the lead pure
     white, which is as far as the type can carry it on its own.) */

  /* the source's darkening gradient over the card's lower 45%: kept, because
     the customer logos on the card's foot are knocked out to white and have
     no other separation from the picture */
  .hero__visual::after{
    content:"";
    position:absolute;
    left:0;right:0;bottom:0;
    height:45%;
    z-index:1;
    pointer-events:none;
    background:linear-gradient(rgba(26,26,26,0),rgba(26,26,26,.6));
  }

  /* the text block: on the card, on the rail, a good way down (the source's
     h1 sits 190px under the card's top) */
  .hero__left{
    position:absolute;
    z-index:2;
    left:max(40px,calc((100% - var(--container)) / 2));
    right:auto;
    top:212px;
    width:auto;
    height:auto;
    max-width:640px;
    padding-bottom:0;
    justify-content:flex-start;
  }

  /* light type on the picture */
  .hero__title{color:var(--on-dark)}
  .hero__title em{color:rgba(251,250,246,.92)}
  .hero__lead{color:#fff}
  /* The scope line is the quietest thing in the text block, but nothing
     darkens the picture behind it (see the note above), so it cannot take the
     .72 muted step the demo card uses against dark glass — at 14px over the
     sunlit part of the photo that washes out. .82 of the page white is the
     lowest step that still reads there and is still clearly below the pure
     white lead. */
  .hero__scope{color:rgba(255,255,255,.82)}
      /* the two buttons are recoloured next to the button system — global.css */

  /* the sourcing demo: the source's floating card, top-right, on the rail */
  .hero__demo{
    top:160px;
    bottom:auto;
    right:max(40px,calc((100% - var(--container)) / 2));
  }

  /* the logo strip, pulled up onto the card's foot:
     audience line 21 + gap 4 + caption 20 + gap 12 + strip 48 + pad 40 = 145 */
  .hero__ticker{
    position:relative;
    z-index:2;
    max-width:none;
    margin-top:-145px;
    height:145px;
    padding:0 40px 40px;
    padding-inline:max(40px,calc((100% - var(--container)) / 2));
    flex-direction:column;
    align-items:flex-start;
    justify-content:flex-end;
    gap:12px;
  }
  .hero__ticker-caption{display:block}
  /* the audience line sits directly above the caption and reads as the
     same block, so it takes the caption's white and leading rather than
     the muted footnote treatment it had under the lead. */
  .hero__ticker-captions .hero__scope{color:#fff;line-height:19.6px}
  .hero__logo{color:#fff;opacity:1}
  .hero__logo img{filter:brightness(0) invert(1)}
}

/* reduced motion: the open list with the first match selected, no caret, and
   the wordmark marquee parked */
@media (prefers-reduced-motion:reduce){
  .sp-search__query::after{display:none}
  .sp-search__drop,.sp-search__row,.sp-search__reason{opacity:1;transform:none;height:auto;transition:none}
  .sp-search__face img{filter:none}
  .sp-search__arrow{animation:none}
  .hero__ticker-track,.hero__ticker-track.is-running{animation:none}
  /* parked, the strip is one set of three marks: the duplicate set that fills the
     loop is hidden and the edge fade is off, or the first mark sits half-faded */
  .hero__logo[aria-hidden="true"]{display:none}
  .hero__ticker-viewport{-webkit-mask-image:none;mask-image:none}
}

/* /styles/features.css */
/* ==========================================================================
   Features section — all numbers measured from the reference at 1440px.

     section        y 900 · h 825.7 · padding 96px 40px · column · gap 64px · align center
     container      1200 @ x 120
     head block     1200 x 136.3 · column · gap 16px · align flex-start
       eyebrow      136.5 x 19.5  (the global .eyebrow utility)
       title        600  x 100.8  (Sentient 300 48/50.4/-2.4, 2 lines, 2nd run --muted)
     cards row      1200 x 433.4 · row · gap 24px · align flex-start
       card         384  x 433.4 · column · gap 16px — the whole stack is one
                    <a> to the page that explains that job, so the column
                    lives on .features__link and the <li> only sizes it
         media      384  x 336 · radius 12 · padding 24 · centred 288x288 art (radius 16)
         text       384  x 81.4 · column · gap 8px
           h3       384  x 27    (Onest 20/27/-0.4 ink)
           p        345.6 x 46.4 (Onest 16/23.2 muted, 90% of card width, 2 lines)

   Motion: appear entries for this band are translateY + opacity (blur(3px) on the
   six headline word runs); the media panels fade from opacity .05 with no travel.
   No hover state was measured on the cards.
   ========================================================================== */

.features{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:64px;
  background:transparent;            /* inherits --page */
}

.features__container{
  display:flex;
  flex-direction:column;
  justify-content:center;
  align-items:center;
  gap:64px;
  padding-inline:0;                  /* section padding already supplies the gutter */
}

/* ---- Headline ----------------------------------------------------------- */
.features__head{
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:16px;
}

/* eyebrow: the global .eyebrow utility (global.css) */

.features__title-wrap{
  display:flex;
  flex-direction:column;
  justify-content:center;
}
.features__title{
  width:820px; /* the second line after the <br> is one line wide */
  max-width:100%;
  text-wrap:balance; /* pretty left "matching." alone after the <br> */
}
/* size/leading/tracking and the muted <em> run come from .t-display-lg */

/* each measured word run is its own inline-block so it can travel + blur */
.features__word{display:inline-block}

/* ---- Cards -------------------------------------------------------------- */
.features__cards{
  width:100%;
  display:flex;
  flex-direction:row;
  align-items:flex-start;
  gap:24px;
}

.features__card{
  flex:1 1 0;
  min-width:0;
  display:flex;
  background:var(--page);
}

/* The whole card is one link to the page that explains that job, so the
   measured card stack (media, 16px, text) lives on the <a>, not the <li>.
   One focus stop per card; the ring is the global one, pulled in to the
   card's own 12px radius so it traces the picture panel. */
.features__link{
  flex:1 1 auto;
  min-width:0;
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:16px;
  color:inherit;
  text-decoration:none;
}
.features__link:focus-visible{outline-offset:4px;border-radius:var(--r-12)}

/* ---- affordance ----------------------------------------------------------
   The whole card is a link to another page, and nothing at rest said so: the
   picture and the heading read as an illustration with a caption. An
   underline that only appears on hover cannot fix that, because by then the
   pointer is already on the card — so the resting state carries the signal
   and the hover confirms it.

   The glyph is the site's existing one. .btn__coin in global.css is a 7px
   north-east arrow on the same path that travels translate(1px,-1px) on
   hover; this is that arrow and that motion, just without the ink coin
   around it and at card scale. Anything that leaves the page now moves the
   same way wherever it appears.

   Three parts, two of them visible before you hover:
     · the arrow, in ink at rest so it carries the same weight as the
       heading it sits beside and is unmissable before you hover;
     · cursor:pointer, stated rather than relied on from the <a>;
     · on hover or keyboard focus the arrow travels up and to the right,
       and the picture lifts 3px onto a soft shadow.
   No underline: it fought the arrow and the pair looked cluttered.

   The lift is on .features__media alone, so the text below holds still and
   the row never reflows. */
.features__link{cursor:pointer}

.features__card-title{
  display:flex;
  align-items:center;
  gap:7px;
}

.features__arrow{
  flex:none;
  color:var(--ink);
  transition:transform .32s var(--hover-ease);
}
.features__link:hover .features__arrow,
.features__link:focus-visible .features__arrow{
  transform:translate(3px,-3px);
}

.features__media{
  transition:transform .32s var(--hover-ease),box-shadow .32s var(--hover-ease);
}
.features__link:hover .features__media,
.features__link:focus-visible .features__media{
  transform:translateY(-3px);
  box-shadow:var(--shadow-card);
}

@media (prefers-reduced-motion:reduce){
  .features__arrow,.features__media{transition:none}
  .features__link:hover .features__arrow,
  .features__link:focus-visible .features__arrow{transform:none}
  .features__link:hover .features__media,
  .features__link:focus-visible .features__media{transform:none}
}

/* media panel — 384x336 box, 24px inset, 288x288 artwork centred inside.
   The photograph comes from styles/wells.css. */
.features__media{
  position:relative;
  width:100%;
  aspect-ratio:384 / 336;            /* 384x336 at the measured 1200 container */
  display:flex;
  align-items:center;
  justify-content:center;
  gap:10px;
  padding:24px;
  border-radius:var(--r-12);
}
/* the global .noise utility, soft-light here. Measured strength was a .5
   layer over a tile drawn at .35 alpha; the shared tile is full strength, so
   .5 x .35 = .175 reproduces it. */
.features__noise{--noise-opacity:.175;--noise-blend:soft-light}
.features__art{
  position:relative;
  z-index:1;
  width:288px;
  height:288px;
  max-width:100%;
  border-radius:var(--r-16);
  object-fit:cover;
}

/* ---- Card copy ---------------------------------------------------------- */
.features__text{
  width:100%;
  display:flex;
  flex-direction:column;
  justify-content:center;
  align-items:flex-start;
  gap:8px;
}
.features__card-title{width:100%}
.features__card-body{width:90%}      /* measured 345.6 of 384 */

/* ---- Motion ------------------------------------------------------------- */
/* the measured media appear is an opacity-only fade from .05 — no travel */
.features__media[data-appear]{opacity:.05;transform:none}
.features__media[data-appear].is-in{opacity:1}

@media (prefers-reduced-motion:reduce){
  .features__media[data-appear]{opacity:1}
}

/* ---- Responsive --------------------------------------------------------- */
@media (max-width:1100px){
  .features__cards{flex-wrap:wrap}
  .features__card{flex:1 1 300px}
}

@media (max-width:900px){
  .features{gap:48px;}
  .features__container{gap:48px}
  .features__title{width:100%}
  .features__cards{flex-direction:column;gap:32px}
  .features__card{flex:1 1 auto;width:100%}
  /* the art never grows past its 288 drawing size; below ~470px wide it is
     the panel's inner width that limits it, and 80% of that took the 9px
     labels under 8px on a phone, so it fills the panel instead. */
  .features__art{width:min(288px,100%);height:auto;aspect-ratio:1}
  .features__card-body{width:100%;max-width:420px}
}

@media (max-width:600px){
  .features{gap:36px;}
  .features__container{gap:36px}
  .features__media{padding:16px}
}

/* /styles/explore.css */
/* ==========================================================================
   Explore — screenshot-style feature explorer, tabs down the left.

   Reads left to right: the tab rail, the product screenshot, the explanation.
   That order is deliberate — the use-cases board directly below runs its tabs
   across the top with copy left / media right, so the two tab sections on the
   home page do not read as the same component twice.

   Geometry on the 1200 rail (.section in global.css owns the 96/40 padding):
     board        1200 wide, radius 16, bg --panel, padding 12, gap 12
       rail       240 wide, four tabs, min-height 56, gap 6, top-aligned
       panels     924 x auto, radius 12, bg --page, padding 12
         panel    900 wide, flex row, gap 20
           media  580 x auto (min 400), radius 10, the sky wash from wells.css
             shot 532 x 355 (the art is 600x400 native, so 89%)
           copy   300 wide: title, body, chip row, link

   PANEL HEIGHT — the trap the use-cases board fell into, solved differently.
   There the four panels are absolutely positioned inside a board whose height
   is a hard-coded 529px, and the CTA only stops jumping because that number
   was hand-measured against the longest panel; it has to be re-measured every
   time the copy or a breakpoint changes.

   Here the four panels are grid items stacked in ONE cell (grid-area:1/1), and
   the inactive ones are hidden with visibility/opacity rather than display:none.
   So they all still contribute to the track: the panels card is exactly as tall
   as the tallest of the four at whatever the current width is, every panel is
   stretched to that height, and `margin-top:auto` on the link drops it on the
   same baseline in all four. No magic number, nothing to re-measure at 1280 /
   1100 / 900 / 600, and the link is pinned at every one of them — including
   phone widths, where the panels stay stacked for the same reason.

   The cost is that all four screenshots are painted at once. They are inline
   SVG of ~6KB each, which is what the use-cases board already does above 1100.

   Motion: the house crossfade — opacity over 430ms on ease-out-cubic, with
   visibility switched at the end of it so a faded-out panel cannot be
   clicked or tabbed into.
   ========================================================================== */

.explore {
  background: var(--page);
}

.explore__inner {
  /* .container gives max-width 1200 + auto margins; .section already carries
     the 40px side padding, so no gutters here. */
  display: flex;
  flex-direction: column;
  gap: 64px;
}

/* ---- header -------------------------------------------------------------- */
.explore__head {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.explore__title {
  max-width: 650px;
}

/* ---- board --------------------------------------------------------------- */
.explore__board {
  display: flex;
  gap: 12px;
  padding: 12px;
  border-radius: var(--r-16);
  background: var(--panel);
}

/* ---- tab rail ------------------------------------------------------------
   Top-aligned, not stretched: four one-line labels blown up to a quarter of a
   400px column each would read as a menu of empty boxes. */
.explore__rail {
  flex: 0 0 240px;
  display: flex;
  flex-direction: column;
  align-content: flex-start;
  gap: 6px;
}

.explore__tab {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 56px;
  padding: 10px 16px;
  border-radius: var(--r-10);
  background: transparent;
  color: var(--muted);
  text-align: left;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 15px;
  line-height: 21px;
  transition: background-color .43s cubic-bezier(.215, .61, .355, 1),
              color .43s cubic-bezier(.215, .61, .355, 1);
}

.explore__tab-icon { flex: 0 0 18px; }
/* the long Swedish compounds have no break opportunity of their own */
.explore__tab-label { white-space: normal; overflow-wrap: anywhere; }

.explore__tab:hover { background: rgba(28, 26, 21, .04); color: var(--ink); }

/* selected: the rail tab takes the panels card's own fill, so the two read as
   one surface — the same cue the use-cases strip uses */
.explore__tab[aria-selected="true"] {
  background: var(--page);
  color: var(--ink);
  box-shadow: var(--shadow-card);
}

/* ---- panels -------------------------------------------------------------- */
.explore__panels {
  flex: 1 1 auto;
  min-width: 0;
  display: grid;
  padding: 12px;
  border-radius: var(--r-12);
  background: var(--page);
}

.explore__panel {
  grid-area: 1 / 1;      /* all four in one cell — see the note at the top */
  display: flex;
  gap: 20px;
  min-width: 0;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  transition: opacity .43s cubic-bezier(.215, .61, .355, 1) 0s,
              visibility 0s linear .43s;
}

.explore__panel.is-active {
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  transition: opacity .43s cubic-bezier(.215, .61, .355, 1) 0s,
              visibility 0s linear 0s;
}

/* the panel is a tabpanel with tabindex="0"; push the global ring clear of
   the 12px inset */
.explore__panel:focus-visible { outline-offset: 4px; }

/* ---- media --------------------------------------------------------------- */
/* .well + data-well="wash" paints the pale sky wash from styles/wells.css —
   the same quiet surface the section this replaced used, so nothing had to be
   added to that sheet. */
.explore__media {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 400px;
  display: grid;
  place-items: center;
  padding: 24px;
  border-radius: var(--r-10);
}

.explore__shot {
  position: relative;      /* over .well__media and the grain */
  width: 532px;
  max-width: 100%;
  filter: drop-shadow(0 12px 32px rgba(28, 26, 21, .14));
}

.explore__ui { width: 100%; height: auto; }

/* ---- copy ---------------------------------------------------------------- */
.explore__copy {
  flex: 0 0 300px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  padding: 8px 8px 4px;
}

.explore__panel-title { text-wrap: balance; }

/* ---- feature chips -------------------------------------------------------
   On-screen text, not decoration: these name the parts of the product that do
   not get their own tab (career site, screening, transcription), so they are
   set at the body-small size in --muted on --soft rather than shrunk. */
.explore__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
}

.explore__chip {
  display: inline-flex;
  align-items: center;
  height: 26px;
  padding: 0 10px;
  border-radius: var(--r-pill);
  background: var(--soft);
  white-space: nowrap;
}

/* ---- link ----------------------------------------------------------------
   margin-top:auto drops it on the floor of the panel. Because every panel is
   stretched to the tallest one's height (see the top of the file), that floor
   is the same y in all four, so the link does not move when you switch tabs. */
.explore__more {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: auto;
  padding-top: 8px;
  color: var(--ink);
}

/* No underline on hover: the arrow carries the motion instead, the same way
   the home page's feature cards do. The glyph is the site's north-east
   arrow — the .btn__coin path in global.css — so every link that leaves the
   page uses one mark and one movement. */
.explore__arrow {
  flex: none;
  transition: transform .32s var(--hover-ease);
}
.explore__more:hover .explore__arrow,
.explore__more:focus-visible .explore__arrow { transform: translate(3px,-3px); }

/* ---- responsive ----------------------------------------------------------
   1280 / 1100 trim the rail and the copy column so the screenshot keeps most
   of the width it loses. At 900 the rail turns into a four-up strip above the
   board and the panel stacks screenshot over copy; at 600 that strip goes 2x2,
   which fits "Consultant matching" on two lines at 375 without any horizontal
   scrolling and keeps all four tabs on screen at once. */
@media (max-width: 1280px) {
  .explore__rail  { flex: 0 0 220px; }
  .explore__copy  { flex: 0 0 280px; }
  .explore__media { min-height: 360px; }
  .explore__shot  { width: 100%; }
}

@media (max-width: 1100px) {
  .explore__rail  { flex: 0 0 200px; }
  .explore__copy  { flex: 0 0 260px; }
  .explore__panel { gap: 16px; }
  .explore__media { min-height: 300px; padding: 16px; }
}

@media (max-width: 900px) {
  .explore__inner { gap: 40px; }
  .explore__board { flex-direction: column; }
  /* minmax(0,1fr), not 1fr: a grid track's automatic minimum is its content,
     so a label the browser cannot break — "Kompetensdatabas" on the Swedish
     home — widens its column past the viewport and scrolls the whole page
     sideways. The English labels are short enough to hide this. */
  .explore__rail  {
    flex: 0 0 auto;
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 8px;
  }
  .explore__tab   { min-height: 48px; }
  .explore__panel { flex-direction: column; gap: 16px; }
  .explore__copy  { flex: 0 0 auto; padding: 4px 8px 8px; }
  .explore__media { min-height: 0; padding: 16px; }
  /* stacked, the well is the full 1200 rail; cap the art near its 600px native
     size so the screenshot stays a screenshot instead of a billboard */
  .explore__shot  { width: min(100%, 560px); }
}

@media (max-width: 600px) {
  .explore__rail  { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .explore__board { padding: 8px; gap: 8px; }
  .explore__panels { padding: 8px; }
  .explore__media { padding: 10px; }
  .explore__copy  { padding: 4px 4px 8px; }
}

@media (prefers-reduced-motion: reduce) {
  .explore__arrow { transition: none; }
  /* global.css clamps transition-duration but not transition-delay, so the
     .43s hold on `visibility` would survive and leave the outgoing panel
     focusable for that long after the swap. Drop the transition outright. */
  .explore__panel,
  .explore__panel.is-active { transition: none; }
}

/* /styles/sticky.css */
/* ==========================================================================
   "How it works" — sticky stacked panels (sections/sticky.html).

   Measured at 1440x900:
   · section        1440 x 3024 (96px block padding, 40px inline padding)
   · inner column   1200 wide, x = 120
   · head           19.5 (eyebrow) + 12 gap + 100.8 (2-line display) = 132.3
   · stack          1200 x 300vh, three 100vh panels
   · card           1200 x 572, 12px padding, 16px radius, --panel fill
   · row            1176 x 548 → media 667.2 (56.7% of the row) + copy 508.8
   · media          24px padding, 10px radius, shot centred (z3)
                    full-bleed backdrop (z0) + 5% noise wash (z2)
   · copy           48px padding, 24px gap, text block 400 wide (body 95%)

   Shot geometry: the art is the 600x400 product set the inner pages use, so
   the slot is 3:2 capped at the art's native 600 rather than the 360x360 box
   the old square ui-sticky-* set needed. 667.2 - 2x24 padding leaves 619, so
   600 fits without the media column having to grow; max-height:100% lets the
   box shrink on its shorter side instead of pushing out of the 548 row. At
   600 native the 8px labels inside the mockups stay readable — at 360 they
   rendered under 5px.

   Sticky mechanic: every panel is `position:sticky; top:0` with height 100vh
   inside a 300vh column, so panel 1 pins at y=0 while panels 2 and 3 slide up
   and cover it in turn; all three release together at the column's bottom.
   Pure CSS — no scroll listener.
   ========================================================================== */

.sticky__section{
  /* also carries .section (position:relative) */
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
}

.sticky__inner{
  display:flex;
  flex-direction:column;
  align-items:center;
}

/* ---- Head --------------------------------------------------------------- */
.sticky__head{
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:12px;
}

/* air between the headline and the first panel: the stack starts exactly where
   the head ends, so the two-line display sat on the card's top edge */
.sticky__head{margin-bottom:48px}

/* eyebrow: the global .eyebrow utility (global.css) */

.sticky__title{
  width:660px;
  max-width:100%;
  /* size/leading/tracking come from .t-display-lg (48 / 50.4 / -2.4px) */
}
.sticky__word{
  display:inline-block;
  will-change:transform,opacity,filter;
}

/* Reveal travel is the measured 32px, which is now the global default —
   see --appear-y in global.css. */

/* ---- Sticky stack ------------------------------------------------------- */
.sticky__stack{
  position:relative;
  z-index:1;
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:center;
}

.sticky__panel{
  position:sticky;
  top:0;
  z-index:1;
  width:100%;
  height:100vh;
  display:flex;
  align-items:center;
  justify-content:center;
}

/* ---- Card --------------------------------------------------------------- */
.sticky__card{
  position:relative;
  width:100%;
  padding:12px;
  border-radius:var(--r-16);
  background:var(--panel);
  overflow:hidden;
  display:flex;
  align-items:center;
  justify-content:center;
}

.sticky__row{
  flex:1 0 0;
  height:548px;
  display:flex;
  flex-direction:row;
  align-items:center;
  justify-content:flex-start;
}

/* ---- Media column ------------------------------------------------------- */
/* the measured 667.2 of the 1176 row. Written as a percentage: as a fixed
   basis it plus the 400-wide copy column and its padding overflowed the card
   from 1266px down and clipped the copy. */
.sticky__media{
  position:relative;
  flex:0 0 56.7%;
  min-width:0;
  align-self:stretch;
  padding:24px;
  border-radius:var(--r-10);
  overflow:hidden;
  display:flex;
  align-items:center;
  justify-content:center;
}

/* carries the wash — see styles/wells.css */
.sticky__media-bg{
  position:absolute;
  inset:0;
  z-index:0;
}

/* 5% noise wash over the backdrop: the global .noise utility at its default
   strength, lifted over the backdrop and under the shot */
.sticky__noise{z-index:2}

.sticky__shot{
  position:relative;
  z-index:3;
  width:100%;
  max-width:600px;
  max-height:100%;
  aspect-ratio:3/2;
}
/* Panel 1's art is the one usable survivor of the old square set, a 288
   viewBox. In the 3:2 slot it meets down to 400x400 and its drawn card, which
   only fills y 2.5-257.5 of that viewBox, lands at 393x310 — visibly lighter
   than the 600x400 its neighbours fill. A square slot (capped by max-height
   at the 500 the media column leaves) draws it 491x394, so all three cards
   come out the same height. */
.sticky__shot--square{aspect-ratio:1}

/* the art (assets/ui) draws its own frame, so no fill or shadow here */
.sticky__shot .sticky__svg{width:100%;height:100%;display:block}

/* ---- Copy column -------------------------------------------------------- */
.sticky__copy{
  flex:1 1 auto;
  align-self:stretch;
  padding:48px;
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  justify-content:center;
  gap:24px;
}

.sticky__text{
  width:400px;
  max-width:400px;
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  justify-content:center;
  gap:12px;
}
.sticky__text h3{width:100%}
.sticky__body{max-width:95%}

/* The step label is the global .eyebrow. Pulled up 4px because the block's
   12px gap was cut for eyebrow-to-display at the head, and at this smaller
   display size it read as a detached line. */
.sticky__step{margin-bottom:-4px}

/* ---- Responsive --------------------------------------------------------- */
@media (max-width:1100px){
  .sticky__text{width:100%;max-width:100%}
}

@media (max-width:900px){
  /* width:100% is required here — this max-width overrides the base
     `max-width:100%`, so without it the 660px width only clamps to 520px
     and overflows viewports narrower than that. */
  .sticky__title{width:100%;max-width:520px}
  .sticky__panel{position:static;height:auto;margin-bottom:24px}
  .sticky__panel:last-child{margin-bottom:0}
  .sticky__row{flex-direction:column;height:auto;align-items:stretch}
  /* stacked, the shot's own 3:2 box sets the media height, so the 360 floor
     the square art needed would only add dead space under it */
  .sticky__media{flex:0 0 auto;padding:24px}
  .sticky__copy{padding:32px 24px 8px;gap:20px}
}

@media (max-width:600px){
  /* the art fills the column, as it does in feature-row and explore at this
     width: capping it smaller here only shrinks type that is already small */
  .sticky__media{padding:16px}
}

/* Reduced motion: the pinning is the section's whole animation, so drop it
   and let the three panels simply stack. (It lives here rather than in the
   global block because sticky.css loads after global.css and would win.) */
@media (prefers-reduced-motion:reduce){
  .sticky__panel{position:static;height:auto;margin-bottom:24px}
  .sticky__panel:last-child{margin-bottom:0}
}

/* /styles/use-cases.css */
/* ==========================================================================
   Who it's for — four-tab audience board
   Geometry from the reference at 1440px; the two numbers the reference could
   not give (tab width, board height) are re-derived below for these four tabs.
     section            1440 wide, padding 96px 40px
     inner column       1200 wide, flex column, gap 64
     header             eyebrow 19.5 + gap 12 + title
     board              1200 wide, radius 16, bg --panel
       tablist          1200 x 76,  padding 16px 40px, gap 24, tab 208 x 44
       panels           1200 x 567, padding 12, radius 16, bg --page
         copy column    411.6 wide, padding 28, gap 32
         media column   flexible, radius 10, padding 48
           screen slot  668.4 x 445.6, radius 6 (centred; fits the padding at 567)
   Tab switch, measured by rAF sampling: opacity/background/colour crossfade over
   ~430ms on an ease-out-cubic curve. No auto-advance (sampled 12s, zero timers).
   ========================================================================== */

.usecases {
  padding: 96px 40px;
  background: var(--page);
}

.usecases__inner {
  /* .container already supplies max-width 1200 + auto margins; drop its gutters
     because the section itself carries the 40px padding measured on the source. */
  padding-inline: 0;
  display: flex;
  flex-direction: column;
  gap: 64px;
}

/* ---- header -------------------------------------------------------------- */
.usecases__head {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* eyebrow: the global .eyebrow utility (global.css) */

.usecases__title {
  max-width: 650px;
}

/* ---- board --------------------------------------------------------------- */
.usecases__board {
  border-radius: var(--r-16);
  background: var(--panel);
}

/* ---- tab strip ----------------------------------------------------------- */
.usecases__tablist {
  display: flex;
  gap: 24px;
  height: 76px;
  padding: 16px 40px;
}

/* Four equal pills, fixed width, not `flex:1 1 0`: an even split of the
   1120px rail would make each pill 262 wide, seven times the 35px "Sales"
   label sitting in it.
   Content floor, from the labels measured in the browser at 14/500 Onest —
   Consultancies 93.1, Sales 35.4, Recruitment 80.2, In-house teams 102.7 —
   is set by the longest: 102.7 + the 18px icon + the 10px gap + 2 x 12px
   padding = 154.7, so 155. All four take that same box so the row reads as
   one segmented control.
   208 is the floor plus ~26px a side, and it is chosen against the NARROWEST
   rail in this bracket, not the widest: at 1101px (one above the breakpoint
   below) the rail's content box measures 926 — 1101 less 80 of section
   padding, 80 of tablist padding and the ~15px classic scrollbar — and
   4 x 208 + 3 x 24 = 904 clears it by 22. Sizing off 1440 alone is exactly
   how the old four-tab version broke: its longest label, "Consultant
   managers", needed 193 and a four-up rail at 901 gave it 167. Four across
   is therefore only kept while the rail can pay for it; at 1100 it stops and
   the pills go 2 x 2 (see below), which is what closes the 901-1100 hole for
   good rather than narrowing the pills until they nearly touch.
   The row is left-aligned at the rail's 40px padding, which is also where the
   panel copy starts (12px panel inset + 28px copy padding), so tab, panel
   title and CTA all share one left edge — verified at x=40 in the board. */
.usecases__tab {
  flex: 0 0 208px;
  min-width: 0;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 0 12px;
  border-radius: var(--r-10);
  background: var(--panel);
  color: var(--muted);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 14px;
  line-height: 21px;
  /* measured crossfade: ~430ms, ease-out-cubic */
  transition: background-color .43s cubic-bezier(.215, .61, .355, 1),
              color .43s cubic-bezier(.215, .61, .355, 1);
}

.usecases__tab-icon { flex: 0 0 18px; }
/* nowrap, and every pill at or above the 155px content floor at every width
   (checked at 1440, 1101, 1100, 901, 900, 601 and 375), so a label can never
   become two lines and break the 44px row. nowrap also makes an undersized
   pill fail loudly — the label would spill — rather than silently reflowing,
   which is what hid the old four-tab collision. */
.usecases__tab-label { white-space: nowrap; }

/* measured hover on an inactive tab: background --panel -> --page, colour unchanged */
.usecases__tab:hover { background: var(--page); }

.usecases__tab[aria-selected="true"] {
  background: var(--page);
  color: var(--ink);
}

/* ---- panels -------------------------------------------------------------- */
.usecases__panels {
  position: relative;
  /* Re-derived for these four panels; 567 was the taller of the two audience
     panels that used to live here and is wrong for four. Measured at 1440 in
     the 411.6px copy column, as title + 32 gap + list + 32 gap + button +
     2 x 28 padding:
       1 Consultancies   75 + 303.6 + 44 = 542.6  (two items wrap to 2 lines)
       2 Sales           75 + 261.6 + 44 = 500.6  (no item wraps past 2)
       3 Recruitment     75 + 261.6 + 44 = 500.6  (same shape as Sales)
       4 In-house teams  75 + 307.8 + 44 = 546.8  (item 1 runs 117.4 tall)
     The board has to clear the TALLEST or .btn{margin-top:auto} stops being
     the rest position on the other tabs and the CTA jumps as you switch. The
     tallest is now In-house teams, not Consultancies: 546.8 + the 12px inset
     top and bottom = 570.8, taken up to 571. Verified by measuring the CTA's
     viewport y on each of the four tabs in turn — one value, four times.
     571 also leaves the media column 571 - 24 - 96 = 451 of inner height, so
     the 445.6px screen still sits inside its 48px padding. */
  height: 571px;
  padding: 12px;
  border-radius: var(--r-16);
  background: var(--page);
}

.usecases__panel {
  position: absolute;
  inset: 12px;
  display: flex;
  pointer-events: none;
}

.usecases__panel.is-active { pointer-events: auto; }
/* the panel is a tabpanel with tabindex="-1": the global ring, pushed out a
   little further so it clears the 12px inset */
.usecases__panel:focus-visible { outline-offset: 4px; }

/* Measured behaviour: the media layers crossfade over 430ms while the text column
   swaps instantly (the reference re-renders it rather than animating it). */
.usecases__media {
  opacity: 0;
  transition: opacity .43s cubic-bezier(.215, .61, .355, 1);
}
.usecases__panel.is-active .usecases__media { opacity: 1; }

.usecases__copy {
  visibility: hidden;
  opacity: 0;
}
.usecases__panel.is-active .usecases__copy {
  visibility: visible;
  opacity: 1;
}

/* ---- copy column ---------------------------------------------------------
   411.6 and the screen's 668.4 below are measured thirds of the 1200 rail.
   They are left as pixels because the media column beside them is flexible
   (flex:1 1 auto, min-width:0) and the screen is clipped by the well, so
   neither one can push the row past the rail the way the results and sticky
   splits did. */
.usecases__copy {
  flex: 0 0 411.6px;
  display: flex;
  flex-direction: column;
  gap: 32px;
  padding: 28px;
}

/* measured: Sentient 300, 30 / 37.5, -1.5px — section-specific step */
.usecases__panel-title {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: 30px;
  line-height: 37.5px;
  letter-spacing: -1.5px;
  color: var(--ink);
}

.usecases__list {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.usecases__item {
  display: flex;
  gap: 16px;
}

.usecases__item-icon {
  flex: 0 0 18px;
  display: flex;
  padding-top: 5px;      /* measured icon slot: 18 x 23, 5px optical offset */
  border-radius: var(--r-4);
  color: var(--ink);
}

.usecases__item-text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.usecases__item-title { display: block; }
.usecases__item-desc  { display: block; max-width: 305.5px; }

/* ---- CTA ----------------------------------------------------------------- */
/* Global .btn system. The copy column is a stretch flex column, so the button
   still spans its width the way the bespoke one did.

   margin-top:auto pins it to the foot of the column. The four panels share
   one fixed-height board but their copy is not the same length — Sales and
   Recruitment run 46px shorter than In-house teams and 42px shorter than
   Consultancies — so without this the button would sit up to 46px higher on
   two tabs than the others and visibly jump as you switch. Now the gap above
   it takes up the slack and the button holds one position across all four
   (verified by measuring its y on each tab: one value, four times). */
.usecases__copy .btn { margin-top: auto; }

/* ---- media column -------------------------------------------------------- */
.usecases__media {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 48px;
  border-radius: var(--r-10);
  /* the sky wash comes from styles/wells.css */
  overflow: hidden;
}

/* app-window slot — measured 668.4 x 445.6, radius 6, centred (overflows the padding) */
.usecases__ui {
  position: relative;
  z-index: 1;
  width: 668.4px;
  height: 445.6px;
  display: block;                  /* the art draws its own translucent frame */
}

/* measured grain layer: the global .noise utility at its default .05, lifted
   over the screen art */
.usecases__grain { z-index: 2; }

/* ---- responsive ---------------------------------------------------------- */
@media (max-width: 1100px) {
  /* The panels stop being stacked absolutely and flow, so the fixed board
     height goes and the CTA no longer has to be held in one place. */
  .usecases__panels { height: auto; }
  .usecases__panel { position: relative; inset: auto; flex-direction: column; }
  .usecases__panel:not(.is-active) { display: none; }
  .usecases__copy { flex: 1 1 auto; }
  .usecases__media { padding: 24px; }
  .usecases__ui { width: 100%; height: auto; }

  /* 901 to 1100 is the range the old four-tab version broke in, so it is the
     one to get right. The rail keeps its 40px padding until 900, so its
     content box here runs 925 down to 726 measured (vw - 80 section - 80
     tablist - the ~15px classic scrollbar, which the arithmetic has to
     include or it is 15px optimistic). Four across would fit — (726 - 72)/4
     = 163.6 against the 155 floor — but only by 4.4px a side at the bottom
     of the bracket, which is a collision waiting for a font to render one
     point wider, and it cannot be improved: 4 pills plus 3 gaps simply have
     no slack left in 726. So stop putting four across. Two per row instead:
     calc(50% - 12px) with the 24px gap is exactly two, 450.5 wide at 1100
     and 351 at 901, both nearly three times the floor. Nothing in this
     bracket can collide.
     The panels are already stacked into one column here, so a 2 x 2 tab grid
     reads as part of that column rather than as a squeezed segmented control
     — and the labels go to the left edge, because a centred label in a 450px
     pill floats. The left column then lines up with the panel copy below. */
  /* the base rail is nowrap at a fixed 76; two rows need both undone here,
     and the 24px gap is kept so calc(50% - 12px) is exactly half a row */
  .usecases__tablist { height: auto; flex-wrap: wrap; }
  .usecases__tab { flex: 0 1 calc(50% - 12px); justify-content: flex-start; }
}

@media (max-width: 900px) {
  .usecases { padding: 72px 24px; }
  .usecases__inner { gap: 40px; }
  /* 900 down: tighter rail (24px gutter, 12px padding, 8px gap), so the
     content box jumps back up to 813 at 900 even though the viewport shrank.
     Stay on the 2 x 2 from the rule above, restated for the 8px gap:
     calc(50% - 4px) is exactly two per row, 402.4 wide at 900 and 260.8 at
     601 (measured), both well over the 155 floor. Four across would be 201
     at 900 but only 125 at 601, under the floor, so it would fail partway
     through this bracket rather than at a breakpoint — another reason the
     switch happens at 1100 and not here. */
  .usecases__tablist { height: auto; flex-wrap: wrap; gap: 8px; padding: 12px; }
  .usecases__tab { flex: 0 1 calc(50% - 4px); }
}

@media (max-width: 600px) {
  .usecases { padding: 56px var(--gutter); }
  .usecases__panel-title { font-size: 24px; line-height: 30px; letter-spacing: -1.2px; }
  /* 2 x 2 cannot survive here: at 375 the rail is 375 - 40 gutters - 24
     padding = 311, and half of that less the gap is 151.5, just under the
     155 floor — "In-house teams" would spill. One pill per row instead: 311
     of width for a 155 label, and a 4 x 44 + 3 x 8 gap + 24 padding = 224px
     rail (measured), which is the price of four tabs on a phone. Labels stay
     left-aligned, as they have been since 1100. */
  .usecases__tab { flex: 1 1 100%; }
  .usecases__copy { padding: 20px; gap: 24px; }
  .usecases__media { padding: 12px; }
}

/* /styles/results.css */
/* ==========================================================================
   Results / stats section — every number below is measured at 1440px.
   section 1440x888.3 · pad 96/40 · container 1200 · head->panel gap 64
   panel 1200x500 r16 pad12 · media col 441.6 · body col 734.4 — written as
   37.55% / auto of the 1176 inner row, so the split survives every width
   ========================================================================== */

.results{
  background:var(--page);
}

.results__container{
  display:flex;
  flex-direction:column;
  gap:64px;
}

/* ---- headline (132.3 tall: 19.5 + 12 + 100.8) --------------------------- */
.results__head{
  display:flex;
  flex-direction:column;
  gap:12px;
  align-items:flex-start;
}
/* eyebrow: the global .eyebrow utility (global.css) */
.results__title-wrap{width:100%;max-width:650px}
.results__title{width:100%}

/* ---- panel -------------------------------------------------------------- */
.results__panel{
  display:flex;
  gap:0;
  height:500px;
  padding:12px;
  background:var(--panel);
  border-radius:var(--r-16);
}

/* left column: the measured 441.6 of the 1176 inner row. A fixed basis here
   plus the body's fixed 734.4 added up to more than the rail below 1280 and
   pushed the page sideways; as a percentage the pair always fits. */
.results__media{
  position:relative;
  flex:0 0 37.55%;
  min-width:0;
  align-self:stretch;
  border-radius:var(--r-10);
}
/* The art used to overflow the well by 4px a side, which hid the card
   backdrop behind it. Inset it instead, so the gradient frames the mock the
   same way it does in the hero, features and closing CTA. */
.results__art{
  position:absolute;
  top:50%;left:50%;
  transform:translate(-50%,-50%);
  width:386px;height:386px;max-width:none;
  display:block;                   /* the art draws its own translucent frame */
}

/* A 40x40 play chip sat dead centre of the media column with no handler behind
   it; markup and rules both removed. Bring them back together when there is a
   tour video to open. */

/* right column: the remaining 734.4, 28/32/28/40 padding -> 662.4 x 420 content */
.results__body{
  flex:1 1 auto;
  min-width:0;
  align-self:stretch;
  display:flex;
  flex-direction:column;
  justify-content:space-between;
  padding:28px 32px 28px 40px;
}

.results__top{
  display:flex;
  flex-direction:column;
  gap:24px;
}

/* quote (513.3) + customer wordmark (101) with a 48px gutter */
.results__quote-row{
  display:flex;
  gap:48px;
  align-items:flex-start;
}
.results__quote{
  flex:1 1 auto;
  min-width:0;
  font-family:var(--font-display);
  font-weight:300;
  font-size:30px;
  line-height:37.5px;
  letter-spacing:-1.5px;
  color:var(--ink);
}
.results__quote span{color:var(--muted)}

.results__logo{
  /* Was a fixed 101x32 box for an inline SVG. It now holds a real wordmark,
     so height is fixed and width follows the file — the same treatment
     .testimonials__logo gives this identical asset. */
  display:block;
  flex:none;
  height:24px;
  width:auto;
  max-width:none;
  opacity:.55;
}

/* name + role, 14/21 stacked, 42 tall */
.results__person{display:flex;flex-direction:column;gap:0}
.results__name{font-family:var(--font-body);font-weight:400;font-size:14px;line-height:21px;color:var(--ink)}
.results__role{font-family:var(--font-body);font-weight:400;font-size:14px;line-height:21px;color:var(--muted)}

/* ---- metrics (3 x 194.1 with 40px gaps, 77 tall) ------------------------ */
.results__metrics{
  display:flex;
  gap:40px;
}
.results__metric{
  flex:1 1 0;
  min-width:0;
  display:flex;
  flex-direction:column;
  gap:6px;
  align-items:flex-start;
}
.results__value{margin:0;font-variant-numeric:tabular-nums}
.results__label{
  margin:0;
  font-family:var(--font-body);font-weight:400;
  font-size:14px;line-height:21px;color:var(--muted);
}

/* ---- responsive --------------------------------------------------------- */
/* the 386 mock stops fitting the 37.55% media column below this width */
@media (max-width:1100px){
  .results__art{width:min(386px,88%);height:auto;aspect-ratio:1}
}
@media (max-width:900px){
  .results__container{gap:48px}
  .results__title-wrap{max-width:none}
  .results__panel{flex-direction:column;height:auto}
  /* the well's height is fixed but the art is aspect-ratio:1, so sizing it
     from the width made it taller than the well and it spilled over the
     panel's rounded corner. Bound it by the height instead. */
  .results__media{flex:none;height:360px;overflow:hidden}
  .results__art{width:auto;height:100%;max-width:100%;max-height:100%}
  .results__body{flex:none;padding:28px 24px;gap:32px}
  .results__quote{font-size:24px;line-height:31px;letter-spacing:-1px}
  .results__quote-row{gap:24px}
  .results__metrics{gap:24px}
}
@media (max-width:600px){
  .results__quote-row{flex-direction:column}
  .results__logo{flex:none}
  .results__media{height:280px}
  .results__metrics{flex-direction:column;gap:20px}
}

/* /styles/testimonials.css */
/* ==========================================================================
   Testimonials — every number below is measured at 1440px.
   section 1440x1300.3 · pad 96/40 · container 1200 · head->grid gap 64
   grid 1200x912 · 3 cols of 392 with 12px gutters · col 2 offset 48 from top
   card 392x280 r12 pad24 bg --panel · inner 344x232, top block / customer
   Nothing scrolls: positions sampled over 8s at rest and in view are identical.
   ========================================================================== */

.testimonials{
  background:var(--page);
}

.testimonials__container{
  display:flex;
  flex-direction:column;
  gap:64px;
  overflow:clip;                /* matches the reference container */
}

/* ---- headline (132.3 tall: 19.5 + 12 + 100.8) --------------------------- */
.testimonials__head{
  display:flex;
  flex-direction:column;
  gap:12px;
  align-items:flex-start;
}
/* eyebrow: the global .eyebrow utility (global.css) */
.testimonials__title-wrap{width:100%;max-width:650px}
.testimonials__title{width:100%}

/* ---- column grid -------------------------------------------------------- */
/* Four real reviews on the 1200 rail. The reference filled it with three
   fixed columns of 392; with four cards that does not divide, and the two
   intermediate attempts both failed in a way worth recording:

     · two fixed 392 columns left ~390px dead to the right of a left-aligned
       heading;
     · columns at flex:1 1 0 fixed the columns but not the CARDS, which were
       still width:392 inside a 589 column — so each card sat at the left of
       its own column with ~200px of empty panel beside it, and the pair read
       as two ragged stacks rather than a grid. That is the "awkward" one.

   So the cards fill their column and the column count does the work: two of
   594 here. 594 is wide for an 18px quote, hence the 46ch measure on the
   quote itself below — the card fills the rail while the text still reads at
   a sane line length, left-aligned inside it. */
.testimonials__grid{
  display:flex;
  gap:12px;
  align-items:flex-start;
}
.testimonials__col{
  flex:1 1 0;
  min-width:0;
  display:flex;
  flex-direction:column;
  gap:12px;
}
/* the second column sits 48px lower — a static offset, not a marquee */
.testimonials__col--2{padding-top:48px}

/* ---- card --------------------------------------------------------------- */
/* Height is no longer fixed at the reference's 280: the four quotes differ by
   ~30 characters and a fixed box left the shortest one visibly hollow. The
   cards in a row still match, because the flex column stretches them. */
.testimonials__card{
  width:100%;
  min-height:232px;
  padding:24px;
  margin:0;
  background:var(--panel);
  border-radius:var(--r-12);
}
.testimonials__card-inner{
  width:100%;
  height:100%;
  min-height:184px;
  display:flex;
  flex-direction:column;
  justify-content:space-between;
  gap:28px;
  overflow:hidden;
}

/* logo (24 tall) + quote, 32px apart */
.testimonials__lede{
  display:flex;
  flex-direction:column;
  gap:32px;
  align-items:flex-start;
}
.testimonials__logo{
  display:block;
  height:24px;
  overflow:visible;
  max-width:none;
  flex:none;
  color:var(--ink);
  opacity:.55;
}
.testimonials__wordmark{
  font-family:var(--font-brand);
  font-weight:500;
  font-size:13px;
  letter-spacing:-.39px;
  fill:currentColor;
}

.testimonials__quote{
  align-self:stretch;
  max-width:46ch;          /* the card is 594 wide; the line should not be */
  font-family:var(--font-body);
  font-weight:400;
  font-size:18px;
  line-height:25.2px;
  color:var(--ink);
}

/* name + role, 14/21 stacked, 42 tall, pinned to the card foot */
.testimonials__customer{display:flex;flex-direction:column;gap:0}
.testimonials__name{font-family:var(--font-body);font-weight:400;font-size:14px;line-height:21px;color:var(--ink)}
.testimonials__role{font-family:var(--font-body);font-weight:400;font-size:14px;line-height:21px;color:var(--muted)}

/* ---- responsive --------------------------------------------------------- */
/* three 392 columns + two 12px gutters = 1200, plus the section's 2x40
   padding: the fixed grid needs 1280, so it gives way at 1279 */
@media (max-width:900px){
  .testimonials__container{gap:48px}
  .testimonials__title-wrap{max-width:none}
  .testimonials__grid{flex-wrap:wrap}
  .testimonials__col{flex:1 1 calc(50% - 6px)}
  .testimonials__col--2{padding-top:0}
  .testimonials__card{min-height:0}
  .testimonials__card-inner{min-height:0;gap:24px}
}
@media (max-width:600px){
  .testimonials__grid{flex-direction:column}
  .testimonials__col{flex:none;width:100%}
  .testimonials__quote{font-size:17px;line-height:24px}
}

/* /styles/security.css */
/* ==========================================================================
   Security section — all numbers measured from the reference at 1440px.

   section        1440 x 638.3   padding 96px 40px   bg rgb(244,242,236)
   container      1200 x 446.3   column, gap 64px, centred
   headline       1200 x 190.7   column, align centre, gap 12px
     eyebrow        77.3 x 19.5  the global .eyebrow utility
     title            600 x 100.8  Sentient 300 48/50.4/-2.4, centred, 2 lines
     intro            360 x 46.4   Onest 16/23.2 muted, centred, 2 lines
   cards          1200 x 191.6   row, gap 16px, justify centre
     card             288 x 191.6  bg rgb(251,250,246), radius 12, padding 24
       icon            18 x 18
       gap             48px
       text block     240 x 77.6   column, gap 6px
         h3           240 x 25.2   Onest 18/25.2 ink
         p            240 x 46.4   Onest 16/23.2 muted
   cards block    1200           column, gap 24px: the cards row plus the
                                 link to /security/ (global .btn--secondary)
   ========================================================================== */

.security{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:64px;
  background:var(--panel);
}

.security__container{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:64px;
}

/* ---- Headline ----------------------------------------------------------- */
.security__headline{
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:12px;
}

/* eyebrow: the global .eyebrow utility (global.css) */

.security__title{width:600px;max-width:100%}
.security__h2{text-align:center}

.security__subtitle{width:360px;max-width:100%}
.security__intro{text-align:center}

/* ---- Trust cards -------------------------------------------------------- */
/* The cards and the link to the security page read as one unit, so they sit
   in their own 24px-gap column; the container's 64px only separates the
   headline from that unit. The security PAGE reuses .security__cards without
   this wrapper, which is why the row rules stay on .security__cards itself. */
.security__cards-block{
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:24px;
}

.security__cards{
  width:100%;
  display:flex;
  justify-content:center;
  align-items:flex-start;
  gap:16px;
}

.security__card{
  flex:0 0 288px;
  min-width:0;
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:48px;
  padding:24px;
  background:var(--page);
  border-radius:var(--r-12);
}

.security__icon{
  width:18px;
  height:18px;
  flex:none;
  color:var(--ink);
}

.security__card-text{
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:6px;
}
.security__card-text > *{width:100%}

/* ---- Responsive --------------------------------------------------------- */
/* four 288px cards + three 16px gaps need the full 1200 rail (1280 of
   viewport with the section's 40px sides); under that, two across */
@media (max-width:1279px){
  .security__cards{flex-wrap:wrap}
  .security__card{flex:1 1 calc(50% - 8px)}
}
@media (max-width:900px){
  .security{gap:48px}
  .security__container{gap:48px}
  .security__title{width:100%}
  .security__subtitle{width:100%;max-width:440px}
  .security__cards{flex-wrap:wrap}
  .security__card{flex:1 1 calc(50% - 8px)}
}

@media (max-width:600px){
  .security__cards{flex-direction:column}
  .security__card{flex:1 1 auto;width:100%;gap:32px}
}

/* /styles/pricing.css */
/* ==========================================================================
   Pricing section — all numbers measured from the reference at 1440px.

   section                        padding 96px 40px   page background
   container       1200           column, gap 48px
   headline        1200 x 132.3   column, align centre, gap 12px
     eyebrow         65.8 x 19.5  the global .eyebrow utility
     title            650 x 100.8 Sentient 300 48/50.4/-2.4, two-tone, centred
   plans           1200 x 534.6   column, align centre, gap 24px
     switch row       211.1 x 28  gap 8px; track 48x28 r8 --soft;
                                  knob 20x20 r5, left 4 -> 24, --faint -> --ink
     cards          1200 x 482.6  row, gap 16px  ->  3 x 389.3
       card         389.3 x 482.6 padding 32, radius 16, bg --panel, gap 24
         head       325.3 x 147.4 column, gap 16
           plan row 325.3 x 27    Onest 20/27/-0.4; tag 63x22 r6 ink
           main     325.3 x 104.4 column, gap 12
             price   ... x 46     row, align end, gap 6; Sentient 40/46/-2
             per      26.5 x 27   Onest 14/21 muted, 6px bottom pad
             desc    292.8 x 46.4 (90% of 325.3) Onest 16/23.2 muted
         list       325.3 x 179.2 column, gap 8; rows 23.2 tall,
                                  16x16 check + 8px gap + 301.3 text
         cta        325.3 x 44    radius 10, padding 1px 16px 0
   ========================================================================== */

.pricing{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:64px;
}

.pricing__container{
  display:flex;
  flex-direction:column;
  gap:48px;
}

/* ---- Headline ----------------------------------------------------------- */
.pricing__headline{
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:12px;
}

/* eyebrow: the global .eyebrow utility (global.css) */

.pricing__title{width:650px;max-width:100%;margin-inline:auto}
.pricing__h2{text-align:center}
/* split runs need their own box to blur / translate on appear */
.pricing__h2 span{display:inline-block;vertical-align:top}

/* ---- Plans block -------------------------------------------------------- */
.pricing__plans{
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:24px;
}

.pricing__top{
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:5px;
}

/* ---- Billing toggle ----------------------------------------------------- */
.pricing__switch{
  display:flex;
  align-items:center;
  gap:8px;
  height:28px;
  background:var(--page);
}

/* Real <button>s, reset back to plain text. global.css already gives every
   button `font:inherit` and no border/background; the element also carries
   .t-body, which supplies the type — so the font is deliberately NOT restated
   here, or this single-class rule would outrank .t-body and undo it. */
.pricing__switch-label{
  appearance:none;
  -webkit-appearance:none;
  margin:0;
  /* all three controls here are click targets (scripts/pricing.js); the bare
     text labels were ~23px tall and the track 28px. */
  padding:11px 4px;
  border:0;
  background:none;
  color:var(--muted);
  text-align:left;
  white-space:nowrap;
  cursor:pointer;
  user-select:none;
  transition:color var(--hover-dur) var(--hover-ease);
}
.pricing__switch-label.is-active{color:var(--ink)}

.pricing__track{
  position:relative;
  flex:none;
  width:48px;
  height:28px;
  border-radius:var(--r-8);
  background:var(--soft);
  padding:0;
}
/* the visual switch stays 48x28; this extends only the hit area to 44 tall */
.pricing__track::after{content:"";position:absolute;inset:-8px;border-radius:inherit}
.pricing__knob{
  position:absolute;
  top:4px;
  left:4px;
  width:20px;
  height:20px;
  border-radius:5px;
  background:var(--faint);
  transition:left var(--hover-dur) var(--hover-ease),
             background-color var(--hover-dur) var(--hover-ease);
}
.pricing__track[aria-checked="true"] .pricing__knob{
  left:24px;
  background:var(--ink);
}

/* ---- Cards -------------------------------------------------------------- */
.pricing__cards{
  width:100%;
  display:flex;
  /* stretch, not flex-start: the three plans carry different amounts of copy
     (Enterprise has no price row, Growth has the tag) and flex-start let each
     card collapse to its own content height, so they ended up three different
     sizes side by side. */
  align-items:stretch;
  gap:16px;
}

.pricing__card{
  flex:1 1 0;
  min-width:0;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:24px;
  padding:32px;
  border-radius:var(--r-16);
  background:var(--panel);
}

.pricing__head{
  width:100%;
  display:flex;
  flex-direction:column;
  gap:16px;
}

.pricing__plan-row{
  display:flex;
  justify-content:space-between;
  align-items:center;
  min-height:27px;
}
.pricing__plan{margin:0}

.pricing__tag{
  flex:none;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  height:22px;
  padding:5px 10px;
  border-radius:var(--r-6);
  background:var(--ink);
  color:var(--on-dark);
  font-family:var(--font-body);
  font-weight:500;
  font-size:12px;
  line-height:12px;
}

.pricing__main{
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:12px;
}

.pricing__price{
  display:flex;
  align-items:flex-end;
  gap:6px;
  min-height:46px;
}
.pricing__amount{margin:0;white-space:nowrap}
.pricing__per{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  padding-bottom:6px;
}

/* Prices are not published: the price slot reads "Book a call". */
.pricing__book-note{margin-top:-8px;color:var(--faint)}

.pricing__desc{width:90%}

/* ---- Feature list ------------------------------------------------------- */
.pricing__list{
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:8px;
}
.pricing__includes{width:100%;color:var(--ink)}

.pricing__features{
  width:100%;
  display:flex;
  flex-direction:column;
  gap:8px;
}
.pricing__features li{
  display:flex;
  align-items:center;
  gap:8px;
  min-height:23.2px;
}
.pricing__check{
  width:16px;
  height:16px;
  flex:none;
  color:var(--faint);
}
.pricing__features li span{flex:1 1 auto;min-width:0}

/* featured card lifts the list to full ink */
.pricing__card--featured .pricing__check{color:var(--ink)}
.pricing__card--featured .pricing__features li span{color:var(--ink)}

/* ---- Buttons ------------------------------------------------------------ */
/* Global .btn system; the cards want theirs edge to edge. */
/* width:100% is the card treatment; margin-top:auto pushes the CTA to the
   foot of the column so all three buttons sit on one line however much copy
   the plan above them carries. */
.pricing__card .btn{width:100%;margin-top:auto}

/* ---- Responsive --------------------------------------------------------- */
@media (max-width:900px){
  .pricing{gap:48px}
  .pricing__container{gap:40px}
  .pricing__title{width:100%}
  .pricing__cards{flex-wrap:wrap}
  .pricing__card{flex:1 1 100%}
}

@media (max-width:600px){
  .pricing__card{padding:24px}
}

/* /styles/faq.css */
/* ==========================================================================
   FAQ — measured at 1440px against the reference.

   section        padding 96px 40px, transparent (sits on --page)
   inner          the 1200 rail (--container), column, gap 64px
   header         column, gap 12px  (eyebrow 19.5px + 12 + headline 100.8 = 132.3)
   grid           two 592px columns, 16px gutter, independent column flow
   row (closed)   73.2px  = 24 + 25.2 + 24
   row (open)     190px   = 73.2 + 116.8 (92.8 of copy + 24 bottom padding)
   card           background #f4f2ec, radius 12px, padding-inline 24px, clipped
   open/close     spring, 520ms, ~1.6% overshoot (sampled from the source)
   ========================================================================== */
.faq__inner{
  
  display:flex;flex-direction:column;gap:64px;
}

/* ---- Header ------------------------------------------------------------- */
.faq__head{display:flex;flex-direction:column;align-items:flex-start;gap:12px}

/* eyebrow: the global .eyebrow utility (global.css) */

.faq__title{width:650px;max-width:100%}

/* ---- Grid --------------------------------------------------------------- */
.faq__grid{display:flex;align-items:flex-start;gap:16px}
.faq__col{
  flex:1 1 0;min-width:0;
  display:flex;flex-direction:column;gap:16px;
}

/* ---- Item --------------------------------------------------------------- */
.faq{
  --faq-dur:520ms;
  /* sampled from the reference's open transition: spring-like, peaks at
     ~1.6% past target around 290ms, fully settled by ~520ms */
  --faq-spring:linear(
    0, 0.044 4.8%, 0.197 9%, 0.324 12.3%, 0.445 15.4%, 0.570 18.8%,
    0.669 21.9%, 0.758 25.2%, 0.822 28.3%, 0.881 31.5%, 0.927 34.8%,
    0.959 38.1%, 0.981 41.2%, 0.997 44.6%, 1.013 50.8%, 1.016 57.3%,
    1.008 65.4%, 1.001 73.3%, 1
  );
}

.faq__item{
  background:var(--panel);
  border-radius:var(--r-12);
  padding-inline:24px;
  overflow:hidden;
}

.faq__row{display:block}

.faq__q{
  display:flex;width:100%;
  align-items:center;justify-content:space-between;
  gap:20px;
  padding:24px 0;
  text-align:left;
  cursor:pointer;
  color:var(--ink);
}
/* the question fills the card, so its ring is pulled inside the clip */
.faq__q:focus-visible{outline-offset:-4px}

.faq__label{flex:1 1 auto;min-width:0;color:var(--ink)}

/* ---- Icon: an original plus that spins into a minus --------------------- */
.faq__icon{
  flex:0 0 20px;width:20px;height:20px;
  overflow:visible;
  color:var(--ink);
  transform:rotate(90deg);            /* closed state, as measured */
  transform-origin:50% 50%;
  transition:transform var(--faq-dur) var(--faq-spring);
}
.faq__icon-bar{
  stroke:currentColor;stroke-width:1.8;stroke-linecap:round;
  transform-origin:12px 12px;
  transition:transform var(--faq-dur) var(--faq-spring);
}
/* on open the glyph counter-rotates back to 0 while the upright bar lies
   down onto the crossbar — a plus that turns into a minus */
.faq__item.is-open .faq__icon{transform:rotate(0deg)}
.faq__item.is-open .faq__icon-bar--v{transform:rotate(90deg)}

/* ---- Answer panel: 0fr → 1fr, no measurement, no jump ------------------- */
.faq__panel{
  display:grid;
  grid-template-rows:0fr;
  transition:grid-template-rows var(--faq-dur) var(--faq-spring);
}
/* visibility:hidden is what keeps a collapsed answer out of the tab order and
   off the screen reader — 0fr + opacity:0 leave it focusable, so the pricing
   FAQ's two in-answer links were tabbable while invisible. It is delayed out
   so the collapse still animates. */
.faq__panel-clip{
  overflow:hidden;
  opacity:0;
  visibility:hidden;
  transition:opacity calc(var(--faq-dur) * .5) var(--hover-ease),
             visibility 0s linear var(--faq-dur);
}
.faq__item.is-open .faq__panel{grid-template-rows:1fr}
.faq__item.is-open .faq__panel-clip{
  opacity:1;
  visibility:visible;
  transition-delay:80ms,0s;
}

/* measured: copy box 520px wide with a 24px tail below it. The padding lives
   on the inner box, never on the grid item, or the 0fr collapse would not
   reach zero. */
.faq__a-box{padding:0 24px 24px 0}
.faq__a{color:var(--muted)}

/* ---- Responsive --------------------------------------------------------- */
@media (max-width:900px){
  .faq__inner{gap:48px}
  .faq__grid{flex-direction:column;gap:16px}
  /* stacked, the columns are cross-axis items under align-items:flex-start,
     so they size to their content instead of the rail — and a question with
     no break opportunity ("kandidatdata", on the Swedish pages) then pushes
     the page wider than the phone. Hold them to the rail explicitly. */
  .faq__col{width:100%}
}
@media (max-width:600px){
  .faq__inner{gap:36px}
  .faq__item{padding-inline:20px}
  .faq__q{padding:20px 0;gap:16px}
  .faq__a-box{padding:0 16px 20px 0}
}

@media (prefers-reduced-motion:reduce){
  .faq__panel,.faq__panel-clip,.faq__icon,.faq__icon-bar{transition:none}
}

/* /styles/cta.css */
/* ==========================================================================
   Final CTA — measured at 1440px against the reference.

   section      padding 96px 40px, transparent
   panel        1200 x 400, background #f4f2ec (--panel), radius 16px,
                padding 12px, overflow hidden, row / centre
   copy col     588 wide, padding 24px, column, gap 24px  (auto height 275.2)
   text stack   540 wide, gap 12px  (headline 100.8 + 12 + lede 46.4 = 159.2)
   headline     Sentient 300 48/50.4/-2.4 — two-tone, <em> run is --muted
                (measured: NOT larger than 48px)
   lede         Onest 400 16/23.2 --muted, box capped at 420px (2 lines)
   button       global .btn .btn--primary (44 tall, r12, ink)
   media frame  588 x 376, radius 12, clipped
   app slot     800 x 533.33, inset 64/64, radius 8, 8px white ring

   NOTE: the media frame is filled by the page's own photograph — see the
   card-wells block in styles/wells.css, which is linked after this file.
   ========================================================================== */

/* ---- Tinted panel ------------------------------------------------------- */
.cta__panel{
  
  display:flex;align-items:center;justify-content:center;
  padding:12px;
  background:var(--panel);
  border-radius:var(--r-16);
  overflow:hidden;
}

/* ---- Copy column -------------------------------------------------------- */
.cta__copy{
  flex:0 0 50%;min-width:0;
  display:flex;flex-direction:column;align-items:flex-start;gap:24px;
  padding:24px;
  position:relative;z-index:1;
}
.cta__text{
  width:100%;max-width:600px;
  display:flex;flex-direction:column;align-items:flex-start;gap:12px;
}
.cta__title{width:100%}
.cta__lede-box{width:100%;max-width:420px}

/* ---- Button (global .btn system) --------------------------------------- */
.cta__actions{position:relative;z-index:3}

/* ---- Media frame -------------------------------------------------------- */
/* the photograph comes from styles/wells.css */
.cta__media{
  flex:0 0 50%;min-width:0;
  position:relative;
  height:376px;
  border-radius:var(--r-12);
  overflow:hidden;
}
.cta__app{
  position:absolute;top:64px;left:64px;z-index:2;
  width:800px;height:533.33px;
}
/* the art draws its own translucent frame (the reference's white 8px ring) */
.cta__app-svg{width:800px;height:533.33px;display:block}

/* ---- Responsive --------------------------------------------------------- */
@media (max-width:900px){
  .cta__panel{flex-direction:column;align-items:stretch}
  .cta__copy,.cta__media{flex:0 0 auto;width:100%}
  .cta__copy{padding:24px 16px}
  .cta__media{height:300px}
  .cta__app{top:40px;left:40px;width:640px;height:426.67px}
  .cta__app-svg{width:640px;height:426.67px}
}
@media (max-width:600px){
  .cta__panel{padding:8px;border-radius:14px}   /* a one-off, half a step under --r-16 */
  .cta__copy{padding:20px 12px;gap:20px}
  .cta__media{height:230px}
  .cta__app{top:28px;left:28px;width:460px;height:306.67px}
  .cta__app-svg{width:460px;height:306.67px}
}

/* /styles/footer.css */
/* ==========================================================================
   Footer.  Measured from the reference at 1440x900.

   footer        1440 x 401.2, bg #f4f2ec, padding 96px 40px 32px
   inner rail    1200 wide at x=120, column, gap 48
   top row       1200 x 170, gap 32 — brand flex 1 (389.3) / cols flex 2 (778.7)
   link column   176.7 wide, gap 16; list gap 12; rows 23.2 tall
   bottom bar    1200 x 55.2, padding-top 32, space-between
   ========================================================================== */

.footer{
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:24px;
  padding:96px 40px 32px;
  background:var(--panel);
}

.footer__inner{
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:48px;
  width:100%;
  max-width:var(--container);
}

/* ---- top row ------------------------------------------------------------ */
.footer__top{
  display:flex;
  flex-direction:row;
  align-items:flex-start;
  justify-content:flex-start;
  gap:32px;
  width:100%;
}

/* ---- brand column (measured 389.3 wide, 165 tall) ----------------------- */
.footer__brand{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:16px;
  flex:1 1 0;
  min-width:0;
}

.footer__logo{
  display:inline-flex;
  flex-direction:row;
  align-items:baseline;   /* the mark is a letter: it sits on the baseline */
  justify-content:center;
  gap:5px;                /* .16em, matching the header lockup */
  height:36.4px;
}
.footer__mark{
  display:inline-block;
  width:20px;                     /* = cap height of the 28px wordmark */
  height:20px;
  color:var(--ink);               /* the mark is fill:currentColor */
}
.footer__mark svg{display:block}
.footer__wordmark{
  font-family:var(--font-body);
  font-weight:500;
  font-size:28px;
  line-height:36.4px;
  letter-spacing:-.56px;
  color:var(--ink);
  white-space:nowrap;
}

.footer__tagline{
  /* 300, not the old 260: at 260 the current tagline breaks after "to" and
     leaves "interviews." alone on a third line (69.6 tall, pushing the brand
     column to 182 and the top row past its 170). 290 is the first width that
     breaks cleanly at the comma into two lines; 300 gives that a little slack
     and puts the top row back on 170. */
  width:300px;            /* wraps to 2 lines at the comma -> 46.4 tall */
  font-family:var(--font-body);
  font-weight:400;
  font-size:16px;
  line-height:23.2px;
  color:var(--muted);
}

/* The 44px hit box centres a 16px glyph, so the mark would otherwise start
   14px in and sit visibly indented from the tagline above it. Pull the row
   back by that exact inset ((44-16)/2) so the glyph's own left edge lands on
   the column edge; the hit area keeps its full 44x44 and just overhangs into
   the section padding, where there is nothing to collide with. */
.footer__social{
  display:flex;
  flex-direction:row;
  align-items:center;
  justify-content:flex-start;
  gap:4px;
  height:44px;
  margin-inline-start:-14px;
}
.footer__social li{display:flex}
/* 44x44 hit area around a 16px glyph; the row keeps its old visual rhythm
   because the gap drops from 16 to 4 by the same amount the boxes grew. */
.footer__social-link{
  display:flex;
  align-items:center;
  justify-content:center;
  width:44px;
  height:44px;
  color:var(--ink);
  opacity:1;
  transition:opacity .15s var(--hover-ease);
}
.footer__social-link:hover,
.footer__social-link:focus-visible{opacity:.6}

/* ---- link columns ------------------------------------------------------- */
/* flex 2.6, not the reference's 2: a fifth column (Resources) divides the
   same rail five ways instead of four, and at 2 that is 137px each — narrow
   enough that "Candidate sourcing" and "Kompetensdatabas" both wrap to two
   lines and the rows stop lining up across columns. 2.6 buys the columns
   ~150px, which clears the longest label, and leaves the brand column 324 —
   still wider than the 300px tagline it has to hold. */
.footer__cols{
  display:flex;
  flex-direction:row;
  align-items:flex-start;
  justify-content:center;
  gap:24px;
  flex:2.6 1 0;
  min-width:0;
}
.footer__col{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  justify-content:center;
  gap:16px;
  flex:1 1 0;
  min-width:0;
}
.footer__col-title{
  width:100%;
  font-family:var(--font-body);
  font-weight:400;
  font-size:18px;
  line-height:25.2px;
  color:var(--ink);
}
.footer__list{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  justify-content:flex-start;
  gap:12px;
  width:100%;
}
.footer__list li{
  width:100%;
  font-family:var(--font-body);
  font-weight:400;
  font-size:16px;
  line-height:23.2px;
  color:var(--muted);
}
.footer__link{
  color:var(--muted);
  transition:color .15s var(--hover-ease);
}
.footer__link:hover,
.footer__link:focus-visible{color:var(--ink)}

/* ---- bottom bar --------------------------------------------------------- */
.footer__bottom{
  display:flex;
  flex-direction:row;
  align-items:center;
  justify-content:space-between;
  width:100%;
  padding-top:32px;      /* measured: no divider rule on the reference */
}
.footer__legal{
  font-family:var(--font-body);
  font-weight:400;
  font-size:16px;
  line-height:23.2px;
  color:var(--muted);
}

.footer__credit{
  display:flex;
  flex-direction:row;
  align-items:center;
  justify-content:center;
  gap:6px;
  font-family:var(--font-body);
  font-weight:400;
  font-size:16px;
  line-height:23.2px;
}
.footer__credit-label{color:var(--muted)}
.footer__credit-link{
  color:var(--ink);
  transition:opacity .15s var(--hover-ease);
}
.footer__credit-link:hover,
.footer__credit-link:focus-visible{opacity:.7}

/* focus: the global ring (global.css) */

/* ---- responsive --------------------------------------------------------- */
/* The brand column used to sit beside the links all the way down to 900. With
   five link columns instead of four that no longer fits: at 1100 the columns
   are 121px and "Candidate sourcing", "Kompetensdatabas" and two of the guide
   labels all wrap to two lines, so the rows stop aligning across columns.
   Stacking the brand above the links from 1279 hands the five columns the
   whole rail (185px each at 1100) and nothing wraps. Below 900 they then wrap
   among themselves as before. */
@media (max-width:1279px){
  .footer__top{flex-direction:column;gap:48px}
  .footer__brand,.footer__cols{flex:1 1 auto;width:100%}
  .footer__cols{justify-content:flex-start}
}
@media (max-width:900px){
  .footer{padding:72px 24px 32px}
  .footer__cols{flex-wrap:wrap;row-gap:40px}
  /* max-width as well as the basis: five columns wrap 2+2+1 here, and a lone
     item on the last row would otherwise grow to the full 837 and sit as a
     wide odd block under two neat pairs. Capped at half, it lines up with the
     column above it. */
  .footer__col{flex:1 1 40%;min-width:160px;max-width:calc(50% - 12px)}
  .footer__tagline{width:100%;max-width:360px}
}
@media (max-width:600px){
  .footer{padding:56px var(--gutter) 24px}
  /* stacked into one tall column here, so the 23px rows 12px apart were the
     hardest thing on the page to hit; pad them out to 44 instead. */
  .footer__list{gap:0}
  .footer__link{display:block;padding-block:10px}
  .footer__wordmark{font-size:24px;line-height:31.2px;letter-spacing:-.48px}
  .footer__cols{gap:24px}
  .footer__col{flex:1 1 100%;max-width:none}
  .footer__bottom{flex-direction:column;align-items:flex-start;gap:8px}
}

/* ---- cookie settings button + consent banner ----------------------------
   The banner is built by scripts/analytics.js and appended to <body>; its
   rules live here because the footer stylesheet is on every page. The two
   choice buttons share one style on purpose (see analytics.js). */
.footer__button{
  padding:0;
  border:0;
  background:none;
  font:inherit;
  text-align:left;
  cursor:pointer;
}

.consent{
  position:fixed;
  left:20px;
  bottom:20px;
  z-index:200;
  display:flex;
  flex-direction:column;
  gap:12px;
  max-width:400px;
  padding:16px;
  border:1px solid var(--line);
  border-radius:var(--r-12);
  background:var(--page);
  box-shadow:var(--shadow-pop);
  color:var(--ink);
}
.consent[hidden]{display:none}
.consent__text{margin:0;color:var(--muted)}
.consent__link{color:var(--ink);text-decoration:underline;text-underline-offset:2px}
.consent__actions{display:flex;gap:8px}
.consent__actions .btn{flex:1 1 0}

@media (max-width:600px){
  .consent{left:var(--gutter);right:var(--gutter);bottom:var(--gutter);max-width:none}
}

/* /styles/wells.css */
/* ==========================================================================
   Card wells: the hero's world.

   LOAD ORDER — build.js must link this file LAST, after global.css and every
   section stylesheet. Several section sheets set a background on the same
   elements; this sheet wins by coming last, which is why the selectors here
   are plain single classes with no doubling and no !important.

   One world for the whole page (a Scandinavian hillside at golden hour, the
   hero picture), and a rhythm rather than a theme: the hero, the three
   feature cards, results and the closing CTA carry pictures; "How it works"
   and use cases rest on a pale sky wash; pricing stays flat. Every picture is
   a soft crop of that world, generated with the hero as the lighting and
   palette reference (tools/bg/run2.sh, prompts in tools/bg/w-*.txt), so a
   white product-UI card (assets/ui/ui-*.svg, inlined by build.js) sits
   cleanly on top.

   Which picture a feature card gets is a content decision, so it is named in
   the markup: <li class="features__card" data-well="sky|grass|horizon">.

   INNER PAGES use the generic .well component at the bottom of this file:
   one world at three hours. Golden hour (sky, grass, horizon, hill, sunset)
   is the home page and the audience pages; early morning (morning-sky,
   morning-hill, morning-horizon) is the product pages; dusk (dusk-hill,
   dusk-horizon, sunset) is the company pages. tools/bg/run3.sh made the
   morning and dusk set with the hero attached as the reference.
   ========================================================================== */

/* picture panels */
[data-well="sky"]     .features__media{--card-bg:url("/assets/img/bg-sky.webp?v=3ae4c8c6")}
[data-well="grass"]   .features__media{--card-bg:url("/assets/img/bg-grass.webp?v=fd9177fe")}
/* the horizon crop: keep the hill crest low in the card, under the art */
[data-well="horizon"] .features__media{--card-bg:url("/assets/img/bg-horizon.webp?v=36ddf793");--card-bg-pos:50% 70%}

.results__media{--card-bg:url("/assets/img/bg-hill.webp?v=b01c0cbf")}
.cta__media{--card-bg:url("/assets/img/bg-sunset.webp?v=f9f22625");--card-bg-pos:50% 0%}  /* sky in the visible band, hills cropped */

.features__media,
.results__media,
.cta__media{
  background-image:var(--card-bg);
  background-size:cover;
  background-position:var(--card-bg-pos,50% 50%);
  background-repeat:no-repeat;
  background-color:var(--sand);
}

/* quiet panels: the sky wash, no picture */
.sticky__media-bg,
.usecases__media{background:var(--sky-wash)}

/* ==========================================================================
   Generic well — any inner-page panel that carries a picture.

     <div class="well" data-well="morning-hill">
       <div class="well__media"></div>          the picture, absolutely filling
       <span class="noise well__noise" aria-hidden="true"></span>
       ...the white UI card / mockup goes here, positioned by the section...
     </div>

   The section sets the well's size and radius; this sheet only paints the
   picture. `--well-pos` moves the crop (default centre). A well with no
   data-well, or data-well="wash", is the quiet sky wash.
   ========================================================================== */
.well{position:relative;overflow:hidden;background:var(--sand)}
.well__media{
  position:absolute;inset:0;
  background-image:var(--well-bg,none);
  background-size:cover;
  background-position:var(--well-pos,50% 50%);
  background-repeat:no-repeat;
  background-color:var(--sand);
}
.well__noise{position:absolute;inset:0;pointer-events:none}
.well:not([data-well]) .well__media,
[data-well="wash"] .well__media{background:var(--sky-wash)}

/* golden hour (home, audience pages) */
[data-well="sky"]     .well__media{--well-bg:url("/assets/img/bg-sky.webp?v=3ae4c8c6")}
[data-well="grass"]   .well__media{--well-bg:url("/assets/img/bg-grass.webp?v=fd9177fe")}
[data-well="horizon"] .well__media{--well-bg:url("/assets/img/bg-horizon.webp?v=36ddf793");--well-pos:50% 70%}
[data-well="hill"]    .well__media{--well-bg:url("/assets/img/bg-hill.webp?v=b01c0cbf")}
[data-well="sunset"]  .well__media{--well-bg:url("/assets/img/bg-sunset.webp?v=f9f22625");--well-pos:50% 0%}
/* early morning (product pages) */
[data-well="morning-sky"]     .well__media{--well-bg:url("/assets/img/bg-morning-sky.webp?v=6d46cb2d")}
[data-well="morning-hill"]    .well__media{--well-bg:url("/assets/img/bg-morning-hill.webp?v=9566efaf")}
[data-well="morning-horizon"] .well__media{--well-bg:url("/assets/img/bg-morning-horizon.webp?v=8b907b94");--well-pos:50% 70%}
/* dusk (company pages) */
[data-well="dusk-hill"]    .well__media{--well-bg:url("/assets/img/bg-dusk-hill.webp?v=beef7656")}
[data-well="dusk-horizon"] .well__media{--well-bg:url("/assets/img/bg-dusk-horizon.webp?v=606bf3eb");--well-pos:50% 30%}
