/* ============================================================
   Goodwood Marine — foundations

   Marine electronics chandlery + workshop, Crews Inn Marina,
   Chaguaramas. The page has one job: convince a boat owner on
   marina wifi that the part is here and these people will fit it.

   Identity: deep ink ground, bone type, one amber accent, Archivo
   display over IBM Plex Sans. Mono (Plex Mono) is reserved for
   real data — coordinates, phone numbers, hours.
   ============================================================ */

/* ── FONTS — self-hosted variable, no CDN ────────────────────── */

@font-face {
  font-family: "Archivo";
  src: url("/assets/fonts/archivo.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("/assets/fonts/ibm-plex-sans.woff2") format("woff2");
  font-weight: 100 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/assets/fonts/ibm-plex-mono.woff2") format("woff2");
  font-weight: 100 700; font-style: normal; font-display: swap;
}

/* ── TOKENS ──────────────────────────────────────────────────── */

:root {
  /* Ground */
  /* Ground. Deep sea rather than near-black — the old palette bottomed out
     at #0B1418, which read industrial. */
  --ink:      #062230;
  --ink-2:    #0A3243;
  --ink-3:    #12506A;

  /* Light ground carries a faint aqua cast instead of a grey one. */
  --paper:    #F1FAFB;
  --card:     #FFFFFF;

  --bone:        #F4FBFC;
  --muted-dark:  #A8CDD8;
  --ink-text:    #062230;
  --muted-light: #3D6472;

  /* Sun. Warmer and brighter than the old amber. */
  --amber:     #FFAE1A;
  --amber-hi:  #FFC24D;
  --amber-dim: rgba(255, 174, 26, .16);
  /* Amber legible on paper — the bright one is ~2:1 there. */
  --amber-ink: #8F5A00;

  /* Water. The new second accent, taken off the hero footage. */
  --aqua:      #039BB4;
  --aqua-hi:   #16C7E0;
  --aqua-dim:  rgba(3, 155, 180, .13);
  --coral:     #FF5B3D;

  --line-dark:  rgba(244, 251, 252, .16);
  --line-light: rgba(6, 34, 48, .13);

  /* Type scale — steps at breakpoints, no clamp() */
  --fs-xs:   0.78rem;
  --fs-sm:   0.9rem;
  --fs-base: 1.0625rem;
  --fs-lg:   1.25rem;
  --fs-xl:   1.6rem;
  --fs-2xl:  2.1rem;
  --fs-3xl:  2.75rem;

  /* Spacing — 4px base */
  --sp-1: 4px;   --sp-2: 8px;   --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 24px;  --sp-6: 32px;  --sp-7: 40px;  --sp-8: 56px;
  --sp-9: 72px;  --sp-10: 96px; --sp-11: 120px;

  --display: "Archivo", system-ui, sans-serif;
  --body:    "IBM Plex Sans", system-ui, sans-serif;
  --data:    "IBM Plex Mono", ui-monospace, monospace;

  --radius:    10px;
  --radius-lg: 20px;
  --container: 1240px;
  --nav-h:     72px;

  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --t-fast:   160ms;
  --t-mid:    260ms;

  --shadow-sm: 0 1px 2px rgba(6, 34, 48,.06), 0 2px 8px rgba(6, 34, 48,.05);
  --shadow-md: 0 4px 12px rgba(6, 34, 48,.09), 0 12px 32px rgba(6, 34, 48,.10);
  --shadow-lg: 0 10px 24px rgba(6, 34, 48,.12), 0 24px 60px rgba(6, 34, 48,.14);
}

/* ── RESET ───────────────────────────────────────────────────── */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 16px);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink-text);
  font-family: var(--body);
  font-size: var(--fs-base);
  font-weight: 400;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, picture, video, svg, iframe { max-width: 100%; display: block; }
/* <picture> is a plain inline wrapper with no height of its own, so an
   img set to height:100% inside it resolves against nothing and the frame
   ends up part-empty. Make the wrapper fill its figure. */
.hero__media picture,
.band__media picture,
.svc-card__media picture,
.guard__media picture,
.svcp__media picture,
.about__media picture,
.range-card__media picture,
.page-head__media picture { width: 100%; height: 100%; }
figure { margin: 0; }
button, input, select, textarea { font: inherit; color: inherit; }
a, button, input, select, textarea, label { touch-action: manipulation; }
button { cursor: pointer; }
::selection { background: var(--amber); color: var(--ink); }
ul, ol { margin: 0; padding: 0; list-style: none; }

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.022em;
  margin: 0;
  color: inherit;
  text-wrap: balance;
}
h1 { font-size: var(--fs-3xl); }
h2 { font-size: var(--fs-2xl); }
h3 { font-size: var(--fs-lg); line-height: 1.25; letter-spacing: -0.01em; }

p { margin: 0; }

a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 3px; }

