/* ============================================================
   Studio Fritz — base tokens (verified against Figma 175:1004)
   Colors: brand orange #ffa000, cream #ffe7be, dark ink #1c1123
   Fonts: EB Garamond (display wordmark) / Estedad ExtraLight (everything else)
   Spacing scale: 4/8/12/16/24/32/40/48/64/80/96/120 (deliberately
   normalized — Figma's own gaps are inconsistent, this scale wins)
   ============================================================ */
:root{
  --orange: #ffa000;
  --orange-light: #ffc159; /* derived tint of --orange (mix ~35% white) -- no Figma token for this exists, flag if it's not the shade meant */
  --cream: #ffe7be;
  --ink: #1c1123;
  --white: #ffffff;
  --line: rgba(255,255,255,0.28);

  /* ---- FLUID SCALE -------------------------------------------------
     1u = one Figma pixel at the 1440 reference frame (100/1440 =
     .0694vw). Every desktop dimension below is a multiple of it, so the
     composition scales as ONE unit rather than each value scaling by its
     own rule. That mix is what actually broke things: percentage-based
     positions moved while hardcoded px stayed put, so captions outgrew
     their images, the logomark drifted off the cap line, and the tiles
     left a strip on the right of a wide screen.

     At exactly 1440 this is 1px, so the design renders at true size and
     every Figma number in this file still reads as itself. Clamped so it
     stops shrinking around 1150 -- which is exactly where mobile now takes
     over, so there is no range where this has stopped scaling but the
     window is still narrowing -- and stops growing at 2px (a ~2880-wide
     window), which is the knob for how large the composition gets on a big
     display. Was 1.4px (~2016 wide); Eliza (2026-10-03): on a wide window the
     Custom photos stopped short of the right edge and the copy sat too far
     left -- the 1440u composition no longer filled the window. Raised so it
     keeps scaling like Figma's frame up to a 5K-class display.

     Two things deliberately do NOT use it: hairlines/borders (a .8px
     border renders fuzzy) and the mobile block below 1152px, which has its
     own scale token (--mu, one Figma pixel at the 402 mobile frame). ------------------------------ */
  --u: clamp(0.8px, 0.0694vw, 2px);

  --sp-4: calc(4 * var(--u));  --sp-8: calc(8 * var(--u));
  --sp-12: calc(12 * var(--u)); --sp-16: calc(16 * var(--u));
  --sp-24: calc(24 * var(--u)); --sp-32: calc(32 * var(--u));
  --sp-40: calc(40 * var(--u)); --sp-48: calc(48 * var(--u));
  --sp-64: calc(64 * var(--u)); --sp-80: calc(80 * var(--u));
  --sp-96: calc(96 * var(--u)); --sp-120: calc(120 * var(--u));

  --edge: var(--sp-16);
  --section-gap: var(--sp-24);

  --nav-gap: calc(33 * var(--u)); /* wordmark bottom -> docked nav top; Figma 460:1999 */

  --fs-headline: calc(20 * var(--u));
  --fs-body: calc(16 * var(--u));
  --fs-input: calc(16 * var(--u));
  --fs-cta: calc(15 * var(--u));

  --font-display: "EB Garamond", Georgia, serif;
  --font-body: "Estedad", ui-sans-serif, system-ui, sans-serif;
}
@media (min-width: 760px){
  :root{ --edge: var(--sp-40); --section-gap: var(--sp-80); }
}

*{ box-sizing: border-box; }
html{ scroll-behavior: smooth; overscroll-behavior: none; }
/* Nothing on this site is meant to scroll sideways. `clip` rather than
   `hidden` on purpose: `hidden` turns html into a scroll container, which
   would break every position:sticky on the page (the header, the carousel
   pane). `clip` trims the overflow without creating one. The carousels
   still scroll, because they are descendants with their own overflow-x. */
html, body{ overflow-x: clip; } /* no rubber-band
  at the page bottom: that bounce fights the carousel scroll-takeover down
  there, so the input reads as the page struggling rather than handing over */
body{
  margin:0;
  background: var(--orange);
  color: var(--white);
  font-family: var(--font-body);
  font-weight: 200; /* ExtraLight */
  -webkit-font-smoothing: antialiased;
}
a{ color:inherit; }
img, video{ max-width:100%; height:auto; display:block; } /* height:auto is
  load-bearing, not tidiness: an <img> with width/height ATTRIBUTES (which we
  set for layout stability) has them applied as presentational hints, so a
  CSS `width:100%` with no matching height leaves the height pinned at the
  attribute's px value -- the image stretches vertically and squashes
  horizontally, worse the narrower the viewport. Rules that genuinely want a
  fixed height (.tile-media img, the icon sizes) are all more specific and
  still win. */
:focus-visible{ outline: 2px solid var(--ink); outline-offset: 3px; }

.eyebrow{
  font-family: var(--font-body); font-weight:200; font-size: 13px;
  letter-spacing:.05em; text-transform:uppercase;
  margin:0 0 var(--sp-16);
}
.btn-cta{
  display:inline-flex; align-items:center; gap:var(--sp-8);
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-cta);
  letter-spacing:.05em; text-transform:uppercase; text-decoration:none;
  background: var(--orange); color: var(--white);
  border: 1px solid var(--white);
  padding: var(--sp-12) var(--sp-16);
  transition: background .18s ease, color .18s ease;
}
.btn-cta:hover{ background: var(--white); color: var(--orange); }

/* ---------- wordmark header: hero overlay -> multiply -> collapsed nav bar
   Per Figma's 3 reference states (HOMEPAGE / HOMEPAGE - Scroll / HOMEPAGE -
   Nav Bar Collapse, nodes 175:1004 / 321:517 / 218:69) plus Eliza's verbal
   spec (2026-09-14, Figma has no animation of its own): at rest the header
   is just STUDIO/FRITZ + the logomark sitting transparently over the hero
   photo. As the user scrolls: (1) the wordmark multiplies -- rows 2 then 3
   reveal via a max-height wipe, never an opacity fade, always fully solid;
   (2) the SAME #heroNav (the one real 6-link nav, normally sitting under
   the two hero paragraphs) rises to dock just under the wordmark -- there
   is only ever one nav in the DOM, it transitions INTO the header rather
   than a second copy fading in beside it; (3) once it's docked, the header
   hard-cuts to its collapsed state: rows fold back to one line, a solid
   (non-video) crop of the Bluff Stools carousel photo fills the bar (the
   header "grabs" the image that happens to be sitting behind it at that
   scroll point), and #heroNav tucks up inside the bar's own bottom edge.
   Background and row state switch as a hard cut, never a gradual fade --
   see js/main.js. */
.wordmark-header{
  position: fixed; top:0; left:0; right:0; z-index:50;
  display:flex; align-items:flex-start; justify-content:space-between;
  padding: var(--sp-8) var(--edge);
  /* NOTE: this used to carry a 2px solid rgba(255,160,0,var(--hdr-bg-a)) border-bottom
     -- once the header hard-cut to solid, that rendered as a full-width solid
     orange stripe under the bar (Eliza: "horizontal orange line, where is
     that coming from?"). Not in Figma (218:69's own boundary line, node
     218:135, is a hairline, not a 2px orange rule) -- removed outright. */
}
/* Collapsed state reserves room below the single wordmark line for #heroNav
   to dock INSIDE the bar (see #heroNav.is-pinned.is-collapsed-nav below) --
   Figma 218:69: header bg is 197px tall at the 1440px reference width, of
   which the wordmark line's own box only accounts for ~139px (8px top pad +
   131px line), leaving ~58px for the two nav rows + bottom pad. Without
   this, the header's own solid background box ends right under the
   wordmark and the docked nav renders past its bottom edge, in the dead
   zone where the old orange line used to be -- i.e. NOT "part of the nav
   bar" per Eliza's note. */
.wordmark-header.is-collapsed{
  /* Figma 460:1999 puts the nav block at y=131..185 inside a bar ending at
     y=197 -- 33 below the wordmark, 12 above the bar's edge. js/main.js
     positions the nav from the TOP using that 33, so this padding is the
     other side of the same sum: 33 gap + ~54 nav + 24 air beneath it.
     (Figma's own 12 read too tight live, so the air is a deliberate
     departure -- the only one in this block.) */
  padding-bottom: calc(111 * var(--u));
  /* The multiply REVEAL is deliberately slow (.7875s -- Eliza's "more
     gradual, 50% less fast"), but the collapse is a different beat: it has
     to land in lockstep with the nav rising into the bar, and at .7875s
     that read as two separate events. Collapse gets its own faster
     duration. NOW REMOVED: the wordmark un-stacks on the way down as the
     mirror of how it stacked up, so both directions use the same .7875s
     wipe and the collapse is no longer a separate faster event. */
}
/* On the orange bar, the orange FRITZ and the orange logomark would both
   disappear into the background -- Figma's orange frame renders them
   light. FRITZ goes white; the logomark swaps to the real white asset
   (images/logos/logomark/logomark-white.svg -- the same file the footer
   already uses), not a CSS filter, so what renders is the drawn artwork
   rather than a recolored approximation of it. Both files sit in the
   markup and only their display toggles, so the swap is instant with no
   flash while a second file fetches. */
/* These used to SWAP at the moment the bar went solid, which was fine for a
   hard cut. With the orange now ramping in over scroll, a swap would leave
   FRITZ orange-on-orange for part of the ramp and the logomark popping at
   one end of it -- so both cross-fade on the same --hdr-bg-a the background
   uses. One driver, everything in step. (The plain rule is the fallback if
   color-mix isn't available; it just snaps, as before.) */
.wordmark-header.is-collapsed .wm-right span{ color: var(--white); }
.wordmark-header.is-collapsed .wm-right span{
  color: color-mix(in srgb, var(--white) calc(var(--hdr-bg-a, 0) * 100%), var(--orange));
}
.wm-mark .wm-mark-white{ position:absolute; inset:0; opacity: var(--hdr-bg-a, 0); }
.wm-mark .wm-mark-orange{ opacity: calc(1 - var(--hdr-bg-a, 0)); }
/* ...and the nav's orange hover would be invisible on orange too, so
   while docked it hovers to cream. */
#heroNav.is-collapsed-nav a:hover{ color: var(--cream); }
/* Collapsed-state bar: SOLID ORANGE, per Figma "HOMEPAGE - Scroll 4 -
   Nav Bar Collapse - Orange". This replaces the frozen bluff-table crop
   -- Eliza's call, to isolate one variable: a flat fill either reads as
   solid or it doesn't, with no ambiguity about whether we're seeing the
   captured image or the live video behind it. js/main.js flips --hdr-bg-a
   at the dock point, which is the one event in the whole sequence. */
.wordmark-header::before{
  content:''; position:absolute; inset:0; z-index:-1;
  background: var(--orange);
  opacity: var(--hdr-bg-a, 0);
  /* No transition, deliberately, in EITHER direction. The bar appears on
     the exact frame the nav lands in it, and disappears on the exact frame
     it leaves -- a fade would be a second event with its own clock, which
     is the kind of thing that reads as jiggle. (The asymmetric
     --hdr-reveal fade this used to carry is gone with it.) */
}
/* The wordmarks are links (home), so the hover states below are a real
   affordance rather than decoration on inert text. NOTE: no colour
   TRANSITION on the header wordmark, deliberately -- FRITZ already
   cross-fades there as a function of scroll (--hdr-bg-a), and layering a
   timed transition on top of a scroll-linked one is exactly the second
   clock that made this page feel jittery. The footer has no such ramp, so
   it gets the site's usual .18s. */
.wm-link, .footer-wm a{ text-decoration:none; color:inherit; display:block; }
/* Eliza (14th pass): "STUDIO should turn full orange on hover, for all
   pages. FRITZ should turn the pale orange, always staying within the 2
   colour orange monochromatic palette." One shared rule covers every
   page since .wm-link is the same markup everywhere. Exception: while
   the header is docked solid orange (.is-collapsed, scrolled state on
   the homepage), STUDIO reverts to white on hover -- full orange on an
   already-orange bar would just disappear. */
/* Specificity note: .wordmark-header.is-static .wm-left span (further
   down) is (0,3,1), same as a bare ".wm-link:hover .wm-left span" --
   which lost the tiebreak on source order on every static-header page
   (every page but the homepage), so hover silently did nothing there.
   Prefixing .wordmark-header here (matching the FRITZ hover rule below,
   which already had it and was never affected) bumps this to (0,4,1) so
   it wins outright regardless of order. */
.wordmark-header .wm-link:hover .wm-left span{ color: var(--orange); }
.wordmark-header.is-collapsed .wm-link:hover .wm-left span{ color: var(--white); }
.wordmark-header .wm-link:hover .wm-right span,
.wordmark-header.is-collapsed .wm-link:hover .wm-right span{ color: var(--orange-light); }
.footer-wm span{ transition: color .18s ease; }
.footer-wm a:hover .fw-cream{ color: var(--white); }
.footer-wm a:hover .fw-white{ color: var(--orange-light); }

.wm-col{ display:flex; flex-direction:column; line-height:.9; position:relative; }
.wm-col span{
  font-family: var(--font-display); font-weight:400;
  font-size: calc(100 * var(--u)); /* Figma's 100px wordmark -- now one multiple of the shared scale instead of its own clamp, so it can't drift against everything else */
  white-space:nowrap;
}
.wm-left span{ color: var(--cream); }
.wm-right{ align-items:flex-end; text-align:right; }
.wm-right span{
  color: var(--orange); letter-spacing:.175em;
  margin-right: -.175em; /* round 10: cancel the trailing letter-spacing gap
    after the last glyph so FRITZ's visible right edge -- not just its box
    edge -- lands flush with hero-links col 3 (About/Contact), per Eliza:
    "about and contact need to be flushed to the end of Fritz". */
} /* solid fill only — no stroke, per Figma (neither STUDIO nor FRITZ ever has one) */
/* multiply rows: revealed by wiping max-height open (in normal flow, so the
   header naturally grows/shrinks), never by fading opacity -- always fully
   solid the instant they're visible, per Eliza's "shouldn't be faded" note. */
.wm-row-2, .wm-row-3{ overflow:hidden; max-height:0; transition: max-height var(--wm-row-dur, .7875s) ease; } /* round 10: a further 50% slower on top of round 8's own 50% slowdown per "multiplication effect could be more gradual, 50% less fast" (.35s -> .525s -> .7875s) */
.wm-row-2.is-on, .wm-row-3.is-on{ max-height: calc(140 * var(--u)); }

/* small orange logomark badge -- round 10 had switched this to top-aligned
   ("looks too low in the center of page, should be top aligned to STUDIO
   FRITZ"), but Eliza has since reversed that decision back to vertically
   CENTERED on the STUDIO/FRITZ wordmark line, matching how the footer
   treats its own logomark (.footer-wm-mark, translate(-50%,-50%)).
   Porting the pre-round-10 fixed px straight from Figma's raw coordinates
   (y=40-123, centre 81.5) reproduced the exact same "too low" problem
   round 10 was fighting -- Figma's y-values don't match our rendering
   (documented above: Figma's text box is 131 tall for a 100px face, ours
   renders a 90px line box), so a literal port lands the mark on the
   glyph's lower half, not its centre. Measured empirically instead: 53.5u
   is the vertical centre of the actual rendered "STUDIO"/"FRITZ" glyphs
   (cap-top to baseline, no descenders in this wordmark) at 100u font-size,
   confirmed by pixel-sampling a screenshot. Fixed px top (not tied to
   header height) so it stays centred no matter how tall the header gets
   during multiply. */
.wm-mark{
  position:absolute; left:50%; top: calc(53.5 * var(--u)); transform: translate(-50%,-50%);
  width: calc(83 * var(--u)); z-index:1; display:block;
}
.wm-mark img{ width:100%; display:block; }

/* #heroNav docked-under-header state: js/main.js captures the nav's
   current on-screen `top` right before switching it to fixed (so there's
   no jump), then sets `top` to its real target -- the CSS transition above
   animates between the two. While still tripled/joining, target is the
   live header's bottom edge + a small gap (nav sits just under the bar);
   once collapsed, target is computed from the header's own bottom edge
   MINUS the nav's height (nav tucks up INSIDE the solid bar instead of
   floating below it -- see .wordmark-header.is-collapsed's padding-bottom
   above, which is what makes room for it). left/right match .hero-content's
   own box so the nav's column x-positions land identically whether pinned
   or not -- and 460:1999 keeps the collapsed bar's nav on the same two axes
   as the hero's (CUSTOM 678, SHOWROOM 1048, ABOUT ending 1400), so this
   moves with .hero-content. If it didn't, the links would slide sideways at
   the dock, which is the one thing this mechanism exists to avoid. */
#heroNav.is-pinned{
  position:fixed; left: calc(50% - 70.5 * var(--u)); right:var(--edge); margin-top:0; height:3.2em; z-index:55;
  transition: none; /* Eliza: "it comes down and shoots all the way down and
    then comes back up... can we just have it just show up because it's just
    adding thrash." Animating `top` here is what produced that -- the nav is
    now placed directly in the bar with no travel at all. */
}
/* Once tucked inside the collapsed bar the nav reads at Figma's much
   smaller scale (218:69: each link's box is ~28px tall at 1440px ref width,
   vs. the hero's own --fs-body) -- shrink font-size only in this state; the
   row-to-row em-based top offsets in .hero-links a:nth-child(4/5/6) scale
   down automatically with it. */
/* 2.1em was sized for the old shrunken nav type and UNDERSTATED the real
   two-row content (~3.4em), so positioning from this box left the second
   row hanging past the bar's bottom edge -- Eliza: "the bottom row of nav
   is just being cut off by the orange." Figma 460:2022-2027: rows at
   y=131 and y=157, each 28 tall, so the block runs 131->185 inside a
   197-tall bar. */
