/* =========================================================================
   Tinline Designs — styles

   Design reference: Figma "Agency Brainstorming", hero frame 204:395
   (1920 × 1080). Hero values are written as Figma px × var(--u), so the
   numbers here can be checked straight against Figma and the whole
   composition scales as one piece.
   ========================================================================= */


/* ---- Font -------------------------------------------------------------- */

/* Self-hosted Bricolage Grotesque (SIL Open Font License), all three variable
   axes. Subset to Latin + common punctuation from the full TTF, the same range
   Google Fonts serves. The TTF in assets/fonts is the source; this is the web copy. */
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("../assets/fonts/bricolage-grotesque-latin.woff2") format("woff2");
  font-weight: 200 800;
  font-stretch: 75% 100%;
  font-style: normal;
  font-display: swap;
}

/* Lato 2.0 (SIL Open Font License, LICENSE-Lato.txt), the secondary font:
   copy, eyebrows, nav, buttons, small caps. The whole upright family is
   declared, 100 to 900; browsers only download the weights a page uses.
   Subset to Latin (same range as Bricolage) from the TTFs in the project's
   fonts/Lato/ (outside website/, so never deployed); the recipe is in
   docs/STYLEGUIDE.md. Italics are in fonts/Lato/ but not converted: nothing
   uses them yet. Lato 2.0 also has the "ti" ligatures from the mockups. */
@font-face {
  font-family: "Lato";
  src: url("../assets/fonts/lato-100-latin.woff2") format("woff2");
  font-weight: 100;   /* Hairline */
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Lato";
  src: url("../assets/fonts/lato-200-latin.woff2") format("woff2");
  font-weight: 200;   /* Thin */
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Lato";
  src: url("../assets/fonts/lato-300-latin.woff2") format("woff2");
  font-weight: 300;   /* Light */
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Lato";
  src: url("../assets/fonts/lato-400-latin.woff2") format("woff2");
  font-weight: 400;   /* Regular */
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Lato";
  src: url("../assets/fonts/lato-500-latin.woff2") format("woff2");
  font-weight: 500;   /* Medium */
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Lato";
  src: url("../assets/fonts/lato-600-latin.woff2") format("woff2");
  font-weight: 600;   /* Semibold */
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Lato";
  src: url("../assets/fonts/lato-700-latin.woff2") format("woff2");
  font-weight: 700;   /* Bold */
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Lato";
  src: url("../assets/fonts/lato-800-latin.woff2") format("woff2");
  font-weight: 800;   /* Heavy (Figma: ExtraBold) */
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Lato";
  src: url("../assets/fonts/lato-900-latin.woff2") format("woff2");
  font-weight: 900;   /* Black */
  font-style: normal;
  font-display: swap;
}


/* ---- Tokens ------------------------------------------------------------ */

:root {
  --color-bg: #F5F5F5;
  --color-ink: #2D3236;
  --color-accent: #D69B42;
  --color-on-ink: var(--color-bg);   /* text on ink fills (Contact pill, button hover) */
  --color-ink-muted: #686060;        /* body copy (philosophy paragraph) */
  --color-placeholder-a: #E6E6E4;    /* striped fill for missing project images */
  --color-placeholder-b: #EDEDEB;

  /* Case study drawer (Figma "TLC Case Study v2"). */
  --color-cream: #FDFCF9;            /* case study cards ("Tinline primary white") */
  --color-drawer: #433A3A;           /* sheet background behind the cards, and the footer */
  --color-accent-strong: #E0A33C;    /* pill border, diamonds, "Send a message" */
  --color-hairline: #C9C6C1;         /* rules inside the typography specimen */
  --color-backdrop: color-mix(in srgb, var(--color-ink) 42%, transparent);
  --color-error: #A33A2C;            /* form errors (contact modal) */

  --font-display: "Bricolage Grotesque", system-ui, sans-serif;   /* big headlines */
  --font-body: "Lato", system-ui, sans-serif;                     /* everything else */

  /* Section headlines (Bricolage, 56px at 1920, e.g. the philosophy h2).
     Weight and tracking matched to James's design of 2026-09-29. */
  --weight-section-headline: 600;
  --tracking-section-headline: -0.015em;

  /* Small caps labels above sections (Lato). */
  --tracking-eyebrow: 0.065em;

  /* Type scale, in Figma px (Figma is the source of truth for sizes). Text
     is a fixed size; only headings flex, from a laptop size up to their
     Figma size, which they reach at 1920 wide and never pass. Shared by the
     page sections and the case study drawer. Phones override these below. */
  --text-h1: clamp(48px, 3.75vw, 72px);       /* case study title */
  --text-h2: clamp(44px, 2.917vw, 56px);      /* section headlines, drawer headings */
  --text-h3: clamp(26px, 1.667vw, 32px);      /* drawer labels ("keywords"), keyword list */
  --text-large: 24px;                         /* copy under homepage section titles, process phase descriptions */
  --text-lead: 22px;                          /* drawer "Ready to connect?" copy (Figma 22.8) */
  --text-body: 20px;                          /* body copy everywhere */
  --text-eyebrow: 20px;                       /* "PHILOSOPHY", "PROJECTS" */
  --text-pill: 16px;                          /* case study section pills */
  --text-button: 15px;                        /* drawer buttons (Figma 15.2) */
  --text-label: 14px;                         /* small caps labels, spec table, panel meta */
  --text-nav: 22px;                           /* nav words (Bricolage), handoff 3a */
  --text-input: 18px;                         /* form fields and the contact intro */

  /* Sizing outside the type scale. The hero (and the philosophy string that
     carries on from it) is one composition that scales with the window:

     --u: one Figma px of the 1920 × 1080 hero frame. Picks whichever of width
     or height is tighter, so the whole frame fits the viewport; stops growing
     at --u-max (1px = the Figma size), so big screens get a 1920 composition
     with more room around it rather than a bigger one. Header and hero use it. */
  --u-max: 1px;
  --u: min(100vw / 1920, 100svh / 1080, var(--u-max));

  /* Widest the content column gets (between the margins). Past this, the
     margins grow instead. (1344 is the content width at 1920; 1600 chosen
     by James 2026-10-06.) */
  --content-max: 1600px;

  /* Page margin, left and right. Everything that lines up with the page edge
     is positioned from this: header, hero words, tagline and button, cans,
     and section content. 288 Figma px of the hero frame, or wider once the
     content column reaches --content-max. Phones set their own below. */
  --margin: max(288 * var(--u), (100vw - var(--content-max)) / 2);

  /* Space between the homepage sections: philosophy, projects, process and
     "(just) the two of us". Content edge to content edge, every screen size
     (James, 2026-10-08; 104 → 144 the same day). The footer keeps its own gap. */
  --section-gap: 144px;

  /* Line length of the copy under a section title (philosophy, projects,
     process, the two of us, footer). Philosophy's measure, shared since
     2026-10-08. */
  --copy-measure: 31em;

  /* How far the orange eyebrow rules sit above centre on the eyebrow line
     (James, 2026-10-08: "up one point"). */
  --eyebrow-rule-raise: 1px;

  /* Readability floors: at small desktop sizes the scaled text would get
     too small, so these sizes stop shrinking here. */
  --min-nav: 14px;
  --min-small-caps: 12px;

  /* Header padding above and below the nav: roomy at the top of the page
     (Figma: nav at y 50), compact once scrolled. */
  --header-pad: calc(50 * var(--u));
  --nav-ease: cubic-bezier(0.2, 0.7, 0.2, 1);   /* nav words and the bar pinning */
  --header-pad-scrolled: max(12px, 18 * var(--u));
}

/* Dark theme: not designed yet. When it is, add the dark values under
   :root[data-theme="dark"] and a prefers-color-scheme default guarded by
   :root:not([data-theme="light"]). Everything below already reads tokens. */


/* ---- Base -------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  /* Keep in-page link targets clear of the fixed header (compact height). */
  scroll-padding-top: 96px;
  /* The drawer locks page scroll; keeping the gutter stops the page jumping
     sideways by a scrollbar's width when it does. */
  scrollbar-gutter: stable;
}

/* Reduced motion: OS setting, unless the visitor chose otherwise on site. */
@media (prefers-reduced-motion: reduce) {
  :root:not([data-motion="full"]) *,
  :root:not([data-motion="full"]) *::before,
  :root:not([data-motion="full"]) *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

:root[data-motion="reduce"] *,
:root[data-motion="reduce"] *::before,
:root[data-motion="reduce"] *::after {
  transition-duration: 0.01ms !important;
  animation-duration: 0.01ms !important;
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-ink);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
}

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

:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 4px;
}


/* ---- Header ------------------------------------------------------------ */

/* Pinned to the top. Transparent over the hero, exactly as in Figma; once the
   page scrolls, main.js adds .is-scrolled and it tightens up and gains a
   background so it stays readable over content. Logo and nav share a centre
   line, which is how Figma has them (logo y 47, nav y 50). */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--header-pad) var(--margin);
  /* Same duration and curve as the nav words, so bar and words settle together. */
  transition: padding 0.45s var(--nav-ease), background-color 0.45s var(--nav-ease), box-shadow 0.45s var(--nav-ease);
  pointer-events: none;   /* the bar itself mustn't block the string underneath */
}

.site-header > * { pointer-events: auto; }

.site-header.is-scrolled {
  padding-block: var(--header-pad-scrolled);
  background: color-mix(in srgb, var(--color-bg) 88%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--color-ink) 8%, transparent);
}