/* Phone numbers are data. A button labelled with words is not. */
a[href^="tel:"]:not(.btn):not(.nav__call):not(.callbar__btn) { font-family: var(--data); }

:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 3px;
  border-radius: 2px;
}

::selection { background: var(--amber); color: var(--ink); }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 300;
  background: var(--amber); color: var(--ink);
  padding: var(--sp-3) var(--sp-5); font-weight: 600;
}
.skip-link:focus { left: 0; }

/* ── SURFACES ────────────────────────────────────────────────── */

.on-dark  { background: var(--ink); color: var(--bone); }
.on-light { background: var(--paper); color: var(--ink-text); }
.on-dark .muted  { color: var(--muted-dark); }
.on-light .muted { color: var(--muted-light); }

.container {
  width: 100%; max-width: var(--container);
  margin: 0 auto; padding: 0 var(--sp-5);
}
.section { padding: var(--sp-10) 0; }

/* ── TYPE UTILITIES ──────────────────────────────────────────── */

/* Section eyebrow. The short amber tick is the one decorative use
   of the accent, and it earns it by marking where a section starts. */
.eyebrow {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted-light);
  margin-bottom: var(--sp-4);
}
.on-dark .eyebrow { color: var(--muted-dark); }
.eyebrow::before {
  content: ""; width: 22px; height: 2px;
  background: var(--amber); border-radius: 2px; flex: none;
}

/* The position stamp — real data, so it earns the mono face. */
.stamp {
  font-family: var(--data);
  font-size: var(--fs-xs);
  letter-spacing: .04em;
  white-space: nowrap;
}

.lead { font-size: var(--fs-lg); line-height: 1.55; }
.measure { max-width: 58ch; }
.hidden { display: none !important; }

/* ── BUTTONS ─────────────────────────────────────────────────── */

.btn {
  --btn-bg: var(--amber);
  --btn-fg: var(--ink);
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sp-3);
  min-height: 52px;
  padding: var(--sp-3) var(--sp-7);
  border: 0; border-radius: var(--radius);
  background: var(--btn-bg); color: var(--btn-fg);
  font-family: var(--body); font-size: var(--fs-base); font-weight: 600;
  text-decoration: none; cursor: pointer;
  transition: background var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out),
              box-shadow var(--t-fast) var(--ease-out);
}
.btn:hover { background: var(--amber-hi); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.btn:active { transform: translateY(0) scale(.985); }

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: currentColor;
  box-shadow: inset 0 0 0 1px var(--line-dark);
}
.btn--ghost:hover {
  background: rgba(244, 251, 252,.08);
  box-shadow: inset 0 0 0 1px currentColor;
}
.on-light .btn--ghost { box-shadow: inset 0 0 0 1px var(--line-light); }
.on-light .btn--ghost:hover { background: rgba(6, 34, 48,.05); }

.btn svg { width: 18px; height: 18px; flex: none; }

/* Text link with an underline that retracts on hover. */
.link {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-weight: 600; text-decoration: none;
  padding: var(--sp-2) 0; position: relative;
}
.link::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: 1.5px; background: currentColor;
  transform-origin: left; transition: transform var(--t-mid) var(--ease-out);
}
.link:hover::after { transform: scaleX(.35); }
.link svg { width: 16px; height: 16px; transition: transform var(--t-fast) var(--ease-out); }
.link:hover svg { transform: translateX(3px); }

.actions { display: flex; flex-wrap: wrap; gap: var(--sp-4); align-items: center; }

/* ── NAV ─────────────────────────────────────────────────────── */

body > header { position: sticky; top: 0; z-index: 100; }

.nav {
  background: rgba(6, 34, 48, .82);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  color: var(--bone);
  border-bottom: 1px solid transparent;
  transition: background var(--t-mid), border-color var(--t-mid),
              translate 320ms var(--ease-out);
}
/* Slides away on the way down, returns on the way up. Never while the
   menu is open, and never near the top. Driven by main.js. */
.nav--hidden { translate: 0 -100%; }
.nav--hidden:focus-within { translate: none; }
/* Solid once the hero is behind us, so the nav never sits over light
   content at low contrast. */
.nav.is-stuck { background: rgba(6, 34, 48, .97); border-bottom-color: var(--line-dark); }

.nav__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); min-height: var(--nav-h);
}

.nav__brand { display: flex; align-items: center; gap: var(--sp-4); min-height: 46px; text-decoration: none; color: var(--bone); }
.nav__logo { height: 34px; width: auto; }
.nav__stamp { color: var(--muted-dark); display: none; }

.nav__links { display: none; align-items: center; gap: var(--sp-7); }
.nav__link {
  position: relative;
  font-size: var(--fs-sm); font-weight: 500;
  color: var(--muted-dark); text-decoration: none;
  padding: var(--sp-2) 0;
  transition: color var(--t-fast);
}
/* Country switcher. Two links rather than a dropdown: no JavaScript needed,
   both regions stay crawlable, and it degrades to plain links. Deliberately
   quiet — the nav already spends its amber on the call button, and the client
   has asked twice for less brightness. */
