/* ============================================================
   OctoDraws — implemented from Figma
   File: IG Post – Second Set (MKT7zFh2JUpELoR8ANPkTd)

   index.html
     HeroPage  1086:5    1400 x 850
     Frame 2   1088:28   1400 x 262
     Frame 3   1088:41   1400 x 1737
     Frame 4   1088:102  1400 x 1158
     Frame 5   1088:139  1400 x 907    (home footer)

   contact.html
     Frame 6   1088:177  1400 x 900    (step 1)
     Frame 7   1090:192  1400 x 900    (step 2)
     Frame 8   1090:311  1400 x 900    (step 3)
     Frame 9   1090:324  1400 x 900    (thank you)
     Frame 10  1109:527  1400 x 1028   (contact footer)
   ============================================================ */

:root {
  /* Figma variables */
  --octodraws-black: #000000;
  --octodraws-icon-purple: #e3a4fe;
  --octodraws-white: #ffffff;

  /* Local colours taken from the design */
  --card-placeholder: #d9d9d9;
  --motion-maroon: #550f10;
  --soma-green: #688e26;

  --font-sans: "Instrument Sans", "Helvetica Neue", Arial, sans-serif;
  --font-geometric: "Century Gothic", "URW Gothic", "Jost", "Questrial", var(--font-sans);

  /* Canvas the design was drawn on */
  --design-w: 1400;

  /* How large the 1400px Figma canvas renders on a wide screen.
     1 = Figma's own sizing; 0.8 = everything 20% smaller, proportions intact.
     This single number controls the scale of the entire site. */
  --canvas-scale: 0.8;
  --canvas-max: calc(var(--design-w) * 1px * var(--canvas-scale));   /* 1120px */

  /* One Figma pixel */
  --px: calc(min(100vw, var(--canvas-max)) / var(--design-w));
}

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

html { scroll-behavior: smooth; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--octodraws-black);
}

