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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* bleed:left / bleed:right — out past one margin only, never both.
   --bleed-stop is the macket coordinate of the edge that stays put,
   expressed as a share of the working area.                               */
.is-bleed-left {
  margin-left: calc(50% - 50vw);
  margin-right: var(--bleed-stop, 0%);
}
.is-bleed-right {
  margin-right: calc(50% - 50vw);
  margin-left: var(--bleed-stop, 0%);
}

/* --- 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;
  inset: 0;
  pointer-events: none;
  z-index: 0;
}
.gridlines i {
  position: absolute;
  top: 0;
  bottom: 0;
  width: var(--line-width);
  background: var(--line-color);
  left: calc(var(--n) * var(--line-step));
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* --- 3. Logo ------------------------------------------------------------ */
.site-header__logo {
  position: absolute;
  z-index: 2;
  left: 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.  */
.site-header__nav {
  position: absolute;
  inset: 0;
  z-index: 2;
  /* The nav box covers the whole header, including the logo. It is
     transparent but would still take the clicks, so it is made inert and
     only the menu items themselves are given back to the pointer. */
  pointer-events: none;
}

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

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

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

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

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

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

   It is an OVERLAY, not flow: on Services the hero deliberately starts at
   110 and runs up behind the whole header. A page whose first block is
   meant to start below the open row writes that into its own --gap.     */
.site-header__sub {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: 52px;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-fast) ease, visibility var(--t-fast);
  /* The nav box above is inert so it cannot swallow clicks meant for the
     page; this row is its own box and takes its own. */
  pointer-events: auto;
}

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

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

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

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

/* 1 — held open by the page */
.site-header[data-subnav="services"] .site-header__sub[data-group="services"],
.site-header[data-subnav="results"]  .site-header__sub[data-group="results"],
.site-header[data-subnav="about"]    .site-header__sub[data-group="about"] {
  opacity: 1;
  visibility: visible;
}

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

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

/* The group's own piece of the plate: from its first line to one past its
   last, so the blur ends on a line and not in the middle of a cell. */
.site-header__sub-plate {
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--from) * var(--line-step));
  width: calc(var(--span) * var(--line-step) + var(--line-width));
  /* The file gives this the same Editorial White 4 at 75 % as the bar above
     it, but it only ever draws the header over the cream hero. On a live
     page the sticky header travels over the blue and amber bands, and there
     a 75 % plate that covers three columns and not the rest reads as a grey
     smear cut through the headline behind it — the bar gets away with it
     because it spans the full width, this row does not. So the row's own
     plate is opaque: the two links stay legible over anything, and the strip
     reads as a panel that belongs to the menu instead of a smudge. */
  background: var(--surface-page);
}

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

/* The seven lines continue down through the whole row, group or not. */
.site-header__sub-lines { z-index: 1; }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* ===== services/s1.css ===== */
/* ==========================================================================
   Section 1 — "Five formats. One standard." hero
   Figma: Services / node 445:3950 "Section 1", 1440 x 968, absolute y 110.

   Two items on the 25 gutter: the masked photograph (708) runs off the left
   edge of the window, the copy column (657 — six columns) ends on the right
   margin. 708 + 25 + 657 = 1390 = 1440 - 50, so the photograph's right edge
   is always one gutter left of the copy column, whatever the window does.

   The block starts one pixel ABOVE the header's box (110 against 111), which
   is why its --gap is -1: the photograph is meant to run up behind the
   blurred plate rather than start below it.
   ========================================================================== */

.s-s1 {
  position: relative;
  height: 968px;
}

.s-s1__inner {
  position: relative;
  height: 100%;
}

/* --- Photograph ---------------------------------------------------------
   bleed:left. The fixed edge is not a share of the working area here but a
   fixed distance from it: the copy column is 657 wide and the gutter is 25,
   so the photograph always stops 682 short of the working area's right edge.
   Written as a length in --bleed-stop, which .is-bleed-left feeds straight
   into margin-right.

   The export (444:3947, rendered whole with contentsOnly) carries its own
   alpha: the amber outline is a masked shape in the artwork, not a CSS
   overlay, and everything outside the cut is transparent, so the page
   background shows through instead of a baked-in colour.                   */
