/* ===== tokens.css ===== */
/* ==========================================================================
   AVELaunch Books — design tokens
   Source of truth: WEBSITE_DESIGN (Figma), page "Dekstop"
   Handoff document v1.0, 7 September 2026, sections 6 and 7
   No colour value may be written anywhere outside this file.
   ========================================================================== */

:root {
  /* --- 6.2 Primitive palette ------------------------------------------- */
  --rich-black-1:      #0B1424;  /* body text, inverse surfaces, 3px strokes */
  --rich-black-2:      #E8EDF5;
  --rich-black-3:      #C7D2E3;  /* 1px hairline, vertical grid lines       */
  --rich-black-4:      #93A3BD;
  --rich-black-5:      #5D6C86;  /* secondary text                          */
  --rich-black-6:      #08101D;
  --rich-black-7:      #050A14;

  --space-cadet-1:     #1B2A57;
  --space-cadet-2:     #EEF2FA;
  --space-cadet-3:     #CBD6EC;
  --space-cadet-4:     #9BAED3;
  --space-cadet-5:     #657BA8;
  --space-cadet-6:     #142042;
  --space-cadet-7:     #0D162D;

  --vista-blue-1:      #7C9EC7;  /* brand surface                           */
  --vista-blue-2:      #F3F7FC;  /* spelled "Vista Vlue 2" in the file      */
  --vista-blue-3:      #DCE8F5;
  --vista-blue-4:      #B7CBE3;
  --vista-blue-5:      #93B1D3;

  --columbia-blue-1:   #C2E6F9;
  --columbia-blue-2:   #FCFEFF;
  --columbia-blue-3:   #EEF8FD;
  --columbia-blue-4:   #D9EEF9;
  --columbia-blue-5:   #CBE8FA;

  --amber-1:           #F2BB16;
  --amber-2:           #F9E08A;
  --amber-3:           #F7CD52;
  --amber-4:           #E0A800;  /* accent: buttons, underlines, active     */

  --editorial-white-1: #F8F7F4;
  --editorial-white-2: #FFFFFF;
  --editorial-white-3: #FDFBF8;
  --editorial-white-4: #EEEAE3;  /* page background                         */

  /* --- 6.3 Semantic layer ----------------------------------------------
     Reference map from the file. The layout binds to primitives, exactly
     as the Figma layers do, so this layer stays a dictionary of roles.     */
  --surface-page:       var(--editorial-white-4);
  --surface-brand:      var(--vista-blue-1);
  --surface-accent:     var(--amber-4);
  --surface-inverse:    var(--rich-black-1);
  --content-primary:    var(--rich-black-1);
  --content-secondary:  var(--rich-black-5);
  --content-on-inverse: var(--editorial-white-4);
  --content-accent:     var(--amber-4);
  --content-on-accent:  var(--rich-black-1);
  --content-on-brand:   var(--rich-black-1);
  --border-strong:      var(--rich-black-1);   /* 3px */
  --border-hairline:    var(--rich-black-3);   /* 1px */
  --border-accent:      var(--amber-4);        /* 3px */
  --action-fill:        var(--amber-4);
  --action-fill-hover:  rgba(255, 255, 255, 0); /* no fill on hover        */
  --action-border-hover: var(--amber-4);

  /* --- 4.1 Grid ---------------------------------------------------------
     1440 reference · 12 columns · Stretch · margin 50 · gutter 25
     Working area 1340. Column width is derived, never written down.       */
  --layout-reference: 1440px;
  --layout-margin:    50px;
  --layout-gutter:    25px;
  --layout-content:   1340px;
  --layout-floor:     1200px;   /* lower bound of the desktop layout       */

  /* --- 4.1 Vertical lines ----------------------------------------------
     Seven lines, step 180 of 1440 = 12.5 % of the window.
     THIS IS THE ONLY PLACE THE POSITIONS EXIST. Both layers — the page
     layer under the content and the header layer over its blurred
     background — read them from here. Writing them twice is what makes
     the two layers drift apart at the header edge.                        */
  --line-step:  12.5%;
  --line-width: 1px;
  --line-color: var(--rich-black-3);

  /* --- 8 Effects --------------------------------------------------------
     One effect on the whole site: BACKGROUND_BLUR 50 on the header plate. */
  --header-blur: 25px;
  --header-plate: rgb(238 234 227 / 0.75);
  --header-height: 61px;

  /* --- Motion ----------------------------------------------------------- */
  --t-fast: 150ms;
  --t-base: 300ms;
}

/* ===== base.css ===== */
/* ==========================================================================
   AVELaunch Books — fonts, typography scale, grid, vertical lines, layout
   intent tags. Handoff sections 4, 5, 7, 15.
   ========================================================================== */

/* --- 15.1 Fonts. Served from our own domain, never a third party. -------- */
@font-face {
  font-family: "Mulish";
  font-style: normal;
  font-weight: 200 1000;
  font-display: swap;
  src: url("../fonts/mulish-latin-wght-normal.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Mulish";
  font-style: normal;
  font-weight: 200 1000;
  font-display: swap;
  src: url("../fonts/mulish-latin-ext-wght-normal.woff2") format("woff2-variations");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Mulish";
  font-style: italic;
  font-weight: 200 1000;
  font-display: swap;
  src: url("../fonts/mulish-latin-wght-italic.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Comforter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/comforter-latin-400-normal.woff2") format("woff2");
}

/* --- Reset -------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-width: var(--layout-floor);
  background: var(--surface-page);
  color: var(--content-primary);
  font-family: "Mulish", "Helvetica Neue", Arial, sans-serif;
  font-weight: 400;
  font-size: 15px;
  line-height: normal;
  -webkit-font-smoothing: antialiased;
}

img, svg, video { display: block; max-width: 100%; }
img { height: auto; }

a { color: inherit; text-decoration: none; }

button, input, textarea, select {
  font: inherit;
  color: inherit;
  margin: 0;
}

h1, h2, h3, h4, p, figure, blockquote, dl, dd { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }

/* 9. Keyboard focus is visible on every interactive element: white plate,
   3px accent stroke — the decision taken for the form fields, applied site
   wide because the component sets carry no separate focus variant.        */
:focus-visible {
  outline: 3px solid var(--border-accent);
  outline-offset: 2px;
  background-color: var(--editorial-white-2);
}

/* --- 7.3 Heading trim ---------------------------------------------------
   Headings in the file sit on the cap height, not on the line box. Without
   the trim every heading drops a few pixels and the spacing above it reads
   larger than the macket.                                                  */
.u-trim {
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
}

/* --- 7.2 Type styles ----------------------------------------------------
   Letter spacing comes from Figma as a percentage of the type size, so it
   is written in em and never converted to pixels. Line height is Auto in
   every style, which is line-height: normal, not 100 %.                    */
.t-heading-accent       { font-family: "Comforter", cursive; font-weight: 400; font-size: 100px; letter-spacing: 0; text-transform: uppercase; }
.t-heading-accent-small { font-family: "Comforter", cursive; font-weight: 400; font-size: 100px; letter-spacing: 0; }
.t-heading              { font-weight: 1000; font-size: 50px; letter-spacing: 0.1em;  text-transform: uppercase; }
.t-heading-wide         { font-weight: 1000; font-size: 50px; letter-spacing: 0.06em; text-transform: uppercase; }
.t-heading-wide-light   { font-weight: 200;  font-size: 50px; letter-spacing: 0.06em; text-transform: uppercase; }
.t-subheading           { font-weight: 400;  font-size: 25px; letter-spacing: 0;      text-transform: uppercase; }
.t-intro                { font-weight: 400;  font-size: 25px; letter-spacing: 0; }
.t-intro-black          { font-weight: 1000; font-size: 25px; letter-spacing: 0;      text-transform: uppercase; }
.t-intro-black-wide     { font-weight: 1000; font-size: 25px; letter-spacing: 0.1em;  text-transform: uppercase; }
.t-base                 { font-weight: 400;  font-size: 15px; letter-spacing: 0; }
.t-base-black           { font-weight: 1000; font-size: 15px; letter-spacing: 0; }
.t-base-italic          { font-weight: 400;  font-size: 15px; font-style: italic; }
.t-base-down-black      { font-weight: 1000; font-size: 15px; text-transform: lowercase; }
.t-base-up              { font-weight: 400;  font-size: 15px; text-transform: uppercase; }
.t-base-up-black        { font-weight: 1000; font-size: 15px; text-transform: uppercase; }
.t-base-up-black-wide   { font-weight: 1000; font-size: 15px; letter-spacing: 0.1em;  text-transform: uppercase; }
.t-label                { font-weight: 400;  font-size: 25px; letter-spacing: 0.1em;  text-transform: uppercase; }
.t-label-wide           { font-weight: 400;  font-size: 25px; letter-spacing: 0.6em;  text-transform: uppercase; }
.t-label-big            { font-weight: 200;  font-size: 100px; text-transform: uppercase; }
.t-label-big-black      { font-weight: 1000; font-size: 100px; text-transform: uppercase; }

.u-secondary { color: var(--content-secondary); }
.u-accent    { color: var(--content-accent); }

/* --- 4.1 / 4.2 Working area ---------------------------------------------
   Above 1440 the working area holds at 1340 and centres; the margins grow.
   Between 1200 and 1440 the margin stays 50, the gutter stays 25, the
   columns narrow. Type sizes do not change.                               */
.container {
  width: min(var(--layout-content), 100% - var(--layout-margin) * 2);
  margin-inline: auto;
}

/* 12-column helper. The column width is derived from the grid, never set. */
.grid12 {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--layout-gutter);
}

/* --- 5.1 Intent tags ----------------------------------------------------
   Five values cover all thirty-nine hand-composed blocks. Where Auto Layout
   in the file disagrees with the tag, the tag wins.                        */

/* fluid — lives inside the working area and narrows with it. Default. */
.is-fluid { width: 100%; }

/* flow — a row of equal elements that wraps when it stops fitting.
   The gap equals the gutter. The count per row is not fixed.              */
.is-flow {
  display: flex;
  flex-wrap: wrap;
  gap: var(--layout-gutter);
}
.is-flow > * { flex: 1 1 var(--flow-basis, 430px); min-width: 0; }

/* bleed:both — runs the full window width both sides. Text and cards
   inside stay in the working area.                                        */