/* Header logo: an inline SVG that starts as "tl." and becomes the full logo
   when the header pins (js/logo-morph.js). Sized in em off the Figma "tl."
   text (40px): the SVG's 288-unit height is 1.2em, which makes its t exactly
   the text t's size. */
.logo {
  display: block;
  font-size: max(24px, 40 * var(--u));
}

.logo__mark {
  display: block;
  height: 1.2em;
  width: auto;
  overflow: visible;
  /* Lay out as tall as a nav pill (43px at 40px) so the two centre together,
     sitting 1.5px higher than centred, which lands the glyphs exactly where
     Figma's "tl." text is (measured against the mockup). */
  margin-block: -0.1em -0.025em;
}

.logo__mark path { fill: var(--color-ink); }
.logo__mark .logo__dot { fill: var(--color-accent); }

.logo__mark .logo__string {
  fill: none;
  stroke: var(--color-accent);
  stroke-linecap: round;
}

/* The "tl." state, before (or without) JavaScript. */
.logo__pop,
.logo__mark .logo__string { opacity: 0; }

/* Nav: lowercase display words (handoff: docs/handoffs/navbar-display-words,
   option 3a). Unpinned, all Medium (500) ink. Pinned (.is-scrolled), the current
   section's link (aria-current, set by main.js) goes ExtraBold and the rest
   fade to the hairline grey; with no current section all stay ink. The
   weight animates through the font's wght axis (transitioning font-weight
   alone was unreliable), and each link sits on a hidden ExtraBold copy of
   itself (.site-nav__sizer) so the row never shifts. */