.s-s1__art {
  --bleed-stop: 682px;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 968px;
  display: flex;
  justify-content: flex-end;
  overflow: hidden;
  z-index: 1;
}

/* The artwork keeps its own 708 x 968 and hangs on the slot's right edge —
   the edge that carries the 25 gutter to the copy. Below 1440 the slot is
   narrower than the artwork and the street at the left is what the flex row
   cuts; the reader and the amber outline never move. Above 1440 the slot is
   wider and the page background shows beyond the photograph's left edge,
   which is preferred over scaling a photograph up or cropping his feet. */
.s-s1__photo {
  flex: 0 0 auto;
  width: 708px;
  height: 968px;
  max-width: none;
}

/* --- Copy ---------------------------------------------------------------
   Frame 87: 657 wide at y 275. Heading block 195, then 50, then the lede.  */
.s-s1__copy {
  position: absolute;
  top: 275px;
  right: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 50px;
  width: 49.0299%;             /* 657 / 1340 — six columns with the gutters */
}

/* --- Heading ------------------------------------------------------------
   Two lines. The Comforter word lies over the Mulish word in one grid cell;
   the Mulish word sits 50 down inside the 85-tall cell. The second line is
   430 wide (three columns) and pushed to the right edge of the column.     */
.s-s1__title {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--layout-gutter);
  font: inherit;
}

.s-s1__line {
  display: grid;
  width: 100%;
}

.s-s1__line--narrow {
  width: 65.4489%;             /* 430 / 657 */
}

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

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

.s-s1__script {
  color: var(--content-accent);
  /* The handwriting paints over the Mulish word. */
  z-index: 1;
}

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

/* ===== services/s2.css ===== */
/* ==========================================================================
   Section 2 — "Compare the formats"
   Figma: Services / node 449:4122 "Section 2", 1440 x 1087, absolute y 1228.

   Vertical budget, read off the file:
     0    heading block  (Comforter over Mulish, 85) ............... 85
     110  subheading, two lines ................................... 49
     184  full-window rule, 3px, centred on the coordinate
     209  compare table ......................................... 842
     1076 closing note ........................................... 11
   85 + 25 + 49 + 23.5 + 3 + 23.5 + 842 + 25 + 11 = 1087.

   The table is a real table: eleven rows of six columns, the first column a
   row header. The row fills run the full window width (449:4014 and its
   siblings are 1440 wide) while the text stays on the working area's grid,
   so the fill lives on the <tr> and the margins live in the end cells'
   padding.
   ========================================================================== */

/* --- Heading ------------------------------------------------------------ */
.s-s2__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--layout-gutter);
  text-align: center;
}

.s-s2__title {
  display: grid;
  width: 100%;
  max-width: 708px;
  font: inherit;
}

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

.s-s2__title-main {
  margin-top: 50px;
  color: var(--content-primary);
}

.s-s2__title-accent {
  color: var(--content-accent);
  z-index: 1;                  /* the handwriting paints over the Mulish word */
}

.s-s2__sub {
  width: 100%;
  max-width: 885px;
  color: var(--content-primary);
}

/* --- The rule -----------------------------------------------------------
   Line 29, 3px Rich Black 1, centred on y 184 and running the full window.
   Half of its weight falls either side of that coordinate, which is why the
   air above and below it is 23.5 and not 25.                               */
.s-s2__rule {
  height: 3px;
  margin-block: 23.5px;
  background: var(--border-strong);
}

/* --- Table --------------------------------------------------------------
   The table sits on the working area, so the page margin stays 50 at every
   width, and the six content columns of 202.5 stand on the 25 gutter:
   6 x 202.5 + 5 x 25 = 1340. The gutter is 12.5 of padding on each side of
   a cell, dropped on the two outer edges, which makes the column boxes
   215 / 227.5 / 227.5 / 227.5 / 227.5 / 215.

   Those are written as percentages of the table and not as calc(): under
   table-layout: fixed Chrome silently drops a column width that mixes a
   percentage with a length and falls back to six equal columns.            */