.region { display: none; align-items: center; gap: var(--sp-2); }
.region__opt {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--data);
  font-size: var(--fs-xs); letter-spacing: .04em;
  color: var(--muted-dark);
  padding: 4px 7px; border-radius: 4px;
  transition: color var(--t-fast);
}
.region__opt:hover { color: var(--bone); }
.region__opt[aria-current="true"] {
  color: var(--bone);
  box-shadow: inset 0 -2px 0 var(--amber);
}
/* The flag carries the state: the region you are in is in colour, the one you
   are not is drained and dimmed. Switching is unmistakable at a glance, which
   two-letter codes alone were not. */
.region__flag {
  width: 20px; height: auto; display: block;
  border-radius: 2px;
  box-shadow: 0 0 0 1px rgba(6, 34, 48, .35);
  filter: grayscale(1); opacity: .5;
  transition: filter var(--t-fast), opacity var(--t-fast);
}
.region__opt:hover .region__flag { filter: grayscale(.35); opacity: .85; }
.region__opt[aria-current="true"] .region__flag { filter: none; opacity: 1; }
/* In the mobile panel it is a full-width pair of named links, not initials. */
.region--menu {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  margin-top: var(--sp-4);
}
.region--menu .region__opt { font-size: var(--fs-sm); padding: 6px 0; }

.nav__link::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px;
  height: 2px; background: var(--amber); border-radius: 2px;
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--t-mid) var(--ease-out);
}
.nav__link:hover { color: var(--bone); }
.nav__link:hover::after,
.nav__link--active::after { transform: scaleX(1); }
.nav__link--active { color: var(--bone); }


.nav__call {
  display: inline-flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; margin-left: auto;
  border-radius: var(--radius);
  background: var(--amber-dim); color: var(--amber);
  text-decoration: none; transition: background var(--t-fast), color var(--t-fast);
}
.nav__call:active { background: var(--amber); color: var(--ink); }
.nav__call svg { width: 20px; height: 20px; }

.nav__burger {
  display: inline-flex; flex-direction: column; justify-content: center;
  gap: 5px; width: 46px; height: 46px; padding: 0 12px;
  background: none; border: 0; cursor: pointer; color: var(--bone);
}
.nav__burger span {
  display: block; height: 1.5px; width: 100%;
  background: currentColor; border-radius: 2px;
  transition: transform var(--t-mid) var(--ease-out), opacity var(--t-fast);
}
.nav__burger.is-open span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav__burger.is-open span:nth-child(2) { opacity: 0; }
.nav__burger.is-open span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

/* Full-screen mobile menu. Links in the wordmark's voice; the exit runs
   at ~65% of the entrance so closing feels immediate (base transition is
   the exit, .is-open overrides it for the entrance). */
.nav__menu {
  position: fixed; inset: var(--nav-h) 0 0 0;
  background: var(--ink);
  padding: var(--sp-7) 0 calc(var(--sp-9) + env(safe-area-inset-bottom));
  transform: translateY(-8px);
  opacity: 0; visibility: hidden;
  transition: opacity 170ms var(--ease-out),
              transform 170ms var(--ease-out),
              visibility 170ms;
  overflow-y: auto; overscroll-behavior: contain; z-index: 90;
}
.nav__menu.is-open {
  opacity: 1; visibility: visible; transform: none;
  transition-duration: 260ms;
}
/* Brand hairline along the top of the panel. */
.nav__menu::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, var(--aqua) 0%, var(--aqua-hi) 55%, var(--amber) 140%);
}

.nav__menu-link {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--sp-4) 0;
  border-bottom: 1px solid var(--line-dark);
  font-family: var(--display);
  font-size: clamp(2rem, 8vw, 2.9rem);
  text-transform: uppercase; line-height: 1.1;
  font-weight: 700;
  letter-spacing: -.02em; color: var(--bone); text-decoration: none;
  opacity: 0; transform: translateY(16px);
}
.nav__menu-link:active { color: var(--amber); }
.nav__menu.is-open .nav__menu-link { animation: menu-in 420ms var(--ease-out) forwards; }
.nav__menu.is-open .nav__menu-link:nth-child(1) { animation-delay: 40ms; }
.nav__menu.is-open .nav__menu-link:nth-child(2) { animation-delay: 85ms; }
.nav__menu.is-open .nav__menu-link:nth-child(3) { animation-delay: 130ms; }
.nav__menu.is-open .nav__menu-link:nth-child(4) { animation-delay: 175ms; }
.nav__menu.is-open .nav__menu-link:nth-child(5) { animation-delay: 220ms; }
.nav__menu-link svg { width: 22px; height: 22px; color: var(--amber); flex: none; }
@keyframes menu-in { to { opacity: 1; transform: none; } }