.is-bleed-both {
  width: 100vw;
  margin-left: calc(50% - 50vw);
}

/* bleed:left / bleed:right — out past one margin only, never both.
   --bleed-stop is the macket coordinate of the edge that stays put,
   expressed as a share of the working area.

   The box stops growing at the reference frame. It used to run to the window
   edge (`margin-left: calc(50% - 50vw)`), which at 1440 made it exactly the
   macket's 1340 — every share inside is a share of 1340, so the composition
   was right there and only there. At 1920 the same box became 1580 and the
   photograph, the cards and the text stretched with it: the "block drifts
   left" the comments report, eighteen times over. Pinned to the frame, the
   proportions inside are the macket's at any width.

   What is supposed to keep running off the edge is the fill, not the
   composition — an amber slab, a coloured band. That is `.u-bleed-fill-left`
   below, on the fill itself. */
.is-bleed-left {
  width: calc(100% - var(--bleed-stop, 0%)
              + (var(--layout-reference) - var(--layout-content)) / 2);
  margin-left: calc((var(--layout-content) - var(--layout-reference)) / 2);
  margin-right: 0;
}
/* Mirror image: for bleed:right the stop is the LEFT inset, so it stays a
   margin and the width comes off the same side. */
.is-bleed-right {
  width: calc(100% - var(--bleed-stop, 0%)
              + (var(--layout-reference) - var(--layout-content)) / 2);
  margin-right: calc((var(--layout-content) - var(--layout-reference)) / 2);
  margin-left: var(--bleed-stop, 0%);
}

/* The fill carries on to the window edge from wherever it stops. It paints a
   viewport's worth sideways and the page clips it, so no width has to be
   worked out. `background: inherit` so the fill's own colour is the only
   place a colour is written. */
.u-bleed-fill-left::before,
.u-bleed-fill-right::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100vw;
  background: inherit;
}
.u-bleed-fill-left::before  { right: 100%; }
.u-bleed-fill-right::after  { left: 100%; }

/* --- 4.0 The frame ------------------------------------------------------
   Everything positioned from --line-step is positioned inside this box, and
   nothing else is: the macket's 1440 frame, centred, shrinking with the
   window below 1440 and holding still above it. Before this existed, the
   line layer was `inset: 0` on the page, so --line-step read as 12.5 % of
   the WINDOW: at 1440 the lines landed on 180 · 360 · … · 1260 exactly, and
   at 1920 they spread to a 240 step and left the working area behind. Same
   for the header's menu, which took its cells from the same percentage.
   One box, one source, so the page layer and the header layer cannot drift
   apart at any width.                                                      */
.u-frame {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: min(100%, var(--layout-reference));
  transform: translateX(-50%);
}

/* --- 4.1 Vertical lines -------------------------------------------------
   One component, two placements. Positions are read from --line-step in
   tokens.css and exist nowhere else, so the page layer and the header layer
   cannot drift apart.                                                      */
.gridlines {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: min(100%, var(--layout-reference));
  transform: translateX(-50%);
  pointer-events: none;
  z-index: 0;
}
.gridlines i {
  position: absolute;
  top: 0;
  bottom: 0;
  width: var(--line-width);
  background: var(--line-color);
  left: calc(var(--n) * var(--line-step));
}

/* The page layer sits under every section, the full height of the document.
   The header is the one exception: it keeps its own sticky positioning and
   rides above, because it draws its own copy of the lines over its plate. */
/* Bleeding blocks are drawn past the window edge on purpose — an amber band
   that runs off the left, a roller whose next card is cut by the right. The
   page clips them at the window. `clip` and not `hidden`: hidden would make
   this a scroll container and the pinned header would stop pinning. */
.page {
  position: relative;
  overflow-x: clip;
}
.page > .gridlines { z-index: 0; }
.page > *:not(.gridlines):not(.site-header):not(.site-up) { position: relative; z-index: 1; }
.page > .site-header { z-index: 2; }

/* Skip link — visible only once it takes focus. */
.skip-link {
  position: absolute;
  left: var(--layout-margin);
  top: 0;
  z-index: 10;
  transform: translateY(-200%);
  padding: 12px 25px;
  background: var(--editorial-white-2);
  color: var(--content-primary);
  font-weight: 1000;
  font-size: 15px;
  text-transform: uppercase;
  transition: transform var(--t-fast);
}
.skip-link:focus-visible { transform: translateY(0); }

/* --- Vertical rhythm between the blocks ---------------------------------
   The file stacks the screen's blocks on a fixed rhythm, and it is defined
   here once rather than inside each section: a section owns its own height,
   never the air around it.

   Read off the Main screen (1:3): the header's box ends at 111 and the first
   block starts at 180; every neighbouring pair of blocks sits 150 apart; the
   footer sits 100 below the last one.

   150 is only the Main screen's number. Services runs 150 · 100 · 0, How It
   Works runs 100 below its halfway point, and the gap under the header is a
   different number on every screen. So the default lives here and a block
   that departs from it writes its own value once, in the markup, as
   `style="--gap: 100px"` on the <section> — the measured Figma number, next
   to the block it belongs to, still not a margin the section sets on itself.

   The FAQ on Main carries `--gap: 0`: its full-width blue fill is meant to
   start exactly where the founder block above it ends.                      */
:root {
  --block-gap: 150px;
  --block-gap-first: 69px;   /* header box 111 → first block 180 */
  --block-gap-footer: 100px;
}

main > section + section  { margin-top: var(--gap, var(--block-gap)); }
main > section:first-child { margin-top: var(--gap, var(--block-gap-first)); }
.page > .site-footer { margin-top: var(--gap-footer, var(--block-gap-footer)); }

/* --- 13.3 Anchors -------------------------------------------------------
   Smooth scroll that accounts for the pinned header, so the target block
   does not hide underneath it.                                            */
html { scroll-behavior: smooth; }
[id] { scroll-margin-top: calc(var(--header-height) + 50px); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* --- Below the 1200 floor ------------------------------------------------
   The design stops at 1200: below that there is no narrower composition to
   fall back to, and `min-width` on its own gave a horizontal scrollbar — the
   headline cut off the left edge, half the hero off the right. A window at
   900 is not a phone; it is a laptop or a half-screen window, and a page you
   have to scroll sideways to read is broken in the only sense that matters.

   So the page keeps its 1200 layout and is scaled down to fit the window.
   Everything stays in proportion and simply reads smaller. This is not a
   narrow layout and it is no substitute for one — it is what the site does
   until a narrow composition is drawn.

   The scale itself cannot be written here: `zoom` needs a plain ratio, and
   no CSS expression turns a viewport width into one — dividing 100vw by 1200
   yields a length, which `zoom` rejects. So it is set by the small inline
   script the build puts at the top of every <body>, and `zoom` rather than
   `transform: scale()` because a transform would make the pinned header and
   the scroll-to-top control position against the transformed box instead of
   the window, and both would come unstuck.                                 */

/* An inline link inside body copy. The site has no underlines anywhere, so
   a link in the middle of a sentence has to be told apart some other way:
   it carries the accent colour and a 1px rule that thickens on hover. */
.u-link-inline {
  color: var(--content-accent);
  border-bottom: 1px solid currentColor;
  transition: border-bottom-width var(--t-fast), color var(--t-fast);
}
.u-link-inline:hover,
.u-link-inline:focus-visible {
  border-bottom-width: 3px;
}

/* ===== header.css ===== */
/* ==========================================================================
   Site header — Figma component set 504:2789, instance 20:1973 on Main.
   Load AFTER css/base.css.

   Full window width, 61px tall, pinned to the top of the window. Three
   layers, bottom to top:

     1. the plate  — Editorial White 4 at 75 % over a background blur
                     (Figma "Rectangle 13", 1440 x 61)
     2. the lines  — the page's own .gridlines component, drawn a second
                     time so the seven lines sit OVER the plate
     3. the logo and the menu

   Geometry: the seven lines and the seven menu cells are the same seven
   positions. They are read from --line-step in tokens.css and appear
   nowhere else, so the page's line layer and the header's cannot drift.
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  height: var(--header-height);
  /* Starts one page margin down; the page's own lines show in that strip. */
  margin-top: var(--layout-margin);
}

/* base.css pins every child of .page with `position: relative` at a higher
   weight than a single class, so the sticky behaviour is restated here at
   matching specificity. Width stays `auto` — the header must measure the
   same box as .page, not 100vw, or the scrollbar would offset its lines by
   a few pixels against the page's. */
.page > .site-header {
  position: sticky;
  z-index: 10;
}

/* --- 1. The plate ------------------------------------------------------- */
.site-header__plate {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--header-plate);
  -webkit-backdrop-filter: blur(var(--header-blur));
  backdrop-filter: blur(var(--header-blur));
}

/* --- 2. The lines -------------------------------------------------------
   The only modifier the shared component needs: it is lifted above the
   plate. The page layer keeps z-index 0 and stays under the content, so
   what shows inside the header is this crisp set at full strength, never
   the page's set dimmed and blurred through the translucent plate.       */
.site-header__lines {
  z-index: 1;
}

/* --- 3. Logo ------------------------------------------------------------ */
/* The macket's margin measured from the frame, not from the window: above
   1440 the frame centres, and a logo pinned to the window edge would sit
   240 away from the menu that starts at the frame's first line. */
.site-header__logo {
  position: absolute;
  z-index: 2;
  left: calc(max(0px, (100% - var(--layout-reference)) / 2) + var(--layout-margin));
  top: 50%;
  transform: translateY(-50%);
}

/* 15px tall, the wordmark's own ratio gives the width (107.45 in the
   macket). Fixed to the window margin, not to a share of the width. */
.site-header__logo img {
  width: auto;
  height: 15px;
}

/* --- 3. Menu ------------------------------------------------------------
   Each cell's line is at --n * --line-step; the label sits one gutter to
   the right of it. The cell width (150 in the macket) is never needed —
   the next cell is placed from the next line, not from this one's edge.  */
/* The frame box, not the window: the cells are placed from --line-step and
   the lines they belong to are now anchored to the macket's 1440 frame
   (base.css §4.0). Window-wide, the menu spread with the window and left
   its own lines behind above 1440. */
.site-header__nav {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: min(100%, var(--layout-reference));
  transform: translateX(-50%);
  z-index: 2;
  /* The nav box covers the whole header, including the logo. It is
     transparent but would still take the clicks, so it is made inert and
     only the menu items themselves are given back to the pointer. */
  pointer-events: none;
}