.s-s2__table {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
  text-align: center;
}

/* table-layout: fixed takes its columns from the first row's cells. */
.s-s2__row--head > * {
  width: 16.9776%;             /* 227.5 / 1340 */
}

.s-s2__row--head > *:first-child,
.s-s2__row--head > *:last-child {
  width: 16.0448%;             /* 215 / 1340 */
}

.s-s2__table th,
.s-s2__table td {
  position: relative;
  padding: 25px 12.5px;
  vertical-align: middle;
  color: var(--content-primary);
}

.s-s2__table th:first-child,
.s-s2__table td:first-child {
  padding-left: 0;
}

.s-s2__table th:last-child,
.s-s2__table td:last-child {
  padding-right: 0;
}

/* The header row has no fill, so the 25 the file puts between it and the
   first band (the table is 842 = 61 + 25 + 756) is carried as its own bottom
   padding rather than by a spacer row.                                     */
.s-s2__table .s-s2__row--head > * {
  padding-bottom: 50px;
}

/* The label column reads left; every format column reads centred. */
.s-s2__label {
  text-align: left;
}

/* Alternating bands. Row 1 (Price) carries the fill, and every other row
   after it — Rich black/3 on the page's Editorial White 4. The rows in the
   file are 1440 wide while their text sits on the working area, so the fill
   is painted by the row itself as a band that runs to both window edges and
   the table stays on the grid. It is drawn behind the row's own text but
   still inside the section's layer, so the page background never covers it. */
.s-s2__table tbody tr {
  position: relative;
}

.s-s2__table tbody tr:nth-child(odd)::after {
  content: "";
  position: absolute;
  z-index: -1;
  top: 0;
  bottom: 0;
  left: calc(50% - 50vw);
  width: 100vw;
  background: var(--rich-black-3);
}

/* --- Yes / no marks -----------------------------------------------------
   The glyphs are decoration; the meaning is the text next to them, which is
   read out and never shown. In the file the check sits in an 18-tall box
   against the dash's 11, which is what makes those rows 68 instead of 61,
   so the box is given here rather than left to whichever font happens to
   supply U+2713.                                                           */
.s-s2__cell--mark {
  line-height: 0;
}

.s-s2__yes,
.s-s2__no {
  display: inline-block;
}

.s-s2__yes {
  height: 18px;
  line-height: 18px;
}

.s-s2__no {
  height: 11px;
  line-height: 11px;
}

/* Read by a screen reader, never shown — the row fill must stay unbroken. */
.s-s2__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  white-space: nowrap;
  clip-path: inset(50%);
}

/* --- Closing note ------------------------------------------------------- */
.s-s2__note {
  margin-top: var(--layout-gutter);
  text-align: right;
  color: var(--content-primary);
}

/* ===== services/s3.css ===== */
/* ==========================================================================
   Section 3 — "The Five formats in detail"
   Figma: Services / node 460:5024 "Section 3", 1340 x 1560, absolute y 2415.

   Two columns that fill the working area exactly: the title block (658, six
   columns and a gutter) on the left and the card stack (682) on the right.

   The stack is five rows of 682 x 360 placed every 300, so each row sits 60
   into the one above it — which is what lets a card's name line run beside
   the previous card's picture instead of under it. The card itself is 341,
   three columns; the other half of the row is the plain rectangle the file
   draws (460:5010 and its siblings), which carries no fill and is simply
   the empty half.

   Card component Service_S3_Card_1..5 (sets around 460:4456+), variants Pas
   and Act. Act is demonstrated in Service_S3_Card_2_act_zone (1050:10527):
   a 658-wide Rich black 3 plate opens to the LEFT of the 341 column, its top
   flush with the picture's top, and the whole card becomes 999 wide. The
   two open instances there sit 25 apart rather than the passive stack's -60,
   so an open row hands the next row a 25 gap.
   ========================================================================== */

.s-s3__inner {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
}

/* --- Title, six columns wide, its contents pushed to the right edge ------
   50 + 85 heading + 25 + 18 + 50 = 228.                                    */