.site-nav ul {
  display: flex;
  align-items: center;
  gap: clamp(40px, 4.72vw, 90px);   /* 68 at 1440, 90 at 1920 (handoff) */
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-nav__item { display: grid; }

.site-nav__item > * {
  grid-area: 1 / 1;
  text-align: center;
}

.site-nav__sizer,
.site-nav a {
  font-family: var(--font-display);
  font-size: var(--text-nav);
  line-height: 1.2;
  letter-spacing: -0.01em;
  white-space: nowrap;
}

.site-nav__sizer {
  visibility: hidden;
  font-weight: 800;
  font-variation-settings: "opsz" 14, "wght" 800;
}

.site-nav a {
  display: block;
  color: var(--color-ink);
  font-weight: 500;                 /* Medium (James, 2026-10-07; was 600) */
  font-variation-settings: "opsz" 14, "wght" 500;
  transition: font-variation-settings 0.45s var(--nav-ease), color 0.45s var(--nav-ease);
}

.site-header.is-scrolled .site-nav:has(a[aria-current]) a { color: var(--color-hairline); }

/* :has() in both rules keeps their specificity equal, so this one wins. */
.site-header.is-scrolled .site-nav:has(a[aria-current]) a[aria-current] {
  color: var(--color-ink);
  font-weight: 800;
  font-variation-settings: "opsz" 14, "wght" 800;
}

/* Hover (not designed; the handoff's suggestion): a faded link comes back
   to ink without changing weight. */
.site-header.is-scrolled .site-nav:has(a[aria-current]) a:hover { color: var(--color-ink); }

@media (prefers-reduced-motion: reduce) {
  :root:not([data-motion="full"]) .site-nav a { transition: none !important; }
}
:root[data-motion="reduce"] .site-nav a { transition: none !important; }

.nav-toggle { display: none; }


/* ---- Hero -------------------------------------------------------------- */

.hero {
  position: relative;
  height: 100svh;
  overflow: clip;
}

/* The 1080-tall Figma frame, centred vertically. Left-side elements are
   measured from the left edge and right-side ones from the right, so on wide
   screens the two words move apart and the string stretches between them. */
.hero__stage {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: calc(1080 * var(--u));
  translate: 0 -50%;
}

.hero__title {
  margin: 0;
  font: inherit;
}

.hero__word {
  position: absolute;
  font-family: var(--font-display);
  /* Figma sets the hero words to optical size 14, width 100. */
  font-variation-settings: "opsz" 14, "wdth" 100;
  font-size: calc(386 * var(--u));
  font-weight: 800;
  letter-spacing: -0.08em;          /* Figma: -30.88px at 386px */
  line-height: normal;
  white-space: nowrap;
}

/* Two pairs Bricolage sets too tight at this size and tracking: t–i and
   n–e (measured at 1920: 6px and 3px, against 18px between straight
   stems). Each is opened a little, as a share of the font size so it scales
   with the word. Round "e" and the open "t" get a touch less than 18px, so
   they look even rather than measure even. */
.hero__kern { margin-left: var(--kern); }
.hero__kern--ti { --kern: 0.023em; }    /* +9px at 386px: 6 → 15 */
.hero__kern--ne { --kern: 0.0285em; }   /* +11px at 386px: 3 → 14 */

.hero__word--tin {
  left: calc(var(--margin) - 3 * var(--u));      /* Figma: 61 */
  top: calc(114 * var(--u));
}

/* Browsers add letter-spacing after the last letter too; Figma doesn't. For
   right-aligned or centred text, these margins/paddings cancel that trailing
   space so glyphs land exactly where Figma puts them. */
.hero__word--line {
  margin-right: 0.08em;
  right: calc(var(--margin) - 11 * var(--u));   /* Figma: 53 */
  top: calc(509 * var(--u));
}

.hero__designs {
  position: absolute;
  right: calc(var(--margin) + 11 * var(--u));   /* Figma: 75 */
  top: calc(902 * var(--u));
  margin-right: -0.4em;             /* trailing letter-spacing, see .hero__word--line */
  font-size: max(var(--min-small-caps), 27 * var(--u));
  font-weight: 400;
  letter-spacing: 0.4em;            /* Figma: 10.8px at 27px */
  line-height: normal;
  text-transform: uppercase;
}

/* Tagline and button share a centre line at Figma x = 279 (margin + 215). */
.hero__tagline {
  position: absolute;
  left: calc(var(--margin) + 215 * var(--u));
  top: calc(796 * var(--u));
  translate: -50% 0;
  margin: 0;
  padding-left: 0.4em;              /* trailing letter-spacing, see .hero__word--line */
  font-size: max(var(--min-small-caps), 20 * var(--u));
  font-weight: 400;
  letter-spacing: 0.4em;            /* Figma: 8px at 20px */
  line-height: 1.65;                /* Figma: 33px at 20px */
  text-align: center;
  text-transform: uppercase;
  white-space: nowrap;
}

.hero__cta {
  position: absolute;
  left: calc(var(--margin) + 215 * var(--u));
  top: calc(886 * var(--u));
  translate: -50% 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: calc(211 * var(--u));
  height: max(40px, 64 * var(--u));
  padding-inline: max(20px, 34 * var(--u));
  padding-left: calc(max(20px, 34 * var(--u)) + 0.2em);   /* trailing letter-spacing */
  border: max(1.5px, 2 * var(--u)) solid var(--color-ink);
  border-radius: 100px;
  /* Same text as .button-cta ("Tell us about it"; James, 2026-10-07). */
  font: 800 var(--text-button) / 1 var(--font-body);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.hero__cta:hover {
  background: var(--color-ink);
  color: var(--color-on-ink);
}

/* Can anchors. Each marks a can's centre (left/top) and resting rotation
   (--can-angle, degrees). Its width is 100 "can units": hero-string.js reads
   it to know how big to draw the cans, string and dot. Values from Figma. */
.hero__anchor {
  --can-unit: var(--u);
  position: absolute;
  width: calc(100 * var(--can-unit));
  height: 0;
  margin-left: calc(-50 * var(--can-unit));
  pointer-events: none;
}

.hero__anchor--a {
  --can-angle: -45;
  left: calc(var(--margin) + 508.25 * var(--u));   /* Figma: 572.25 */
  top: calc(338.26 * var(--u));
}

.hero__anchor--b {
  --can-angle: 110;
  left: calc(100% - var(--margin) - 663.68 * var(--u));   /* Figma: 1192.32 */
  top: calc(823.39 * var(--u));
}

.hero__string {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.hero__rope {
  fill: none;
  stroke: var(--color-ink);
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The gold stretch the dot sends down the string (hero-string.js, "loop").
   Butt caps, so its moving ends are clean; the dark rope's round caps stay
   underneath at the cans. */
.hero__rope--lit {
  stroke: var(--color-accent);
  stroke-linecap: butt;
}

.hero__dot circle { fill: var(--color-accent); }
.hero__dot .hero__dot-halo { opacity: 0.5; }


/* ---- Philosophy -------------------------------------------------------
   Design reference: docs/handoffs/philosophy-carried-line (option 5a),
   a 1440 × 1900 artboard. Handoff px are written × var(--a), which is sized
   so that 1440 wide matches the handoff exactly and bigger screens scale up
   in step with the hero. Left/right margins follow the hero's (64 × --u)
   so the statement lines up under "tin". The string, can and dot use the
   hero's sizes (× --can-unit), not the handoff's. */

/* Registered so philosophy.js can read one handoff px as a pixel value. */
@property --a {
  syntax: "<length>";
  inherits: true;
  initial-value: 1px;
}

/* Where the string's scroll timeline ends, measured from the section top
   (philosophy.js: progress 1 = this line at the viewport bottom). It was the
   section's height until 2026-10-01, when the section was trimmed to end at
   its text; kept separate so the string still draws at the same pace. */
@property --timeline-end {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}

.philosophy {
  --a: calc(var(--u) * 4 / 3);      /* one handoff px */
  --statement-top: calc(1230 * var(--a));
  --timeline-end: calc(1900 * var(--a));
  position: relative;
  /* Height follows the statement: the section ends where its text does, and
     the next section's top padding sets the gap. */
  padding: var(--statement-top) var(--margin) 0;
  /* The handoff lets optical size follow font size (the browser default);
     the hero pins it at 14 to match Figma. */
  font-optical-sizing: auto;
  font-variation-settings: "wdth" 100;
}

.philosophy__string {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;                /* the start dot sits up in the hero, under DESIGNS */
  pointer-events: none;
}

.philosophy__rope {
  fill: none;
  stroke: var(--color-ink);
  stroke-linecap: round;
}

.philosophy__start { fill: var(--color-accent); }
.philosophy__pulse circle { fill: var(--color-accent); }
.philosophy__pulse .philosophy__pulse-halo { opacity: 0.5; }

/* End can: centre and rotation (180 = mouth down). Same mechanism as
   .hero__anchor. Handoff: can at x 120, mouth at y 1166. */
.philosophy__can-anchor {
  --can-unit: var(--u);
  --can-angle: 180;
  position: absolute;
  left: calc(var(--margin) + 56 * var(--a));
  top: calc(1166 * var(--a) - 54 * var(--can-unit));
  width: calc(100 * var(--can-unit));
  height: 0;
  margin-left: calc(-50 * var(--can-unit));
  pointer-events: none;
}

/* Statement block: James's design of 2026-09-29 (replaced the handoff's
   eyebrow + 104px headline). Type from the type scale (:root), spacing in
   px as measured off the design image. */
.philosophy__statement {
  position: relative;               /* in flow, at the section's top padding */
}

.philosophy__eyebrow {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0;
  font-size: var(--text-eyebrow);
  font-weight: 500;                 /* Lato Medium */
  letter-spacing: var(--tracking-eyebrow);
  line-height: 1.2;
  text-transform: uppercase;
}

.philosophy__eyebrow > span:first-child {
  margin-right: calc(-1 * var(--tracking-eyebrow));   /* trailing letter-spacing */
}

/* The orange rule after the eyebrow; philosophy.js draws it in from the left. */
.philosophy__rule {
  flex: none;
  position: relative;
  top: calc(-1 * var(--eyebrow-rule-raise));
  width: 66px;
  height: 2px;
  background: var(--color-accent);
  transform-origin: left center;
}

.philosophy__title {
  /* Pulled 0.12em left of the eyebrow and copy, as in the design (optical
     alignment for the round "c" at this size). */
  margin: 49px 0 0 -0.12em;
  font-family: var(--font-display);
  /* Optical size 14, like the hero and Figma's default: the design's wider,
     looser letter shapes. */
  font-variation-settings: "opsz" 14, "wdth" 100;
  font-size: var(--text-h2);
  font-weight: var(--weight-section-headline);
  line-height: 1.1;
  letter-spacing: var(--tracking-section-headline);
  text-wrap: balance;               /* when it wraps (phones), no lone last word */
}

.philosophy__copy {
  max-width: var(--copy-measure);   /* wraps as the design does */
  margin: 35px 0 0;
  color: var(--color-ink-muted);
  font-size: var(--text-large);   /* copy under a section title: 24 (James, 2026-10-07) */
  line-height: 1.333;
  text-wrap: pretty;                /* no lone last word */
}

.philosophy__copy strong {
  color: var(--color-ink);
  font-weight: 600;                 /* Lato Semibold */
}

/* Statement reveal. Plays once, shortly after the statement scrolls into view
   (philosophy.js adds .is-in). Order: eyebrow, rule draws across, headline
   word by word, then the paragraph rises in. Without JS none of this applies
   and the text simply shows; with reduced motion it shows at once. */
.philosophy__statement {
  --reveal-delay: 150ms;            /* after coming into view */
  --reveal-duration: 700ms;         /* each element's fade */
  --reveal-word-step: 90ms;         /* stagger between headline words */
  --reveal-ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --reveal-rise: 16px;   /* how far the paragraph rises */
}

.is-armed .philosophy__eyebrow,
.is-armed .philosophy__word,
.is-armed .philosophy__copy {
  transition: opacity var(--reveal-duration) var(--reveal-ease),
              transform var(--reveal-duration) var(--reveal-ease);
}

.is-armed .philosophy__rule {
  transition: transform var(--reveal-duration) var(--reveal-ease);
}

.is-armed:not(.is-in) .philosophy__eyebrow { opacity: 0; }
.is-armed:not(.is-in) .philosophy__rule { transform: scaleX(0); }
.is-armed:not(.is-in) .philosophy__word { opacity: 0.12; }
.is-armed:not(.is-in) .philosophy__copy { opacity: 0; transform: translateY(var(--reveal-rise)); }

.is-in .philosophy__eyebrow { transition-delay: var(--reveal-delay); }
.is-in .philosophy__rule { transition-delay: calc(var(--reveal-delay) + 150ms); }
.is-in .philosophy__word {
  transition-delay: calc(var(--reveal-delay) + 250ms + var(--i) * var(--reveal-word-step));
}
.is-in .philosophy__copy {
  transition-delay: calc(var(--reveal-delay) + 400ms + var(--words) * var(--reveal-word-step));
}

.is-instant .philosophy__eyebrow,
.is-instant .philosophy__rule,
.is-instant .philosophy__word,
.is-instant .philosophy__copy { transition: none; }


/* ---- Projects ---------------------------------------------------------
   Design reference: docs/handoffs/projects-expanding-panels (option 2d),
   designed at 1440 wide. Type comes from the type scale, so the eyebrow,
   headline and copy match the philosophy statement; spacing is px, with the
   large gaps flexing between a laptop size and their size at 1920. Side
   margins are the site's --margin (handoff: 93px). */

.projects {
  /* Knobs. */
  --panel-count: 3;                 /* keep in step with the panels in index.html */
  --panel-flex-open: 4;             /* closed panels are flex 1 */
  --panel-gap: 24px;
  /* 540 at 1440, 720 at 1920; never taller than 70% of the window.
     (Was 640 / 853 / 80% until 2026-10-07: James, "a little less tall".) */
  --panel-height: min(clamp(420px, 37.5vw, 720px), 70svh);
  --panel-radius: 32px;
  --panel-ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --panel-duration: 0.6s;           /* width and name rotation */
  --card-in-duration: 0.35s;        /* label card fade in (scale takes +0.1s) */
  --card-in-delay: 0.35s;           /* so it lands after the name has mostly turned */
  --card-out-duration: 0.15s;

  /* Card and name metrics. The name sits on the card's text position, so
     its offsets are the card's inset plus its padding. */
  --card-inset: 32px;
  --card-pad-x: 28px;
  --card-pad-y: 24px;
  --name-size: 36px;

  /* Panel logos (James, 2026-10-08): the project's background colour
     (--panel-bg, inline on each panel) with its logo centred, scaling with
     the panel. The logo fits a box this share of the panel; on an open
     panel the box's centre rises to clear the label card. */
  --logo-width: 64%;
  --logo-height: 52%;
  --card-height: calc(2 * var(--card-pad-y) + 1.2 * var(--text-label) + 8px + var(--name-size));

  /* "Coming soon" placeholder (docs/handoffs/projects-coming-soon). The
     headline is 148px at 1440 and up; below that it shrinks with the open
     panel's width (row − gaps, its share of the flex) so "coming" never
     clips. 0.234 = 148 / the open panel's width at 1440. */
  --soon-size: min(148px, calc((100cqw - (var(--panel-count) - 1) * var(--panel-gap))
      * var(--panel-flex-open) / (var(--panel-count) - 1 + var(--panel-flex-open)) * 0.234));
  --soon-strip-size: 56px;

  /* No bottom padding: Process's top padding is the gap between them. */
  padding: var(--section-gap) var(--margin) 0;
}

/* Stacked: eyebrow, headline, copy (James's layout, 2026-10-06). */
.projects__head {
  display: block;
}

/* Same eyebrow as the philosophy statement. The .section-* classes are the
   shared section header (Process & services uses them). */
.projects__eyebrow,
.section-eyebrow {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0;
  font-size: var(--text-eyebrow);
  font-weight: 500;                 /* Lato Medium */
  letter-spacing: var(--tracking-eyebrow);
  line-height: 1.2;
  text-transform: uppercase;
}

.projects__eyebrow > span:first-child,
.section-eyebrow > span:first-child {
  margin-right: calc(-1 * var(--tracking-eyebrow));   /* trailing letter-spacing */
}

.projects__rule,
.section-eyebrow__rule {
  flex: none;
  position: relative;
  top: calc(-1 * var(--eyebrow-rule-raise));
  width: 66px;
  height: 2px;
  background: var(--color-accent);
}

.projects__title,
.section-title {
  margin: 32px 0 0 -0.12em;         /* pulled left: optical alignment, as philosophy */
  font-family: var(--font-display);
  font-variation-settings: "opsz" 14, "wdth" 100;
  font-size: var(--text-h2);
  font-weight: var(--weight-section-headline);
  line-height: 1.1;
  letter-spacing: var(--tracking-section-headline);
  text-wrap: balance;
}

.projects__copy,
.section-copy {
  max-width: var(--copy-measure);   /* same line breaks as philosophy */
  margin: 24px 0 0;
  color: var(--color-ink-muted);
  font-size: var(--text-large);   /* copy under a section title: 24 (James, 2026-10-07) */
  line-height: 1.333;
  text-wrap: pretty;                /* no lone last word */
}

/* The row is a size container so a closed panel's resting width can be
   worked out in CSS: (row − gaps) / (closed panels + open flex). */
.projects__panels {
  container-type: inline-size;
  display: flex;
  gap: var(--panel-gap);
  height: var(--panel-height);
  margin-top: clamp(40px, 2.5vw, 48px);   /* gap between the headline block and the panels */
}

.panel {
  flex: 1;
  min-width: 0;
  position: relative;
  overflow: hidden;
  border-radius: var(--panel-radius);
  /* A project sets --panel-bg (its brand colour) and has a .panel__logo;
     without one the panel shows the placeholder stripes. */
  background: var(--panel-bg, repeating-linear-gradient(135deg,
      var(--color-placeholder-a) 0 10px, var(--color-placeholder-b) 10px 20px));
  transition: flex var(--panel-duration) var(--panel-ease);
}

.panel.is-open { flex: var(--panel-flex-open); }

/* Centred in the panel, or on an open panel in the space above the label
   card; it moves with the same timing as the panel's width. */
.panel__logo {
  --clear: 0px;                     /* space kept free at the bottom */
  position: absolute;
  left: 50%;
  top: calc((100% - var(--clear)) / 2);
  width: var(--logo-width);
  height: min(var(--logo-height), calc(100% - var(--clear) - 2 * var(--card-inset)));
  object-fit: contain;
  translate: -50% -50%;
  transition: top var(--panel-duration) var(--panel-ease),
              height var(--panel-duration) var(--panel-ease);
}

.panel.is-open .panel__logo { --clear: calc(var(--card-height) + var(--card-inset)); }

/* Coming soon: cream card on a hairline, "coming / soon." when open, a
   vertical "coming soon." strip when closed; the two crossfade. */
.panel--soon {
  border: 1.5px solid var(--color-hairline);
  background: var(--color-cream);
  color: var(--color-ink);
  cursor: default;
}

.panel__soon,
.panel__soon-strip > span {
  font-family: var(--font-display);
  font-variation-settings: "opsz" 14, "wdth" 100;
  font-weight: var(--weight-section-headline);
  white-space: nowrap;
}

.panel__soon {
  position: absolute;
  left: calc(var(--soon-size) * 38 / 148);      /* 38 at 148 */
  bottom: calc(var(--soon-size) * 34 / 148);    /* 34 at 148 */
  display: flex;
  flex-direction: column;
  font-size: var(--soon-size);
  line-height: 0.8;
  letter-spacing: -0.03em;
  opacity: 0;
  transform: scale(0.96);
  transform-origin: left bottom;
  transition: opacity var(--card-out-duration) ease,
              transform var(--card-out-duration) ease;
}

.panel.is-open .panel__soon {
  opacity: 1;
  transform: scale(1);
  transition: opacity var(--card-in-duration) ease var(--card-in-delay),
              transform calc(var(--card-in-duration) + 0.1s) var(--panel-ease)
                        calc(var(--card-in-delay) - 0.05s);
}

.panel__soon-dot { color: var(--color-accent); }

.panel__soon-strip {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 36px;
  display: flex;
  justify-content: center;
  transition: opacity 0.3s ease;
}

.panel__soon-strip > span {
  writing-mode: vertical-rl;
  transform: rotate(180deg);        /* reads bottom to top */
  font-size: var(--soon-strip-size);
  line-height: 1;
  letter-spacing: -0.02em;
}

.panel.is-open .panel__soon-strip { opacity: 0; }

.panel__card {
  position: absolute;
  left: var(--card-inset);
  bottom: var(--card-inset);
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: var(--card-pad-y) var(--card-pad-x);
  border-radius: 20px;
  background: var(--color-bg);
  white-space: nowrap;
  opacity: 0;
  transform: scale(0.96);
  transform-origin: left bottom;
  transition: opacity var(--card-out-duration) ease,
              transform var(--card-out-duration) ease;
}

.panel.is-open .panel__card {
  opacity: 1;
  transform: scale(1);
  transition: opacity var(--card-in-duration) ease var(--card-in-delay),
              transform calc(var(--card-in-duration) + 0.1s) var(--panel-ease)
                        calc(var(--card-in-delay) - 0.05s);
}

.panel__meta {
  color: var(--color-ink-muted);
  font-size: var(--text-label);
  font-weight: 500;
  letter-spacing: var(--tracking-eyebrow);
  line-height: 1.2;
  text-transform: uppercase;
}

/* Inside the label card, so it comes and goes with the card: closed panels
   show only their image. */
.panel__name {
  color: var(--color-ink);
  font-family: var(--font-display);
  font-variation-settings: "opsz" 14, "wdth" 100;
  font-size: var(--name-size);
  font-weight: var(--weight-section-headline);
  line-height: 1;
  letter-spacing: var(--tracking-section-headline);
  white-space: nowrap;
}

/* Reduced motion: snap, including the card's delay (the global rule above
   shortens durations but leaves delays). */
@media (prefers-reduced-motion: reduce) {
  :root:not([data-motion="full"]) :is(.panel, .panel__card, .panel__logo, .panel__soon, .panel__soon-strip) { transition: none !important; }
}
:root[data-motion="reduce"] :is(.panel, .panel__card, .panel__logo, .panel__soon, .panel__soon-strip) { transition: none !important; }

/* Narrow screens (not designed; the handoff's suggested fallback): panels
   stack, all open, names horizontal, no hover. Also applies to small
   landscape windows, hence its own query rather than the portrait one. */
@media (max-aspect-ratio: 1/1), (max-width: 900px) {
  .projects {
    --panel-height: 400px;
    --name-size: 30px;
    --card-inset: 20px;
    --card-pad-x: 20px;
    --card-pad-y: 18px;
    /* The card's meta and name can each wrap to two lines here. */
    --card-height: calc(2 * var(--card-pad-y) + 2.4 * var(--text-label) + 8px + 2 * var(--name-size));
  }

  .projects__head {
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
  }

  .projects__eyebrow, .section-eyebrow { gap: 12px; }
  .projects__rule, .section-eyebrow__rule { width: 44px; height: 1.5px; }
  .projects__title, .section-title { margin-top: 24px; }

  .projects__panels {
    flex-direction: column;
    height: auto;
    margin-top: 48px;
  }

  .panel,
  .panel.is-open {
    flex: none;
    height: var(--panel-height);
  }

  /* Every card shows here, so every logo clears it. */
  .panel .panel__logo { --clear: calc(var(--card-height) + var(--card-inset)); }

  /* Every panel is open here: the headline shows, the strip doesn't. Sized
     to the panel's full width, at most 104 (not designed; the handoff
     suggests 96–110 at this height). */
  .projects { --soon-size: min(104px, calc(100cqw * 0.234)); }
  .panel .panel__soon { opacity: 1; transform: none; transition: none; }
  .panel .panel__soon-strip { display: none; }

  /* The card may wrap here; the panel is narrower than a long name. */
  .panel__card { right: var(--card-inset); }
  .panel__card,
  .panel__name { white-space: normal; }

  .panel .panel__card {
    opacity: 1;
    transform: none;
    transition: none;
  }
}


/* ---- Process & services -----------------------------------------------
   Handoff: docs/handoffs/process-services (Claude Design). Sizes and colours
   are the site's (type scale, palette), not the handoff's own values. The
   header uses the shared section header (.section-eyebrow / -title / -copy,
   the same rules as Projects). Behaviour and the phase animations:
   js/process.js. */

.process {
  /* Illustration palette for the phase animations only (handoff values). */
  --art-panel: var(--color-placeholder-b);
  --art-ink: var(--color-ink);
  --art-accent: var(--color-accent);
  --art-idle: #B4B1AC;              /* scattered dots before they gather */
  --art-tile: #DEDCD8;              /* empty grid tiles */
  --art-guide: #D5D3D0;             /* baselines and the dashed trajectory */

  --process-ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --process-rule: 1px solid var(--color-ink);   /* dividers in this section */

  /* Large gaps flex like Projects': laptop size → their size at 1920. */
  --gap-big: clamp(80px, 6.77vw, 130px);        /* between the parts */

  padding: var(--section-gap) var(--margin) clamp(120px, 10.42vw, 200px);
}

/* Five phase words, one row that never wraps: sized from the column so all
   five fit (Figma: 86px, which it reaches from about 1920 wide). A display
   piece, like the hero, so it scales rather than using the type scale. */
.process__words {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 16px;
  margin-top: clamp(64px, 5.73vw, 110px);
}

.process__word {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-hairline);
  font-family: var(--font-display);
  font-variation-settings: "opsz" 14, "wdth" 100;
  font-size: min(86px, (100vw - 2 * var(--margin)) * 0.064);   /* handoff 0.066; trimmed so "Grow" clears the edge */
  font-weight: 800;
  line-height: 0.9;
  letter-spacing: -0.05em;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.3s ease;
}

/* The gold bar under the active word grows in from the left. */
.process__word::after {
  content: "";
  width: 0;
  height: 6px;
  border-radius: 6px;
  background: var(--color-accent);
  transition: width 0.4s var(--process-ease);
}

.process__word.is-active { color: var(--color-ink); }
.process__word.is-active::after { width: 100%; }

.process__word:focus-visible { outline-offset: 8px; }

/* Description on the left, animation on the right. */
.process__detail {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 80px;
  align-items: start;
  margin-top: 48px;
  padding-top: 32px;
  border-top: var(--process-rule);
}

.process__desc {
  margin: 0;
  font-size: var(--text-large);
  line-height: 1.45;
  text-wrap: pretty;
}

.process__panel {
  position: relative;
  height: 260px;
  border-radius: 20px;
  background: var(--art-panel);
  overflow: hidden;
}

.process__art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* Each phase's group; process.js sets the elements' on/off values, these
   transitions animate between them. */
.process__phase { opacity: 0; transition: opacity 0.35s ease; }
.process__phase.is-active { opacity: 1; }
.process__art [data-t] { transition: transform var(--t-dur, 0.7s) var(--t-ease, var(--process-ease)) var(--t-delay, 0s); }
.process__art [data-fill] { transition: fill var(--f-dur, 0.35s) ease var(--f-delay, 0s); }
.process__art [data-fade] { transition: opacity var(--o-dur, 0.4s) ease var(--o-delay, 0s); }

/* Launch: the stroke draws along the curve while the dot rides it. */
.process__trace {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 1.1s cubic-bezier(0.5, 0, 0.2, 1) 0.15s;
}

.process__rider {
  offset-path: path("M 70 215 C 230 215 290 200 360 130 S 480 45 530 45");
  offset-rotate: 0deg;
  offset-distance: 0%;
  transition: offset-distance 1.1s cubic-bezier(0.5, 0, 0.2, 1) 0.15s;
}

.is-on .process__trace { stroke-dashoffset: 0; }
.is-on .process__rider { offset-distance: 100%; }

/* Reduced motion: every animation shows its finished state at once. */
@media (prefers-reduced-motion: reduce) {
  :root:not([data-motion="full"]) .process__art * { transition: none !important; }
}
:root[data-motion="reduce"] .process__art * { transition: none !important; }

/* Services accordion. */
.services {
  margin-top: var(--gap-big);
  border-bottom: var(--process-rule);
}

.services__item { border-top: var(--process-rule); }

.services__heading { margin: 0; }

.services__toggle {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 48px;
  gap: 24px;
  align-items: center;
  width: 100%;
  padding: 30px 0;
  border: 0;
  background: none;
  color: var(--color-ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

/* Lato Bold, title case (James, 2026-10-07): the one heading style here
   that isn't a lowercase Bricolage display line. */
.services__name {
  font-size: var(--text-large);
  font-weight: 700;
  line-height: 1.2;
}

.services__price {
  color: var(--color-ink-muted);
  font-size: var(--text-label);
  letter-spacing: 0.02em;
}

/* Same round button as the drawer's close button. */
.services__icon {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border: 2px solid var(--color-ink);
  border-radius: 50%;
  transition: transform 0.4s var(--process-ease), background-color 0.2s ease, color 0.2s ease;
}

.services__icon svg {
  width: 14px;
  height: 9px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
}

.services__toggle:hover .services__icon {
  background: var(--color-ink);
  color: var(--color-bg);
}

.services__item.is-open .services__icon { transform: rotate(180deg); }

.services__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.45s var(--process-ease);
}

.services__item.is-open .services__panel { grid-template-rows: 1fr; }

.services__clip {
  min-height: 0;
  overflow: hidden;
}

.services__list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px 32px;
  margin: 0;
  padding: 0 0 36px;
  list-style: none;
}

.services__list li {
  display: flex;
  align-items: baseline;
  gap: 12px;
  font-size: var(--text-body);
  line-height: 1.4;
}

/* Gold check. */
.services__list li::before {
  content: "";
  flex: none;
  width: 14px;
  height: 11px;
  background: no-repeat center / contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 11'%3E%3Cpath d='M1 5.5l4 4L13 1' fill='none' stroke='%23D69B42' stroke-width='2'/%3E%3C/svg%3E");
}

/* The two of us. */
.people { margin-top: var(--section-gap); }


.people__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 64px;
  margin-top: 48px;
}

.person {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 5fr);
  gap: 40px;
  align-items: start;
}

.person__portrait {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: center top;
  border-radius: 24px;
  /* Shows only while the photo loads. */
  background: var(--color-placeholder-a);
}

.person__text {
  display: flex;
  flex-direction: column;
  gap: 28px;
}

.person__intro {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-bottom: 28px;
  border-bottom: var(--process-rule);
}

.person__name {
  margin: 0;
  font-family: var(--font-display);
  font-variation-settings: "opsz" 14, "wdth" 100;
  font-size: var(--text-h3);
  font-weight: var(--weight-section-headline);
  line-height: 1;
  letter-spacing: var(--tracking-section-headline);
}

.person__role,
.person__label {
  margin: 0;
  font-size: var(--text-label);
  font-weight: 500;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

.person__role { color: var(--color-accent); }
.person__label { color: var(--color-ink-muted); }

.person__skills {
  margin: 0;
  font-size: var(--text-body);
  line-height: 1.5;
  text-wrap: pretty;
}

.person__found {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 8px;
}

.person__found-text {
  margin: 0;
  color: var(--color-ink-muted);
  font-size: var(--text-body);
  line-height: 1.5;
  text-wrap: pretty;
}

/* Narrow screens (not designed; the handoff's suggestion): two-column
   parts stack, services list in two columns (one on phones). The phase
   words keep one row while they're readable; on phones they wrap. */
@media (max-aspect-ratio: 1/1), (max-width: 900px) {
  .process {
    --gap-big: 72px;
    padding-bottom: 110px;
  }

  .process__detail,
  .people__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
  }

  .services__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .people__grid { gap: 56px; }
}

@media (max-width: 600px) {
  .process__words {
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 12px 20px;
    margin-top: 48px;
  }

  .process__word { font-size: 40px; }

  .services__toggle {
    grid-template-columns: minmax(0, 1fr) 48px;
    row-gap: 6px;
    padding: 24px 0;
  }

  .services__price { grid-row: 2; }
  .services__icon { grid-column: 2; grid-row: 1 / span 2; }
  .services__list { grid-template-columns: minmax(0, 1fr); }

  .person { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  .person__portrait { width: min(240px, 66%); }
}


/* ---- Footer / contact ---------------------------------------------------
   James's design of 2026-10-07: the shared section header on the drawer's
   dark brown, one call to action, then the sign-off bar (shared with the
   drawer footer). "Browse FAQs" is left off for now. */
.site-footer {
  padding: clamp(96px, 8.33vw, 160px) var(--margin) 40px;
  background: var(--color-drawer);
  color: #fff;
}

.site-footer .section-title { color: var(--color-cream); }

.site-footer .section-copy {
  color: #fff;
  font-weight: 400;
}

.site-footer__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  margin-top: 48px;
}

.site-footer .footer-bar { margin-top: clamp(80px, 6.77vw, 130px); }

@media (max-aspect-ratio: 1/1), (max-width: 900px) {
  .site-footer { padding-block: 80px 32px; }
}


/* ---- Contact form modal ------------------------------------------------
   James's mockup of 2026-10-07 (copy as given), in the site's styles: the
   drawer's cream card, backdrop and close button, the shared eyebrow, a
   lowercase Bricolage title, Lato everything else, the gold pill button.
   A native modal <dialog> (focus trap, Escape, top layer); js/contact.js
   opens, closes, animates and sends it (Netlify Forms). */

.contact {
  /* Knobs. */
  --contact-width: 560px;
  --contact-pad: 44px;              /* same as the case study cards */
  --contact-in: 0.35s;
  --contact-out: 0.2s;
  --contact-ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --field-radius: 12px;
  --contact-frame: 40px;            /* brown frame round the card (James, 2026-10-07) */

  width: min(var(--contact-width) + 2 * var(--contact-frame), 100vw - 32px);
  max-width: none;
  max-height: calc(100svh - 32px);
  padding: var(--contact-frame);
  border: 0;
  border-radius: 28px;              /* as the drawer sheet */
  background: var(--color-drawer);
  color: var(--color-ink);
  overflow: visible;
  box-shadow: 0 30px 90px color-mix(in srgb, var(--color-ink) 22%, transparent);
}

.contact::backdrop { background: var(--color-backdrop); }

/* Desktop layout only (landscape, wider than 900, i.e. not the stacked
   layout): the right edge sits on the page margin, where the nav ends.
   Everywhere else, and always when it opens over a case study
   (.is-over-drawer, set by contact.js), it's centred (James, 2026-10-07). */
@media (min-width: 901px) and (min-aspect-ratio: 1001/1000) {
  .contact { margin-right: var(--margin); }
  .contact.is-over-drawer { margin-right: auto; }
}

/* Open: fade and rise; closing (.is-closing): fade out. */
.contact[open] { animation: contact-in var(--contact-in) var(--contact-ease); }
.contact[open]::backdrop { animation: contact-fade var(--contact-in) ease; }
.contact.is-closing { animation: contact-out var(--contact-out) ease forwards; }
.contact.is-closing::backdrop { animation: contact-fade var(--contact-out) ease reverse forwards; }

@keyframes contact-in { from { opacity: 0; transform: translateY(24px); } }
@keyframes contact-out { to { opacity: 0; transform: translateY(12px); } }
@keyframes contact-fade { from { opacity: 0; } }

.contact__card {
  position: relative;
  max-height: calc(100svh - 32px - 2 * var(--contact-frame));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--contact-pad);
  border-radius: 24px;
  background: var(--color-cream);
}