#heroNav.is-pinned.is-collapsed-nav{ height:3.4em; }
/* round 10: nav must NOT shrink once docked -- Eliza: "nav bar items are shrinking... they should just stay the same." (was font-size:11px here) */
@media (max-width: 1152px){ #heroNav.is-pinned{ position:static; left:auto; right:auto; top:auto !important; } }

/* ---------- hand-drawn stamp accent (loose/imperfect by design, intentional) ----------
   Static/pinned by default (stays put while the page scrolls beneath it) — see the
   Stamp behavior rule in the project plan. Only About and Mobile Hamburger deviate. */
.stamp{
  /* Eliza (15th pass): "never have the floating stamp push up over the
     nav bar, should hide under it on all pages -- rule." This was a
     literal z-index bug, not a positioning one: the stamp was stacked
     at 55, above .wordmark-header's 50, so on any scroll position where
     their boxes overlapped the stamp painted OVER the header instead of
     being hidden by it. Dropped below the header (matching the pattern
     already used for #mobileMenu's own z-index:45 "under the header's
     50" a bit further down) so the header always wins the stack
     regardless of scroll position -- true on every page, not just this
     one, since .page-stamp/.catalogue-stamp were already correctly
     under it (z-index 5 / 1) and only this one was ever wrong. */
  position: fixed; left: var(--edge); top:55%; z-index:45; /* was 60.7% -- shifted up so it clears the "Download Summer 2026 Catalogue" button at initial landing on short viewports (Eliza 2026-09-26) */
  width: calc(142 * var(--u)); /* scaled down 25% from 190px per Eliza's 2026-09-14 note */
  opacity:1;
  pointer-events:none;
}
.stamp img{ width:100%; height:auto; display:block; } /* height:auto -- the
  new cropped stamp SVGs (Google Drive Assets/Stamps) aren't the same ratio
  to each other, so no shared aspect-ratio override; each sizes off its own
  intrinsic viewBox. */

/* ---------- hero ---------- */
/* Eliza: "vertical bar is still cut off on homepage" -- the scroll-cue
   (.scroll-cue, the hairline under the hero nav) sits in normal flow
   right after the nav, so its bottom edge is wherever the hero's own
   content stack happens to land, not a fixed fraction of hero height.
   On a short viewport (13" MacBook-class, ~768-800px tall) the content
   stack runs past the vh-capped hero box before the cue's pulse animation
   even finishes, and overflow:hidden here was clipping it -- confirmed by
   measuring .scroll-cue's bounding rect against .hero's at several real
   viewport heights (768/720/800px all overshot by 9-12px; 900px+ did
   not). Nothing else in .hero needs clipping: the video/poster and the
   ::after gradient are already inset:0 + 100% width/height, so they can't
   overflow their own box regardless. */
.hero{ position:relative; min-height:100vh; background: var(--ink); }
.hero video, .hero .poster{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
}
.hero::after{
  content:""; position:absolute; inset:0;
  background: linear-gradient(0deg, rgba(20,10,25,.75) 0%, rgba(20,10,25,.05) 45%, transparent 65%);
}
.hero-content{
  /* --para-gap lives here (not on .hero-intro) so its sibling .hero-links
     can read the same value for its column-2 anchor -- custom properties
     only cascade to descendants, and hero-intro/hero-links are siblings. */
  /* 2026-09-20 realignment. Figma moved the whole right-hand block onto the
     logomark's left edge: 411:1269 sits at x=679, and 316:267 (the intro
     paragraph), 316:269 CUSTOM and 316:270 CATALOGUE are all at 679 now too.
     679/1440 = 47.1528%. Was 43.4% (625), which lined up with nothing.

     The gap closed with it: columns are 679..1029 and 1048..1402, so 19
     between them rather than 73. 19/721 = 2.635% of the block's width, and
     at 1fr 1fr that puts them at 679..1030 and 1049..1400 -- Figma to within
     2px. */
  --para-gap: 6.13%;   /* was 2.635% (19u): the two paragraphs read as one block. Left column + CUSTOM/CATALOGUE moved 29u left (see left: below) while column 2 stays put at x=1048 on the FRITZ right edge -> 46u gutter */
  position:absolute; z-index:2;
  /* The logomark's own left edge, not a percentage that merely equals it at
     1440. .wm-mark is centred and 83u wide, so its left edge is always
     50% - 41.5u. 47.1528% matches that at exactly 1440 and nowhere else:
     --u is clamped, so past ~2000px the mark stops moving outward from the
     centre while a raw percentage keeps tracking the viewport, and CUSTOM
     drifts left of it. Same failure the footer's column 3 had, same fix. */
  left: calc(50% - 70.5 * var(--u)); right: var(--edge);
  /* Eliza 2026-10-03: the vertical line kept getting squished or cut off
     because the stack hung from the TOP (60.1%) and grew down with copy
     wrapping. Anchored from the bottom instead: Figma has the 88u line 22u
     above the hero's bottom and CATALOGUE ending 49u above the line (706) -- so every gap is fixed whatever the window height. */
  bottom: calc(22 * var(--u));   /* the cue is the last child, so this is the LINE's distance from the edge */
}
/* z-index:2 above makes .hero-content its own stacking context, which
   traps #heroNav's z-index:55 inside it -- so once docked, the nav could
   never paint above .wordmark-header (z-index:50). The header covered the
   docked nav and ate its pointer events, which is why hover stopped
   turning the links orange, and why the bar's solid background would have
   hidden the nav outright. js/main.js adds this class only while the nav
   is docked, so the un-docked hero keeps its original stacking. */
.hero-content.is-nav-pinned{ z-index: 60; }
.hero-intro{
  display:grid; gap: var(--para-gap);
  grid-template-columns: 1fr 1fr;
}
.hero-intro p{
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase; text-align:justify;
  color: var(--white); margin:0;
}
/* 6 separate, equal-hierarchy page links (2 rows x 3 cols) — every link is
   its own page (Custom/Showroom/About/Catalogue/Trade/Contact), same size,
   same solid white color. Individually positioned to match Figma's real
   column layout (col 1 left-aligned flush left; col 2 left-aligned ~32% in;
   col 3 right-aligned flush with the content block's right edge) rather
   than an evenly-distributed flex row. */
.hero-links{
  /* Figma 175:1004: nav rows at y=652 and y=678 (26px pitch), block running
     652->706 = 54 tall, starting 34 below the paragraph block's bottom edge
     at y=618. Was 3.2em/24px, which is why the rows sat a touch tight. */
  position:relative; height:3.4em; margin-top: calc(34 * var(--u));
}
.hero-links a{
  position:absolute;
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  letter-spacing:.05em; text-transform:uppercase; text-decoration:none; color: var(--white);
}
.hero-links a:nth-child(1){ top:0; left:0; text-align:left; }
/* Column 2 is LEFT-aligned on the FOUNDED paragraph's own left edge now
   (316:271 SHOWROOM and 316:274 TRADE both moved to 1048, where they used to
   sit at 876 and 923 sharing a right edge of 975). Same expression as
   before, since the paragraph grid's second column starts at exactly
   (width + gap) / 2 -- only the side it anchors from changed. */
.hero-links a:nth-child(2){ top:0; left: calc(50% + var(--para-gap) / 2); text-align:left; }
.hero-links a:nth-child(3){ top:0; right:0; text-align:right; }
.hero-links a:nth-child(4){ top:1.625em; left:0; text-align:left; }
.hero-links a:nth-child(5){ top:1.625em; left: calc(50% + var(--para-gap) / 2); text-align:left; }
.hero-links a:nth-child(6){ top:1.625em; right:0; text-align:right; }
.hero-links a:hover{ color: var(--orange); }

/* download button: thin outline over the hero photo, left edge, near the
   bottom — Figma's version here is bordered/transparent, not solid-filled */
.btn-outline{
  display:inline-flex; align-items:center; gap: calc(30 * var(--u)); /* Figma: arrow starts at
    x=345, label ends at 315 -- label left, arrow right, 30 between them */
  font-family: var(--font-body); font-weight:200; font-size: calc(14 * var(--u));
  letter-spacing:.05em; text-transform:uppercase; text-decoration:none;
  background:transparent; color: var(--white);
  border: 1px solid var(--white);
  padding: calc(4 * var(--u)) calc(10 * var(--u)); /* Figma 175:1004 Group 16: 324x33 box, label inset 8/4 */
  transition: background .18s ease, color .18s ease;
}
.btn-outline:hover{ background: var(--white); color: var(--ink); }
.btn-outline img{ width: calc(9 * var(--u)); height: calc(9 * var(--u)); } /* Figma Group 17: 9x9 */
.btn-outline:hover img{ filter: invert(1); } /* white arrow -> dark on hover's white fill */
.hero-catalogue-link{
  position:absolute; z-index:2; left: var(--edge); bottom: var(--sp-40);
}

/* scroll cue: thin vertical line, pulses once on load to invite scrolling
   (Figma node 321:508: x=720, y=755, height=88, in the 1440x865 hero.)

   2026-09-23: was position:absolute against .hero itself (left:50%,
   top:87.3%), i.e. two values with no relationship to the nav block it
   sits under -- Eliza: "the vertical line looks cramped." At the
   reference width the numbers land right (720/1440 is exactly 50%, and
   755/865 is 87.3%), but that's the same coincidence the footer and the
   old hero-content alignment already hit: 720 is close to hero-content's
   own left edge (679) only because both happen to be near the page's
   centre at 1440. hero-content's OWN height is content-flow (however many
   lines the two paragraphs wrap to), while the cue's 87.3% is a fixed
   fraction of the hero regardless of that flow -- two independently
   driven values, the exact pattern this file already treats as a bug
   elsewhere. Widen the window and the gap between them isn't fixed: it
   shrinks, and at wide-enough viewports the two rows overlap outright.

   Fixed by moving the cue INTO .hero-content as the third flow child,
   right after the nav -- so its position is a function of wherever the
   nav actually ends, not a guess at where it should be. margin-top is the
   Figma gap (755 - 706, where 706 is CATALOGUE's own bottom edge) and
   margin-left is the cue's offset from the column's own left edge (720 -
   679), both in --u so they track the same scale as everything else. */
.scroll-cue{
  /* Eliza: "too low and not pulsing... people don't know to scroll" --
     margin-top brought way in from the nav (49u -> 18u) so it reads higher
     on screen; base opacity raised (.55 -> .7) and a glow added on the
     pulse beat so the animation is actually visible against the hero
     video, not just a 1px hairline flickering slightly brighter. */
  /* Eliza 2026-10-03: "sitting too high" vs Figma 321:508 -- back to Figma's
     49u gap (755 - CATALOGUE's bottom at 706); the 18u above was the
     earlier "too low" nudge, which overshot. */
  /* Clamped rather than a flat 49u: on a tall window the line follows
     Figma (49u under the nav, ending ~22u above the hero's bottom); the
     middle term is that bottom-edge limit (measured: the stack runs
     ~334u + 60.1% of the hero tall), so a short window falls back to 18u
     instead of pushing the line past the fold (the old "cut off" bug). */
  margin: calc(49 * var(--u)) 0 0 calc(70 * var(--u));   /* stays centred on the page: block left moved 29u, so +29u here */
  width:1px; height: calc(88 * var(--u)); background: rgba(255,255,255,.7); /* width stays a real 1px -- hairlines don't scale */
  pointer-events:none; animation: scrollCuePulse 2.5s ease-out .6s infinite both;
  transform-origin: top center;
  transition: opacity .3s ease;
}
/* Eliza 2026-09-26: "on scroll, can we have the vertical line disappear
   sooner so it doesn't start to overlap with things, and in reverse
   scroll up, also come in later." .hero-content sits at a fixed screen
   position until the nav docks (see js/main.js's header() render loop),
   so the cue itself never physically moves on scroll -- it's the row2/
   row3 nav rows opening beneath it that start to collide with it. Fixed
   with scroll-position hysteresis in js/main.js (search "scroll-cue
   hysteresis"): two different thresholds, not one, so it hides early on
   the way down and only comes back once you're nearly back at the top on
   the way up -- a single shared threshold would make it flicker back on
   the moment you paused or nudged upward mid-scroll. */
.scroll-cue.is-hidden{ opacity:0 !important; }
@keyframes scrollCuePulse{
  /* Eliza: pulse should shrink to about half its size, not grow, and
     happen 2x as often -- so scaleY goes 1 -> .5 (was 1 -> 1.25) and the
     cycle is 2.5s (was 5s). A glow (box-shadow) rides the same beat so the
     pulse itself is unmistakable, not just a subtle brightness shift. */
  0%    { opacity:.7;  transform: scaleY(1);  box-shadow: none; }
  14.4% { opacity:1;   transform: scaleY(.5); box-shadow: 0 0 calc(8 * var(--u)) rgba(255,255,255,.9); }
  36%   { opacity:.7;  transform: scaleY(1);  box-shadow: none; }
  100%  { opacity:.7;  transform: scaleY(1);  box-shadow: none; }
}
@media (max-width: 1152px){
  .scroll-cue{ display:none; }
}
/* .hero-divider removed 2026-09-17. It was a 1px rgba(255,255,255,.28)
   rule on the hero/carousel seam; against the orange body that renders as
   a pale strip, which is what Eliza saw as "the thin orange line or gap
   above the catalogue carousel". Figma does carry a hairline there
   (321:509 at y=865, and 175:1012 at y=901), so this is a deliberate
   departure from the file, not an oversight -- at 1px over that seam it
   reads as a rendering artifact rather than a rule. */

@media (max-width: 1152px){
  /* below the width the 1440px reference composition was built at, drop
     back to a simple full-width stacked layout */
  .hero-content{ position:relative; left:auto; right:auto; top:auto; padding: calc(var(--sp-80) + 40px) var(--edge) 0; }
  .hero-intro{ grid-template-columns: 1fr; max-width:600px; }
  .hero-links{ position:static; height:auto; display:flex; flex-wrap:wrap; gap: var(--sp-16) var(--sp-24); margin-top: var(--sp-16); }
  .hero-links a{ position:static !important; text-align:left !important; }
  .hero-catalogue-link{ position:relative; left:auto; bottom:auto; margin: var(--sp-16) var(--edge) var(--sp-24); }
}

/* ---------- mobile-only elements: off by default ----------
   These have no desktop equivalent in Figma, so they are hidden here and
   switched on inside the mobile block rather than the other way round --
   desktop stays exactly as it was. */
.nav-toggle{ display:none; }
.mobile-menu{ display:none; }
.band-about{ display:none; }

/* ---------- utility ---------- */
.sr-only{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0;
}

/* ---------- carousels ---------- */
.carousel{ position:relative; overflow:hidden; background: var(--orange); }
.carousel-track{
  display:flex; align-items:flex-start; overflow-x:auto; scrollbar-width:none;
  cursor:grab; -webkit-overflow-scrolling:touch;
  /* 1px wider than its box, so the sub-pixel translateX the drift applies
     (see js/main.js) can never uncover a sliver at the right edge. Clipped
     by .carousel's own overflow:hidden, so it costs nothing. */
  width: calc(100% + 1px);
}
.carousel-track::-webkit-scrollbar{ display:none; }
.carousel-track.dragging{ cursor:grabbing; scroll-snap-type:none; }
.carousel .tile{ flex:0 0 auto; margin:0 0 0 -1px; } /* GLOBAL: tiles overlap by 1px so a fractional layout width (narrow windows, sub-pixel drift) can never open a hairline of the orange carousel background between photos. Applied to every tile, first included, so the loop period stays exact. */
.tile-link{ display:block; color:inherit; text-decoration:none; cursor:pointer; }
/* The global :focus-visible ring (2px ink, offset 3) painted as stray black
   vertical lines at tile edges after a click/drag. Carousel tiles get an
   inset ring instead, and none for pointer focus. */
.carousel .tile-link:focus{ outline:none; }
.carousel .tile-link:focus-visible{ outline: 2px solid var(--white); outline-offset: -6px; }
/* Eliza (2026-10-02): "make all carousels clickable." Each tile's media +
   caption are wrapped in this anchor rather than the <figure> itself, so
   the flex sizing above (which keys off .tile) is untouched. */
.tile-media{
  position:relative; overflow:hidden; display:block; width:max-content;
  /* Figma's 389 tile on a 1440 frame is 27.01vw, so 27vw reproduces the
     design exactly at the reference width AND keeps scaling past it --
     Eliza on her iMac: "there's excessive room left on the right... can we
     scale the images up when it's iMac?" A hard 389px cap was what left
     that room, and with it, too little horizontal travel for the
     scroll-hijack to have anything to do. */
  height: 27vw; min-height:220px; max-height:560px;
}
/* Eliza: "it's def still showing cropped vertically -- you should be
   shrinking it to height of the carousel rather than cropping it
   vertically." Was a hand-tuned aspect-ratio box per tile (inline style on
   each .tile-media) + object-fit:cover, which crops whenever a photo's
   real aspect ratio doesn't exactly match the number that was tuned for
   it. Now the image is in normal flow at the tile's fixed height with
   width:auto -- it scales to that height at its own true aspect ratio, no
   cropping, and .tile-media's width:max-content above follows it so the
   tile itself is exactly as wide as the scaled photo. The per-tile inline
   aspect-ratio hints stay in the HTML as width/height-style metadata but
   no longer force a crop box. */
.tile-media img, .tile-media video{
  position:static; display:block; height:100%; width:auto; max-width:none;
  pointer-events:none;
}
.carousel .tile figcaption{
  background: transparent; color:#fff;
  padding: 0 var(--sp-16) var(--sp-8) 0; /* Figma: captions are flush with their
    own tile's left edge (175:1030 x=866 = image x=866, and the same for
    175:1035 / 175:1033) -- the 16px inset was ours, not the design's */
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  letter-spacing:.05em; text-transform:uppercase; white-space:nowrap;
  pointer-events:none;
  width:0; min-width:100%; overflow:hidden; text-overflow:ellipsis;
}

/* pre-footer carousel: scroll-hijacked (vertical scroll -> horizontal, 1:1) */
.scroll-hijack{ position:relative; background: var(--orange); }
/* Height is set by js/main.js: pane height + a runway sized to
   (viewport - collapsed bar - pane), so the pane pins flush under the
   bar and holds while the footer rises into the space below it. The
   background matters for the frame or two after a resize, before the
   runway is re-measured -- that strip must never flash cream. */
.scroll-hijack-sticky{
  position:sticky; top: calc(var(--hdr-h, 0px) - 1px); height:auto; overflow:hidden; background: var(--orange); /* -1px: tucks under the bar so no sub-pixel line shows */
} /* round 10 v3: flex-end (v2) just relocated the dead space from below the
     carousel to above it -- still one large, clearly-visible blank block,
     now sitting right under the hero, per Eliza's "big padding gaps are
     still on homepage" follow-up. (Superseded 2026-09-18: the pane is no
     longer viewport-tall at all -- it hugs the 389 band, and the runway
     that used to come from its height is now set explicitly on the
     wrapper by js/main.js.) tile-media's height is shared with every other carousel
     on the site so it shouldn't change just for this section -- so
     instead of anchoring the leftover space to one edge, split it evenly
     top/bottom by centering. Same total empty space, but it reads as
     breathing room around a centered carousel instead of a void before
     or after it. Explicit background here too, so that leftover space is
     never anything but orange. */
.scroll-hijack .carousel-track{ overflow-x:hidden; } /* position driven by JS, not native scroll */
/* Blowing the tiles up to fill a viewport-tall pane was the wrong lever --
   Figma has this carousel at the same 389 band as every other one
   (460:2049-2052), sitting flush under the cove image (which ends at
   y=1656, exactly where the band starts) and running straight into the
   footer. So the pane hugs the band instead of being a viewport-tall box
   with slack that has to be parked somewhere, and it sticks BELOW the
   collapsed bar (--hdr-h, published by js/main.js) so the bar never
   covers it. */

/* ---------- catalogue CTA band ---------- */
.catalogue-band{
  display:flex; align-items:center; justify-content:flex-end;
  background: transparent; color: var(--white); text-decoration:none;
  padding: 28px 21px 0; /* Figma 175:1023/175:1024: the CATALOGUE line sits 28
    below the caption row (which ends y=1289) and its box ends at y=1361 --
    exactly where the cove image starts, so zero bottom padding, confirmed.
    Arrow sits 21 from the frame's right edge, not the 40 page margin. */
  font-family: var(--font-body); font-weight:200; font-size: 25px;
  letter-spacing:.05em; text-transform:uppercase; gap: var(--sp-8);
}
.catalogue-band img{ width:19px; height:20px; } /* Figma 175:1024 */
body.page-product .catalogue-band{ display:none; }   /* mobile-only on product pages (Figma 342:1043) */
.catalogue-band:hover{ color: var(--orange-light); }
/* Eliza (2026-10-02): "any buttons with arrows should lighten both the
   word + button, not just the word -- make this a global rule." This
   one used to lighten only the text and leave the arrow icon white --
   CSS filter re-tinting an inline SVG isn't reliable, but the swap-the-
   whole-asset technique every other arrow button on the site already
   uses (content: url(...)) works here just as well, so it gets its own
   pre-tinted arrow-orange-light.svg instead of a filter. */
.catalogue-band:hover img{ content: url("../images/logos/arrows/arrow-orange-light.svg"); }

/* ---------- feature product block ---------- */
.feature-product{ position:relative; background: var(--orange); }
.feature-product img{ width:100%; display:block; }
.feature-arrow{
  position:absolute; left:94.9%; top:92.8%; width:3.6%; aspect-ratio:1;
  display:flex; align-items:center; justify-content:center;
  text-decoration:none;
}
.feature-arrow img{ width:60%; height:60%; }
/* Eliza (2026-10-02): same global "arrow buttons lighten on hover" rule --
   this one is icon-only (no text to lighten in the first place), but it
   sits on the same orange background as .catalogue-band, so it gets the
   identical light-orange swap for consistency rather than being left out. */
.feature-arrow:hover img{ content: url("../images/logos/arrows/arrow-orange-light.svg"); }

/* ---------- footer ----------
   Per Figma (get_design_context, node 175:1004, footer region): the
   STUDIO/FRITZ wordmark is its own full-width row (STUDIO left, FRITZ
   right — a reprise of the header), stacked ABOVE the nav columns, not
   beside them. The 4 columns all start at the same y and sit at fixed x
   offsets across the content width: 0% (Custom/Catalogue/Showroom),
   ~21% (Trade/About/Contact), ~47% (FAQ/Warranty/Press/IG), ~74%
   (newsletter) — reproduced here as absolutely positioned columns rather
   than a generic wrapping flex row, so the alignment matches exactly. */
.site-footer{ background: var(--orange); color: var(--white); padding: 40px var(--edge) var(--sp-32); } /* Figma (175:1004 / 460:1999) actually has the footer wordmark flush with the caption row -- 2745 to 2745, zero gap -- and that was confirmed on 2026-09-14. Overridden on 2026-09-16 after Eliza flagged it as too narrow three separate times looking at the live page: 40px top. A deliberate departure from Figma, not a miss. */
.footer-top{ display:flex; flex-direction:column; gap: var(--sp-64); padding-bottom: var(--section-gap); }
.footer-wm{ position:relative; display:flex; justify-content:space-between; align-items:flex-start; }
.footer-wm-mark{
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  width: calc(83 * var(--u)); display:block; /* Figma 404:488 */
}
.footer-wm-mark img{ width:100%; display:block; }
.footer-wm span{
  font-family: var(--font-display); font-weight:400;
  /* Figma 404:419/420: 358x131 -- identical to the header wordmark
     (316:295), so the same 100px face, not the 80px this used to cap at.
     On the shared scale now, so it can't drift against the rest. */
  font-size: calc(100 * var(--u)); display:block; line-height:1;
}
.footer-wm .fw-cream{ color: var(--cream); }
.footer-wm .fw-white{ color: var(--white); letter-spacing:.175em; } /* matches the header FRITZ's own tracking exception (.wm-right span) -- round 10: "FRITZ spacing in footer looks too narrow" */

.footer-links{ position:relative; min-height:9em; }
.footer-col{ position:absolute; top:0; display:flex; flex-direction:column; gap: var(--sp-12); }
.footer-col:nth-child(1){ left:0; }
/* Figma right-aligns this column: TRADE (404:407) x=350 w=48, ABOUT
   (404:405) x=346 w=52, CONTACT (404:406) x=325 w=73 -- three different
   left edges, all ending on x=398. Ours shared one left edge instead,
   which is the "left justified" Eliza flagged. 398 sits 1002 from the
   1400 container edge, i.e. 73.68% of the 1360 row. */
.footer-col:nth-child(2){ left:auto; right:73.68%; align-items:flex-end; text-align:right; }
/* Column 3 aligns with the LEFT EDGE OF THE LOGOMARK (Figma: both at
   x=682 -- 404:409 and the mark 404:488). Expressed against the mark's own
   geometry rather than a fixed 47%: the mark is centred and 83u wide, so
   its left edge is always 50% minus half of that. The old fixed percentage
   tracked the container's width while the mark tracked the centre, so the
   two drifted apart as the window widened. */
.footer-col.footer-col-wide{ left: calc(50% - 41.5 * var(--u)); max-width: calc(280 * var(--u)); }
.footer-col a{
  text-decoration:none; font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  letter-spacing:.05em; text-transform:uppercase; color: var(--white); white-space:nowrap;
}
/* was font-size:14px + white-space:normal, which wrapped "Frequently Asked
   Questions" and "Press / eliza@studiofritz.co" to 2 lines -- Figma shows
   each of FAQ/Warranty/Press/IG on its own single line (175:1004: e.g.
   node 404:409 "FREQUENTLY ASKED QUESTIONS" is one 221px-wide line, not
   two) -- dropped the override so this column inherits the same
   white-space:nowrap as the other footer columns. */
.footer-col a:hover{ color: var(--orange-light); } /* was text-decoration:underline -- footer links are "buttons" per Eliza's hover rule too: light orange, never underlined */

/* copyright/location -- Figma node 442:1989 (added by Eliza directly to the
   Homepage frame, 175:1004): "this is footer SOT" going forward, so this
   pulls the exact text/styling from Figma rather than placeholder copy. */
.footer-copyright{
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  letter-spacing:.05em; text-transform:uppercase; color: var(--white); line-height:1.5; margin:0;
  /* Eliza moved this to a fixed two-line break (after the year) in the
     bottom-left of the footer, left-aligned on every breakpoint -- align-self
     here because .footer-bottom centres its children for the back-to-top's
     sake, which would otherwise shrink-wrap this and centre it too. */
  align-self:stretch; text-align:left;
}
.footer-bottom{ display:flex; flex-direction:column; align-items:center; }

/* Back to top. The whole thing is one anchor, so the rule and the label are
   both clickable -- and the hit area spans the gap between them, which is
   the part that would otherwise feel broken. The rule reprises the hero's
   scroll cue (88u, a real 1px -- hairlines don't scale) at the other end of
   the page: one invites you down, one brings you back. */
.back-to-top{
  display:flex; flex-direction:column; align-items:center;
  gap: calc(24 * var(--u)); margin-top: calc(24 * var(--u));
  text-decoration:none; color: var(--white);
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  letter-spacing:.05em; text-transform:uppercase;
  transition: color .18s ease;
}
.btt-line{ display:block; width:1px; height: calc(88 * var(--u)); background: var(--white); transition: background .18s ease; }
.back-to-top:hover{ color: var(--orange-light); }
.back-to-top:hover .btt-line{ background: var(--orange-light); } /* Figma's own text content (442:1989) is already ALL CAPS -- mixed-case
     read as a mismatched typeface next to the rest of the all-caps footer
     ("copyright in wrong typeface"); text-transform matches how every
     other footer/nav label on the site is written (source in normal case,
     CSS uppercases it) rather than typing the source in caps. */

.newsletter{
  position:absolute; top:0; left:74%; width:26%; min-width:14em;
  display:flex; flex-direction:column; gap: var(--sp-4);
} /* Figma (404:400-410): label-to-input gap is tight (~4px) but
     input-to-download-button gap is much bigger (~31px) -- a single
     uniform gap value doesn't capture that, so the base gap matches the
     tight spacing and .accent below adds the extra gap before the button
     ("download summer catalogue layout is wrong") */
.newsletter label{ font-family: var(--font-body); font-weight:200; font-size: calc(14 * var(--u)); letter-spacing:.05em; text-transform:uppercase; }
.newsletter form{ position:relative; }
.newsletter input{
  width:100%; border:0; background: var(--cream);
  height: calc(35 * var(--u)); /* Figma 404:400 "Rectangle 8": 351x35 */
  padding: 0 calc(40 * var(--u)) 0 calc(13 * var(--u)); /* label inset x=1062 in a box at x=1049 */
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-input);
  color: var(--ink); letter-spacing:.05em; text-transform:uppercase; /* Eliza: "force all caps on enter your email fields, all references" -- placeholder was already hardcoded caps, but the typed value (and the browser's own autofill suggestion) rendered in whatever case the person/their address book used. Pure display transform, same submitted value. */
  outline:none; /* Eliza: "get rid of black outline when i click it" -- browser default focus ring read as a stray black box on the cream field; focus is still visible via the border below. */
  border: 1px solid transparent;
}
.newsletter input:focus, .newsletter input:focus-visible{ border-color: var(--white); outline: 1px solid var(--white); outline-offset: 0; }   /* white focus stroke, not black (footer + hamburger, all widths) */
.newsletter input::placeholder{ color: var(--ink); opacity:.7; }
.newsletter button{
  position:absolute; right: var(--sp-8); top:50%; transform:translateY(-50%);
  border:0; background:none; cursor:pointer; padding: var(--sp-4);
  display:flex; align-items:center; justify-content:center;
}
.newsletter button img{ width: calc(14 * var(--u)); height: calc(14 * var(--u)); transition: opacity .15s ease; }
.newsletter button:hover img{ opacity:.6; }
/* Was a solid white box per Figma (404:401, "Rectangle 9") under an
   orange label -- Eliza asked for the footer/mobile-menu download buttons
   to match the homepage hero's own above-the-fold button (.btn-outline):
   white outline, white text, transparent background, since they're above
   the fold there same as the hero's. Sized to match the email input above
   it, same as before. This is still the base/mobile-menu appearance;
   see the .site-footer override below for the desktop footer, which
   Eliza later asked to have a solid orange fill instead of transparent. */
.newsletter .accent{
  display:flex; align-items:center; justify-content:space-between; /* Figma
    404:410 label at x=1062 in a box starting x=1049, Group 30 arrow at
    x=1379 against a right edge of 1400: label left, arrow right -- it was
    centred */
  text-decoration:none; background:transparent; color: var(--white);
  border: 1px solid var(--white);
  font-family: var(--font-body); font-weight:200; font-size: calc(14 * var(--u));
  letter-spacing:.05em; text-transform:uppercase;
  /* Figma 404:401 "Rectangle 9" is 351x33 and the input above it is 351x35
     -- near-identical heights. Ours came out ~25 tall against a ~43 input,
     which is the "too thin" Eliza flagged. Height is set explicitly rather
     than derived from padding, so the proportion holds whatever the line
     box does. Border is 1px on top of that height, same box-sizing as
     .btn-outline. */
  box-sizing: border-box;
  min-height: calc(33 * var(--u));
  padding: 0 calc(11 * var(--u)) 0 calc(13 * var(--u)); text-align:left;
  margin-top: calc(31 * var(--u)); /* Figma: input bottom 2965 -> button top 2996 */
  transition: background .18s ease, color .18s ease, border-color .18s ease;
}
/* Orange-light tint on hover, not .btn-outline's white-invert -- keeps the
   white arrow icon legible against the fill (a white icon on a white-invert
   hover would disappear), and matches the site's general hover convention
   of turning --orange-light rather than inverting. */