.s-s3__title {
  flex: 0 0 49.1045%;          /* 658 / 1340 */
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--layout-gutter);
  padding-block: 50px;
}

.s-s3__lockup {
  display: grid;
  width: 82.6748%;             /* 544 / 658 */
  font: inherit;
}

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

.s-s3__word {
  margin-top: 50px;
  color: var(--content-primary);
}

.s-s3__script {
  color: var(--content-accent);
  z-index: 1;                  /* the handwriting paints over the Mulish word */
}

.s-s3__sub {
  width: 34.6505%;             /* 228 / 658 */
  color: var(--content-primary);
}

/* --- The stack ---------------------------------------------------------- */
.s-s3__cards {
  flex: 0 0 50.8955%;          /* 682 / 1340 */
  /* The open panel hangs left, over the title column, so the stack is the
     upper layer of the two. */
  position: relative;
  z-index: 1;
}

.s-s3__row {
  position: relative;
  display: grid;
  /* minmax(0, …) so the 658 plate in the cell cannot widen its own track. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: start;
  column-gap: 0;
}

/* Every row after the first is pulled 60 up: 360 tall on a 300 step. */
.s-s3__row + .s-s3__row {
  margin-top: -60px;
}

/* An open row is a full card, not an overlapped one: the act zone puts 25
   between two open instances. */
.s-s3__row.is-open + .s-s3__row {
  margin-top: var(--layout-gutter);
}

/* The card takes one half of the row; which half alternates down the stack.
   The empty half is the file's plain rectangle and needs no element.       */
.s-s3__row--right .s-s3__card,
.s-s3__row--right .s-s3__panel {
  grid-column: 2;
}

.s-s3__row--left .s-s3__card,
.s-s3__row--left .s-s3__panel {
  grid-column: 1;
}

.s-s3__card,
.s-s3__panel {
  grid-row: 1;
  min-width: 0;
}

/* --- Card: name line, then the picture ---------------------------------- */
.s-s3__card {
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
  position: relative;
  z-index: 1;
}

.s-s3__head {
  font: inherit;
}

/* 35 tall: the number is Heading Wide Light at 50 and sets the line. */
.s-s3__trigger {
  display: flex;
  /* The name sits at the bottom of the number's 35-tall box — Frame 95 hangs
     both on the same alphabetic baseline, which the cap-height trim gives
     for free once the two are bottom-aligned. */
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--layout-gutter);
  width: 100%;
  padding: 0 var(--layout-gutter);
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
}

.s-s3__name {
  color: var(--content-primary);
  transition: color var(--t-fast) ease;
}

.s-s3__num {
  flex: 0 0 auto;
  color: var(--vista-blue-1);
  text-align: right;
  transition: color var(--t-fast) ease;
}

.s-s3__trigger:hover .s-s3__name,
.s-s3__trigger:hover .s-s3__num,
.s-s3__trigger:focus-visible .s-s3__name,
.s-s3__trigger:focus-visible .s-s3__num {
  color: var(--content-accent);
}

.s-s3__pic {
  width: 100%;
  height: 300px;
  object-fit: cover;
}

/* --- Act: the 658 plate that opens to the left --------------------------
   The panel shares the card's grid cell, so the row measures its height and
   the rows below are pushed down; the negative margin then moves it out to
   the left without changing that measurement. Animated on grid-template-rows
   so the real content height is measured rather than guessed.              */
.s-s3__panel {
  display: grid;
  grid-template-rows: 0fr;
  width: var(--s3-panel-w);
  margin-top: 60px;            /* the plate's top meets the picture's top */
  margin-left: calc(var(--s3-panel-w) * -1);
  justify-self: start;
  transition: grid-template-rows var(--t-base) ease;
  z-index: 2;
}

/* The plate is 658 while there is room for it, and never further left than
   the working area's own edge. The room is a fixed share of the grid cell:
   658 / 341 of it for a card on the left half, 999 / 341 for one on the
   right, because both the cell and the room are the same share of the
   working area at every width.                                            */
