/* ===== 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;
  --header-top:       0px;    /* 2026-10-27, client: no strip above the desktop header (was 50 in the file, then 20) */
  --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;
}

/* 2026-10-15, designer's desktop review of 13 Oct, items 10 and 18: fields
   stay Editorial White 4 #EEEAE3 in every state; focus adds only the 3 px
   Amber 4 #E0A800 outline. The tablet hand-off of 13 Oct: Editorial White 4
   is the only white. So on the desktop layer focus no longer paints a plate
   of pure white (#FFFFFF, --editorial-white-2) — it used to here, and as an
   element-type match it won over every input's own fill. The plate is kept
   below 1280 only, so the tablet and mobile layers, which have no focus
   rule of their own and inherited this one, behave exactly as before; that
   is their brief to change, not this one. A block that sets its own focus
   fill (sections/main/s15.css) still wins on specificity. */
@media (max-width: 1279.98px) {
  :focus-visible {
    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); }

/* 2026-10-27: the designer ships one carousel chevron (Arrow1.svg →
   assets/icon-arrow-prev.svg?v=b0bd3895, pointing left). A next arrow is the same file
   mirrored. */
.u-flip-x    { transform: scaleX(-1); }

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

/* 2026-10-15, designer's desktop review of 13 Oct, item 1 ("no lines").
   The layer was present on all 27 pages at 180 · 360 · … · 1260 of the 1440
   frame and showed on the page ground for 30–85 % of each page's height (the
   rest is opaque section fills, which cover it in the file too — Main 1:3,
   `BackgroundLines` 73:593 sits under `Sections + footer`). What was missing
   is the strip above the header: the header's 50 margin-top collapses
   through `.page`, so `.page` — and the layer with `top: 0` — began at y 50
   and the 0–50 strip had no lines, where the file draws `UpperLines`
   152:1612. The layer now starts at the top of the document. Desktop only:
   the tablet and mobile layers hide this header, so nothing collapses
   there. */
@media (min-width: 1280px) {
  .page > .gridlines { top: calc(-1 * var(--header-top)); }
}
.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;
}

/* 2026-11-02, client: a text link that keeps the colour of the words around
   it, so it reads on the page, on Vista Blue and on Amber plates alike — the
   privacy line under every form (js/forms.js) and "Read the story →" on the
   author cards. Same shape as .u-link-inline: a 1px rule under the words
   that thickens on hover and focus. Not in Figma. */
.u-link-text {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: text-decoration-thickness var(--t-fast);
}
.u-link-text:hover,
.u-link-text:focus-visible {
  text-decoration-thickness: 3px;
}

/* 2026-11-02, client: "Result" on the author cards (business b6/t4/m5,
   wellness w5/t4/m5) was an amber or outlined box that looked like a
   button. It is a label now: the word in Base Up Black Wide, Rich Black 1,
   after a short Amber 4 rule. No plate, no box, not focusable, not a link.
   The span inside carries u-trim (a flex item is a block box). Not in Figma,
   which draws the box. */
.c-result-label {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  color: var(--content-primary);
}
.c-result-label::before {
  content: "";
  flex: 0 0 25px;
  height: 3px;
  background: var(--border-accent);
}
.c-result-more { margin: 0; color: var(--content-primary); }

/* 2026-10-27, client: the counters (js/stats.js). Digits keep one width while
   they count, and the "+" hangs outside the number so the number itself is
   what sits on the centre line (it looked off-centre with the "+" counted). */
.stat-n { font-variant-numeric: tabular-nums; }
.stat-wrap { position: relative; display: inline-block; }
/* 2026-10-27, client: centring the digits alone looked off the other way;
   the group sits between the two — shifted left by about half the "+" so
   the eye reads number and sign as centred. */
.stat-wrap:has(.stat-plus) { left: -0.17em; }
.stat-plus { position: absolute; left: 100%; top: 0; }

/* 2026-11-02, founders: the logo cursor of 2026-10-27 is gone — amber on
   amber buttons, and visitors could not tell what was clickable. The native
   cursor is back; anything clickable shows the pointing hand. */
a, button, [role="button"], label, summary, select,
[data-open-form], .is-tappable { cursor: pointer; }
/* A text field inside a clickable label keeps the text caret. */
input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]),
textarea { cursor: text; }

/* --- Pull quote --------------------------------------------------------
   2026-10-27, client ("make the quote a quote"): the founder's quote on
   Main, About, For business experts and For wellness experts read like a
   heading (Intro Black, all caps, as Figma 998:11862 and its siblings draw
   it). It now speaks the site's own quote language, the one from the case
   pages' "In their own words" band (case.css .s-case-quote__*, caset.css
   .tb-cases-6__*): the amber opening mark in Label Big Black, the words in
   Intro beside it, the attribution under the words. The words are italic,
   as the quotes in Client Voices are (main/s7). The mobile reading of the
   same pattern is in m-base.css (.c-quote--m).

     <figure class="c-quote">
       <p class="c-quote__mark t-label-big-black u-trim" aria-hidden="true">“</p>
       <blockquote class="c-quote__words"><p class="t-intro u-trim">…</p></blockquote>
       <figcaption class="c-quote__by t-base-up-black u-trim">— Name</figcaption>
     </figure>                                                              */
.c-quote {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: var(--layout-gutter);
  row-gap: var(--layout-gutter);
  align-items: start;
  text-align: left;
  /* 2026-10-27, client: more air between the quote and what is around it. */
  margin-block: 30px;
}
.c-quote__mark {
  grid-row: 1 / span 2;
  color: var(--content-accent);
}
.c-quote__words {
  grid-column: 2;
  font-style: italic;
}
.c-quote__by {
  grid-column: 2;
  color: var(--content-secondary);
}

/* 2026-10-27, client: the pull-quote types itself out (js/quote.js). The
   letters are hidden, not removed, so the quote keeps its size from the
   start; the attribution fades in when the last letter is down. */
.c-quote.is-typing .c-quote__ch { opacity: 0; }
.c-quote.is-typing .c-quote__ch.is-on { opacity: 1; }
.c-quote.is-typing .c-quote__by { opacity: 0; transition: opacity 500ms ease; }
.c-quote.is-typing .c-quote__by.is-on { opacity: 1; }

/* ===== 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 strip down; the page's own lines show in that strip. The file
     draws it 50 (one page margin); 20 since 2026-10-27, the client's call
     after the designer's answer that the strip and its lines must stay. */
  margin-top: var(--header-top);
}

/* 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);
}

/* 2026-10-27, desktop review 20 Oct item 14 ("the header does not show which
   section the visitor is on"). Read from every Dekstop frame's Header
   instance: the bar label of the section is Amber 4 (Button_text prop=hov
   colour, 2:385) on the section's own pages AND on its sub-pages —
   Discovery Sprint 504:3358 → Services; Free Resources 521:2838 / 818:6803
   and the three cases → Results; FAQ 521:3179 and Contact 521:3200 → About.
   The exact-page link already gets aria-current from build.py; the sub-pages
   only marked their own link in the (closed) sub-row, so nothing showed in
   the bar. The page's sub-nav group (data-subnav, from pages.json) now marks
   its owner too. The rows stay closed: the client ruled on 08 Oct that the
   header never opens by itself, although the frames draw it open.        */
.site-header[data-subnav="services"] .site-header__link[data-opens="services"],
.site-header[data-subnav="results"]  .site-header__link[data-opens="results"],
.site-header[data-subnav="about"]    .site-header__link[data-opens="about"] {
  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. The plate under the row is the bar's own plate,
   grown by 52 across the full width, with the seven lines carried down
   through it (Figma "Group 75") — see item 12 below, 2026-10-15. Until then
   the plate covered only the group's own columns and the rest was bare.

   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 — REMOVED 2026-10-08 at the client's request. The page used to hold
   its own group's row open (Services, Results, About). The client: the
   header must never open by itself — only under the pointer or the caret,
   which is what the Figma component's open variants (set 504:2789) are.
   The current page is still marked in the bar (aria-current, amber). */

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

/* 2026-10-15, designer's review of 13 Oct, item 12 — the open header is one
   block. The group's own piece of the plate and its own clipped copy of the
   lines used to be drawn here, column by column; the rest of the 52 strip was
   bare and the page scrolled visibly under it. The file draws the open
   variants (Services 966:7456, Results 521:2698, About 521:3038) as one
   1440 x 113 "Rectangle 13" under bar and row together, with all seven lines
   carried down ("Group 75"). So: the bar's plate grows by the row whenever
   any group is open, and one line layer (.site-header__row) runs through
   the row at all seven positions. Only the rule (Line 39) and the links stay
   per group. */
.site-header__plate {
  transition: bottom var(--t-fast) ease;
}

.site-header__row {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: 52px;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-fast) ease, visibility var(--t-fast);
}

.site-header:has(.site-header__link[data-opens]:hover) .site-header__plate,
.site-header:has(.site-header__link[data-opens]:focus-visible) .site-header__plate,
.site-header:has(.site-header__sub:hover) .site-header__plate,
.site-header:has(.site-header__sub:focus-within) .site-header__plate {
  bottom: -52px;
}
.site-header:has(.site-header__link[data-opens]:hover) .site-header__row,
.site-header:has(.site-header__link[data-opens]:focus-visible) .site-header__row,
.site-header:has(.site-header__sub:hover) .site-header__row,
.site-header:has(.site-header__sub:focus-within) .site-header__row {
  opacity: 1;
  visibility: visible;
}

/* 2026-11-11 — touch. Client: «на планшеті у горизонтальному вʼю не
   відкриваються підменю у хедері». A tablet in landscape (1024 and up) gets
   this layer, and js/touch-hover.js turns every :hover rule off after a
   touch, so nothing above could open the rows by finger. js/header-touch.js
   marks the tapped group on the header (data-touch-open; first tap opens,
   second tap on the same label follows its link, a touch outside closes).
   Drawn exactly like the hovered state: the group's row, the plate grown by
   52, the line layer, the label in amber. Placed after the rules above on
   purpose: same weight (0,4,0), so the later rule wins over step 2. */
.site-header[data-touch-open="services"] .site-header__sub[data-group="services"],
.site-header[data-touch-open="results"]  .site-header__sub[data-group="results"],
.site-header[data-touch-open="about"]    .site-header__sub[data-group="about"],
.site-header[data-touch-open] .site-header__row {
  opacity: 1;
  visibility: visible;
}
.site-header[data-touch-open] .site-header__plate {
  bottom: -52px;
}
.site-header[data-touch-open="services"] .site-header__link[data-opens="services"],
.site-header[data-touch-open="results"]  .site-header__link[data-opens="results"],
.site-header[data-touch-open="about"]    .site-header__link[data-opens="about"] {
  color: var(--content-accent);
}

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

.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;
}

/* 2026-10-15, designer's desktop review of 13 Oct, item 11: "after the
   Discovery Sprint link the rule follows at once; 50 between them, as in
   the macket" (footer 152:1464 — last Services link ends at 289, rule at
   339). The links carry `.u-trim` but are inline <a>, and text-box-trim does
   nothing on an inline box (CLAUDE.md trap), so each link kept its 19 px
   line box instead of its 11 px cap height: six of them pushed the column
   48 px down and left 2 px above the rule. Blockified, the trim applies and
   the column ends at 289 again. Same for the legal row, which made the
   footer 423 tall instead of 415. */
.site-footer__list a,
.site-footer__legal a {
  display: block;
}

/* --- 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);
}

/* 2026-10-15, designer's desktop review of 13 Oct, item 2 (and item 3 of the
   28 Sep review): "at the top, directly under the header, as in the macket;
   it should read as a bookmark". Main 1:3 draws `Button_form` 657:4066 at
   x 50 of the frame, 61 x 72, its top 52 below the header's foot (header
   50–111, button 163–235). The 52 is exactly the open sub-navigation row,
   so the bookmark hangs from the header and an open row never covers it.
   With the header pinned its foot is at 61, so the top is 61 + 52 = 113.
   Same x rule as the header's logo: 50 from the 1440 frame, not from the
   window. The tablet layer did the same on 14 Oct (css/t-header.css).
   Supersedes the move to the window's foot recorded above. Desktop only:
   the mobile layer restyles this element and stays as it is. */
@media (min-width: 1280px) {
  .site-up {
    left: calc(max(0px, (100% - var(--layout-reference)) / 2) + var(--layout-margin));
    top: calc(var(--header-height) + 52px);
    bottom: auto;
    width: 61px;
    height: 72px;
    padding: 0;
  }
}

/* 2026-10-27, designer's answer to our question "кнопка UP" (Q&A of 20 Oct):
   the bookmark stays where it is; "on hover over yellow it changes its
   colour to white (EEEAE3) where possible". The Button_form hov variant
   empties the fill, which over an Amber 4 band (TrustLine, the yellow form
   blocks) leaves an amber ring on amber — the button disappears. So on
   desktop the hovered and keyboard-focused button is filled Editorial
   White 4; the 3 px amber ring stays. On the page ground (also Editorial
   White 4) this looks exactly like the old empty fill, so only the case
   over yellow changes. Mouse only for hover, as the brief asks; the tablet
   press state lives in css/t-header.css and is not changed here. */
@media (min-width: 1280px) and (hover: hover) and (pointer: fine) {
  .site-up:hover {
    background: var(--editorial-white-4);
  }
}
@media (min-width: 1280px) {
  .site-up:focus-visible {
    background: var(--editorial-white-4);
  }
}

/* 2026-10-27, designer's answer (UP over yellow): where the button sits on
   an Amber 4 surface it turns Editorial White 4 by itself, the amber ring
   kept — js/up.js sets [data-on-amber]. Desktop and tablet only. */
@media (min-width: 768px) {
  .site-up.site-up[data-on-amber] {
    background: var(--editorial-white-4);
    box-shadow: inset 0 0 0 3px var(--action-border-hover);
  }
}

/* 2026-11-04, client («давай» to the UP fixes): while a call to action lies under it, the button steps aside
   (js/up.js sets [data-over-control]) and the tap reaches the page. */
.site-up.site-up[data-shown][data-over-control] {
  opacity: 0;
  pointer-events: none;
}

/* ===== 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: 767.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__panel { padding-top: 15px; }
  .consent__panel .consent__btn { width: 100%; }
}

/* 2026-11-04 (live from main, merged into dev) — Tetiana Lipatova's cookie edits, Marketing
   thread of 02.11, her reply of 03.11 20:00, and the web-pages playbook rule
   «consent banner on mobile: a strip, not a wall» (under 15% of the viewport;
   the hero headline stays visible). Overrides the 2026-10-08 phone layout.
   - The three buttons look the same at every width: same size, colour, type
     and contrast (before: Accept filled, Reject outlined, Settings a text link).
   - Phone: the banner is a strip of at most 90 px when closed — one sentence,
     the title kept for screen readers only, three equal buttons of 34 px.
     Each button's touch area still reaches 44 px tall through ::after
     (CONTRACT_MOBILE §5: invisible area, nothing visible moves). */
.consent__actions .consent__btn { background: transparent; }
.consent__actions .consent__btn:hover { background: var(--action-fill); }