/* Foot arrives after the links, not alongside them. */
.nav__menu-foot {
  margin-top: var(--sp-8); display: grid; gap: var(--sp-4);
  opacity: 0; transform: translateY(12px);
}
.nav__menu.is-open .nav__menu-foot { animation: menu-in 380ms var(--ease-out) 290ms forwards; }
.nav__menu-foot .btn { width: 100%; }
.nav__menu-place { color: var(--muted-dark); font-size: var(--fs-sm); }

/* ── STICKY MOBILE CALL BAR ─────────────────────────────────────
   This is a business people ring from a dock, so below the desktop
   breakpoint a call action stays within thumb reach. */

.callbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 95;
  display: flex; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4) calc(var(--sp-3) + env(safe-area-inset-bottom));
  background: rgba(6, 34, 48, .94);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--line-dark);
  transform: translateY(110%);
  transition: transform var(--t-mid) var(--ease-out);
}
.callbar.is-visible { transform: none; }
/* Clearance so the bar never covers the last of the footer. */
body { padding-bottom: 76px; }
@media (min-width: 1024px) { body { padding-bottom: 0; } }
.callbar__btn {
  flex: 1; display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sp-2); min-height: 48px; border-radius: var(--radius);
  font-weight: 600; font-size: var(--fs-sm); text-decoration: none;
  background: var(--amber); color: var(--ink);
}
.callbar__btn--ghost { background: transparent; color: var(--bone); box-shadow: inset 0 0 0 1px var(--line-dark); }
.callbar__btn svg { width: 18px; height: 18px; }
.callbar__btn { transition: scale 120ms var(--ease-out); }
.callbar__btn:active { scale: .96; }

/* ── PAGE HEAD (inner pages) ─────────────────────────────────── */

.page-head { position: relative; padding: var(--sp-10) 0 var(--sp-9); overflow: hidden; }
.page-head__inner { position: relative; z-index: 1; }
.page-head h1 { max-width: 18ch; }
.page-head .lead { margin-top: var(--sp-5); max-width: 52ch; color: var(--muted-dark); }

/* Every head arrives, same language as the hero. The offsets live in the
   keyframes so a browser with animations off shows the text. */
.page-head h1 { animation: head-rise 700ms var(--ease-out) both; }
.page-head .lead { animation: head-rise 620ms var(--ease-out) 140ms both; }
.page-head .crumbs { animation: head-rise 520ms var(--ease-out) both; }
@keyframes head-rise { from { opacity: 0; translate: 0 26px; } }

/* A photographed head: the image sits under the scrim, drifts on scroll,
   and gives the inner pages the same presence as the hero. */
.page-head--photo { min-height: 44vh; display: flex; align-items: flex-end; padding-bottom: var(--sp-8); }
.page-head__media { position: absolute; inset: 0; z-index: 0; }
.page-head__media img {
  width: 100%; height: 100%; object-fit: cover;
  filter: saturate(1.04) contrast(1.03);
}
.page-head__media::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(180deg, rgba(6,34,48,.62) 0%, rgba(6,34,48,.34) 45%, rgba(6,34,48,.84) 100%),
    linear-gradient(90deg, rgba(6,34,48,.66) 0%, rgba(6,34,48,.18) 70%);
}
.page-head--photo .lead { color: rgba(244, 251, 252, .88); }
.page-head--photo h1, .page-head--photo .lead { text-shadow: 0 1px 14px rgba(6, 34, 48, .5); }

/* A faint chart-grid wash — it is the grid of a chartplotter, which
   is what this shop sells, and it stops flat dark panels reading as
   empty without adding a single word. */
.grid-wash::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(var(--line-dark) 1px, transparent 1px),
    linear-gradient(90deg, var(--line-dark) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(ellipse 80% 70% at 70% 0%, #000 0%, transparent 75%);
  -webkit-mask-image: radial-gradient(ellipse 80% 70% at 70% 0%, #000 0%, transparent 75%);
  opacity: .55;
}

/* ── ARGUMENT BAND ───────────────────────────────────────────
   A full-bleed statement over a dimmed photograph. Used on more
   than one page, so it lives here rather than in a page sheet. */

.band { position: relative; overflow: hidden; padding: var(--sp-11) 0; }
.band__media { position: absolute; inset: 0; z-index: 0; }
.band__media img { width: 100%; height: 100%; object-fit: cover; filter: saturate(1.02); }
.band__media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(6, 34, 48,.96) 0%, rgba(6, 34, 48,.86) 55%, rgba(6, 34, 48,.62) 100%);
}
.band__inner { position: relative; z-index: 1; max-width: 42ch; }
.band h2 { max-width: 17ch; margin-bottom: var(--sp-5); }
.band h2 em { font-style: normal; color: var(--amber); }
.band p { color: rgba(244, 251, 252,.8); max-width: 40ch; }
.band .link { margin-top: var(--sp-6); color: var(--bone); }