.s-s3__row--left .s-s3__panel {
  --s3-panel-w: min(658px, 192.9619%);
}

.s-s3__row--right .s-s3__panel {
  --s3-panel-w: min(658px, 292.9619%);
}

.s-s3__panel-inner {
  overflow: hidden;
  visibility: hidden;
  transition: visibility 0s linear var(--t-base);
}

.s-s3__row.is-open .s-s3__panel {
  grid-template-rows: 1fr;
}

.s-s3__row.is-open .s-s3__panel-inner {
  visibility: visible;
  transition-delay: 0s;
}

/* 25 of padding, and a 608 content column whose own blocks sit 25 apart. */
.s-s3__plate {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--layout-gutter);
  padding: var(--layout-gutter);
  background: var(--rich-black-3);
  color: var(--content-primary);
}

/* The two keys run the full 608; everything they introduce is 544 and hangs
   on the right edge, which is the 64 indent the file draws.                */
.s-s3__key {
  width: 100%;
  font: inherit;
}

.s-s3__for,
.s-s3__list {
  width: 89.4737%;             /* 544 / 608 */
}

.s-s3__list {
  list-style: disc;
  padding-left: 22.5px;
}

.s-s3__foot {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--layout-gutter);
  width: 100%;
}

.s-s3__terms {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--layout-gutter);
  width: 63.4868%;             /* 386 / 608 */
}

.s-s3__price {
  width: 77.4611%;             /* 299 / 386 */
}

/* Button_form: Amber 4, 25 all round, label on its cap height — 25 + 11 + 25
   is the 61 of the macket. Hover empties the fill and keeps a 3px stroke,
   the site-wide behaviour set in tokens.css.                               */
.s-s3__button {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--layout-gutter);
  background: var(--action-fill);
  color: var(--content-on-accent);
  text-align: center;
  transition: background-color var(--t-fast) ease, box-shadow var(--t-fast) ease;
}

.s-s3__button-label {
  white-space: nowrap;
}

.s-s3__button:hover {
  background: var(--action-fill-hover);
  box-shadow: inset 0 0 0 3px var(--action-border-hover);
}

/* ===== services/s4.css ===== */
/* ==========================================================================
   Section 4 — "Still deciding which format fits?" / Discovery Sprint
   Figma: Services / node 483:2349 "Section 4", 1440 x 1014, absolute y 3975.

   The one block on this screen that carries its own fill — Vista Blue 1,
   full window width — and the one whose air above it is zero, because the
   150 the eye reads as a gap is the block's own top padding (Frame 105 sits
   at y 150 inside it). So the padding stays here and --gap is 0: the fill
   is meant to begin exactly where the card stack above it ends.

   150 + (85 title + 100 + 579 body) + 100 = 1014.
   ========================================================================== */

.s-s4 {
  background: var(--surface-brand);
  padding-block: 150px 100px;
  color: var(--content-on-brand);
}

.s-s4__inner {
  display: flex;
  flex-direction: column;
  gap: 100px;
}

/* --- Title, both lines on the right edge of the working area ------------ */
.s-s4__title {
  display: grid;
  width: 100%;
  text-align: right;
  font: inherit;
}

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

.s-s4__title-main {
  margin-top: 50px;
  color: var(--content-primary);
}

/* On the blue the handwriting is Editorial White 4, not the amber it is
   everywhere else on this screen. */
.s-s4__title-accent {
  color: var(--editorial-white-4);
  z-index: 1;
}

/* --- Body: photograph and copy, 1197 of the 1340, left aligned ---------- */
.s-s4__body {
  display: flex;
  align-items: flex-start;
  gap: var(--layout-gutter);
  width: 100%;
  max-width: 1197px;
}

/* The slot is 628 — what the layout counts — while the artwork is 638 and
   starts 10 to the left of it, which is how the file draws the amber outline
   reaching past the photograph's edge (the mask sits at x -10, the
   photograph at 0). The export carries its own alpha, so the blue shows
   through the cut rather than being baked into the file. */
.s-s4__art {
  flex: 1 1 628px;
  min-width: 0;
}