@media (max-width: 767.98px) {
  .consent__inner {
    row-gap: 5px;
    padding: 6px 15px calc(6px + env(safe-area-inset-bottom));
  }
  .consent__copy { gap: 0; }
  .consent__title {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .consent__text { font-size: 13px; line-height: 1.3; }
  .consent__actions { gap: 8px; }
  .consent__actions .consent__btn {
    position: relative;
    flex: 1 1 0;
    min-height: 34px;
    padding: 0 6px;
    border-width: 2px;
    font-size: 13px;
  }
  .consent__actions .consent__btn::after {
    content: "";
    position: absolute;
    left: 0; right: 0;
    top: -5px; bottom: -6px;
  }
  .consent__panel { padding-top: 10px; gap: 10px; }
  .consent__panel .consent__text,
  .consent__panel .t-base { font-size: 13px; }
}

/* ===== call-popup.css ===== */
/* "Book a call" popup (2026-10-27, client request; partials/call-popup.html,
   js/call-popup.js). Not in the Figma file: built from the site's tokens.
   The widget brings its own styles (assets/booking/booking.css, loaded on the
   first open); this file is only the dialog shell, so every page stays light.

   Stacking: the dialog is opened with showModal(), so it sits in the browser's
   top layer, above every z-index on the page, including the `.page > *` pin
   in base.css (0,4,0) and the consent banner (30). The dialog lives in <body>,
   outside .page, so that pin never applies to it. Where showModal() is missing
   the script opens it as a plain fixed box (.is-fallback) at z-index 40:
   above the consent banner and the menus (20), and the same weight the
   Greenlight page gives its own modal.

   The dialog fills the window and scrolls by itself; the box is centred in
   it. A click on the dialog outside the box is a click on the backdrop. */
.call-popup {
  position: fixed;
  inset: 0;
  z-index: 40;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 32px 16px;
  border: 0;
  background: transparent;
  color: var(--content-primary);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.call-popup:not([open]) { display: none; }
.call-popup[open] {
  display: flex;
  align-items: flex-start;
  justify-content: center;
}
.call-popup::backdrop { background: rgb(11 20 36 / 0.72); }   /* Rich Black 1 at 72 %, as on the Greenlight modal */
.call-popup.is-fallback { background: rgb(11 20 36 / 0.72); }

.call-popup__box {
  position: relative;
  width: 100%;
  max-width: 820px;          /* the widget's own max width (booking.css .avl) */
  margin: auto 0;
  padding: 64px 56px 44px;
  background: var(--surface-page);   /* Editorial White 4 */
  color: var(--content-primary);     /* Rich Black 1 */
  border: 1px solid var(--border-hairline);
}

/* Close: the site's amber square button (Base Up Black buttons, css/base.css
   action tokens): amber fill and a 3 px amber frame; on hover the fill goes
   and the frame stays. The cross is two 20 × 2 bars, as in the menus. */
.call-popup__close {
  position: absolute;
  top: 0;
  right: 0;
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 3px solid var(--action-fill);
  background: var(--action-fill);
  color: var(--content-on-accent);
  cursor: pointer;
  transition: background 0.15s;
}
.call-popup__close:hover { background: var(--action-fill-hover); }
.call-popup__close:focus-visible { outline: 2px solid var(--content-primary); outline-offset: 2px; }
.call-popup__close span { position: relative; display: block; width: 20px; height: 20px; }
.call-popup__close span::before,
.call-popup__close span::after {
  content: "";
  position: absolute;
  left: 0;
  top: 9px;
  width: 20px;
  height: 2px;
  background: currentColor;
}
.call-popup__close span::before { transform: rotate(45deg); }
.call-popup__close span::after  { transform: rotate(-45deg); }

.call-popup__loading { margin: 0; color: var(--content-secondary); }

/* 2026-11-02, form audit: the required-field stars and the «* Required fields»
   line that /call (sections/call/k1.css) and the product pages carry since
   27–29 Oct. The dialog holds the same widget on every other page and had
   neither. Rules copied from k1.css; the shared widget is untouched. */
.call-popup #avl-booking .avl-field:has(input[required]) > span::after,
.call-popup #avl-booking .avl-fieldset legend::after { content: " *"; color: #9B1C1C; font-weight: 1000; }
.call-popup #avl-booking[data-step="contacts"] .avl-who::after { content: "* Required fields"; display: block; margin-top: 8px; font-size: 13px; color: rgba(11, 20, 36, .72); }

/* The page under the dialog does not scroll. A classic scrollbar's width is
   kept as padding so nothing shifts (the same pair as the tablet menu). */
html.is-call-popup-open {
  overflow: hidden;
  padding-right: var(--call-sbw, 0px);
}

/* Phone width: the dialog is the whole screen. */
@media (max-width: 767.98px) {
  .call-popup { padding: 0; }
  .call-popup__box {
    max-width: none;
    min-height: 100%;
    margin: 0;
    padding: 64px 16px 32px;
    border: 0;
  }
}

/* ===== forms.css ===== */
/* ==========================================================================
   Form fields — required star, "* Required fields" line, inline errors
   (2026-11-02, pre-release form audit). Behaviour in js/forms.js. Not in the
   Figma file: the macket's forms have one status line and no field errors.

   The star and its colour are the product pages' (products/authority,
   sections/call/k1.css: " *" in #9B1C1C, the booking widget's --avl-err),
   so every form on the site marks required fields the same way.

   Most of the site's forms sit on Vista Blue 1 (#7C9EC7). That red on it is
   3.0 : 1 — enough for the star and a rule (non-text, 3 : 1), not for 15 px
   words (4.5 : 1). So the note and the messages are Rich Black 1 (6.8 : 1),
   and the red marks a message as an error with a 3 px rule at its left, the
   booking widget's own error mark (assets/booking/booking.css, .avl-err).
   ========================================================================== */

:root { --form-error: #9B1C1C; }

.f-req::after {
  content: " *";
  color: var(--form-error);
  font-weight: 1000;
}

/* "* Required fields": the form's last line (2026-11-03, client: «"*" і
   пояснення вниз»; js/forms.js arrange). A footnote, so it takes the privacy
   line's size and its distance: 15 from the line above, the form's own gap
   taken off (--f-gap). In a grid it spans every column. */
.f-note {
  display: block;
  grid-column: 1 / -1;
  align-self: stretch;
  margin: calc(15px - var(--f-gap, 0px)) 0 0;
  font-size: 13px;
  line-height: 1.4;
  text-align: left;
  color: var(--content-primary);
}

/* Desktop: the status and privacy lines in the button's row, right of the
   button (2026-11-03, client: «текст під кнопкою винести праворуч від кнопки
   в ряд»). The row centres them on the button's height; on Contact and FAQ
   WhatsApp keeps the right end. The selectors carry form[data-ave-form] so
   they outrank each block's own margins for its status line. */
form[data-ave-form] .f-row {
  display: flex;
  align-items: center;
  gap: var(--layout-gutter);
}
form[data-ave-form] .f-side {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
form[data-ave-form] .f-side > [role="status"] {
  margin: 0;
}

/* Tablet, the same row: the button takes its label's width instead of the
   form's, and the reply line reads as on the desktop (Base Up). */
.is-t form[data-ave-form] .f-row {
  flex-direction: row;
}
.is-t form[data-ave-form] .f-row > [type="submit"] {
  flex: 0 0 auto;
  width: auto;
  padding-left: 25px;
  padding-right: 25px;
}
.is-t form[data-ave-form] .f-side > :not(.f-privacy) {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: flex-start;
  gap: 8px var(--layout-gutter);
  margin: 0;
  padding: 0;
}
.is-t form[data-ave-form] .f-side .t-base:not(.f-privacy) {
  text-transform: uppercase;
}
.is-t form[data-ave-form] [data-f-prompt]:not([data-f-prompt-on]) {
  display: none;
}
.is-t form[data-ave-form] .f-lead {
  display: contents;
}

.f-error {
  display: block;
  margin-top: 8px;
  padding-left: 8px;
  border-left: 3px solid var(--form-error);
  color: var(--content-primary);
  font-weight: 1000;
  line-height: 1.3;
}
/* After the button of a one-row form (js/forms.js): a row of its own. */
.f-error--row {
  flex: 1 0 100%;
  grid-column: 1 / -1;
  margin-top: 0;
}

/* The privacy line under every form (2026-11-02, client; js/forms.js). Not
   in Figma. Small type, the colour of the form's own words: Rich Black 1 on
   the Vista Blue and Amber plates and on the light page, which is what the
   forms already set. The link is .u-link-text (css/base.css). In a flex or
   grid form it takes a row of its own across every column.

   One distance on every form: 15 from the line above it
   (--f-privacy-space; a block may set its own, as the guides do for
   Figma's 25). The form's own row gap would add to the margin, so
   js/forms.js writes that gap into --f-gap and the margin takes it off. */
.f-privacy {
  display: block;
  flex: 0 0 auto;
  grid-column: 1 / -1;
  align-self: stretch;
  width: 100%;
  max-width: 100%;
  margin: calc(var(--f-privacy-space, 15px) - var(--f-gap, 0px)) 0 0;
  font-size: 13px;
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0;
  text-transform: none;
  text-align: left;
  color: inherit;
}

/* iOS Safari zooms the page into any field set under 16 px when it takes
   focus, and does not zoom back. The site's field type is 15 px (t-base), so
   fields are 16 px wherever a phone or tablet can show them: the tablet and
   mobile layers, and any touch screen. On the mobile layer a single-line
   field is also brought to the 44 px touch target (CONTRACT_MOBILE.md). */
@media (max-width: 1279.98px), (hover: none) and (pointer: coarse) {
  input:not([type="radio"]):not([type="checkbox"]):not([type="hidden"]),
  textarea:not([hidden]) {   /* the :not()s outweigh the 15 px type classes */
    font-size: 16px;
  }
}
@media (max-width: 767.98px) {
  form[data-ave-form] input:not([type="radio"]):not([type="checkbox"]):not([type="hidden"]) {
    min-height: 44px;
  }
}

/* 2026-11-04, client (phone review): «поле Your Idea … зробити fixed, і коли людина вводить більше
   тексту, просто додавати скрол». Every lead form's text area keeps its
   drawn size; longer text scrolls inside it. */
form[data-ave-form] textarea {
  resize: none;
  overflow-y: auto;
}

/* 2026-11-04, client (tablet photos): «відступ між першим, другим та третім
   блоком велика». Every tablet lead form: Name | Email, Your idea and the
   button row stand 25 apart (the idea field was 50 under the email row). */
@media (min-width: 768px) and (max-width: 1279.98px) {
  .is-t form[data-ave-form] .tb-form__fields { row-gap: var(--t-gap); }
  .is-t form[data-ave-form] [class*="__field"]:not(.tb-form__field):has(> textarea) { margin-top: var(--t-gap); }   /* the grid forms (Contact, FAQ) space it by row-gap */
}

/* ===== insights/article.css ===== */
/* ==========================================================================
   Insights — the article template.
   Figma screens Blog_A1 407:1454 · Blog_A2 422:3560 · Blog_A3 424:4027 ·
   Blog_A4 428:4460 · Blog_A5 438:1934 · Blog_A6 438:2574.

   The six screens are the same five blocks in the same order, at the same
   widths, with the same rhythm. They differ only in what the body says, how
   many "Title + text" blocks it takes to say it, which photograph the hero
   carries and which two articles the related cards point at. So this file
   carries the whole layout and has no fragment of its own; each page lists
   it in `pages.json` beside its own `aN` and the shared `tail`.

     hero    Section 1       1440 x 1154–1284   --gap 150 (under the header)
     body    the Title+text  885 wide, tables    --gap  50
             column          1340 wide
     author  Author Card +   1390 [bleed:left]  --gap 150
             Related Articles
     sprint  Section 8       1440 [bleed:both]  --gap 150
     cta     CTA_Section      885 wide          --gap 150
                                                footer gap 100

   Inside the body every block is 50 from the next, which is the same 50 the
   body block sits below the hero; inside a block the rows are 25 apart.
   ========================================================================== */

/* --- Shared: Button_form ------------------------------------------------
   The amber plate with a 25 pad on all four sides. Its stroke is the same
   colour as the fill at rest, so emptying the fill on hover leaves the box
   exactly the size it was.                                                 */
.s-article .s-article__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--layout-gutter);
  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-article .s-article__cta-label {
  white-space: nowrap;
}

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

/* ==========================================================================
   1 — Hero.  Section 1, e.g. 411:1578 on Blog_A1.
   Flex column, 50 between the three rows: the 1340 head, the full-width
   photograph, and the 1112 lede.
   ========================================================================== */

.s-article--hero .s-article__hero {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 50px;
}/* Frame 85: the whole working area, four rows 25 apart. */
.s-article--hero .s-article__head {
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
}

.s-article--hero .s-article__meta {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--layout-gutter);
}

.s-article--hero .s-article__stamp {
  display: flex;
  align-items: center;
  gap: var(--layout-gutter);
  white-space: nowrap;
}

/* --- The photograph -----------------------------------------------------
   Intent tag: bleed:both — 1440 x 780 at the reference, running to both
   window edges. The export already carries the crop and, on Blog_A1, the
   mirroring the file applies on the canvas, so no transform is repeated
   here.                                                                    */
/* 2026-11-02, client ("as if we were advertising the photo"): the picture
   was 1440 x 780 and filled the first screen. It is an illustration now:
   still bleed:both (the "In this article" plate hangs on the window's left
   edge over it), but 500 tall at 1440 — 440 at 1280, 560 at most — so the
   title, the meta line and the top of the picture share the first screen.
   The export keeps its 1440 x 780; the box crops it, holding the upper
   middle, where the faces and the books are. */
.s-article--hero .s-article__media {
  position: relative;
  margin-block: 0;
  height: clamp(440px, 34.7222vw, 560px);   /* 500 / 1440 */
}

/* The direct child only: the table of contents lies inside this figure and
   carries an arrow of its own that must keep its own size. */
.s-article--hero .s-article__media > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 35%;
}

/* --- SideBar, e.g. 1022:8037 --------------------------------------------
   "In this article": Rich Black 3, 594 wide, pinned to the window's left
   edge and to the top of the photograph (macket y 567 on every screen, which
   is exactly where the picture starts). 50 of padding, 25 on the right; the
   arrow column is 11 wide with the caption turned a quarter turn beside it. */
.s-article--hero .s-article__toc {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 1;
  display: flex;
  gap: var(--layout-gutter);
  width: 594px;
  max-width: 100%;
  padding: 50px 25px 50px 50px;
  background: var(--rich-black-3);
  color: var(--content-primary);
}

.s-article--hero .s-article__toc-rail {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 26px;
  flex: 0 0 13px;
}

/* 2026-10-15, review 13 Oct item 21: "In this article" starts collapsed and
   opens on click. SideBar set 1014:12551 has the two states: Pas 1014:12550
   is 86 x 302 — 50 of padding, the 11-wide rail with the arrow pointing
   right, 25 — and Act 1014:12549 is the open 594 plate the build already
   drew (the macket shows Act on every article only as an example). The
   rail is the toggle button; article.js flips aria-expanded and the
   styles read it, so the picture and the state cannot drift apart.       */
.s-article--hero .s-article__toc-rail {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
}
.s-article--hero .s-article__toc-rail img {
  transition: transform var(--t-fast) ease;
}
.s-article--hero .s-article__toc:has(.s-article__toc-rail[aria-expanded="false"]) {
  width: auto;
}
.s-article--hero .s-article__toc-rail[aria-expanded="false"] img {
  transform: rotate(180deg);   /* Pas: the same chevron, pointing right */
}
.s-article--hero .s-article__toc-rail[aria-expanded="false"] + .s-article__toc-list {
  display: none;
}
/* 2026-10-27, desktop review 20 Oct item 4: the plate stays fixed while the
   article scrolls (article.js sets is-pinned, --toc-top and --toc-max). Same
   x as at rest: the figure is bleed:both, so its left edge is the window's.
   If the window is shorter than the open list, the plate scrolls inside.   */
.s-article--hero .s-article__toc.is-pinned {
  position: fixed;
  top: var(--toc-top, 0px);
  left: 0;
  z-index: 9;                     /* under the header's 10 and UP's 11 */
  max-height: var(--toc-max, none);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.s-article--hero .s-article__toc-caption {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  white-space: nowrap;
}

.s-article--hero .s-article__toc-list {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
}

.s-article--hero .s-article__toc-list a {
  display: block;
  transition: color var(--t-fast) ease;
}

.s-article--hero .s-article__toc-list a:hover,
.s-article--hero .s-article__toc-list a:focus-visible {
  color: var(--content-accent);
}

/* The lede: 1112 of the 1340, centred — columns 2 to 11. */
.s-article--hero .s-article__lede {
  width: 82.9851%;
  margin-inline: auto;
  color: var(--content-primary);
}

/* ==========================================================================
   2 — Body.  The "Title + text" column, 885 wide and centred in the working
   area, with the comparison tables running the full 1340.
   ========================================================================== */

.s-article--body .s-article__body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 50px;
  color: var(--content-primary);
}

.s-article--body .s-article__block {
  width: 66.0448%;            /* 885 / 1340 */
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
}

.s-article--body .s-article__text {
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
}

/* Bulleted runs. Figma holds each list as one text node with a disc marker;
   the marker sits 22.5 in, which is 1.5 of the 15px type. */
.s-article--body .s-article__list {
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
  padding-left: 22.5px;
  list-style: disc;
}

.s-article--body .s-article__list li {
  list-style: disc;
}

/* 2026-10-27, Insights articles pass (H2): a numbered list in the client's
   copy (articles 18, 20, 21). Same list, decimal markers; not in Figma. */
.s-article--body .s-article__list--num li {
  list-style: decimal;
}

/* Links in the running text: Vista Blue 1, and the weight comes from the
   type class on the anchor itself. */
.s-article--body .s-article__link {
  color: var(--vista-blue-1);
  text-underline-offset: 3px;
}

.s-article--body .s-article__link:hover,
.s-article--body .s-article__link:focus-visible {
  text-decoration: underline;
}

/* The button that closes the article sits on its own, centred, and keeps the
   same 50 above and below it as every other row of the column. */
.s-article--body .s-article__act {
  display: flex;
  justify-content: center;
}

/* --- Table 2c / 3c / 4c -------------------------------------------------
   The whole working area. Cells are 3px Vista Blue 1 with 25 of padding and
   the strokes collapse, exactly as the file overlaps its rows and cells by
   3. The head row takes the Vista Blue plate.                              */
.s-article--body .s-article__table-wrap {
  width: 100%;
}

.s-article--body .s-article__table {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

/* The file gives the tables no caption; one is written here for the screen
   reader and taken out of the picture. */
.s-article--body .s-article__table-caption {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Column widths are the file's own: Table 4c is four even 335 cells,
   Table 2c is 666 + 677, Table 3c is 250 + 545 + 545 of the 1340. */
.s-article--body .s-article__table--c2 th:first-child  { width: 49.7015%; }
.s-article--body .s-article__table--c3 th:first-child  { width: 18.6567%; }
.s-article--body .s-article__table--c3 th + td,
.s-article--body .s-article__table--c3 td + td         { width: 40.6716%; }
.s-article--body .s-article__table--c3 thead th + th   { width: 40.6716%; }
.s-article--body .s-article__table--c4 th:first-child  { width: 25%; }

.s-article--body .s-article__table th,
.s-article--body .s-article__table td {
  padding: var(--layout-gutter);
  border: 3px solid var(--vista-blue-1);
  text-align: left;
  vertical-align: top;
}

.s-article--body .s-article__table thead th {
  background: var(--surface-brand);
}

/* ==========================================================================
   3 — Author card and related articles.  e.g. 1038:8655.
   Intent tag: bleed:left. The block runs off the LEFT window edge and its
   right edge is the right edge of the working area, so --bleed-stop is 0.
   ========================================================================== */

.s-article--author .s-article__author {
  --bleed-stop: 0%;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--layout-gutter);
}

/* 707 + 26 + 316 + 25 + 316 = 1390. The 26 is what the file has between the
   card and the first related article; every other gap here is the gutter. */
.s-article--author .s-article__author-row {
  display: flex;
  align-items: center;
  gap: 26px;
  width: 100%;
}

.s-article--author .s-article__author-card {
  flex: 0 0 50.8633%;        /* 707 / 1390 */
  min-width: 0;
  display: flex;
  align-items: center;
  height: 303px;
  padding: 50px 25px 50px 50px;
  background: var(--surface-brand);
  color: var(--content-on-brand);
}

.s-article--author .s-article__author-in {
  display: flex;
  align-items: center;
  gap: var(--layout-gutter);
  width: 100%;
}

.s-article--author .s-article__author-mark {
  flex: 1 1 auto;
  min-width: 0;
  height: 203px;
  object-fit: cover;
}

.s-article--author .s-article__author-col {
  flex: 0 0 63.9241%;        /* 404 / 632 */
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 38px;
}

.s-article--author .s-article__author-text {
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
  width: 100%;
}

/* --- Blog_Card_S1, the outlined variant ---------------------------------
   No fill and a 3px Rich Black 1 stroke, no number, the title on the foot of
   the square. Hover lays the Amber plate under it, which is the only move
   the set makes when a card has no photograph of its own.                  */
.s-article--author .s-article__related {
  display: flex;
  align-items: center;
  gap: var(--layout-gutter);
  flex: 0 0 auto;
}

/* 2026-10-15, review 13 Oct item 22: hover filled the card with Amber; it
   now lays the related article's own photograph over the card, the Hov
   move of Blog_Card_S1 (371:2035) exactly as the Insights grid does it —
   the picture at 25 % under the title (insights/s1.css). The photograph is
   that article's card picture from the grid. Only a card that links to an
   article gets the state: the cards on Blog_A3, A5 and A6 name articles
   that are not built, have no picture and go nowhere, so they stay flat.
   The title is in flow (pushed to the foot, 25 in) instead of absolutely
   placed, so the link's ::after covers the whole square, not the title.  */
.s-article--author .s-article__related-card {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  width: 316px;
  height: 303px;
  padding: 25px;
  border: 3px solid var(--border-strong);
  color: var(--content-primary);
}

.s-article--author .s-article__related-photo {
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity var(--t-base) ease;
}

.s-article--author .s-article__related-card:hover .s-article__related-photo,
.s-article--author .s-article__related-card:focus-within .s-article__related-photo {
  opacity: 0.25;
}

.s-article--author .s-article__related-title a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.s-article--author .s-article__related-label {
  width: 100%;
  text-align: right;
}

/* ==========================================================================
   4 — Section 8, the Discovery Sprint band.  e.g. 1038:8691.
   Intent tag: bleed:both. The amber band runs off the left window edge and
   the photograph off the right, so the box is the working area and the two
   fills reach past it. Horizontal measures are shares of the 1340 working
   area; the vertical offsets are tied to type and stay in pixels.
   812 = 485 (down to the panel) + 327 (the panel and its button).
   ========================================================================== */

.s-article--sprint .s-article__sprint {
  position: relative;
  min-height: 812px;
}

/* Macket 0..935 x 0..225: from the window edge to x 935, i.e. 885 of the
   working area. */
.s-article--sprint .s-article__band {
  position: absolute;
  top: 0;
  height: 225px;
  left: calc(50% - 50vw);
  right: 33.9552%;           /* 1 - 885 / 1340 */
  background: var(--amber-4);
  z-index: 0;
}

/* Macket 253..1188 x 50..576.  The rectangle in the file is stretched to
   1187 wide, but its image fill still ends at x 1188 — the render shows bare
   page from there to the window edge — so the picture keeps the same 935 it
   has on the homepage and only the amber band below reaches past a margin. */
.s-article--sprint .s-article__sprint-media {
  position: absolute;
  top: 50px;
  height: 526px;
  left: 15.1493%;            /* 203 / 1340 */
  width: 69.7761%;           /* 935 / 1340 */
  margin: 0;
  z-index: 1;
}

.s-article--sprint .s-article__sprint-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: left bottom;
}

/* The band carried across the photograph at half strength — in the file the
   same rectangle masked by the picture. The intersection is x 253..935 and
   y 50..225 in macket coordinates. */
.s-article--sprint .s-article__tint {
  position: absolute;
  top: 50px;
  height: 175px;
  left: 15.1493%;
  right: 33.9552%;
  background: var(--amber-4);
  opacity: 0.5;
  z-index: 2;
}

/* "DISCOVERY" over "SPRINT", centred on the working area's axis. */
.s-article--sprint .s-article__lockup {
  position: absolute;
  top: 300px;
  left: 50%;
  width: 49.1045%;           /* 658 / 1340 */
  transform: translateX(-50%);
  display: grid;
  text-align: center;
  z-index: 3;
}

.s-article--sprint .s-article__lockup > * {
  grid-area: 1 / 1;
}

.s-article--sprint .s-article__script {
  z-index: 1;
  color: var(--content-on-inverse);
}

.s-article--sprint .s-article__word {
  margin-top: 50px;
  color: var(--content-accent);
}

/* Panel and button, macket 505..935 from y 485. */
.s-article--sprint .s-article__panel-col {
  position: relative;
  z-index: 4;
  margin-left: 33.9552%;     /* 455 / 1340 */
  width: 32.0896%;           /* 430 / 1340 */
  padding-top: 485px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--layout-gutter);
}