/* ── PRINCIPLES / STEPS ──────────────────────────────────────
   Numbered cards, used on the about page and the products page.
   The numerals are set in the data face because they are an index,
   and they sit behind the heading rather than beside it so they
   read as texture. */

.principles { display: grid; gap: var(--sp-5); }
.principles li {
  position: relative; overflow: hidden;
  background: var(--card); border-radius: var(--radius-lg);
  padding: var(--sp-7) var(--sp-6) var(--sp-6);
  box-shadow: var(--shadow-sm);
  transition: transform var(--t-mid) var(--ease-out), box-shadow var(--t-mid) var(--ease-out);
}
.principles li:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }
.principles__num {
  position: absolute; top: -6px; right: var(--sp-4);
  font-family: var(--data); font-size: 3.75rem; font-weight: 600;
  color: rgba(6, 34, 48, .05);
  line-height: 1; pointer-events: none;
}
.principles h3 { margin-bottom: var(--sp-3); padding-right: var(--sp-9); }
.principles p { color: var(--muted-light); font-size: var(--fs-sm); max-width: 36ch; }

/* ── JUMP BAR ────────────────────────────────────────────────
   Sticky lateral nav. Anchors on the services page; page links
   across the products hubs, so it lives here. */

.jump {
  position: sticky; top: var(--nav-h); z-index: 50;
  border-bottom: 1px solid var(--line-light);
  background: rgba(241, 250, 251, .92);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.jump__inner {
  display: flex; gap: var(--sp-6);
  overflow-x: auto; scrollbar-width: none;
  padding-top: var(--sp-3); padding-bottom: var(--sp-3);
  -webkit-overflow-scrolling: touch;
}
.jump__inner::-webkit-scrollbar { display: none; }
.jump a {
  white-space: nowrap;
  font-size: var(--fs-sm); font-weight: 500;
  color: var(--muted-light); text-decoration: none;
  padding: var(--sp-3) 0;
  min-height: 44px; display: inline-flex; align-items: center;
  border-bottom: 2px solid transparent;
  transition: color var(--t-fast), border-color var(--t-fast);
}
.jump a:hover { color: var(--ink-text); border-bottom-color: var(--amber); }
.jump a[aria-current="page"] { color: var(--ink-text); border-bottom-color: var(--amber); }


/* ── RANGE TICKER ────────────────────────────────────────────
   A moving band of the range, straight under the proof strip. Two
   identical runs slide by one run's width, so the loop is seamless.
   Duplicated content is aria-hidden; the animation is off entirely
   for reduced motion, where it simply becomes a static list. */

/* A quiet band, not a highlighter. It ran as a bright aqua-to-amber gradient
   with near-black type; the client called it too bright. It now sits on the
   dark ground the rest of the site uses, so it continues the page head and
   lets the range below it be the loud thing. */
.ticker {
  overflow: hidden;
  padding: var(--sp-5) 0;
  background: var(--ink-2);
  border-block: 1px solid var(--line-dark);
}
.ticker__track { display: flex; width: max-content; animation: ticker 38s linear infinite; }
.ticker__run { display: flex; align-items: center; gap: var(--sp-6); padding-right: var(--sp-6); }
.ticker__run li {
  display: inline-flex; align-items: center; gap: var(--sp-6);
  white-space: nowrap;
  font-family: var(--display); font-weight: 600;
  font-size: var(--fs-base); letter-spacing: -.01em;
  color: var(--muted-dark);
}
.ticker__run li span { color: var(--amber); opacity: .5; font-size: .5em; }
@keyframes ticker { to { transform: translateX(-50%); } }
.ticker:hover .ticker__track { animation-play-state: paused; }

/* ── RANGE CARD ──────────────────────────────────────────────
   The product tile. Used on the home teaser and on the products
   page, so it lives here rather than in a page sheet.

   Deliberately unlike .svc-card, which sits directly above it on
   the home page: paper ground not white, 4px radius not 8, a
   hairline border, no shadow, and a product plate the image sits
   *inside* rather than a photograph cropped to fill. A product
   read as a product, not as another picture of the yard. */

.range-card {
  display: flex; flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--line-light);
  border-radius: var(--radius);
  overflow: hidden;
  text-decoration: none; color: var(--ink-text);
  transition: border-color var(--t-mid) var(--ease-out);
}
/* Only the linked variant reacts — the fifteen tiles on the products
   page go nowhere, so they must not look as though they do. */
a.range-card:hover { border-color: var(--amber); }

.range-card__media {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--card);
  border-bottom: 1px solid var(--line-light);
  display: grid; place-items: center;
  overflow: hidden;
}
/* Placeholder plate. A faint chart grid and the stock icon, so an
   empty frame reads as deliberate rather than broken while the real
   product photography is outstanding. Swapping in a <picture> means
   adding `.range-card__media picture` to the height allowlist above.

   The grid is for the EMPTY state only. Behind a real product it shows
   through the image's padding ring and frames it like a box — the client
   read that as the picture having gridlines and being stretched. */