.newsletter .accent:hover{ background: var(--white); color: var(--orange); border-color: var(--white); }
.newsletter .accent:hover img{ content: url("../images/logos/arrows/arrow-orange.svg"); }
.newsletter .accent img{ width: calc(14 * var(--u)); height: calc(14 * var(--u)); } /* same 14x14 artboard as the input arrow; Figma draws them at equal size */

/* REVERSED (Eliza, 14th pass, 2026-10-02): "catalogue button should be
   inverted, white lines text arrow" -- back to the same outline style as
   the base .newsletter .accent rule above (white border, transparent
   fill, white text), undoing the 2026-09-28 solid-orange-fill decision
   this replaced. Left as an explicit (now-empty-effect) .site-footer
   override rather than deleted outright, so this reversal has its own
   visible history if it ever needs to flip back.
   Also (Eliza): "aligning text with the button above it and ensuring
   they're same size -- make this a rule for buttons that are stacked."
   width:100% here is that rule made explicit: a button stacked directly
   under another full-width control (the email input, same .newsletter
   column) always matches that control's width, not just its own content
   width, so their left/right edges and text inset line up exactly. */
.site-footer .newsletter .accent{
  background:transparent; border-color: var(--white); color: var(--white);
  width:100%; box-sizing:border-box;
}
.site-footer .newsletter .accent:hover{
  background: var(--white); border-color: var(--white); color: var(--orange);
}
.site-footer .newsletter .accent:hover img{ content: url("../images/logos/arrows/arrow-orange.svg"); }
/* Eliza (15th pass): "ENTER YOUR EMAIL is too big in footer." Scoped to
   the footer specifically (not the mobile-menu newsletter, which is a
   different, smaller context and wasn't flagged) rather than touching
   the shared --fs-input every other form field on the site uses. */
.site-footer .newsletter input{ font-size: calc(14 * var(--u)); }
/* Same white-on-orange swap .inquire-modal already does for this
   component on a dark background -- the default --ink would be nearly
   unreadable on the footer's orange fill. */
.site-footer .sf-field-error{ color: var(--white); }

@media (max-width: 1152px){
  .footer-links{ position:static; min-height:auto; display:flex; flex-wrap:wrap; gap: var(--sp-32); }
  .footer-col{ position:static; }
  .newsletter{ position:static; width:auto; }
}



/* ============================================================
   ABOUT PAGE — Figma 175:1147 (desktop, 1440) / 338:3 (mobile, 402)

   White page, unlike everything else on the site. Figma 175:1274 is
   literally bg-white, not cream — checked rather than inferred, because
   cream and white are hard to tell apart in a render and STUDIO is set in
   cream here, which only reads at all against white.

   Header and footer are the homepage's, verbatim. Where the About frames
   disagree with them the homepage wins: those frames are older in three
   visible ways (hamburger at 52 rather than 56, "JOIN NEWSLETTER" rather
   than "SIGN UP FOR NEWSLETTER", and a mobile footer whose nav rows
   overlap each other). One canonical header and footer beats a faithful
   copy of a stale frame.

   Layout is positioned rather than flowed, like the footer: Figma places
   every element on an absolute coordinate and the composition overlaps
   (the stamp sits across the hands photo's column). The section heights
   come from Figma's own landmarks.

   NOT trusted: Figma's text-box heights. 175:1201 claims 611 tall for
   copy that sets in about 13 lines, and 175:1202 claims 812. Same trap as
   the homepage hero. Text flows to its natural height here and the
   sections carry enough room for it.
   ============================================================ */
body.page-about, body.page-light{ background: var(--white); color: var(--ink); }

/* Static bar: no hero to dock out of, and no animations here yet. Figma
   502:5 / 502:69 / 502:6 moved this back to the homepage's own collapsed
   layout -- STUDIO at 36, the orange logomark centred at 679, FRITZ ending
   at 1402 -- and added the logomark, which it previously didn't have. So
   this is now structurally the homepage bar, just never animated: same
   markup, same axes, one static variant on top. */
.wordmark-header.is-static{
  /* Eliza 2026-10-02: "nav bar is not floating on all non-homepage pages!
     should behave like homepage nav bar after it appears." Was
     position:absolute (scrolls away with the page) by deliberate earlier
     choice; now fixed, same as the homepage's own header -- desktop was
     the only breakpoint left scrolling away. <main> still starts at page 0
     (unchanged) since both absolute and fixed are equally out of flow;
     only the scroll behavior changes.
     Eliza 2026-10-02 (follow-up): the --hdr-bg-a orange ramp this first
     reused from the homepage read as "weird" here -- is-static's own link
     colour is always dark ink (it has no collapsed-state swap to white,
     unlike the homepage bar), so the ramp just produced dark text on a
     solid orange bar partway through. These pages have no video/hero to
     cross-fade out of in the first place, so there's nothing for a ramp to
     justify: flat solid white, no fade, no colour-swap -- "does not
     require complexity." */
  /* Eliza 2026-10-02 (2nd follow-up): "custom, catalogue, trade etc. are
     all over transparent background - they need to be over white. the nav
     bar needs to be same height as the solid orange nav bar on homepage."
     The 24u bottom pad only covered the wordmark row -- the nav links
     (.hero-links.is-static-nav, top:131u height:54u -> ends at 185u) sat
     well past the background box's own bottom edge (8 top + ~90 content +
     24 bottom = 122u), rendering over bare page background for most of
     their height. Figma 218:69 (the same bar this is structurally copied
     from) is 197px tall at this reference width with that identical
     131..185 nav band inside it, i.e. 12u of air below the nav -- so the
     fix is the same total height as the homepage's own collapsed bar, not
     a one-off number: 8 top + ~90 content + 99 bottom = 197u. */
  position:fixed; top:0; left:0; right:0; z-index:50;
  padding: var(--sp-8) var(--edge) calc(99 * var(--u));
  background: var(--white);
}
/* Kill the shared .wordmark-header::before orange-ramp layer for static
   headers -- it's --hdr-bg-a driven and js/main.js's staticHeader() no
   longer sets that variable at all, but this makes the independence
   explicit rather than relying on the variable simply staying at 0. */
.wordmark-header.is-static::before{ display:none; }
.wordmark-header.is-static .wm-row-1{ font-size: calc(100 * var(--u)); }
/* 316:278-283: the same two axes as the homepage — 679 and 1048, column 3
   right-aligned. Expressed the same way so the pages can't drift apart. */
.wordmark-header.is-static .hero-links.is-static-nav{
  /* --para-gap is normally inherited from .hero-content, which this page has
     no equivalent of. Without it the column-2 anchor is invalid and columns
     1 and 2 collapse onto each other. */
  --para-gap: 6.13%;
  position:absolute; left: calc(50% - 70.5 * var(--u)); right: var(--edge);
  top: calc(131 * var(--u)); height: calc(54 * var(--u)); margin:0;
}
.wordmark-header.is-static .hero-links a{ color: var(--ink); }
.wordmark-header.is-static .hero-links a:hover{ color: var(--orange); }
.wordmark-header.is-static .hero-links a[aria-current="page"]{ color: var(--orange); }
/* STUDIO stays --cream on .is-static headers, same as the homepage --
   Eliza (2026-10-02, correction): the earlier ink swap here mistook a
   different bug (the nav bar's background not reaching full white/height)
   for a text-contrast problem. Cream is correct; reverted. */
.wordmark-header.is-static .wm-left span{ color: var(--cream); }
.wordmark-header.is-static .wm-right span{ color: var(--orange); }

/* Figma 316:357 runs x=304 from y=42 to 2433, with two short horizontals
   at 42 and 63 (316:358/359) bracketing its top. One element: the rule is
   the border, the bracket is drawn with ::before / ::after. */
/* 316:357 now runs x=305 from y=215 (was x=304 from y=42) -- it starts
   below the nav rather than beside it, since the bar gained a logomark. */
.about-rule, .page-rule{
  position:absolute; left: calc(305 * var(--u));
  top: var(--rule-top, calc(215 * var(--u)));
  /* 2u, not 1px. 316:357 carries a 2px stroke (its export is inset by 2),
     and at 1px this read as too thin. It scales, unlike the site's
     hairlines: those stay 1px because a sub-pixel border renders fuzzy,
     but 2u never falls below 1.6 so it has the room. */
  width: calc(2 * var(--u)); height: var(--rule-h, calc(2391 * var(--u)));
  background: var(--orange); pointer-events:none;
  /* Eliza 2026-10-03 (global): the long F rule always sits BEHIND page
     content -- never over copy; photos (positioned, later in the tree)
     paint over it, which is allowed. */
  z-index:-1;
}
/* STANDING RULE (Eliza, 2026-09-27): whenever this bracket/crossbar motif
   is built anywhere on the site -- this shared component, the Product
   page's own literal .product-accent copy below, or any future one --
   the SECOND (lower) crossbar must start flush with the vertical stroke
   and extend only outward (away from the first crossbar), never back
   across the vertical to the far side. Only the FIRST/top crossbar is
   meant to cross the vertical on both sides (that's the "T" the corner
   reads as). This exact failure mode -- the second line sticking out
   past the vertical -- has recurred more than once (see the intro-F
   glyph fix elsewhere in this file), hence writing it down as a rule
   rather than re-deriving it per instance.
   Every white page draws the same bracket at a different depth, so the two
   numbers that differ are variables and the motif is written once. The
   defaults are About's, so About renders exactly as before.
   Contact (321:665) and Trade (321:718) still have the rule at the OLD
   y=42, from before the bar gained its logomark -- the same edit the
   comment above records for About was never carried across. They use
   About's 215, and run to the white/carousel seam at 1025. */
body.page-contact, body.page-trade, body.page-thanks{
  --rule-top: calc(215 * var(--u));
  --rule-h: calc(810 * var(--u));
}
body.page-catalogue{
  --rule-h: calc(2199 * var(--u));
}
.about-rule::before, .about-rule::after,
.page-rule::before, .page-rule::after{
  content:''; z-index:-1; position:absolute; height: calc(2 * var(--u)); background: var(--orange);
}
.about-rule::before, .page-rule::before{ left: calc(-20 * var(--u)); top:0;                     width: calc(163 * var(--u)); }
.about-rule::after,  .page-rule::after{  left:0;                     top: calc(21 * var(--u)); width: calc(125 * var(--u)); }

main{ position:relative; }        /* .about-rule anchors to the page, not the viewport */

.about-block{ position:relative; }
.about-maker{ height: calc(1403 * var(--u)); }   /* to where ABOUT THE STUDIO starts */
.about-studio{ height: calc(892 * var(--u)); }   /* 1403 -> carousel band at 2295 */

.about-label{
  position:absolute; margin:0;
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-headline);
  letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
}
/* 265:757 is 189 wide for 15 characters and 265:759 is 198 for 16 — the
   same 12.5px per character, so the same size despite their boxes
   reporting 25 and 35. */
.about-label-maker{  left: var(--edge);            top: calc(266 * var(--u)); }
.about-label-studio{ left: calc(321 * var(--u));   top: 0; }

.about-col{ position:absolute; }
.about-col p{
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase;
  text-align:justify; color: var(--ink); margin:0;
}
.about-col p + p{ margin-top: 1.7em; }
.about-col-a1{ left: calc(464 * var(--u)); top: calc(266 * var(--u));  width: calc(399 * var(--u)); }
.about-col-b1{ left: calc(991 * var(--u)); top: calc(266 * var(--u));  width: calc(412 * var(--u)); }
.about-col-a2{ left: calc(321 * var(--u)); top: calc(53 * var(--u));   width: calc(399 * var(--u)); }
.about-col-b2{ left: calc(961 * var(--u)); top: calc(53 * var(--u));   width: calc(412 * var(--u)); }

.about-fig{ position:absolute; margin:0; }
.about-fig img{ width:100%; height:100%; object-fit:cover; display:block; }
/* aspect-ratio holds the box while the photos are still being exported, so
   the composition is reviewable before the assets land */
.about-portrait{ left: calc(22 * var(--u));   top: calc(311 * var(--u));  width: calc(386 * var(--u)); aspect-ratio: 386 / 622; }
.about-hands{    left: calc(1048 * var(--u)); top: calc(841 * var(--u));  width: calc(371 * var(--u)); aspect-ratio: 371 / 454; }
/* top 485 -> 575: the site's About copy has an extra closing paragraph
   Figma's column doesn't, so at Figma's y the photo butted the last line.
   Eliza 2026-10-03: "too close to the copy". */
.about-stools{   left: calc(797 * var(--u));  top: calc(575 * var(--u));  width: calc(427 * var(--u)); aspect-ratio: 427 / 292; }
.about-portrait, .about-hands, .about-stools{ background: var(--cream); }

/* 244:467 — the soft orange mark, with its caption to the LEFT of it
   (244:454 at x=694 against the mark at x=888). */
.about-stamp-fig{
  left: calc(888 * var(--u)); top: calc(1028 * var(--u));
  width: calc(185 * var(--u)); aspect-ratio: 185 / 323;
}
.about-stamp-fig img{ height:auto; object-fit:contain; }
.about-stamp-fig figcaption{
  position:absolute; left: calc(-194 * var(--u)); top: calc(198 * var(--u));
  width: calc(169 * var(--u));
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
}

/* Group 9: a filled orange bar, label left, arrow right — the inverse of
   the footer's white-filled download button. */
.about-cta{
  position:absolute; left: calc(461 * var(--u)); top: calc(791 * var(--u));
  width: calc(402 * var(--u)); min-height: calc(33 * var(--u));
  display:flex; align-items:center; justify-content:space-between;
  padding: 0 calc(12 * var(--u)) 0 calc(10 * var(--u));
  background: var(--orange); color: var(--white); text-decoration:none;
  border: 1px solid var(--orange);
  font-family: var(--font-body); font-weight:200; font-size: calc(14 * var(--u));
  letter-spacing:.05em; text-transform:uppercase;
  transition: background .18s ease, color .18s ease;
}
.about-cta:hover{ background: var(--white); color: var(--orange); }
.about-cta:hover img{ content: url("../images/logos/arrows/arrow-orange.svg"); }
.about-cta img{ width: calc(11 * var(--u)); height: calc(11 * var(--u)); }

/* The band link under the carousel stays mobile-only on About too: 338:15
   carries a CATALOGUE link under the mobile carousel, the desktop frame
   (175:1147) has only the four captions and no link. Same as the homepage,
   so no rule needed here — the mobile block switches it on. */

/* ============================================================
   WHITE SUPPORTING PAGES -- shared shell
   Contact 278:961 / 370:115, Trade 297:29 / 370:284, success 297:95
   ------------------------------------------------------------
   Contact and Trade are the same page with different labels: Figma gives
   them identical x/y for the stamp, the rule, every field and the submit.
   One component; the pages differ only in markup.

   Departures from Figma, all of them drift rather than design:
   - the lede sits at x=319 on both while every field starts at 328.
     Normalised to 328, so the block has one left edge.
   - the textarea and submit end at 1417 -- a 23 right margin, where the
     header and footer both use 40. Normalised to --edge.
   - off one identical form, the carousel starts at 1025 on Contact and
     993 on Trade. Normalised to 1025, the looser of the two, since Trade
     also carries a note under its textarea.
   - Trade's footer reads JOIN NEWSLETTER where every other page says SIGN
     UP FOR NEWSLETTER. Normalised to the latter.
   - captions drift up to 56px off their tiles (Contact's ABOUT THE MAKER,
     Trade's BLUFF TABLE). They ride .tile figcaption instead, which is
     flush with its tile on every page already.
   ============================================================ */
.page-section{ position:relative; height: calc(1025 * var(--u)); }

.page-label{
  position:absolute; left: var(--edge); top: calc(266 * var(--u)); margin:0;
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-headline);
  letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
}
.page-lede{
  position:absolute; left: calc(328 * var(--u)); top: calc(313 * var(--u));
  width: calc(442 * var(--u)); margin:0;
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
}
.page-lede a{ color:inherit; text-decoration:underline; text-underline-offset:.2em; }
.page-lede a:hover{ color: var(--orange); }

/* 292:18 / 297:88 -- the soft mark About carries, here with no caption.
   Base position is also the fallback rest position for js/main.js's
   pageStampFloat, which pins/releases this on desktop (Contact, Custom,
   Showroom, Trade, FAQ) so it floats with scroll and stops above the
   last carousel -- z-index matches the homepage .stamp it mirrors. */
.page-stamp{
  position:absolute; left: calc(22 * var(--u)); top: calc(597 * var(--u));
  width: calc(185 * var(--u)); margin:0; pointer-events:none; z-index:5;
}
.page-stamp img{ width:100%; height:auto; display:block; }

/* ---------- the form ----------
   Three short fields left, the long one right. Both columns come out the
   same height on their own -- 3 x (label + 15 + 50) + 2 x 29 against
   label + 15 + 288 -- which is why Figma has them both ending on 815.
   Nothing is positioned to make that happen, so the rhythm survives a
   field being added or a label wrapping onto two lines. */
.sf-form{
  position:absolute; left: calc(328 * var(--u)); right: var(--edge);
  top: calc(487 * var(--u));
  display:grid; grid-template-columns: calc(330 * var(--u)) 1fr;
  column-gap: calc(37 * var(--u));
}
.sf-col-a{ grid-column:1; }
.sf-col-b{ grid-column:2; }

.sf-field{ margin: 0 0 calc(29 * var(--u)); }
.sf-field:last-child{ margin-bottom:0; }
.sf-field label{
  display:block; margin-bottom: calc(15 * var(--u));
  /* Eliza (2026-10-02): "on trade and contact form, sometimes the copy
     is bolder -- should be consistently Light." This was the one
     font-weight:300 on either page (every other label/paragraph site-
     wide is 200) -- just inconsistent, not an intentional heavier
     weight, so it read as randomly bolder wherever a form field label
     sat next to 200-weight body copy. */
  font-family: var(--font-body); font-weight:200; font-size: calc(16 * var(--u));
  line-height: 1.6875;                        /* 278:1033: 16px on a 27px line */
  letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
}
.sf-field input, .sf-field textarea{
  display:block; width:100%; border-radius:0;
  background: rgba(255,255,255,.44);          /* 278:1049 */
  border: 2px solid var(--orange);            /* Eliza 2026-10-03: cream was too faint */
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-input);
  letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
  height: calc(50 * var(--u)); padding: 0 calc(13 * var(--u));
}
.sf-field textarea{
  height: calc(288 * var(--u)); padding: calc(13 * var(--u));
  resize:vertical; line-height:1.7;
}
.sf-field input::placeholder, .sf-field textarea::placeholder{
  color: var(--ink); opacity:.45; text-transform:uppercase; letter-spacing:.05em;
}
.sf-field input:focus, .sf-field textarea:focus{ outline:none; border-color: var(--orange); }
/* Contact (278:1058): the message box is 169 tall, not Trade's 288, so the
   new showroom/designer field (648:11/648:12) lands on y=725 -- the same
   row as ITEM(S) OF INTEREST -- and both columns end together on 815. */
#interior-architects{ scroll-margin-top: calc(240 * var(--u)); } /* clears the fixed nav when /custom#interior-architects jumps here */
/* GLOBAL FORM RULE (Eliza, 2026-10-03): the message box always stretches so
   the bottom field in the right column ends on the same line as the bottom
   field in the left column -- the grid already makes both columns the same
   height; the textarea simply absorbs whatever is left. */
@media (min-width:1153px){
  body.page-contact .sf-col-b, body.page-trade .sf-col-b{ display:flex; flex-direction:column; }
  body.page-contact .sf-col-b .sf-field:has(textarea), body.page-trade .sf-col-b .sf-field:has(textarea){
    flex: 1 1 auto; display:flex; flex-direction:column; min-height:0;
  }
  body.page-contact .sf-col-b .sf-field textarea, body.page-trade .sf-col-b .sf-field textarea{
    flex: 1 1 auto; height:auto; min-height: calc(169 * var(--u)); resize: none;
  }
}
@media (min-width:1153px){
  body.page-contact label[for="designer"]{ white-space:nowrap; } /* copy shortened so it fits one line at the standard 16 label size */ /* 16u runs ~770 wide against a 705 column; 14u keeps it on one line so the input stays on ITEM(S) OF INTEREST's row */
}

/* Only after a submit attempt, so nothing is flagged on arrival. */
.sf-form.is-validated input:invalid,
.sf-form.is-validated textarea:invalid{ border-color: var(--orange); }

/* Replaces the browser's own floating validation bubble (js/main.js
   suppresses it entirely -- it can't be restyled, it's OS chrome) with a
   plain line under the field, in the site's own ink colour and caps
   instead of dark-on-white system UI with a pointer and a drop shadow. */
.sf-field-error{
  display:block; margin-top: calc(6 * var(--u));
  font-family: var(--font-body); font-weight:200; font-size: calc(12 * var(--u));
  line-height:1.4; letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
}
.sf-field-error[hidden]{ display:none; }
/* Out of flow: the line sits in the gap under its field (29u > 6u + one
   12u line), so showing it never moves the fields below. */
.sf-field{ position:relative; }
.sf-field .sf-field-error{ position:absolute; left:0; right:0; top:100%; margin-top: calc(5 * var(--u)); }

/* 297:90's note and the submit share one band: note left, button right. */
.sf-actions{
  grid-column: 1 / -1; display:flex; align-items:flex-start;
  justify-content:space-between; gap: var(--sp-24);
  margin-top: calc(31 * var(--u));
}
.sf-note{
  margin:0; max-width: calc(481 * var(--u));
  font-family: var(--font-body); font-weight:200; font-size: calc(14 * var(--u));
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
}
.sf-submit{
  flex:0 0 auto; margin-left:auto;
  width: calc(204 * var(--u)); min-height: calc(33 * var(--u));
  display:flex; align-items:center; justify-content:space-between;
  padding: 0 calc(11 * var(--u)) 0 calc(17 * var(--u));
  background: var(--orange); color: var(--white); border: 1px solid var(--orange); cursor:pointer;
  font-family: var(--font-body); font-weight:200; font-size: calc(14 * var(--u));
  letter-spacing:.05em; text-transform:uppercase;
  transition: background .18s ease, color .18s ease;
}
.sf-submit:hover{ background: var(--white); color: var(--orange); }
.sf-submit:hover img{ content: url("../images/logos/arrows/arrow-orange.svg"); }
.sf-submit img{ width: calc(10 * var(--u)); height: calc(10 * var(--u)); }

/* Shown by js/main.js only while no endpoint is wired up, so the form
   says what it is doing instead of silently doing nothing. */
.sf-unwired{
  grid-column: 1 / -1; margin: var(--sp-12) 0 0;
  font-family: var(--font-body); font-weight:200; font-size: calc(14 * var(--u));
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase; color: var(--orange);
}

/* ---------- form success (297:95) ---------- */
.page-thanks-msg{
  position:absolute; left: calc(328 * var(--u)); top: calc(487 * var(--u));
  width: calc(722 * var(--u)); margin:0;
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-headline);
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
}
.page-thanks-back{
  position:absolute; left: calc(328 * var(--u)); top: calc(620 * var(--u));
  width: calc(204 * var(--u));
}

/* ============================================================
   INQUIRE MODAL (shared component, not a Figma-linked frame --
   built from a pasted screenshot Eliza sent, "Inquire pop-up" /
   "Inquire pop-up mobile", 2026-09-27, not a get_design_context node)
   Every "Inquire to Purchase" button on a product page opens this
   instead of navigating to Contact -- js/main.js's inquireModal()
   pre-fills the Item(s) of Interest field from that button's own
   data-inquire-product attribute, so each product page's own trigger
   supplies its own copy with no per-page script needed. Reuses the
   shared .sf-form/.sf-field markup verbatim (including its
   text-transform:uppercase inputs -- "force caps lock on all
   fields" is already true of every form on the site) rather than a
   parallel field system, just repositioned from page-absolute to
   modal-relative and recoloured for the orange panel.
   ------------------------------------------------------------ */
.inquire-modal{
  position:fixed; inset:0; z-index:300; display:flex;
  align-items:flex-start; justify-content:center;
  padding: calc(120 * var(--u)) var(--edge) calc(64 * var(--u));
  overflow-y:auto;
}
.inquire-modal[hidden]{ display:none; }
body.inquire-modal-open{ overflow:hidden; }