.s-article--sprint .s-article__panel {
  width: 100%;
  padding: 50px 25px;   /* 2026-10-27, client: equal 50 top and bottom (was 25 / 50), as the home panel */
  background: var(--surface-brand);
}

.s-article--sprint .s-article__panel-in {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--layout-gutter);
  text-align: center;
  color: var(--content-on-brand);
}

.s-article--sprint .s-article__panel-in > * {
  width: 88.3721%;           /* 380 / 430 */
}

/* ==========================================================================
   5 — CTA_Section.  e.g. 1038:8916, 885 wide and centred, 100 between the
   card block and the form block.
   ========================================================================== */

.s-article--cta .s-article__tail {
  width: 66.0448%;           /* 885 / 1340 */
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: 100px;
}
/* 2026-11-02: the ask and its form left this block for contact/c2. */

.s-article--cta .s-article__ways {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 50px;
}

.s-article--cta .s-article__intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--layout-gutter);
  width: 100%;
  max-width: 753px;
  text-align: center;
}

.s-article--cta .s-article__title {
  display: grid;
  width: 100%;
  font: inherit;
}

.s-article--cta .s-article__title > * {
  grid-area: 1 / 1;
  width: 100%;
}

.s-article--cta .s-article__title-main {
  margin-top: 50px;
}

.s-article--cta .s-article__title-accent {
  color: var(--content-accent);
}

.s-article--cta .s-article__subheading {
  width: 100%;
  max-width: 480px;
}

/* Two Blog_CTA_Card of 430 x 550 with the gutter between them: 885.
   2026-11-02, client: three cards (the message way is back), so the card
   row runs the full working area, 3 x 430 + 2 x 25 = 1340, as on the
   Insights index and the home page; the heading above stays 753. */
.s-article--cta .s-article__ways {
  width: 151.4124%;                       /* 1340 / 885 */
  margin-inline: -25.7062%;               /* (885 - 1340) / 2 / 885 */
}
.s-article--cta .s-article__cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--layout-gutter);
  width: 100%;
}

.s-article--cta .s-article__card {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 550px;
  background: var(--rich-black-3);
  transition: background-color var(--t-base) ease;
}

.s-article--cta .s-article__card:hover,
.s-article--cta .s-article__card:focus-within {
  background: var(--amber-4);
}

.s-article--cta .s-article__card-panel {
  flex: 0 0 auto;
  min-height: 229px;
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
  padding: 50px 25px 25px;
  color: var(--content-primary);
}

.s-article--cta .s-article__card-photo {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

.s-article--cta .s-article__card-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.s-article--cta .s-article__card-button {
  position: absolute;
  right: 25px;
  bottom: 25px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--layout-gutter);
  background: var(--action-fill);
  color: var(--content-on-accent);
  transition: background-color var(--t-fast) ease, box-shadow var(--t-fast) ease;
}

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

/* 2026-10-27, client ("far too much space"): the article opens 69 under the
   header like the home page, not 150 — set on each article's hero section
   (style="--gap: 69px"). */

/* ===== contact/c2.css ===== */
/* ==========================================================================
   Contact — block 2, "Your idea in two sentences"
   Figma: node 681:3903 "Section 2", 1340 x 661 — the whole working area,
   split six and six: the text column 658 at x 0, the form 657 at x 683.
   Form component: FAQ_S7_Form, instance 681:3913 — the SAME component the
   FAQ screen's block 7 uses, same 657 x 661, same WhatsApp button, same
   "Type your message" placeholder. The rules below are f7.css's, renamed;
   see the report, this form is now on three screens.

   148 heading group + 25 + 49 lede = 222 in the left column.
   50 + 506 + 44 + 11 + 50 = 661 in the form.
   ========================================================================== */

.s-c2 .s-c2__intro {
  grid-column: 1 / span 6;
  align-self: start;
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
}
.s-c2 .s-c2__form {
  grid-column: 7 / span 6;
}

/* The Comforter word lies over the Mulish heading in one grid cell. The
   heading sits 50 down inside the group; the accent starts at 0. Here the
   Mulish line is TWO lines, so the group is 148 tall, not 85.             */
.s-c2 .s-c2__title {
  display: grid;
  width: 100%;
  max-width: 569px;
  font: inherit;
}
.s-c2 .s-c2__title > * {
  grid-area: 1 / 1;
  width: 100%;
}
.s-c2 .s-c2__title-main {
  margin-top: 50px;
}
.s-c2 .s-c2__title-accent {
  color: var(--amber-4);
}

/* --- Form ---------------------------------------------------------------
   50 + 420 fields + 25 + 61 buttons + 44 + 11 status + 50 = 661.          */
.s-c2 .s-c2__form {
  display: flex;
  flex-direction: column;
  padding: 50px 25px;
  background: var(--vista-blue-1);
}
.s-c2 .s-c2__body {
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
}
.s-c2 .s-c2__fields {
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
}
.s-c2 .s-c2__field {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.s-c2 .s-c2__label {
  color: var(--content-on-brand);
}

/* --- Plates -------------------------------------------------------------
   Main_S14_Form_text_card: Editorial White 4 plate, no border at rest,
   15 of padding all round — 15 + cap height 11 + 15 = 41 for a one-liner. */
.s-c2 .s-c2__plate {
  width: 100%;
  border: 0;
  background: var(--editorial-white-4);
  color: var(--content-primary);
}
.s-c2 .s-c2__input {
  height: 41px;
  padding: 0 15px;
}
.s-c2 .s-c2__textarea {
  height: 225px;
  padding: 15px;
  resize: vertical;
}
.s-c2 .s-c2__plate::placeholder {
  color: var(--vista-blue-1);
  opacity: 1;
}
/* The Act variants draw the focus stroke on the plate edge rather than 2
   outside it, so the offset base.css sets site wide is dropped here.      */
.s-c2 .s-c2__plate:focus-visible {
  outline-offset: 0;
  background-color: var(--editorial-white-4);  /* 2026-10-15: review items 10/18 — no white plate on focus */
}

/* --- The two buttons ----------------------------------------------------
   The row is 607 wide with the pair pushed to its ends, which is how
   FAQ_S7_Form draws it. This is the one thing Main's form does not have.  */
.s-c2 .s-c2__actions-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--layout-gutter);
}
.s-c2 .s-c2__submit,
.s-c2 .s-c2__whatsapp {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 25px;
  border: 0;
  cursor: pointer;
  transition: background-color var(--t-fast) ease, box-shadow var(--t-fast) ease;
}
.s-c2 .s-c2__submit {
  background: var(--action-fill);
  color: var(--content-on-accent);
}
.s-c2 .s-c2__whatsapp {
  background: none;
  box-shadow: inset 0 0 0 3px var(--border-strong);
  color: var(--content-on-brand);
}
/* The label is trimmed to its cap height, so 25 + 11 + 25 gives the 61 of
   the macket. It carries the trim rather than the button, because only a
   flex item is a block container of its own text.                        */
