/* /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/page-hero.css */
/* ==========================================================================
   Page hero — the opening of every inner page (shared component).

   Not the home page's cinematic hero: container width, text first, about
   half the viewport tall, the header solid above it. Two columns from 900
   up: copy (eyebrow, display headline, lead, the two CTAs) and one media
   slot, a .well carrying the page family's picture with a white product-UI
   mockup on it. Under 900 it stacks, copy first.

   Markup (copy this; only the text, the data-well and the @svg change):

   <section class="page-hero section" aria-labelledby="ph-title">
     <div class="container page-hero__inner">
       <div class="page-hero__copy">
         <p class="eyebrow page-hero__eyebrow" data-appear style="--appear-delay:.05s">Candidate sourcing</p>
         <h1 class="page-hero__title t-display-xl" id="ph-title" data-appear="blur" style="--appear-delay:.1s">
           Describe the role.<br><em>Find people who fit.</em>
         </h1>
         <p class="page-hero__lead t-body" data-appear style="--appear-delay:.18s">One or two plain sentences.</p>
         <div class="page-hero__actions" data-appear style="--appear-delay:.26s">
           <a class="btn btn--primary" href="{{link:signup}}"><span class="btn__text" data-label="Start free trial"><span class="btn__l">Start free trial</span></span></a>
           <a class="btn btn--secondary" href="{{link:demo}}"><span class="btn__text" data-label="Book a demo"><span class="btn__l">Book a demo</span></span></a>
         </div>
       </div>
       <div class="page-hero__media well" data-well="morning-hill" data-appear style="--appear-delay:.14s">
         <div class="well__media"></div>
         <span class="noise well__noise" aria-hidden="true"></span>
         <div class="page-hero__shot">
           <!-- @svg ui-sourcing-hero.svg class="page-hero__svg" -->
         </div>
       </div>
     </div>
   </section>

   Sizes at 1440: rail 1200, copy column 540, media 588 x 460 (radius 16),
   the 600x400 landscape mockup scaled to 520 wide and centred. The section's
   own top padding clears the fixed header (global.css offsets main's first
   non-hero section by --header-h + 32).
   ========================================================================== */
.page-hero{padding:24px 40px 64px}
.page-hero__inner{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:64px;
}
.page-hero__copy{
  flex:0 1 540px;
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:20px;
}
.page-hero__title{margin:0}
.page-hero__lead{max-width:460px;margin:0;font-size:18px;line-height:27px}
.page-hero__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}

.page-hero__media{
  flex:0 0 588px;
  height:460px;
  border-radius:var(--r-16);
  display:grid;
  place-items:center;
}
.page-hero__shot{
  position:relative;
  width:520px;
  filter:drop-shadow(0 12px 32px rgba(28,26,21,.14));
}
.page-hero__svg{display:block;width:100%;height:auto}

@media (max-width:1279px){
  .page-hero__media{flex:0 0 50%;height:420px}
  .page-hero__shot{width:88%}
}
@media (max-width:900px){
  .page-hero{padding:16px 24px 48px}
  .page-hero__inner{flex-direction:column;align-items:stretch;gap:32px}
  .page-hero__copy{flex:0 0 auto}
  .page-hero__media{flex:0 0 auto;height:auto;aspect-ratio:588/460}
}
@media (max-width:600px){
  .page-hero{padding:8px var(--gutter) 40px}
  .page-hero__media{aspect-ratio:4/3}
  .page-hero__shot{width:92%}
}

/* /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/resources/hero.css */
/* ==========================================================================
   Blog hero — the flat variant of the shared page hero.

   styles/page-hero.css builds a two-column hero: a 540px copy column beside a
   588x460 picture well. The blog index has no artwork in its opening (the
   reference measures a centred 750px title over a 400px lead, then the card
   grid), so there is no media column to sit beside and a 540px column
   left-aligned against 660px of empty page would read as a mistake.

   This sheet turns the same markup into one centred column, the same move
   styles/pricing/hero.css makes for the other flat page. It is a separate
   file rather than a reuse of that one because prc-* classes belong to the
   pricing page and its own header documents it as "the one FLAT page in the
   set"; the right long-term fix is a .page-hero--flat modifier hoisted into
   page-hero.css, which is outside this task's file ownership.

   Loaded after page-hero.css (build.js links a page's "styles" list, then the
   section sheets), so these single-class rules win on source order at equal
   weight. The section's padding-top keeps coming from global.css's
   `main > .section:first-child` rule, which clears the fixed header.

   Sizes at 1440: copy column 750 max (the measured title width), lead 560
   max, 64px down to the first card row. The reference lead box is 400, but
   its sentence is one line shorter than ours; at 400 this copy broke into
   four short ragged lines under a 750 headline, so the box is widened to
   three. It stays well inside the title width, which is what carries the
   centred shape. That 64 is the
   head -> content gap every band on the site uses, and it is produced by this
   section's padding-bottom alone: styles/resources/grid.css zeroes the grid
   section's padding-top so the two do not add up.
   ========================================================================== */