.inquire-modal-backdrop{ position:fixed; inset:0; background: rgba(28,17,35,.4); }
.inquire-modal-panel{
  position:relative; z-index:1; width:100%; max-width: calc(1107 * var(--u));
  /* Eliza 2026-10-03: white pop-up, orange outline (Figma "Inquire pop-up":
     951 of a 1237 frame = ~1107u wide, fields 330u + 16u + 701u) */
  background: var(--white); color: var(--ink); border: 1px solid var(--orange);
  padding: calc(40 * var(--u)) calc(30 * var(--u)) calc(48 * var(--u));
}
.inquire-modal-stamp{ width: calc(64 * var(--u)); margin: 0 0 calc(24 * var(--u)); }
.inquire-modal-stamp img{ width:100%; height:auto; display:block; }
.inquire-modal-close{
  position:absolute; top: calc(28 * var(--u)); right: calc(28 * var(--u));
  width: calc(20 * var(--u)); height: calc(20 * var(--u)); padding:0; border:0;
  background:none; color: var(--orange); cursor:pointer;
  display:flex; align-items:center; justify-content:center;
}
.inquire-modal-close svg{ width:100%; height:100%; display:block; }

.inquire-modal-lede{
  margin: 0 0 calc(32 * var(--u)); max-width: calc(600 * var(--u));
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
}
.inquire-modal-lede a{ color:inherit; text-decoration:underline; text-underline-offset:.2em; }

.inquire-modal .sf-form{
  position:static; display:grid;
  grid-template-columns: calc(330 * var(--u)) minmax(0,1fr); column-gap: calc(16 * var(--u));
}
/* the notes box is as tall as the first two left-hand fields, so the
   showroom/designer field below it lands on YOUR COMPANY's row */
.inquire-modal .sf-field textarea{ height: calc(171 * var(--u)); }
.inquire-modal .sf-field label[for="inquire-designer"]{ white-space:nowrap; }

/* ============================================================
   SHOWROOM (278:1574 desktop / 370:462 mobile)
   White section runs 0-1719 (278:1575) -- same seam as Contact/Trade below.
   Its rule (321:704) is still at the old y=42 bar position, never carried
   forward the way About's 316:357 was, so it gets the same treatment as
   Contact/Trade: run from 215 to the white/carousel seam.
   ------------------------------------------------------------
   Departures from Figma, all of them drift rather than design:
   - Eliza 2026-09-28: re-pulled 278:1574 fresh (get_design_context +
     get_metadata) after she flagged this section as "way off." Findings:
     the "Furnish Bainbridge is a woman-owned..." paragraph that used to
     sit above the address was never in Figma at all -- removed. The
     Furnish Bainbridge logo (298:182) IS downloadable after all (the
     earlier 403 was some transient/session issue, not a real block) --
     it's a real placed raster, now saved as
     images/showroom/furnish-bainbridge-lockup.png and rendered as an
     actual <img>, not a text placeholder. And the interior photo's real
     box (524:90) is 424x283 landscape, not the 254x381 portrait box this
     was built against -- fixed below, which is why the photo looked
     wrongly cropped.

     2026-09-28: Eliza uploaded Furnish Bainbridge's real logo lockup
     (Drive: 05.Showroom/1-FurnishBainbridge-Lockup-BlueGray) to replace
     the stopgap crop pulled out of the Figma comp. Its native aspect
     ratio is ~1.441 (wider relative to its height than the old asset's
     ~1.354), so the box below is sized to that ratio -- height held the
     same as before, width recalculated -- otherwise object-fit:contain
     letterboxes it inside a mismatched box, which read as "spacing
     weird" around the logo.
   - image15 (298:185), the small accent between the two blurbs, is two
     plain rules meeting at a corner, not a photo or a third-party mark --
     reproduced directly instead of held back.
   - the four-tile grid's Figma layer names (Geary/Pangyo/Westlake/Shoal)
     don't match their own captions (BLUFF TABLE/POINT GREY STOOLS/W
     INTERIOR ARCHITECTS/SHOAL COFFEE TABLE) -- the same caption drift
     already documented above for Contact/Trade. Tiles use the codebase's
     own product photography, matched to the caption text instead of the
     Figma layer's filename.
   ============================================================ */
body.page-showroom{
  --rule-top: calc(215 * var(--u));
  --rule-h: calc(948 * var(--u));   /* 215 -> the white/carousel seam at 1163 (Figma) */
}
.showroom-section{ position:relative; height: calc(1163 * var(--u)); } /* Figma: carousel starts 95u under the lowest content (photo bottom 1240) -- was 1719, ~384u of dead white */

.showroom-col{
  position:absolute; left: calc(324 * var(--u)); width: calc(442 * var(--u)); margin:0;
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
  text-align:justify;
}
.showroom-col p{ margin:0; }
.showroom-col p + p{ margin-top: 1.7em; }
/* Desktop's Figma frame has no blurb, only the address -- see the drift
   note above. Hidden here, shown in the mobile media query where its own
   frame really does include it. */
.showroom-blurb{ display:none; }
.showroom-partner{ top: calc(317 * var(--u)); }
.showroom-location{ top: calc(799 * var(--u)); }

/* 615:563 -- VISIT button, replaces the overlapping Furnish logo (Eliza, 2026-10-02) */
.showroom-cta.showroom-visit{ top: calc(450 * var(--u)); }

/* 298:185 -- a plain corner-rule accent; see the drift note above. */
.showroom-accent{
  position:absolute; left: calc(324 * var(--u)); top: calc(663 * var(--u));
  width: calc(97 * var(--u)); height: calc(97 * var(--u)); margin:0; pointer-events:none;
  /* Figma 2026-10-03: the solid orange logomark, not the faint cream corner */
  background: url("../images/logos/logomark/logomark-orange.svg") center / contain no-repeat;
}

/* 524:90 ("5 1") -- real box is 823,325, 424x283 (landscape); was built
   against a stale 824,279, 254x381 (portrait) box, which force-cropped
   Eliza's landscape photo into a tall sliver. Fixed to the real coords. */
.showroom-portrait{
  position:absolute; left: calc(823 * var(--u)); top: calc(325 * var(--u));
  width: calc(424 * var(--u)); aspect-ratio: 424 / 283; margin:0; background: var(--cream);
}
.showroom-interior{
  position:absolute; left: calc(1137 * var(--u)); top: calc(760 * var(--u));
  width: calc(247 * var(--u)); aspect-ratio: 247 / 297; margin:0; background: var(--cream);
}
.showroom-portrait img, .showroom-interior img{ width:100%; height:100%; object-fit:cover; display:block; }

.showroom-cta{
  position:absolute; left: calc(319 * var(--u)); top: calc(944 * var(--u));
  width: calc(402 * var(--u)); min-height: calc(33 * var(--u));
  display:flex; align-items:center; justify-content:space-between;
  padding: 0 calc(12 * var(--u)) 0 calc(10 * var(--u));
  background: var(--orange); color: var(--white); text-decoration:none;
  border: 1px solid var(--orange);
  font-family: var(--font-body); font-weight:200; font-size: calc(14 * var(--u));
  letter-spacing:.05em; text-transform:uppercase;
  transition: background .18s ease, color .18s ease;
}
.showroom-cta:hover{ background: var(--white); color: var(--orange); }
.showroom-cta:hover img{ content: url("../images/logos/arrows/arrow-orange.svg"); }
.showroom-cta img{ width: calc(11 * var(--u)); height: calc(11 * var(--u)); }

/* the four-tile strip (278:1576-1583) bleeds past the frame at 1887 wide
   on a 1440 canvas -- the same draggable overflow every other carousel on
   the site uses, just here on white instead of orange. */
/* Eliza (2026-10-03): white caption strip between the carousel and the
   orange footer read as a gap -- bottom carousel stays orange here too
   (captions go white, as on Catalogue/Home). */
body.page-showroom .carousel{ background: var(--orange); }

/* ============================================================
   FAQ (278:1707 desktop / 370:543 mobile)
   White section runs 0-2909 -- same seam pattern as the other white
   pages. Its rule (299:197) is still at the old y=42 bar position, so it
   gets the Contact/Trade/Showroom treatment: 215 to the seam.
   ------------------------------------------------------------
   Departures from Figma, drift rather than design:
   - the desktop grid's Figma layer names (Geary/Pangyo/Westlake/Shoal)
     don't match their captions -- the same drift as Showroom's grid,
     same fix: codebase photography matched to the caption text.
   - the mobile frame repeats "HOW MUCH DOES SHIPPING COST?" a second
     time near the bottom -- an authoring duplicate, not an eleventh
     question. Both frames answer the same ten questions, so it's built
     once.
   - the mobile frame shortens the heading to "FAQs"; every footer and
     menu link elsewhere on the site spells out "Frequently Asked
     Questions", so the full title is kept on both breakpoints.
   - desktop positions each question/answer at its own exact Figma
     coordinate; mobile's per-item gaps are a function of how long each
     answer happens to run rather than a deliberate rhythm, so mobile
     runs the list in flow with one consistent gap instead of
     reproducing ten different ones.
   ============================================================ */
body.page-faq{
  --rule-top: calc(215 * var(--u));
  --rule-h: calc(2743 * var(--u));   /* 215 -> the white/carousel seam at 2958, recomputed for the standardized 64u inter-item gap below */
}
.faq-section{ position:relative; height: calc(2958 * var(--u)); }
body.page-faq .page-label{ width: calc(230 * var(--u)); white-space:normal; line-height:1.35; }
body.page-faq .page-stamp{ left: calc(1218 * var(--u)); top: calc(266 * var(--u)); }

.faq-q{
  position:absolute; left: calc(319 * var(--u)); width: calc(589 * var(--u)); margin:0;
  font-family: var(--font-body); font-weight:200; font-size: calc(20 * var(--u));
  line-height:1.35; letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
}

/* Anchor target for footer/menu "Lifetime Warranty" links (#faq.html#warranty).
   scroll-margin-top keeps the fixed header (--hdr-h, published by js/main.js)
   from covering the question after the smooth-scroll lands. */
#warranty{ scroll-margin-top: calc(var(--hdr-h, 0px) + 24 * var(--u)); }
.faq-a{
  position:absolute; left: calc(547 * var(--u)); width: calc(402 * var(--u)); margin:0;
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
  text-align:justify;
}
.faq-still{
  /* Eliza: "standardize all vertical spacing between answers" -- the 10
     questions now flow at a fixed 64u gap (previously each answer's
     bottom was wherever its own text happened to wrap to, ranging
     13-115u to the next question). This block's own top is recomputed
     to follow the last answer by that same rhythm (~104u, same ratio the
     original Figma coordinates used here). */
  position:absolute; left: calc(547 * var(--u)); top: calc(2742 * var(--u)); margin:0;
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
}
.faq-cta{
  position:absolute; left: calc(547 * var(--u)); top: calc(2794 * var(--u));
  width: calc(402 * var(--u)); min-height: calc(33 * var(--u));
  display:flex; align-items:center; justify-content:space-between;
  padding: 0 calc(12 * var(--u)) 0 calc(10 * var(--u));
  background: var(--orange); color: var(--white); text-decoration:none;
  border: 1px solid var(--orange);
  font-family: var(--font-body); font-weight:200; font-size: calc(14 * var(--u));
  letter-spacing:.05em; text-transform:uppercase;
  transition: background .18s ease, color .18s ease;
}
.faq-cta:hover{ background: var(--white); color: var(--orange); }
.faq-cta:hover img{ content: url("../images/logos/arrows/arrow-orange.svg"); }
.faq-cta img{ width: calc(11 * var(--u)); height: calc(11 * var(--u)); }

/* the four-tile strip bleeds past the frame, same as Showroom's -- see
   that page's own comment for the caption-matching note. */
/* (FAQ used to override the carousel to white. That made the caption strip under the photos a white band between the carousel and the orange footer. The carousel is orange on every page now, so nothing can sit between it and the footer.) */

/* ============================================================
   CUSTOM (265:787 desktop / 404:689 mobile)
   The largest white page on the site -- an intro, a two-photo strip, two
   project-feature essays (client testimonial + photo band each), and the
   standard four-tile carousel. White section runs 0-3978. Its rule
   (321:652) is at the old y=42 bar position, same Contact/Trade/Showroom/
   FAQ treatment: 215 to the seam.
   ------------------------------------------------------------
   Desktop positions every block at its own exact Figma coordinate, same
   as every other white page. Mobile reorders real content, not just a
   reflow: the intro pairs with INT-6+IMG_0274 first and DSC_1055 moves to
   a standalone band near the end, instead of DSC_1055 sitting beside the
   intro copy the way it does on desktop. Rather than force one shared DOM
   order to serve two genuinely different layouts, the markup follows
   MOBILE's reading order (mobile is flow-positioned, so DOM order IS its
   layout) and desktop repositions every block with its own absolute
   coordinate, which works regardless of where a block sits in the DOM.
   ------------------------------------------------------------
   Other departures from Figma, drift rather than design:
   - the carousel's Figma layer names don't match their captions -- same
     drift as Showroom/FAQ, same fix.
   - the two photo captions ("Union Square, San Francisco" / "South Lake
     Union, Seattle") sit inside whichever photo they're closest to,
     rather than each frame's own literal pixel position -- Figma's own
     mobile frame anchors "Union Square" to the wrong photo (INT-6's
     bottom edge, not IMG_0274's, where desktop and the caption's own
     subject both put it), so both breakpoints anchor it to the same
     photo, at a consistent bottom-left inset.
   ============================================================ */
body.page-custom{
  --rule-top: calc(215 * var(--u));
  --rule-h: calc(3763 * var(--u));   /* 215 -> the white/carousel seam at 3978 */
}
.custom-section{ position:relative; height: calc(3978 * var(--u)); }

.custom-intro{
  position:absolute; left: calc(319 * var(--u)); top: calc(312 * var(--u));
  width: calc(442 * var(--u)); margin:0;
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
  text-align:justify;
}
.custom-intro p{ margin:0; }
.custom-intro p + p{ margin-top: 1.7em; }

.custom-cta{
  position:absolute; left: calc(319 * var(--u)); top: calc(580 * var(--u));
  width: calc(402 * var(--u)); min-height: calc(33 * var(--u));
  display:flex; align-items:center; justify-content:space-between;
  padding: 0 calc(12 * var(--u)) 0 calc(10 * var(--u));
  background: var(--orange); color: var(--white); text-decoration:none;
  border: 1px solid var(--orange);
  font-family: var(--font-body); font-weight:200; font-size: calc(14 * var(--u));
  letter-spacing:.05em; text-transform:uppercase;
  transition: background .18s ease, color .18s ease;
}
.custom-cta:hover{ background: var(--white); color: var(--orange); }
.custom-cta:hover img{ content: url("../images/logos/arrows/arrow-orange.svg"); }
.custom-cta img{ width: calc(11 * var(--u)); height: calc(11 * var(--u)); }

/* Custom: the floating stamp starts under the CUSTOM label (nav bar ends 197u) instead of
   at the generic 597u, which sat low on tall windows. The second, static
   stamp is hidden on desktop -- with one stamp now floating down the same
   left edge, a fixed copy would collide with it as it passed. */
@media (min-width:1153px){
  body.page-custom .page-stamp{ top: calc(325 * var(--u)); }
  body.page-custom .custom-stamp-2{ display:none; }
}
/* second stamp -- Custom is the one white page long enough to carry two */
.custom-stamp-2{
  position:absolute; left: calc(22 * var(--u)); top: calc(1204 * var(--u));
  width: calc(185 * var(--u)); margin:0; pointer-events:none;
}
.custom-stamp-2 img{ width:100%; height:auto; display:block; }

.custom-photo{ position:relative; margin:0; background: var(--cream); overflow:hidden; }
.custom-photo img{ width:100%; height:100%; object-fit:cover; display:block; }
.custom-photo-hero{     position:absolute; left: calc(798 * var(--u));  top: calc(319 * var(--u));  width: calc(621 * var(--u)); aspect-ratio: 621/480; }
.custom-photo-int6{     position:absolute; left:0;                      top: calc(928 * var(--u));  width: calc(743 * var(--u)); aspect-ratio: 743/928; }
.custom-photo-img0274{  position:absolute; left: calc(743 * var(--u));  top: calc(928 * var(--u));  width: calc(697 * var(--u)); aspect-ratio: 697/928; }
.custom-photo-westlake3{position:absolute; left:0;                      top: calc(2628 * var(--u)); width: calc(475 * var(--u)); aspect-ratio: 475/695; }
.custom-photo-westlake2{position:absolute; left: calc(475 * var(--u));  top: calc(2628 * var(--u)); width: calc(965 * var(--u)); aspect-ratio: 965/695; }

.custom-caption{
  position:absolute; left: calc(16 * var(--u)); bottom: calc(20 * var(--u)); margin:0;
  color: var(--white); pointer-events:none;
  font-family: var(--font-body); font-weight:200; font-size: calc(20 * var(--u));
  letter-spacing:.05em; text-transform:uppercase;
}

.custom-feature-label{
  position:absolute; left: calc(22 * var(--u)); margin:0;
  font-family: var(--font-body); font-weight:200; font-size: calc(20 * var(--u));
  letter-spacing:.05em; text-transform:uppercase; color: var(--ink); line-height:1.4;
}
.custom-feature-copy, .custom-feature-quote, .custom-feature-attr{
  position:absolute; margin:0; font-size: var(--fs-body);
  font-family: var(--font-body); font-weight:200; line-height:1.7;
  letter-spacing:.05em; text-transform:uppercase; color: var(--ink); text-align:justify;
}
/* Eliza (2026-10-02): "copy on 2 pars should be same size, constanzia too
   far down -- do it like you did for the Interior Architects section
   below it." The shared rule above only ever set font-size on
   .custom-feature-copy, leaving .custom-feature-quote and
   .custom-feature-attr to fall back to whatever ambient size they
   inherited -- fine for the Interior Architects section because it
   always overrides all three inline (15px, matching its own Figma node),
   but the .WORLD section above it never did, so its quote paragraph (and
   therefore "Constanzia...") rendered at the wrong size and reflowed
   taller than Figma's 16px box, pushing the fixed-position attribution
   line visually far below where the quote actually ended. Moving
   font-size onto the shared selector gives every instance a matching
   16px baseline (Figma's own value for the .WORLD copy/quote/attr) while
   the Interior Architects section's existing inline 15px overrides still
   win as before -- nothing about that section changes. */
.custom-feature-copy p, .custom-feature-quote p{ margin:0; }
.custom-feature-copy p + p, .custom-feature-quote p + p{ margin-top: 1.7em; }
.custom-feature-copy{ left: calc(328 * var(--u)); width: calc(442 * var(--u)); }
.custom-feature-divider{ display:none; }

body.page-custom .carousel{ background: var(--orange); }

/* ============================================================
   PRODUCT — COVE TABLE (232:400 desktop / 342:858 mobile)
   The only product-detail page in this batch (Eliza: "just do it for cove
   table for now"). White section runs 0-1628 (vs Custom/Showroom/FAQ's
   single rule bar, Figma gives this page its own small bracket accent
   next to the title -- a short horizontal tick, a long vertical stem down
   to the first divider, and a second short horizontal tick -- built
   literally rather than forced into the shared .page-rule pattern).
   ------------------------------------------------------------
   Gallery: hero uses the site-wide Cove Table photo (also the homepage
   carousel tile); the three thumbnails use the additional angles Eliza
   supplied in Images/07.Product_Pages/01.Cove_Table (cove-table-2/3/4.webp
   -- joinery detail, in-situ side view, styled detail) rather than
   reusing a single shot.
   Same gap for the three wood-species swatches (walnut / euro beech /
   cherry) -- no swatch photography exists, so these are flat CSS
   gradients sampled from Figma's own swatch colors, not photographed
   grain. Swap for real macro photos when Eliza has them.
   ------------------------------------------------------------
   Other departures from Figma, drift rather than design:
   - the small gallery nav arrows (244:311/244:316) are decorative ticks
     with no evident click behavior in Figma (no linked frame) -- built
     as a static SVG accent, not a working prev/next control.
   - "studio-mark-FFA000-soft" is just the standard orange stamp at low
     opacity, not a distinct asset -- reused stamp-orange.svg + opacity.
   - the wood-swatch labels are Figma right-aligned at tight, overlap-
     prone offsets; centered under each swatch instead, same non-overlap
     goal, no odd ragged edge.
   - mobile's own frame swaps the shared "pieces in the wild" carousel
     for a different, uncaptioned 4-tile strip (pareuko/cove/bluff/union
     sq crops) that doesn't exist in code or asset form anywhere else on
     the site. Every other page -- including this one's own desktop
     frame -- uses the single shared carousel component, so mobile reuses
     it too rather than one-off building a second, inconsistent gallery.
   ============================================================ */
.product-section{ --s1:0px; --s2:0px; --s: calc(var(--s1) + var(--s2)); position:relative; height: calc(1811 * var(--u) + var(--s)); max-width: calc(1440 * var(--u)); margin: 0 auto; }

.product-accent{ position:absolute; background: var(--orange); pointer-events:none; z-index:-1; }
.product-accent-h1{ left: calc(285 * var(--u)); top: calc(215 * var(--u)); width: calc(163 * var(--u)); height: calc(2 * var(--u)); }
.product-accent-v { left: calc(305 * var(--u)); top: calc(215 * var(--u)); width: calc(2 * var(--u));   height: calc(608 * var(--u) + var(--s1)); } /* ends on divider 1, whatever the window height */
.product-accent-h2{ left: calc(305 * var(--u)); top: calc(236 * var(--u)); width: calc(125 * var(--u)); height: calc(2 * var(--u)); }

.product-title{
  position:absolute; left: calc(40 * var(--u)); top: calc(274 * var(--u)); margin:0;
  font-family: var(--font-body); font-weight:200; font-size: calc(25 * var(--u));
  letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
}

/* Eliza (13th pass, 2026-09-29): full gallery redesign, 8 explicit rules:
   (1) all photos bottom-align to the orange divider line with a
   consistent gap between them; (2) every non-hero photo shares the same
   view height; (3) each photo keeps its own real aspect ratio (never
   cropped/letterboxed); (4) the hero position (3rd from left) is largest
   on load; (5) clicking an arrow moves WHICH position is "hero" size --
   the previous hero shrinks back to the shared compact height; (6) that
   growing/shrinking is animated; (7) the two leftmost positions grow less
   in their hero state so they never reach up into the product title; (8)
   the gap between photos resizes automatically to keep the same total
   padding as photos change size.

   Photos never move or swap again -- each of the 4 figures below keeps
   its own fixed photo permanently. Only a `.is-hero` class moves between
   them (see productGallery() in js/main.js). Visual left-to-right order
   is set with `order` below (thumb-5, cove2, hero, cove3) WITHOUT
   touching DOM order, because the mobile media query further down still
   depends on DOM order for its own stacked layout. .product-gallery is a
   flex row: align-items:flex-end bottom-aligns every photo to the same
   line (rule 1) and justify-content:space-between is what gives rule 8
   its "gap resizes on its own" behavior for free -- the browser
   redistributes the row's leftover width between items every frame while
   heights (and therefore widths, since width stays auto/aspect-ratio-
   driven) are transitioning. */
.product-gallery{
  position:absolute;
  left: calc(46 * var(--u));
  right: calc(170 * var(--u));
  /* top 278u = the lower horizontal F line (236+2) + the 40u keep-out. The
     F rule is 40u on EVERY side, horizontal arms included, so no photo
     can sit closer than that to any part of it (was 232u: the hero ran
     straight into the arm). */
  top: calc(278 * var(--u));
  height: calc(545 * var(--u) + var(--s1));
  display:flex;
  align-items:flex-end;
  justify-content:space-between;
  /* Eliza (2026-10-02): "too cramped on other products" -- now that photo
     CONTENT rotates through fixed-size boxes instead of boxes resizing
     (see productGallery() in js/main.js), each product's own photo aspect
     ratios decide how much width the 4 boxes actually take up, so
     space-between alone could leave barely any gap for a product whose
     photos run wide. `gap` is a floor underneath space-between -- items
     never sit closer than this regardless of their own widths. */
  gap: calc(24 * var(--u));
}

.product-photo{
  position:relative; margin:0; flex: 0 0 auto;
  height: calc(152 * var(--u)); width:auto; /* shared compact height, rule 2 */
  transition: height .45s cubic-bezier(.65,0,.35,1); /* rule 6 */
}
.product-photo img{ height:100%; width:auto; object-fit:contain; object-position:center bottom; display:block; transition: max-width .45s cubic-bezier(.65,0,.35,1); } /* higher specificity than .gallery-img alone (class+tag beats class) -- kept in sync with it below. object-fit:contain + width:auto (never cropped, rule 3); object-position:center bottom so the photo's own bottom edge is what sits on the divider regardless of letterbox space (rule 1). */