.s-c2 .s-c2__submit-label,
.s-c2 .s-c2__whatsapp-label {
  white-space: nowrap;
}
.s-c2 .s-c2__submit:hover:not([disabled]) {
  background: var(--action-fill-hover);
  box-shadow: inset 0 0 0 3px var(--action-border-hover);
}
.s-c2 .s-c2__whatsapp:hover,
.s-c2 .s-c2__whatsapp:focus-visible {
  box-shadow: inset 0 0 0 3px var(--action-border-hover);
  color: var(--content-accent);
}
/* The Loading variant leaves the button looking exactly as it does at rest,
   so nothing is restyled here — it is only made unusable.                 */
.s-c2 .s-c2__submit[disabled] {
  cursor: progress;
}

/* --- Status line --------------------------------------------------------
   25 of the 44 between the button row and the status line comes from the
   form's own gap, the remaining 19 from here.                             */
.s-c2 .s-c2__status {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--layout-gutter);
  margin-top: 44px;
  color: var(--content-on-brand);
}
.s-c2 .s-c2__message {
  text-align: right;
}
.s-c2 .s-c2__hint[hidden],
.s-c2 .s-c2__state[hidden],
.s-c2 .s-c2__message[hidden] {
  display: none;
}

/* ===== t-base.css ===== */
/* ==========================================================================
   Tablet foundation — Figma page "Tablet" (1826:8397), 36 frames 1024 wide.
   Added 2026-10-08. Load AFTER every desktop stylesheet and before the
   mobile ones. See CONTRACT_TABLET.md.

   Three layers now share one set of URLs:
     below 768        mobile   (`is-m` blocks, css/m-*.css)
     768 – 1279.98    tablet   (`is-t` blocks, this file and css/t-*.css)
     1280 and up      desktop  (every other block)
   Decided with the client 2026-10-08: tablet from 768 to 1279. Until then
   the desktop layer started at 1024 and was scaled down by `zoom` between
   1024 and 1199; from 1280 up the desktop never needs that.

   Like the mobile layer this is an overlay: every rule is inside the tablet
   media query, so at 1280 and up the desktop layer is untouched.
   ========================================================================== */

/* --- Layer bounds, 2026-10-15 — tablet hand-off §3.3 -----------------------
   "768 and 1280 as variables in one place; moving a bound must be a change
   of one number." CSS cannot put a custom property inside a media query, so
   the ONE place is tools/build.py: BP_TABLET = 768, BP_DESKTOP = 1280. The
   build rewrites, in every stylesheet it emits, the four media-query forms
   (min-width: 768px) (max-width: 767.98px) (max-width: 1279.98px)
   (min-width: 1280px) and the two values below from those constants, and
   prints every other width bound it meets (a block's own step inside a
   layer, such as 899.98, is allowed but listed). The sources keep the literal numbers so a file still reads on
   its own. Scripts read the bounds from these two properties (js/t-menu.js).
   Lives here and not in css/tokens.css so the desktop-only build stays
   byte-identical. */
:root {
  --bp-tablet:  768px;
  --bp-desktop: 1280px;
}

@media (min-width: 768px) and (max-width: 1279.98px) {

  /* --- Grid -------------------------------------------------------------
     Frame 1024 · margin 50 · working area 924 · three columns of 308.
     `BackgroundLines` (1826:20016 on Main_t): four lines at x 50, 358, 666
     and 974, the full height of the screen. Between 768 and 1024 the
     working area stretches with the window and the 50 margins hold; above
     1024 it stops at 924 and centres. Nothing scales.

     2026-10-15, tablet hand-off §3.2 (designer, 13 Oct 2026) — OVERRIDES
     CONTRACT_TABLET §4 ("margins stay 50"): below 1024 the side margins
     shrink from 50 toward 25 first, and only then does the working area
     shrink. So the area is 924 from 974 up (margins 25 at 974, 50 at 1024),
     and below 974 it is the window minus 25 + 25 (718 at 768). Above 1024
     the area stays 924, centred. `--t-margin` is that live margin and every
     consumer — .container, the page lines, the header's menu panel, the UP
     control, the footer and the blocks that bleed by `-1 * --t-margin` —
     reads it, so they move together. `--t-sbw` is the classic scrollbar's
     width, written by js/t-menu.js (0 with overlay scrollbars, i.e. on every
     tablet), so that 100vw means the same width as 100 % of the page. */
  :root {
    --t-reference: 1024px;
    --t-margin-min: 25px;
    --t-margin-max: 50px;
    --t-content:   924px;
    --t-margin:    clamp(var(--t-margin-min),
                         (100vw - var(--t-sbw, 0px) - var(--t-content)) / 2,
                         var(--t-margin-max));

    /* Spacing steps used by the tablet frames: the same five as the rest of
       the file, plus 100 between sections. */
    --t-gap-tight: 10px;
    --t-gap-mid:   15px;
    --t-gap:       25px;
    --t-gap-block: 50px;
    --t-gap-big:   75px;
    --t-gap-section: 100px;

    /* Header: logo at y 58, menu button at y 50, rule at y 108. */
    /* 2026-11-04, client (tablet photos, Redmi Pad Pro): «хедер дуже високий, треба зменшити»: the macket's top 50 is the device status bar; on a real tablet the
       browser bar is already above the page. 108 -> 60, as on mobile (89 -> 50). */
    --t-header-h:  60px;

    --t-tap:       44px;
  }

  body {
    min-width: 0;          /* the desktop floor is 1200 */
    overflow-x: clip;
  }

  .container {
    width: min(100% - var(--t-margin) * 2, var(--t-content));
    margin-inline: auto;
  }

  /* The page's line layer: four lines instead of seven, on the working area
     instead of the 1440 frame. */
  .page > .gridlines {
    width: min(100% - var(--t-margin) * 2, var(--t-content));
  }
  .page > .gridlines i:nth-child(n + 5) { display: none; }
  .page > .gridlines i { left: calc((var(--n) - 1) * (100% - var(--line-width)) / 3); }

  /* Touch targets, as on mobile: the area grows from the centre to 44 and
     never moves what is drawn. */
  .t-tap { position: relative; }
  .t-tap::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width:  max(100%, var(--tap-w, var(--t-tap)));
    height: max(100%, var(--tap-h, var(--t-tap)));
  }

  :target { scroll-margin-top: calc(var(--t-header-h) + var(--t-gap)); }

  /* Keyboard focus — tablet hand-off §15 and §6, 2026-10-15. A visible ring
     on every interactive element: the 3 px Amber 4 stroke base.css already
     draws, on an Editorial White 4 plate instead of base.css's Editorial
     White 2 — "Editorial white / 4 is the only white; add no new white"
     (§6, §12.1). Anchor scrolling stays smooth through base.css
     (`html { scroll-behavior: smooth }`, off under prefers-reduced-motion). */
  :focus-visible {
    outline: 3px solid var(--border-accent);
    outline-offset: 2px;
    background-color: var(--editorial-white-4);
  }
}

/* ==========================================================================
   Layer switch. A page carries all three sets of blocks; each layer hides the
   other two. Tablet blocks are marked `is-t`, mobile ones `is-m`.
   ========================================================================== */
@media (min-width: 768px) and (max-width: 1279.98px) {
  .page > main > section:not(.is-t) { display: none; }
  /* Sections+footer on every tablet frame: 50 under the header rule, 100
     between sections. A screen that differs sets --gap-t on the block. */
  .page > main > .is-t:first-child,
  .page > main > section:not(.is-t) + .is-t { margin-top: var(--t-gap-block); }
  .page > main > .is-t + .is-t { margin-top: var(--gap-t, var(--t-gap-section)); }
}
@media (max-width: 767.98px), (min-width: 1280px) {
  .page > main > .is-t { display: none; }
}

/* ==========================================================================
   Accordion chevrons — hover and press. 2026-10-27, designer's answer
   (tablet question 7, hand-off §9.1): the chevron in the rows of FAQ_*_t,
   Service_cards_t (the FAQ rows of Services and Discovery Sprint) and
   How_it_works_full_t takes the Hov of `Main_S11_Arrows` 1826:18090 —
   Rich Black 1 → Amber 4 — while its row is hovered with a real pointer,
   and while it is pressed on touch. Written once for the layer: every
   tablet accordion row is a button with aria-expanded holding the chevron
   file (assets/chevron-down.png?v=d31a804b, or t-process-chevron.svg on How it works).
   The drawing is moved out of the image's box and the box is painted Amber 4
   through the file's own shape, so the turn (open / closed) still applies.
   ========================================================================== */
@media (min-width: 768px) and (max-width: 1279.98px) and (hover: hover) and (pointer: fine) {
  .page .is-t button[aria-expanded]:hover img[src$="chevron-down.png"],
  .page .is-t button[aria-expanded]:hover img[src$="t-process-chevron.svg"] {
    object-position: 0 -9999px;
    background-color: var(--amber-4);
    -webkit-mask: no-repeat center / 100% 100%;
            mask: no-repeat center / 100% 100%;
  }
  .page .is-t button[aria-expanded]:hover img[src$="chevron-down.png"] {
    -webkit-mask-image: url("../assets/chevron-down.png?v=d31a804b");
            mask-image: url("../assets/chevron-down.png?v=d31a804b");
  }
  .page .is-t button[aria-expanded]:hover img[src$="t-process-chevron.svg"] {
    -webkit-mask-image: url("../assets/t-process-chevron.svg?v=99a9df03");
            mask-image: url("../assets/t-process-chevron.svg?v=99a9df03");
  }
}
@media (min-width: 768px) and (max-width: 1279.98px) {
  .page .is-t button[aria-expanded]:active img[src$="chevron-down.png"],
  .page .is-t button[aria-expanded]:active img[src$="t-process-chevron.svg"] {
    object-position: 0 -9999px;
    background-color: var(--amber-4);
    -webkit-mask: no-repeat center / 100% 100%;
            mask: no-repeat center / 100% 100%;
  }
  .page .is-t button[aria-expanded]:active img[src$="chevron-down.png"] {
    -webkit-mask-image: url("../assets/chevron-down.png?v=d31a804b");
            mask-image: url("../assets/chevron-down.png?v=d31a804b");
  }
  .page .is-t button[aria-expanded]:active img[src$="t-process-chevron.svg"] {
    -webkit-mask-image: url("../assets/t-process-chevron.svg?v=99a9df03");
            mask-image: url("../assets/t-process-chevron.svg?v=99a9df03");
  }
}

/* 2026-11-04, client (tablet photos 15:09): «при тапі не з'являється цитата»: the quote plate over a team portrait (main t9.js, about t3.js). */
@media (min-width: 768px) and (max-width: 1279.98px) {
  .tq-wrap { position: relative; display: block; cursor: pointer; }
  .tq-wrap > img { display: block; }
  .tq {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--t-gap-mid, 15px);
    background: var(--surface-accent);
    color: var(--content-on-accent);
    font-size: 15px;
    line-height: 1.35;
    text-align: center;
    opacity: 0;
    transition: opacity var(--t-base) ease;
    pointer-events: none;
  }
  .tq-wrap.is-on .tq { opacity: 1; }
}

/* ===== t-header.css ===== */
/* ==========================================================================
   Tablet header and menu — partials/t-header.html, js/t-menu.js.
   Figma: Logo_header 1826:20036, Menu_T 1826:20065 (Pas / Act), Line 54.
   Inside the tablet query; nothing here exists below 768 or at 1280 and up.
   ========================================================================== */