.site-header__item {
  position: absolute;
  top: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  pointer-events: auto;
  left: calc(var(--n) * var(--line-step) + var(--layout-gutter));
}

.site-header__link {
  white-space: nowrap;
  transition: color var(--t-fast);
}

/* Active page. The five variants in the set carry no other difference at
   this height, so one rule covers Main, Services, Process, Results and
   About. Styled off the attribute so the markup cannot drift from it. */
.site-header__link[aria-current="page"],
.site-header__link:hover,
.site-header__link:focus-visible {
  color: var(--content-accent);
}

/* --- 4. The sub-navigation ----------------------------------------------
   Three of the five header variants in the set are 113 tall instead of 61:
   Services (966:7456), Results (521:2698) and About (521:3038). The extra
   52 is a second row of links that hangs under the item that owns it —
   All services / Discovery Sprint under Services, Author Stories / Free
   Resources under Results, Our Team & Story / FAQ / Contact under About.

   Each sub-item sits on the SAME seven positions as the bar above it, one
   gutter right of its line, and the group's plate covers only its own
   columns. The rest of the row is bare: the page shows through it, with
   the seven lines carried down across the full width (Figma "Group 75").

   The block is a child of the <li> that opens it, so :hover and
   :focus-within on that item are the entire interaction — no script, and
   the pointer can travel down into the row without losing the hover
   because it never leaves the <li>'s subtree.

   It is an OVERLAY, not flow: on Services the hero deliberately starts at
   110 and runs up behind the whole header. A page whose first block is
   meant to start below the open row writes that into its own --gap.     */
/* The row is a frame box, not a window-wide one: every piece inside it —
   plate, rule, line copy, labels — is placed from --line-step, and the line
   copy is now anchored to the macket's 1440 frame (base.css §4.0). If this
   row stayed window-wide the plate would sit at 12.5 % of the window while
   the lines sat on the frame, and above 1440 they would come apart. */
.site-header__sub {
  position: absolute;
  top: 100%;
  left: 50%;
  width: min(100%, var(--layout-reference));
  transform: translateX(-50%);
  height: 52px;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-fast) ease, visibility var(--t-fast);
  /* The nav box above is inert so it cannot swallow clicks meant for the
     page; this row is its own box and takes its own. */
  pointer-events: auto;
}

/* The block is a sibling of the menu, not a child of the item that opens it:
   the item is itself absolutely positioned, so a descendant would be laid
   out against that one narrow cell instead of across the header. :has()
   carries the relationship instead.

   Three states, in this order, and the order is the whole logic:

     1. a page that belongs to a group holds that group's row open;
     2. the moment the pointer or the caret lands on ANY opening item, every
        row closes — otherwise the page's own row and the hovered one draw
        on top of each other in the same 52px strip, which is what the
        header did on all seven section pages;
     3. the row belonging to what is actually being pointed at opens.

   Step 3 also keeps the row open while the pointer is inside it, so
   travelling down from the label into the links does not close it. */

/* 1 — held open by the page, at the top of the page only. js/header.js
   adds .is-scrolled once the page has moved (2026-10-08: a scrolled or
   anchor-linked page had the row lying over its content). */
.site-header[data-subnav="services"]:not(.is-scrolled) .site-header__sub[data-group="services"],
.site-header[data-subnav="results"]:not(.is-scrolled)  .site-header__sub[data-group="results"],
.site-header[data-subnav="about"]:not(.is-scrolled)    .site-header__sub[data-group="about"] {
  opacity: 1;
  visibility: visible;
}

/* 2 — anything being pointed at or tabbed to closes all of them first */
.site-header:has(.site-header__link[data-opens]:hover) .site-header__sub,
.site-header:has(.site-header__link[data-opens]:focus-visible) .site-header__sub,
.site-header:has(.site-header__sub:hover) .site-header__sub,
.site-header:has(.site-header__sub:focus-within) .site-header__sub {
  opacity: 0;
  visibility: hidden;
}

/* 3 — and only the one being pointed at opens */
.site-header:has(.site-header__link[data-opens="services"]:hover) .site-header__sub[data-group="services"],
.site-header:has(.site-header__link[data-opens="services"]:focus-visible) .site-header__sub[data-group="services"],
.site-header:has(.site-header__sub[data-group="services"]:hover) .site-header__sub[data-group="services"],
.site-header:has(.site-header__sub[data-group="services"]:focus-within) .site-header__sub[data-group="services"],
.site-header:has(.site-header__link[data-opens="results"]:hover) .site-header__sub[data-group="results"],
.site-header:has(.site-header__link[data-opens="results"]:focus-visible) .site-header__sub[data-group="results"],
.site-header:has(.site-header__sub[data-group="results"]:hover) .site-header__sub[data-group="results"],
.site-header:has(.site-header__sub[data-group="results"]:focus-within) .site-header__sub[data-group="results"],
.site-header:has(.site-header__link[data-opens="about"]:hover) .site-header__sub[data-group="about"],
.site-header:has(.site-header__link[data-opens="about"]:focus-visible) .site-header__sub[data-group="about"],
.site-header:has(.site-header__sub[data-group="about"]:hover) .site-header__sub[data-group="about"],
.site-header:has(.site-header__sub[data-group="about"]:focus-within) .site-header__sub[data-group="about"] {
  opacity: 1;
  visibility: visible;
}

/* The group's own piece of the plate: from its first line to one past its
   last, so the blur ends on a line and not in the middle of a cell. */
.site-header__sub-plate {
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--from) * var(--line-step));
  width: calc(var(--span) * var(--line-step) + var(--line-width));
  background: var(--header-plate);
  -webkit-backdrop-filter: blur(var(--header-blur));
  backdrop-filter: blur(var(--header-blur));
}

/* Figma "Line 39": 1px at y 62, i.e. the first pixel of this row, spanning
   exactly the group's columns. */
.site-header__sub-rule {
  position: absolute;
  top: 1px;
  height: var(--line-width);
  left: calc(var(--from) * var(--line-step));
  width: calc(var(--span) * var(--line-step) + var(--line-width));
  background: var(--line-color);
  z-index: 2;
}

/* The lines carry on down through the row — but only inside the group's own
   columns.

   They used to be drawn across all seven. On the page the line layer lies
   UNDER the sections, so a section's own fill hides it; this copy sits above
   the page instead, so every line outside the open panel was painted onto
   whatever content happened to be under the header — four loose verticals
   hanging off the bar to the left of the About panel, with no plate and no
   rule to belong to. Services never showed it because its panel starts at
   the first line and there is nothing to its left.

   The layer stays full width so the `--n` percentages still resolve against
   the same box as everywhere else; the clip is what limits what is painted,
   from the group's first line to the far edge of its last column. */
.site-header__sub-lines {
  z-index: 1;
  clip-path: inset(
    0
    max(0px, calc(100% - (var(--from) + var(--span)) * var(--line-step) - var(--line-width)))
    0
    calc(var(--from) * var(--line-step)));
}

.site-header__submenu {
  position: absolute;
  inset: 0;
  z-index: 3;
}

/* Macket: label baseline at y 76 within the 113 header, i.e. 15 into this
   row; same one-gutter offset from the line as the bar above. */
.site-header__subitem {
  position: absolute;
  top: 15px;
  left: calc(var(--n) * var(--line-step) + var(--layout-gutter));
  pointer-events: auto;
}

/* Sentence case, Base Regular — the one place on the site where a menu
   label is not set in capitals. */
.site-header__sublink {
  white-space: nowrap;
  transition: color var(--t-fast);
}

.site-header__sublink[aria-current="page"],
.site-header__sublink:hover,
.site-header__sublink:focus-visible {
  color: var(--content-accent);
}

/* ===== footer.css ===== */
/* ==========================================================================
   Site footer — Figma symbol 152:1464, instance 966:8527.
   Load AFTER css/base.css.

   Full window width, 415 tall in the macket, Vista Blue 1. The fill is
   opaque, so it covers the page's vertical line layer — the macket shows
   no lines inside the footer.

   Vertical rhythm, read off the macket (footer top = 0):

        50  logo, 15 tall
        83  hairline, full working area
        98  tagline          |  50   Company / Services / Contact headings
       134  social icons     |  98   first link of each column
       184  Barcelona office | 289   last link of the Services column
       339  hairline
       354  legal links and copyright
       415  foot

   The right-hand link block starts level with the logo, so the first
   hairline crosses it. That is why the two halves are one grid with fixed
   rows rather than two stacked blocks: the rules span both columns while
   the link block spans the rows above and below the first of them.
   ========================================================================== */

.site-footer {
  background: var(--vista-blue-1);
  padding-block: var(--layout-margin);
  min-height: 415px;
}

.site-footer__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  /* logo band · hairline · body · hairline · bottom bar */
  grid-template-rows: 33px var(--line-width) 255px var(--line-width) auto;
}

/* --- Logo --------------------------------------------------------------- */
.site-footer__logo {
  grid-column: 1;
  grid-row: 1;
  justify-self: start;
}

.site-footer__logo img {
  width: auto;
  height: 15px;
}

/* --- Hairlines ---------------------------------------------------------- */
.site-footer__rule {
  grid-column: 1 / -1;
  margin: 0;
  border: 0;
  height: var(--line-width);
  background: var(--rich-black-1);
}
.site-footer__rule--top    { grid-row: 2; }
.site-footer__rule--bottom { grid-row: 4; }

/* --- Left half: tagline, socials, office -------------------------------- */
.site-footer__brand {
  grid-column: 1;
  grid-row: 3;
}

.site-footer__tagline { margin-top: 14px; }

.site-footer__social {
  display: flex;
  align-items: center;
  gap: var(--layout-gutter);
  margin-top: var(--layout-gutter);
}

.site-footer__office {
  display: block;
  font-style: normal;
  margin-top: var(--layout-gutter);
}
.site-footer__office span { display: block; }

/* --- Right half: three link columns -------------------------------------
   Spans from the logo band down past the first hairline, exactly as in the
   macket. 169 wide each, 50 apart — two gutters.                          */
.site-footer__nav {
  grid-column: 2;
  grid-row: 1 / 4;
  align-self: start;
  display: flex;
  gap: calc(var(--layout-gutter) * 2);
}

