/* =============================================================================
   QuadQuote website: the one stylesheet.

   The LAYOUT language is taken from depoly.co: a floating white nav bar, a
   full-bleed hero with flat colour panels overlapping its foot, every panel
   opening on a "● LABEL" row over a 2px rule, big light statement type, cards
   whose footers are split into ruled cells, and a footer drawn as a ruled grid.

   The COLOURS are not DePoly's. Every one is QuadQuote's own, lifted from the
   app's src/style.css :root, and each one takes over the job a DePoly colour
   did (see the token block below). So the site should read as "the same people
   who made the app" while keeping DePoly's calm, architectural feel.

   Order of this file: fonts, tokens, base, shared components (labels, panels,
   buttons, links, figures), then page sections top to bottom, then the
   responsive steps, then motion. Class names are plain BEM-ish words so that
   the HTML says what each block is.

   CSP note: the site's Content-Security-Policy (public/_headers) forbids
   inline style="" attributes, so every visual rule lives here, including the
   per-part colours of the hero drawing (.p0 to .p12).
   ============================================================================= */


/* ---- Fonts ------------------------------------------------------------------
   Self-hosted (assets/fonts, SIL OFL licences beside them) so the site makes
   no third-party requests at all: nothing to disclose in the privacy note,
   nothing to block, no cookie banner.

   Hanken Grotesk stands in for DePoly's FK Grotesk (a paid face): a plain,
   slightly warm grotesk with the same proportions. JetBrains Mono carries the
   figures, indexes and small caps tags, because the app prints every figure in
   a monospace face and the site should feel the same where numbers appear.

   Only the "latin" subset is shipped; the unicode-range is Google's latin range,
   so a rare glyph outside it (the arrows, the tick) falls back to the system
   face instead of forcing a second download. */
@font-face {
  font-family: "Hanken Grotesk";
  src: url("/assets/fonts/hanken-grotesk-latin.woff2") format("woff2");
  font-weight: 300 800;
  font-style: normal;
  font-display: swap;
  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: "JetBrains Mono";
  src: url("/assets/fonts/jetbrains-mono-latin.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  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;
}


/* ---- Tokens -----------------------------------------------------------------
   Left column: the QuadQuote name and value (src/style.css). Right comment:
   the DePoly colour whose role it takes. Change a colour here, never inline. */
:root {
  /* Ink: the app's darkest colour, "--text two stops deeper" (its own comment).
     Takes DePoly's denim #002d42: all text, every rule, the dark buttons. */
  --ink: #16202b;
  --ink-2: #1d2a37;        /* hover on ink */
  --ink-line: #2c3d4e;     /* hairlines drawn ON ink */
  --ink-text: #eaeff4;     /* body text on ink */
  --ink-dim: #9db0c2;      /* secondary text on ink */
  --bed: #10161c;          /* the drawing editor's canvas: the hero's cutting bed */

  --bg: #f4f6f8;           /* app --bg        : DePoly crema #ebebe1, the page */
  --paper: #fff;           /* app --panel     : the nav bar and inner cards */
  --steel: #dde3ea;        /* app --line      : DePoly beige #d9daca, statement panels */
  --alloy: #c3cbd4;        /* app --line2     : DePoly natural #b3bda4, the licence panel */
  --sky: #e6f1fb;          /* app --accent-bg : DePoly sky #d9dfdf, list panels */
  --mint: #d9f7e6;         /* app --ok-bg     : DePoly lime #f2febc, the highlight colour */

  --dim: #4a5a68;          /* app --dim: secondary text; also the nav links, which
                              DePoly sets in a pale grey too faint to read easily */
  --dimmer: #8a9099;
  --blue: #185fa5;         /* app --accent: links in running text, focus rings */
  --blue-deep: #12508c;
  --go: #14b869;           /* app --ok-bright: ticks, done steps, the one green button */
  --go-deep: #0c8f57;      /* app --ok */
  --total: #0f6e56;        /* the colour the app prints a quote's grand total in */
  --laser: #42f0e9;        /* the app's true-size view: the hero's laser trace */

  /* Type */
  --sans: "Hanken Grotesk", "Segoe UI", system-ui, -apple-system, Roboto, sans-serif;
  --mono: "JetBrains Mono", Consolas, Menlo, "DejaVu Sans Mono", monospace;

  /* Space. DePoly uses 40px gutters and gaps on a desktop and about 10px on a
     phone; clamp() walks between the two instead of jumping at a breakpoint. */
  --gutter: clamp(12px, 2.8vw, 40px);
  --gap: clamp(12px, 2.8vw, 40px);
  --pad: clamp(20px, 2.2vw, 32px);           /* inside a panel */
  --rule: 2px solid var(--ink);               /* the rule under every panel label */
  --hair: 1px solid var(--ink);               /* the ruled grids (footer, bento) */
  --radius: 2px;                              /* DePoly's corners: square in all but name */
  --max: 1920px;                              /* content never stretches wider */
  --nav-top: clamp(10px, 1.4vw, 20px);        /* the floating bar's distance from the top */
  --nav-h: clamp(64px, 6.8vw, 100px);         /* its height */

  /* How far the intro panels ride up over the foot of the hero. */
  --overlap: clamp(90px, 22vh, 280px);

  /* Small drawn glyphs, used as CSS masks so they take currentColor. Data URIs
     are allowed by the CSP (img-src 'self' data:). */
  --glyph-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 14'%3E%3Cpath d='M1 7h16M11 1l6 6-6 6' fill='none' stroke='%23000' stroke-width='2.4'/%3E%3C/svg%3E");
  --glyph-tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.5 8.5l3.5 3.5 7.5-8' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --glyph-plus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1v14M1 8h14' fill='none' stroke='%23000' stroke-width='2.2'/%3E%3C/svg%3E");
  --glyph-minus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M1 8h14' fill='none' stroke='%23000' stroke-width='2.2'/%3E%3C/svg%3E");

  color-scheme: light;
}


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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  /* Anchor jumps stop BELOW the fixed nav bar instead of under it. */
  scroll-padding-top: calc(var(--nav-top) + var(--nav-h) + 16px);
}
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 400 18px/1.5 var(--sans);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* clip, not hidden: hidden would make body a scroll container and break the
     sticky/fixed behaviour; clip just refuses to paint a stray overflow. */
  overflow-x: clip;
}

/* The hidden attribute always wins, even over a class that sets display (the
   script-only buttons are hidden this way until site.js wires them up). */