@media (min-width: 768px) and (max-width: 1279.98px) {

  /* The desktop header and footer are not part of the tablet frames; the
     tablet has its own. The UP control is shared and restyled below. */
  .page > .site-header,
  .page > .site-footer { display: none; }

  /* UP — Figma `Button_form` 1826:21402: 61 wide, 72 tall, label on its
     side, hanging from the header rule at x 50, y 110 on every tablet frame
     (measured on the frame renders, 2026-10-14). OVERRIDE of the earlier
     tablet build, which sent it to the foot of the window as the desktop and
     mobile layers do: the file — and the designer's review, item 3 — put it
     directly under the header, reading as a bookmark. It stays fixed there
     while the sticky header stays on screen; shown once a screen has been
     scrolled (js/up.js). */
  .site-up {
    left: max(var(--t-margin), (100% - var(--t-reference)) / 2 + var(--t-margin));
    top: calc(var(--t-header-h) + 2px);
    bottom: auto;
    width: 61px;
    height: 72px;
    padding: 0;
  }

  /* 2026-10-27, designer's answer (all pages, question 3: UP control): "on
     hover over the yellow it changes its colour to white (EEEAE3)". On the
     tablet the hover (mouse or trackpad only, hand-off §9.1) and the press
     (touch, while the finger is down) fill the button with Editorial White 4
     and keep the 3 px Amber 4 stroke inside, so it stays visible over an
     Amber 4 band, where up.css's transparent hover made it vanish. On touch
     the shared up.css :hover would stick after a tap, so without a fine
     pointer the resting drawing is restored. Keyboard focus takes the same
     white plate (hand-off §6: Editorial White 4 is the only white). */
  .site-up:hover,
  .site-up:focus-visible {
    background: var(--action-fill);
    box-shadow: inset 0 0 0 3px var(--action-fill);
  }
  .site-up:focus-visible,
  .site-up:active {
    background: var(--editorial-white-4);
    box-shadow: inset 0 0 0 3px var(--action-border-hover);
  }

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

  /* base.css pins `.page > *:not(.gridlines):not(.site-header):not(.site-up)`
     at `position: relative; z-index: 1` — specificity 0,4,0. `.page >
     .t-menu` is only 0,2,0 and loses both properties, which put the menu in
     the flow under the header. The repeated class lifts each rule to 0,5,0;
     it is a weight, not a typo. */
  .page > .t-header.t-header.t-header.t-header { position: sticky; top: 0; z-index: 10; }
  .page > .t-menu.t-menu.t-menu.t-menu         { position: fixed;  z-index: 20; }

  .t-header {
    height: var(--t-header-h);
  }
  /* 2026-10-15, tablet hand-off §8: "no effects at all — zero shadows and
     zero blurs on all 37 screens; the tablet header has no background blur,
     it is solid." The plate was the desktop's 75 % Editorial White 4 with a
     25 px backdrop blur; on the tablet it is solid Editorial White 4. */
  .t-header__plate {
    position: absolute;
    inset: 0;
    background: var(--surface-page);
  }
  /* The solid plate would hide the page lines, but Main_t draws
     `BackgroundLines` (1826:20016) from y 0, through the header (sampled on
     the frame render, 2026-10-15: Rich Black 3 at x 50 · 358 · 666 · 974
     for y 0–107). The plate draws its own copy, in the same box and the
     same positions as `.page > .gridlines` in css/t-base.css: a 1 px line
     at background-position 0 / ⅓ / ⅔ / 100 % lands at (n − 1)(100 % − 1px)/3,
     which is exactly the page layer's formula. */
  .t-header__plate::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: min(100% - var(--t-margin) * 2, var(--t-content));
    --t-line: linear-gradient(var(--line-color), var(--line-color));
    background:
      var(--t-line) 0       0 / var(--line-width) 100% no-repeat,
      var(--t-line) 33.333% 0 / var(--line-width) 100% no-repeat,
      var(--t-line) 66.667% 0 / var(--line-width) 100% no-repeat,
      var(--t-line) 100%    0 / var(--line-width) 100% no-repeat;
  }

  /* Logo 179 × 25, centred, top at 58. */
  .t-header__logo {
    position: absolute;
    z-index: 2;
    left: 50%;
    top: 13px;                           /* was 58: the header lost its status-bar band */
    transform: translateX(-50%);
    line-height: 0;
  }
  .t-header__logo img { width: 179px; height: 25px; }

  /* Menu_T Pas: 70 × 40 at y 50, flush with the right edge of the 1024
     frame — which is the window's edge below 1024 and the frame's above. */
  .t-header__toggle {
    position: absolute;
    z-index: 2;
    top: 5px;                            /* was 50 */
    right: max(0px, (100% - var(--t-reference)) / 2);
    width: 70px;
    height: 40px;
    padding: 10px;
    border: 0;
    background: var(--surface-page);
    display: grid;
    place-items: center start;
    cursor: pointer;
  }
  .t-header__bars,
  .t-header__bars::before,
  .t-header__bars::after {
    display: block;
    width: 25px;
    height: 2px;
    background: var(--content-primary);
  }
  .t-header__bars { position: relative; }
  .t-header__bars::before,
  .t-header__bars::after { content: ""; position: absolute; left: 0; }
  .t-header__bars::before { top: -8px; }
  .t-header__bars::after  { top:  8px; }

  /* Line 54: 2 px Rich Black at y 108–109, the width of the frame
     (measured on the frame renders, 2026-10-14; the earlier build drew the
     1 px grid line in Rich Black 3, which nearly vanished). */
  .t-header__rule {
    position: absolute;
    left: 50%;
    bottom: -2px;                         /* y 108–109, under the 108 header */
    transform: translateX(-50%);
    width: min(100%, var(--t-reference));
    margin: 0;
    border: 0;
    border-top: 2px solid var(--content-primary);
  }

  /* --- Menu_T Act -------------------------------------------------------
     A panel 1024 wide whose close button lands where the menu button was
     (y 50), so the X replaces the bars in place. Taller than the window on
     a short screen, it scrolls on its own. */
  .t-menu {
    position: fixed;
    top: 50px;
    left: 50%;
    transform: translateX(-50%);
    width: min(100%, var(--t-reference));
    max-height: calc(100vh - 50px);
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--surface-page);
    border-bottom: 2px solid var(--border-strong);
  }
  /* 2026-10-27, designer's answer (tablet question 1, Menu_T Act 1826:20071):
     "the panel stretches to the full height and width of the page; a tap
     outside the links does nothing." OVERRIDES the 1024 x 758 panel above:
     it now covers the whole window (inset 0, 100dvh), so no part of the page
     shows under it at 768 x 1024 or wider than 1024. The content keeps the
     file's places: 50 of padding on top puts the close button at y 50, where
     the menu button was, and the links stay on the 924 working area. The
     Act frame's 2 px Rich Black 1 rule at its foot is dropped: the panel's
     foot is now the window's edge. Taps on the empty panel close nothing
     (js/t-menu.js closes only on a link, the close button, the menu button
     or Escape). */
  .t-menu {
    top: 0;
    left: 0;
    transform: none;
    width: 100%;
    height: 100vh;
    height: 100dvh;
    max-height: none;
    box-sizing: border-box;
    padding-top: 5px;                    /* close lands where the menu button is (was 50) */
    border-bottom: 0;
  }
  .t-menu[hidden] { display: none; }

  /* 2026-10-15, hand-off §10.1: the page under the open menu does not
     scroll (js/t-menu.js sets the class). The panel keeps its own scroll.
     A classic scrollbar's width is kept as padding so nothing shifts. */
  html.is-t-menu-open {
    overflow: hidden;
    padding-right: var(--t-sbw, 0px);
  }

  .t-menu__inner {
    width: min(100% - var(--t-margin) * 2, var(--t-content));
    margin-inline: auto;
    padding-bottom: var(--t-gap-block);
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
  }

  .t-menu__head {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
  }
  .t-menu__close {
    width: 45px;
    height: 40px;
    padding: 10px 12px 10px 13px;
    border: 0;
    background: none;
    cursor: pointer;
  }
  .t-menu__close span {
    position: relative;
    display: block;
    width: 20px;
    height: 20px;
  }
  .t-menu__close span::before,
  .t-menu__close span::after {
    content: "";
    position: absolute;
    left: -2px;
    top: 9px;
    width: 24px;
    height: 2px;
    background: var(--content-primary);
  }
  .t-menu__close span::before { transform: rotate(45deg); }
  .t-menu__close span::after  { transform: rotate(-45deg); }

  .t-menu__rule {
    width: 100%;
    margin: 0;
    border: 0;
    border-top: 2px solid var(--border-strong);
  }

  /* Nine links, 25 apart; from the second on, a hairline 15 above. */
  .t-menu__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
  }
  .t-menu__list li + li {
    padding-top: var(--t-gap-mid);
    border-top: var(--line-width) solid var(--line-color);
  }
  .t-menu__list a {
    display: block;           /* u-trim needs a block box */
    width: fit-content;
    color: var(--content-primary);
    text-decoration: none;
  }

  .t-menu__foot {
    margin-top: calc(var(--t-gap-big) - var(--t-gap));
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
  }

  /* Button_form_m in the tablet menu: full width, 25 padding, the label
     trimmed to its cap height — 15 + 50 = 65 high. */
  .t-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    min-height: 65px;
    padding: 25px;
    color: var(--content-primary);
    text-decoration: none;
    text-align: center;
  }
  .t-btn--fill { background: var(--action-fill); }
  .t-btn--line { border: 3px solid var(--border-strong); padding: 22px; }
}

@media (min-width: 768px) and (max-width: 1279.98px) and (hover: hover) and (pointer: fine) {
  /* 2026-10-27, the UP hover on a real pointer — see the block above. */
  .site-up:hover {
    background: var(--editorial-white-4);
    box-shadow: inset 0 0 0 3px var(--action-border-hover);
  }
}

/* Above the tablet range and below it the tablet chrome does not exist. The
   script removes `hidden` unconditionally, so this has to say it. */
@media (max-width: 767.98px), (min-width: 1280px) {
  .t-header, .t-menu, .t-footer { display: none !important; }
}

/* ===== t-footer.css ===== */
/* ==========================================================================
   Tablet footer — partials/t-footer.html, Figma `Footer_t` 1899:15330.
   1024 × 335 in the file; the ground runs the full window, the 924 column
   centres. Inside the tablet query only.
   ========================================================================== */

@media (min-width: 768px) and (max-width: 1279.98px) {

  .page > .t-footer {
    margin-top: var(--t-gap-section);     /* Sections+footer: 100 */
    background: var(--surface-brand);
  }

  .t-footer__inner {
    width: min(100% - var(--t-margin) * 2, var(--t-content));
    margin-inline: auto;
    padding-block: var(--t-gap-block);
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
    color: var(--content-primary);
  }

  .t-footer__top {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--t-gap);
  }
  .t-footer__logo { line-height: 0; }
  .t-footer__logo img { width: 179px; height: 25px; }
  .t-footer__tagline {
    display: block;
    margin: 0;
    max-width: 608px;
    text-align: right;
  }

  .t-footer__rule {
    width: 100%;
    margin: 0;
    border: 0;
    border-top: 2px solid var(--border-strong);
  }

  .t-footer__middle {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--t-gap);
  }
  .t-footer__left {
    width: min(450px, 60%);
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
  }

  .t-footer__social {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    align-items: center;
    gap: var(--t-gap);
    height: 25px;
  }
  .t-footer__social a { display: block; line-height: 0; }

  /* Three lines set solid: the file's paragraph has no gap between them.
     One block box trimmed to cap height at the top and the baseline at the
     foot, as Figma trims the paragraph — a flex column would leave the trim
     with nothing to act on and the footer 12 px taller than Footer_t's 335
     (found 2026-10-12). */
  .t-footer__office {
    font-style: normal;
    display: block;
    text-box-trim: trim-both;
    text-box-edge: cap alphabetic;
  }
  .t-footer__office span { display: block; line-height: normal; }

  .t-footer__reach,
  .t-footer__legal {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
  }
  .t-footer__reach {
    flex-direction: column;
    align-items: flex-end;
    gap: var(--t-gap);
  }
  /* The two lines sit on a 36 step (cap height + 25), so 44-tall touch
     areas overlapped by 8; 36 keeps them edge to edge (CONTRACT_TABLET §6,
     2026-10-14). */
  .t-footer__reach a { --tap-h: 36px; }
  .t-footer__legal {
    justify-content: flex-end;
    gap: var(--t-gap);
  }
  .t-footer a {
    display: block;            /* u-trim needs a block box */
    color: inherit;
    text-decoration: none;
  }
  .t-footer__legal a { color: var(--content-on-inverse); }   /* Editorial White 4 */
  /* 2026-10-15, hand-off §15: the focus plate is Editorial White 4
     (css/t-base.css), the same as these links' text — on focus the text
     turns Rich Black 1 so it stays readable inside the ring. */
  .t-footer__legal a:focus-visible { color: var(--content-primary); }
}

/* ===== insights/it.css ===== */
/* ==========================================================================
   Insights tablet — the shared vocabulary of the seven tablet screens.
   Figma page "Tablet" 1826:8397: `Blog_t` 1972:15308 and `Blog_A1_t` …
   `Blog_A6_t` (1978:16797, 1996:11223, 1997:17120, 1997:18223, 1997:19396,
   1997:23212). Added 2026-10-09.

   One CSS id, `it`, listed first in all seven pages' `sectionsTablet`, so
   the pieces the screens share — the heading lockup, `Button_form`, the
   `Blog_Card_S1` plate, the "three ways to start" cards, and the whole
   article layout (Sections 1 to 5 of every Blog_A*_t) — are written once
   rather than seven times. It carries no markup.

   Everything sits inside the tablet query (CONTRACT_TABLET.md §2.1).
   ========================================================================== */