.site-footer__col {
  display: flex;
  flex-direction: column;
  gap: 30px;
  width: 169px;
}

.site-footer__list {
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
  align-items: start;
}

/* --- Bottom bar --------------------------------------------------------- */
.site-footer__bottom {
  grid-column: 1 / -1;
  grid-row: 5;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--layout-gutter);
  margin-top: 14px;
}

.site-footer__legal {
  display: flex;
  flex-wrap: wrap;
  gap: var(--layout-gutter);
}

.site-footer__copy {
  text-align: right;
  white-space: nowrap;
}

/* --- Links -------------------------------------------------------------- */
.site-footer a {
  transition: color var(--t-fast);
}
.site-footer a:hover,
.site-footer a:focus-visible {
  color: var(--content-accent);
}

/* --- The reduced footer — Figma `Footer_min` 917:7587, 1440 x 319 --------
   Used by the two paid-traffic landing pages. Same brand block, same legal
   row, same hairline; the three site-map columns are replaced by "Contact"
   and two ways to reach us, and the second hairline is gone.

   Measured from the symbol: logo 50,50 · rule y 83 · tagline y 98 · social
   y 134 · office y 184 · legal row and copyright y 258. With the 50 page
   padding those become a 33 logo band, the rule, a 160 body and the bottom
   bar — 319 in total.                                                     */
.site-footer--min {
  min-height: 319px;
}

.site-footer--min .site-footer__grid {
  /* logo band · hairline · body · bottom bar */
  grid-template-rows: 33px var(--line-width) 160px auto;
}

/* "Contact" sits on the logo's line, hard right. */
.site-footer--min .site-footer__contact {
  grid-column: 2;
  grid-row: 1;
  justify-self: end;
  align-self: start;
}

/* WhatsApp and the address share the tagline's line, right aligned. */
.site-footer--min .site-footer__reach {
  grid-column: 2;
  grid-row: 3;
  justify-self: end;
  align-self: start;
  display: flex;
  gap: 50px;
  margin-top: 14px;
}

.site-footer--min .site-footer__reach a {
  transition: color var(--t-fast);
}
.site-footer--min .site-footer__reach a:hover,
.site-footer--min .site-footer__reach a:focus-visible {
  color: var(--content-accent);
}

/* The bottom bar moves up one row, since there is no second hairline. */
.site-footer--min .site-footer__bottom {
  grid-row: 4;
}

/* ===== up.css ===== */
/* ==========================================================================
   Scroll-to-top control — `Button_form` 657:4075, macket 50,235 · 61 × 72.
   Load AFTER css/base.css.

   Fixed to the window at the page margin, at the same y the file draws it,
   so it sits in the empty strip left of the first vertical line and clear of
   the header. The label is set on its side reading bottom to top, which is
   what makes the box taller than it is wide.
   ========================================================================== */

.site-up {
  position: fixed;
  left: var(--layout-margin);
  /* The file draws this at y 235 — a static position on a page that does not
     scroll. As a floating control at the same coordinate it sits on top of
     whatever band happens to be passing: the Services list on the homepage
     runs its blue fill from the page margin, and the button covered the first
     row's line. So it keeps the file's x and moves to the foot of the window,
     out of the reading column and where a back-to-top control is looked for. */
  bottom: var(--layout-margin);
  z-index: 11;                      /* over the header's 10 */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 25px;
  border: 0;
  background: var(--action-fill);
  color: var(--content-on-accent);
  box-shadow: inset 0 0 0 3px var(--action-fill);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--t-base) ease,
              background-color var(--t-fast) ease,
              box-shadow var(--t-fast) ease;
}

/* `hidden` is removed by the script; `data-shown` is what fades it in, so
   the control is never a dead button and never a flash on load. */
.site-up[data-shown] { opacity: 1; }

.site-up__label {
  writing-mode: vertical-rl;
  transform: rotate(180deg);        /* reads bottom to top, as in the file */
  white-space: nowrap;
}

/* pas → hov on Button_form: the fill empties, the amber stroke stays, and
   the box does not change size because the stroke is drawn inside. */
.site-up:hover,
.site-up:focus-visible {
  background: var(--action-fill-hover);
  box-shadow: inset 0 0 0 3px var(--action-border-hover);
}

/* ===== consent.css ===== */
/* ==========================================================================
   Cookie consent banner — partials/consent.html, behaviour in js/track.js
   Not in the Figma file (added 2026-10-08). Everything here is a token or a
   type style the site already has: page ground, the 3 px Rich Black 1 rule,
   the Amber 4 action and ring, 15 px type, the 25 / 50 spacing steps.

   Desktop: copy left, three buttons right; the settings panel opens below
   across the full working area. Phone: one column, buttons share a row.

   The banner sits outside .page, so base.css's z-index pin (`.page > *` at
   1, specificity 0,4,0) does not reach it and a plain number is enough.
   ========================================================================== */

.consent {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  max-height: 100vh;
  overflow-y: auto;
  background: var(--surface-page);
  border-top: 3px solid var(--border-strong);
  color: var(--content-primary);
}
.consent[hidden],
.consent [hidden] { display: none !important; }

.consent__inner {
  box-sizing: border-box;
  width: min(100%, var(--layout-reference));
  margin-inline: auto;
  padding: 25px var(--layout-margin);
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  column-gap: 50px;
  row-gap: 25px;
}

.consent__copy { display: grid; gap: 10px; max-width: 80ch; }
.consent__title,
.consent__text { margin: 0; }
.consent__text { line-height: 1.5; }
.consent__link {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--border-accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

.consent__actions { display: flex; gap: 15px; }

.consent__btn {
  min-width: 150px;
  min-height: 44px;
  padding: 0 25px;
  border: 3px solid var(--border-accent);
  border-radius: 0;
  background: transparent;
  font-family: inherit;
  color: var(--content-on-accent);
  cursor: pointer;
  transition: background-color var(--t-fast);
}
.consent__btn--fill { background: var(--action-fill); }
.consent__btn--fill:hover { background: var(--action-fill-hover); }
.consent__btn--line:hover { background: var(--action-fill); }
.consent__btn--text {
  min-width: 0;
  padding: 0 10px;
  border-color: transparent;
  text-decoration: underline;
  text-decoration-color: var(--border-accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 5px;
}
.consent__btn--text:hover { border-color: var(--border-accent); }
.consent__btn:focus-visible,
.consent__box:focus-visible {
  outline: 3px solid var(--border-strong);
  outline-offset: 3px;
}

/* Settings panel: spans both columns under the copy and the buttons. */
.consent__panel {
  grid-column: 1 / -1;
  display: grid;
  gap: 15px;
  justify-items: start;
  padding-top: 25px;
  border-top: 1px solid var(--border-hairline);
}
.consent__row {
  display: grid;
  grid-template-columns: 22px 1fr;
  gap: 15px;
  align-items: start;
  max-width: 80ch;
  cursor: pointer;
}
.consent__label { display: grid; gap: 5px; line-height: 1.5; }
.consent__box {
  width: 22px;
  height: 22px;
  margin: 0;
  accent-color: var(--amber-4);
  cursor: pointer;
}
.consent__box:disabled { cursor: default; }

/* Phone: one column; the three buttons share the row. */
@media (max-width: 1023.98px) {
  .consent__inner {
    grid-template-columns: 1fr;
    row-gap: 15px;
    padding: 15px 25px calc(15px + env(safe-area-inset-bottom));
  }
  .consent__actions { gap: 10px; }
  .consent__btn { flex: 1; min-width: 0; padding: 0 10px; }
  .consent__btn--text { flex: 0 0 auto; }
  .consent__panel { padding-top: 15px; }
  .consent__panel .consent__btn { width: 100%; }
}

/* ===== insights/s1.css ===== */
/* ==========================================================================
   Insights — Section 1.  Figma "Blog" 355:1175, instance 888:8818,
   macket 0..1440 x 111..1869 (1440 x 1758).

   Three bands, stacked with no air between the first two:

       725  hero plate        [bleed:both] — photograph under a 50 % Rich
                              Black 1 wash, the lockup and the featured
                              teaser laid over it
       828  card deck         [bleed:both] — Vista Blue 1, the 4 x 2 grid of
                              Blog_Card_S1 inside the working area
        50  air
       155  filter block      — seven Autors_Filter_Button over the caption

   725 + 828 + 50 + 155 = 1758, and the block sits flush under the header,
   which is why the section carries --gap: 0 in the markup.
   ========================================================================== */

.s-s1 {
  display: flex;
  flex-direction: column;
}

/* The deck sits flush under the hero plate; the filter block below it is the
   one internal gap on this screen, and it is 50. */
.s-s1 > .container {
  margin-top: 50px;
}

/* --- The hero plate -----------------------------------------------------
   The photograph is exported at the crop the file shows (1440 x 725 of a
   1440 x 1080 source, anchored top), so the box keeps its 725 and the
   picture covers it from the top edge down as the window narrows.        */
.s-s1 .s-s1__hero {
  position: relative;
  height: 725px;
  overflow: hidden;
}

.s-s1 .s-s1__hero-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

/* Rich Black 1 at 50 %, drawn here rather than baked into the export so the
   picture underneath stays a photograph and not a darkened one. */
.s-s1 .s-s1__hero-tint {
  position: absolute;
  inset: 0;
  background: var(--rich-black-1);
  opacity: 0.5;
}

.s-s1 .s-s1__hero-inner {
  position: relative;
  height: 100%;
}/* --- The lockup ---------------------------------------------------------
   Macket 164,150 · 1112 wide.  "INSIGHTS" in Comforter lies over "FOR
   AUTHORS" in Mulish; the Mulish line sits 50 down inside the 85 group.   */
.s-s1 .s-s1__lockup {
  position: absolute;
  top: 150px;
  left: 8.5075%;        /* 114 / 1340 — column 2 of the grid */
  width: 82.9851%;      /* 1112 / 1340 */
  display: grid;
  font: inherit;
}

.s-s1 .s-s1__lockup > * {
  grid-area: 1 / 1;
  width: 100%;
}

.s-s1 .s-s1__script {
  z-index: 1;
  color: var(--content-accent);
}

.s-s1 .s-s1__word {
  margin-top: 50px;
  color: var(--content-on-inverse);
}

/* --- Featured teaser ----------------------------------------------------
   Macket 164,521 · 657 x 154.  The two Button_form instances beside it are
   hidden in the file, so the heading itself carries the link.             */
.s-s1 .s-s1__teaser {
  position: absolute;
  top: 521px;
  left: 8.5075%;
  width: 49.0299%;      /* 657 / 1340 */
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
  color: var(--content-on-inverse);
}

.s-s1 .s-s1__teaser-title a {
  transition: color var(--t-fast) ease;
}

.s-s1 .s-s1__teaser-title a:hover,
.s-s1 .s-s1__teaser-title a:focus-visible {
  color: var(--content-accent);
}

/* --- Card deck ----------------------------------------------------------
   Blog_S1_Card_Scroller: 1440 x 828 of Vista Blue 1.  50 of air, the 1340
   grid, 50, the pager row, 50.                                            */
.s-s1 .s-s1__deck {
  background: var(--surface-brand);
  padding: 50px 0;
}

.s-s1 .s-s1__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--layout-gutter);
}