/* Visual order only -- DOM order is unchanged (mobile depends on it). */
.product-thumb-5{ order:1; }
.product-thumb-cove2{ order:2; }
.product-hero{ order:3; }
.product-thumb-cove3{ order:4; }

/* Hero state per position (rule 4 default: .product-hero starts with
   is-hero in the HTML). Rule 7: the two leftmost positions (thumb-5,
   cove2) grow to a smaller hero height than hero/cove3 so they never
   climb high enough to reach "COVE SIDE TABLE" (title sits ~274-300u
   from the top; a 380u-tall box bottom-aligned to the 823u divider tops
   out at 443u, safely clear -- a full 591u box would top out at 232u,
   which does reach the title). */
.product-hero.is-hero, .product-thumb-cove3.is-hero{ height: calc(545 * var(--u) + var(--s1)); }
.product-thumb-5.is-hero, .product-thumb-cove2.is-hero{ height: calc(380 * var(--u)); }

/* Safety max-width caps -- not a design size, just a guard so an
   unusually wide photo (checked across all 7 product pages) can't run
   past a neighbor or the page edge; object-fit:contain still won't crop
   it, it just can't grow past this width. Compact-state caps (matching
   the original per-column budget) and larger hero-state caps per
   position, sized against .product-gallery's own content budget
   (1440 - 46 - 170 margins = 1224u, minus gaps and the other 3 compact
   items) so the widest realistic hero photo never overflows. */
.product-thumb-5 .gallery-img, .product-thumb-cove2 .gallery-img{ max-width: calc(241 * var(--u)); }
.product-hero .gallery-img, .product-thumb-cove3 .gallery-img{ max-width: calc(300 * var(--u)); }
.product-thumb-5.is-hero .gallery-img, .product-thumb-cove2.is-hero .gallery-img{ max-width: calc(450 * var(--u)); }
.product-hero.is-hero .gallery-img, .product-thumb-cove3.is-hero .gallery-img{ max-width: calc(700 * var(--u)); }

.gallery-img{
  height:100%; width:auto; object-fit:contain; object-position:center bottom; display:block;
  -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
}
.product-photo img{ pointer-events:none; } /* drag now reads from whichever photo is active, not just hero -- see productGallery() */

/* Only the currently-enlarged photo shows the drag affordance -- dragging
   moves the hero STATE now, not a photo, but it still reads from
   whichever box is active. */
.product-photo.is-hero{ cursor:grab; touch-action: pan-y; user-select:none; -webkit-user-select:none; }
.product-photo.is-dragging{ cursor:grabbing; }

.product-nav-arrows{
  /* Eliza (2026-10-02): "move the arrows BELOW the orange line, since
     then they overlap with the images." top:797 sat above
     .product-divider-1 (top:823) and clipped into the gallery photos --
     moved below the line instead, in the gap before .product-desc
     (top:880), clear of both the divider and the gallery. */
  position:absolute; right: calc(80 * var(--u)); top: calc(840 * var(--u) + var(--s1));
  height: calc(17 * var(--u));
  display:flex; align-items:center; gap: calc(13 * var(--u));
}
.product-nav-btn{
  appearance:none; background:none; border:0; color:inherit;
  padding: calc(6 * var(--u)); margin: calc(-6 * var(--u));
  display:flex; align-items:center; justify-content:center; cursor:pointer;
}
.product-nav-icon{ width: calc(16.15 * var(--u)); height: calc(17 * var(--u)); display:block; }
.product-nav-icon-prev{ transform: scaleX(-1); }
.product-nav-btn:hover, .product-nav-btn:focus-visible{ opacity:.6; }
.product-nav-btn:focus-visible{ outline: none; }

[data-gallery-thumb]{ cursor:pointer; }
[data-gallery-thumb] img{ transition: opacity .2s ease, max-width .45s cubic-bezier(.65,0,.35,1); }
[data-gallery-thumb]:hover img{ opacity:.82; }

.product-stamp-soft{
  /* Eliza 2026-09-27: "the stamp looks very faint" -- .3 read as barely
     there against the white section background. .55 keeps it a soft
     background accent (not competing with the real content) while
     actually being visible. */
  /* Eliza (9th pass, 2026-09-29): "shifting stamp to bottom left under
     the orange line as its starting point so it doesn't overlap with
     the arrows." Old spot (left1301/top594) sat right beside the old
     nav arrows/cove3 corner -- now that those boxes resized, moved the
     stamp's natural/starting position to the bottom-left instead: under
     .product-divider-1 (top:823u), in the space thumb-5 vacated when it
     moved to stack above cove2. productStampFloat() in main.js mirrors
     these same 46/847 constants for its own natural-position math (the
     float/pin-to-viewport behavior itself is unchanged). */
  position:absolute; left: calc(46 * var(--u)); top: calc(847 * var(--u) + var(--s1));
  width: calc(126 * var(--u)); margin:0; opacity:.55; pointer-events:none;
  z-index: 5; /* above photos/copy, below the nav bar (z-index 50) -- Eliza 2026-10-03 */
}
.product-stamp-soft img{ width:100%; height:auto; display:block; }

/* Eliza 2026-09-28: "the orange horizontal bar should bleed with left and
   right of the page." left:0/width:100% is 100% of .product-section,
   which is capped at max-width:1440u and centered -- once --u hits its
   1.4px clamp ceiling (viewports wider than ~2016px, e.g. Eliza's iMac),
   the section stops growing but the viewport keeps going, leaving a
   visible gap on both sides where this line used to stop short of the
   real page edge. The standard full-bleed trick (50%/-50vw) breaks it
   out of the section's own constrained box so it always reaches the true
   viewport edges regardless of --u's ceiling. */
.product-divider{
  position:absolute; left:50%; width:100vw; margin-left:-50vw;
  height:1px; margin-top:0; margin-bottom:0; border:0; background: var(--orange);
} /* Eliza: "product page line should be orange not grey" */
/* divider 1 matches the long F's 2u weight and sits above the photos (Eliza 2026-10-03); divider 2 stays a 1px hairline */
.product-divider-1{ top: calc(822 * var(--u) + var(--s1)); height: calc(2 * var(--u)); z-index: 2; }
.product-divider-2{ top: calc(1219 * var(--u) + var(--s)); }

.product-desc{
  position:absolute; left: calc(528 * var(--u)); top: calc(880 * var(--u) + var(--s1));
  width: calc(399 * var(--u)); margin:0;
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
  text-align:justify;
}
.product-desc p{ margin:0; }
.product-desc p + p{ margin-top: 1.7em; }

.product-dims, .product-price, .product-config{
  position:absolute; top: calc(1280 * var(--u) + var(--s)); width: calc(399 * var(--u)); margin:0;
  font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
}
.product-dims p, .product-price p{ margin:0; }
.product-dims p + p{ margin-top: 1.7em; }
.product-dims{ left: calc(40 * var(--u)); }
.product-price{ left: calc(528 * var(--u)); }
.product-config{ left: calc(1006 * var(--u)); }
.product-config ul{ margin: 1.7em 0 0; padding-left: calc(24 * var(--u)); }
.product-config li + li{ margin-top:.3em; }
/* Eliza: "bullets look too big relative to figma" -- the default disc
   marker scales with the list text's own font-size (var(--fs-body)),
   which reads much heavier than Figma's small bullet glyph; ::marker
   lets the dot shrink independently of the (unchanged) list text. */
.product-config li::marker{ font-size: .5em; }

.product-cta{
  position:absolute; left: calc(528 * var(--u)); width: calc(402 * var(--u)); min-height: calc(33 * var(--u));
  display:flex; align-items:center; justify-content:space-between;
  padding: 0 calc(12 * var(--u)) 0 calc(10 * var(--u));
  background: var(--orange); color: var(--white); text-decoration:none;
  border: 1px solid var(--orange);
  font-family: var(--font-body); font-weight:200; font-size: calc(14 * var(--u));
  letter-spacing:.05em; text-transform:uppercase;
  transition: background .18s ease, color .18s ease;
}
.product-cta:hover{ background: var(--white); color: var(--orange); }
.product-cta:hover img{ content: url("../images/logos/arrows/arrow-orange.svg"); }
.product-cta img{ width: calc(11 * var(--u)); height: calc(11 * var(--u)); }
.product-cta-inquire{ top: calc(1325 * var(--u) + var(--s)); border: 1px solid var(--orange); }
/* Eliza (14th pass): "hovering over INQUIRE TO PURCHASE, have it go
   inverted: white fill, orange outline, text and arrow" -- same
   inversion pattern as the spec-sheet button's hover, just reversed
   (that one starts outlined and fills orange on hover; this one starts
   filled and goes outlined on hover), so border is always present
   (transparent on the resting white-on-orange state would look off --
   actually resting state already has an orange border matching bg, so
   the outline doesn't shift the box size when it inverts). */
.product-cta-inquire:hover{ background: var(--white); color: var(--orange); }
.product-cta-inquire:hover img{ content: url("../images/logos/arrows/arrow-orange.svg"); }
/* Eliza: "make 'download spec sheet' orange outline, transparent fill,
   orange text" -- using an explicit white fill rather than truly
   transparent (same look here since the section behind it is white, but
   won't go invisible-then-wrong-contrast if this button ever sits on a
   non-white background elsewhere). */
.product-cta-spec{
  top: calc(1391 * var(--u) + var(--s));
  background: var(--white); color: var(--orange);
  border: 1px solid var(--orange);
}
.product-cta-spec:hover{ background: var(--orange); color: var(--white); }
.product-cta-spec:hover img{ content: url("../images/logos/arrows/arrow-white.svg"); }

.product-swatches{
  /* Eliza (2026-10-02): "image 3: layout got messed up" -- the real copy
     ("Available in the following wood species:") is longer than whatever
     Figma had at this column width (399u) and wraps to 2 lines, but this
     top offset was set assuming a single line, so the wrapped second line
     ("...SPECIES:") rendered UNDER the swatch row instead of above it.
     Pushed down by the wrapped line's own height (~30px at 1440) plus a
     touch of breathing room, so it clears the wrap at any viewport since
     both scale together via --u. */
  position:absolute; left: calc(1006 * var(--u)); top: calc(1485 * var(--u) + var(--s)); display:flex; gap: calc(27 * var(--u));
}
.product-swatch{ width: calc(73 * var(--u)); text-align:right; } /* Eliza: "walnut, cherry, price adjusted etc should be right aligned" */
.product-swatch-chip{ display:block; width:100%; aspect-ratio:1; }
/* Eliza sent real macro photos of the three wood species (Drive:
   Product Pages > 08. Wood Options) -- replaced the CSS-gradient
   stand-ins with the actual swatch photography. */
.product-swatch-beech .product-swatch-chip{
  background: url("../images/product/swatch-beech.webp") center/cover;
}
.product-swatch-cherry .product-swatch-chip{
  background: url("../images/product/swatch-cherry.webp") center/cover;
}
.product-swatch-walnut .product-swatch-chip{
  background: url("../images/product/swatch-walnut.webp") center/cover;
}
.product-swatch p{
  margin: calc(8 * var(--u)) 0 0; font-family: var(--font-body); font-weight:200;
  font-size: calc(13 * var(--u)); line-height:1.4; letter-spacing:.05em;
  text-transform:uppercase; color: var(--ink);
}
/* Eliza: "the text on SKUs is different from figma" -- Black Walnut's
   price-adjustment fine print (Price / Adjusted / Accordingly) runs
   smaller than the swatch name + price line, matching Figma. */
.product-swatch-fine{ display:block; font-size: calc(10 * var(--u)); line-height: 1.4; } /* 14u between the fine-print lines, not the 18u strut of the 13u label above */

/* ============================================================
   CATALOGUE (244:489 desktop / 342:587 mobile)
   Reuses the shared .page-rule bracket (unlike Product, which built its
   own literal copy) -- see the standing rule on .page-rule above for why
   that's the version to copy from. Section is normal document flow, not
   the absolute-positioned-to-Figma-coordinates approach About/Custom/
   Product use: the product grid was reorganized into three clean columns
   at Eliza's request (for the scroll-parallax effect below), which
   doesn't map onto Figma's own scattered per-item coordinates anyway, so
   there's nothing gained by fighting flow layout to hit exact positions
   here. Bottom carousel keeps the default orange background/white
   caption (no white-carousel override like Showroom/FAQ/Custom)
   -- Figma's own captions for this row sit below where the page's white
   background ends, on orange, matching the shared component's default.
   ------------------------------------------------------------ */
.catalogue-section{ position:relative; height: calc(2086 * var(--u)); max-width: calc(1440 * var(--u)); margin: 0 auto; }

.catalogue-intro{
  position:absolute; left: calc(529 * var(--u)); top: calc(274 * var(--u));
  width: calc(399 * var(--u));
}
.catalogue-intro p{
  margin:0; font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
  text-align:justify;
}
.catalogue-intro p + p{ margin-top: 1.7em; }

.catalogue-download{
  /* z-index:3, above .catalogue-grid's 2 -- found while testing tonight's
     other changes: the grid (position:absolute, same stacking level by
     default as this button) silently sat ON TOP of this button wherever
     their boxes overlapped, intercepting every click. Pre-existing bug,
     not caused by anything in this pass -- the button LOOKED clickable
     but never was. */
  position:absolute; z-index:3; left: calc(1076 * var(--u)); top: calc(394 * var(--u));
  display:flex; align-items:center; justify-content:space-between; gap: calc(12 * var(--u));
  width: calc(324 * var(--u)); min-height: calc(33 * var(--u));
  padding: 0 calc(12 * var(--u)) 0 calc(10 * var(--u));
  background: var(--orange); color: var(--white); text-decoration:none;
  font-family: var(--font-body); font-weight:200; font-size: calc(14 * var(--u));
  letter-spacing:.05em; text-transform:uppercase;
  transition: background .18s ease;
}
/* Eliza (15th pass): "button should invert on hover" -- same full
   inversion as .product-cta-inquire (white fill, orange outline, text
   + arrow swap to the orange asset), not the lighter-tint treatment
   this had before. border is set in the resting state too (orange on
   orange, invisible until hover) so box-sizing:border-box keeps the
   size identical on both states -- no 1px jump. */
.catalogue-download{ border: 1px solid var(--orange); }
.catalogue-download:hover{ background: var(--white); color: var(--orange); }
.catalogue-download:hover img{ content: url("../images/logos/arrows/arrow-orange.svg"); }
.catalogue-download img{ width: calc(11 * var(--u)); height: calc(11 * var(--u)); flex:none; }

/* Soft floating orange seal between the download button and the image
   grid (244:562, imgStudioMarkFfa000Soft1) -- that exact Figma asset
   export is blocked from this environment (403), so this reuses the
   same stamp-orange.svg + faded-opacity treatment already established
   for .product-stamp-soft rather than a bespoke doodle graphic. Flag to
   Eliza if she wants the real hand-drawn seal swapped in later. */
.catalogue-stamp{
  position:absolute; left: calc(847 * var(--u)); top: calc(446 * var(--u));
  width: calc(126 * var(--u)); margin:0; opacity:.55; pointer-events:none; z-index:5;
}
.catalogue-stamp img{ width:100%; height:auto; display:block; }

/* Three columns at their real Figma boxes -- column A bleeds to the left
   page edge and column C bleeds to the right page edge, per Eliza's
   feedback that these should touch the sides like Figma rather than sit
   inset inside the page's usual --edge margin. Each column keeps its own
   Figma top offset (the stagger) under the scroll-linked parallax in
   js/main.js -- .catalogue-item-media wraps the two photos so mobile can
   add a second, smaller photo beside the hero one without disturbing
   this desktop absolute layout (mobile hides it, see below). */
.catalogue-grid{ position:absolute; left:0; top:0; width:100%; height: calc(1723 * var(--u)); z-index:2; }
.catalogue-col{ position:absolute; display:flex; flex-direction:column; gap: calc(24 * var(--u)); } /* Eliza: "columns look weirdly spaced" -- widened from 8u to match Figma's real item-to-item gap */
.catalogue-col:nth-child(1){ left:0;                     top: calc(471 * var(--u)); width: calc(455 * var(--u)); }
.catalogue-col:nth-child(2){ left: calc(502 * var(--u)); top: calc(582 * var(--u)); width: calc(436 * var(--u)); }
.catalogue-col:nth-child(3){ right:0;                    top: calc(515 * var(--u)); width: calc(457 * var(--u)); }

.catalogue-item{ display:block; text-decoration:none; color: var(--ink); }
.catalogue-item-media{ display:block; }
.catalogue-photo{
  margin:0; background: var(--cream); overflow:hidden;
}
.catalogue-photo img{ width:100%; height:100%; object-fit:cover; display:block; }
.catalogue-photo-sm{ display:none; } /* mobile-only second photo, see below */
/* Eliza 2026-09-28: "product names in left col should be flush with 16px
   horizontal margin, not flush like the pics" -- the photos deliberately
   bleed to the page edge (see .catalogue-col above), but the caption text
   underneath should sit at the standard --edge inset like body copy
   elsewhere on the site, not flush with the photo's own edge.
   Eliza (2026-10-02): that --edge inset only actually applies to column 1,
   which is the one that bleeds to the page's own left edge -- columns 2
   and 3 are already inset by their own left/right position (see
   .catalogue-col above) and were getting double-indented. Scoped below. */
.catalogue-item h2{
  margin: calc(16 * var(--u)) 0 0;
  font-family: var(--font-body); font-weight:200;
  font-size: calc(20 * var(--u)); letter-spacing:.05em; text-transform:uppercase;
  color: var(--ink); transition: color .18s ease;
}
.catalogue-col:nth-child(1) .catalogue-item h2{ padding: 0 var(--edge); }
.catalogue-item:hover h2{ color: var(--orange); }
.catalogue-item:hover .catalogue-arrow{ content: url("../images/logos/arrows/arrow-orange.svg"); } /* Eliza (14th pass): "arrows should also turn orange on hover, not just the product name" */
.catalogue-arrow{
  width: calc(13 * var(--u)); height: calc(13 * var(--u)); margin-left: calc(8 * var(--u));
  display:inline-block; vertical-align:middle;
}

.catalogue-more{
  position:absolute; left: calc(529 * var(--u)); top: calc(1817 * var(--u)); width: calc(399 * var(--u));
}
.catalogue-more p{
  margin:0; font-family: var(--font-body); font-weight:200; font-size: var(--fs-body);
  line-height:1.7; letter-spacing:.05em; text-transform:uppercase; color: var(--ink);
  text-align:justify;
}
.catalogue-more p + p{ margin-top: 1.7em; }

.catalogue-collaborate{
  position:absolute; left: calc(528 * var(--u)); top: calc(1989 * var(--u));
  display:flex; align-items:center; justify-content:space-between; gap: calc(12 * var(--u));
  width: calc(402 * var(--u)); min-height: calc(33 * var(--u));
  padding: 0 calc(12 * var(--u)) 0 calc(10 * var(--u));
  background: var(--orange); color: var(--white); text-decoration:none;
  border: 1px solid var(--orange);
  font-family: var(--font-body); font-weight:200; font-size: calc(14 * var(--u));
  letter-spacing:.05em; text-transform:uppercase;
  transition: background .18s ease, color .18s ease;
}
.catalogue-collaborate:hover{ background: var(--white); color: var(--orange); }
.catalogue-collaborate:hover img{ content: url("../images/logos/arrows/arrow-orange.svg"); }
.catalogue-collaborate img{ width: calc(11 * var(--u)); height: calc(11 * var(--u)); flex:none; }


/* Every carousel-background override above turns the tile background white --
   but .tile figcaption is hardcoded white text (correct on the orange
   carousels elsewhere), so on these four it went invisible while still
   reserving its own height: a blank white band between the images and
   whatever follows (reported live on Custom, but the same shared rule hit
   Showroom/FAQ/Product too). First fix just hid the captions outright --
   Eliza (product page, 2026-09-28): "names are missing below bottom
   carousel," with a Figma reference showing them present in --ink, so
   recolor instead of hiding. Mobile keeps its own no-per-tile-captions
   rule below (Figma's mobile frames genuinely omit them). */


/* ============================================================
   MOBILE — built from Figma's 402-wide frames:
     160:104   HOMEPAGE - Mobile            (base)
     278:1285  HOMEPAGE - Mobile - Scroll
     278:1232  HOMEPAGE - Mobile - Nav Bar Collapse
     242:177   HOMEPAGE - Mobile - Hamburger

   Same approach as desktop, one scale down: 1mu = one Figma pixel at the
   402 reference, so every number below still reads as itself.

   Breakpoint is 1152, not 900. That closes the dead zone the architecture
   doc flagged: --u stops shrinking at ~1152 (its 0.8 floor) while mobile
   used to wait until 900, so between the two the desktop composition had
   stopped scaling but the window kept narrowing.

   NOT here, because Figma's mobile frames don't have them: the multiply
   effect (Eliza: "there's no multiply effect on STUDIO FRITZ"), the hero
   nav links, the hero download button, the scroll cue, the per-tile
   captions, and the feature-image arrow.
   ============================================================ */