@media (min-width: 768px) and (max-width: 1279.98px) {

  /* --- First block -----------------------------------------------------
     On all seven frames `Sections+footer` starts at y 233, 125 under the
     header rule at 108, not the 50 the layer switch gives a first block.
     Same weight as the t-base.css rule (0,3,2) and later, so it wins. */
  /* 2026-10-27, client: less space under the header; was 125 */
  .page > main > section.is-t.tb-first { margin-top: var(--t-gap-block); }

  .tb-sr {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }

  /* --- Heading lockup — `Group 110` (e.g. 1972:15605) --------------------
     The Comforter 100 script and the Mulish `Heading` share one cell; the
     word hangs 27 below the top of the group and the script is drawn over
     it. The group is as tall as the script's 75 cap height, or 27 plus the
     word where the word runs to two lines (Section 3 of Blog_t). */
  .tb-lockup {
    display: grid;
    text-align: center;
    font: inherit;
    margin: 0;
  }
  .tb-lockup > * { grid-area: 1 / 1; }
  .tb-lockup__word { margin-top: 27px; }
  .tb-lockup__script {
    position: relative;
    color: var(--content-accent);
    pointer-events: none;
  }
  .tb-lockup--left { text-align: left; }

  /* --- `Button_form` — 25 of padding round an 11-tall trimmed cap: 61.
     A block flex box; the label is its own element so `u-trim` reaches it
     (CONTRACT_TABLET.md §5). `--line` is the outlined twin in `Form_t`. */
  .tb-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    padding: var(--t-gap);
    border: 0;
    background: var(--action-fill);
    color: var(--content-on-accent);
    text-align: center;
    text-decoration: none;
    cursor: pointer;
  }
  .tb-btn--line {
    background: transparent;
    border: 3px solid var(--border-strong);
    padding: calc(var(--t-gap) - 3px);
    color: var(--content-primary);
  }
  .tb-btn[disabled] { cursor: default; }

  /* --- `Blog_Card_S1` — the flat Pas plate, 449 x 316 at 1024.
     The component scales with its instance: the 25 inset of the 316
     square becomes 7.91 % of the card's width (35.5 at 449), and 25 top
     and bottom. Number at the top right in `Label`, title at the foot in
     `Intro Black`. No photograph: the desktop's Hov / Act states lay one
     on, and a touch screen has no hover. */
  .tb-card {
    position: relative;
    display: flex;
    flex-direction: column;
    min-height: 316px;
    padding: var(--t-gap) 7.91%;
    background: var(--rich-black-3);
    color: var(--content-primary);
    text-decoration: none;
  }
  .tb-card__no {
    align-self: flex-end;
    text-align: right;
  }
  .tb-card__title { margin-top: auto; }

  /* --- "Three ways to start" — `Group 116` (1974:16230): a 924 x 265
     Rich black 3 plate, the copy column 25 in and 425 wide, the button at
     its foot, the photograph 449 wide flush right. 25 between cards. */
  .tb-ways {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap-block);
  }
  .tb-ways__head {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
    text-align: center;
  }
  .tb-ways__list {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
  }
  .tb-ways__card {
    display: grid;
    grid-template-columns: minmax(0, 475fr) minmax(0, 449fr);
    min-height: 265px;
    background: var(--rich-black-3);
  }
  .tb-ways__copy {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
    padding: var(--t-gap);
  }
  .tb-ways__copy .tb-btn { margin-top: auto; }
  .tb-ways__text {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
    padding-bottom: var(--t-gap);   /* keeps the button clear of a long line */
  }
  .tb-ways__photo {
    position: relative;
    min-height: 265px;
  }
  .tb-ways__photo img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* ======================================================================
     ARTICLES — Blog_A1_t … Blog_A6_t. Five sections, 100 apart:
       1  head, contents, lede          (aNt1, per article)
       2  the text, tables, closing ask (aNt2, per article)
       3  author card and related       (aNt3, per article)
       4  Discovery Sprint              (at4, shared)
       5  three ways and the form       (at5, shared)
     ====================================================================== */

  /* --- Section 1 — `Frame 793` / `Frame 798` (1978:17413 / 1978:17461) */
  .tb-at1 .container {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap-block);
  }
  .tb-at1__head {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
  }
  /* `Frame 791`: the byline on the left, date and reading time on the
     right, 25 apart, both 133 wide and right-aligned. */
  .tb-at1__meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--t-gap);
  }
  .tb-at1__stamp {
    display: flex;
    gap: var(--t-gap);
    text-align: right;
  }
  .tb-at1__stamp > * { display: block; min-width: 133px; }

  /* `Blog_menu` — `Frame 798`, a Rich black 3 plate with 50 of padding.
     The file draws it open: the caption, 50, and two columns of
     `Button_text` 400 and 399 wide, 25 apart, the rows 25 apart. Collapsed
     by default (CONTRACT_TABLET.md §6), so the closed plate is the caption
     alone, 111 high; the chevron is the mobile `Blog_menu`'s. */
  .tb-at1__toc {
    background: var(--rich-black-3);
    padding: var(--t-gap-block);
  }
  .tb-at1__toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--t-gap);
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    text-align: left;
    cursor: pointer;
  }
  .tb-at1__chev { flex: 0 0 auto; transition: transform var(--t-fast); }
  .tb-at1__toc.is-open .tb-at1__chev { transform: rotate(180deg); }
  .tb-at1__panel { margin-top: var(--t-gap-block); }
  .tb-at1__panel[hidden] { display: none; }
  /* Two `Button_text` columns, 400 and 399 wide, 25 apart; ceil(n/2) rows
     on the left. 2026-10-14: two lists in a grid, not one list in multicol —
     multicol balanced a row across and padded the plate by up to 28. */
  .tb-at1__list {
    display: grid;
    grid-template-columns: minmax(0, 400fr) minmax(0, 399fr);
    column-gap: var(--t-gap);
    align-items: start;
  }
  .tb-at1__list ol {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
  }
  .tb-at1__item {
    display: block;
    --tap-h: 36px;     /* rows are 25 apart: the area may not reach the next one */
  }
  /* 2026-10-14: the label is an inline span, and `u-trim` does nothing on an
     inline box — each row kept its full leading and stood 44 apart instead
     of the file's 36. Blockified: open plate now the file's 409
     (1978:17465). */
  .tb-at1__item > .u-trim { display: block; }
  .tb-at1__ledes {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap-block);
  }

  /* --- Section 2 — "All text" (1997:17048), `Table` (1996:10992).
     `Title + text`: the title, 25, the paragraphs 25 apart; blocks 50
     apart. The file draws 15 under some of article 1's titles and 25
     under every other; 25 is the rhythm used everywhere here. Article 6
     sets its blocks 25 apart — its own `--tb-flow`. */
  .tb-at2 .container {
    display: flex;
    flex-direction: column;
    gap: var(--tb-flow, var(--t-gap-block));
  }
  /* The contents jumps with scrollIntoView before the hash changes, so the
     heading is not yet `:target`: it carries the header clearance itself. */
  .tb-at2 [id^="t-sec-"] { scroll-margin-top: calc(var(--t-header-h) + var(--t-gap)); }
  .tb-at-block,
  .tb-at-text {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
  }
  .tb-at-list {
    display: flex;
    flex-direction: column;
    gap: 8px;                   /* the file sets the items at the type's own leading:
                                   ~19 per line less the 11 cap the trim keeps */
    padding-left: 22.5px;       /* the disc sits 1.5 of the 15px type in */
  }
  .tb-at-list li { list-style: disc; }
  /* 2026-10-27 (H2): numbered list in the client's copy (articles 18, 20, 21). */
  .tb-at-list--num li { list-style: decimal; }

  /* 2026-10-14: per-block spacing hooks, all defaulting to the values
     above, so a page that sets none of them renders as before.
     `--tb-text-gap` — paragraphs inside one `Text` frame: Blog_A1_t sets
     them 15 / 16 apart in sections 5 and 8 (1978:17510, 1996:10994), not
     25, to match those nodes. `.tb-at-step25` puts the 25 back where the
     same frame has it (above "Main risk", 1996:11006).
     `.tb-at-list--loose` — a list whose items are separate text nodes 25
     apart, as paragraphs are: Blog_A2_t "Five criteria" (1997:17070) and
     Blog_A6_t "four stages" (1997:23555), to match those nodes.
     `--tb-act-gap` — Blog_A4_t / A5_t set the `All text` blocks 25 apart
     (`--tb-flow`) but keep the closing `Button_form` 50 below the text and
     the line under it 50 below the button (1997:18352, 1997:19540):
     the 25 of the flow plus this margin. */
  .tb-at-text { gap: var(--tb-text-gap, var(--t-gap)); }
  .tb-at-step25 { margin-top: calc(var(--t-gap) - var(--tb-text-gap, var(--t-gap))); }
  .tb-at-list--loose { gap: var(--t-gap); }
  .tb-at-act { margin-block: var(--tb-act-gap, 0px); }
  .tb-at-act:last-child { margin-bottom: 0; }   /* A5: the button closes Section 2 */
  .tb-at-link {
    color: var(--vista-blue-1);
    text-decoration: underline;
    text-underline-offset: 3px;
  }

  /* 2026-10-15 — tablet hand-off §5: an inline link in running text was
     19 tall. Vertical padding on an inline box grows its tap area without
     moving a line (inline padding does not enter the line box) or the
     underline (text-decoration, not a border). 38, not 44: two links two
     lines apart (38) going to different sources must not overlap (§5 rule
     4) — at 44 they did, in the "how long" article at 768 — and the text
     reflows at every width, so the area stays at that gap everywhere. */
  .tb-at-link { padding-block: 9.5px; }

  /* Tables: a 2px Vista blue 1 frame and rules, the header row filled with
     it, 25 of padding in each cell. Below the width the columns need they
     scroll sideways inside their own box; the page never does. */
  .tb-at-table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  .tb-at-table {
    width: 100%;
    min-width: 760px;
    border-collapse: collapse;
    table-layout: fixed;
  }
  .tb-at-table th,
  .tb-at-table td {
    padding: var(--t-gap);
    border: 2px solid var(--vista-blue-1);
    text-align: left;
    vertical-align: top;
  }
  .tb-at-table thead th { background: var(--surface-brand); }
  .tb-at-table--c2 { min-width: 600px; }
  /* Article 6 (1998:25781): the label column 100 + 50, the two others 337
     + 50 of 924. */
  .tb-at-table--c3 th:first-child { width: 16.23%; }

  /* --- Section 3 — `Author Card` 1996:11052 and `Frame 810`.
     A Vista blue 1 plate, 50 of padding: the 203 mark, 25, the copy
     column — name in `Intro`, 25, the line, 38, the button. Then 25, the
     related cards on the two-column grid, 25, and the label right-aligned
     under them. */
  .tb-at3 .container {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
  }
  .tb-at3__author {
    display: flex;
    align-items: center;
    gap: var(--t-gap);
    padding: var(--t-gap-block);
    background: var(--surface-brand);
    color: var(--content-on-brand);
  }
  .tb-at3__mark {
    flex: 0 0 203px;
    width: 203px;
    height: 203px;
    object-fit: cover;
  }
  .tb-at3__col {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 38px;
  }
  .tb-at3__text {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
  }
  .tb-at3__related {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--t-gap);
  }
  .tb-at3__label { text-align: right; }

  /* --- Section 4 — Discovery Sprint, 1996:11091.
     The 924 x 526 photograph; the lockup centred over it, its top at 250
     (47.5 % of the picture) — the script "Discovery" in Editorial white 4,
     the word "Sprint" in amber 50 below it; the Vista blue 1 panel 608
     wide, centred, its top 91 above the picture's foot; the button 25
     under the panel. */
  .tb-at4__media {
    position: relative;
  }
  .tb-at4__photo {
    width: 100%;
    aspect-ratio: 924 / 526;
    object-fit: cover;
  }
  .tb-at4__lockup {
    position: absolute;
    left: 0;
    right: 0;
    top: 47.53%;
    display: grid;
    text-align: center;
  }
  .tb-at4__lockup > * { grid-area: 1 / 1; }
  .tb-at4__script { color: var(--editorial-white-4); position: relative; }
  .tb-at4__word { margin-top: var(--t-gap-block); color: var(--content-accent); }
  .tb-at4__col {
    position: relative;
    width: min(608px, 100%);
    margin: -91px auto 0;
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
  }
  .tb-at4__panel {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
    padding: var(--t-gap) var(--t-gap) var(--t-gap-block);
    background: var(--surface-brand);
    color: var(--content-on-brand);
    text-align: center;
  }

  /* --- Section 5 — three ways (1996:11109). The ask (1996:11169) is the
     Contact page's tablet form block since 2026-11-02 (contact/t2). */
  .tb-at5 .container {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap-section);
  }
  /* 2026-11-02: the ask and Form_t left this block for contact/t2. */
}

/* === Tablet hover / press — hand-off §9.1 (added 2026-10-15) ===
   Replaces CONTRACT_TABLET §6 "no hover states": the tablet hand-off of
   13 Oct 2026, §9.1, gives every Components_Tablet set (1826:17360) that has
   a Hov variant its hover — only where the device has a real pointer — and
   uses the same drawing as the pressed state on touch: shown while the
   finger is down (:active), gone on release, never sticky; nothing is
   reachable only by hover. Disabled and aria-disabled controls take
   neither. Written once per page (this file is in every bundle of the
   page); the selectors carry `.page .is-t` so a block's own later rule
   cannot outweigh them. Sets with a Hov variant that are not here:
   Logo_header (tablet header, css/t-header.css — not this layer of
   files) and any set this page does not use. */
@media (min-width: 768px) and (max-width: 1279.98px) and (hover: hover) and (pointer: fine) {
  /* Button_form 1826:17361 — Pas (Amber 4 plate) → hov: no fill, a 3px Amber 4 stroke inside */
  .page .is-t .tb-btn:not(.tb-btn--line):not(.tb-btn--fill):not(:disabled):not([aria-disabled="true"]):hover {
    background-color: var(--action-fill-hover);
    box-shadow: inset 0 0 0 3px var(--action-border-hover);
  }

  /* Button_form, outlined instance (3px Rich Black 1 border) → the same hov stroke, Amber 4 */
  .page .is-t .tb-btn--line:not(:disabled):not([aria-disabled="true"]):hover {
    border-color: var(--action-border-hover);
  }

  /* Button_text 1826:18056 — Pas Rich Black 1 → hov Amber 4; with it the Main_S11_Arrows 1826:18090 chevron of a back link (Hov: Amber 4) */
  .page .is-t .tb-at1__item:not(:disabled):not([aria-disabled="true"]):hover {
    color: var(--amber-4);
  }
}
@media (min-width: 768px) and (max-width: 1279.98px) {
  /* The same drawings as the pressed state, on touch and pointer alike. */
  .page .is-t .tb-btn:not(.tb-btn--line):not(.tb-btn--fill):not(:disabled):not([aria-disabled="true"]):active {
    background-color: var(--action-fill-hover);
    box-shadow: inset 0 0 0 3px var(--action-border-hover);
  }
  .page .is-t .tb-btn--line:not(:disabled):not([aria-disabled="true"]):active {
    border-color: var(--action-border-hover);
  }
  .page .is-t .tb-at1__item:not(:disabled):not([aria-disabled="true"]):active {
    color: var(--amber-4);
  }
}

/* 2026-11-02: the Blog_Card_S1 photograph hover of the tablet index deck
   (bt2) is gone with the deck; the related cards never carried one. */

/* 2026-10-27, designer's answer (tablet, articles «Three ways to start»):
   the same hover as Free Resources — the panel turns Amber 4, and its button
   turns Editorial White 4 with an Amber 4 ring so it does not vanish. Mouse
   hover only; the same drawing while a finger is down. */
@media (min-width: 768px) and (max-width: 1279.98px) and (hover: hover) and (pointer: fine) {
  .page .is-t .tb-ways__card:hover,
  .page .is-t .tb-ways__card:focus-within { background: var(--amber-4); }
  .page .is-t .tb-ways__card:hover .tb-btn,
  .page .is-t .tb-ways__card:focus-within .tb-btn {
    background: var(--editorial-white-4);
    box-shadow: inset 0 0 0 3px var(--amber-4);
  }
}
@media (min-width: 768px) and (max-width: 1279.98px) {
  .page .is-t .tb-ways__card:active { background: var(--amber-4); }
  .page .is-t .tb-ways__card:active .tb-btn {
    background: var(--editorial-white-4);
    box-shadow: inset 0 0 0 3px var(--amber-4);
  }
}

/* ===== insights/contact/t1.css.css ===== */
/* ==========================================================================
   Contact tablet — block 1, plus the pieces the contact tablet blocks share
   (lockup, `Button_form`). Figma: "Section 1" 2022:17873, 1024 x 1111.
     Hero photo  2022:17829   1024 x 498
     Frame 853   2022:17872   1024 x 613, Vista Blue 1, padding 50
   ========================================================================== */

@media (min-width: 768px) and (max-width: 1279.98px) {

  /* --- Lockup `Group 110` — heading 27 down, Comforter over it ---------- */
  /* `Group 110` is 75 tall; the trimmed Comforter cap alone comes to 73. */
  .tb-contact-lockup {
    display: grid;
    min-height: 75px;
    font: inherit;
    text-align: center;
  }
  .tb-contact-lockup > * { grid-area: 1 / 1; width: 100%; }
  .tb-contact-lockup__word { margin-top: 27px; color: var(--content-primary); }
  .tb-contact-lockup__script { color: var(--amber-4); }
  .tb-contact-lockup--on-brand .tb-contact-lockup__script { color: var(--editorial-white-4); }

  /* --- `Button_form`, 61: 25 + cap 11 + 25; outlined stroke inside ------ */
  .tb-contact-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    padding: var(--t-gap);
    border: 0;
    background: var(--action-fill);
    color: var(--content-on-accent);
    text-align: center;
    cursor: pointer;
  }
  .tb-contact-btn--ghost {
    padding: calc(var(--t-gap) - 3px);
    border: 3px solid var(--border-strong);
    background: none;
  }
  .tb-contact-btn > span { display: block; white-space: nowrap; }

  /* --- Hero: three layers, bottom to top, as the file stacks them ------- */
  .tb-contact-1__hero {
    position: relative;
    height: 498px;
    overflow: hidden;
  }
  /* `a756ebea…` 2022:17830: 1024 x 203, on the bottom edge, full window. */
  .tb-contact-1__desk {
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 203px;
    object-fit: cover;
    object-position: center bottom;
  }
  /* `Mask group` 2022:17831: the silhouette, 982 x 497, pinned right, and
     only its strip from x 609 to 998 of the frame is drawn (the rectangle
     2022:17833 the mask is applied to) — 390 wide, 26 in from the right. */
  .tb-contact-1__halo {
    position: absolute;
    right: 0;
    top: 0;
    width: 982px;
    max-width: 100%;
    height: 497px;
    background: var(--vista-blue-1);
    -webkit-mask-image: url("../assets/contact-hero-halo.png?v=bcfee160");
    mask-image: url("../assets/contact-hero-halo.png?v=bcfee160");
    -webkit-mask-size: 982px 497px;
    mask-size: 982px 497px;
    -webkit-mask-position: 100% 0;
    mask-position: 100% 0;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    clip-path: inset(0 26px 0 calc(100% - 416px));
  }
  /* `Untitled … 1` 2022:17834: the portrait, 988 x 498, pinned right. The
     left of the file is transparent, so cover crops nothing visible at 768. */
  .tb-contact-1__author {
    position: absolute;
    right: 0;
    top: 0;
    width: 988px;
    max-width: 100%;
    height: 498px;
    object-fit: cover;
    object-position: 100% 50%;
  }

  /* --- Band ------------------------------------------------------------- */
  .tb-contact-1__band {
    padding-block: var(--t-gap-block);
    background: var(--vista-blue-1);
  }
  .tb-contact-1__lede {
    margin-top: var(--t-gap);
    text-align: center;
  }

  /* `Cards` 2022:17869: three plates, 25 apart, equal thirds. */
  .tb-contact-1__ways {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--t-gap);
    margin-top: var(--t-gap-block);
  }
  .tb-contact-1__way {
    display: flex;
    flex-direction: column;
    padding: var(--t-gap);
    background: var(--editorial-white-4);
    color: var(--content-primary);
  }
  .tb-contact-1__way--inverse {
    background: var(--rich-black-1);
    color: var(--editorial-white-4);
  }
  .tb-contact-1__step { color: var(--amber-4); }
  .tb-contact-1__title { margin-top: var(--t-gap); }
  .tb-contact-1__body { margin-top: var(--t-gap-block); }
  .tb-contact-1__act { margin-top: var(--t-gap-block); }
  .tb-contact-1__link {
    display: block;
    color: var(--content-primary);
  }
}