/* Same round button as the drawer's close. */
.contact__close {
  position: absolute;
  top: 20px;
  right: 20px;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 2px solid var(--color-ink);
  border-radius: 50%;
  background: var(--color-cream);
  color: var(--color-ink);
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.contact__close:hover {
  background: var(--color-ink);
  color: var(--color-cream);
}

.contact__close svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}

.contact__title {
  margin: 24px 0 0 -0.06em;         /* optical alignment, as the section titles */
  font-family: var(--font-display);
  font-variation-settings: "opsz" 14, "wdth" 100;
  font-size: min(var(--text-h2), 44px);
  font-weight: var(--weight-section-headline);
  line-height: 1.05;
  letter-spacing: var(--tracking-section-headline);
}

.contact__intro {
  margin: 16px 0 0;
  color: var(--color-ink-muted);
  font-size: var(--text-input);
  line-height: 1.45;
  text-wrap: pretty;
}

.contact__form {
  display: flex;
  flex-direction: column;
  gap: 20px;
  margin-top: 32px;
}

.contact__field {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Sentence case Lato (James, 2026-10-07), written that way in the HTML. */
.contact__label {
  font-size: var(--text-pill);
  font-weight: 700;
}

.contact__optional {
  color: var(--color-ink-muted);
  font-weight: 400;
}

.contact__input {
  width: 100%;
  padding: 14px 16px;
  border: 1px solid var(--color-hairline);
  border-radius: var(--field-radius);
  background: #fff;
  color: var(--color-ink);
  font: 400 var(--text-input) / 1.4 var(--font-body);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.contact__input::placeholder { color: color-mix(in srgb, var(--color-ink-muted) 75%, transparent); }

.contact__input:hover { border-color: var(--color-ink-muted); }

.contact__input:focus {
  outline: none;
  border-color: var(--color-ink);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 35%, transparent);
}

/* Only after the visitor has interacted (not on first open). */
.contact__input:user-invalid { border-color: var(--color-error); }

.contact__input--area {
  min-height: 120px;
  resize: vertical;
}

/* "How did you hear about us?": a native dropdown (<select>) drawn like the
   other fields, with our chevron. The empty first option reads as a
   placeholder. */
.contact__input--pick {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  padding-right: 44px;
  background: #fff no-repeat right 16px center / 14px 9px
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 9'%3E%3Cpath d='M1 1.5l6 6 6-6' fill='none' stroke='%232D3236' stroke-width='2'/%3E%3C/svg%3E");
}

.contact__input--pick:has(option[value=""]:checked) {
  color: color-mix(in srgb, var(--color-ink-muted) 75%, transparent);
}

.contact__input--pick option { color: var(--color-ink); }

.contact__submit {
  gap: 16px;
  width: 100%;
  margin-top: 8px;
}

.contact__submit[disabled] { opacity: 0.6; cursor: progress; }

.contact__arrow {
  width: 24px;
  height: auto;
  flex: none;
}

.contact__note {
  margin: 0;
  color: var(--color-ink-muted);
  font-size: var(--text-label);
  text-align: center;
}

.contact__error {
  margin: 0;
  color: var(--color-error);
  font-size: var(--text-label);
  text-align: center;
}

.contact__error a { text-decoration: underline; }

.contact__done .button-cta { margin-top: 32px; }

/* Reduced motion: no open/close animation. */
@media (prefers-reduced-motion: reduce) {
  :root:not([data-motion="full"]) .contact,
  :root:not([data-motion="full"]) .contact::backdrop { animation: none !important; }
}
:root[data-motion="reduce"] .contact,
:root[data-motion="reduce"] .contact::backdrop { animation: none !important; }

@media (max-width: 600px) {
  .contact { --contact-pad: 24px; --contact-frame: 16px; }
  .contact__close { top: 12px; right: 12px; }
  .contact__title { margin-top: 16px; }
}


/* ---- Dropdown -------------------------------------------------------------
   A designed dropdown over a real <select data-dropdown> (js/dropdown.js).
   The button wears the field's own classes (e.g. .contact__input); this
   adds the chevron, the panel and the motion. data-motion picks how the
   panel opens: drop | unfold | settle. Reduced motion: the global rule
   above shortens every transition, so it simply appears. */

.dropdown {
  /* Knobs. */
  --dropdown-ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --dropdown-in: 0.22s;
  --dropdown-out: 0.14s;
  --dropdown-radius: 12px;

  position: relative;
}

/* The real select: still in the form, not on screen. */
.dropdown__native {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
}

.dropdown__button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  text-align: left;
  cursor: pointer;
  background-image: none;           /* the field's own chevron; ours turns */
}