[hidden] { display: none !important; }

h1, h2, h3, h4, p, figure, blockquote { margin: 0; }
h1, h2, h3, h4 { font-weight: inherit; }
ul, ol { margin: 0; padding: 0; }
img, svg { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; }
button, input, select, textarea { font: inherit; color: inherit; }

/* One focus style everywhere: the app's accent blue, well clear of the edge, so
   a keyboard user can always see where they are, on light panels and on ink. */
:focus-visible { outline: 3px solid var(--blue); outline-offset: 3px; }
.on-ink :focus-visible, .hero :focus-visible, .footer-strip :focus-visible { outline-color: var(--laser); }

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

/* The first thing a keyboard reaches: jump past the nav to the content. Hidden
   until focused, then it drops in over the nav bar. */
.skip-link {
  position: fixed; z-index: 100; left: var(--gutter); top: -80px;
  background: var(--ink); color: #fff; padding: 14px 18px;
  font: 700 15px/1 var(--sans); letter-spacing: .04em; text-transform: uppercase;
  text-decoration: none;
}
.skip-link:focus { top: 12px; }

.mono { font-family: var(--mono); }

/* The page's content column: full width up to --max, gutters either side. */
.wrap {
  width: 100%;
  max-width: var(--max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
/* A panel that IS the section (its colour must not run into the gutters), so it
   takes the gutters as margin instead of padding. Its edges line up exactly with
   the content edges of a .wrap block above or below it. */
.wrap-panel {
  width: calc(100% - 2 * var(--gutter));
  max-width: calc(var(--max) - 2 * var(--gutter));
  margin-inline: auto;
}


/* ---- Labels: "● THE CHALLENGE" ----------------------------------------------
   DePoly opens every panel with a filled dot and a bold uppercase word, and uses
   a ring instead of a dot for the highlight panels. The label is the panel's
   heading (an h2 in the HTML), so it is small but it is still the heading. */
.label {
  display: inline-flex; align-items: center; gap: .7em;
  font: 700 clamp(15px, 1.2vw, 19px)/1.1 var(--sans);
  letter-spacing: .035em;
  text-transform: uppercase;
  color: var(--ink);
}
.dot {
  width: 1.05em; height: 1.05em; flex: none;
  border-radius: 50%;
  background: currentColor;
}
.dot--ring { background: transparent; box-shadow: inset 0 0 0 .22em currentColor; }
.dot--go { color: var(--go); }

/* A small monospace tag: dates, "PER PC · PER YEAR", figure numbers. */
.tag {
  font: 500 12.5px/1.2 var(--mono);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--dim);
}
.chip {
  display: inline-block;
  padding: 5px 8px 4px;
  font: 600 11.5px/1 var(--mono);
  letter-spacing: .08em;
  text-transform: uppercase;
  background: var(--mint);
  color: var(--total);
  border-radius: var(--radius);
  white-space: nowrap;
}
.chip--soon { background: var(--steel); color: var(--dim); }


/* ---- Statement type ----------------------------------------------------------
   DePoly's big light sentences: the page is carried by these rather than by
   headlines. Regular weight, tight leading, a hair of negative tracking. */
.statement {
  font-weight: 400;
  font-size: clamp(26px, 2.7vw, 46px);
  line-height: 1.12;
  letter-spacing: -.012em;
  text-wrap: pretty;
}
.statement--md { font-size: clamp(22px, 2.05vw, 34px); line-height: 1.16; }
.lede { font-size: clamp(17px, 1.3vw, 20px); line-height: 1.55; color: var(--dim); max-width: 62ch; }


/* ---- Panels ------------------------------------------------------------------
   A flat block of one colour. --panel-bg picks the colour so a variant is one
   line. The head row is DePoly's: label on the left, an optional link or tag on
   the right, and the 2px rule under it running the full width of the panel. */
.panel {
  --panel-bg: var(--steel);
  background: var(--panel-bg);
  color: var(--ink);
  display: flex; flex-direction: column;
  min-width: 0;                 /* a long word shrinks inside, never pushes out */
}
.panel--steel { --panel-bg: var(--steel); }
.panel--alloy { --panel-bg: var(--alloy); }
/* --dim on alloy is about 4.3:1, just under the 4.5:1 small text needs; the
   alloy panel's own small text is set in ink instead. */
.panel--alloy > .panel__head .tag { color: var(--ink); }
.panel--sky   { --panel-bg: var(--sky); }
.panel--mint  { --panel-bg: var(--mint); }
.panel--paper { --panel-bg: var(--paper); }

.panel__head {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 10px 20px;
  min-height: clamp(64px, 5.8vw, 88px);
  padding: 14px var(--pad);
  border-bottom: var(--rule);
}
.panel__body { padding: var(--pad); }
.panel__body > * + * { margin-top: clamp(16px, 1.6vw, 24px); }


/* ---- Buttons and links -------------------------------------------------------
   DePoly's buttons are solid dark rectangles with bold uppercase words. Ours are
   the same in ink; on the dark hero the primary is the app's own green, the
   colour of the Activate button on the app's dark licence screen. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .6em;
  min-height: 56px;
  padding: 16px 26px;
  border: 2px solid var(--ink);
  border-radius: var(--radius);
  background: var(--ink); color: #fff;
  font: 700 15.5px/1.1 var(--sans);
  letter-spacing: .045em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .18s ease, border-color .18s ease, color .18s ease;
}
.btn:hover { background: var(--ink-2); border-color: var(--ink-2); }
/* Ink words on the green, not white: white on #14b869 is about 2.4:1, too faint
   to read comfortably; ink on it is over 6:1. */
.btn--go { background: var(--go); border-color: var(--go); color: var(--ink); }
.btn--go:hover { background: #2fd584; border-color: #2fd584; }
.btn--ghost { background: transparent; color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: #fff; }
.btn--ghost-light { background: transparent; border-color: rgb(255 255 255 / 55%); color: #fff; }
.btn--ghost-light:hover { background: rgb(255 255 255 / 10%); border-color: #fff; }

/* "READ MORE →": DePoly's bold uppercase text link. The arrow is a mask so it
   is always the link's own colour, and it nudges right on hover. */
.link-caps {
  display: inline-flex; align-items: center; gap: .55em;
  padding-block: 6px;
  font: 700 clamp(14.5px, 1.1vw, 17px)/1.1 var(--sans);
  letter-spacing: .045em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
}
.link-caps::after {
  content: "";
  width: 1.1em; height: .8em; flex: none;
  background: currentColor;
  -webkit-mask: var(--glyph-arrow) center / contain no-repeat;
  mask: var(--glyph-arrow) center / contain no-repeat;
  transition: transform .18s ease;
}
.link-caps:hover::after { transform: translateX(4px); }
.link-caps:hover { text-decoration: underline; text-underline-offset: 5px; text-decoration-thickness: 2px; }

/* Links inside running text: the app's blue, underlined. */
.prose a { color: var(--blue); text-underline-offset: 3px; }
.prose a:hover { color: var(--blue-deep); }


/* ---- Product screens ---------------------------------------------------------
   Every product image on the site is a QuadQuote screen (today a drawn
   placeholder, later a real screenshot; see website/README.md). They all share
   this frame: white, a hairline edge and a soft shadow, so they read as a
   window lying on the panel rather than as a flat picture. */
.screen {
  background: #fff;
  border: 1px solid rgb(22 32 43 / 16%);
  box-shadow: 0 26px 60px -24px rgb(22 32 43 / 50%), 0 2px 8px rgb(22 32 43 / 10%);
}
.screen img { width: 100%; }

.figcap {
  display: flex; gap: 10px 16px; align-items: baseline; flex-wrap: wrap;
  font-size: 15.5px; line-height: 1.45; color: var(--dim);
}


/* ---- Icons -------------------------------------------------------------------
   The app's own nav glyphs (src/shell.js ICONS), used from the sprite at the top
   of index.html. Same drawing rules as the app's icon(): hairline 1.5 stroke in
   a -12..12 box, round caps and joins, no fill. */
.icon {
  width: 24px; height: 24px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round;
}
.icon-tile {
  display: grid; place-items: center;
  width: 52px; height: 52px;
  background: var(--sky);
  color: var(--ink);
}
.icon-tile .icon { width: 28px; height: 28px; }


/* =============================================================================
   NAV: DePoly's floating white bar.
   Fixed 20px from the top and one gutter in from each side, so the hero shows
   around it. Wordmark left, uppercase links in the middle (thin rules split
   them into groups, as DePoly's do), one dark button right. Under 992px the
   links fold into a <details> menu, which opens and closes with no JavaScript.
   ============================================================================= */
.site-header {
  position: fixed; z-index: 50;
  top: var(--nav-top); left: 0; right: 0;
  padding-inline: var(--gutter);
  pointer-events: none;          /* the gutters either side stay clickable */
}
.nav {
  pointer-events: auto;
  position: relative;
  max-width: var(--max);
  height: var(--nav-h);
  margin-inline: auto;
  display: flex; align-items: center; gap: clamp(12px, 1.6vw, 32px);
  padding-inline: clamp(16px, 2.8vw, 40px) clamp(10px, 1.3vw, 18px);
  background: var(--paper);
  box-shadow: 0 10px 30px -18px rgb(22 32 43 / 35%);
}
.nav__brand { display: block; flex: none; }
/* The lockup is the app's own PNG (black ink on alpha), height-led so its
   proportions are never guessed. */
.nav__brand img { height: clamp(34px, 3.3vw, 50px); width: auto; }

.nav__links {
  display: flex; align-items: center;
  list-style: none;
  margin-inline: auto;
}
.nav__links a {
  display: block;
  padding: 12px clamp(9px, 1.1vw, 20px);
  font: 700 clamp(13.5px, 1.02vw, 16px)/1.1 var(--sans);
  letter-spacing: .035em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--dim);
  transition: color .15s ease;
}
.nav__links a:hover,
.nav__links a[aria-current="true"] { color: var(--ink); }
/* The thin upright rule DePoly draws between groups of links. */
.nav__links .nav__group { border-left: 1px solid var(--alloy); margin-left: 4px; padding-left: 4px; }
.nav__cta { flex: none; min-height: calc(var(--nav-h) - 36px); }

/* ---- Mobile menu (<details>) ---- */
.nav__menu { display: none; margin-left: auto; }
.nav__toggle {
  list-style: none;
  display: grid; place-items: center;
  width: 48px; height: 48px;
  cursor: pointer;
}
.nav__toggle::-webkit-details-marker { display: none; }
/* DePoly's menu button is a plain ring; open, it becomes a cross. */
.nav__ring {
  width: 26px; height: 26px; border-radius: 50%;
  box-shadow: inset 0 0 0 4px var(--ink);
  position: relative;
  transition: transform .2s ease;
}
.nav__menu[open] .nav__ring { box-shadow: none; transform: rotate(45deg); }
.nav__menu[open] .nav__ring::before,
.nav__menu[open] .nav__ring::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 26px; height: 3.5px; background: var(--ink);
  transform: translate(-50%, -50%);
}
.nav__menu[open] .nav__ring::after { transform: translate(-50%, -50%) rotate(90deg); }

.nav__sheet {
  position: absolute; left: 0; right: 0; top: calc(100% + 8px);
  background: var(--paper);
  padding: 10px clamp(16px, 4vw, 28px) 24px;
  box-shadow: 0 24px 40px -20px rgb(22 32 43 / 40%);
  max-height: calc(100svh - var(--nav-h) - var(--nav-top) * 2 - 16px);
  overflow-y: auto;
}
.nav__sheet ul { list-style: none; }
.nav__sheet li + li { border-top: 1px solid var(--steel); }
.nav__sheet a:not(.btn) {
  display: block; padding: 16px 2px;
  font: 700 20px/1.1 var(--sans); letter-spacing: .03em; text-transform: uppercase;
  text-decoration: none; color: var(--ink);
}
.nav__sheet .btn { width: 100%; margin-top: 14px; }


/* =============================================================================
   HERO: the cutting bed.
   DePoly's hero is a full-bleed material render with panels floating over its
   foot. Ours is QuadQuote's own drawing of a nested sheet (the Nest step's
   sheet, in white) on the editor's dark, gridded canvas, with the QuadQuote
   mark lit up among the parts. The SVG is decorative; the words carry the
   meaning, and the two are laid out so the drawing never sits behind the words.
   ============================================================================= */
.hero {
  position: relative;
  isolation: isolate;             /* keeps the bed and scrim's negative z-index inside */
  overflow: hidden;
  min-height: max(640px, 100svh);
  color: #fff;
  padding:
    calc(var(--nav-top) + var(--nav-h) + clamp(36px, 9vh, 120px))
    var(--gutter)
    calc(var(--overlap) + clamp(48px, 8vh, 110px));
  /* The drawing editor's dark canvas and drafting grid (20px lines, every fifth
     one stronger), as the hero's own background, so the grid runs the full
     width, under the words and under the drawing alike, wherever the drawing is
     placed. */
  background-color: var(--bed);
  background-image:
    linear-gradient(#223040 1px, transparent 1px),
    linear-gradient(90deg, #223040 1px, transparent 1px),
    linear-gradient(#18222c 1px, transparent 1px),
    linear-gradient(90deg, #18222c 1px, transparent 1px);
  background-size: 100px 100px, 100px 100px, 20px 20px, 20px 20px;
}
/* Wide screens: two columns that cannot overlap. The words keep to the left 44%
   of the content width (.hero__copy > * below); the drawing gets the box to their
   right, from 24px past that column to the right gutter, and from under the nav
   bar down to where the intro panels start riding up over the hero. The SVG's
   preserveAspectRatio="xMidYMid meet" fits the whole sheet inside that box and
   centres it. */
.hero__bed {
  position: absolute; z-index: -2;
  top: calc(var(--nav-top) + var(--nav-h) + 12px);
  bottom: calc(var(--overlap) + 12px);
  left: calc(var(--gutter) + (100% - 2 * var(--gutter)) * .44 + 24px);
  right: var(--gutter);
}
.hero__bed svg { width: 100%; height: 100%; }
/* A scrim from the left (and a little from the foot) that quietens the grid under
   the words. It is clear by just past the middle, where the drawing begins. */
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    linear-gradient(90deg, rgb(16 22 28 / 94%) 0%, rgb(16 22 28 / 80%) 26%, rgb(16 22 28 / 18%) 43%, rgb(16 22 28 / 0%) 52%),
    linear-gradient(0deg, rgb(16 22 28 / 85%) 0%, rgb(16 22 28 / 0%) 34%);
}
.hero__copy { max-width: var(--max); margin-inline: auto; }
/* The word column: 44% of the content width (the drawing's box starts just past
   it). The headline is capped at 8em as well, so it always breaks the same way,
   "Drawings in." / "Nested, priced," / "quoted.", at every screen size. */
.hero__copy > * { max-width: min(760px, 44%); }
.hero__copy > .hero__title { max-width: min(8em, 44%); }
.hero__copy > .hero__lead { max-width: min(44ch, 44%); }

/* The small caps line above a page title. Only the 404 and privacy pages use it
   now (the home page's hero opens straight on its headline). Its dot is plain
   white, like the hero drawing. */
.hero__eyebrow {
  display: inline-flex; align-items: center; gap: 12px;
  font: 500 clamp(12.5px, 1vw, 15px)/1.2 var(--mono);
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-dim);
}
.hero__eyebrow .dot { width: 10px; height: 10px; background: var(--ink-text); }

/* 5.6vw keeps the longest line, "Nested, priced," (about 6.4em), inside the 44%
   word column at every desktop width. */
.hero__title {
  margin-top: clamp(18px, 2.4vh, 28px);
  font-weight: 500;
  font-size: clamp(44px, 5.6vw, 100px);
  line-height: .98;
  letter-spacing: -.028em;
}
.hero__lead {
  margin-top: clamp(20px, 3vh, 32px);
  font-size: clamp(18px, 1.45vw, 22px);
  line-height: 1.5;
  color: var(--ink-text);
}
.hero__actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: clamp(28px, 4vh, 44px); }

/* ---- The bed drawing ------------------------------------------------------------
   The hero draws the nest in white only, so the single thing lit up, the
   QuadQuote mark, is the one thing the eye finds. (The app itself colours nest
   parts by hue = n x 137.508 degrees; the product pictures lower down still show
   that.) The pN classes on the parts only record which parts are the same type.
   Everything else on the sheet (outline, dimensions, datum, trim, offcut hatch)
   is white at low strength, set on the elements in index.html. */
.bed .part { stroke: #fff; fill: rgb(255 255 255 / 8%); stroke-width: 1.6; vector-effect: non-scaling-stroke; }
/* A hole shows the sheet through it, as the app draws one. */
.bed .hole { fill: var(--ink); stroke: #fff; stroke-width: 1.3; vector-effect: non-scaling-stroke; }
/* A mirrored copy is cross-hatched, exactly as the app marks one. */
.bed .part.mirrored { fill: url(#bed-xhatch); }

/* The QuadQuote mark is the one part the eye should find. Every other part sits
   in .parts--dim and is turned down as a group to a third of its strength: dimmed
   white. The mark is drawn above everything in bright white, with a glow made of
   two wider translucent white strokes underneath (no blur filter, so the laser
   can run over it cheaply). */
.bed .parts--dim { opacity: .34; }
/* 72% fill so the mark reads as white, not grey, on the dark sheet (white at 40%
   over ink comes out a mid grey); the full-strength outline still shows its
   edges and the gaps between its four pieces. */
.bed .logo-part .part { stroke: #fff; stroke-width: 2.2; fill: rgb(255 255 255 / 72%); }
.bed .logo-glow {
  fill: none;
  stroke: #fff;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.bed .logo-glow--wide { stroke-opacity: .11; stroke-width: 18; }
.bed .logo-glow--near { stroke-opacity: .24; stroke-width: 7; }

/* The sheet's own labels: its header line, "OFFCUT", and the two dimensions, in
   the mono face the app prints its sheet figures in, in faint white. */
.bed .bed-text {
  font-family: var(--mono); font-size: 14px; font-weight: 500;
  letter-spacing: .1em;
  fill: rgb(255 255 255 / 42%);
}
.bed .bed-text--dim { fill: rgb(255 255 255 / 32%); letter-spacing: .06em; font-size: 15px; }

/* The laser. The four .cut paths are the outlines of the mark's four pieces;
   site.js runs a white spark around them in turn, with a short tail that fades
   behind it (a moving dash), so the mark stays whole the whole time. With no
   JavaScript, or when the visitor asks for reduced motion, the laser is not
   drawn at all: the still picture is the dimmed sheet and the glowing mark. */
.bed:not(.is-cutting) .laser { display: none; }
.bed .cut {
  fill: none;
  stroke: #fff;
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
/* The tail's glow: a wide translucent copy of each cut (made by site.js) under
   it, rather than a blur filter, which would be recomputed on every frame. */
.bed .cut-glow {
  fill: none;
  stroke: #fff;
  stroke-opacity: .25;
  stroke-width: 8;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.bed .laser-head { opacity: 0; }
.bed.is-cutting .laser-head { opacity: 1; }
.bed .laser-core { fill: #fff; }
.bed .laser-halo { fill: url(#bed-halo); }

/* Pause / play for the laser (WCAG 2.2.2), tucked into the hero's lower right,
   just above where the intro panels begin. */
.hero__pause {
  position: absolute; z-index: 1;
  right: var(--gutter);
  bottom: calc(var(--overlap) + 16px);
  display: inline-flex; align-items: center; gap: 10px;
  padding: 10px 14px;
  border: 1px solid rgb(255 255 255 / 28%);
  border-radius: var(--radius);
  background: rgb(16 22 28 / 60%);
  color: var(--ink-text);
  font: 600 12.5px/1 var(--mono); letter-spacing: .08em; text-transform: uppercase;
  cursor: pointer;
}
.hero__pause:hover { border-color: rgb(255 255 255 / 60%); }
/* Two bars when it will pause, a triangle when it will play. */
.hero__pause::before {
  content: ""; width: 10px; height: 12px;
  background: linear-gradient(90deg, currentColor 0 3px, transparent 3px 7px, currentColor 7px 10px);
}
.hero__pause[aria-pressed="true"]::before {
  background: currentColor;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}


/* =============================================================================
   INTRO: the panels that ride up over the hero's foot.
   DePoly's layout exactly: a left column (52%) stacking two panels, and a
   right column holding one tall list panel, all pulled up by --overlap.
   ============================================================================= */
.intro {
  position: relative; z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 52fr) minmax(0, 48fr);
  gap: var(--gap);
  margin-top: calc(-1 * var(--overlap));
}
.intro__stack { display: grid; gap: var(--gap); align-content: start; }

/* "Our solution": a product screen with a statement card overlapping its
   lower-left corner, the way DePoly lays a text panel over its tanks. */
.solution__figure { padding: var(--pad) var(--pad) 0; }
.solution__card {
  position: relative;
  width: min(92%, 660px);
  margin-top: calc(-1 * clamp(40px, 7vw, 130px));
  padding: var(--pad);
  background: var(--steel);
}
.solution__card > * + * { margin-top: 18px; }

/* "What's new": DePoly's Latest News panel, the cards are real recent changes. */
.news__list {
  list-style: none;
  display: grid; gap: clamp(12px, 1.4vw, 22px);
  padding: var(--pad);
}
.news-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 18px 22px;
  padding: clamp(20px, 2vw, 30px);
  background: var(--paper);
}
.news-card__title {
  margin-top: 8px;
  font: 500 clamp(20px, 1.6vw, 26px)/1.15 var(--sans);
  letter-spacing: -.005em;
}
.news-card__text { margin-top: 10px; font-size: 16.5px; line-height: 1.5; color: var(--dim); }
.news-card .link-caps { margin-top: 12px; }
.news-card__art {
  display: grid; place-items: center;
  width: clamp(64px, 6.4vw, 108px); aspect-ratio: 1;
  background: var(--sky);
}
.news-card__art .icon { width: 46%; height: 46%; stroke-width: 1.3; }


/* =============================================================================
   SHOWCASE: the big picture.
   Where DePoly puts its full-width photograph, we put the Nest step on a dark,
   gridded ground (the hero's bed again, quieter), with its caption below.
   ============================================================================= */
.showcase { margin-top: var(--gap); }
.showcase__ground {
  padding: clamp(18px, 4.5vw, 80px) clamp(14px, 5vw, 96px);
  background-color: var(--ink);
  /* The editor's drafting grid: 24px minor lines, every fifth one stronger. */
  background-image:
    linear-gradient(rgb(255 255 255 / 6%) 1px, transparent 1px),
    linear-gradient(90deg, rgb(255 255 255 / 6%) 1px, transparent 1px),
    linear-gradient(rgb(255 255 255 / 2.5%) 1px, transparent 1px),
    linear-gradient(90deg, rgb(255 255 255 / 2.5%) 1px, transparent 1px);
  background-size: 120px 120px, 120px 120px, 24px 24px, 24px 24px;
}
.showcase__ground .screen { border-color: rgb(255 255 255 / 12%); box-shadow: 0 40px 80px -30px rgb(0 0 0 / 70%); }
.showcase__caption {
  display: grid;
  grid-template-columns: minmax(0, 52fr) minmax(0, 48fr);
  gap: var(--gap);
  align-items: start;
  padding: var(--pad);
  background: var(--paper);
  border-bottom: var(--rule);
}


/* =============================================================================
   SPLIT: a picture beside a statement panel (DePoly's "Who is DePoly" row).
   ============================================================================= */
.split {
  display: grid;
  grid-template-columns: minmax(0, 48fr) minmax(0, 52fr);
  gap: var(--gap);
  margin-top: var(--gap);
}
.split__media {
  display: grid; place-items: center;
  padding: clamp(20px, 3.2vw, 56px);
  background: var(--sky);
}
.split__media--mint { background: var(--mint); }


/* =============================================================================
   HOW IT WORKS: the app's own stage bar, then one card per stage.
   ============================================================================= */
.section { margin-top: var(--gap); }

/* A drawing of the app's top-bar stage bar (src/shell.js), not a screenshot of
   it: Main, then four numbered stages; done ones filled green with a tick, the
   current one in the accent blue, joined by short rules. */
.stagebar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 0;
  list-style: none;
  padding: 16px clamp(16px, 2vw, 28px);
  background: var(--paper);
  border: 1px solid rgb(22 32 43 / 14%);
  width: fit-content; max-width: 100%;
}
.stage {
  display: flex; align-items: center; gap: 10px;
  font: 600 15px/1 var(--sans);
  color: var(--dim);
  white-space: nowrap;
}
.stage + .stage::before {
  content: ""; width: clamp(14px, 2.4vw, 40px); height: 2px; margin-inline: 12px 2px;
  background: var(--alloy);
}
.stage--done + .stage::before { background: var(--go-deep); }
.stage__num {
  display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 50%;
  border: 2px solid var(--alloy);
  font: 700 13px/1 var(--mono);
  color: var(--dim);
  background: #fff;
}
.stage__num .icon { width: 18px; height: 18px; }
.stage--done { color: var(--ink); }
/* The app fills done stages with its bright green; on a white web page that
   green is too faint for a white tick (about 2.4:1), so the site uses the app's
   deeper --ok green, which carries the tick at about 4:1. */
.stage--done .stage__num { background: var(--go-deep); border-color: var(--go-deep); color: #fff; }
/* The tick replaces the number once a stage is done, as in the app. */
.stage--done .stage__num span { display: none; }
.stage--done .stage__num::before {
  content: ""; width: 15px; height: 15px; background: #fff;
  -webkit-mask: var(--glyph-tick) center / contain no-repeat;
  mask: var(--glyph-tick) center / contain no-repeat;
}
.stage--now { color: var(--blue); }
.stage--now .stage__num { border-color: var(--blue); color: var(--blue); }

.steps {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(12px, 1.4vw, 22px);
  list-style: none;
}
/* DePoly's job card: a pale card, a big bold title, and a footer split into two
   cells by 2px rules. */
.step-card {
  display: flex; flex-direction: column;
  background: var(--bg);
}
.step-card__body { flex: 1; padding: clamp(20px, 2vw, 30px); }
.step-card__no { font: 500 13px/1 var(--mono); letter-spacing: .1em; color: var(--dim); }
.step-card__title {
  margin-top: 14px;
  font: 700 clamp(26px, 2.3vw, 38px)/1 var(--sans);
  letter-spacing: -.01em;
}
.step-card__text { margin-top: 14px; font-size: 16.5px; line-height: 1.5; color: var(--dim); }
.card-foot {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  border-top: var(--rule);
}
/* A fixed floor height, so a tag that wraps to two lines on one card does not
   lift that card's footer rule above its neighbours' (DePoly's rules line up). */
.card-foot > * { min-height: 64px; padding: 15px clamp(16px, 1.6vw, 22px); display: flex; align-items: center; }
.card-foot > * + * { border-left: var(--rule); }
.card-foot .tag { color: var(--ink); }


/* =============================================================================
   FEATURES: a ruled bento grid.
   The rules are the grid's 1px gaps showing the ink background through, so
   they stay continuous across cells that span two columns or rows. The grid is
   always filled exactly (4 columns: 3 figures of 2x2 + 12 cells = 6 rows), or
   the ink would show through an empty slot as a black block.
   ============================================================================= */
.bento {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-flow: dense;
  gap: 1px;
  background: var(--ink);
  border-top: var(--rule);
}
.bento > * { background: var(--paper); padding: clamp(20px, 2vw, 32px); }
.bento__cell h3 { margin-top: 20px; font: 700 clamp(19px, 1.35vw, 22px)/1.2 var(--sans); }
.bento__cell p { margin-top: 8px; font-size: 16px; line-height: 1.5; color: var(--dim); }
.bento__fig {
  grid-column: span 2; grid-row: span 2;
  display: flex; flex-direction: column; justify-content: space-between; gap: 22px;
  background: var(--sky);
}
.bento__fig--mint { background: var(--mint); }
.bento__fig--steel { background: var(--steel); }
.bento__fig h3 { font: 700 clamp(20px, 1.5vw, 24px)/1.2 var(--sans); }
.bento__fig p { margin-top: 8px; font-size: 16px; color: var(--dim); max-width: 60ch; }


/* =============================================================================
   LICENSING: three cards on the alloy panel (DePoly's "We are hiring" cards,
   turned into licence levels), then the facts that hold for every licence.
   ============================================================================= */
.plans {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(12px, 1.4vw, 22px);
  padding: 0 var(--pad) var(--pad);
  list-style: none;
}
.plan {
  display: flex; flex-direction: column;
  background: var(--bg);
}
.plan--featured { background: var(--paper); box-shadow: inset 0 0 0 3px var(--ink); }
/* Side by side, the three cards share their rows (top, ticks, footer) through
   subgrid, so the rule under each card's top and the rule over each footer sit
   level across all three, even when one card's name wraps to two lines. */
@supports (grid-template-rows: subgrid) {
  .plans { row-gap: 0; }
  .plan { display: grid; grid-row: span 3; grid-template-rows: subgrid; }
}
.plan__top { padding: clamp(20px, 2vw, 30px); border-bottom: var(--rule); }
.plan__tier { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; }
.plan__name {
  margin-top: 14px;
  font: 700 clamp(28px, 2.4vw, 40px)/1 var(--sans);
  letter-spacing: -.012em;
}
.plan__pitch { margin-top: 12px; font-size: 17.5px; line-height: 1.45; color: var(--dim); }
.ticks {
  flex: 1;
  display: grid; align-content: start; gap: 12px;
  list-style: none;
  padding: clamp(20px, 2vw, 30px);
  font-size: 16.5px; line-height: 1.4;
}
.ticks li { position: relative; padding-left: 30px; }
.ticks li::before {
  content: ""; position: absolute; left: 0; top: .12em;
  width: 18px; height: 18px;
  background: var(--go-deep);        /* 3:1 or better against the pale cards */
  -webkit-mask: var(--glyph-tick) center / contain no-repeat;
  mask: var(--glyph-tick) center / contain no-repeat;
}
.ticks li.is-soon { color: var(--dim); }
.ticks li.is-soon::before { background: var(--dimmer); }
.ticks .chip { margin-left: 6px; vertical-align: 1px; }
/* The price cell. Prices are not published yet, so it holds "Contact sales for
   pricing"; putting a figure in is a one-line change (see website/README.md). */
.plan__price { flex-direction: column; align-items: flex-start !important; justify-content: center; gap: 4px; }
.plan__amount { font: 600 16px/1.25 var(--sans); }
.plan__amount--figure { font: 700 26px/1 var(--mono); }
.plan__basis { font: 500 12px/1.2 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--dim); }

/* Every licence: a ruled list on the steel panel. */
.facts { list-style: none; }
.facts li {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 16px;
  align-items: start;
  padding: 18px var(--pad);
  border-top: 1px solid rgb(22 32 43 / 22%);
}
.facts li:first-child { border-top: 0; }
.facts strong { display: block; font-weight: 700; font-size: 18px; line-height: 1.3; }
/* Only the description under each heading. Scoped to the text column (li > div)
   because the icon's box is a <span> too, and a bare ".facts span" used to catch
   it, turning off the box's centring and leaving every icon sitting high. */
.facts li > div > span { display: block; margin-top: 4px; font-size: 16px; line-height: 1.45; color: var(--dim); }
/* The icon sits bare on the panel, level with the heading's line (18px text on
   a 1.3 line is about 23px tall, so a 26px icon is nudged up to share its
   middle), rather than in a white tile that made a second box beside the text. */
.facts .icon-tile { width: 26px; height: 26px; margin-top: -1px; background: none; }
.facts .icon-tile .icon { width: 26px; height: 26px; }

.licence-row {
  display: grid;
  grid-template-columns: minmax(0, 44fr) minmax(0, 56fr);
  gap: var(--gap);
  margin-top: var(--gap);
}
/* The offering tile: the order book on mint, with a statement card overlapping
   its foot (DePoly's "Wherever you are in the supply chain" tile). */
.offer { position: relative; display: flex; flex-direction: column; }
.offer__figure { padding: var(--pad) var(--pad) 0; }
.offer__card {
  position: relative;
  width: min(86%, 620px);
  margin-top: calc(-1 * clamp(40px, 6vw, 110px));
  padding: var(--pad);
  background: var(--steel);
}
.offer__card > * + * { margin-top: 16px; }


/* =============================================================================
   FAQ: the statement on the left, the questions on the right, each question a
   <details> so it opens with no JavaScript and is a real button to a keyboard.
   ============================================================================= */
.faq {
  display: grid;
  grid-template-columns: minmax(0, 40fr) minmax(0, 60fr);
}
.faq__intro { border-right: var(--rule); }
.faq__list { border-top: 0; }
.qa { border-bottom: var(--rule); }
.qa:last-child { border-bottom: 0; }
.qa summary {
  list-style: none;
  display: flex; justify-content: space-between; align-items: center; gap: 24px;
  padding: clamp(18px, 1.8vw, 26px) var(--pad);
  cursor: pointer;
  font: 500 clamp(19px, 1.5vw, 23px)/1.25 var(--sans);
}
.qa summary::-webkit-details-marker { display: none; }
.qa summary::after {
  content: ""; width: 18px; height: 18px; flex: none;
  background: var(--ink);
  -webkit-mask: var(--glyph-plus) center / contain no-repeat;
  mask: var(--glyph-plus) center / contain no-repeat;
}
.qa[open] summary::after {
  -webkit-mask-image: var(--glyph-minus);
  mask-image: var(--glyph-minus);
}
.qa summary:hover { background: rgb(255 255 255 / 35%); }
.qa__a { padding: 0 var(--pad) clamp(20px, 2vw, 28px); max-width: 72ch; color: var(--dim); font-size: 17px; }
.qa__a p + p { margin-top: 10px; }


/* =============================================================================
   CONTACT: DePoly's newsletter band, turned into "tell us about your shop".
   A plain mailto form: it opens the visitor's own email program, so nothing is
   sent from, or stored by, this website.
   ============================================================================= */
.contact {
  display: grid;
  grid-template-columns: minmax(0, 30fr) minmax(0, 70fr);
  gap: var(--gap);
  padding: clamp(28px, 4vw, 64px) var(--pad);
  background: var(--mint);
  border-bottom: var(--rule);
}
.contact__title {
  font: 600 clamp(28px, 2.6vw, 42px)/1.1 var(--sans);
  letter-spacing: -.012em;
  max-width: 24ch;
}
.contact__sub { margin-top: 16px; font-size: 18px; color: var(--dim); max-width: 64ch; }
.contact__sub a { color: var(--ink); font-weight: 600; }
.copy-btn {
  margin-left: 6px;
  padding: 6px 10px;
  border: 2px solid var(--ink); border-radius: var(--radius);
  background: transparent; color: var(--ink);
  font: 700 12px/1 var(--sans); letter-spacing: .06em; text-transform: uppercase;
  cursor: pointer; vertical-align: 2px;
}
.copy-btn:hover { background: var(--ink); color: #fff; }
.copy-status { margin-left: 8px; font-size: 15px; color: var(--total); font-weight: 600; }

.form {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-top: 28px;
  max-width: 880px;
}
.field { display: grid; gap: 6px; }
.field--wide { grid-column: 1 / -1; }
.field label {
  font: 600 12.5px/1.2 var(--mono);
  letter-spacing: .08em; text-transform: uppercase;
}
.field input, .field select, .field textarea {
  width: 100%;
  min-height: 58px;
  padding: 14px 14px;
  border: 2px solid var(--ink);
  border-radius: 0;
  background: var(--paper);
  font-size: 17px;
  line-height: 1.3;
}
.field textarea { min-height: 128px; resize: vertical; }
.field select {
  appearance: none; -webkit-appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink) 50%), linear-gradient(135deg, var(--ink) 50%, transparent 50%);
  background-position: calc(100% - 22px) 50%, calc(100% - 16px) 50%;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 44px;
}
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible { outline-offset: 0; }
.form__actions {
  grid-column: 1 / -1;
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px 22px;
  margin-top: 6px;
}
.form__note { font-size: 15px; color: var(--dim); max-width: 46ch; }


/* =============================================================================
   FOOTER: DePoly's ruled grid, full bleed, then the dark strip.
   ============================================================================= */
.site-footer { background: var(--mint); }
.footer-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) repeat(3, minmax(0, 1fr));
  max-width: var(--max); margin-inline: auto;
}
.footer-cell {
  padding: clamp(28px, 3.2vw, 50px) clamp(20px, 3.2vw, 50px);
  border-right: var(--hair);
}
.footer-cell:last-child { border-right: 0; }
.footer-cell img { width: clamp(150px, 12vw, 200px); }
.footer-cell p { margin-top: 18px; font-size: 16.5px; line-height: 1.5; color: var(--dim); }
/* Two classes deep so it outranks ".footer-cell p" (these heads are <p>s). */
.footer-cell .footer-head {
  display: block;
  margin: 0 0 18px;
  font: 800 16px/1 var(--sans); letter-spacing: .03em; text-transform: uppercase;
  color: var(--ink);
}
.footer-links { list-style: none; display: grid; gap: 10px; }
.footer-links a { text-decoration: none; font-size: 17px; }
.footer-links a:hover { text-decoration: underline; text-underline-offset: 4px; }
.footer-cell--cta { display: flex; flex-direction: column; align-items: flex-start; gap: 16px; }
.footer-bottom {
  display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 12px 28px;
  max-width: var(--max); margin-inline: auto;
  padding: 20px clamp(20px, 3.2vw, 50px);
  font-size: 15px;
}
.footer-bottom-wrap { border-top: var(--hair); }
.footer-bottom nav { display: flex; gap: 28px; }
.footer-bottom a { text-decoration: none; }
.footer-bottom a:hover { text-decoration: underline; text-underline-offset: 4px; }
.footer-strip {
  background: var(--ink); color: var(--ink-dim);
  font: 500 clamp(11.5px, .95vw, 14px)/1.4 var(--mono);
  letter-spacing: .12em; text-transform: uppercase;
  text-align: center;
  padding: 22px var(--gutter);
}
.footer-strip b { color: var(--laser); font-weight: 600; }


/* =============================================================================
   SMALL PAGES (404, privacy): a dark head like the hero, then one panel.
   ============================================================================= */
.page-head {
  position: relative; isolation: isolate; overflow: hidden;
  background: var(--bed); color: #fff;
  padding:
    calc(var(--nav-top) + var(--nav-h) + clamp(40px, 8vh, 110px))
    var(--gutter)
    calc(var(--overlap) * .55 + clamp(40px, 6vh, 80px));
  background-image:
    linear-gradient(rgb(255 255 255 / 5%) 1px, transparent 1px),
    linear-gradient(90deg, rgb(255 255 255 / 5%) 1px, transparent 1px);
  background-size: 48px 48px;
}
.page-head__inner { max-width: var(--max); margin-inline: auto; }
.page-head h1 {
  margin-top: 18px;
  font-weight: 500; font-size: clamp(40px, 5.2vw, 84px); line-height: 1; letter-spacing: -.025em;
  max-width: 16ch;
}
.page-body { margin-top: calc(-1 * var(--overlap) * .55); position: relative; z-index: 2; }
.page-body .panel { max-width: 1100px; }
.prose { font-size: 18px; line-height: 1.6; max-width: 70ch; }
.prose h2 { font: 700 22px/1.25 var(--sans); margin-top: 34px; }
.prose p, .prose ul { margin-top: 14px; }
.prose ul { padding-left: 1.2em; }
.prose li + li { margin-top: 6px; }


/* =============================================================================
   RESPONSIVE: the steps DePoly's Webflow build uses (991 / 767 / 479).
   ============================================================================= */
@media (max-width: 1279px) {
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .plans { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 991px) {
  /* Nav folds into the ring menu. */
  .nav__links, .nav__cta { display: none; }
  .nav__menu { display: block; }

  .intro, .split, .licence-row, .faq, .contact, .showcase__caption { grid-template-columns: minmax(0, 1fr); }
  .faq__intro { border-right: 0; border-bottom: var(--rule); }
  /* Stacked, the cards no longer share rows: back to one flex column each, with
     the gap between cards restored. */
  .plans { grid-template-columns: minmax(0, 1fr); row-gap: clamp(12px, 1.4vw, 22px); }
  .plan { display: flex; grid-row: auto; max-width: 720px; }

  /* Two columns: figures take a full row each, cells pair up (still no holes:
     3 figure rows + 12 cells = 9 full rows). */
  .bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .bento__fig { grid-column: span 2; grid-row: auto; }

  .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer-cell:nth-child(2) { border-right: 0; }
  .footer-cell:nth-child(-n + 2) { border-bottom: var(--hair); }

  /* Narrow screens: no room beside the words, so the drawing follows them, the
     whole sheet at full width (the box takes the drawing's own proportions,
     1060 x 620), between the buttons and the intro panels. The words run the
     full width again, and need no scrim, since nothing sits behind them. */
  .hero__bed {
    position: relative; inset: auto; z-index: 0;
    margin-top: clamp(32px, 7vw, 56px);
    aspect-ratio: 1060 / 620;
  }
  .hero__copy > * { max-width: 760px; }
  .hero__copy > .hero__title { max-width: 8em; }
  .hero__copy > .hero__lead { max-width: 44ch; }
  .hero::after { background: linear-gradient(0deg, rgb(16 22 28 / 70%) 0%, rgb(16 22 28 / 0%) 16%); }
}

@media (max-width: 767px) {
  .steps { grid-template-columns: minmax(0, 1fr); }
  .bento { grid-template-columns: minmax(0, 1fr); }
  .bento__fig { grid-column: auto; }
  .news-card { grid-template-columns: minmax(0, 1fr); }
  .news-card__art { display: none; }
  .form { grid-template-columns: minmax(0, 1fr); }
  .footer-grid { grid-template-columns: minmax(0, 1fr); }
  .footer-cell { border-right: 0; border-bottom: var(--hair); }
  .footer-cell:last-child { border-bottom: 0; }
  .solution__card, .offer__card { width: auto; margin-right: var(--pad); }
  .stage + .stage::before { margin-inline: 8px 0; }
  .stage__label { display: none; }
  .stage--now .stage__label, .stage--home .stage__label { display: inline; }
}

@media (max-width: 479px) {
  .hero__actions .btn { width: 100%; }
  .card-foot { grid-template-columns: minmax(0, 1fr); }
  .card-foot > * + * { border-left: 0; border-top: var(--rule); }
  .qa summary { gap: 14px; }
}


/* =============================================================================
   MOTION
   Panels rise into place as they scroll into view, DePoly-style. Done with
   scroll-driven CSS animation, so there is no script and no flash: where the
   browser lacks animation-timeline the rule is skipped entirely and everything
   is simply there; where the visitor asks for reduced motion, nothing moves.
   ============================================================================= */
@keyframes qq-rise {
  from { opacity: 0; transform: translateY(32px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    [data-reveal] {
      animation: qq-rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 55%;
    }
  }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}

/* Windows High Contrast (forced colours). The browser swaps every colour for the
   visitor's system colours and drops backgrounds, which would erase the glyphs
   drawn as masked backgrounds (arrows, ticks, plus/minus, dots). Give them the
   system text colour and opt them out of the swap so they stay visible. */
@media (forced-colors: active) {
  .link-caps::after, .ticks li::before, .qa summary::after,
  .stage--done .stage__num::before, .dot, .hero__pause::before {
    forced-color-adjust: none;
    background: CanvasText;
  }
  .dot--ring { background: transparent; box-shadow: inset 0 0 0 .22em CanvasText; }
  .panel, .plan, .news-card, .step-card { border: 1px solid CanvasText; }
}

@media print {
  .site-header, .hero__bed, .skip-link, .footer-strip, .nav__menu { display: none !important; }
  .hero { min-height: 0; background: #fff; color: var(--ink); padding: 24px 0; }
  .hero::after { display: none; }
  .intro { margin-top: 0; }
}