@media (max-width: 1152px){
  :root{
    /* 100/402 = .2488vw. Floor holds the small phones (320 -> .8);
       ceiling caps it around 500 so the phone composition doesn't inflate
       across the tablet range -- see the note at the end of this block. */
    --mu: clamp(0.78px, 0.2488vw, 1.25px);
    --edge: 16px;   /* fixed 16px side margin at every mobile width (was scaling to 20px on wider phones/tablets) */
    --section-gap: calc(32 * var(--mu));
  }

  /* ---------- header: fixed bar, no multiply ----------
     Identical in all three scroll frames (wordmark y=4, mark 36 at x=183,
     hamburger lines at y=52/57/62), so the bar never changes size -- the
     only thing that happens on scroll is the orange ramping in, on the
     same --hdr-bg-a driver desktop uses. FRITZ and the logomark
     cross-fade with it for free. */
  .wm-row-2, .wm-row-3{ display:none; }
  .wordmark-header{
    height: calc(81 * var(--mu));
    /* 278:1232's carousel band moved 68 -> 81 and the hamburger lines 52/57/62
       -> 56/61/66, which is Eliza's "nav bar is a bit too narrow vertically
       and needs more padding under the hamburger": 15 of air under the icon
       instead of 2. (Line 16 still sits at 68 in the file, but the bar reads
       to where content actually starts.) */
    padding: calc(4 * var(--mu)) var(--edge) 0;
    align-items:flex-start;
    /* was align-items:center, which put the 40mu line box at 14..54 -- the
       hamburger starts at 52, so the icon sat under FRITZ with 2mu between
       them ("too close to Fritz"). Figma top-aligns the wordmark at y=4;
       doing the same drops the glyphs to 4..44 and opens the gap without
       moving anything else. */
  }
  .wordmark-header.is-collapsed{ padding-bottom:0; }  /* nothing docks in here */
  .wm-col span{ font-size: calc(40 * var(--mu)); }    /* 342:75 STUDIO 144 wide / 342:76 FRITZ 142 -> 40 both ways */
  /* Reversed along with desktop: centered on the wordmark line instead of
     top-aligned, matching the footer's treatment. Figma's raw mark-box
     coordinates don't survive porting (same problem as desktop -- see the
     comment on the base .wm-mark rule), so this is measured empirically:
     21.65mu is the vertical centre of the rendered STUDIO/FRITZ glyphs
     (cap-top to baseline) at this breakpoint's font-size, confirmed by
     pixel-sampling a screenshot. */
  .wm-mark{ top: calc(21.65 * var(--mu)); width: calc(36 * var(--mu)); transform: translate(-50%,-50%); }

  .nav-toggle{
    display:flex; flex-direction:column; justify-content:space-between;
    position:absolute; right: var(--edge); top: calc(56 * var(--mu));
    width: calc(19 * var(--mu)); height: calc(11 * var(--mu));
    padding:0; border:0; background:none; cursor:pointer; color: var(--white);
  }
  .nav-toggle span{ display:block; width:100%; height:1px; background: currentColor; transition: transform .2s ease, opacity .2s ease; }
  /* the visible lines are 19x11; this grows the tap target to ~44 without
     moving them */
  .nav-toggle::after{ content:''; position:absolute; inset: calc(-16 * var(--mu)) calc(-12 * var(--mu)); }
  .nav-toggle.is-open span:nth-child(1){ transform: translateY(calc(5 * var(--mu))) rotate(45deg); }
  .nav-toggle.is-open span:nth-child(2){ opacity:0; }
  .nav-toggle.is-open span:nth-child(3){ transform: translateY(calc(-5 * var(--mu))) rotate(-45deg); }

  /* ---------- hero ----------
     Figma 160:104: photo 0..468, intro paragraph over it at y=314, second
     paragraph at y=483 -- BELOW the seam, on orange. Rather than duplicate
     the copy, .hero-content keeps both paragraphs and overflows the hero;
     the hero's bottom margin is the room it overflows into. */
  .hero{
    min-height:0; height: calc(468 * var(--mu));
    overflow:visible;
    margin-bottom: calc(180 * var(--mu));
    /* Figma's 147 assumed 205:69 was 74 tall -- that hand-resized box
       again. At 4 lines x 27.2 the paragraph actually runs to 591, so the
       real gap to the carousel was 24mu, not the 58 I thought I was
       setting. 180 puts ~56 of air under it. */
  }
  .hero::after{ background: linear-gradient(0deg, rgba(20,10,25,.75) 0%, rgba(20,10,25,.05) 55%, transparent 78%); }
  .hero-content{
    position:absolute; z-index:2;
    top: 0; bottom: 0;                      /* spans the hero so paragraph 2 can key off the seam */
    left: calc(17 * var(--mu));
    right: calc(74 * var(--mu));            /* 205:68 is 311 wide, stopping short of the stamp at x=348 */
    padding:0;
  }
  /* GLOBAL RULE: paragraph 1 ends just above the hero/orange seam and
     paragraph 2 always starts below it, whatever the viewport width or
     line-wrap -- row 1 is exactly the hero's height (p1 bottom-aligned in
     it), row 2 overflows onto the orange. */
  .hero-intro{ height:100%; grid-template-columns:1fr; grid-template-rows: 100% auto; row-gap: calc(15 * var(--mu)); max-width:none; }
  .hero-intro p{ font-size: calc(16 * var(--mu)); line-height:1.7; }
  .hero-intro p:first-child{ align-self:end; padding-bottom: calc(17 * var(--mu)); }
  /* 205:68 is 137 tall across 5 lines = 27.4/line, and 16 x 1.7 = 27.2.
     (205:69's own box reports 74, which can't be right for its 4 lines at
     the same size -- a hand-resized text box. The 5-line one is the
     trustworthy measurement, and it agrees with desktop.) */
  .hero-links, .hero-catalogue-link, .scroll-cue, .feature-arrow{ display:none; }

  /* Stays FIXED, exactly like desktop -- it persists over the page as you
     scroll rather than scrolling away with the hero. (I'd read 244:483's
     two positions across the base and scroll frames as the stamp moving
     with the page; it was the page moving under a pinned stamp. Figma's
     375 on a 621 viewport is 60.4%, which is desktop's 60.7% to within
     rounding -- the frames agreed with desktop all along.) Only the side
     differs: right edge on mobile, left on desktop. */
  .stamp{ left: calc(348 * var(--mu)); width: calc(44 * var(--mu)); }
  /* the fixed stamp outranks the menu panel in z, and Eliza is cutting
     stamps from that screen, not adding one */
  body.menu-open .stamp{ display:none; }

  /* ---------- carousels ---------- */
  .tile-media{ height: calc(119 * var(--mu)); min-height:0; max-height:none; }   /* 242:81 etc: 119 band */
  .scroll-hijack .tile-media{ height: calc(103 * var(--mu)); }                    /* 242:94 etc: 103 band */
  /* no visible per-tile captions in the mobile frames -- but still read by screen readers (display:none removed the only text some links had) */
  .carousel .tile figcaption{ position:absolute; width:1px; height:1px; margin:-1px; padding:0; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }

  body.page-product .catalogue-band{ display:flex; }
  .catalogue-band{
    /* 278:1232, tightened: band ends 200, CATALOGUE at 208, cove at 248 */
    padding: calc(8 * var(--mu)) var(--edge) calc(5 * var(--mu));
    font-size: calc(16 * var(--mu)); gap: calc(8 * var(--mu));
    /* Figma has these at 21 (278:1320 is 115 wide, same as the footer's
       CATALOGUE), but on a 402 frame that makes them the largest type on
       the page after the wordmark, sitting on an otherwise empty band --
       they read as headlines while doing a nav link's job. Dropped to the
       hero body size. Desktop keeps its 25: there the link sits alone on a
       1440 canvas with air around it and 16 would disappear. */
  }
  .catalogue-band img{ width: calc(11 * var(--mu)); height: calc(11 * var(--mu)); }
  /* 404:798 / 404:831: ABOUT sits flush between the band and the footer
     wordmark (band ends 1152, text 1153, footer 1188). */
  /* 278:1232: ABOUT starts level with the band's own bottom edge, and the
     footer wordmark follows 12 later */
  .band-about{ display:flex; padding: calc(8 * var(--mu)) var(--edge) calc(12 * var(--mu)); }

  /* ---------- footer ----------
     Mobile SPLITS the wordmark: STUDIO opens the footer (y=1188) and FRITZ
     closes it (y=1823) with everything in between. .footer-wm goes
     display:contents so its three children become flex items of
     .footer-top and can be re-ordered, instead of the markup being
     duplicated or forked. */
  .site-footer{ padding: 0 var(--edge) calc(46 * var(--mu)); }  /* label ends 2242, frame 2288 */
  .footer-top{ display:flex; flex-direction:column; gap:0; padding-bottom:0; }
  .footer-wm{ display:contents; }
  .footer-wm span{
    font-size: calc(102 * var(--mu)); line-height:1.3;   /* 102 not Figma's 106: STUDIO at 106 is 380 wide, which bleeds past the 16px side margins (370 available) */
    /* 404:787 STUDIO is 380 wide and 404:788 FRITZ is 375, against desktop's
       358/354 at a 100 face -- both give 106 independently. 1.3 line-height
       reproduces Figma's own 138-tall box, so the gaps below are Figma's
       numbers unmodified. */
  }
  .footer-wm > a:first-of-type{ order:1; }
  .footer-links{ order:2; margin-top: calc(10 * var(--mu)); }
  .footer-wm > a:last-of-type{ order:3; margin-top: calc(19 * var(--mu)); }
  .footer-wm-mark{
    order:4; position:static; transform:none;
    width: calc(83 * var(--mu)); margin: calc(8 * var(--mu)) auto 0;   /* 404:776, centred at x=160+41.5 = 201.5 = 402/2 */
  }
  .footer-bottom{ order:5; margin-top: calc(44 * var(--mu)); }  /* mark ends 2052, legal at 2096 */
  .footer-copyright{ font-size: calc(14 * var(--mu)); text-align:left; }
  /* 160:104: legal ends 2142, rule 2158..2208, label at 2219 */
  .back-to-top{
    gap: calc(11 * var(--mu)); margin-top: calc(16 * var(--mu));
    font-size: calc(14 * var(--mu));
  }
  .btt-line{ height: calc(50 * var(--mu)); }

  .footer-links{
    position:static; min-height:0;
    display:grid; grid-template-columns: auto auto;
    row-gap: calc(29 * var(--mu)); column-gap:0;
  }
  /* position:static here was !important, which silently beat the overlay's
     own absolute positioning further down -- .mm-col-a and friends share
     these classes, and !important wins over source order no matter what.
     That is what collapsed the hamburger into a stack with everything
     running off the right edge. Source order alone does the job. */
  .footer-col{ position:static; gap: calc(2 * var(--mu)); }
  .footer-col:nth-child(1){ grid-column:1; justify-self:start; align-items:flex-start; text-align:left; }
  .footer-col:nth-child(2){ grid-column:2; justify-self:end; align-items:flex-end; text-align:right; right:auto; }
  .footer-col.footer-col-wide{
    grid-column:1 / -1; left:auto; max-width:none;
    align-items:flex-end; text-align:right; gap: calc(15 * var(--mu));
  }
  .footer-col a{ font-size: calc(21 * var(--mu)); line-height:1.667; }
  /* 404:781 CUSTOM 89 wide vs desktop's 67 at 16px -> 21.3, and the other
     five links agree to within .3 of that. */
  .footer-col.footer-col-wide a{ font-size: calc(14 * var(--mu)); line-height:1.5; color: var(--white); }
  /* 404:777 FAQ is 189 vs desktop's 221 at 16 -> 13.7, and its three
     siblings all land on 13.7 too. Cream rather than white: in the mobile
     frames this column reads visibly softer than CUSTOM/CATALOGUE beside
     it, which are solid white. JUDGMENT CALL -- say if it should be white. */

  .newsletter{
    grid-column:1 / -1; position:static; width:auto; left:auto; top:auto;
    margin-top: calc(28 * var(--mu)); gap: calc(8 * var(--mu));
  }
  .newsletter label{ font-size: calc(15 * var(--mu)); }
  .newsletter input{
    height: calc(50 * var(--mu));                                  /* 411:1089 Rectangle 7: 370x50 */
    font-size: calc(15 * var(--mu));
    padding: 0 calc(45 * var(--mu)) 0 calc(16 * var(--mu));         /* 411:1100 sits at x=32 in a box at x=16 */
  }
  .newsletter button{ right: calc(6 * var(--mu)); padding: calc(13 * var(--mu)); }   /* 17px arrow, 43px hit area */
  .newsletter .accent{
    min-height: calc(33 * var(--mu));                               /* 411:1090 Rectangle 8: 370x33 */
    margin-top: calc(24 * var(--mu));                               /* input ends 1747 -> button 1771 */
    font-size: calc(15 * var(--mu)); padding: 0 calc(14 * var(--mu));
  }
  /* One size for the email field and the button under it, in every context
     (footer, hamburger menu). Specificity matches the desktop footer rule. */
  .newsletter input, .site-footer .newsletter input, .mobile-menu .newsletter input,
  .newsletter .accent, .site-footer .newsletter .accent, .mobile-menu .newsletter .accent{ font-size: calc(15 * var(--mu)); }
  .newsletter button img,
  .newsletter .accent img{ width: calc(10.5 * var(--mu)); height: calc(10.5 * var(--mu)); }  /* Group 30/31: 10.48x10 */

  /* ---------- hamburger overlay (242:177, rearranged 2026-09-18) ----------
     The columns are no longer side by side: CUSTOM/CATALOGUE/SHOWROOM sit
     top left, TRADE/ABOUT/CONTACT drop lower on the right, and the stamp
     grew to 130x226 and moved to the left where it overlaps the right
     column's band. Nothing about that reads as a flow layout, so the panel
     is one positioned canvas at Figma's own 752 height with each piece at
     its measured coordinate -- trying to express it as stacked rows would
     be fighting the design rather than reproducing it. The canvas scrolls
     if the viewport is shorter than it. */
  .mobile-menu{
    display:block;
    position:fixed; inset:0; z-index:45;      /* under the header's 50, so the wordmark stays put */
    background: var(--orange);
    overflow-y:auto; -webkit-overflow-scrolling:touch;
  }
  .mobile-menu[hidden]{ display:none; }
  .mm-inner{ position:relative; height: calc(752 * var(--mu)); }
  body.menu-open{ overflow:hidden; }
  /* With the panel open the bar sits on orange whatever the scroll position
     says, so force the collapsed colouring -- otherwise at the top of the
     page FRITZ and the logomark are still orange, on orange. */
  body.menu-open .wordmark-header{ --hdr-bg-a: 1 !important; }
  body.menu-open .wm-right span{ color: var(--white); }
  /* Eliza 2026-10-03: the open menu is ALL orange -- header bar included, on
     every page (the static-header pages have a flat white bar that the
     --hdr-bg-a override above never touched). White wordmark/mark/X per Figma. */
  body.menu-open .wordmark-header, body.menu-open .wordmark-header.is-static{ background: var(--orange) !important; }
  body.menu-open .wordmark-header .wm-left span{ color: var(--cream) !important; }
  body.menu-open .wordmark-header .wm-right span{ color: var(--white) !important; }
  /* More air above the lockup in the open menu: Figma 242:177 puts the logomark
     at y=12 (36x36), i.e. 8 lower than the closed bar's 4. The whole lockup
     moves together so STUDIO / mark / FRITZ stay aligned. */
  .wordmark-header, .wordmark-header.is-static{ transition: padding-top .2s ease; }
  .wm-mark{ transition: top .2s ease; }
  body.menu-open .wordmark-header .wm-mark{ top: calc(29.65 * var(--mu)); }   /* moves with the lockup: stays centred on STUDIO / FRITZ */
  /* Figma 242:182/225: the close X is 29x29, right edge at 384, top 76 -- much
     bigger than the 19x11 hamburger and lower. */
  body.menu-open .nav-toggle{ width: calc(29 * var(--mu)); height: calc(29 * var(--mu)); top: calc(76 * var(--mu)); right: calc(18 * var(--mu)); }
  body.menu-open .nav-toggle span{ position:absolute; left: calc(-6 * var(--mu)); width: calc(41 * var(--mu)); top:50%; margin-top: -.5px; }
  body.menu-open .nav-toggle.is-open span:nth-child(1){ transform: rotate(45deg); }
  body.menu-open .nav-toggle.is-open span:nth-child(3){ transform: rotate(-45deg); }
  .nav-toggle{ -webkit-tap-highlight-color: transparent; }
  body.menu-open .wordmark-header, body.menu-open .wordmark-header.is-static{ padding-top: calc(12 * var(--mu)) !important; }
  body.menu-open .wordmark-header .wm-mark-orange{ opacity:0 !important; }
  body.menu-open .wordmark-header .wm-mark-white{ opacity:1 !important; }
  body.menu-open .wordmark-header .nav-toggle{ color: var(--white) !important; outline:none; box-shadow:none; }
  .mobile-menu .mm-newsletter label{ color: var(--white); }
  .mobile-menu .mm-newsletter .accent{ background: var(--white); color: var(--orange); border-color: var(--white); }
  .mobile-menu .mm-newsletter .accent img{ content: url("../images/logos/arrows/arrow-orange.svg"); }

  /* Every rule below is scoped under .mobile-menu on purpose.

     The overlay used to borrow .footer-col / .footer-col-wide / .accent so
     it could reuse their styling, and that kept losing silently: the footer
     rules are written as .footer-col:nth-child(2) and .footer-col.footer-col-wide
     and .newsletter .accent, all of which outrank a bare .mm-* class. So
     .footer-col:nth-child(1){left:0} pinned the left column to the edge,
     :nth-child(2){right:auto} pushed the right column off the screen, and
     .newsletter .accent kept the download button white-filled -- which is
     why its white arrow was invisible, not missing.

     Sharing classes across two layouts that disagree is the whole problem,
     so the columns have their own class now and everything here is scoped
     deep enough to win outright. */
  .mm-links{ display:contents; }
  .mobile-menu .mm-col{ display:flex; flex-direction:column; }
  .mobile-menu .mm-col a{
    text-decoration:none; font-family: var(--font-body); font-weight:200;
    letter-spacing:.05em; text-transform:uppercase; color: var(--white);
    white-space:nowrap; font-size: calc(21 * var(--mu)); line-height:1.667;
  }
  .mobile-menu .mm-col a:hover{ color: var(--orange-light); }

  .mobile-menu .mm-col-a{
    position:absolute; left: calc(17 * var(--mu)); top: calc(146 * var(--mu));
    gap: calc(2 * var(--mu));
  }
  .mobile-menu .mm-col-b{
    position:absolute; right: var(--edge); top: calc(244 * var(--mu));
    gap: calc(2 * var(--mu)); align-items:flex-end; text-align:right;
  }
  .mobile-menu .mm-stamp{
    position:absolute; left: calc(18 * var(--mu)); top: calc(281 * var(--mu));
    width: calc(130 * var(--mu));            /* 244:485 */
  }
  .mobile-menu .mm-stamp img{ width:100%; height:auto; display:block; }
  .mobile-menu .mm-secondary{
    position:absolute; right: var(--edge); top: calc(387 * var(--mu));
    gap: calc(15 * var(--mu)); align-items:flex-end; text-align:right;
  }
  .mobile-menu .mm-secondary a{ font-size: calc(14 * var(--mu)); line-height:1.5; color: var(--white); }
  .mobile-menu .mm-newsletter{
    position:absolute; left: var(--edge); top: calc(543 * var(--mu));
    right: var(--edge); width:auto; margin-top:0;   /* spans the full width between the 16px margins at any device width */
  }
  /* The download button is the SAME outline box as the footer's --
     inherits .newsletter .accent, white arrow included. */

  /* ---------- About page (Figma 338:3) ----------
     Everything the desktop composition overlaps, mobile stacks: one text
     column instead of two, full-bleed photos, labels right-aligned above
     their block. So this is flow, not coordinates — the only positioned
     things are the stamp and its caption, which genuinely sit side by side.

     The header goes back into flow here: the desktop page pulls it out so
     Figma's page-absolute y-coordinates line up, and mobile has none of
     those. */
  /* Same bar as the homepage's on mobile: flex row, logomark centred. */
  .wordmark-header.is-static{
    position:fixed; padding: calc(4 * var(--mu)) var(--edge) 0;
    height: calc(81 * var(--mu)); display:flex; align-items:flex-start;
    justify-content:space-between;
    background: var(--white);
  }
  .wordmark-header.is-static .wm-row-1{ font-size: calc(40 * var(--mu)); }
  .wordmark-header.is-static .hero-links.is-static-nav{ display:none; }  /* hamburger instead */
  /* STUDIO stays --cream here too, matching Figma 338:21 and the desktop
     rule above -- Eliza (2026-10-02, correction): the earlier ink swap
     mistook a different bug (background not reaching full white/height)
     for a text-contrast problem. .nav-toggle's generic mobile rule is
     white, which would be invisible here until the bar fills in -- the
     explicit orange override below still handles that. */
  .wordmark-header.is-static .wm-left span{ color: var(--cream); }
  .wordmark-header.is-static .wm-right span{ color: var(--orange); }
  .wordmark-header.is-static .nav-toggle{ color: var(--orange); }
  /* Eliza 2026-10-02: flat white bar, no scroll-driven ramp -- see the
     desktop .wordmark-header.is-static comment for why. STUDIO/FRITZ/the
     hamburger keep their at-rest colours (set above) at every scroll
     position; no collapsed-state override needed. */
  .about-rule{ display:none; }                                           /* not in the mobile frame */

  body.page-about main{ padding-top: calc(81 * var(--mu)); }
  .about-block{ height:auto; }
  .about-maker, .about-studio{ height:auto; }
  /* Desktop absolutely positions everything, so the markup is in reading
     order, not visual order: the label is written before the photo. In flow
     that puts the label above it. Figma runs photo (68) then label (756), so
     flex the section and pull the photo up. Everything else keeps DOM order. */
  .about-maker{ display:flex; flex-direction:column; }
  .about-portrait{ order:-1; }

  /* 338:57 and 338:85 are both 25 tall, so pin the line box to 25 and the
     margins below are true gaps rather than top-to-top distances. */
  .about-label{
    position:static; display:block;
    text-align:right; padding: 0 var(--edge);
    font-size: calc(16 * var(--mu)); line-height: 1.5625;
  }
  .about-label-maker{  margin: calc(40 * var(--mu)) 0 calc(24 * var(--mu)); }  /* portrait ends 716; label 756-781; copy 805 */
  .about-label-studio{ margin: calc(55 * var(--mu)) 0 calc(46 * var(--mu)); }  /* stamp ends 2606; label 2661-2686; copy 2732 */

  /* Flex column with a gap rather than p + p margins, so the reorder below
     cannot collapse a gap: adjacency is DOM order, gap is visual order. */
  .about-col{
    position:static; width:auto; padding: 0 calc(15 * var(--mu));
    display:flex; flex-direction:column; gap:1.7em;
  }
  .about-col p + p{ margin-top:0; }
  .about-col p{ font-size: calc(16 * var(--mu)); }
  /* Desktop splits each section into two columns; mobile runs them as one.
     The second column follows the first with the same paragraph rhythm
     rather than a section break. */
  .about-col-b1, .about-col-b2{ margin-top: 1.7em; }
  /* 338:61 runs the maker copy as one block and puts the family-history line
     straight after "raised in a family of architects", ahead of "Lucas
     introduces". Same six paragraphs as desktop, reordered by order: only
     desktop holds the copy, so it cannot drift. */
  .about-col-b1 > p:nth-child(1){ order:2; }
  .about-col-b1 > p:nth-child(2){ order:1; }
  .about-col-b1 > p:nth-child(3){ order:3; }

  .about-fig{ position:static; width:auto; }
  /* 338:58 and 338:80 are full-bleed at 402 wide; 338:88 is 427 wide on a
     402 frame, i.e. deliberately overflowing to the right. */
  .about-portrait{ aspect-ratio: 402 / 648; }
  .about-hands{ aspect-ratio: 402 / 492; margin-top: calc(96 * var(--mu)); }
  /* 338:88 is drawn 427 wide on a 402 frame, i.e. hanging 25px off the right
     edge. Reproducing that literally is what pushed the page sideways. Full
     bleed at Figma's height crops the same 6% off the right and keeps the
     vertical rhythm exact. */
  .about-stools{
    width:auto; aspect-ratio:auto; height:auto;
    margin-top: calc(92 * var(--mu));
  }

  /* 342:721: a full-width rule under the hands photo, at y=2275 */
  .about-hands::after{
    content:''; position:absolute; left:0; right:0; bottom:0;
    height:1px; background: var(--orange);
  }
  /* relative, not static, so the rule above can anchor to it -- which means
     the desktop left/top would come back as an offset. Cancel them. */
  .about-hands{ position:relative; left:auto; top:auto; }
  .about-stools img{ height:auto; object-fit:contain; }

  /* The one piece that stays positioned: 338:83's mark at x=210 with
     338:82's caption at x=16, side by side rather than stacked. */
  .about-stamp-fig{
    position:relative; left:auto; top:auto;
    width: calc(185 * var(--mu)); margin: calc(8 * var(--mu)) 0 0 calc(210 * var(--mu));
  }
  .about-stamp-fig figcaption{
    left: calc(-194 * var(--mu)); top: calc(198 * var(--mu));
    width: calc(169 * var(--mu)); font-size: calc(14 * var(--mu));
  }

  .about-cta{
    position:static; width:auto; margin: calc(79 * var(--mu)) var(--edge) 0;
    min-height: calc(28 * var(--mu)); font-size: calc(14 * var(--mu));
    padding: 0 calc(13 * var(--mu)) 0 calc(9 * var(--mu));
  }
  .about-cta img{ width: calc(10 * var(--mu)); height: calc(10 * var(--mu)); }

  /* ---------- white supporting pages, mobile ----------
     370:115 / 370:284 drop the rule and the stamp and run the form as one
     column. Same +13 offset About carries: the bar is 81 here against
     Figma's 68, so everything below it sits 13 lower by design. */
  .page-section{ height:auto; padding-top: calc(81 * var(--mu)); }
  .page-rule, .page-stamp{ display:none; }

  .page-label{
    position:static; display:block; text-align:right; padding: 0 var(--edge);
    margin: calc(33 * var(--mu)) 0 0;          /* bar ends 68, label 101 */
    font-size: calc(16 * var(--mu)); line-height:1.5625;
  }
  .page-lede{
    position:static; width:auto; padding: 0 calc(15 * var(--mu));
    margin: calc(23 * var(--mu)) 0 0;          /* label ends 126, lede 149 */
    font-size: calc(16 * var(--mu));
  }

  .sf-form{
    position:static; display:block;
    padding: 0 var(--edge);
    margin: calc(40 * var(--mu)) 0 calc(46 * var(--mu));  /* submit ends 1092, carousel 1138 */
  }
  .sf-field{ margin-bottom: calc(29 * var(--mu)); }
  /* Stacked, the two columns become one run of fields, so the last field in
     column A must not drop its bottom margin against the first in column B
     (370:268 ends 633, 370:265 starts 662 -- the same 29 as every other). */
  .sf-col-b{ margin-top: calc(29 * var(--mu)); }
  .sf-field label{
    margin-bottom: calc(15 * var(--mu)); font-size: calc(16 * var(--mu));
  }
  .sf-field input, .sf-field textarea{
    height: calc(50 * var(--mu)); padding: 0 calc(13 * var(--mu));
    font-size: calc(16 * var(--mu));
  }
  .sf-field textarea{ height: calc(288 * var(--mu)); padding: calc(13 * var(--mu)); }
  /* Figma stacks the note above a full-width button, rather than setting
     them side by side as the desktop band does. */
  .sf-actions{
    display:block; margin-top: calc(69 * var(--mu));     /* textarea ends 990, submit 1059 */
  }
  .sf-note{ max-width:none; font-size: calc(14 * var(--mu)); margin-bottom: calc(16 * var(--mu)); }
  .sf-submit{
    width:100%; min-height: calc(33 * var(--mu));
    padding: 0 calc(13 * var(--mu)) 0 calc(9 * var(--mu));
    font-size: calc(14 * var(--mu));
  }
  .sf-submit img{ width: calc(10 * var(--mu)); height: calc(10 * var(--mu)); }
  .sf-unwired{ font-size: calc(14 * var(--mu)); }
  .sf-field-error{ margin-top: calc(6 * var(--mu)); font-size: calc(12 * var(--mu)); }
  .sf-field .sf-field-error{ margin-top: calc(4 * var(--mu)); }


  /* INQUIRE MODAL mobile: full-bleed panel, fields stacked like every
     other .sf-form on mobile (base .sf-form{display:block} rule already
     handles that -- this just neutralizes the desktop grid this modal
     adds above and rescales to --mu). */
  .inquire-modal{ padding:0; display:block; }   /* block, not flex: the white panel grows with the form instead of stopping at the screen height */
  .inquire-modal-panel{
    max-width:none; min-height:100%; border:0; box-sizing:border-box;
    padding: calc(72 * var(--mu)) var(--edge) calc(48 * var(--mu));   /* text sits exactly on the 16px margins */
  }
  .inquire-modal-stamp{ width: calc(64 * var(--mu)); margin-bottom: calc(24 * var(--mu)); }
  .inquire-modal-close{
    top: calc(28 * var(--mu)); right: var(--edge);
    width: calc(16 * var(--mu)); height: calc(16 * var(--mu));
  }
  .inquire-modal-lede{ max-width:none; font-size: calc(15 * var(--mu)); margin-bottom: calc(24 * var(--mu)); }
  .inquire-modal .sf-form{ display:block; padding-left:0; padding-right:0; }   /* panel already supplies the 16px edge; .sf-form's own 16px doubled it to 32 */
  .inquire-modal .sf-col-b{ margin-top: calc(29 * var(--mu)); display:block; }
  .inquire-modal .sf-field textarea{ height: calc(288 * var(--mu)); }
  .inquire-modal .sf-field label[for="inquire-designer"]{ white-space:normal; font-size: calc(16 * var(--mu)); line-height:1.6875; }

  .page-thanks-msg{
    position:static; width:auto; padding: 0 calc(16 * var(--mu));
    margin: calc(40 * var(--mu)) 0 0; font-size: calc(18 * var(--mu));
  }
  .page-thanks-back{
    position:static; width:auto; margin: calc(40 * var(--mu)) calc(16 * var(--mu)) calc(46 * var(--mu));
  }

  /* the band link matches the homepage's mobile one again */
  .page-about .band-about{ padding: calc(8 * var(--mu)) var(--edge) calc(12 * var(--mu)); font-size: calc(16 * var(--mu)); }
  .page-about .band-about img{ width: calc(11 * var(--mu)); height: calc(11 * var(--mu)); }
  /* ---------- Showroom, mobile (370:462) ----------
     No rule and no second (interior/DSC_1318) photo in this frame --
     Figma drops both on mobile the way it drops the rule on every white
     page here. Gaps below are true gaps between each element's Figma box
     and the next, same convention as the rest of this block. */
  /* Updated Figma (370:462, Oct 2026): address + VISIT, photo, then the
     orange logomark (left) and stamp (right, overlapping the photo's
     bottom edge by 53), studio location, BOOK AN APPOINTMENT, carousel.
     The blurb paragraph is gone from this frame. Flex column so every
     gap is a true gap between boxes (Figma: 74 / 74 / 75 / 54 / 76 / 89). */
  .showroom-section{ height:auto; padding-top: calc(81 * var(--mu)); display:flex; flex-direction:column; }
  body.page-showroom .page-rule{ display:none; }

  .showroom-col{
    position:static; width:auto; padding: 0 var(--edge);
    font-size: calc(16 * var(--mu));
  }
  .showroom-blurb{ display:none; }
  .showroom-partner{ margin-top: calc(74 * var(--mu)); }
  .showroom-location{ margin-top: calc(54 * var(--mu)); }
  .showroom-portrait{
    position:static; left:auto; top:auto;
    width: max(100%, calc(424 * var(--mu))); aspect-ratio: 424 / 283; margin: calc(75 * var(--mu)) 0 0;
  }
  .showroom-interior{ display:none; }
  /* orange logomark (397:199, 97x97) replaces the old cream corner rule */
  .showroom-accent{
    position:static; width: calc(97 * var(--mu)); height: calc(97 * var(--mu));
    margin: calc(212 * var(--mu)) 0 0 var(--edge);
    background: url("../images/logos/logomark/logomark-orange.svg") center/contain no-repeat;
  }
  .showroom-accent::before, .showroom-accent::after{ display:none; }
  .showroom-cta{
    position:static; width:auto; margin: calc(75 * var(--mu)) var(--edge) 0;
    min-height: calc(33 * var(--mu)); font-size: calc(14 * var(--mu));
    padding: 0 calc(13 * var(--mu)) 0 calc(9 * var(--mu));
  }
  .showroom-cta.showroom-visit{ margin-top: calc(74 * var(--mu)); }
  .showroom-cta:not(.showroom-visit){ margin-top: calc(76 * var(--mu)); }
  .showroom-cta img{ width: calc(10 * var(--mu)); height: calc(10 * var(--mu)); }
  /* 397:213 -- stamp right-aligned, top 53 above the photo's bottom edge;
     zero layout height so the logomark and it share the same band. */
  body.page-showroom .page-stamp{
    display:block; position:static; width: calc(185 * var(--mu)); height:0; z-index:2;
    margin: calc(-53 * var(--mu)) 0 0 calc(210 * var(--mu));
  }
  .showroom-partner{ order:1; } .showroom-visit{ order:2; } .showroom-portrait{ order:3; }
  body.page-showroom .page-stamp{ order:4; } .showroom-accent{ order:5; }
  .showroom-location{ order:6; } .showroom-cta:not(.showroom-visit){ order:7; }
  body.page-showroom .carousel{ margin-top: calc(89 * var(--mu)); }
  /* Figma: the white page runs down behind the carousel; orange resumes at the ABOUT band */
  body.page-showroom .scroll-hijack, body.page-showroom .scroll-hijack-sticky{ background: linear-gradient(var(--white) calc(100% - 32 * var(--mu)), var(--orange) 0); }
  /* ---------- FAQ, mobile (370:543) ----------
     Flow, one consistent gap between items -- see the drift note above. */
  .faq-section{ height:auto; padding-top: calc(81 * var(--mu)); }
  body.page-faq .page-rule{ display:none; }
  body.page-faq .page-label{ width:auto; }
  /* 411:978 -- unlike Contact/Trade, FAQ's mobile frame keeps the stamp,
     just relocated (right-aligned, no caption), same treatment as
     Showroom's mobile stamp. */
  body.page-faq .page-stamp{ display:none; }   /* removed on mobile (Eliza) */

  .faq-list{ padding: 0 var(--edge); margin: calc(40 * var(--mu)) 0 0; }
  .faq-item + .faq-item{ margin-top: calc(40 * var(--mu)); }
  .faq-q{
    position:static; width:auto; margin:0 0 calc(13 * var(--mu));
    font-size: calc(20 * var(--mu));
  }
  #warranty{ scroll-margin-top: calc(var(--hdr-h, 0px) + 24 * var(--mu)); }
  .faq-a{
    position:static; width:auto; margin:0;
    font-size: calc(16 * var(--mu));
  }
  .faq-still{
    position:static; margin: calc(40 * var(--mu)) var(--edge) 0;
    font-size: calc(16 * var(--mu));
  }
  .faq-cta{
    position:static; width:auto; margin: calc(20 * var(--mu)) var(--edge) 0;
    min-height: calc(33 * var(--mu)); font-size: calc(14 * var(--mu));
    padding: 0 calc(13 * var(--mu)) 0 calc(9 * var(--mu));
  }
  .faq-cta img{ width: calc(10 * var(--mu)); height: calc(10 * var(--mu)); }
  .faq-section{ padding-bottom: calc(30 * var(--mu)); }   /* the gap lives inside the white section, not as an orange margin above the carousel */
  body.page-faq .carousel{ margin-top:0; }
  /* ---------- Custom, mobile (404:689) ----------
     Real reading order, not a reflow of the desktop DOM -- see the note
     above the desktop block. Gaps around the two testimonial quotes are
     normalized to the spacing scale rather than Figma's exact numbers:
     quote text reflows differently in a live browser than in Figma's own
     layout, so a gap measured against Figma's text would drift out of
     sync with the real render; the margins around the fixed-size photos,
     the CTA and the short two-line attributions use Figma's real numbers
     since those don't reflow. */
  .custom-section{ height:auto; padding-top: calc(81 * var(--mu)); }
  body.page-custom .page-rule{ display:none; }
  body.page-custom .page-stamp, .custom-stamp-2{ display:none; }   /* not in this frame */

  .custom-intro{
    position:static; width:auto; padding:0 var(--edge);
    margin: calc(23 * var(--mu)) 0 0; font-size: calc(15 * var(--mu));
  }
  .custom-cta{
    position:static; width:auto; margin: calc(24 * var(--mu)) var(--edge) 0;
    min-height: calc(33 * var(--mu)); font-size: calc(14 * var(--mu));
    padding: 0 calc(13 * var(--mu)) 0 calc(9 * var(--mu));
  }
  .custom-cta img{ width: calc(10 * var(--mu)); height: calc(10 * var(--mu)); }

  .custom-photo{ position:relative; width:auto; aspect-ratio:auto; }
  .custom-photo img{ width:100%; height:auto; object-fit:contain; display:block; }   /* whole photo, full bleed, at any width */
  .custom-photo-hero{      position:relative; left:auto; top:auto; height:auto; margin:0; }   /* last in the page, flush with the carousel */
  .custom-photo-int6{      position:relative; left:auto; top:auto; height:auto; margin: calc(77 * var(--mu)) 0 0; }
  .custom-photo-img0274{   position:relative; left:auto; top:auto; height:auto; margin:0; }
  .custom-photo-westlake3{ position:relative; left:auto; top:auto; height:auto; margin: calc(88 * var(--mu)) 0 0; }
  .custom-photo-westlake2{ position:relative; left:auto; top:auto; height:auto; margin:0; }

  .custom-caption{
    left: calc(16 * var(--mu)); bottom: calc(16 * var(--mu));
    font-size: calc(16 * var(--mu));
  }

  .custom-feature-label{
    position:static; padding:0 var(--edge); margin: calc(112 * var(--mu)) 0 0;
    font-size: calc(16 * var(--mu));
  }
  /* Several of these carry inline left/top/width/font-size in desktop units
     (style="left:calc(955*var(--u))..."), which beat a plain class rule --
     that is what left the quotes ~2/3 width and the Interior Architects text
     small. !important so every column is edge to edge inside the 16px margins. */
  .custom-feature-copy, .custom-feature-quote, .custom-feature-attr{
    position:static !important; left:auto !important; top:auto !important;
    width:auto !important; padding:0 var(--edge); box-sizing:border-box;
  }
  .custom-feature-copy, .custom-feature-quote, .custom-feature-attr{ font-size: calc(15 * var(--mu)) !important; }
  .custom-feature-copy{ margin: calc(40 * var(--mu)) 0 0; }
  .custom-feature-quote{ margin: calc(77 * var(--mu)) 0 0; }   /* 411:1029 rule -> 411:1025 quote: 77 */
  .custom-feature-attr{ margin: calc(58 * var(--mu)) 0 0; min-height: calc(55 * var(--mu)); }   /* 411:1025 box end -> 411:1027 attr: 58 */
  .custom-feature-attr-last{ margin-bottom: calc(54 * var(--mu)); }  /* 411:1045 box end 4885 -> carousel 4939 */
  .custom-feature-divider{
    display:block; height:1px; background: var(--orange); border:0;
    margin: calc(32 * var(--mu)) 0 0;   /* bleeds edge to edge (Figma), not inset to the text margin */
  }

  body.page-custom .carousel{ margin-top: 0; }

  /* ---------- Product / Cove Table, mobile (342:858) ----------
     No accent bracket and no divider lines in Figma's mobile frame --
     both hidden. The gallery-nav ticks are desktop-only decoration too. */
  /* Figma 342:858: stamp (70x122) at x16,y68 and title right-aligned at
     y99 sit in the 160mu band under the header; the four photos then
     stack FULL-BLEED, object-fit:cover, with 1px orange lines at each
     seam (hero 484, 268, 268, 672). The desktop gallery is an absolute
     flex row with is-hero/max-width rules of higher specificity, so every
     one of those is reset here explicitly. */
  .product-section{ height:auto !important; padding-top:0; }
  .product-accent{ display:none; }
  .product-nav-arrows{ display:none; }
  .product-divider{ display:none; }

  .product-top{ position:relative; display:block; height: calc(160 * var(--mu)); padding:0; }
  .product-stamp-soft{
    position:absolute; z-index:2; left: calc(16 * var(--mu)); top: calc(68 * var(--mu));
    width: calc(70 * var(--mu)); margin:0;
  }
  .product-title{
    position:absolute; left:auto; right: calc(16 * var(--mu)); top: calc(99 * var(--mu)); margin:0;
    font-size: calc(20 * var(--mu)); text-align:right; white-space:nowrap;
  }

  .product-gallery{
    position:static; left:auto; right:auto; top:auto; height:auto !important;
    display:block; gap:0;
  }
  .product-photo,
  .product-hero.is-hero, .product-thumb-5.is-hero, .product-thumb-cove2.is-hero, .product-thumb-cove3.is-hero{
    position:relative; left:auto; top:auto; width:100%; aspect-ratio:auto; margin:0 !important;
    transition:none; overflow:hidden;
  }
  .product-gallery .product-photo:nth-child(n+5){ display:none; }   /* never more than 4 photos in a row before the product info */
  .product-photo img, .product-photo .gallery-img,
  .product-hero.is-hero .gallery-img, .product-thumb-cove3.is-hero .gallery-img,
  .product-thumb-5.is-hero .gallery-img, .product-thumb-cove2.is-hero .gallery-img{
    width:100%; height:auto; max-width:none !important; object-fit:contain; object-position:center;
    transition:none; /* whole photo always shows -- no fixed height, so widening never crops (Eliza 2026-10-04) */
  }
  .product-hero, .product-hero.is-hero, .product-thumb-cove2, .product-thumb-cove2.is-hero,
  .product-thumb-cove3, .product-thumb-cove3.is-hero, .product-thumb-5, .product-thumb-5.is-hero{ height:auto; }
  .product-photo img, .product-photo .gallery-img{ display:block; }

  .product-desc{
    position:static; left:auto; top:auto; width:auto; padding:0 var(--edge);
    margin: calc(40 * var(--mu)) 0 0; font-size: calc(15 * var(--mu));
  }

  .product-dims, .product-price, .product-config{
    position:static; left:auto; top:auto; width:auto; padding:0 var(--edge);
    font-size: calc(15 * var(--mu));
  }
  .product-price{ margin: calc(32 * var(--mu)) 0 0; }
  .product-dims{ margin: calc(32 * var(--mu)) 0 0; }
  .product-config{ margin: calc(32 * var(--mu)) 0 0; }

  .product-cta{
    position:static; left:auto; width:auto; margin: calc(20 * var(--mu)) var(--edge) 0;
    min-height: calc(33 * var(--mu)); font-size: calc(14 * var(--mu));
    padding: 0 calc(13 * var(--mu)) 0 calc(9 * var(--mu));
  }
  .product-cta img{ width: calc(10 * var(--mu)); height: calc(10 * var(--mu)); }
  .product-cta-inquire{ top:auto; }
  .product-cta-spec{ top:auto; margin-top: calc(12 * var(--mu)); }

  .product-swatches{ position:static; left:auto; top:auto; padding: 0 var(--edge); margin: calc(32 * var(--mu)) 0 0; gap: calc(18 * var(--mu)); }
  .product-swatch p{ font-size: calc(12 * var(--mu)); margin-top: calc(6 * var(--mu)); }

  /* Body copy, in Figma's (342:858) order and spacing: desc -> orange rule ->
     price -> the two buttons -> dimensions -> finish/configurations ->
     swatches (right-aligned). The HTML order differs (dimensions sit above the
     price), so the section is a flex column and \`order\` does the rearranging
     on mobile only. Gaps are Figma's top-to-top distances minus line boxes. */
  .product-section{ display:flex; flex-direction:column; padding-bottom: calc(100 * var(--mu)); }
  .product-top{ order:0; } .product-gallery{ order:1; }
  .product-desc{ order:2; } .product-divider-1{ order:3; } .product-price{ order:4; }
  .product-cta-inquire{ order:5; } .product-cta-spec{ order:6; }
  .product-dims{ order:7; } .product-config{ order:8; } .product-swatches{ order:9; }
  .product-desc, .product-dims, .product-price, .product-config{ font-size: calc(16 * var(--mu)); line-height: calc(27 * var(--mu)); }
  .product-desc{ margin: calc(114 * var(--mu)) 0 0; }
  .product-desc p, .product-dims p, .product-config p, .product-config ul{ margin:0; }
  .product-desc p + p{ margin-top: calc(27 * var(--mu)); }
  .product-divider-1{
    display:block; position:static; left:auto; top:auto; width:100%; height:0;
    border:0; border-top:1px solid var(--orange); margin: calc(112 * var(--mu)) 0 0;
  }
  .product-price{ margin: calc(67 * var(--mu)) 0 0; }
  .product-cta-inquire{ margin-top: calc(18 * var(--mu)); }
  .product-cta-spec{ margin-top: calc(29 * var(--mu)); }
  .product-dims{ margin: calc(100 * var(--mu)) 0 0; }
  .product-dims p + p, .product-config p + p{ margin-top: calc(24 * var(--mu)); }
  .product-config{ margin: calc(24 * var(--mu)) 0 0; }
  .product-config ul{ padding-left: calc(24 * var(--mu)); }
  .product-config li{ padding:0; }
  .product-swatches{
    justify-content:flex-end; align-items:flex-start; gap: calc(21 * var(--mu));
    margin: calc(36 * var(--mu)) 0 0; padding: 0 var(--edge);
  }
  .product-swatch{ width: calc(73 * var(--mu)); display:flex; flex-direction:column; align-items:flex-end; }   /* labels wider than the chip grow leftwards, so every right edge lines up at the 16px margin */
  .product-swatch p{ width:100%; }
  .product-swatch-chip{ width: calc(73 * var(--mu)); height: calc(73 * var(--mu)); aspect-ratio:auto; }
  .product-swatch p{ text-align:right; font-size: calc(15 * var(--mu)); line-height: calc(18 * var(--mu)); letter-spacing:.05em; }
  .product-swatch-fine{ font-size: calc(10 * var(--mu)); display:block; width:max-content; margin-left:auto; }
  body.page-product .carousel{ margin-top:0; }
  body.page-product .carousel{ background: transparent; }   /* no orange behind the tiles: a fractional-pixel top edge blended into it as a hairline above the strip */   /* the gap is the section's own white padding, never an orange strip */

  /* CATALOGUE mobile (342:587): a real two-column layout, not desktop
     turned into a single stack -- a wide "hero" photo (264mu) on the
     left, a smaller second photo (138mu) on the right, bottom-aligned
     with the hero (every item in this Figma frame has its hero and
     small photo share the exact same bottom edge -- confirmed against
     every one of the 7 items, not a guess). Caption + arrow run full
     width below both photos; a hairline separates each item. No
     parallax (desktop-only effect) and page-rule is dropped like every
     other mobile frame. */
  body.page-catalogue .page-rule{ display:none; }
  .catalogue-section{ height:auto; padding: calc(101 * var(--mu)) 0 calc(48 * var(--mu)); }
  .catalogue-intro, .catalogue-more, .catalogue-download, .catalogue-collaborate{
    position:static; left:auto; top:auto;
  }
  .catalogue-intro, .catalogue-more{ margin-left:0; padding: 0 var(--edge); max-width:none; width:auto; }
  .catalogue-intro{ margin-top: calc(24 * var(--mu)); font-size: calc(15 * var(--mu)); }
  .catalogue-intro p{ font-size: calc(15 * var(--mu)); }
  .catalogue-download, .catalogue-collaborate{
    width:auto; margin: calc(24 * var(--mu)) var(--edge) 0;
    min-height: calc(33 * var(--mu)); font-size: calc(14 * var(--mu));
    padding: 0 calc(13 * var(--mu)) 0 calc(9 * var(--mu));
  }
  .catalogue-download img, .catalogue-collaborate img{ width: calc(10 * var(--mu)); height: calc(10 * var(--mu)); }
  .catalogue-stamp{ display:none; }

  .catalogue-grid{ position:static; height:auto; display:flex; flex-direction:column; margin-top: calc(32 * var(--mu)); }
  .catalogue-col{ position:static; display:contents; } /* desktop-only grouping */
  .catalogue-item{ display:block; }
  /* No divider lines between items (they weren't in Figma). One uniform gap
     between every item: caption of one to the top of the next photo. */
  /* .catalogue-col is display:contents, but \`+\` still only sees siblings inside
     one column, so the first item of columns 2 and 3 got no gap at all (Portage
     Chair / Bluff Stool sat on the photo above). Every item gets it, except the
     very first. */
  .catalogue-item{ margin-top: calc(56 * var(--mu)); }
  .catalogue-col:first-child .catalogue-item:first-child{ margin-top:0; }
  .catalogue-item-media{
    display:grid; grid-template-columns: minmax(0,264fr) minmax(0,138fr);   /* fills the full width at any device width */
    align-items:end; column-gap:0;
  }
  .catalogue-photo-sm{ display:block; margin:0; background: var(--cream); overflow:hidden; }
  .catalogue-photo-sm img{ width:100%; height:auto; object-fit:contain; display:block; }
  .catalogue-item h2{ margin-top: calc(12 * var(--mu)); padding: 0 var(--edge); font-size: calc(15 * var(--mu)); }
  .catalogue-arrow{ width: calc(13 * var(--mu)); height: calc(13 * var(--mu)); margin-left: calc(8 * var(--mu)); }
  .catalogue-more{ margin-top: calc(40 * var(--mu)); font-size: calc(15 * var(--mu)); }
}