.s-s4__photo {
  width: calc(100% + 10px);
  height: auto;
  max-width: none;
  margin-left: -10px;
}

.s-s4__copy {
  flex: 0 1 544px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 50px;
}

/* 514 of the 544, hung on the right edge. */
.s-s4__lead {
  width: 514px;
  max-width: 100%;
  color: var(--content-primary);
}

/* Frame 100 is indented 114 into the copy column. Its text boxes are drawn
   459 wide, 29 past the column they sit in; that overhang is dropped here
   so the paragraph cannot reach past the working area once the window is
   under 1440 — it wraps to one more line instead, and the body's height is
   set by the 579 photograph either way. */
.s-s4__detail {
  display: flex;
  flex-direction: column;
  gap: 50px;
  width: min(459px, calc(100% - 114px));
  margin-right: auto;
  margin-left: 114px;
  color: var(--content-primary);
}

.s-s4__cta {
  width: min(430px, 100%);
  margin-right: auto;
  margin-left: 114px;
}

/* Button_form: Amber 4, 25 all round, the label on its cap height so
   25 + 11 + 25 gives the 61 of the macket. */
.s-s4__button {
  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-s4__button-label {
  white-space: nowrap;
}

.s-s4__button:hover {
  background: var(--action-fill-hover);
  box-shadow: inset 0 0 0 3px var(--action-border-hover);
}

/* ===== services/s5.css ===== */
/* ==========================================================================
   Section 5 — "Questions about pricing and formats"
   Figma: Services / node 483:2674 "Section 5", 885 x 603, absolute y 5139.

   Card component Sevice_S5_Card, set 483:2509 — ten variants, a Pas and an
   Act for each of the five rows. The Act variants (483:2530, 2536, 2542,
   2548, 2554) are where the answers live; nothing in the passive state shows
   them. Act keeps the Rich black 3 plate and the question exactly where they
   were, turns the chevron up, and adds the answer in a 607 column with 50
   under it — collapsed 61, open 166 for a two-line answer and 185 for three.

   148 title + 50 + (5 x 61 + 4 x 25) = 603.
   ========================================================================== */

/* Eight columns with their gutters, centred in the working area: two columns
   and a gutter each side. 885 at the 1440 reference.                        */
.s-s5__grid {
  row-gap: 50px;
}

.s-s5__intro,
.s-s5__list {
  grid-column: 3 / span 8;
}

/* --- Heading ------------------------------------------------------------
   The Comforter word lies over the Mulish heading in one grid cell, and the
   Mulish heading sits 50 down inside it. Two lines of 50 give the 148.     */
.s-s5__intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.s-s5__title {
  display: grid;
  width: 100%;
  max-width: 753px;
  font: inherit;
}

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

.s-s5__title-main {
  margin-top: 50px;
  color: var(--content-primary);
}

.s-s5__title-accent {
  color: var(--content-accent);
  z-index: 1;                  /* the handwriting paints over the Mulish word */
}

/* --- Rows ---------------------------------------------------------------
   Collapsed row is 61: 25 + cap height 11 + 25. Gap between rows 25.
   The plate is Rich black 3 on the page's own background — the homepage FAQ
   inverts this, Editorial White 4 on a blue fill.                          */
.s-s5__list {
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
}

.s-s5__item {
  background: var(--rich-black-3);
}

.s-s5__question {
  font: inherit;
}

.s-s5__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--layout-gutter);
  width: 100%;
  padding: 25px 25px 25px 50px;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
}

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

/* The chevron is Main_S11_Arrows: a 45-degree rule, 21.213 x 10.607. */
.s-s5__chevron {
  flex: 0 0 auto;
  width: 21.213px;
  height: 10.607px;
  transition: transform var(--t-base) ease;
}

.s-s5__item.is-open .s-s5__chevron {
  transform: rotate(180deg);
}

/* --- Panel --------------------------------------------------------------
   Animated on grid-template-rows so the real content height is measured
   instead of guessed with a max-height. visibility keeps the collapsed
   answer out of the accessibility tree once the transition has finished. */
.s-s5__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--t-base) ease;
}