.dropdown__button.is-empty .dropdown__value {
  color: color-mix(in srgb, var(--color-ink-muted) 75%, transparent);
}

.dropdown__value {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dropdown__chevron {
  display: grid;
  place-items: center;
  flex: none;
  transition: transform 0.3s var(--dropdown-ease);
}

.dropdown__chevron svg {
  width: 14px;
  height: 9px;
  fill: none;
  stroke: var(--color-ink);
  stroke-width: 2;
}

.dropdown.is-open .dropdown__chevron { transform: rotate(180deg); }

.dropdown.is-open .dropdown__button {
  border-color: var(--color-ink);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 35%, transparent);
}

/* Panel. Fixed to the window by dropdown.js (top/bottom, left, width). */
.dropdown__list {
  position: fixed;
  z-index: 20;
  margin: 0;
  padding: 6px;
  overflow-y: auto;
  overscroll-behavior: contain;
  border: 1px solid var(--color-hairline);
  border-radius: var(--dropdown-radius);
  background: #fff;
  box-shadow: 0 18px 40px color-mix(in srgb, var(--color-ink) 16%, transparent);
  list-style: none;
}

.dropdown__option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 12px;
  border-radius: 8px;
  color: var(--color-ink);
  font: 400 var(--text-input) / 1.3 var(--font-body);
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.dropdown__option.is-active { background: color-mix(in srgb, var(--color-accent) 14%, transparent); }