/* UNDESIGNED RANGE: roughly 520 to 1152. Figma only has 402-wide mobile
   frames and a 1440 desktop frame, so above ~520 this is the phone
   composition stretched, with --mu capped so the type doesn't inflate with
   it. It holds together, but it is an extrapolation, not a design -- a
   tablet frame in Figma is what would settle it. */


/* ============================================================
   SITE INTRO (index.html only) -- full-screen orange loader that
   plays once per tab session before the homepage, per Figma's
   "intro" / "intro - joins" / "intro - end state" frames.

   Eliza 2026-10-02: "get rid of the stamp entirely, change to just
   the modern F. I want it to draw in from the outer perimeters,
   joining together, and then the top 2 horizontal lines shortening
   into place, outside in." The stamp (.intro-stamp, the traced
   circular woodworker's mark) is removed outright -- see git history
   for the old 600+-path asset and its per-part draw sequence if it's
   ever needed again. Two phases now, both driven off one wrapper
   (.intro-f-wrap):

   Phase 1 -- "draws in from the outer perimeters, joining together"
   (.is-joining): the top bar, mid bar and vertical bar each start
   translated off past the actual edge of the viewport -- top bar
   from the right, mid bar from the left, vertical bar from the top,
   so they visibly converge from three different directions -- and
   slide into their assembled position together. The horizontal bars
   are already at an OVERSHOOT length at this point (wider than their
   true final length), so the shape that "joins" together reads as a
   slightly oversized cross, not the final compact F.

   Phase 2 -- "top 2 horizontal lines shortening into place, outside
   in" (.is-drawn): once joined, the two horizontal bars shrink from
   their overshoot length down to true length via scaleX, anchored
   (transform-origin) at their INNER end -- the end nearest the
   vertical bar -- so the visible motion is the OUTER tip retracting
   inward, i.e. "outside in." The vertical bar does not take part in
   this phase; it already landed at full/final height in phase 1.

   Plays once per tab (sessionStorage) since it's a first-visit
   flourish. Click/tap/Escape/Enter skips straight to the end.
   Reduced motion collapses it to a quick fade -- the durations below
   are wall-clock waits between class toggles in js/main.js (search
   "SITE INTRO"), kept separate from the CSS transition durations
   (which the site's global prefers-reduced-motion rule already
   zeroes), so a reduced-motion visitor doesn't sit through a silent
   version of the full timeline. ============================================================ */