.res-hero{padding-inline:40px;padding-bottom:64px}

/* one centred column at every width; the 899 branch in page-hero.css
   stretches and left-aligns its own class, this one never does */
.res-hero__inner{
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:0;
}

.res-hero__copy{
  flex:0 1 auto;
  width:100%;
  max-width:750px;
  align-items:center;
  text-align:center;
  gap:16px;                          /* measured head-block gap */
}

/* own class on the same <p>, so this stays a single-class rule and wins on
   source order over .page-hero__lead instead of out-specifying it */
.res-hero__lead{max-width:560px}

@media (max-width:900px){
  .res-hero{padding-inline:24px;padding-bottom:48px}
}
@media (max-width:600px){
  .res-hero{padding-inline:var(--gutter);padding-bottom:36px}
  .res-hero__copy{gap:14px}
  /* at 375 the measured lead runs the full column rather than a 400 box */
  .res-hero__lead{max-width:none}
}

/* /styles/resources/grid.css */
/* ==========================================================================
   Blog index · card grid — all numbers measured from the reference at 1440px
   (solva-template.framer.website/company/blog).

     section    padding 96px 40px (.section) with padding-top ZEROED — the
                reference runs its head block and its grid inside one section
                64px apart, and this port splits them into two so the head can
                be the shared page hero. styles/resources/hero.css supplies that 64
                as its padding-bottom; if this section also took the 96 the
                gap would be 160. Same trick styles/pricing/plans.css uses.
     grid       1200 rail · 3 columns · row gap 24 · column gap 16
                (3 x 389.33 + 2 x 16 = 1200 exactly)
     card       389.3 x 450 · radius 16 · #f4f2ec fill (= --panel)
                padding 12px 12px 24px · column · gap 16
       media    365.3 x 274 → aspect-ratio 4/3 · radius 12 · clipped
       text     padding-inline 12 · column · gap 16
         head   column · gap 12
           meta row · gap 16 · 12px icon + 6px + Onest 14/21 --muted
           title  Onest 20/27/-0.4 = .t-h3, two lines
         footer Onest 14/21

   The card's 450 height is NOT restated here. The reference gets equal-height
   cards from a fixed height plus a two-line title; this grid gets them from
   `align-items:stretch` (the grid default) plus a 2-line clamp on the title
   and `margin-top:auto` on the footer row, so a short title still leaves the
   footers aligned and a long one cannot push one card taller than its
   neighbours. Same result, no magic number, and it survives the 40px title
   the real posts will bring.

   The reference card has NO excerpt, NO author, NO category chip; the page
   has NO featured post, NO filters and NO pagination. Nothing was added
   except the content-type chip, which takes the slot the reference gave the
   publication date — see the note at the top of sections/resources/grid.html
   for why these pages carry no date.

   FOUR CARDS IN THREE COLUMNS leaves one alone on the second row. That is
   left as it is rather than special-cased to a 2x2: the grid has to hold
   five and six as well the moment anything else is published, and a layout
   that only looks right at exactly four is a trap.

   HOVER / FOCUS: the reference card does almost nothing on hover (a small
   arrow slide on "Read more"). This site already has an established
   "clickable card that goes to another page" behaviour — styles/features.css:
   the whole card is one <a>, a north-east arrow rides the title AT REST, and
   on hover or keyboard focus the arrow travels translate(3px,-3px) while the
   media panel lifts 3px onto --shadow-card. The a.res-card__inner rules at
   the bottom of this sheet are exactly that, so a post card behaves like
   every other card on the site rather than like the template.

   Those rules are element+class (`a.res-card__inner`) on purpose: a card with
   no destination must not look clickable, so the affordance is attached to
   the <a> rather than the card. Every card on the page is a link today; a
   future placeholder slot can be a <div> and will correctly go inert.
   ========================================================================== */