/* --- Blog_Card_S1, set 371:2035 -----------------------------------------
   Square, 316 at the reference.  Three states:

     Pas  flat plate — Editorial White 4, Amber 4 on the featured card
     Hov  the article's photograph laid over the plate at 25 %, the title
          and the number still on top of it
     Act  the photograph at full strength, the title gone

   The photograph is in the markup at all times and changes opacity, so
   nothing reflows and the picture is already decoded when it is wanted.
   :focus-within carries Hov to the keyboard.                               */
.s-s1 .s-s1__card {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: var(--editorial-white-4);
  color: var(--content-primary);
}

.s-s1 .s-s1__card--featured {
  background: var(--amber-4);
}

.s-s1 .s-s1__card-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity var(--t-base) ease;
}

.s-s1 .s-s1__card:hover .s-s1__card-photo,
.s-s1 .s-s1__card:focus-within .s-s1__card-photo {
  opacity: 0.25;
}

/* Act: the picture takes the card and the title steps out of the way. The
   featured plate drops its amber under the photograph, exactly as the Hov
   variant of Card3 does. */
.s-s1 .s-s1__card:active .s-s1__card-photo {
  opacity: 1;
}

.s-s1 .s-s1__card:active .s-s1__card-title {
  opacity: 0;
}

.s-s1 .s-s1__card--featured:hover,
.s-s1 .s-s1__card--featured:focus-within {
  background: var(--editorial-white-4);
}

/* 25 in from three sides, sitting on the foot of the card. */
.s-s1 .s-s1__card-title {
  position: absolute;
  left: 25px;
  right: 25px;
  bottom: 25px;
  transition: opacity var(--t-fast) ease;
}

/* The whole square is the target; the anchor only carries the destination. */
.s-s1 .s-s1__card-link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.s-s1 .s-s1__card-no {
  position: absolute;
  top: 25px;
  right: 25px;
  text-align: right;
  white-space: nowrap;
}

/* --- Pager --------------------------------------------------------------
   Macket: the count reads centred on x 731 and the arrow sits at x 835,
   both with their tops at 757 of the 828 block — 50 under the grid.       */
.s-s1 .s-s1__pager {
  position: relative;
  height: 22px;
  margin-top: 50px;
}

.s-s1 .s-s1__count {
  position: absolute;
  left: 50.8209%;       /* 681 / 1340 */
  top: 0;
  transform: translateX(-50%);
  color: var(--content-on-inverse);
  white-space: nowrap;
}

.s-s1 .s-s1__next {
  position: absolute;
  left: 58.5821%;       /* 785 / 1340 */
  top: 0;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  transition: opacity var(--t-fast) ease;
}

.s-s1 .s-s1__next[disabled] {
  opacity: 0.35;
  cursor: default;
}

/* --- Filter block -------------------------------------------------------
   Macket 164,1603 · 1112 x 155: the button field is 119 tall (two 47 rows
   with the gutter between them), 25, then the caption.                    */
.s-s1 .s-s1__filters {
  margin-left: 8.5075%;
  width: 82.9851%;
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
}

.s-s1 .s-s1__row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-content: center;
  gap: var(--layout-gutter);
}

/* Autors_Filter_Button.  25 of side padding and 15 above and below an
   11-tall trimmed cap give the 47 of the macket; the stroke is 3px and is
   drawn on the box, so the plate state does not resize it.                */
.s-s1 .s-s1__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 15px 25px;
  border: 3px solid var(--border-hairline);
  background: transparent;
  color: var(--content-primary);
  cursor: pointer;
  transition: border-color var(--t-fast), background-color var(--t-fast),
              color var(--t-fast);
}

.s-s1 .s-s1__btn-label {
  white-space: nowrap;
}

/* Hov (769:5312): the hairline becomes the brand blue. */
.s-s1 .s-s1__btn:hover,
.s-s1 .s-s1__btn:focus-visible {
  border-color: var(--vista-blue-1);
}

/* Act: the Rich Black plate.  Styled off aria-pressed so the markup and the
   picture cannot drift apart. */
.s-s1 .s-s1__btn[aria-pressed="true"] {
  border-color: var(--rich-black-1);
  background: var(--rich-black-1);
  color: var(--content-on-inverse);
}

.s-s1 .s-s1__btn[aria-pressed="true"]:focus-visible {
  background: var(--rich-black-1);
}

.s-s1 .s-s1__browse {
  text-align: center;
}

/* The live region reports the filter result to a screen reader; it carries
   no height of its own, so the block stays 155 tall. */
.s-s1 .s-s1__status {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ===== insights/s2.css ===== */
/* ==========================================================================
   Insights — Section 2, "Get publishing insights in your inbox."
   Figma node 972:10764, macket 164..1390 x 2019..2289 (1226 x 270).
   No intent tag: fluid.  The block starts at column 2 of the grid and runs
   to the right edge of the working area, so it is 1226 of the 1340.

   270 = 148 (the lockup) + 25 + 97 (the form row).
   The gap above it is the screen's default 150, so nothing is written here.
   ========================================================================== */

.s-s2 .s-s2__block {
  margin-left: 8.5075%;      /* 114 / 1340 — column 2 */
  width: 91.4925%;           /* 1226 / 1340 */
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
}

/* --- Lockup -------------------------------------------------------------
   "Get" in Comforter lies over the Mulish line, which sits 50 down inside
   the 85 group and wraps at 975.728 of the 1226 — two lines, so the group
   is 148 tall rather than 85.                                             */
.s-s2 .s-s2__lockup {
  display: grid;
  font: inherit;
}

.s-s2 .s-s2__lockup > * {
  grid-area: 1 / 1;
  width: 100%;
}

.s-s2 .s-s2__script {
  z-index: 1;
  color: var(--content-accent);
}

.s-s2 .s-s2__word {
  margin-top: 50px;
  width: 79.5863%;           /* 975.728 / 1226 */
  color: var(--content-primary);
}

/* --- Form row -----------------------------------------------------------
   Macket 544 + 25 + 657 = 1226.  The left column holds the lede at 430 of
   its 544; the right column is the six-column form.                       */
.s-s2 .s-s2__row {
  display: flex;
  align-items: flex-start;
  gap: var(--layout-gutter);
}

.s-s2 .s-s2__lede {
  flex: 0 1 44.3720%;        /* 544 / 1226 */
  width: 79.0441%;           /* 430 / 544 — the text's own measure */
  color: var(--content-primary);
}

.s-s2 .s-s2__form {
  flex: 0 1 53.5889%;        /* 657 / 1226 */
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
}

/* 493 plate + 25 + the button; the row is 61 tall, which is the button. */
.s-s2 .s-s2__field {
  display: flex;
  align-items: stretch;
  gap: var(--layout-gutter);
}

/* The label is for the screen reader only: the macket shows the placeholder
   alone inside the plate. */
.s-s2 .s-s2__label {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Main_S14_Form_text_card, the outlined variant: a 3px Vista Blue 1 stroke
   and no fill, 61 tall.                                                   */
.s-s2 .s-s2__plate {
  flex: 1 1 auto;
  min-width: 0;
  height: 61px;
  padding: 0 15px;
  border: 3px solid var(--vista-blue-1);
  background: transparent;
  color: var(--content-primary);
}

.s-s2 .s-s2__plate::placeholder {
  color: var(--vista-blue-1);
  opacity: 1;
}

.s-s2 .s-s2__plate:focus-visible {
  outline-offset: 0;
  background-color: var(--editorial-white-2);
}

/* Button_form.  The stroke matches the fill at rest, so emptying the fill on
   hover leaves the box the same size.                                     */
.s-s2 .s-s2__submit {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 25px;
  border: 0;
  background: var(--action-fill);
  box-shadow: inset 0 0 0 3px var(--action-fill);
  color: var(--content-on-accent);
  cursor: pointer;
  transition: background-color var(--t-fast) ease, box-shadow var(--t-fast) ease;
}

.s-s2 .s-s2__submit-label {
  white-space: nowrap;
}

.s-s2 .s-s2__submit:hover,
.s-s2 .s-s2__submit:focus-visible {
  background: var(--action-fill-hover);
  box-shadow: inset 0 0 0 3px var(--action-border-hover);
}

.s-s2 .s-s2__note {
  color: var(--content-primary);
}

/* ===== insights/cta.css ===== */
/* ==========================================================================
   Insights — three ways to start.  Intent tag: flow.
   Figma: "CTA", node 972:10725, 1340 x 759 — the whole working area.
   Card component Service_S6_Card, instances 972:10732 / :10733 / :10734.
   The same block the Main screen carries, so the numbers are the same:
   159 heading + 50 + 550 cards = 759, and no fill — the page ground shows.
   The gap above it is the screen's default 150, so nothing is written here.
   ========================================================================== */

.s-cta .s-cta__inner {
  display: flex;
  flex-direction: column;
  gap: 50px;
}

/* --- Heading ------------------------------------------------------------
   The Comforter word lies over the Mulish heading in one grid cell: the
   heading sits 50 down inside the 85-tall group, the accent starts at 0.  */
.s-cta .s-cta__intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--layout-gutter);
  text-align: center;
}
.s-cta .s-cta__title {
  display: grid;
  width: 100%;
  max-width: 753px;
  font: inherit;
}
.s-cta .s-cta__title > * {
  grid-area: 1 / 1;
  width: 100%;
}
.s-cta .s-cta__title-main {
  margin-top: 50px;
}
.s-cta .s-cta__title-accent {
  color: var(--amber-4);
}
.s-cta .s-cta__subheading {
  width: 100%;
  max-width: 480px;
}