/* === Tablet hover / press — hand-off §9.1 (added 2026-10-15) ===
   Replaces CONTRACT_TABLET §6 "no hover states": the tablet hand-off of
   13 Oct 2026, §9.1, gives every Components_Tablet set (1826:17360) that has
   a Hov variant its hover — only where the device has a real pointer — and
   uses the same drawing as the pressed state on touch: shown while the
   finger is down (:active), gone on release, never sticky; nothing is
   reachable only by hover. Disabled and aria-disabled controls take
   neither. Written once per page (this file is in every bundle of the
   page); the selectors carry `.page .is-t` so a block's own later rule
   cannot outweigh them. Sets with a Hov variant that are not here:
   Logo_header (tablet header, css/t-header.css — not this layer of
   files) and any set this page does not use. */
@media (min-width: 768px) and (max-width: 1279.98px) and (hover: hover) and (pointer: fine) {
  /* Button_form 1826:17361 — Pas (Amber 4 plate) → hov: no fill, a 3px Amber 4 stroke inside */
  .page .is-t .tb-contact-btn:not(.tb-contact-btn--ghost):not(:disabled):not([aria-disabled="true"]):hover {
    background-color: var(--action-fill-hover);
    box-shadow: inset 0 0 0 3px var(--action-border-hover);
  }

  /* Button_form, outlined instance (3px Rich Black 1 border) → the same hov stroke, Amber 4 */
  .page .is-t .tb-contact-btn--ghost:not(:disabled):not([aria-disabled="true"]):hover {
    border-color: var(--action-border-hover);
  }

  /* Button_text 1826:18056 — Pas Rich Black 1 → hov Amber 4; with it the Main_S11_Arrows 1826:18090 chevron of a back link (Hov: Amber 4) */
  .page .is-t .tb-contact-1__link:not(:disabled):not([aria-disabled="true"]):hover {
    color: var(--amber-4);
  }
}
@media (min-width: 768px) and (max-width: 1279.98px) {
  /* The same drawings as the pressed state, on touch and pointer alike. */
  .page .is-t .tb-contact-btn:not(.tb-contact-btn--ghost):not(:disabled):not([aria-disabled="true"]):active {
    background-color: var(--action-fill-hover);
    box-shadow: inset 0 0 0 3px var(--action-border-hover);
  }
  .page .is-t .tb-contact-btn--ghost:not(:disabled):not([aria-disabled="true"]):active {
    border-color: var(--action-border-hover);
  }
  .page .is-t .tb-contact-1__link:not(:disabled):not([aria-disabled="true"]):active {
    color: var(--amber-4);
  }
}

/* ===== insights/contact/t2.css ===== */
/* ==========================================================================
   Contact tablet — block 2, the invitation and `Form_t`.
   Figma: "Section 2" 2022:17905; form instance 2022:17880 of `Form_t`
   1875:15100, 924 x 683. Lockup 125 (two lines of heading), 25, lede, 50,
   form. The form rules are the FAQ tablet block 7's (sections/faq/t7.css),
   scoped to this block: the same component on another page.

   Form_t: Vista Blue 1 plate, 25 at the sides, 50 at the bottom (the file
   reads 23 at the top — taken as 25, the step every other edge uses).
   ========================================================================== */

@media (min-width: 768px) and (max-width: 1279.98px) {

  .tb-contact-2 .tb-contact-2__lede {
    margin-top: var(--t-gap);
    text-align: center;
  }
  .tb-contact-2 .tb-form { margin-top: var(--t-gap-block); }

  /* --- Form_t ----------------------------------------------------------- */
  .tb-contact-2 .tb-form {
    padding: var(--t-gap) var(--t-gap) var(--t-gap-block);
    background: var(--vista-blue-1);
  }
  .tb-contact-2 .tb-form__fields {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: var(--t-gap);
    row-gap: var(--t-gap-block);
  }
  .tb-contact-2 .tb-form__field {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap-mid);
    min-width: 0;
  }
  .tb-contact-2 .tb-form__field--wide { grid-column: 1 / -1; }
  .tb-contact-2 .tb-form__label { display: block; color: var(--content-primary); }

  .tb-contact-2 .tb-form__input {
    display: block;
    width: 100%;
    height: 50px;
    padding: 0 var(--t-gap-mid);
    border: 0;
    border-radius: 0;
    background: var(--editorial-white-4);
    color: var(--content-primary);
    font-family: inherit;
  }
  .tb-contact-2 .tb-form__input--big {
    height: 225px;
    padding: var(--t-gap-mid);
    resize: vertical;
  }
  .tb-contact-2 .tb-form__input::placeholder { color: var(--vista-blue-1); opacity: 1; }
  /* Keyboard focus is not in the macket and is required all the same. */
  .tb-contact-2 .tb-form__input:focus-visible {
    outline: 3px solid var(--border-accent);
    outline-offset: 0;
    background-color: var(--editorial-white-4);   /* 2026-10-15, hand-off §12.1: never base.css's #FFFFFF */
  }

  .tb-contact-2 .tb-form__buttons {
    display: flex;
    flex-direction: column;
    gap: var(--t-gap);
    margin-top: var(--t-gap);
  }
  .tb-contact-2 .tb-contact-btn:disabled { cursor: progress; }

  /* State (Base Up; Base Up Black Wide once a request is under way) on the
     left, the note (Base, right-aligned) on the right — 425 and 424 at 1024. */
  .tb-contact-2 .tb-form__status {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: var(--t-gap);
    align-items: center;
    margin-top: var(--t-gap-block);
    color: var(--content-primary);
  }
  .tb-contact-2 .tb-form__note { text-align: right; }
}

/* ===== 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 768 this layer overrides the
   desktop layer; at 768 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: 767.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 in the macket, whose top 44 is the
       phone's status bar. 2026-11-04, client (phone review): «прибрати відступ на хедері на всіх
       сторінках» — on a real phone the browser bar is already above the page,
       so the band is gone: the bar is 50, burger at 5, logo at 17. */
    --m-header-h:  50px;

    /* 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)); }

  /* --- 12 Form fields in focus (2026-10-27) -----------------------------
     Mobile review 20 Oct, items 6 and 9: on every page a field in focus
     keeps the Editorial White 4 ground of the page — never #FFFFFF — and
     shows one 3 px Amber 4 stroke on its own edge. base.css paints the white
     on every `:focus-visible` below 1280 and puts the ring 2 px off the
     edge, which over a coloured form plate reads as a double outline. This
     overrides CONTRACT_MOBILE §12 ("white ground"); the designer's review is
     newer. Block rules that set their own focus state carry the same values. */
  input:focus-visible,
  textarea:focus-visible,
  select:focus-visible {
    background-color: var(--editorial-white-4);
    outline: 3px solid var(--border-accent);
    outline-offset: 0;
  }

}

/* ==========================================================================
   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 768 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: 767.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: 768px) {
  .page > main > .is-m { display: none; }
}

/* --- Pull quote, mobile (2026-10-27, client) -----------------------------
   The founder's quote on the four mobile pages, read as the case pages'
   mobile quote band reads (casem.css .s-cam6__*): the opening mark on its
   own line, Mulish Regular 75 in Amber (the file's measurement, no style
   in the file), the words in Base italic, the attribution under them, all
   centred as every mobile founder block is. Desktop and tablet: base.css. */
@media (max-width: 767.98px) {
  .c-quote.c-quote--m {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--m-gap-mid);
    text-align: center;
  }
  .c-quote--m .c-quote__mark {
    grid-row: auto;
    font-weight: 400;
    font-size: 75px;
    /* Trimmed to the cap, the box is 53 tall but the mark's ink is only its
       top 16 (measured 2026-10-27); without this the words sat 52 under the
       ink instead of 15. The box is cut to the ink (0.22em = 16.5 of 75);
       the empty part of the line overflows invisibly. */
    height: 0.22em;
  }
  .c-quote--m .c-quote__words,
  .c-quote--m .c-quote__by { grid-column: auto; }

  /* 2026-11-04, client (phone review): «Show filters» / «Hide filters» on Results and Insights
     (sections/results/m2, sections/insights/bm1). A chip-like button with a
     chevron; the panel under it opens on tap. */
  .f-toggle {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 13px 15px;
    border: 1px solid var(--rich-black-1);
    background: transparent;
    color: var(--rich-black-1);
    cursor: pointer;
  }
  .f-toggle > span { font-size: 13px; }
  /* The chevron is its own span: .m-tap already owns ::after (the 44 touch area). */
  .f-toggle__chev {
    width: 7px;
    height: 7px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
    transition: transform var(--t-base) ease;
  }
  .f-toggle[aria-expanded="true"] .f-toggle__chev { transform: translateY(2px) rotate(-135deg); }
  .f-panel { margin-top: var(--m-gap-mid); }
  .f-panel[hidden] { display: none; }
}

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

@media (max-width: 767.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   */
  }
  /* 2026-10-27 · mobile review 20 Oct, items 7 and 8. `base.css` pins
     `.page > *:not(.gridlines):not(.site-header):not(.site-up)` at
     `position: relative` with weight 0,4,0, and the 0,2,0 rules here lost to
     it: the header scrolled away with the page (item 7) and the overlay
     opened in the flow under the burger instead of over the window (item 8).
     The selectors below carry 0,5,0, the same cure the tablet header uses. */
  .page > .m-header.m-header.m-header.m-header.m-header { position: sticky; top: 0; z-index: 10; }
  .page > .m-menu.m-menu.m-menu.m-menu.m-menu          { position: fixed; inset: 0; z-index: 20; }

  /* 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: 17px;                           /* was 59: header without the status-bar band */
    --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: 5px;                            /* was 49 */
    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: 5px var(--m-gap-block);   /* close lands where the burger is (was 49) */
  }

  /* 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; }
  /* 2026-10-27 · review 20 Oct, item 8 ("all elements as in the file"):
     Line 55 1244:11210 under the cross is Rich Black 1 in the Act variant;
     only the rules between the items are Rich Black 3. */
  .m-menu__rule { border-top-color: var(--content-primary); }

  /* 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 at 768 and up. */