.dropdown__option[aria-selected="true"] { font-weight: 700; }

/* Gold check on the chosen answer. */
.dropdown__option[aria-selected="true"]::after {
  content: "";
  flex: none;
  width: 14px;
  height: 11px;
  background: no-repeat center / contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 11'%3E%3Cpath d='M1 5.5l4 4L13 1' fill='none' stroke='%23D69B42' stroke-width='2'/%3E%3C/svg%3E");
}

/* Motion A, drop: fades in and settles down from the field. */
.dropdown[data-motion="drop"] .dropdown__list {
  opacity: 0;
  transform: translateY(-8px) scale(0.98);
  transform-origin: top center;
  transition: opacity var(--dropdown-out) ease, transform var(--dropdown-out) ease;
}

.dropdown[data-motion="drop"] .dropdown__list.is-up { transform: translateY(8px) scale(0.98); transform-origin: bottom center; }

.dropdown[data-motion="drop"] .dropdown__list.is-shown {
  opacity: 1;
  transform: none;
  transition: opacity var(--dropdown-in) ease, transform var(--dropdown-in) var(--dropdown-ease);
}

/* Motion B, unfold: the panel unrolls from the field, options follow one by
   one. */
.dropdown[data-motion="unfold"] .dropdown__list {
  clip-path: inset(0 0 100% 0 round var(--dropdown-radius));
  transition: clip-path var(--dropdown-out) ease;
}

.dropdown[data-motion="unfold"] .dropdown__list.is-up { clip-path: inset(100% 0 0 0 round var(--dropdown-radius)); }

.dropdown[data-motion="unfold"] .dropdown__list.is-shown {
  clip-path: inset(0 0 0 0 round var(--dropdown-radius));
  transition: clip-path 0.3s var(--dropdown-ease);
}

.dropdown[data-motion="unfold"] .dropdown__option {
  opacity: 0;
  transform: translateY(-4px);
  transition: background-color 0.15s ease, opacity 0.1s ease, transform 0.1s ease;
}

.dropdown[data-motion="unfold"] .is-shown .dropdown__option {
  opacity: 1;
  transform: none;
  transition: background-color 0.15s ease,
              opacity 0.25s ease calc(60ms + var(--i) * 30ms),
              transform 0.3s var(--dropdown-ease) calc(60ms + var(--i) * 30ms);
}

/* Motion C, settle: grows from the field with a small overshoot. */
.dropdown[data-motion="settle"] .dropdown__list {
  opacity: 0;
  transform: scale(0.9);
  transform-origin: top center;
  transition: opacity var(--dropdown-out) ease, transform var(--dropdown-out) ease;
}

.dropdown[data-motion="settle"] .dropdown__list.is-up { transform-origin: bottom center; }

.dropdown[data-motion="settle"] .dropdown__list.is-shown {
  opacity: 1;
  transform: none;
  transition: opacity 0.18s ease, transform 0.38s cubic-bezier(0.34, 1.56, 0.64, 1);
}


/* ---- Case study drawer ------------------------------------------------
   Handoff: docs/handoffs/case-study-drawer (open/close motion; the motion
   constants are CONFIG in js/drawer.js). Layout: Figma "TLC Case Study v2"
   (file gWWhmdmX9bFQuoEanmYnOu, node 365:137), designed at 1440 wide with an
   80px margin. Figma px are real px: type from the type scale (:root),
   everything else as in Figma. The sheet is placed so the cards' *content*
   lines up with the homepage margin (--margin); it is wider than the
   homepage copy by the sheet padding plus the card padding. Content wider
   than the column wraps (lists, headings). */