/* --- Cards --------------------------------------------------------------
   430 x 3 + 25 x 2 = 1340: the row is the whole working area, and it wraps
   rather than shrinks once the cards stop fitting.                        */
.s-cta .s-cta__cards {
  --flow-basis: 430px;
}

/* Variant Hov: the text panel swaps Rich Black 3 for Amber 4 and nothing
   else moves. :focus-within carries it to the keyboard, because the card's
   only target is the link inside it.                                      */
.s-cta .s-cta__card {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 550px;
  background: var(--rich-black-3);
  transition: background-color var(--t-base) ease;
}
.s-cta .s-cta__card:hover,
.s-cta .s-cta__card:focus-within {
  background: var(--amber-4);
}

/* The panel ends at 229 of the 550. A floor, not a fixed height: below the
   reference width the title wraps onto more lines and the panel grows into
   the photograph rather than over it.                                     */
.s-cta .s-cta__panel {
  flex: 0 0 auto;
  min-height: 229px;
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
  padding: 50px 25px 25px;
}
.s-cta .s-cta__card-title,
.s-cta .s-cta__card-line {
  color: var(--content-primary);
}

.s-cta .s-cta__photo-wrap {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}
.s-cta .s-cta__photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The button lies over the photograph, 25 from the bottom and 25 from the
   right; its width is the label plus 25 each side, which is what gives the
   three buttons three different widths in the macket.                     */
.s-cta .s-cta__button {
  position: absolute;
  right: 25px;
  bottom: 25px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 25px;
  background: var(--action-fill);
  color: var(--content-on-accent);
  transition: background-color var(--t-fast) ease, box-shadow var(--t-fast) ease;
}
.s-cta .s-cta__button-label {
  white-space: nowrap;
}
.s-cta .s-cta__button:hover {
  background: var(--action-fill-hover);
  box-shadow: inset 0 0 0 3px var(--action-border-hover);
}

/* ===== m-base.css ===== */
/* ==========================================================================
   Mobile foundation — Figma page "Mobile", hand-off document v1.0.
   Load AFTER every desktop stylesheet. See CONTRACT_MOBILE.md.

   The whole file is one media query. Below 1024 this layer overrides the
   desktop layer; at 1024 and up not a single rule here applies, so the
   desktop layout is untouched byte for byte.

   Why an overlay rather than two wrapped halves: the desktop CSS is live and
   already verified. Wrapping it would rewrite every one of its rules to prove
   a layout that is not changing. This way the desktop bytes stay as they are
   and the mobile layer states only its differences.
   ========================================================================== */

@media (max-width: 1023.98px) {

  /* --- 3.1 Grid ---------------------------------------------------------
     402 reference · 6 columns · Stretch · margin 25 · gutter 25
     Working area 352. Column 37.83 is derived and written nowhere.        */
  :root {
    --m-reference: 402px;
    --m-margin:    25px;
    --m-gutter:    25px;
    --m-content:   352px;   /* at the reference width                      */
    --m-max:       430px;   /* the column stops growing here (3.2)         */

    /* 4. Three gaps carry 94 % of 3 010 Auto Layout nodes. */
    --m-gap-tight: 10px;
    --m-gap-mid:   15px;
    --m-gap:       25px;
    --m-gap-block: 50px;
    --m-gap-big:   75px;

    /* 9.1 Header: logo at y 59, rule at y 89. */
    --m-header-h:  89px;

    /* 5.2 Touch targets grow from the centre toward this. */
    --m-tap:       44px;
  }

  /* --- 3.2 Reflow -------------------------------------------------------
     The desktop floor is 1200 and it is what puts a horizontal scrollbar on
     a phone. Below the breakpoint there is no floor: the page is as wide as
     the window and never wider.                                           */
  body {
    min-width: 0;
    overflow-x: clip;
  }

  /* Working area. Below 430 it stretches with the window and the 25 margins
     hold; above 430 it stops at 380 and centres, and the window fills with
     the page ground. Nothing scales — sizes and spacing are the macket's.  */
  .container {
    width: min(100% - var(--m-margin) * 2, calc(var(--m-max) - var(--m-margin) * 2));
    margin-inline: auto;
  }

  /* 6 columns, not 12. A block that asked for the desktop grid gets the
     mobile one without having to know which layer it is in.               */
  .grid12 {
    grid-template-columns: repeat(6, 1fr);
    gap: var(--m-gutter);
  }

  /* --- Intent tags ------------------------------------------------------
     `flow` on mobile is a single column: two 430-basis children side by side
     cannot fit 352. Bleed keeps its meaning — the full window, which above
     430 is wider than the column.                                          */
  .is-flow { display: block; }
  .is-flow > * + * { margin-top: var(--m-gap); }

  .is-bleed-left,
  .is-bleed-right,
  .is-bleed-both,
  .m-bleed {
    width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: 0;
  }

  /* --- 3.1 Background lines ---------------------------------------------
     Unlike desktop, where the line layer spans the page, `BackgroundLines`
     on mobile is 352 wide and starts below the header — it lives inside the
     working area. The desktop layer's seven lines at 12.5 % of the window
     are wrong here and are switched off; each screen draws its own set
     inside its own container.                                              */
  .page > .gridlines { display: none; }

  /* --- 5.6 Touch targets ------------------------------------------------
     The area grows from the centre of the element toward 44 on each axis,
     independently, and never moves or resizes what is drawn. Where a
     neighbour is closer than 44, the block sets --tap-h (or --tap-w) to
     twice the half-gap for EVERY item in that row, so the row is even under
     the thumb (5.3).

     ::after and not padding: padding would move the element.               */
  .m-tap { position: relative; }
  .m-tap::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width:  max(100%, var(--tap-w, var(--m-tap)));
    height: max(100%, var(--tap-h, var(--m-tap)));
  }

  /* An indicator is not a target: carousel dots and arrows show that more
     exists, they do not move anything (5.7).                               */
  .m-indicator { pointer-events: none; }

  /* --- 7 Type -----------------------------------------------------------
     Eleven of the twelve mobile styles are the desktop values unchanged —
     the 15 and 25 sizes are the same file-wide. Only the Comforter accent
     differs, and it differs by half: 50 on mobile against 100 on desktop.
     The styles are named "… Mobile" in Figma for exactly this reason.      */
  .t-heading-accent,
  .t-heading-accent-small { font-size: 50px; }

  /* 7.2 The one style with no desktop counterpart: the numeral on the error
     page. 500 is the size, not a typo.                                     */
  .t-404 {
    font-family: "Comforter", cursive;
    font-weight: 400;
    font-size: 500px;
    letter-spacing: 0.05em;
  }

  /* --- 3.2 Long pages ---------------------------------------------------
     Screens run to 14 382. Smooth anchor scrolling has to clear the pinned
     header or the target lands underneath it.                              */
  :target { scroll-margin-top: calc(var(--m-header-h) + var(--m-gap)); }

}

/* ==========================================================================
   Layer switch. A page carries both sets of blocks; each layer hides the
   other's. The mobile blocks are marked `is-m` by the screen that writes
   them; everything else in <main> is the desktop layer.

   The second query is the only rule in this file that applies at 1024 and up,
   and it can only hide blocks that a desktop-only build never emits — so the
   desktop layer is still untouched.
   ========================================================================== */
@media (max-width: 1023.98px) {
  .page > main > section:not(.is-m) { display: none; }
  .page > main > .is-m + .is-m { margin-top: var(--gap-m, var(--m-gap-big)); }
  .page > main > .is-m:first-child { margin-top: 0; }
}
@media (min-width: 1024px) {
  .page > main > .is-m { display: none; }
}

/* ===== m-header.css ===== */
/* ==========================================================================
   Mobile header and menu — Figma `Menu_mob` 1244:11197.
   Inside the mobile media query; nothing here exists at 1024 and up.
   ========================================================================== */