@media (min-width: 768px) {
  .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 768 and up.
   ========================================================================== */

@media (max-width: 767.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: 767.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/a2m1.css ===== */
/* ==========================================================================
   Insights article mobile — the whole screen.
   Figma: `Blog_A1_m` 1549:13620, `Blog_A2_m` 1564:13051, `Blog_A3_m`
   1564:13576. One template, three sets of copy.

     block 1   Section 1 — the head, the photograph, the lede, the contents
     block 2   the article
     block 3   the team card
     block 4   the related articles
     block 5   the Discovery Sprint
     block 6   the three ways to start and the form

   This file carries all six, and the vocabulary they share — the lockup, the
   plate, the button and the article card. Each of those is one component in
   the file, so each is written once here rather than copied into six
   stylesheets. The three article pages get one copy of this file each,
   because they share sections/insights/ and a page's bundle is built from
   the blocks it names.

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

@media (max-width: 767.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.
     ====================================================================== */
  .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;
  }

  /* Shared: the pale plate — Rich black 3, 25 of padding all round. */
  .bm-plate {
    background: var(--rich-black-3);
    color: var(--content-primary);
    padding: var(--m-gap);
  }

  /* Shared: `Button_form`, 61 tall — 25, an 11-tall trimmed cap, 25.
     A block-level flex box, with the label its own element inside it: a flex
     item is blockified and `u-trim` only reaches a block container, so 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%; }
  .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, a Rich black 1
     veil at 75 % sits over it and the copy sits on top: 25 of padding, 23 at
     the foot, 48 between the three rows.

     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 Rich black 1 token held back to 75 %, not an eighth colour. */
  .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);
  }
  .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 — Section 1
     ====================================================================== */

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

  /* 3.1 `BackgroundLines`: 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 352
     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 14 273 runs past the screen's own
     height; it is the designer's single long guide, not a height. */
  .s-am1__lines {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: -1;
    pointer-events: none;
  }
  .s-am1__lines > .container { position: relative; height: 100%; }
  .s-am1__lines i {
    position: absolute;
    top: 0;
    bottom: 0;
    width: var(--line-width);
    background: var(--line-color);
  }
  .s-am1__lines i:nth-child(1) { left: 0; }
  .s-am1__lines i:nth-child(2) { left: 33.333%; }
  .s-am1__lines i:nth-child(3) { left: 66.667%; }
  .s-am1__lines i:nth-child(4) { right: 0; }

  /* `Frame 593`: the topic ranged right, then the title, the byline and the
     stamp, each 25 below the last. */
  .s-am1__topic { text-align: right; }
  .s-am1__title { margin-top: var(--m-gap); }
  .s-am1__by    { margin-top: var(--m-gap); }

  /* `Frame 592`, 352 x 11: the date at the left edge and the reading time at
     the right. Two blockified flex items, so `u-trim` reaches both and the
     row keeps its 11. */
  .s-am1__meta {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--m-gap);
    margin-top: var(--m-gap);
  }
  .s-am1__date { flex: 0 0 auto; }
  .s-am1__read { flex: 0 0 auto; text-align: right; }

  /* `Button_form_m` across the working area. Its nearest neighbour is the
     stamp row 25 above, and the button is 61 tall, so `m-tap` resolves to
     its own bounds and nothing grows. */
  .s-am1__back { margin-top: var(--m-gap); }

  /* `Rectangle 163`, 402 x 275 — the full window. Above 430 the window is
     wider than the design ever gets, so the picture stops at the 430 column
     and centres with the rest of the page. The 275 is a height, not a ratio:
     §3.2 says sizes do not scale with the window, so a narrower phone crops
     the picture rather than shrinking it. */
  .s-am1__art { margin-top: var(--m-gap); }
  /* 2026-11-02, client (the hero picture read as an advert): 16 : 9 of the
     column, about 220 at 390, was a fixed 275; it crops on the upper middle,
     where the faces and the books are. */
  .s-am1__photo {
    display: block;
    width: 100%;
    max-width: var(--m-max);
    height: auto;
    aspect-ratio: 16 / 9;
    margin-inline: auto;
    object-fit: cover;
    object-position: 50% 35%;
  }

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

  /* --- 10 The contents — `Blog_menu` 1564:11672 ------------------------
     Pas is 61: 25 of padding, an 11-tall trimmed cap and 25 again. Act is
     the same box with the list under it, and it opens to whatever the list
     comes to — the 493 the Act variant pins is twelve single-line items,
     never a height set here, which is also why a heading that wraps simply
     makes the row taller instead of truncating. */
  .s-am1__toc { margin-top: var(--m-gap); }

  .s-am1__toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--m-gap);
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    color: var(--content-primary);
    text-align: left;
    cursor: pointer;
  }
  /* A flex item, so already blockified and `u-trim` reaches it. Left inline
     it would keep its full line box and the closed row would stand 69. */
  .s-am1__toggle-label { display: block; }
  .s-am1__chev { flex: 0 0 auto; }
  /* `Main_S11_Arrows`: down when the list is closed, up when it is open. */
  .s-am1__toc.is-open .s-am1__chev { transform: scaleY(-1); }

  .s-am1__panel { margin-top: var(--m-gap); }
  /* The entries carry their own "01. " in the copy, as the file draws them,
     so the list draws no marker of its own. */
  .s-am1__list {
    display: grid;
    gap: var(--m-gap);
    margin: 0;
    padding: 0;
    list-style: none;
  }

  /* --- 5 Touch ---------------------------------------------------------
     `Button_text` is 11 tall on a 25 gap, so the rows sit on a 36 step —
     the tightest packing in the whole macket (§5.4). Every item in the
     column therefore carries the same 36 band (§5.3), and the areas meet
     exactly at the midpoint of each gap without overlapping. A heading that
     wraps is taller than 36, and `max()` keeps that item's own height
     instead: its area still ends at its own edge, 25 clear of its
     neighbour's. */
  .s-am1__item {
    display: block;
    --tap-h: 36px;
    color: var(--content-primary);
    text-decoration: none;
  }
  .s-am1__item > span { display: block; }
  .s-am1__item:focus-visible { outline: 3px solid var(--border-accent); }

  /* ======================================================================
     Block 2 — the article
     ====================================================================== */

  .am-block + .am-block { margin-top: var(--m-gap); }
  .am-block + .am-table,
  .am-table + .am-block { margin-top: var(--m-gap); }

  /* 3.2 The jump from the contents has to clear the pinned header. The same
     offset m-base.css puts on `:target`, set on the heading itself so a
     scripted scroll lands where a hash arrival does. */
  .am-block > h2 { scroll-margin-top: calc(var(--m-header-h) + var(--m-gap)); }

  .am-text { margin-top: var(--m-gap); }
  .am-text > * + * { margin-top: var(--m-gap); }

  /* Bulleted runs. The file holds each list as one text node with a disc
     marker; the marker sits 22.5 in, which is 1.5 of the 15px type. */
  .am-list {
    display: flex;
    flex-direction: column;
    gap: var(--m-gap);
    padding-left: 22.5px;
    list-style: disc;
  }
  .am-list li { list-style: disc; }

  /* Links in the running text: Vista blue 1, the weight from the type class
     on the anchor itself. No hover state — §9 and §15. */
  .am-link {
    color: var(--vista-blue-1);
    text-underline-offset: 3px;
  }
  .am-link:focus-visible { text-decoration: underline; }

  .am-act { margin-top: var(--m-gap); }

  /* --- 11 The comparison carousel — `Blog_A1_Table_m` 1564:12630 -------
     The strip of three, then the card 15 under it. Swipe, with scroll-snap
     doing the landing; no autoplay and no wrap.                           */
  .am-table__tabs {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 17px var(--m-gap-tight);
  }
  /* `Autors_Filter_Button`: 15 of padding, a 3px stroke drawn inside the box
     and an 11-tall trimmed cap — 47. It is an indicator, not a button: it
     takes no touch area and answers no tap (5.7, and `m-indicator` in
     m-base.css turns pointer events off for the strip). */
  .am-table__tab {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--m-gap-mid);
    border: 3px solid var(--rich-black-3);
    color: var(--content-primary);
    text-align: center;
    white-space: nowrap;
  }
  .am-table__tab > span { display: block; }
  .am-table__tab.is-on {
    border-color: var(--rich-black-1);
    background: var(--surface-inverse);
    color: var(--content-on-inverse);
  }

  .am-table__track {
    display: flex;
    gap: var(--m-gutter);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    margin-top: var(--m-gap-mid);
  }
  .am-table__track::-webkit-scrollbar { display: none; }
  .am-table__slide {
    flex: 0 0 100%;
    min-width: 0;
    scroll-snap-align: start;
    scroll-snap-stop: always;
  }

  .am-table__rows {
    display: grid;
    gap: var(--m-gap);
    margin: var(--m-gap) 0 0;
  }
  /* The hairline is drawn rather than bordered so it adds no height: the row
     box stays label + 15 + value + 15, and the 25 grid gap lands the next
     row where the file puts it. */
  .am-table__row {
    position: relative;
    display: grid;
    gap: var(--m-gap-mid);
    padding-bottom: var(--m-gap-mid);
  }
  .am-table__row::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: var(--line-width);
    background: var(--rich-black-1);
  }
  .am-table__row dd { margin: 0; }

  /* ======================================================================
     Block 3 — the team card
     ====================================================================== */

  /* `Group 124`, 302 x 125: a Columbia blue 5 band with the mark centred in
     it. The mark's own file already carries that ground, so the two meet
     without a seam and the band simply extends it to the full 302. */
  .s-am3__mark {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 125px;
    background: var(--columbia-blue-5);
  }
  .s-am3__mark img {
    width: 144px;
    height: 125px;
    object-fit: contain;
  }

  .s-am3__name { margin-top: var(--m-gap); }
  .s-am3__line { margin-top: var(--m-gap-mid); }
  /* 61 tall across the 302, its nearest neighbour 25 above, so `m-tap`
     resolves to its own bounds. */
  .s-am3__act  { margin-top: var(--m-gap); }

  /* ======================================================================
     Block 4 — the related articles
     ====================================================================== */

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

  /* ======================================================================
     Block 5 — the Discovery Sprint
     ====================================================================== */

  .s-am5__art { position: relative; }
  .s-am5__photo {
    display: block;
    width: 100%;
    height: 198px;
    object-fit: cover;
  }
  /* `Group 90` at y 80 of the 198. The one place the pair swaps colours: the
     script is the page ground and the word is amber, because the plate under
     them is a photograph. */
  .s-am5__lockup {
    position: absolute;
    left: 0;
    right: 0;
    top: 80px;
  }
  .s-am5__lockup .bm-lockup__script { color: var(--content-on-inverse); }
  .s-am5__lockup .bm-lockup__word   { color: var(--content-accent); }

  /* `Frame 367`, a Vista blue 1 plate 352 x 205: 25 of padding, the lead,
     15, the line, 50, the price, 25. */
  .s-am5__panel {
    margin-top: var(--m-gap);
    padding: var(--m-gap);
    background: var(--surface-brand);
    color: var(--content-on-brand);
    text-align: center;
  }
  .s-am5__line  { margin-top: var(--m-gap-mid); }
  /* The one line on the plate the file draws in the page ground rather than
     in Rich black 1 — sampled off the rendered frame 1564:13219. */
  .s-am5__price {
    margin-top: var(--m-gap-block);
    color: var(--content-on-inverse);
  }

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

  /* ======================================================================
     Block 6 — three ways to start, and the form
     ====================================================================== */

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

  .s-am6__cards {
    display: grid;
    gap: var(--m-gap-mid);
    margin-top: var(--m-gap);
  }
  .s-am6__card-title { text-align: center; }
  .s-am6__card-line  { margin-top: var(--m-gap); text-align: center; }
  /* 61 tall and never narrower than 156; the nearest other target is the
     button on the next card, 25 + 50 of padding away. */
  .s-am6__card-act   { margin-top: var(--m-gap); }

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

  /* --- 12 `Form_Pas`, 352 x 592 ---------------------------------------
     25 of padding on the brand surface, the label 10 above its field (the
     tightest gap the file uses), the three groups 25 apart, the button 25
     under the last field and the state line 25 under the button.
     25 + 542 + 25 = 592, and every one of those numbers is a gap rather
     than a height set here. */
  .s-am6__form {
    margin-top: var(--m-gap);
    padding: var(--m-gap);
    background: var(--surface-brand);
    color: var(--content-on-brand);
  }
  .s-am6__fields { display: grid; gap: var(--m-gap); }
  .s-am6__field  { display: grid; gap: var(--m-gap-tight); margin: 0; }

  /* `Form_cards_mobile`: Small 302 x 41, Big 302 x 225. */
  .s-am6__input {
    width: 100%;
    height: 41px;
    padding-inline: var(--m-gap-tight);
    border: 0;
    background: var(--surface-page);
    color: var(--content-primary);
  }
  .s-am6__input--big {
    height: 225px;
    padding-block: var(--m-gap-tight);
    resize: vertical;
  }
  .s-am6__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. Written here
     rather than left to the shared `:focus-visible` because the field's own
     background is declared above and would win over it. The offset is taken
     off so the ring sits on the field's edge and stays inside the form's 25
     of padding. */
  .s-am6__input:focus-visible {
    background: var(--editorial-white-4);  /* 2026-10-27 · review 20 Oct, item 9: the page's Editorial White 4, never #FFFFFF */
    outline: 3px solid var(--border-accent);
    outline-offset: 0;
  }

  .s-am6__foot { margin-top: var(--m-gap); text-align: center; }
  /* 113 x 61 — 25, the 11 cap, 25 — so the width comes from the label. Its
     nearest neighbour is the last field, 25 above, so `m-tap` resolves to
     the button's own 61 and adds nothing. */
  .s-am6__submit { width: fit-content; margin-inline: auto; }
  .s-am6__submit[disabled] { cursor: default; }

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

  /* --- Carried over from articles 4-6, where these two were measured -----
     The tab strip is packed from the left in every table set in the file —
     the rows end at 352 / 221 / 253 / 323 inside the same 352 — not spread
     to the window edges. With three tabs the slack is small, which is why it
     went unnoticed here first. 15 is the gap §4 names. */
  .am-table__tabs { justify-content: flex-start; gap: var(--m-gap-mid); }

  /* The closing `Button_form_m` and the line under it: 25 in the file. The
     pair rules above only cover block to block, and `p` is reset to margin 0
     in base.css, so without this the line sits flush against the button. */
  .am-act + .am-block { margin-top: var(--m-gap); }
}

/* ===== insights/contact/m1.css.css ===== */
/* ==========================================================================
   Contact mobile — block 1, the photograph and the three ways to reach us.
   Figma: `Contact_m` 1609:14955 / "Section 1" 1609:15268, 402 x 1179.

     photo        402 x 283, full window, at the top of the block
     band         Vista Blue, full window, from the foot of the photo down;
                  25 of padding over the lockup and 25 under the last card
     lockup       "WITH A CONVERSATION" with the script "Start" drawn over
                  it, both centred; the Mulish word hangs 15 below the top of
                  the group, which the two-line word makes 64 tall
     lede         15 under the lockup, centred
     cards        25 under the lede; three 352 x 221 plates, 15 apart, each
                  with 25 of padding, the title, the body 25 under it and a
                  `Button_form` 25 under that

   This file also carries the vocabulary the screen's three blocks share —
   the heading lockup (`Group 89`) and the button (`Button_form`). They are
   one component each in the file, so they are written once here rather than
   copied into three stylesheets.

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

@media (max-width: 767.98px) {

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

     The heading lockup — Figma `Group 89`.
     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 —
     the two-line words on blocks 1 and 2 make the group 64. That is the
     file's own rule and it needs no measured height here.

     Every lockup on this screen is centred.
     ====================================================================== */
  .cm-lockup {
    display: grid;
    font: inherit;
    text-align: center;
  }
  .cm-lockup > * { grid-area: 1 / 1; }
  .cm-lockup__word { margin-top: var(--m-gap-mid); }
  .cm-lockup__script {
    color: var(--content-accent);
    pointer-events: none;
  }

  /* ======================================================================
     Shared: `Button_form`, 61 tall — 25 of padding, an 11-tall trimmed cap,
     and 25 again. The file's 260 / 157 / 142 widths are the three labels
     plus that padding, so the width is never set here.

     A 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.

     5. The button is 61 tall and no neighbour comes within 44 of it — the
     cards are 15 apart and 221 tall — so `m-tap` resolves to the button's
     own bounds on both axes and adds nothing visible.
     ====================================================================== */
  .cm-btn {
    display: inline-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;
  }

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

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

  /* --- 3.1 Background lines --------------------------------------------
     `BackgroundLines` 1609:14956: four lines at 0, 33.33, 66.67 and 100 per
     cent of the working area, starting under the header and running the
     length of the screen. The file draws one continuous set, 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, exactly as the file stacks it under `Sections`.

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

  /* --- The photograph ---------------------------------------------------
     Full window below 430. Above it the window is wider than the design
     ever gets, so the picture stops at the 430 column and centres with the
     rest of the page instead of stretching to a size the macket does not
     have. Its upper corners are transparent and the page ground shows
     through them, as the file draws it.

     2026-10-27 · mobile review 20 Oct, item 15: a light line showed between
     the picture and the blue band. The cause was in the file, not the
     layout: the export's last pixel row was 13 % opaque edge to edge, so the
     page ground showed through it. assets/m-contact-hero.webp?v=34ef3484 now repeats
     the row above in that place; the photograph meets the band directly.  */
  .s-cm1__photo {
    position: relative;
    width: 100%;
    max-width: var(--m-max);
    margin-inline: auto;
  }

  /* --- The surface ------------------------------------------------------ */
  .s-cm1__band {
    padding-block: var(--m-gap);
    background: var(--surface-brand);
    color: var(--content-on-brand);
  }

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

  /* --- The three cards -------------------------------------------------- */
  .s-cm1__ways {
    display: grid;
    gap: var(--m-gap-mid);
    margin-top: var(--m-gap);
  }
  .s-cm1__way {
    padding: var(--m-gap);
    background: var(--surface-page);
    color: var(--content-primary);
    text-align: center;
  }
  /* `Frame 466`, the one inverse plate on the screen. */
  .s-cm1__way--inverse {
    background: var(--surface-inverse);
    color: var(--content-on-inverse);
  }

  /* The heading carries its type class itself, so nothing is declared for it
     here: a `font` shorthand written after base.css would win over the class
     and take the 1000 weight back off. */
  .s-cm1__way-body  { margin-top: var(--m-gap); }
  .s-cm1__way-act   { margin-top: var(--m-gap); }

}

/* ===== insights/contact/m2.css ===== */
/* ==========================================================================
   Contact mobile — block 2, the form.
   Figma: "Section 2" 1609:15295, 402 x 745; `Form_Pas` 1609:15276, 352 x 592
   — the same component the FAQ and home screens carry.

     lockup      Group 89, a two-line word under the script
     lede        15 under the lockup, centred
     form        25 under the lede, the full 352 working area

   Form_Pas: 25 of padding on the brand surface, the label 10 above its field
   (the tightest gap the file uses), the three groups 25 apart, the button 25
   under the last field and the state line 25 under the button.
   25 + 542 + 25 = 592, and every one of those numbers comes from a gap, not
   from a height set here.
   ========================================================================== */

@media (max-width: 767.98px) {

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

  /* --- 12 The form ------------------------------------------------------ */
  .s-cm2__form {
    margin-top: var(--m-gap);
    padding: var(--m-gap);
    background: var(--surface-brand);
    color: var(--content-on-brand);
  }

  .s-cm2__fields {
    display: grid;
    gap: var(--m-gap);
  }
  .s-cm2__field {
    display: grid;
    gap: var(--m-gap-tight);
  }

  /* `Form_cards_mobile`: Small 302 x 41, Big 302 x 225. */
  .s-cm2__input {
    width: 100%;
    height: 41px;
    padding-inline: var(--m-gap-tight);
    border: 0;
    background: var(--surface-page);
    color: var(--content-primary);
  }
  .s-cm2__input--big {
    height: 225px;
    padding-block: var(--m-gap-tight);
    resize: vertical;
  }
  .s-cm2__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. Written
     here rather than left to the shared `:focus-visible` because the field's
     own background is declared later in the bundle and would win over it.
     The offset is taken off so the ring sits on the field's edge and stays
     inside the form's 25 of padding. */
  .s-cm2__input:focus-visible {
    background: var(--editorial-white-4);  /* 2026-10-27 · review 20 Oct, item 9: the page's Editorial White 4, never #FFFFFF */
    outline: 3px solid var(--border-accent);
    outline-offset: 0;
  }

  .s-cm2__foot {
    margin-top: var(--m-gap);
    text-align: center;
  }
  /* `Button_form` inside the form is 113 x 61 — 25, the 11 cap, 25 — so the
     width comes from the label rather than being set here. Its nearest
     neighbour is the last field, 25 above, so `m-tap` resolves to the
     button's own 61 and adds nothing. */
  .s-cm2__submit {
    display: inline-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;
    cursor: pointer;
  }
  /* A second tap while the request is in flight must be impossible. */
  .s-cm2__submit[disabled] { cursor: default; }

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

}