.drawer {
  /* Knobs. */
  --drawer-top: 56px;               /* gap above the sheet */
  --drawer-radius: 28px;
  --drawer-pad: 40px;   /* sheet padding around the cards */
  --card-pad: 44px;
  --card-radius: 24px;
  --card-gap: 40px;  /* between the cards */
  --sheet-inset: max(0px, calc(var(--margin) - var(--drawer-pad) - var(--card-pad)));

  position: fixed;
  inset: 0;
  z-index: 50;
  visibility: hidden;
  pointer-events: none;
}

.drawer.is-open {
  visibility: visible;
  pointer-events: auto;
}

.drawer__backdrop {
  position: absolute;
  inset: 0;
  background: var(--color-backdrop);
  opacity: 0;
}

.drawer.is-open .drawer__backdrop { opacity: 1; }

.drawer__sheet {
  position: absolute;
  inset: var(--drawer-top) var(--sheet-inset) 0;
  overflow: hidden;
  border-radius: var(--drawer-radius) var(--drawer-radius) 0 0;
  background: var(--color-drawer);
  box-shadow: 0 30px 90px color-mix(in srgb, var(--color-ink) 22%, transparent);
}

.drawer__scroller {
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Sticky, zero height: only the close button shows, so no bar covers the
   cards. The button has its own fill so it reads over cream and dark alike. */
.drawer__bar {
  position: sticky;
  top: 0;
  z-index: 3;
  height: 0;
}

.drawer__close {
  position: absolute;
  top: 16px;
  right: 20px;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 2px solid var(--color-ink);
  border-radius: 50%;
  background: var(--color-cream);
  color: var(--color-ink);
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.drawer__close:hover {
  background: var(--color-ink);
  color: var(--color-cream);
}

.drawer__close svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}

.drawer__inner {
  display: flex;
  flex-direction: column;
  padding: var(--drawer-pad);
}

.drawer__content {
  display: flex;
  flex-direction: column;
  gap: var(--card-gap);
}

/* Type, shared by every case study (Figma sizes × --a, with floors). */
.cs-h1,
.cs-h2,
.cs-h3 {
  margin: 0;
  font-family: var(--font-display);
  font-variation-settings: "opsz" 14, "wdth" 100;
  font-weight: 700;                 /* Figma: Bold (section headlines on the page are 600) */
  line-height: 1;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.cs-h1 { font-size: var(--text-h1); }
.cs-h2 { font-size: var(--text-h2); }

.cs-h3 {
  color: var(--color-ink-muted);
  font-size: var(--text-h3);
}

.cs-body {
  margin: 0;
  font-size: var(--text-body);
  letter-spacing: 0.02em;
  line-height: normal;
}

.cs-body--intro {
  color: #000;
  letter-spacing: 0.04em;
}

.cs-card {
  padding: var(--card-pad);
  border-radius: var(--card-radius);
  background: var(--color-cream);
  color: var(--color-ink);
}

/* Intro card: title, rule and copy; spec table; cover image on the right. */
.cs-intro {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 100px;
  row-gap: 80px;
}

.cs-intro__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 40px;
}

.cs-intro__rule {
  width: 245px;
  height: 0;
  border-top: 4px solid var(--color-accent-strong);
}

/* The cover keeps its own proportions (a portrait poster with a border that
   must not be cropped), top-aligned; the text column may run longer. */
.cs-intro__media {
  position: relative;
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: start;
  min-width: 0;
  aspect-ratio: 1172 / 1502;
  border-radius: 16px;
  overflow: hidden;
}

.cs-intro__media img,
.cs-grid img,
.cs-result img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.cs-intro__media img {
  position: absolute;
  inset: 0;
}

.cs-spec {
  grid-column: 1;
  grid-row: 2;
  align-self: end;
  margin: 0;
  font-size: var(--text-label);
  letter-spacing: 0.04em;
}

.cs-spec__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  min-height: 60px;
}

.cs-spec__row:nth-child(1) { border-bottom: 1px solid var(--color-ink-muted); }
.cs-spec__row:nth-child(3) { border-top: 1px solid var(--color-ink-muted); }

.cs-spec dt { text-transform: uppercase; }

.cs-spec dd {
  margin: 0;
  letter-spacing: 0;
  text-align: right;
}

.cs-spec ul {
  display: flex;
  align-items: center;
  margin: 0;
  padding: 0;
  list-style: none;
}

.cs-spec li + li::before {
  content: "|";
  margin-inline: 12px;
}

/* Section cards: a pill, headline and copy, then image blocks. */
.cs-section {
  display: flex;
  flex-direction: column;
  gap: 88px;
}