@media (max-width: 1023.98px) {

  /* The desktop header and its three sub-rows do not appear on a phone: the
     mobile menu is an overlay with its own, flatter list. */
  .page > .site-header { display: none; }

  .m-header[hidden] { display: block; }   /* `hidden` is for the no-CSS case */

  .m-header {
    position: sticky;
    top: 0;
    z-index: 10;
    height: var(--m-header-h);            /* 89 — the rule sits on the edge   */
  }
  .page > .m-header { position: sticky; z-index: 10; }

  /* 8. The one effect in the whole mobile version. */
  .m-header__plate {
    position: absolute;
    inset: 0;
    z-index: 0;
    background: var(--header-plate);
    -webkit-backdrop-filter: blur(var(--header-blur));
    backdrop-filter: blur(var(--header-blur));
  }

  /* Logo at 25,59. Its touch area reaches 44 on the vertical — the room is
     there, and nothing else is near it. */
  .m-header__logo {
    position: absolute;
    z-index: 2;
    left: var(--m-margin);
    top: 59px;
    --tap-w: 107px;
  }
  .m-header__logo img { width: auto; height: 15px; }

  /* The button at 332,49 is 70 × 40 in the file: wide enough across, four
     pixels short down. The area takes the full 44 on both axes; the nearest
     other target is the logo, 200 away. */
  .m-header__toggle {
    position: absolute;
    z-index: 2;
    right: var(--m-margin);
    top: 49px;
    width: 45px;
    height: 40px;
    display: grid;
    place-items: center;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
  }

  /* Three bars drawn in CSS, as the file draws them — not an exported icon. */
  .m-header__bars,
  .m-header__bars::before,
  .m-header__bars::after {
    display: block;
    width: 20px;
    height: 2px;
    background: var(--content-primary);
  }
  .m-header__bars { position: relative; }
  .m-header__bars::before,
  .m-header__bars::after { content: ""; position: absolute; left: 0; }
  .m-header__bars::before { top: -6px; }
  .m-header__bars::after  { top:  6px; }

  /* Line 54 at y 89, 352 wide — inside the working area, not edge to edge. */
  .m-header__rule {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    bottom: 0;
    width: min(100% - var(--m-margin) * 2, calc(var(--m-max) - var(--m-margin) * 2));
    margin: 0;
    border: 0;
    border-top: var(--line-width) solid var(--line-color);
  }

  /* --- The overlay ------------------------------------------------------
     402 × 830 in the file, anchored under the header. On a real phone it
     takes the window, because a fixed height would leave the page showing
     under it on a tall screen and cut the buttons off on a short one.     */
  .page > .m-header { position: sticky; z-index: 10; }
  .page > .m-menu   { position: fixed;  z-index: 20; }

  .m-menu {
    position: fixed;
    inset: 0;
    z-index: 20;
    background: var(--surface-page);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  .m-menu[hidden] { display: none; }

  .m-menu__inner {
    display: flex;
    flex-direction: column;
    min-height: 100%;
    padding-block: 49px var(--m-gap-block);
  }

  /* Close at 332,0 · 45 × 40 with a 20 × 20 glyph, then the rule at y 40. */
  .m-menu__head { position: relative; height: 40px; }

  .m-menu__close {
    position: absolute;
    right: 0;
    top: 0;
    width: 45px;
    height: 40px;
    display: grid;
    place-items: center;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
  }
  .m-menu__close span,
  .m-menu__close span::before,
  .m-menu__close span::after { display: block; }
  .m-menu__close span {
    position: relative;
    width: 20px;
    height: 20px;
  }
  .m-menu__close span::before,
  .m-menu__close span::after {
    content: "";
    position: absolute;
    left: 0;
    top: 9px;
    width: 20px;
    height: 2px;
    background: var(--content-primary);
  }
  .m-menu__close span::before { transform: rotate(45deg); }
  .m-menu__close span::after  { transform: rotate(-45deg); }

  .m-menu__rule,
  .m-menu__list li + li {
    border: 0;
    border-top: var(--line-width) solid var(--line-color);
  }
  .m-menu__rule { position: absolute; bottom: 0; left: 0; right: 0; margin: 0; }

  /* Nine items on a 41 step: the label sits 15 below its own rule, the row is
     26 tall. 41 between centres is under 44, so by 5.2 every area takes half
     the gap on each side — 41 — and by 5.3 every item in the list takes the
     same one, so the first and last are not larger than the rest. */
  .m-menu__list { margin-top: var(--m-gap); }
  .m-menu__list li { padding-bottom: 15px; }
  /* 15 above the label and 15 below gives a 42 step, not the file's 41: in
     Figma the rule is a zero-height line, in CSS it is a real pixel. The
     padding above absorbs it so the step lands on 41 exactly. */
  .m-menu__list li + li { padding-top: 14px; }
  .m-menu__list a { display: block; --tap-h: 41px; }

  /* The two calls to action and the address, at the foot of the overlay.
     `margin-top: auto` pins them down however tall the window is, which is
     what the file's fixed 646 does on a 830 frame. */
  .m-menu__foot {
    margin-top: auto;
    padding-top: var(--m-gap-big);
    display: grid;
    justify-items: center;
    gap: var(--m-gap-mid);
  }

  .m-menu__foot .m-btn {
    display: grid;
    place-items: center;
    width: 253px;
    max-width: 100%;
    height: 41px;
    text-align: center;
  }
  .m-menu__foot .m-btn--fill {
    background: var(--action-fill);
    color: var(--content-on-accent);
  }
  .m-menu__foot .m-btn--line {
    box-shadow: inset 0 0 0 3px var(--border-strong);
    color: var(--content-primary);
  }

  .m-menu__mail { margin-top: calc(var(--m-gap-block) + 6px); }
  .m-menu__mail a { --tap-h: 44px; }

  /* While the overlay is open the page underneath does not scroll. */
  body.is-m-menu-open { overflow: hidden; }

}

/* The mobile chrome exists in the markup at every width; only the media query
   keeps it off the desktop layer. `hidden` is removed by the script as soon
   as it runs, so without this the header renders twice above 1024. */
@media (min-width: 1024px) {
  .m-header, .m-menu, .m-footer { display: none !important; }
}

/* ===== m-footer.css ===== */
/* ==========================================================================
   Mobile footer — Figma `Footer_m` 1774:15900, 402 × 449.
   Inside the mobile media query; nothing here exists at 1024 and up.
   ========================================================================== */

@media (max-width: 1023.98px) {

  .page > .site-footer { display: none; }
  .m-footer[hidden] { display: block; }

  /* The file leaves 75 between the last block and the footer. The desktop
     layer sets its own gap on .site-footer, which is hidden down here, so
     this one has to be stated. */
  .page > .m-footer { margin-top: var(--m-gap-big); }

  .m-footer {
    background: var(--surface-brand);
    color: var(--content-on-brand);
    text-align: center;
  }

  /* The block runs edge to edge; the content keeps the 25 margins. */
  .m-footer__inner { padding-block: var(--m-gap) var(--m-gap-block); }

  .m-footer__logo {
    display: inline-block;
    --tap-h: 44px;
    --tap-w: 107px;
  }
  .m-footer__logo img { width: auto; height: 15px; }

  /* Three groups. The file sets them 10 apart, not 25: `Frame 481` runs
     logo 15 · 10 · group 169 · 10 · group 62 · 10 · group 98 = 374, which
     with the 25 above and 50 below is the footer's 449. The 25 that stood
     here was what made the block 46 too tall on all 37 screens. */
  .m-footer__group { margin-top: var(--m-gap-tight); }
  .m-footer__rule {
    margin: 0 0 var(--m-gap-mid);
    border: 0;
    border-top: var(--line-width) solid var(--content-on-brand);
  }

  /* Two lines, 30 tall in the file: 11 a line on a 19 step. */
  .m-footer__tagline { margin-inline: auto; max-width: 30ch; line-height: 19px; }

  /* Three marks on a 50 step: 50 between centres clears 44, so each area is
     the full 44 × 44 and they still do not touch. */
  .m-footer__social {
    display: flex;
    justify-content: center;
    gap: 25px;
    margin-top: var(--m-gap);
  }
  .m-footer__social a { display: block; }

  /* `text-box-trim` only takes effect on a block box: a bare <span> inside a
     grid is still inline, the trim is ignored, and the line keeps its full
     leading. Every trimmed label here is blockified for that reason — the
     same trap that put 202px of drift into the FAQ.
     Figma writes the three address lines on an 18 step from a 49-tall box. */
  .m-footer__office span { display: block; }
  .m-footer__office {
    display: grid;
    gap: 7px;
    margin-top: var(--m-gap);
    font-style: normal;
  }

  /* 5.3 — one row, one size. The step is 36 in the file, so every link in
     both lists takes a 36 band: the rows stay even under the thumb and no
     two areas meet. This is the floor the contract records at §5.4.        */
  .m-footer__reach,
  .m-footer__legal {
    display: grid;
    gap: 25px;
  }
  /* `block`, not `inline-block`: an inline-block still sits in a line box, so
     the <li> keeps the full leading even after the label itself is trimmed and
     the row measures 19 where the file measures 11. */
  .m-footer__reach a,
  .m-footer__legal a {
    display: block;
    --tap-h: 36px;
  }

  .m-footer__legal a { color: var(--content-on-inverse); }

}

/* ===== m-up.css ===== */
/* ==========================================================================
   Mobile "up" control — Figma `Button_form` 41 × 52, drawn at 25,143 on all
   37 screens. Contract §9.2.
   ========================================================================== */

@media (max-width: 1023.98px) {

  /* The desktop control is 61 × 72 and sits at the desktop margin; the mobile
     one is its own size at its own place, so the shared element is restyled
     rather than duplicated. */
  .site-up { position: relative; }
  .site-up::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width:  max(100%, var(--tap-w, var(--m-tap)));
    height: max(100%, var(--tap-h, var(--m-tap)));
  }

  .site-up {
    position: fixed;
    left: var(--m-margin);
    bottom: var(--m-margin);
    padding: 0;
    width: 41px;
    height: 52px;

    /* 5.5 — three pixels short across. The room is there: the nearest other
       target is the footer, and on a scrolled page nothing sits beside it. */
    --tap-w: 44px;
    --tap-h: 52px;
  }

  /* The file draws it at y 143, under the header. As a floating control it
     keeps the file's x and moves to the foot of the window, out of the
     reading column — the same decision as on desktop, and for the same
     reason: at 143 it would sit on whatever band is passing under it. */

  .site-up__label { font-size: 15px; }

}

/* ===== insights/bm1.css ===== */
/* ==========================================================================
   Insights index mobile — block 1, the opening and the card deck.
   Figma: `Blog_m` 1542:10403 / "Section 1" 1549:13480, 352 x 1439.

     lockup     `Group 89` 1542:10699 — the script "Insights" over the Mulish
                word, centred, the word hanging 15 below the top of the group
                and inset 6 from its left
     filters    25 under it, seven `Autors_Filter_Button` on a 25 grid
     caption    25 under the filters, centred
     deck       25 under the caption, `Blog_S1_Cards` 1542:13288: four cards
                to a position, 15 apart, dots 15 under the stack

   This file also carries the vocabulary the screen's three blocks share —
   the heading lockup, the article card, the pale plate and the button. Each
   is one component in the file, so each is written once here rather than
   copied into three stylesheets.

   The whole file is one media query; nothing here exists at 1024 and up.
   ========================================================================== */