.range-card__media:has(picture)::before { content: none; }
.range-card__media::before {
  content: ""; position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(6, 34, 48,.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(6, 34, 48,.055) 1px, transparent 1px);
  background-size: 26px 26px;
}
/* The plate is a centring grid for the placeholder icon, so a percentage
   height on a <picture> inside it never resolves against the plate. Take the
   image out of flow instead — the same thing .band__media does. */
.range-card__media picture { position: absolute; inset: 0; }
/* A product is never cropped: contain, with room to breathe. */
.range-card__media img {
  width: 100%; height: 100%;
  object-fit: contain;
  padding: var(--sp-5);
}

.range-card__icon {
  position: relative;
  width: 34px; height: 34px;
  color: rgba(6, 34, 48,.20);
}

.range-card__body { padding: var(--sp-4) var(--sp-4) var(--sp-5); }
/* Smaller than the global h3 — these are labels in a set, not headings. */
.range-card__body h3 { font-size: var(--fs-base); margin-bottom: var(--sp-2); }
.range-card__body p {
  font-size: var(--fs-xs); line-height: 1.6;
  color: var(--muted-light);
}

/* ── CONTACT STRIP ───────────────────────────────────────────── */

.contact-cta { position: relative; overflow: hidden; padding: var(--sp-10) 0; }
.contact-cta__inner { position: relative; z-index: 1; display: grid; gap: var(--sp-8); }
.contact-cta h2 { max-width: 15ch; }
/* A contact detail, not a headline. At --fs-2xl this matched the h2 beside it,
   and mono with negative tracking reads larger still — the client called it
   giant. It also carries the email address on regions with no phone, which is
   a much longer string. */
.contact-cta__phone {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  font-family: var(--data); font-size: var(--fs-lg); font-weight: 500;
  letter-spacing: 0; color: var(--bone); text-decoration: none;
  word-break: break-word;
  transition: color var(--t-fast);
}
.contact-cta__phone:hover { color: var(--amber); }
.contact-cta__phone svg { width: 18px; height: 18px; color: var(--amber); flex: none; }
.contact-cta__meta { margin-top: var(--sp-5); color: var(--muted-dark); }

/* ── FORMS ───────────────────────────────────────────────────── */

.form-row { display: grid; gap: var(--sp-5); }
.form-group { display: flex; flex-direction: column; margin-bottom: var(--sp-5); }
.form-group label { font-size: var(--fs-sm); font-weight: 600; color: var(--muted-light); margin-bottom: var(--sp-2); }
.form-group input, .form-group select, .form-group textarea {
  font-family: var(--body); font-size: var(--fs-base); color: var(--ink-text);
  background: var(--card); padding: var(--sp-3) var(--sp-4);
  min-height: 52px; border: 1px solid var(--line-light); border-radius: var(--radius);
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.form-group textarea { min-height: 170px; resize: vertical; }
.form-group input:focus, .form-group select:focus, .form-group textarea:focus {
  border-color: var(--amber); box-shadow: 0 0 0 3px var(--amber-dim); outline: none;
}
.req { color: #B4462B; }
.form-note { font-size: var(--fs-sm); color: var(--muted-light); margin-top: var(--sp-4); }
.form-honey { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.banner {
  padding: var(--sp-4) var(--sp-5); background: var(--card);
  border-left: 3px solid var(--amber); border-radius: var(--radius);
  box-shadow: var(--shadow-sm); margin-bottom: var(--sp-6);
}

/* ── FOOTER ──────────────────────────────────────────────────── */

.footer { padding: var(--sp-9) 0 var(--sp-7); font-size: var(--fs-sm); }
.footer__grid { display: grid; gap: var(--sp-8); }
.footer__logo { height: 34px; width: auto; margin-bottom: var(--sp-4); }
.footer p { color: var(--muted-dark); max-width: 34ch; }
.footer__dealer { margin-top: var(--sp-4); color: var(--bone); font-weight: 600; }
.footer__head {
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--bone); margin-bottom: var(--sp-4);
}
.footer__list li { margin-bottom: var(--sp-1); }
.footer__link { display: inline-flex; align-items: center; min-height: 44px; min-width: 44px; }
.footer__link { color: var(--muted-dark); text-decoration: none; transition: color var(--t-fast); }
.footer__link:hover { color: var(--amber); }
.footer__bottom {
  margin-top: var(--sp-9); padding-top: var(--sp-5);
  border-top: 1px solid var(--line-dark);
  display: flex; flex-wrap: wrap; gap: var(--sp-4); justify-content: space-between;
  font-size: var(--fs-xs); color: var(--muted-dark);
}

/* Degraded chrome — only if a partial fails to load. */
.fallback-bar { background: var(--ink); color: var(--bone); }
.fallback-bar__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); flex-wrap: wrap; min-height: var(--nav-h);
  padding-top: var(--sp-3); padding-bottom: var(--sp-3);
}
.fallback-bar__brand { font-family: var(--display); font-weight: 700; color: var(--bone); text-decoration: none; }
.fallback-bar__call { color: var(--amber); }
.fallback-foot { background: var(--ink); padding: var(--sp-8) 0; color: var(--muted-dark); }