.site-intro{
  position:fixed; inset:0; z-index:200; background: var(--orange);
  cursor:pointer; transition: opacity .45s ease;
}
.site-intro.is-done{ opacity:0; pointer-events:none; }
.site-intro.is-removed{ display:none; }
/* Eliza: "user shouldn't be able to scroll down below the fold" during the
   intro -- the vertical bar deliberately bleeds past it (60vh/40vh), so a
   plain overflow:hidden on body isn't enough to stop every scroll/touch
   gesture from nudging the page and revealing the bar's cut-off end.
   position:fixed is the full lock: it also defeats iOS's rubber-band
   overscroll, which overflow:hidden alone does not. */
body.intro-active{ overflow:hidden; position:fixed; inset:0; width:100%; }

/* Eliza: "it looks too big on macbook 13, scale down the entire
   animation 50%" -- wrap the mark in one positioned box the same
   size as the intro screen and scale THAT by half, anchored to
   viewport center, so the whole composition just shrinks in place
   without hand-halving every value tuned into the F below. */
.intro-marks{ position:absolute; inset:0; transform: scale(.5); transform-origin: 50% 50%; }

/* Centred on the F glyph's own vertical stroke (at x=117.5 of its 612-wide
   viewBox), not the box -- the F is a left-weighted letterform, not a
   symmetric mark, so centring the box would centre empty space instead of
   the stroke the mark is actually built around. */
.intro-f-wrap{
  position:absolute; top:24.3vh; left:50%; transform: translateX(calc(-117.5 / 612 * 100%));
  width:min(30vw, 300px);
}
.intro-f{ display:block; width:100%; overflow:visible; }

.intro-f line{
  fill:none; stroke: var(--white); stroke-width: calc(2 * var(--u)); /* Eliza: "thinner, like 1 pt" -- was 9u; then "should be 2pt" */
  vector-effect:non-scaling-stroke;
  opacity:0;
  transition: opacity .9s ease, transform 1.5s cubic-bezier(.16,.84,.44,1); /* Eliza: "slow down the animation 200%" -- all intro durations/delays *3 */
}

/* Phase 1 start state: off past the viewport edge (big vw offset
   survives the .intro-marks .5 scale above) and at overshoot length
   (scaleX > 1). transform-origin sits at each line's INNER end (the
   end nearest the vertical bar) so phase 2's scaleX-down reads as
   the OUTER tip retracting, not the whole line sliding. */
.intro-f-top{
  transform-box: fill-box; transform-origin: 0% 50%;
  transform: translateX(160vw);
}
.intro-f-mid{
  transform-box: fill-box; transform-origin: 0% 50%;
  transform: translateX(-160vw);
}
/* Eliza 2026-09-26: "still crossing over on the 2nd line/sticking out" --
   the real logomark's own mid bar (113-508) pokes 4.5u left of the
   vertical stroke's centreline (117.5), invisible at logomark scale but
   read as an overshoot blown up here. Per her reference, the mid bar
   stops flush at the centreline (x2=117.5 in index.html) instead of
   crossing it. */

/* Phase 1 -- joins: arrive at position, still overshoot length. */
.intro-f-wrap.is-joining .intro-f-top{ opacity:1; transform: translateX(0); }
.intro-f-wrap.is-joining .intro-f-mid{ opacity:1; transform: translateX(0); transition-delay: .18s, .18s; }

/* Phase 2 -- shortens into place, outside in: scaleX relaxes to 1,
   anchored at the inner end, so only the outer tip moves. Top bar
   first, mid bar close behind (same stagger shape as the old draw). */
/* Eliza 2026-10-04: second effect (horizontal bars shrinking in) removed -- the bars now arrive at their final length. */

/* Eliza: the vertical stroke read as "cut off weird into 2 pieces" when it
   was an SVG <line> plus a separate bleed div -- one HTML bar spans from
   the stroke's start (y=58 of the 612-tall box, as a %) down through the
   box AND the 60vh bleed below the fold, in one piece. It joins in phase 1
   (translates down from above the top edge into place, already at full
   height) and takes no part in phase 2. left is centred on the stroke's
   own centreline (117.5 of 612) minus half the bar's width, same centring
   math .intro-f-wrap already uses for the whole mark. */
.intro-f-vert-bar{
  position:absolute; top:calc(58 / 612 * 100%);
  left:calc((117.5 / 612 * 100%) - (1 * var(--u)));
  width:calc(2 * var(--u));
  height:calc(((612 - 58) / 612 * 100%) + 125.7vh - min(30vw, 300px));
  background: var(--white); /* matches .intro-f line's 2pt stroke */
  opacity:0; transform: translateY(140vh);
  /* Eliza 2026-10-02: "vertical line should come down up, not up down" --
     was translateY(-140vh) (rises INTO place by dropping down from above
     the top edge); flipped to a positive offset so it travels up from
     below the bottom edge instead, landing in the same spot.
     2026-10-02 (follow-up): the previous empirically-tuned "126vh" value
     was fit to six measured viewport sizes (768-1080px tall) and still
     fell short on an iMac outside that range -- replaced with an EXACT
     closed-form derivation instead of another empirical fit.
     .intro-marks (this element's transformed ancestor) has inset:0, so
     its own untransformed layout box is exactly 100vw x 100vh; its
     `transform: scale(.5)` around 50%/50% then means any descendant's
     LAYOUT position Y maps to a VISUAL position of
     centerY + .5*(Y - centerY) = 50vh + .5*(Y - 50vh). Setting that equal
     to the true viewport bottom (100vh) and solving for Y gives
     Y = 150vh -- so for the bar's bottom edge to land exactly on the
     real fold, its layout-space bottom must sit at 150vh from the top of
     .intro-marks, independent of viewport height by construction (no
     fitting, no sample sizes). That bottom edge = .intro-f-wrap's own
     `top` (24.3vh) + .intro-f-wrap's own height (min(30vw,300px), same
     cap this element's own width/height % terms are already relative
     to) + this bar's added vh term -- so the added term is
     150vh - 24.3vh - min(30vw,300px) = 125.7vh - min(30vw,300px). */
  transition: opacity .9s ease, transform 1.5s cubic-bezier(.16,.84,.44,1) .36s;
}
.intro-f-wrap.is-joining .intro-f-vert-bar{ opacity:1; transform: translateY(0); }

/* Eliza (14th pass, 2026-10-02): "on macbook 13 inch, a common device,
   the vertical bar is squished and cut off -- things need to shift up
   and the vertical bar needs to always be fully visible." .intro-f-wrap's
   top offset and the vert-bar's bleed are tuned in vh against a ~900px-
   tall reference viewport; a 13" MacBook is SHORT, not narrow (its width
   is well past the 1152px mobile breakpoint below, so it was hitting the
   full desktop layout), so the same vh math eats a much bigger share of a
   shorter screen. Height-based query, independent of the width one
   below: shift the mark up so the full draw-in always fits inside a
   short desktop viewport.
   Eliza (follow-up, same day): "still squished -- should look like
   [the Figma end-state reference], full bleed to the bottom of the
   fold." The first pass here fixed layout overflow by SHRINKING the
   bleed (40vh, down from the base rule's 60vh at the time) -- which
   stopped it running past the fold, but also stopped it reaching the
   fold at all, the opposite problem. Both numbers measured live
   (Playwright, not guessed): the base rule's own bleed was independently
   retuned from 60vh to 92vh for the same reason (see .intro-f-vert-bar
   above), and this override needs its own larger value rather than
   inheriting that ratio, since .intro-f-wrap's `top` is also different
   here (15vh vs the base rule's 24.3vh) -- 100vh was what landed the
   bar's bottom edge flush with the fold at 1512x823 and 1280x800, but
   those were only two sample points again, same mistake as the base
   rule. Replaced with the same exact closed-form derivation (see
   .intro-f-vert-bar above): 150vh - 15vh (this query's own `top`) -
   min(30vw,300px) = 135vh - min(30vw,300px). */
@media (min-width: 1153px) and (max-height: 850px){
  .intro-f-wrap{ top:15vh; }
  .intro-f-vert-bar{ height:calc(((612 - 58) / 612 * 100%) + 135vh - min(30vw, 300px)); transform: translateY(100vh); }

  /* Eliza 2026-10-02: "fix above the fold vertical bar on macbook pro 13
     inch... set rule for all responsiveness that it needs to shift
     paragraphs and bar up above the fold so user can see it on landing."
     .hero-content's `top: 60.1%` is a fixed fraction of hero height, but
     the stack below it (paragraphs -> nav links -> .scroll-cue) scales
     with WIDTH via --u, not height -- so on a viewport that's wide enough
     for --u to sit near its max but short enough that 100vh is tight (the
     13" MacBook Pro class, ~800-850px tall), the stack's real height
     outgrows the room `top: 60.1%` leaves below it and the cue's bottom
     edge lands past the fold. Measured live at 1512x823 (current 13"
     MacBook Pro, browser chrome included): the cue's bottom overshot the
     viewport by ~12px.
     Anchoring from the BOTTOM instead of the top fixes this at the source
     rather than hand-tuning one top% per breakpoint: the cue is the last
     flow child of .hero-content, so pinning .hero-content's own bottom a
     fixed distance above the hero's bottom edge (== the viewport's bottom
     edge, since .hero is exactly 100vh once this fix lets it be) holds
     the cue a constant, guaranteed-visible distance off the fold no
     matter how tall the paragraph block wraps or how --u scales the rest
     of the stack. */
  .hero-content{ top:auto; bottom: calc(40 * var(--u)); }
}

@media (max-width: 1152px){
  .intro-f-wrap{ top:19.7vh; width:min(46vw, 190px); }
  /* Eliza (2026-10-02, same pass as the iMac fix above): mobile never had
     its own .intro-f-vert-bar override, so it was silently inheriting the
     desktop base rule's bleed math -- which assumes .intro-f-wrap's own
     height is min(30vw,300px) (the desktop cap), but mobile's wrap is
     min(46vw,190px) instead. Same exact derivation, this query's own
     top (19.7vh) and width cap (46vw,190px):
     150vh - 19.7vh - min(46vw,190px) = 130.3vh - min(46vw,190px). */
  .intro-f-vert-bar{ height:calc(((612 - 58) / 612 * 100%) + 130.3vh - min(46vw, 190px)); }
}

@media (prefers-reduced-motion: reduce){
  *{ transition-duration:.001ms !important; animation-duration:.001ms !important; }
}

/* No focus box around a clicked catalogue item / tile (keyboard focus keeps its ring). */
.catalogue-item, .tile-link{ -webkit-tap-highlight-color: transparent; }
.catalogue-item:focus:not(:focus-visible), .tile-link:focus:not(:focus-visible){ outline:none; }

/* Skip link: first tab stop, visible only on keyboard focus. */
.skip-link{ position:absolute; left:8px; top:-60px; z-index:100; background: var(--ink); color: var(--white); padding:10px 14px; font-family: var(--font-body); font-size:14px; letter-spacing:.05em; text-transform:uppercase; text-decoration:none; }
.skip-link:focus{ top:8px; }

/* ============================================================
   GLOBAL RULES (Eliza 2026-10-04) -- kept last so they win over per-page rules.
   ============================================================ */

/* 1. One arrow size and one button font size, site-wide per breakpoint. */
:root{ --arrow: calc(11 * var(--u)); --btn-fs: calc(14 * var(--u)); }
@media (max-width: 1152px){ :root{ --arrow: calc(10 * var(--mu)); --btn-fs: calc(14 * var(--mu)); } }
.btn-outline img, .newsletter button img, .newsletter .accent img,
.site-footer .newsletter .accent img, .mobile-menu .newsletter .accent img,
.about-cta img, .sf-submit img, .showroom-cta img, .faq-cta img, .custom-cta img,
.product-cta img, .catalogue-download img, .catalogue-collaborate img{
  width: var(--arrow); height: var(--arrow);
}
/* CATALOGUE band is a big type link, so its arrow scales with the text (Figma 19x20 at 25px) instead of the button arrow size. */
.catalogue-band img{ width:.76em; height:.8em; }
.btn-outline, .newsletter .accent, .site-footer .newsletter .accent, .mobile-menu .newsletter .accent,
.about-cta, .sf-submit, .showroom-cta, .faq-cta, .custom-cta, .product-cta,
.catalogue-download, .catalogue-collaborate,
.newsletter input, .site-footer .newsletter input, .mobile-menu .newsletter input{ font-size: var(--btn-fs); }

/* 2. Footer / hamburger DOWNLOAD CATALOGUE: dark purple text + arrow on white. */
.site-footer .newsletter .accent, .mobile-menu .newsletter .accent, .mobile-menu .mm-newsletter .accent{
  background: var(--white); color: var(--ink); border-color: var(--white);
}
.site-footer .newsletter .accent img, .mobile-menu .newsletter .accent img, .mobile-menu .mm-newsletter .accent img{
  content: url("../images/logos/arrows/arrow-purple.svg");
}
.site-footer .newsletter .accent:hover, .mobile-menu .newsletter .accent:hover, .mobile-menu .mm-newsletter .accent:hover{
  background: var(--orange); border-color: var(--white); color: var(--white);   /* inverted: orange fill, white outline + text */
}
.site-footer .newsletter .accent:hover img, .mobile-menu .newsletter .accent:hover img, .mobile-menu .mm-newsletter .accent:hover img{
  content: url("../images/logos/arrows/arrow-white.svg");
}

/* Footer: main links stay 16 (desktop); FAQ / Guarantee / Press / IG and SIGN UP FOR NEWSLETTER are always the same 14. */
.footer-col.footer-col-wide a, .newsletter label{ font-size: var(--btn-fs); }
.mobile-menu .mm-secondary a, .mobile-menu .newsletter label, .mobile-menu .mm-newsletter label{ font-size: var(--btn-fs); }

/* 3. Footer + hamburger secondary links (FAQ, Guarantee, Press, IG...) are always white. */
.footer-col.footer-col-wide a, .mobile-menu .mm-secondary a{ color: var(--white); }
.footer-col.footer-col-wide a:hover, .mobile-menu .mm-secondary a:hover{ color: var(--orange-light); }

/* 4. White copy on orange is Light (300); ink-on-white and white-on-dark-photo stay ExtraLight (200).
      The big STUDIO / FRITZ wordmark is a display face and is excluded. */
body :is(.site-footer, .mobile-menu, .carousel, .catalogue-band) :is(a, label, span, p, div, figcaption, input, button, small):not(.footer-wm):not(.footer-wm *):not(.accent):not(input){
  font-weight:300 !important;
}
.catalogue-band{ font-weight:300 !important; }
/* ink on white / cream has no contrast issue, so the download button and email field stay ExtraLight; the white-on-orange INQUIRE button is Light. */
.newsletter .accent, .newsletter input{ font-weight:200 !important; }
.product-cta-inquire{ font-weight:300; }

/* 5. Floating stamps on mobile: stay put on scroll, start below the nav bar, tuck under footer/carousel. */
@media (max-width: 1152px){
  .stamp{ left:auto; right: calc(10 * var(--mu)); top: max(55%, calc(81 * var(--mu) + 16 * var(--mu))); }
  body.page-product .product-stamp-soft{
    position:fixed !important; left: var(--edge); right:auto; top: calc(81 * var(--mu) + 16 * var(--mu)); z-index:5;
  }
  body.page-product .carousel, body.page-product .site-footer{ position:relative; z-index:6; }
}

/* 6. Email field is exactly as thick as the button under it (Eliza 2026-10-04). */
:root{ --field-h: calc(33 * var(--u)); }
@media (max-width: 1152px){ :root{ --field-h: calc(33 * var(--mu)); } }
.newsletter input, .site-footer .newsletter input, .mobile-menu .newsletter input{ height: var(--field-h); box-sizing:border-box; }
.newsletter .accent, .site-footer .newsletter .accent, .mobile-menu .newsletter .accent{ min-height: var(--field-h); height: var(--field-h); }
.newsletter button{ padding:0; width: var(--field-h); height: var(--field-h); right:0; }

/* 7. Product page: FINISH sits on the same top line as DIMENSIONS and STARTING PRICE. */
.product-config p{ margin:0; }
.product-config p + p{ margin-top:1.7em; }

/* 8. No hairline between the carousel and the footer (the footer starts on a fractional pixel). */
.scroll-hijack + .site-footer{ box-shadow: 0 -2px 0 var(--orange); }

/* 9. Stacked / arrow buttons: every arrow sits the same distance from the right edge as the email field's arrow. */
:root{ --arrow-inset: calc((var(--field-h) - var(--arrow)) / 2); }
.newsletter .accent, .site-footer .newsletter .accent, .mobile-menu .newsletter .accent,
.btn-outline, .about-cta, .sf-submit, .showroom-cta, .faq-cta, .custom-cta, .product-cta,
.catalogue-download, .catalogue-collaborate{ padding-right: calc(var(--arrow-inset) - 1px); } /* -1px: the 1px border */
.newsletter button{ justify-content:center; }

/* 10. All widths: no hairline where a section meets the carousel (sub-pixel seam showed the orange behind the tiles). */
.scroll-hijack{ margin-top:-1px; }
.scroll-hijack, .scroll-hijack-sticky, .carousel, body.page-showroom .carousel, body.page-custom .carousel{ background: linear-gradient(transparent 1px, var(--orange) 1px); }
/* (every layer is transparent for its first pixel, so no orange row can ever sit above the first tile; below that it is solid orange, including the empty runway above the footer) */

/* ============================================================
   GLOBAL RULES, batch 2 (Eliza 2026-10-04)
   ============================================================ */

/* Images carry width/height attributes so the browser reserves their space before they load.
   height:auto keeps those attributes from ever stretching a photo; class rules still win. */
img{ height:auto; }

/* Product title never runs into the F-shaped accent: it drops to a second line (line height 1.1 x size). */
.product-title{ line-height:1.1; }
@media (min-width: 1153px){ .product-title{ max-width: calc(241 * var(--u)); } }   /* 305u accent line - 40u left - 24u clearance */

/* Keyboard focus: one visible ring everywhere (ink on light, white on orange / dark photo). */
:focus-visible{ outline: 2px solid var(--ink); outline-offset: 3px; }
.site-footer :focus-visible, .mobile-menu :focus-visible, .carousel :focus-visible, .catalogue-band:focus-visible,
.hero :focus-visible, #heroNav :focus-visible, body.menu-open .nav-toggle:focus-visible{ outline-color: var(--white) !important; outline-style:solid !important; outline-width:2px !important; }
.newsletter input:focus-visible{ outline-offset:0; }

/* 44px touch targets on mobile. Buttons and the email field grow together; small links get an invisible bigger hit area. */
@media (max-width: 1152px){
  :root{ --field-h: max(44px, calc(33 * var(--mu))); }
  .product-cta, .catalogue-download, .catalogue-collaborate, .about-cta, .showroom-cta, .faq-cta, .custom-cta, .sf-submit,
  .btn-outline{ min-height: 44px; }
  .catalogue-band, .footer-col a, .mobile-menu .mm-col a, .mobile-menu .mm-secondary a{ position:relative; }
  .catalogue-band::after, .footer-col a::after, .mobile-menu .mm-col a::after, .mobile-menu .mm-secondary a::after{
    content:''; position:absolute; left:0; right:0; top:-8px; bottom:-8px;
  }
}

/* 12. No hairlines between touching photos. Neighbouring photos meet on fractional pixels, which lets the page colour
      bleed through as a thin white line on some screens; the earlier photo tucks 1px under the later one. */
.custom-photo-int6{ width: calc(743 * var(--u) + 1px); height: calc(928 * var(--u)); aspect-ratio:auto; }
.custom-photo-westlake3{ width: calc(475 * var(--u) + 1px); height: calc(695 * var(--u)); aspect-ratio:auto; }
@media (max-width: 1152px){
  .custom-photo-int6, .custom-photo-westlake3{ width:auto; height:auto; }
  .custom-photo-img0274, .custom-photo-westlake2{ margin-top:-1px !important; }
  .product-gallery .product-photo + .product-photo{ margin-top:-1px !important; }
  .catalogue-item-media .catalogue-photo-sm{ margin-left:-1px; }
}

/* Cropped photos always crop from the vertical centre */
.catalogue-photo img, .custom-photo img{ object-position:center center; }


/* ============================================================
   NEWSLETTER FIELD (footer + hamburger), Eliza 2026-10-04: cream fill
   with a white ring looked off against the orange. Now a solid white
   field -- same fill as the DOWNLOAD CATALOGUE button under it -- and the
   focus state is a white ring floating 2px outside it on the orange, so
   focus is still clearly visible without a second tone inside the box.
   ============================================================ */
.newsletter input{ background: var(--white); border-color: var(--white); }
.newsletter input:focus, .newsletter input:focus-visible{ border-color: var(--white); outline: 1px solid var(--white); outline-offset: 3px; }
.newsletter input::placeholder{ color: var(--ink); opacity:.55; }

/* form status line (newsletter + contact/trade/inquire) */
.newsletter .nl-status{ margin:0; font-family: var(--font-body); font-weight:300; font-size: var(--btn-fs); letter-spacing:.05em; text-transform:uppercase; color: var(--white); }
.newsletter .nl-status[hidden]{ display:none; }
.newsletter form.is-sending button{ pointer-events:none; }
.sf-form.is-sending .sf-submit{ opacity:.5; pointer-events:none; }
input.sf-hp, .newsletter input.sf-hp, .sf-form input.sf-hp{ position:absolute !important; left:-9999px !important; top:auto !important; width:1px !important; height:1px !important; min-height:0 !important; padding:0 !important; border:0 !important; opacity:0 !important; pointer-events:none !important; }
.sf-status{ margin: calc(16 * var(--u)) 0 0; font-family: var(--font-body); font-weight:200; letter-spacing:.05em; text-transform:uppercase; }
@media (max-width:1152px){ .sf-status{ margin-top: calc(16 * var(--mu)); font-size: calc(14 * var(--mu)); } }

/* ============================================================
   404 (Figma "404 error", Eliza 2026-10-04). Same chrome as Thank You, but
   the composition differs: label left, message + button start at x=529 in
   the same row as the label, the soft stamp sits on the RIGHT edge, and the
   white section is short (carousel starts at y=556). Desktop only; mobile
   keeps the shared stacked Thank You layout.
   ============================================================ */
@media (min-width:1153px){
  body.page-404{ --rule-h: calc(279 * var(--u)); }
  body.page-404 .page-section{ height: calc(556 * var(--u)); }
  body.page-404 .page-label{ top: calc(274 * var(--u)); }
  body.page-404 .page-thanks-msg{ left: calc(529 * var(--u)); top: calc(274 * var(--u)); width: calc(500 * var(--u)); font-size: var(--fs-body); }
  body.page-404 .page-thanks-back{ left: calc(529 * var(--u)); top: calc(362 * var(--u)); width: calc(324 * var(--u)); }
  body.page-404 .page-stamp{ position:absolute !important; left:auto !important; right: var(--edge) !important; top: calc(284 * var(--u)) !important; width: calc(125 * var(--u)) !important; transform:none !important; }
}
.page-thanks-back, .page-thanks-back:hover{ text-decoration:none; }

/* 404 mobile (Figma "404 MOBILE", Eliza 2026-10-04): label right-aligned on
   the 16px edge, message and full-width button under it, then the soft
   stamp on the left edge before the carousel. */
@media (max-width:1152px){
  body.page-404 .page-section{ display:flex; flex-direction:column; padding-bottom: calc(26 * var(--mu)); }
  body.page-404 .page-label{ order:1; align-self:flex-end; }
  body.page-404 .page-thanks-msg{ order:2; }
  body.page-404 .page-thanks-back{ order:3; text-decoration:none; }
  body.page-404 .page-stamp{
    order:4; display:block !important; position:static !important; transform:none !important;
    width: calc(68 * var(--mu)); margin: calc(-22 * var(--mu)) 0 0 var(--edge);
  }
}

/* Newsletter arrow: pinned to the field itself (not 50% of whatever the form grows to), always the dark purple, never faded. */
.newsletter button{ top:0; transform:none; }
.newsletter button:hover img, .newsletter button img{ opacity:1; }
.newsletter button:hover img{ transform: translate(1px,1px); }
.newsletter button img{ transition: transform .15s ease; }

/* 2px orange rule under the white bar on non-homepage pages (is-static is
   only ever on those), shown only once the page has scrolled (js/main.js
   staticHeader toggles .is-scrolled). A box-shadow, not a border, so the bar's height --
   and everything keyed to --hdr-h -- is unchanged. Dropped while the mobile
   menu is open, where the bar turns orange and merges with the panel. */
.wordmark-header.is-static{ box-shadow: 0 0 0 var(--orange); transition: box-shadow .2s ease; }
.wordmark-header.is-static.is-scrolled{ box-shadow: 0 2px 0 var(--orange); }
body.menu-open .wordmark-header.is-static{ box-shadow:none; }