.s-s5__panel-inner {
  overflow: hidden;
  visibility: hidden;
  transition: visibility 0s linear var(--t-base);
}

.s-s5__item.is-open .s-s5__panel {
  grid-template-rows: 1fr;
}

.s-s5__item.is-open .s-s5__panel-inner {
  visibility: visible;
  transition-delay: 0s;
}

/* Open row: 25 + question 11 + 50 + answer + 50. 25 of the 50 between the
   question and the answer is the trigger's own bottom padding, which is what
   keeps the collapsed row at 61; the other 25 is here. The answer column is
   607 wide — 228 stays empty on the right.                                */
.s-s5__answer {
  padding: 25px 228px 50px 50px;
  color: var(--content-primary);
}

/* ===== services/s6.css ===== */
/* ==========================================================================
   Section 6 — three ways to start
   Figma: Services / node 495:2592 "Section 6", 1340 x 759, absolute y 5892.
   Card component: Service_S6_Card, instances 495:2566 / 495:2564 / 495:2565.
   Identical to the homepage s14 in copy, geometry, photographs and states —
   it is the same component placed on the same three-column row.
   ========================================================================== */

/* 159 heading + 50 + 550 cards = 759. No fill: the page background shows. */
.s-s6__inner {
  display: flex;
  flex-direction: column;
  gap: 50px;
}

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

/* --- Cards --------------------------------------------------------------
   Three 430 blocks with the 25 gutter: 430 * 3 + 25 * 2 = 1340 exactly, so
   the row is the whole working area.

   The basis is written as that share of the row rather than as the literal
   430, and it resolves to exactly 430 at the 1440 reference. Written as
   430px the row wraps the moment the working area drops below 1340 — the
   flow helper wraps on the base size before it shrinks — and the three
   cards would break to 2 + 1 anywhere under 1440, which is the band the
   layout is required to hold. The 0.02 is there so sub-pixel rounding
   cannot tip the line into a wrap.                                        */
.s-s6__cards {
  /* 430 is three columns with their gutters. Kept as the literal card width,
     not a calc that forces three across: the flow tag says the row wraps when
     the cards stop fitting, and the acceptance list is explicit that flow rows
     wrap rather than shrink. Same basis as s5 and s7. */
  --flow-basis: 430px;
}
/* --- Hover: the Service_S6_Card Hov variant -----------------------------
   The text panel swaps Rich Black 3 for Amber 4. Nothing else moves: the
   type stays Rich Black 1, the photograph and the button keep their place.
   :focus-within carries it to the keyboard, since the whole card is a
   target for the link inside it.                                           */
.s-s6__card {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 550px;
  background: var(--rich-black-3);
  transition: background-color var(--t-base) ease;
}

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

/* The text panel ends at 229 in the macket (41.64 % of 550). It is a floor,
   not a fixed height: below 1440 the card narrows, the title wraps onto
   more lines and the panel grows into the photo rather than over it.      */
.s-s6__panel {
  flex: 0 0 auto;
  min-height: 229px;
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
  padding: 50px 25px 25px;
}
/* No font reset on the title: it carries .t-intro-black, and resetting the
   h3 here would win on the cascade and undo the type class.              */
.s-s6__card-title,
.s-s6__card-line {
  color: var(--content-primary);
}

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

/* The button sits over the photo, 25 from the bottom and 25 from the right;
   its width is the label plus 25 of padding on each side, which is what
   makes the three buttons three different widths in the macket.           */
.s-s6__button {
  position: absolute;
  right: 25px;
  bottom: 25px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 25px;
  background: var(--action-fill);
  color: var(--content-on-accent);
  transition: background-color var(--t-fast) ease, box-shadow var(--t-fast) ease;
}
/* 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 anchor because only a
   flex item is a block container of its own text.                        */
.s-s6__button-label {
  white-space: nowrap;
}
.s-s6__button:hover {
  background: var(--action-fill-hover);
  box-shadow: inset 0 0 0 3px var(--action-border-hover);
}