/* ── SCROLL REVEAL ───────────────────────────────────────────
   Opacity + transform only, so nothing reflows. Content is hidden
   only once JS has confirmed it can reveal it (the .js-reveal class
   is set by script) — a failed script must never blank the page. */

.js-reveal .reveal { opacity: 0; translate: 0 34px; scale: .985; }
.js-reveal .reveal.is-in {
  opacity: 1; translate: 0 0; scale: 1;
  transition: opacity 640ms var(--ease-out), translate 640ms var(--ease-out),
              scale 640ms var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

/* Figures wipe open top-down instead of sliding — clip-path, so it can
   never collide with a transform hover. */
.js-reveal .reveal--wipe { opacity: 1; translate: none; scale: none; clip-path: inset(0 0 100% 0); }
.js-reveal .reveal--wipe.is-in {
  clip-path: inset(0 0 0 0);
  transition: clip-path 900ms var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

/* Parallaxed images oversize slightly so travel never shows an edge.
   The `scale` property, so card hover transforms stay untouched. */
img[data-parallax], [data-parallax] img { scale: 1.14; }

/* ── DEPTH GAUGE ─────────────────────────────────────────────
   The signature: scroll position read out as depth, the way a
   sounder reads the bottom. Injected by main.js, wide screens
   only, skipped for reduced motion. Blend-difference keeps it
   legible over dark and light sections alike. */
.depth {
  position: fixed; right: var(--sp-6); top: 50%; translate: 0 -50%;
  z-index: 60; display: flex; flex-direction: column; align-items: center;
  gap: var(--sp-3); pointer-events: none;
  mix-blend-mode: difference; color: #fff;
}
.depth__track { position: relative; width: 1px; height: 150px; background: rgba(255,255,255,.32); }
.depth__fill { position: absolute; inset: 0; background: #fff; transform-origin: top; scale: 1 0; }
.depth__num { font-family: var(--data); font-size: var(--fs-xs); letter-spacing: .04em; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js-reveal .reveal, .js-reveal .reveal.is-in { opacity: 1; translate: none; transition: none; }
  .nav__menu.is-open .nav__menu-link { animation: none; opacity: 1; transform: none; }
  .ticker__track { animation: none; }
  .btn:hover, .btn:active { transform: none; }
  .js-reveal .reveal--wipe, .js-reveal .reveal--wipe.is-in { clip-path: none; transition: none; }
  img[data-parallax], [data-parallax] img { scale: none; }
  .hero__line > span, .hero__side { animation: none; }
  .page-head h1, .page-head .lead, .page-head .crumbs { animation: none; }
  .nav--hidden { translate: none; }
  .nav__menu.is-open .nav__menu-link,
  .nav__menu.is-open .nav__menu-foot { animation: none; opacity: 1; transform: none; }
  .footer__link:hover { translate: none; }
  .callbar__btn:active { scale: none; }
}

/* ── RESPONSIVE ──────────────────────────────────────────────── */

@media (min-width: 600px) {
  :root { --fs-2xl: 2.5rem; --fs-3xl: 3.4rem; }
  .container { padding: 0 var(--sp-6); }
}

@media (min-width: 900px) {
  :root { --fs-xl: 1.75rem; --fs-2xl: 3rem; --fs-3xl: 4.4rem; }
  .principles { grid-template-columns: repeat(3, 1fr); gap: var(--sp-6); }
  .container { padding: 0 var(--sp-7); }
  .section { padding: var(--sp-11) 0; }
  .form-row { grid-template-columns: 1fr 1fr; }
  .footer__grid { grid-template-columns: 1.7fr 1fr 1fr 1.2fr; }
  .contact-cta__inner { grid-template-columns: 1.1fr 1fr; align-items: center; }
}

@media (min-width: 1024px) {
  .nav__links { display: flex; }
  /* The initials pair rides at the far right of the links row. */
  .nav__links .region { display: flex; margin-left: var(--sp-2); }
  .nav__stamp { display: block; }
  .nav__call, .nav__burger { display: none; }
  .nav__menu { display: none !important; }
  .callbar { display: none; }
}

@media (min-width: 1200px) {
  :root { --fs-3xl: 5rem; }
}

/* Gauge never shows on narrow screens even if injected before a resize. */
@media (max-width: 1199px) { .depth { display: none; } }

/* ── QUOTE LIST ──────────────────────────────────────────────
   Gather products across the range, then hand the list to WhatsApp (or email
   where no WhatsApp number exists) as a prefilled quote request. No prices
   anywhere: the customer is asking what it costs, which is the whole point.
   Sits above the sticky call bar so the two never overlap. */
.quote {
  position: fixed; right: var(--sp-5); bottom: var(--sp-5);
  z-index: 60;
  display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-3);
}
.quote__toggle {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  background: var(--ink-2); color: var(--bone);
  border: 0; border-radius: var(--radius);
  padding: var(--sp-3) var(--sp-5);
  font-weight: 600; font-size: var(--fs-sm);
  box-shadow: 0 10px 30px rgba(6, 34, 48, .45), inset 0 0 0 1px var(--line-dark);
}
.quote__count {
  font-family: var(--data); font-size: var(--fs-xs);
  background: var(--amber); color: var(--ink);
  border-radius: 999px; min-width: 22px; padding: 1px 6px; text-align: center;
}
.quote__panel {
  width: min(340px, calc(100vw - var(--sp-7)));
  background: var(--ink-2); color: var(--bone);
  border-radius: var(--radius);
  box-shadow: 0 20px 50px rgba(6, 34, 48, .5), inset 0 0 0 1px var(--line-dark);
  padding: var(--sp-5);
}
.quote__head { font-weight: 700; margin-bottom: var(--sp-4); }
.quote__list { display: grid; gap: var(--sp-2); max-height: 46vh; overflow-y: auto; }
.quote__item {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4);
  font-size: var(--fs-sm);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--line-dark);
}
.quote__remove {
  background: none; border: 0; padding: 0;
  color: var(--muted-dark); font-size: var(--fs-xs);
  text-decoration: underline; flex: none;
}
.quote__remove:hover { color: var(--bone); }
.quote__actions { display: flex; align-items: center; gap: var(--sp-4); margin-top: var(--sp-5); }
.quote__clear { background: none; border: 0; color: var(--muted-dark); font-size: var(--fs-xs); text-decoration: underline; }
.quote__clear:hover { color: var(--bone); }
.quote__note { margin-top: var(--sp-4); font-size: var(--fs-xs); color: var(--muted-dark); }