body {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img { display: block; }

/* ---------- Layout primitives ---------- */

.page {
  width: min(100%, var(--canvas-max));
  margin-inline: auto;
  background: var(--octodraws-black);
  container-type: inline-size;
}

/* A Figma frame: fixed canvas height, children placed absolutely.
   --px is re-derived from the page container so a vertical scrollbar
   never pushes the canvas wider than the viewport. */
.section {
  --px: calc(100cqw / var(--design-w));
  position: relative;
  width: 100%;
  height: calc(var(--h) * var(--px));
  background: var(--octodraws-black);
  overflow: hidden;
  scroll-margin-top: 0;
}

/* Anything placed by Figma coordinates. */
.abs {
  position: absolute;
  left:   calc(var(--l) * var(--px));
  top:    calc(var(--t) * var(--px));
  width:  calc(var(--w) * var(--px));
  height: calc(var(--h) * var(--px));
}

/* Right-aligned layers Figma exports as left + translateX(-100%). */
.abs--from-right { transform: translateX(-100%); }

/* Image crop box: the <img> is oversized and positioned inside it. */
.crop { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.crop img { position: absolute; max-width: none; }

/* ---------- Type styles (from the Figma text styles) ---------- */

.txt {
  margin: 0;
  font-family: var(--font-sans);
  font-size: calc(var(--fs) * var(--px));
  letter-spacing: calc(var(--ls, 0) * var(--px));
  line-height: 1.2;
  font-variation-settings: "wdth" 100;
  word-break: break-word;
  color: var(--octodraws-white);
}

/* Website H1 — Bold 48 / 1.2 / -3% */
.t-h1     { --fs: 48; --ls: -1.44; font-weight: 700; }
/* Website Subtitle — Bold 36 / 1.2 / -3% */
.t-sub    { --fs: 36; --ls: -1.08; font-weight: 700; }
/* Website Subtext — Medium 24 / 1.2 / -3% */
.t-sub24  { --fs: 24; --ls: -0.72; font-weight: 500; }
/* Website FAQ Description — Regular 24 / 1.2 / -3% */
.t-faq24  { --fs: 24; --ls: -0.72; font-weight: 400; }
/* Website Brand Caption — Regular 15 / 1.2 / 0 */
.t-cap15  { --fs: 15; --ls: 0;     font-weight: 400; }
/* Body copy — Regular 32 / 1.2 / 0 */
.t-body32 { --fs: 32; --ls: 0;     font-weight: 400; }
/* FAQ question — Medium 32 / 1.2 / -3% */
.t-med32  { --fs: 32; --ls: -0.96; font-weight: 500; }
/* Medium 36 / 1.2 / -3% — FAQ toggle, contact form labels */
.t-med36  { --fs: 36; --ls: -1.08; font-weight: 500; }
/* Medium 48 / 1.2 / -3% — contact page headings */
.t-med48  { --fs: 48; --ls: -1.44; font-weight: 500; }
/* Regular 14 / 1.2 / -3% — contact form note */
.t-note14 { --fs: 14; --ls: -0.42; font-weight: 400; }

.on-white { color: #000000; }
.pre-wrap { white-space: pre-wrap; }

/* Labels that exist for screen readers only — the design shows the field's
   name as placeholder text instead. */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- Shared nav (identical across every frame) ---------- */

.hero-wordmark    { --l: 35;  --t: 23; --w: 312; --h: 46; }
.hero-nav-home    { --l: 570; --t: 23; --w: 134; --h: 46; }
.hero-nav-work    { --l: 782; --t: 23; --w: 122; --h: 46; }
.hero-nav-contact { --l: 982; --t: 23; --w: 180; --h: 46; }

.nav-link {
  display: block;
  text-decoration: none;
  color: var(--octodraws-white);
  transition: color 160ms ease;
}
.nav-link:hover { color: var(--octodraws-icon-purple); }
.nav-link:focus-visible {
  outline: calc(2 * var(--px)) solid var(--octodraws-white);
  outline-offset: calc(4 * var(--px));
}

/* ============================================================
   index.html — 1. HeroPage (1086:5)
   ============================================================ */
#home { --h: 850; }

/* Sits 13px past the frame's bottom edge — the section clips it, as in Figma. */
.hero-art { --l: 2; --t: 245; --w: 1396; --h: 618; }

/* Base artwork and the paint canvas share one box, so nothing moves or reflows. */
.hero-art-base,
.hero-art-paint {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  pointer-events: none;
}
/* Strokes land here; empty until the cursor paints. */
.hero-art-paint { display: block; }

/* Preloaded variation sources — never rendered, only read by the canvas. */
.hero-art-sources { display: none; }

/* ============================================================
   index.html — 2. Featured Work intro (1088:28)
   ============================================================ */
#work { --h: 262; }

.intro-title { --l: 57;  --t: 74; --w: 281; --h: 86; }
.intro-copy  { --l: 397; --t: 72; --w: 947; --h: 119; }

/* ============================================================
   index.html — 3. Work cards (1088:41)
   ============================================================ */
#works { --h: 1737; }

.card {
  background: var(--card-placeholder);
  border-radius: calc(40 * var(--px));
  overflow: hidden;
}
/* A work card that links through to its case study. */
.work-link {
  display: block;
  text-decoration: none;
  transition: transform 180ms ease, box-shadow 180ms ease;
}
.work-link:hover {
  transform: translateY(calc(-6 * var(--px)));
  box-shadow: 0 calc(18 * var(--px)) calc(40 * var(--px)) rgba(0, 0, 0, 0.45);
}
.work-link:focus-visible {
  outline: calc(3 * var(--px)) solid var(--octodraws-white);
  outline-offset: calc(4 * var(--px));
}

/* Figma 1088:41 reordered the stack to Motion, Soma, Baseline. Each card now
   carries its own caption pill, so every coordinate below the card line is
   card-relative and reads straight off the Figma tree. */
.card-motion   { --l: 54;  --t: 47;   --w: 952; --h: 462; }
.card-soma     { --l: 388; --t: 585;  --w: 952; --h: 462; }
.card-baseline { --l: 54;  --t: 1123; --w: 952; --h: 462; }

/* Baseline artwork (1102:416) */
.baseline-media { --l: -11; --t: 0; --w: 978; --h: 462; }
.baseline-media img { left: 0; top: -90.32%; width: 98.98%; height: 280.65%; }

/* Motion artwork — nested IG post frame (1102:418) */
.motion-frame {
  --l: 0; --t: -489; --w: 952; --h: 951;
  background: var(--motion-maroon);
  overflow: hidden;
}
.motion-media { --l: 0; --t: 488; --w: 952; --h: 455; }
.motion-media img { left: 0.04%; top: -70.53%; width: 99.96%; height: 278.86%; }

/* Soma artwork (1102:444 + 1102:468 + 1102:446) */
.soma-backdrop { --l: 0; --t: 0; --w: 965; --h: 477; }
.soma-backdrop img { left: -2.18%; top: -126.12%; width: 102.18%; height: 283.27%; }

.soma-media { --l: 0; --t: 0; --w: 960; --h: 477; }
.soma-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: bottom;
  pointer-events: none;
}

.soma-headline {
  --l: 61; --t: 85; --w: 830; --h: 166;
  margin: 0;
  font-family: var(--font-geometric);
  font-weight: 700;
  font-size: calc(80 * var(--px));
  line-height: calc(90 * var(--px));
  color: var(--octodraws-white);
  word-break: break-word;
}
.soma-headline em {
  font-style: italic;
  color: var(--soma-green);
}

/* White caption pills */
.pill {
  background: var(--octodraws-white);
  border-radius: calc(20 * var(--px));
  --w: 903; --h: 97;
}
.pill-motion   { --l: 24; --t: 332; }
.pill-soma     { --l: 24; --t: 340; }
.pill-baseline { --l: 24; --t: 340; }

.tag-motion    { --l: 42;  --t: 354; --w: 94;  --h: 35; }
.name-motion   { --l: 246; --t: 354; --w: 141; --h: 35; }
.desc-motion   { --l: 498; --t: 354; --w: 412; --h: 54; }

.tag-soma      { --l: 42;  --t: 356; --w: 184; --h: 35; }
.name-soma     { --l: 300; --t: 356; --w: 141; --h: 35; }
.desc-soma     { --l: 515; --t: 356; --w: 395; --h: 66; }

.tag-baseline  { --l: 42;  --t: 362; --w: 94;  --h: 35; }
.name-baseline { --l: 246; --t: 362; --w: 141; --h: 35; }
.desc-baseline { --l: 498; --t: 362; --w: 412; --h: 54; }

.all-works {
  --l: 1340; --t: 1650; --w: 494; --h: 43;
  text-align: right;
  color: var(--octodraws-white);
  text-decoration: underline;
  text-decoration-skip-ink: none;
  text-underline-position: from-font;
  transition: color 160ms ease;
}
.all-works:hover { color: var(--octodraws-icon-purple); }
.all-works:focus-visible {
  outline: calc(2 * var(--px)) solid var(--octodraws-white);
  outline-offset: calc(4 * var(--px));
}

/* ============================================================
   index.html — 4. FAQ (1088:102)
   ============================================================ */
/* Collapsed, the rows sit exactly where Figma puts them: first question at
   y=297, 157px apart, section 1158 tall (297 + 5×33 + 4×124 + 200). Opening a
   panel grows the section and pushes the rows below it down. */
#faq {
  --h: 1158;
  height: auto;
  min-height: calc(var(--h) * var(--px));
  overflow: visible;
  padding-top: calc(297 * var(--px));
  padding-bottom: calc(198 * var(--px));
}

.faq-title { --l: 77; --t: 150; --w: 831; --h: 86; }

.faq-item {
  position: relative;
  --ql: 397;   /* question left edge    */
  --pr: 64;    /* sign inset from right */
}
/* Figma's row gaps are 157 / 158 / 158 / 157, not uniform. */
.faq-item + .faq-item           { margin-top: calc(124 * var(--px)); }
.faq-item + .faq-item--gap125   { margin-top: calc(125 * var(--px)); }

/* Row 5 sits 9px left of the others in the Figma frame. */
.faq-item--offset { --ql: 388; --pr: 73; }

.faq-trigger {
  display: block;
  position: relative;
  width: 100%;
  height: calc(33 * var(--px));
  margin: 0;
  padding: 0 0 0 calc(var(--ql) * var(--px));
  background: none;
  border: 0;
  text-align: left;
  cursor: pointer;
  color: var(--octodraws-white);
  transition: color 160ms ease;
}
.faq-trigger:hover { color: var(--octodraws-icon-purple); }
.faq-trigger:focus-visible {
  outline: calc(2 * var(--px)) solid var(--octodraws-white);
  outline-offset: calc(6 * var(--px));
}

.faq-sign {
  position: absolute;
  top: 0;
  right: calc(var(--pr) * var(--px));
  display: block;
  width: calc(17 * var(--px));
  text-align: right;
}

/* 0fr → 1fr animates to the panel's natural height. */
.faq-panel {
  display: grid;
  grid-template-rows: 0fr;
  padding-top: 0;
  padding-left: calc(var(--ql) * var(--px));
  transition: grid-template-rows 250ms cubic-bezier(0.4, 0, 0.2, 1),
              padding-top   250ms cubic-bezier(0.4, 0, 0.2, 1);
}
.faq-panel > div { overflow: hidden; }
.faq-panel p {
  margin: 0;
  max-width: calc(760 * var(--px));
  opacity: 0;
  transition: opacity 160ms ease;
}

.faq-item.is-open .faq-panel {
  grid-template-rows: 1fr;
  padding-top: calc(11 * var(--px));   /* puts line 1 at question top + 44 */
}
.faq-item.is-open .faq-panel p {
  opacity: 1;
  transition: opacity 200ms ease 90ms;
}

@media (prefers-reduced-motion: reduce) {
  .faq-panel, .faq-panel p { transition-duration: 1ms; }
}

/* ============================================================
   work.html — Work index (1169:3994, 1400 x 3238)
   ============================================================ */
#work-index { --h: 3238; }

.work-title { --l: 281; --t: 241; --w: 831; --h: 58; text-align: center; }

/* One entry = clipped image frame + caption pill, lifting together. */
.work-item { --w: 952; --h: 462; }
.work-inner {
  position: absolute;
  inset: 0;
  display: block;
  text-decoration: none;
  border-radius: calc(40 * var(--px));
  transition: transform 280ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.work-inner .card { transition: box-shadow 280ms ease; }
.work-inner .card img { transition: transform 520ms cubic-bezier(0.2, 0.7, 0.3, 1); }

.work-inner:hover { transform: translateY(calc(-10 * var(--px))); }
.work-inner:hover .card {
  box-shadow: 0 calc(26 * var(--px)) calc(55 * var(--px)) rgba(0, 0, 0, 0.55);
}
.work-inner:hover .card img { transform: scale(1.045); }
.work-inner:focus-visible {
  outline: calc(3 * var(--px)) solid var(--octodraws-white);
  outline-offset: calc(6 * var(--px));
}

/* Only entries that link somewhere get the pointer. */
a.work-inner { cursor: pointer; }

/* Baseline moves to the end, so the other four each take the slot above.
   The slots themselves are unchanged and keep alternating left and right. */
.wi-motion   { --l: 59;  --t: 477;  }
.wi-soma     { --l: 392; --t: 1017; }
.wi-form     { --l: 59;  --t: 1557; }
.wi-receipt  { --l: 392; --t: 2097; }
.wi-baseline { --l: 59;  --t: 2662; }

/* Card-local coordinates (identical offsets across every entry). */
.wi-card { --l: 0; --t: 0; --w: 952; --h: 462; }
.wi-pill { --l: 24; --t: 340; --w: 903; --h: 97; }
.wi-pill--motion { --t: 332; }

.wi-tag  { --w: 94;  --h: 35; }
.wi-name { --w: 141; --h: 35; }
.wi-desc { --w: 412; --h: 54; }

/* Form artwork */
.form-media { --l: 0; --t: 0; --w: 952; --h: 462; }
.form-media img { left: -0.05%; top: -81.18%; width: 99.97%; height: 275.92%; }

/* Receipt artwork — the Figma frame stacks three full-bleed layers; the
   top one is opaque and covers the other two, so only it is rendered. */
.receipt-media { --l: 0; --t: 0; --w: 952; --h: 462; }
.receipt-media img { left: 0.01%; top: -98.3%; width: 100.05%; height: 274.89%; }

/* Scroll-in reveal */
.reveal {
  opacity: 0;
  transform: translateY(calc(28 * var(--px)));
  transition: opacity 480ms ease, transform 480ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  .work-inner, .work-inner .card img { transition: none; }
  .work-inner:hover { transform: none; }
  .work-inner:hover .card img { transform: none; }
}

/* ============================================================
   Footer — home (1088:139, 907 tall)
   and contact (1109:527, 1028 tall, everything 135px lower)
   ============================================================ */
.site-footer { --h: 907; }

.footer-art { --l: 2; --t: 41; --w: 1396; --h: 618; }
.footer-art img {
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  pointer-events: none;
}

.footer-bar {
  --l: 34; --t: 669; --w: 1331; --h: 197;
  background: var(--octodraws-icon-purple);
  border-radius: calc(20 * var(--px));
}

.footer-badge {
  --l: 1181; --t: 688; --w: 163; --h: 160;
  background: var(--octodraws-black);
  border-radius: calc(20 * var(--px));
}

.footer-mark { --l: 1192; --t: 708; --w: 142; --h: 120; }
.footer-mark img { left: -37.46%; top: -55.15%; width: 176.88%; height: 209.23%; }

.fh-navigate { --l: 59;  --t: 689; --w: 246; --h: 38; }
.fh-social   { --l: 387; --t: 689; --w: 206; --h: 38; }
.fh-contact  { --l: 777; --t: 689; --w: 317; --h: 38; }

.f-item { --h: 29; }
.f-home      { --l: 59;  --t: 745; --w: 246; }
.f-work      { --l: 59;  --t: 781; --w: 246; }
.f-contact   { --l: 59;  --t: 817; --w: 246; }
.f-instagram { --l: 387; --t: 745; --w: 118; }
.f-linkedin  { --l: 387; --t: 781; --w: 118; }
.f-x         { --l: 387; --t: 817; --w: 20;  }
.f-email     { --l: 777; --t: 745; --w: 380; }
.f-site      { --l: 777; --t: 781; --w: 334; }

.f-link {
  display: block;
  color: #000000;
  text-decoration: none;
  transition: opacity 160ms ease;
}
/* The footer sits on the purple bar, so the accent is already the background
   here and purple-on-purple would disappear. These keep full black contrast
   and show the hover as an underline instead. */
.f-link:hover { opacity: 1; text-decoration: underline; }
/* X has no destination yet. It keeps its place and its resting appearance but
   does not pretend to be clickable. */
.f-link[aria-disabled] { cursor: default; }
.f-link[aria-disabled]:hover { opacity: 1; text-decoration: none; }
.f-link:focus-visible {
  outline: calc(2 * var(--px)) solid #000000;
  outline-offset: calc(3 * var(--px));
}

/* Case-study footer — the octopus artwork belongs to the home page, so the
   work pages drop it. The art filled design-y 41..659; without it the whole
   bar block moves up by 628 and the frame loses the same amount, which is
   what closes the gap above the footer. The 41 tail below the bar is kept,
   and the bar itself is untouched. */
.site-footer--work { --h: 279; }
.site-footer--work .footer-bar    { --t: 41; }
.site-footer--work .footer-badge  { --t: 60; }
.site-footer--work .footer-mark   { --t: 80; }
.site-footer--work .fh-navigate,
.site-footer--work .fh-social,
.site-footer--work .fh-contact    { --t: 61; }
.site-footer--work .f-home,
.site-footer--work .f-instagram,
.site-footer--work .f-email       { --t: 117; }
.site-footer--work .f-work,
.site-footer--work .f-linkedin,
.site-footer--work .f-site        { --t: 153; }
.site-footer--work .f-contact,
.site-footer--work .f-x           { --t: 189; }

/* Contact-page footer — Frame 10 (1109:527).
   The octopus artwork belongs to the home page, so this frame drops it too.
   It filled design-y 179..797 and the bar began at 804; without it the bar
   block moves up by 763 and the frame loses the same amount, keeping the 27
   tail the contact frame had below the bar. The bar itself is unchanged. */
.site-footer--contact { --h: 265; }
.site-footer--contact .footer-bar    { --t: 41; }
.site-footer--contact .footer-badge  { --t: 60; }
.site-footer--contact .footer-mark   { --t: 80; }
.site-footer--contact .fh-navigate,
.site-footer--contact .fh-social,
.site-footer--contact .fh-contact    { --t: 61; }
.site-footer--contact .f-home,
.site-footer--contact .f-instagram,
.site-footer--contact .f-email       { --t: 117; }
.site-footer--contact .f-work,
.site-footer--contact .f-linkedin,
.site-footer--contact .f-site        { --t: 153; }
.site-footer--contact .f-contact,
.site-footer--contact .f-x           { --t: 189; }

/* With the artwork gone the page can be shorter than the window, which would
   leave the footer stranded mid-screen above a band of background. Making the
   page a full-height column and pushing the footer down with auto margin keeps
   it on the bottom edge when the content is short, and lets it sit after the
   content as normal when the form grows. */
.page--contact {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
}
.page--contact > * { flex: 0 0 auto; }
.page--contact > .site-footer { margin-top: auto; }

/* ============================================================
   Case-study pages on phones (work-*.html, .page--case)

   On desktop a case page is one tall Figma frame: the panel pinned at the
   left and every card placed by absolute coordinates on a 1400-wide canvas.
   Shrinking that to 390px makes the whole thing illegible, so below 760px the
   frame becomes a single column — panel first, then the cards in DOM order,
   which is already their top-to-bottom order on desktop.

   Nothing inside a block is re-laid-out. Each block keeps its own Figma
   coordinates and only --px is re-derived from that block's own design width,
   so a card that is 909 wide in Figma simply renders its 909-unit canvas at
   the column width. That is why the artwork, type and spacing inside every
   card stay exactly in proportion.

   Desktop is untouched: every rule here lives inside the media query.
   ============================================================ */
@media (max-width: 760px) {
  .page--case {
    --m-gutter: 16px;
    --m-gap: 18px;
    --m-col: calc(100cqw - 2 * var(--m-gutter));
    /* The pinned panel is the only block that does not render at its full
       canvas width — at 1:1 it took nearly half the screen. 0.84 is as far as
       it scales before the step labels stop being comfortable to read. */
    --m-panel-scale: 0.84;
  }

  /* Nav — sized off a phone-width canvas instead of 1400, narrow enough that
     the wordmark and all three links still sit on one line. */
  .page--case > header.section {
    --px: calc(100cqw / 980);
    height: auto;
    padding: calc(26 * var(--px)) var(--m-gutter);
    display: flex;
    align-items: baseline;
    gap: calc(24 * var(--px));
    flex-wrap: wrap;
  }
  .page--case > header.section .abs {
    position: static;
    width: auto;
    height: auto;
  }
  .page--case > header.section nav {
    display: flex;
    gap: calc(24 * var(--px));
    margin-left: auto;
  }

  /* The case frame stops being a fixed-height canvas and becomes a column. */
  .page--case .case-bl,
  .page--case .case-rc,
  .page--case .case,
  .page--case .case-fm,
  .page--case .case-sm {
    height: auto;
    overflow: visible;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--m-gap);
    padding: var(--m-gutter) var(--m-gutter) calc(2 * var(--m-gutter));
  }

  /* The panel is the frame's first child, so it opens the page, and it stays
     pinned to the top while the cards scroll underneath — the same behaviour
     as the desktop column. Its canvas is 470 wide (383 on Form). The height
     cap keeps it from swallowing the viewport when a step is open; past that
     the panel scrolls inside itself.

     Unlike desktop, the steps do not advance with the scroll — the reader
     opens them by tapping. That is handled in each page's script. */
  .page--case .bl-panel,
  .page--case .rc-panel,
  .page--case .mo-panel,
  .page--case .fm-panel,
  .page--case .sm-panel {
    position: sticky;
    top: var(--m-gutter);
    z-index: 3;
    margin-left: 0;
    /* Full bleed like the cards, but its contents run at --m-panel-scale. */
    width: var(--m-col);
    max-height: calc(100svh - 2 * var(--m-gutter));
    overflow: hidden auto;
    overscroll-behavior: contain;
    /* One divisor for all five. Form's panel canvas is 383 rather than 470,
       which at its own divisor rendered half a phone screen tall and with
       visibly larger type than the other four; since the width is forced here,
       the divisor only sets content scale, so sharing it makes every case page
       read at the same size. */
    --px: calc(var(--m-col) / 470 * var(--m-panel-scale));
  }

  /* Each page's script lifts these two out of the panel — the intro to just
     below it, the next-project row to the end of the case study. Both run at
     the panel's unscaled size, because standing on their own they are body
     copy rather than panel furniture, and both take the column width. */
  .page--case .bl-intro,
  .page--case .rc-intro,
  .page--case .mo-intro,
  .page--case .fm-intro,
  .page--case .sm-intro,
  .page--case .bl-next-row,
  .page--case .rc-next-row,
  .page--case .mo-next-row,
  .page--case .fm-next-row,
  .page--case .sm-next-row {
    --px: calc(var(--m-col) / 470);
    width: var(--m-col);
    max-width: 100%;
    margin-top: 0;
  }

  /* Every card the frame places by coordinate becomes a block in the column.
     .abs still computes its own width and height from --w/--h, which now
     resolve to the column width and a proportional height. */
  .page--case .case-bl > .abs,
  .page--case .case-rc > .abs,
  .page--case .case > .abs,
  .page--case .case-fm > .abs,
  .page--case .case-sm > .abs {
    position: relative;
    left: auto;
    top: auto;
    --px: calc(var(--m-col) / var(--w));
  }
}

/* ============================================================
   Contact form on phones

   The steps are one 1400-wide canvas with every field at an absolute x, so
   scaling alone cannot fix them: large enough to read and the content runs off
   the screen, small enough to fit and 36px type lands at about 10px. Below
   760px the canvas is dropped and the step becomes a stacked column instead —
   header, heading, then each control full width. The option pills and buttons
   survive this because their captions are nested inside them rather than
   floating over them.
   ============================================================ */
@media (max-width: 760px) {
  .page--contact .contact-step {
    --px: calc(100cqw / 660);
    height: auto;
    min-height: 0;
    overflow: visible;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: calc(22 * var(--px));
    padding: calc(22 * var(--px)) 16px calc(34 * var(--px));
  }
  /* The step toggle has to keep winning over the display above. */
  .page--contact .contact-step[hidden] { display: none; }

  /* Everything the frame placed by coordinate joins the column. */
  .page--contact .contact-step .abs {
    position: static;
    left: auto; top: auto;
    width: auto; height: auto;
  }

  /* Wordmark and nav run smaller than the form copy, as on the work pages. */
  .page--contact .contact-step > .hero-wordmark,
  .page--contact .contact-step > nav { --px: calc(100cqw / 980); }
  .page--contact .contact-step > nav {
    display: flex;
    gap: calc(26 * var(--px));
  }

  .page--contact .contact-title,
  .page--contact .thanks-title { text-align: left; }

  /* These all have to out-rank the .abs reset above, which sets width and
     height to auto — hence the full three-class selectors. */
  .page--contact .contact-step .field { width: 100%; }
  .page--contact .contact-step .field-problem,
  .page--contact .contact-step .field-brand {
    min-height: calc(200 * var(--px));
    padding: calc(14 * var(--px)) calc(16 * var(--px));
  }

  /* Radio groups stack; each pill is a full-width tap target. */
  .page--contact .contact-step [role="radiogroup"] {
    display: flex;
    flex-direction: column;
    gap: calc(12 * var(--px));
  }
  .page--contact .contact-step .opt {
    position: relative;
    width: 100%;
    min-height: calc(78 * var(--px));
    display: flex;
    align-items: center;
    padding: calc(10 * var(--px)) calc(18 * var(--px));
  }
  .page--contact .contact-step .opt-text { text-align: left; }

  .page--contact .contact-step .btn {
    width: 100%;
    min-height: calc(78 * var(--px));
    display: flex;
    align-items: center;
    justify-content: center;
  }

  /* 14px of a 1400 canvas is unreadable at this scale. */
  .page--contact .contact-step .note-budget { font-size: calc(19 * var(--px)); }

  /* In the phone column the error joins the flow directly under its field,
     so it needs no measuring. */
  .page--contact .contact-step .field-error {
    position: static;
    width: auto;
    font-size: calc(26 * var(--px));
    margin-top: calc(-10 * var(--px));
  }
}

/* ============================================================
   contact.html — the four steps (Frames 6, 7, 8, 9)
   ============================================================ */
.contact-step { --h: 900; }
.contact-step[hidden] { display: none; }

/* Headings */
.contact-title      { --l: 281; --t: 241; --w: 831; --h: 58; text-align: center; }
.contact-title--s2  { --t: 195; }
.thanks-title       { --l: 277; --t: 321; --w: 831; --h: 58; text-align: center; }
.thanks-body        { --l: 149; --t: 468; --w: 1102; --h: 172; }
.thanks-body p      { margin: 0; }

/* --- Step 1 (1088:177) --- */
/* The Figma frame shows only the label text, no input chrome. Each field is
   an input sitting exactly on that text box with the label as its placeholder,
   so the step renders identically to the design until someone types. */
.field {
  display: block;
  background: transparent;
  border: 0;
  border-bottom: calc(1 * var(--px)) solid rgba(255, 255, 255, 0.25);
  border-radius: 0;
  padding: 0;
  color: var(--octodraws-white);
  font-family: var(--font-sans);
  font-size: calc(var(--fs) * var(--px));
  letter-spacing: calc(var(--ls, 0) * var(--px));
  font-weight: 500;
  line-height: 1.2;
  font-variation-settings: "wdth" 100;
  transition: border-color 160ms ease;
}
.field::placeholder { color: var(--octodraws-white); opacity: 1; }
.field:hover { border-bottom-color: var(--octodraws-icon-purple); }
.field:focus {
  outline: none;
  border-bottom-color: var(--octodraws-white);
}
.field:focus::placeholder { opacity: 0.4; }

/* Fields keep the design's left edge and baseline; they run to the right
   edge of the button column (x=1245) so there is room to type. */
.field-name    { --l: 154; --t: 479; --w: 1091; --h: 43; --fs: 36; --ls: -1.08; }
.field-email   { --l: 154; --t: 541; --w: 1091; --h: 43; --fs: 36; --ls: -1.08; }
.field-website { --l: 154; --t: 603; --w: 1091; --h: 43; --fs: 36; --ls: -1.08; }

/* --- Step 2 (1090:192) --- */
/* The brand question is an addition above Company Stage, so step 2 is 130px
   taller than the other frames and every row below the new one has moved down
   by exactly 130. Labels keep x=154 and answers x=570, as in the design. */
#step-2 { --h: 1030; }

.label-brand  { --l: 154; --t: 289; --w: 400; --h: 43; }
.field-brand  {
  --l: 570; --t: 275; --w: 675; --h: 130; --fs: 24; --ls: -0.72;
  border: calc(1 * var(--px)) solid rgba(255, 255, 255, 0.25);
  border-radius: calc(10 * var(--px));
  padding: calc(14 * var(--px)) calc(16 * var(--px));
  resize: none;
}
.field-brand:hover { border-color: var(--octodraws-icon-purple); }
.field-brand:focus { border-color: var(--octodraws-white); }

.label-stage  { --l: 154; --t: 489; --w: 258; --h: 43; }
.label-budget { --l: 154; --t: 653; --w: 346; --h: 43; }
.label-date   { --l: 154; --t: 755; --w: 180; --h: 43; }
.note-budget  { --l: 154; --t: 702; --w: 338; --h: 17; }

.field-date   { --l: 570; --t: 755; --w: 200; --h: 43; --fs: 36; --ls: -1.08; }

/* Selectable option pills. The label is the grey box; its caption is a
   separate layer at the Figma coordinates and lets clicks through. */
.opt {
  display: block;
  background: var(--card-placeholder);
  border: 0;
  border-radius: calc(10 * var(--px));
  padding: 0;
  cursor: pointer;
  transition: background-color 160ms ease;
}
.opt-input {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
/* Hovering previews the colour the pill takes once it is chosen. */
.opt:hover { background: var(--octodraws-icon-purple); }
.opt:has(.opt-input:checked) { background: var(--octodraws-icon-purple); }
.opt:has(.opt-input:focus-visible) {
  outline: calc(2 * var(--px)) solid var(--octodraws-white);
  outline-offset: calc(3 * var(--px));
}
.opt-text { pointer-events: none; text-align: center; }

.opt-ideation    { --l: 570;  --t: 449; --w: 354; --h: 89; }
.opt-growing     { --l: 950;  --t: 449; --w: 295; --h: 38; }
.opt-established { --l: 950;  --t: 500; --w: 295; --h: 38; }
.opt-enterprise  { --l: 570;  --t: 556; --w: 675; --h: 38; }

/* Captions live inside their box, so these are box-relative: Figma's value
   less the box origin. The pair has to travel together once the step reflows
   into a phone column. */
.txt-ideation    { --l: 15;   --t: 30;  --w: 323; --h: 29; }
.txt-growing     { --l: 14;   --t: 4;   --w: 267; --h: 29; }
.txt-established { --l: 11;   --t: 5;   --w: 270; --h: 22; }
.txt-enterprise  { --l: 82;   --t: 4;   --w: 511; --h: 23; }

.opt-b1 { --l: 570;  --t: 657; --w: 158; --h: 38; }
.opt-b2 { --l: 740;  --t: 657; --w: 158; --h: 38; }
.opt-b3 { --l: 909;  --t: 657; --w: 158; --h: 38; }
.opt-b4 { --l: 1087; --t: 657; --w: 158; --h: 38; }

.txt-b1 { --l: 8;  --t: 7; --w: 142; --h: 23; }
.txt-b2 { --l: 8;  --t: 8; --w: 142; --h: 21; }
.txt-b3 { --l: 8;  --t: 8; --w: 142; --h: 23; }
.txt-b4 { --l: 19; --t: 7; --w: 120; --h: 24; }

/* --- Step 3 (1090:311) --- */
.question-problem { --l: 148; --t: 488; --w: 720; --h: 43; }

/* Not in the Figma frame: the frame poses the question but draws no answer
   field, so this textarea fills the empty band above the buttons. */
.field-problem {
  --l: 148; --t: 551; --w: 1157; --h: 140; --fs: 24; --ls: -0.72;
  border: calc(1 * var(--px)) solid rgba(255, 255, 255, 0.25);
  border-radius: calc(10 * var(--px));
  padding: calc(14 * var(--px)) calc(16 * var(--px));
  resize: none;
}
.field-problem:hover { border-color: var(--octodraws-icon-purple); }
.field-problem:focus { border-color: var(--octodraws-white); }

/* --- Required fields --- */
/* The asterisk rides along with its label rather than taking a box of its own,
   so no question moves. */
.req {
  margin-left: calc(6 * var(--px));
  color: var(--octodraws-icon-purple);
}

/* A field's error sits in the gap the design already leaves beneath it, so
   showing one never pushes the form around. JS measures the field and places
   it; on phones the step is a flow column and it simply follows its field. */
.field-error {
  position: absolute;
  margin: 0;
  color: #ff9b9b;
  font-family: var(--font-sans);
  font-size: calc(15 * var(--px));
  line-height: 1.1;
  font-variation-settings: "wdth" 100;
  pointer-events: none;
}
.field-error[hidden] { display: none; }

.field.is-invalid            { border-bottom-color: #ff9b9b; }
.field-brand.is-invalid,
.field-problem.is-invalid    { border-color: #ff9b9b; }
.opt.is-invalid              { box-shadow: 0 0 0 calc(2 * var(--px)) #ff9b9b; }

/* Submission error line — sits between the two step-3 buttons. */
.form-status {
  --l: 320; --t: 720; --w: 760; --h: 24;
  text-align: center;
  color: #ff9b9b;
}
.form-status[hidden] { display: none; }

/* --- Buttons (all four steps) --- */
.btn {
  display: block;
  background: var(--card-placeholder);
  border: 0;
  padding: 0;
  cursor: pointer;
  transition: background-color 160ms ease;
}
.btn:hover { background: var(--octodraws-icon-purple); }
.btn:focus-visible {
  outline: calc(2 * var(--px)) solid var(--octodraws-white);
  outline-offset: calc(3 * var(--px));
}
.btn-text { pointer-events: none; text-align: center; }

.btn-round  { border-radius: calc(40 * var(--px)); }
.btn-square { border-radius: calc(10 * var(--px)); }

/* Button captions are box-relative for the same reason as the option ones. */
/* Step 1 */
.btn-next-1  { --l: 1047; --t: 701; --w: 198; --h: 38; }
.txt-next-1  { --l: 24; --t: 7; --w: 150; --h: 23; }

/* Step 2 */
.btn-prev-2  { --l: 154;  --t: 865; --w: 198; --h: 38; }
.txt-prev-2  { --l: 27; --t: 6; --w: 150; --h: 23; }
.btn-next-2  { --l: 1047; --t: 865; --w: 198; --h: 38; }
.txt-next-2  { --l: 27; --t: 5; --w: 150; --h: 23; }

/* Step 3 */
.btn-prev-3  { --l: 95;   --t: 714; --w: 198; --h: 38; }
.txt-prev-3  { --l: 27; --t: 6; --w: 150; --h: 23; }
.btn-next-3  { --l: 1107; --t: 714; --w: 198; --h: 38; }
.txt-next-3  { --l: 24; --t: 7; --w: 150; --h: 23; }