/* the head block lives in the hero section; this one starts flush */
.res-grid{padding-top:0}

.res-grid__cards{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:24px 16px;                     /* measured row 24 / column 16 */
}

.res-card{
  display:flex;                      /* the <li> only sizes the card */
  min-width:0;
}

/* the measured card stack. An <a> here makes the whole card one link and one
   focus stop (see the hover block at the end). */
.res-card__inner{
  flex:1 1 auto;
  min-width:0;
  display:flex;
  flex-direction:column;
  gap:16px;
  padding:12px 12px 24px;
  border-radius:var(--r-16);
  background:var(--panel);
  color:inherit;
}

/* ---- Thumbnail ----------------------------------------------------------
   1200/630, not the reference's 4:3: the same ratio as the og:image, so the
   card, the social preview and the guide hero crop one picture the same way.
   The pictures are 16:9 (assets/img/guide-<slug>.webp, generated from
   tools/guides/) with the subject right of centre, so object-fit:cover only
   trims a sliver top and bottom. The --soft fill is the empty state for a
   future card that has no picture yet. */
.res-card__media{
  position:relative;
  aspect-ratio:1200 / 630;
  display:grid;
  place-items:center;
  overflow:hidden;
  border-radius:var(--r-12);
  background:var(--soft);
}
.res-card__photo{display:block;width:100%;height:100%;object-fit:cover}

/* ---- Copy --------------------------------------------------------------- */
.res-card__text{
  flex:1 1 auto;                     /* lets the footer row sink to the base */
  display:flex;
  flex-direction:column;
  gap:16px;
  padding-inline:12px;               /* measured 341.3 inside a 365.3 column */
}
.res-card__head{
  display:flex;
  flex-direction:column;
  gap:12px;
}

.res-card__meta{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:6px 16px;                      /* 16 between the two facts */
  margin:0;
}
.res-card__meta-item{
  display:inline-flex;
  align-items:center;
  gap:6px;
}
.res-card__icon{flex:none;color:var(--faint)}

/* two lines, as measured; a longer real headline is clipped rather than
   allowed to change the card's height relative to its row-mates */
.res-card__title{
  margin:0;
  display:-webkit-box;
  -webkit-box-orient:vertical;
  -webkit-line-clamp:2;
  line-clamp:2;
  overflow:hidden;
}

/* margin-top:auto is what makes the footers line up across a row */
.res-card__pending,
.res-card__more{margin:0;margin-top:auto}
.res-card__pending{color:var(--faint)}   /* a statement, not a control */

/* ---- The link variant ----------------------------------------------------
   Lifted from styles/features.css so a post card and a product card behave
   identically. Only applies once .res-card__inner is an <a>. */
.res-card__more{
  display:flex;
  align-items:center;
  gap:7px;
}
.res-card__arrow{
  flex:none;
  color:var(--ink);
  transition:transform .32s var(--hover-ease);
}

a.res-card__inner{cursor:pointer;text-decoration:none}
/* the global ring, pulled in to the card's own 16px radius so it traces the
   card instead of a 6px-cornered box around it */
a.res-card__inner:focus-visible{outline-offset:3px;border-radius:var(--r-16)}

a.res-card__inner:hover .res-card__arrow,
a.res-card__inner:focus-visible .res-card__arrow{transform:translate(3px,-3px)}

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

@media (prefers-reduced-motion:reduce){
  .res-card__arrow,
  a.res-card__inner .res-card__media{transition:none}
  a.res-card__inner:hover .res-card__arrow,
  a.res-card__inner:focus-visible .res-card__arrow,
  a.res-card__inner:hover .res-card__media,
  a.res-card__inner:focus-visible .res-card__media{transform:none}
}

/* ---- Responsive ----------------------------------------------------------
   The four house breakpoints. 1280 needs nothing: the 1200 rail simply loses
   its fixed width and the three columns shrink with it, which is what the
   reference does too. Three across stops being readable at about 1100 (the
   card falls under ~330 and the two-line title starts clipping real words),
   which is the site-wide "three drops to two" step; 600 is one across, as
   measured at 375 where the reference stacks. */
@media (max-width:1100px){
  .res-grid__cards{grid-template-columns:repeat(2,1fr);gap:24px 16px}
}
@media (max-width:600px){
  .res-grid__cards{grid-template-columns:1fr;gap:20px}
}

/* /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%}