@media (max-width: 599px) {
  .quote { right: var(--sp-4); bottom: 84px; }
}

/* ── PRODUCT LINES (family leaf pages) ───────────────────────
   The level below the category hub: each product line with its variants as
   chips. A chip is the only thing on the site that can enter the quote list,
   because "Axiom" is not something anyone can price — "Axiom 2 Pro RVM 12in"
   is. Generated by scripts/build-range.mjs from content/range.json. */
.line-list { display: grid; gap: var(--sp-5); margin-top: var(--sp-8); }
.line {
  display: grid; gap: var(--sp-4) var(--sp-5);
  grid-template-columns: 64px 1fr;
  align-items: start;
  padding: var(--sp-6);
  background: var(--card);
  border: 1px solid var(--line-light);
  border-radius: var(--radius);
}
/* A picture of the line. The client asked for it because these are genuinely
   different products - an i70s looks nothing like an i50 - and a column of
   identically-set headings gives a reader nothing to recognise. */
.line__thumb {
  width: 64px; height: 64px;
  display: grid; place-items: center;
  background: var(--paper);
  border: 1px solid var(--line-light);
  border-radius: var(--radius);
  overflow: hidden;
}
.line__thumb img { width: 100%; height: 100%; object-fit: contain; }
.line__thumb--empty svg { width: 22px; height: 22px; color: rgba(6, 34, 48, .18); }
.line__head h3 { margin-bottom: var(--sp-2); }
.line__head p { color: var(--muted-light); max-width: 60ch; font-size: var(--fs-sm); }
.line__variants { display: flex; flex-wrap: wrap; gap: var(--sp-3); grid-column: 1 / -1; }

/* Lifted above any stretched whole-card link. The category tiles already hit
   this once: a button sitting under a card's stretched ::after navigates to
   the card's href instead of firing its own handler. */
.variant {
  position: relative; z-index: 2;
  font-family: var(--data); font-size: var(--fs-sm);
  color: var(--ink-text);
  background: var(--paper);
  border: 1px solid var(--line-light);
  border-radius: var(--radius);
  padding: var(--sp-3) var(--sp-5);
  min-height: 44px;
  transition: border-color var(--t-fast), background var(--t-fast), color var(--t-fast);
}
.variant:hover { border-color: var(--ink-3); }
.variant.is-added {
  background: var(--amber); border-color: var(--amber); color: var(--ink);
  font-weight: 600;
}
.variant.is-added::before { content: "¹3  "; }

.line-foot {
  margin-top: var(--sp-7);
  color: var(--muted-light); font-size: var(--fs-sm);
  max-width: 66ch;
}

@media (min-width: 800px) {
  .line { grid-template-columns: 72px 1.1fr 1fr; gap: var(--sp-6); align-items: center; }
  .line__thumb { width: 72px; height: 72px; }
  /* The full-width span is a mobile arrangement; here the chips share the row. */
  .line__variants { grid-column: auto; justify-content: flex-end; }
}