/* ===== services/s15.css ===== */
/* ==========================================================================
   Section 15 — "Your book starts here" contact form
   Figma: Services / node 972:9768 "Section 15", 885 x 796, absolute y 6801 —
   the same 885 block, centred in the working area, as the homepage s15.
   Form component: Main_S14_Form, instance 972:9773, component set 1356:8297
   with the four states Default 152:994, Loading 1356:8298, Error 1356:8324,
   Send 1356:8351. Field plate: Main_S14_Form_text_card, set 144:914.
   ========================================================================== */

/* The heading block is 885 = eight columns with their gutters, centred:
   two columns and a gutter each side. The form is 657 = six columns, also
   centred, so it starts one column plus a gutter inside the heading.      */
.s-s15__grid {
  row-gap: 50px;
}
.s-s15__title {
  grid-column: 3 / span 8;
}
.s-s15__form {
  grid-column: 4 / span 6;
}

/* --- Heading ------------------------------------------------------------
   The Comforter word lies over the Mulish heading in one grid cell. The
   heading sits 50 down inside the 85-tall group; the accent starts at 0.  */
.s-s15__title {
  display: grid;
  justify-items: center;
  text-align: center;
  font: inherit;
}
.s-s15__title > * {
  grid-area: 1 / 1;
  width: 100%;
  max-width: 617px;
}
.s-s15__title-main {
  margin-top: 50px;
}
.s-s15__title-accent {
  color: var(--amber-4);
}

/* --- Form ---------------------------------------------------------------
   50 + 420 fields + 25 + 61 button + 44 + 11 status + 50 = 661.           */
.s-s15__form {
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
  padding: 50px 25px;
  background: var(--vista-blue-1);
}
.s-s15__fields {
  display: flex;
  flex-direction: column;
  gap: var(--layout-gutter);
}
.s-s15__field {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.s-s15__label {
  color: var(--content-on-brand);
}

/* --- Plates -------------------------------------------------------------
   Editorial White 4 plate, no border in the resting state. 15 of padding
   all round: 15 + cap height 11 + 15 = 41 for the two single-line fields. */
.s-s15__plate {
  width: 100%;
  border: 0;
  background: var(--editorial-white-4);
  color: var(--content-primary);
}
.s-s15__input {
  height: 41px;
  padding: 0 15px;
}
.s-s15__textarea {
  height: 225px;
  padding: 15px;
  resize: vertical;
}
.s-s15__plate::placeholder {
  color: var(--vista-blue-1);
  opacity: 1;
}

/* Focus is a white plate with a 3px Amber 4 stroke — the decision base.css
   already applies site wide. Here the stroke sits on the plate edge rather
   than 2 outside it, which is how Main_S14_Form_text_card draws its Act
   variants (144:911 small, 144:910 big).                                  */
.s-s15__plate:focus-visible {
  outline-offset: 0;
  background-color: var(--editorial-white-2);
}

/* --- Actions ------------------------------------------------------------ */
.s-s15__actions {
  display: flex;
  align-items: center;
  gap: var(--layout-gutter);
}
.s-s15__submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 25px;
  border: 0;
  background: var(--action-fill);
  color: var(--content-on-accent);
  cursor: pointer;
  transition: background-color var(--t-fast) ease, box-shadow var(--t-fast) ease;
}
/* 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-s15__submit-label {
  white-space: nowrap;
}
.s-s15__submit:hover:not([disabled]) {
  background: var(--action-fill-hover);
  box-shadow: inset 0 0 0 3px var(--action-border-hover);
}

/* The Loading variant leaves the button looking exactly as it does at rest,
   so nothing is restyled here — it is only made unusable.                 */
.s-s15__submit[disabled] {
  cursor: progress;
}

/* --- Status line --------------------------------------------------------
   At rest the reassurance line stands alone on the left. In the three other
   states the state word takes the left and the message takes the right.   */
/* 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-s15__status {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--layout-gutter);
  margin-top: 19px;
  color: var(--content-on-brand);
}
.s-s15__message {
  text-align: right;
}
.s-s15__hint[hidden],
.s-s15__state[hidden],
.s-s15__message[hidden] {
  display: none;
}