.cs-block {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

/* The intro block and keywords sit closer to each other than the section gap. */
.cs-stack {
  display: flex;
  flex-direction: column;
  gap: 56px;
}

.cs-intro-block {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 40px;
  max-width: 580px;
}

.cs-pill {
  padding: 10px 20px;
  border: 1px solid var(--color-accent-strong);
  border-radius: 10px;
  background: var(--color-accent);
  font-size: var(--text-pill);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.cs-keywords {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 32px;
  margin: 0;
  padding: 0;
  color: #2A2727;
  font-size: var(--text-h3);
  font-weight: 300;                 /* Lato Light */
  list-style: none;
}

.cs-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 32px;
}

.cs-grid > * {
  margin: 0;
  aspect-ratio: 624 / 372;
  border-radius: 8px;
  overflow: hidden;
}

/* Diamond-separated lists. Each <ul> is a row as authored in Figma; on a
   narrower column it wraps. Every item has a diamond in front; each <ul>
   is pulled left by one diamond-and-gaps and .cs-lists clips it, so the
   diamond that starts any line (first item or wrapped) is hidden. */
/* On desktop each row stays on one line across the photos' width: the text
   scales with the column (a size container), like Figma, where 20px rows
   fit a 1280 column; never larger than --text-body. Diamonds and gaps are
   in em so they scale with it. */
.cs-lists {
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  gap: 16px;
  overflow: hidden;
}

.cs-list {
  --diamond: 0.8em;                 /* 16px at 20px */
  --diamond-gap: 0.8em;             /* each side of a diamond */
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  margin: 0 0 0 calc(-1 * (var(--diamond) + 2 * var(--diamond-gap)));
  padding: 0;
  list-style: none;
  font-size: min(var(--text-body), 1.55cqw);   /* the widest row (style direction) just fits */
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.cs-list li {
  display: flex;
  align-items: center;
}

.cs-list li::before {
  content: "";
  flex: none;
  width: var(--diamond);
  height: var(--diamond);
  margin-inline: var(--diamond-gap);
  background: var(--color-accent-strong);
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}

/* Palette and typography. */
.cs-pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 100px;
}

.cs-pair > * {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.cs-swatches {
  display: flex;
  flex: 1;
  gap: 8px;
  min-height: 260px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.cs-swatches li {
  flex: 1;
  border-radius: 8px;
  background: var(--swatch);
}

.cs-specimen {
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding: 40px;
  border: 1px solid var(--color-hairline);
  border-radius: 10px;
}

.cs-specimen__aa {
  display: flex;
  align-items: center;
  gap: 60px;
  font-size: clamp(64px, 4.583vw, 88px);
  letter-spacing: -0.02em;
  line-height: 1;
}

.cs-specimen__aa > :first-child { font-family: var(--cs-display-font); font-weight: 700; }
.cs-specimen__aa > :last-child { font-family: var(--cs-body-font); font-weight: 300; }

.cs-specimen hr {
  width: 100%;
  margin: 0;
  border: 0;
  border-top: 1px solid var(--color-hairline);
}

.cs-specimen__label {
  display: block;
  margin-bottom: 16px;
  color: var(--color-ink-muted);
  font-size: var(--text-label);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.cs-specimen__name {
  margin: 0;
  font-size: 24px;
  line-height: 1;
}

.cs-specimen__name--display { font-family: var(--cs-display-font); font-weight: 700; }
.cs-specimen__name--body { font-family: var(--cs-body-font); font-weight: 400; }

.cs-specimen__sample {
  margin: 0;
  color: var(--color-ink-muted);
  font-family: var(--cs-body-font);
  font-size: 24px;
  line-height: 1.2;
  overflow-wrap: anywhere;
}

/* The result image keeps its own proportions: set --ratio on .cs-result to
   the image's width / height (Teri Lynn Clark's is the default). */
.cs-result {
  aspect-ratio: var(--ratio, 2278 / 1220);
}

/* A row of images at one shared height, uncropped, each as wide as its
   proportions need: set --ratio (width / height) on each figure. Same gap
   and corners as .cs-grid (James, 2026-10-08: Eye Candy's box and card). */
.cs-row {
  display: flex;
  gap: 32px;
}

.cs-row > * {
  flex: calc(var(--ratio)) 1 0;     /* calc() turns "744 / 1136" into a number */
  min-width: 0;
  margin: 0;
  border-radius: 8px;
  overflow: hidden;
}

.cs-row img {
  display: block;
  width: 100%;
  height: auto;
}

/* A project without a case study yet. */
.cs-stub {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-end;
  gap: 24px;
  min-height: 480px;
}

/* Previous / next. */
/* Previous / next: at the bottom of the last card (drawer.js puts it there),
   text and arrow only. */
.drawer__pager {
  display: flex;
  justify-content: center;
  gap: 215px;
  margin-top: 140px;
}

.drawer__pager-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 24px;
  width: 243px;
  height: 60px;
  padding: 0 32px;
  border: 0;
  background: none;
  color: var(--color-ink);
  font: 800 var(--text-button) / 1 var(--font-body);   /* Lato Heavy (Figma: ExtraBold) */
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
}

.drawer__pager-btn--prev { color: #464646; }

/* Hover (not in Figma): the arrow nudges outward. */
.drawer__pager-btn .cs-arrow { transition: transform 0.2s ease; }
.drawer__pager-btn--next:hover .cs-arrow { transform: translateX(4px); }
.drawer__pager-btn--prev:hover .cs-arrow { transform: scaleX(-1) translateX(4px); }

.drawer__pager-btn .cs-arrow {
  flex: none;
  display: block;
  width: 24px;
  height: auto;
}

.drawer__pager-btn--prev .cs-arrow { transform: scaleX(-1); }

/* Footer: "ready to connect?" and the sign-off (bar, logo, copyright and
   the button are shared with the page footer; see "Footer" below). */
.drawer__footer {
  padding: calc(130px - var(--drawer-pad)) var(--card-pad) 40px;
  color: #fff;
}

.drawer__cta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 40px;
  max-width: 571px;
}

.drawer__cta h2 {
  margin: 0;
  color: var(--color-cream);
  font-family: var(--font-display);
  font-variation-settings: "opsz" 14, "wdth" 100;
  font-size: var(--text-h2);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
}

.drawer__cta p {
  margin: 0;
  font-size: var(--text-lead);
  font-weight: 400;                 /* Lato Regular (James, 2026-10-07) */
  letter-spacing: 0.03em;
  line-height: 1.333;
}

/* The main call to action ("Tell us about it"), page footer and drawer. */
.button-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 283px;
  height: 60px;
  padding: 0 32px 0 calc(32px + 0.2em);   /* trailing letter-spacing */
  border-radius: 100px;             /* a pill, like "Let's talk" */
  background: var(--color-accent-strong);
  color: var(--color-ink);
  border: 0;
  font: 800 var(--text-button) / 1 var(--font-body);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.button-cta:hover { background: var(--color-cream); }

/* Sign-off bar under both footers: rule, light logo, copyright. */
.footer-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  margin-top: 77px;
  padding-top: 24px;
  border-top: 1px solid #fff;
}

.footer-logo {
  display: grid;
  justify-items: end;
}

.footer-logo img {
  display: block;
  height: 50px;
  width: auto;
}

/* "DESIGNS" under the logo: Lato, like the hero's (James, 2026-10-07). */
.footer-logo span {
  margin-top: -6px;
  margin-right: -0.46em;            /* trailing letter-spacing */
  font-family: var(--font-body);
  font-size: 7px;
  letter-spacing: 0.46em;
}

.footer-copyright {
  margin: 0;
  font-size: 16px;
  letter-spacing: 0.05em;
  line-height: 2;
}

/* Below 1200 wide the one-line rows would get too small to read: the
   lists become bullet lists, as on phones. */
@media (max-width: 1199px) {
  .cs-list {
    flex-direction: column;
    align-items: flex-start;
    row-gap: 12px;
    margin-left: 0;
    font-size: var(--text-body);
    white-space: normal;
  }

  .cs-list li::before { margin-left: 0; }
}


/* ---- Stacked layout (phones, portrait tablets) --------------------------
   First attempt, not designed in Figma yet. Values are px on a 390-wide
   phone, × var(--m). The string runs top-left to bottom-right like desktop,
   between a can under "tin" and a can above "line". */

@media (max-aspect-ratio: 1/1) {
  :root {
    /* Type scale on phones. */
    --text-h1: 36px;
    --text-h2: 32px;
    --text-h3: 22px;
    --text-large: 19px;
    --text-lead: 17px;
    --text-body: 17px;
    --text-eyebrow: 13px;

    --m: calc(100vw / 390);
    --margin: calc(20 * var(--m));
    --header-pad: calc(16 * var(--m));
    --header-pad-scrolled: 10px;
  }

  .site-header { padding-inline: var(--margin); }

  .logo { font-size: calc(32 * var(--m)); }

  .nav-toggle {
    display: block;
    padding: 6px 16px;
    border: 1.5px solid var(--color-ink);
    border-radius: 100px;
    background: none;
    color: var(--color-ink);
    font: 500 15px/1.4 var(--font-body);
    cursor: pointer;
  }

  .nav-toggle[aria-expanded="true"] {
    background: var(--color-ink);
    color: var(--color-on-ink);
  }

  .site-nav {
    display: none;
    position: absolute;
    right: var(--margin);
    top: calc(100% + 4px);
    padding: 8px;
    border-radius: 24px;
    background: var(--color-bg);
    box-shadow: 0 12px 32px color-mix(in srgb, var(--color-ink) 15%, transparent);
  }

  .site-nav.is-open { display: block; }

  .site-nav ul {
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
  }

  /* Dropdown: same words, left-aligned, always ink. */
  .site-nav__item > * { text-align: left; }

  .site-nav__sizer,
  .site-nav a {
    padding: 8px 20px;
    font-size: 20px;
    line-height: 1.5;
  }

  .site-header.is-scrolled .site-nav:has(a[aria-current]) a { color: var(--color-ink); }

  .hero {
    height: auto;
    min-height: 100svh;
  }

  .hero__stage {
    position: relative;
    top: auto;
    translate: none;
    height: calc(850 * var(--m));
  }

  .hero__word { font-size: calc(170 * var(--m)); }

  .hero__word--tin {
    left: calc(var(--margin) - 6 * var(--m));
    top: calc(64 * var(--m));
  }

  .hero__word--line {
    right: calc(var(--margin) - 8 * var(--m));
    top: calc(460 * var(--m));
  }

  .hero__designs {
    right: calc(var(--margin) - 4 * var(--m));
    top: calc(640 * var(--m));
    font-size: calc(16 * var(--m));
  }

  .hero__tagline {
    left: 50%;
    top: calc(700 * var(--m));
    font-size: calc(13 * var(--m));
  }

  .hero__cta {
    left: 50%;
    top: calc(772 * var(--m));
    min-width: calc(180 * var(--m));
    height: calc(52 * var(--m));
    padding-inline: calc(24 * var(--m));
  }

  .hero__anchor { --can-unit: calc(var(--m) * 0.75); }

  .hero__anchor--a {
    --can-angle: -35;
    left: calc(var(--margin) + 50 * var(--m));
    top: calc(300 * var(--m));
  }

  .hero__anchor--b {
    --can-angle: 150;
    left: calc(100% - var(--margin) - 52 * var(--m));
    top: calc(440 * var(--m));
  }

  /* Philosophy, stacked: not designed yet (the handoff asks design to do
     mobile). Same timeline, a taller and narrower run of string. */
  .philosophy {
    --a: calc(var(--m) * 0.44);     /* string geometry on a 390 phone */
    --statement-top: calc(1100 * var(--m));
    --timeline-end: calc(1600 * var(--m));
  }

  .philosophy__can-anchor {
    --can-unit: calc(var(--m) * 0.75);
    left: calc(var(--margin) + 40 * var(--m));
    top: calc(1020 * var(--m));
  }

  .philosophy__eyebrow { gap: 12px; }
  .philosophy__rule { width: 44px; height: 1.5px; }
  .philosophy__title { margin-top: 24px; }
  .philosophy__copy { margin-top: 18px; }
}


/* ---- Case study drawer, stacked (phones, portrait tablets) --------------
   Not designed. Same cards, one column, the phone type scale (:root); the
   sheet runs edge to edge and the content margin falls back to the sheet
   and card padding. */

@media (max-aspect-ratio: 1/1), (max-width: 900px) {
  .drawer {
    --drawer-top: 24px;
    --drawer-pad: 12px;
    --card-pad: 20px;
    --card-gap: 12px;
    --card-radius: 18px;
    --sheet-inset: 0px;
  }

  .drawer__close { top: 12px; right: 12px; }

  .cs-intro {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 32px;
  }

  .cs-intro__media {
    grid-column: 1;
    grid-row: auto;
    order: 2;
    align-self: auto;
  }

  .cs-spec { grid-column: 1; grid-row: auto; order: 3; }

  .cs-section { gap: 40px; }
  .cs-intro-block { max-width: none; }
  .cs-grid { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .cs-row { flex-direction: column; gap: 12px; }
  .cs-row > * { flex: none; }       /* full width, natural height */
  .cs-pair { grid-template-columns: minmax(0, 1fr); row-gap: 40px; }
  .cs-swatches { min-height: 160px; }
  .cs-specimen { padding: 20px; }
  .cs-specimen__aa { font-size: 64px; gap: 32px; }
  .cs-intro__rule { width: 160px; }
  .cs-keywords { gap: 4px 20px; }

  /* One item per line, every diamond showing, as bullets. */
  .cs-list {
    flex-direction: column;
    align-items: flex-start;
    row-gap: 12px;
    margin-left: 0;
    font-size: var(--text-body);
    white-space: normal;
  }
  .cs-list li::before { margin-left: 0; }
  .cs-lists { gap: 12px; }

  .drawer__pager { gap: 12px; margin-top: 40px; }
  .drawer__pager-btn { flex: 1; width: auto; min-width: 0; padding: 0 16px; }

  .drawer__footer { padding: 56px 20px 32px; }
  .button-cta { min-width: 0; width: 100%; }
  .footer-bar { flex-direction: column; align-items: flex-start; margin-top: 48px; }
  .footer-copyright { line-height: 1.5; }
}