@media (max-width: 1023.98px) {

  /* ======================================================================
     Shared (bm- : blog mobile; m- is taken by the shared mobile layer)

     The heading lockup — Figma `Group 89` / `Group 90`.
     Comforter 50 and Mulish 25 share one cell and the script is drawn over
     the word. The group is as tall as the script's cap height, 38, or as
     the 15 offset plus the word where the word runs to more than one line.
     That is the file's own rule and it needs no measured height here.
     ====================================================================== */
  .bm-lockup {
    display: grid;
    font: inherit;
    text-align: center;
  }
  .bm-lockup > * { grid-area: 1 / 1; }
  .bm-lockup__word { margin-top: var(--m-gap-mid); margin-left: 6px; }
  .bm-lockup__script {
    color: var(--content-accent);
    pointer-events: none;
  }
  /* Section 2's lockup is the plain pair — no 6 inset, the word simply
     centred under the script. */
  .bm-lockup--flush .bm-lockup__word { margin-left: 0; }

  /* ======================================================================
     Shared: the pale plate — Rich black 3, 25 of padding all round.
     The three start cards, the contents, the team card and the comparison
     table are all this one surface.
     ====================================================================== */
  .bm-plate {
    background: var(--rich-black-3);
    color: var(--content-primary);
    padding: var(--m-gap);
  }

  /* ======================================================================
     Shared: `Button_form`, 61 tall — 25 of padding, an 11-tall trimmed cap,
     and 25 again.

     A block-level flex box rather than an inline one: inline-level children
     sit on a text baseline, which would leave the strut's descender under
     the button. The label is its own element inside it, because a flex item
     is blockified and `u-trim` only reaches a block container — set on the
     flex box itself it does nothing and the button stands 69.
     ====================================================================== */
  .bm-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--m-gap);
    border: 0;
    background: var(--action-fill);
    color: var(--content-on-accent);
    text-align: center;
    text-decoration: none;
    cursor: pointer;
  }
  .bm-btn--full { width: 100%; }
  /* Where the file sizes the button to its label and centres it — the three
     start cards draw it at 260, 253 and 142 — the width is the label's and
     is not set here. */
  .bm-btn--auto { width: fit-content; margin-inline: auto; }

  /* ======================================================================
     Shared: the article card — Figma `Frame 587` 1542:13125, 352 x 200, and
     its three-line twin at 219.

     The photograph fills the card and a Rich black 1 veil at 75 % sits over
     it; the copy sits on top. 25 of padding, 23 at the foot, and 48 between
     the three rows — which is what makes a two-line title 200 and a
     three-line title 219, height from content rather than from the file.

     5.7 "One link, one area": the card, its title and its arrow all go to
     the same place, so the whole card is one <a> with one area on its own
     bounds. Nothing inside it is a target.
     ====================================================================== */
  .bm-card__link {
    display: block;
    position: relative;
    isolation: isolate;
    overflow: hidden;
    padding: var(--m-gap) var(--m-gap) 23px;
    color: var(--content-on-inverse);
    text-decoration: none;
  }

  .bm-card__photo {
    position: absolute;
    inset: 0;
    z-index: -2;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  /* The veil is the Rich black 1 token at 75 %, not a fourth colour: §6
     allows seven and this is one of them held back, not a new one.        */
  .bm-card__veil {
    position: absolute;
    inset: 0;
    z-index: -1;
    background: var(--rich-black-1);
    opacity: 0.75;
  }

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

  .bm-card__row {
    display: flex;
    align-items: center;
    gap: var(--m-gap);
  }
  /* Both are flex items and so already blockified — `u-trim` reaches them.
     Left inline they would keep their full line box and every card would
     stand 8 taller than the file's 200. */
  .bm-card__topic {
    flex: 1 1 auto;
    min-width: 0;
    color: var(--content-accent);
  }
  .bm-card__no {
    flex: 0 0 auto;
    text-align: right;
  }

  .bm-card__title { display: block; }

  .bm-card__go {
    display: flex;
    align-items: center;
    gap: var(--m-gap-mid);
    color: var(--content-accent);
  }
  .bm-card__go-label { display: block; }
  .bm-card__arrow { flex: 0 0 auto; }

  /* ======================================================================
     Block 1
     ====================================================================== */

  .s-bm1 { display: flow-root; }

  /* --- 3.1 Background lines --------------------------------------------
     `BackgroundLines` 1542:10404: four lines at Figma x 25 · 142.33 ·
     259.67 · 377 on the 402 macket, which is 0, 33.33, 66.67 and 100 per
     cent of the working area. The file draws one continuous set for the
     whole screen, so one layer is drawn here and positioned against <main>,
     which base.css has already made the nearest positioned ancestor.
     z-index -1 keeps it under every plate and word.

     The file's 13 299 runs past the screen's own 3 307; it is the
     designer's single long guide, not a height to transfer.               */
  .s-bm1__lines {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: -1;
    pointer-events: none;
  }
  .s-bm1__lines > .container { position: relative; height: 100%; }
  .s-bm1__lines i {
    position: absolute;
    top: 0;
    bottom: 0;
    width: var(--line-width);
    background: var(--line-color);
  }
  .s-bm1__lines i:nth-child(1) { left: 0; }
  .s-bm1__lines i:nth-child(2) { left: 33.333%; }
  .s-bm1__lines i:nth-child(3) { left: 66.667%; }
  .s-bm1__lines i:nth-child(4) { right: 0; }

  /* --- The seven filters ------------------------------------------------
     `Autors_Filter_Button` Pas: 15 of padding all round, a 3px stroke drawn
     inside the box, and an 11-tall trimmed cap — the 47 the file measures.
     The stroke is inside, so nothing moves.

     The file lays the seven out 2 / 1 / 1 / 1 / 1 / 1 and centres each row.
     That arrangement is not composed here: at 352 the widths simply wrap
     that way, and at 320 the pair splits onto two rows of its own rather
     than crossing the margin.

     5 Touch: the button is 47 tall and never narrower than 66, so `m-tap`
     resolves to the button's own bounds on both axes and adds nothing. The
     25 between neighbours therefore survives: no two areas touch, and every
     item carries the same 47, which is §5.3 satisfied by the component
     rather than by an override.                                           */
  .s-bm1__filters {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--m-gap);
    margin-top: var(--m-gap);
  }
  .s-bm1__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--m-gap-mid);
    border: 3px solid var(--rich-black-3);
    background: transparent;
    color: var(--content-primary);
    text-align: center;
    white-space: nowrap;
    cursor: pointer;
  }
  /* Act — the Rich black 1 plate. "All" carries it on load, which is the
     state the file draws. No Hov variant is built (§9, §15). */
  .s-bm1__btn[aria-pressed="true"] {
    border-color: var(--rich-black-1);
    background: var(--surface-inverse);
    color: var(--content-on-inverse);
  }

  .s-bm1__browse { margin-top: var(--m-gap); text-align: center; }

  /* --- 11 The deck ------------------------------------------------------
     Swipe, with scroll-snap doing the landing. No autoplay and no wrap: the
     track simply ends, as the file's positions do.                        */
  .s-bm1__deck { margin-top: var(--m-gap); }

  .s-bm1__track {
    display: flex;
    gap: var(--m-gutter);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
  }
  .s-bm1__track::-webkit-scrollbar { display: none; }
  /* The display above outranks the user-agent's [hidden] rule, so the empty
     deck states it again. */
  .s-bm1__track[hidden] { display: none; }
  .s-bm1__slide {
    flex: 0 0 100%;
    min-width: 0;
    scroll-snap-align: start;
    scroll-snap-stop: always;
  }

  .s-bm1__stack { display: grid; gap: var(--m-gap-mid); }

  .s-bm1__dots {
    display: flex;
    justify-content: center;
    gap: var(--m-gap-mid);
    margin-top: var(--m-gap-mid);
  }
  .s-bm1__dots i {
    width: var(--m-gap-tight);
    height: var(--m-gap-tight);
    border-radius: 50%;
    background: var(--rich-black-3);
  }
  .s-bm1__dots i.is-on { background: var(--rich-black-1); }

  .s-bm1__empty { text-align: center; }

  /* The filter's spoken answer. Not in the macket and not drawn: a button
     that changes what is on screen has to say so. */
  .s-bm1__status {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

}

/* ===== insights/bm2.css ===== */
/* ==========================================================================
   Insights index mobile — block 2, the newsletter sign-up.
   Figma: "Section 2" 1549:13479, 352 x 267, top 1678.

   Everything on this block sits on the 15 rhythm: lockup, lede, field,
   button, note. The lockup, the plate and the button come from bm1.css.
   ========================================================================== */

@media (max-width: 1023.98px) {

  .s-bm2__lede { margin-top: var(--m-gap-mid); text-align: center; }

  .s-bm2__form { margin-top: var(--m-gap-mid); }

  /* The label is required and not drawn: the macket shows a placeholder
     doing a label's job, which leaves the field unnamed once a value is
     typed into it. */
  .s-bm2__label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* `Form_cards_mobile` Small, 352 x 41 — 15, an 11-tall cap, 15.

     Unlike the contact form's fields, this one sits on the page ground
     rather than inside a plate, so it is drawn as the ground with a 1px
     Rich black 3 edge: the outline the file shows, and no eighth colour.  */
  .s-bm2__input {
    display: block;
    width: 100%;
    height: 41px;
    padding-inline: var(--m-gap-tight);
    border: var(--line-width) solid var(--rich-black-3);
    background: var(--surface-page);
    color: var(--content-primary);
  }
  .s-bm2__input::placeholder { color: var(--vista-blue-1); opacity: 1; }

  /* 12. Keyboard focus is not in the macket and is required all the same:
     a white ground and a 3px Amber stroke, both from the tokens. The offset
     is taken off so the ring sits on the field's own edge. */
  .s-bm2__input:focus-visible {
    background: var(--editorial-white-2);
    outline: 3px solid var(--border-accent);
    outline-offset: 0;
  }

  /* `Button_form_m`, 352 x 61, across the working area. Its nearest
     neighbour is the field, 15 above, so the areas would meet at 15 — but
     both are taller than 44 already and `m-tap` resolves to the button's own
     61 without growing, so nothing overlaps. */
  .s-bm2__submit { margin-top: var(--m-gap-mid); }

  .s-bm2__note { margin-top: var(--m-gap-mid); text-align: center; }

}

/* ===== insights/bm3.css ===== */
/* ==========================================================================
   Insights index mobile — block 3, the three ways to start.
   Figma: "Section 3" 1549:13541, 352 x 763, top 2020.

   Card heights in the file are 202, 183 and 240. All three are 25 of
   padding, a title, 25, an italic line, 25 and a 61-tall button, so the
   three numbers are what the copy comes to and none of them is set here:
   card two's title is one line where card three's is two, and card three's
   line runs to three where card one's runs to two.
   ========================================================================== */

@media (max-width: 1023.98px) {

  .s-bm3__lede { margin-top: var(--m-gap-mid); text-align: center; }

  .s-bm3__cards {
    display: grid;
    gap: var(--m-gap-mid);
    margin-top: var(--m-gap);
  }

  .s-bm3__title { text-align: center; }
  .s-bm3__line  { margin-top: var(--m-gap); text-align: center; }

  /* 5 Touch: the button is 61 tall and never narrower than 142, so `m-tap`
     resolves to its own bounds and adds nothing. The nearest other target is
     the button on the next card, 25 + 50 of padding away, so no two areas
     come near each other. */
  .s-bm3__act { margin-top: var(--m-gap); }

}
