:root {
  --black: #111111;
  /* The ink as an rgb triple, because rgba() cannot take a hex custom
     property. Every rgba(var(--ink-rgb), ...) below depends on this line
     existing: an rgba() whose variable is undefined is invalid at
     computed-value time, which resolves to transparent rather than falling
     back to an earlier declaration. That is exactly how the header lost its
     background and put white nav text on a cream hero. */
  --ink-rgb: 17, 17, 17;
  --ink-raised: #141414;
  --card-dark: #1a1a1e;
  --card-border: #35353a;
  --on-dark-muted: #C9C9CC;

  /* Glass. Deliberately only three of these: backdrop-filter makes the browser
     sample and blur what is behind the element on every frame it moves, so it
     is cheap on a handful of things and expensive on a grid of nine. It also
     only SHOWS where something varied sits behind it — over a flat fill it is
     an invisible cost. Both are why it is on the ghost button, the contact
     form and the quote card, and nowhere else. */
  --glass-blur: blur(14px) saturate(1.35);
  --glass-light: rgba(255, 255, 255, 0.55);
  --glass-dark: rgba(255, 255, 255, 0.045);
  --charcoal: #222226;
  --gold: #E8B923;
  --gold-light: #F5D566;
  --gold-dark: #C79A15;
  /* The same gold taken down until it clears 4.5:1 on cream. --gold-dark is
     2.45:1 there, which is fine as a border or an underline and is not fine as
     text — and the adaptive header puts the current-page link in it the moment
     the bar passes over a light section. Used only where the accent has to be
     read as type on a light ground. */
  --gold-ink: #81650D;
  --gold-soft: rgba(232, 185, 35, 0.12);
  /* The cycling word in the hero headline. --gold is 1.74:1 on cream and
     --gold-dark is 2.45:1 — both fail the 3:1 that large display type needs,
     and this is the biggest, boldest thing on the page. --gold-ink (5.21:1)
     passes but reads olive-brown and throws away the point of an accent. This
     is 3.47:1: the brightest gold that still clears the bar. */
  --gold-hero: #A87F0E;

  /* Picture framing. One radius and one shadow for every photograph on the
     site, so the hero strips and the service cards are visibly the same
     treatment rather than two near-misses. The shadow is two layers on
     purpose: a tight dark one for the contact edge, a wide soft one for the
     lift. A single blur does one or the other, never both. */
  --frame-radius: 12px;
  --shadow-frame: 0 1px 2px rgba(17, 17, 17, 0.07), 0 14px 30px -10px rgba(17, 17, 17, 0.22);
  --cream: #FAF8F3;
  --gray: #6B6B6F;
  --gray-light: #9A9A9E;
  --border: #E8E6DF;
  --radius: 10px;
  --radius-lg: 16px;
  --max-width: 1160px;
  /* The one gutter every row on the site starts from.

     It reproduces what the old centred 1160px container gave a section — at
     1512 that is exactly 200px, at 1200 exactly 44px — so unifying the site on
     this line brings the header, hero and brand band IN to meet the sections,
     rather than pushing the sections out to the screen edges. Capped at 260 so
     a wide monitor does not strand everything in a narrow column down the
     middle the way a plain centred container would at 724px. */
  --edge: clamp(24px, calc((100vw - 1160px) / 2 + 24px), 260px);
  --hero-copy: clamp(440px, 44vw, 620px);   /* the hero copy column; the photo panel takes the rest */   /* the hero's left column; the render takes the rest */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --shadow-sm: 0 1px 2px rgba(var(--ink-rgb), 0.04), 0 1px 3px rgba(var(--ink-rgb), 0.03);
  --shadow-md: 0 8px 24px rgba(var(--ink-rgb), 0.07), 0 2px 6px rgba(var(--ink-rgb), 0.04);
  --shadow-lg: 0 24px 48px rgba(var(--ink-rgb), 0.14), 0 8px 16px rgba(var(--ink-rgb), 0.06);
  --shadow-gold: 0 10px 24px rgba(199, 154, 21, 0.28);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; }

body {
  font-family: "Manrope", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--black);
  background: #fff;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

.container {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 24px;
}

h1, h2, h3 { line-height: 1.15; font-weight: 800; letter-spacing: -0.02em; }
h2 { font-size: clamp(1.7rem, 3vw, 2.4rem); margin-bottom: 14px; }
h3 { font-size: 1.15rem; margin-bottom: 10px; }
p { color: var(--gray); }

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

::selection { background: var(--gold); color: var(--black); }

a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--gold-dark);
  outline-offset: 3px;
  border-radius: 4px;
}

.section-sub {
  color: var(--gray);
  max-width: 560px;
  margin-bottom: 48px;
  font-size: 1.05rem;
}

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 22px;
  border-radius: 999px;
  font-weight: 700;
  font-size: 0.95rem;
  cursor: pointer;
  border: 2px solid transparent;
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease), background 0.2s var(--ease), color 0.2s var(--ease);
  white-space: nowrap;
}
.btn-primary {
  background: var(--gold);
  color: var(--black);
  box-shadow: var(--shadow-sm);
}
.btn-primary:hover {
  background: var(--gold-dark);
  transform: translateY(-2px);
  box-shadow: var(--shadow-gold);
}
.btn-primary:active {
  transform: translateY(0);
  box-shadow: var(--shadow-sm);
}
/* The frost alone did nothing here. The hero behind this button is very nearly
   flat cream, and a blur with nothing to blur is just a pale fill — Caleb
   spotted that it did not read as glass at all.

   Glass is legible because of what it does to light, not because of the blur:
   a bright edge along the top where it catches, and colour thrown onto the
   surface beneath it. So the frost stays for the browsers that show it, and
   the gold glow underneath plus the inset highlight along the top do the
   actual work. Those two need nothing behind them to be visible. */
.btn-ghost {
  background: var(--glass-light);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-color: rgba(var(--ink-rgb), 0.42);
  color: var(--black);
  box-shadow:
    /* colour cast onto the page beneath, as a pane of tinted glass would */
    0 8px 22px -6px rgba(232, 185, 35, 0.55),
    0 2px 6px rgba(var(--ink-rgb), 0.06),
    /* the lit top edge, which is the part the eye reads as glass */
    inset 0 1px 0 rgba(255, 255, 255, 0.9);
}
.btn-ghost:hover {
  background: var(--black);
  color: #fff;
  transform: translateY(-2px);
  /* the glow warms and spreads as it lifts, rather than being swapped for a
     neutral shadow that would read as a different button */
  box-shadow:
    0 12px 28px -6px rgba(232, 185, 35, 0.7),
    0 4px 10px rgba(var(--ink-rgb), 0.14);
}
.btn-ghost:active {
  transform: translateY(0);
  box-shadow: 0 4px 12px -4px rgba(232, 185, 35, 0.5);
}
/* The ghost button on the hero. Its light pane and dark type were drawn for a
   cream ground; on the scrim that is a white lozenge shouting louder than the
   gold primary beside it, which inverts the two buttons' importance. Here it
   is the outline it is meant to be — and the frost finally has something worth
   blurring behind it, which the cream version never did. */
.hero .btn-ghost {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.55);
  color: #fff;
  box-shadow:
    0 8px 22px -6px rgba(17, 17, 17, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.28);
}
.hero .btn-ghost:hover {
  background: #fff;
  color: var(--black);
  box-shadow:
    0 12px 28px -6px rgba(232, 185, 35, 0.5),
    0 4px 10px rgba(17, 17, 17, 0.35);
}

.btn-lg { padding: 15px 30px; font-size: 1rem; }
.btn-block { width: 100%; }
.btn-nav { display: inline-flex; }

/* Header */
.site-header {
  /* sticky also makes this the containing block the open menu hangs off */
  position: sticky;
  top: 0;
  background: rgba(255,255,255,0.92);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
  z-index: 100;
  transition: box-shadow 0.25s var(--ease), border-color 0.25s var(--ease);
}
.site-header.is-scrolled {
  box-shadow: 0 4px 20px rgba(var(--ink-rgb), 0.06);
  border-bottom-color: transparent;
}
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 14px;
  padding-bottom: 14px;
  gap: 24px;
}
.logo {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  background: var(--black);
  border-radius: 8px;
  /* Sized to fill the header, not to grow it. The bar's height is set by the
     tallest thing in it — the CTA button at 52px — so the logo pill is built
     to match that exactly and the banner does not move.

     Uses retailmark-wordmark.png, which is the master logo cropped to its ink.
     The master has the padding baked in: the wordmark is only 49% of that
     file's height, so setting a height on it sized mostly empty space and left
     the mark stranded in the middle of the black pill. Do not swap this back
     to retailmark-logo.png without re-tuning the numbers below. */
  padding: 10px 14px;
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.logo:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-sm);
}
.main-nav {
  display: flex;
  gap: clamp(18px, 1.7vw, 28px);
  flex: 1;
  justify-content: center;
}
.main-nav a {
  position: relative;
  /* "Why Us" is two words and wrapped to two lines the moment the bar got
     tight, which reads as a broken header rather than as a full one. The bar
     runs out of room instead, and the breakpoints below handle that. */
  white-space: nowrap;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--charcoal);
  padding: 4px 0;
  transition: color 0.2s var(--ease);
}
.main-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 100%;
  bottom: -2px;
  height: 2px;
  background: var(--gold-dark);
  border-radius: 2px;
  transition: right 0.25s var(--ease);
}
.main-nav a:hover { color: var(--gold-dark); }
.main-nav a:hover::after { right: 0; }
.nav-toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 4px;
}
.nav-toggle span {
  width: 24px;
  height: 2px;
  background: var(--black);
  border-radius: 2px;
  transition: transform 0.2s var(--ease), opacity 0.2s var(--ease);
}

/* Hero */
.hero {
  padding: 104px 0 76px;
  /* Tall enough to give the photograph room to be a photograph. Under this it
     is a letterbox strip behind some type rather than a picture of a store. */
  min-height: min(88vh, 1200px);
  display: flex;
  align-items: center;
  /* The ground behind the photographs, so a cross-fade never dissolves to
     white and the hero is still a dark block if the images never arrive. */
  background: #2B2B2E;
  color: #fff;
  position: relative;
  overflow: hidden;
}

/* --------------------------------------------------------------------------
   The hero photograph, and the grey over it
   A stack of store interiors cross-fading in place, with a scrim on top. The
   scrim is the whole reason the type is readable: a photograph of a lit
   supermarket is bright, busy and high-contrast everywhere, which is the worst
   possible ground for white text.

   It is a gradient rather than a flat wash, and left-weighted, so the copy
   column sits on something near-solid while the right side of the frame stays
   a picture. A flat 85% wash over the whole thing reads as a grey rectangle
   that happens to have a photo in it; this reads as a photograph the type is
   standing on.
   -------------------------------------------------------------------------- */
.hero-bg { position: absolute; inset: 0; z-index: 0; }
.hero-bg img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Greyscale here rather than baked into the files, as everywhere else on the
     site: one asset serves either decision. The lift stops the darker frames
     going muddy once the scrim is over them. */
  filter: grayscale(1) contrast(1.06) brightness(1.02);
  opacity: 0;
  transition: opacity 1.25s var(--ease);
}
.hero-bg img.on { opacity: 1; }
/* before the script runs, and if it never does, hold the first frame */
.hero-bg img:first-child { opacity: 1; }

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    /* the grey, heaviest under the copy and thinning across the frame */
    linear-gradient(100deg,
      rgba(30, 30, 33, 0.95) 0%,
      rgba(30, 30, 33, 0.93) 34%,
      rgba(30, 30, 33, 0.78) 58%,
      rgba(30, 30, 33, 0.55) 82%,
      rgba(30, 30, 33, 0.48) 100%),
    /* a little extra under the header, which is a black bar over a photograph
       that might be pale at the top, and along the bottom edge where the hero
       meets the next band */
    linear-gradient(to bottom,
      rgba(17, 17, 17, 0.5) 0%,
      rgba(17, 17, 17, 0) 22%,
      rgba(17, 17, 17, 0) 78%,
      rgba(17, 17, 17, 0.45) 100%);
}

/* Narrow enough and there is no room for a photograph beside the copy — the
   type runs most of the width, so the scrim has to run all of it. 900 rather
   than a phone breakpoint because that is where the copy column stops being
   capped and starts reaching into the part of the frame the picture shows
   through: at 768 the last words of the paragraph were sitting on a lit shelf.
   */
@media (max-width: 900px) {
  .hero::after {
    background:
      linear-gradient(180deg,
        rgba(24, 24, 27, 0.92) 0%,
        rgba(24, 24, 27, 0.9) 60%,
        rgba(24, 24, 27, 0.94) 100%);
  }
}
.hero-inner { position: relative; }
.hero-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--black);
  color: var(--gold);
  /* Driven by the SAME 29vw as the pill's width below, which is the whole
     trick: the two then clamp at the same viewport widths and the line fills
     the same fraction of the pill at every size. Given its own vw coefficient
     the font hit its floor at 1042 while the pill was still growing from 875,
     so between those the text sat marooned in a widening bubble — 0.93 full on
     a phone and 0.82 on a desktop. When the lockup grew from 24vw to 29vw
     every number here was scaled by that same 1.208, floor and ceiling
     included, which is what preserved it: font over pill went 14.08/330 to
     17.12/400, and measured across 390 to 2560 the fill is now flat to three
     decimals. Change one and change all three. */
  font-size: clamp(0.68rem, 1.24vw, 1.07rem);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  padding: 8px clamp(12px, 1.1vw, 16px);
  border-radius: 999px;
  margin-bottom: 26px;
  box-shadow: var(--shadow-md);
  /* The same width as the wordmark above it, so the two read as one lockup
     rather than as a mark with a smaller unrelated tag underneath. Identical
     expression to .hero-logo's width — change one and change both. */
  width: clamp(255px, 29vw, 400px);
}
.hero h1 {
  font-size: clamp(2.1rem, 5vw, 3.4rem);
  margin-bottom: 22px;
  /* Evens the lines out instead of filling the first one and dropping whatever
     is left onto the second. A short headline is exactly where the default
     leaves a single orphaned word. */
  text-wrap: balance;
}

/* --------------------------------------------------------------------------
   The cycling word in the headline
   Pure CSS, no script: the words are stacked in one grid cell and take turns.
   Stacked rather than swapped by JS because the cell is then as wide as the
   longest word from first paint, so the line never reflows mid-cycle and the
   headline below it never jumps. It also means the fallback is the finished
   thing rather than a blank space, if the CSS is all that arrives.
   -------------------------------------------------------------------------- */
.cycle { position: relative; display: inline-grid; vertical-align: bottom; }

/* The headline's real text. The rotating words are decoration on top of one
   fixed sentence, so a screen reader gets that sentence once, not five. */
.cycle-sr {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.cycle-track { display: inline-grid; }
.cycle-track > span {
  grid-area: 1 / 1;
  justify-self: start;
  white-space: nowrap;
  /* --gold-hero is the gold taken down until it clears 3:1 on cream. The hero
     is not cream any more: on the scrim that value reads as brown and the full
     --gold is 8.9:1. Anywhere else this class lands on a light ground, so the
     variable stays and the hero overrides it. */
  color: var(--gold-hero);
  opacity: 0;
  /* 5 words x 3.5s. Each holds for about three seconds and takes half of one
     to trade places with the next. */
  animation: cycle-word 17.5s infinite;
}
.cycle-track > span:nth-child(2) { animation-delay:  3.5s; }
.cycle-track > span:nth-child(3) { animation-delay:  7s; }
.cycle-track > span:nth-child(4) { animation-delay: 10.5s; }
.cycle-track > span:nth-child(5) { animation-delay: 14s; }

@keyframes cycle-word {
  0%   { opacity: 0; transform: translateY(0.3em); }
  3%   { opacity: 1; transform: none; }
  17%  { opacity: 1; transform: none; }
  20%  { opacity: 0; transform: translateY(-0.3em); }
  100% { opacity: 0; transform: translateY(0.3em); }
}

/* A word that changes itself every three seconds beside text someone is trying
   to read is the exact thing this setting is for. One word, held. */
.hero .cycle-track > span { color: var(--gold); }

@media (prefers-reduced-motion: reduce) {
  .cycle-track > span { animation: none; opacity: 0; transform: none; }
  .cycle-track > span:first-child { opacity: 1; }
}
.hero-sub {
  font-size: 1.15rem;
  margin-bottom: 36px;
  /* Not --gray. That is a mid grey picked to sit on cream; on the scrim it is
     nearly the same value as its ground and the paragraph disappears. */
  color: var(--on-dark-muted);
}
.hero-cta { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 60px; }
.hero-stats {
  display: flex;
  gap: 28px 34px;
  flex-wrap: wrap;
  /* the rule is a hairline of the page showing through, so on a dark hero it
     is white at low alpha rather than the cream --border, which would draw a
     bright line across the picture */
  border-top: 1px solid rgba(255, 255, 255, 0.2);
  padding-top: 30px;
}
.hero-stats div { display: flex; flex-direction: column; gap: 4px; }
.hero-stats strong { font-size: 1.2rem; letter-spacing: -0.01em; color: #fff; }
.hero-stats span { font-size: 0.85rem; color: var(--on-dark-muted); }

/* Logos strip */
.logos-strip { padding: 36px 0; border-bottom: 1px solid var(--border); }
.logos-label {
  text-align: center;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--gray);
  margin-bottom: 18px;
}
.logos-row {
  display: flex;
  justify-content: center;
  gap: 48px;
  flex-wrap: wrap;
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--charcoal);
}
.logos-row span {
  opacity: 0.6;
  transition: opacity 0.2s var(--ease), color 0.2s var(--ease);
}
.logos-row span:hover {
  opacity: 1;
  color: var(--gold-dark);
}

/* Services */
.services { padding: 96px 0; }
.service-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
}
.service-card {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  /* No padding: the photo is a banner and has to reach the card's own edges.
     The title block below supplies its own. overflow:hidden is what makes the
     photo take the border-radius, and what keeps the hover zoom inside it. */
  padding: 0;
  overflow: hidden;
  /* The same shadow the hero strips carry, for the same reason: it is the only
     thing giving a grey photograph an edge now that there is no mat. */
  box-shadow: var(--shadow-frame);
  transition: box-shadow 0.25s var(--ease), transform 0.25s var(--ease), border-color 0.25s var(--ease);
}
.service-card:hover {
  box-shadow: var(--shadow-lg);
  transform: translateY(-4px);
  border-color: rgba(232, 185, 35, 0.4);
}

/* The photo. aspect-ratio holds the row heights level before the image has
   loaded, so nine cards do not reflow one at a time on a slow connection. */
.service-media {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--gold-soft);   /* what shows while the WebP is in flight */
}
.service-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Same treatment the Bentonville strip and the platform logos get: grey at
     rest so nine different stock photos read as one set rather than nine
     moods, colour on hover so the card answers the cursor. */
  filter: grayscale(1) contrast(1.04);
  transform: scale(1.001);        /* pre-promotes the layer; kills the 1px
                                     seam some WebKit builds show on zoom */
  transition: filter 0.35s var(--ease), transform 0.5s var(--ease);
}
.service-card:hover .service-media img,
.service-card:focus-visible .service-media img {
  filter: grayscale(0) contrast(1);
  transform: scale(1.05);
}

/* The number rides on the photo now. Absolute, so it does not push the title
   down, and the scrim behind it is what keeps it legible over a dark frame. */
.service-icon {
  position: absolute;
  top: 12px;
  left: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.92);
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.18);
  font-weight: 800;
  color: var(--gold-dark);
  font-size: 0.85rem;
  transition: background 0.25s var(--ease), transform 0.25s var(--ease);
}
.service-card:hover .service-icon {
  background: var(--gold);
  color: var(--black);
  transform: scale(1.06);
}
.service-card h3 {
  margin: 0;
  padding: 18px 46px 20px 22px;   /* right side is the arrow's lane */
  font-size: 1.06rem;
  line-height: 1.25;
  transition: color 0.2s var(--ease);
}

/* The cards are links, so they have to look like one before the cursor
   arrives. The arrow is the affordance a hover-lift alone does not give a
   touch screen, where there is no hover at all. */
a.service-card {
  display: block;
  color: inherit;
  text-decoration: none;
  position: relative;
}
a.service-card h3 { color: var(--black); }
a.service-card:hover h3, a.service-card:focus-visible h3 { color: var(--gold-dark); }
a.service-card::after {
  content: "\2192";
  position: absolute;
  right: 20px;
  /* Pinned to the title row, not the card: the card's bottom is now wherever
     the longest title in the row put it. */
  bottom: 20px;
  font-size: 1.05rem;
  line-height: 1;
  color: var(--gold-dark);
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity 0.25s var(--ease), transform 0.25s var(--ease);
}
a.service-card:hover::after, a.service-card:focus-visible::after {
  opacity: 1;
  transform: none;
}
a.service-card:focus-visible {
  outline: 2px solid var(--gold-dark);
  outline-offset: 3px;
}

/* Coarse pointers never hover, so the arrow is simply always there. */
@media (hover: none) {
  a.service-card::after { opacity: 0.55; transform: none; }
}

/* The hover zoom is the one bit of motion in the card. Greyscale-to-colour is
   a colour change, not movement, so it stays. */
@media (prefers-reduced-motion: reduce) {
  .service-media img,
  .service-card:hover .service-media img,
  .service-card:focus-visible .service-media img { transform: none; }
}

/* Why */
.why {
  background: var(--black);
  color: #fff;
  padding: 96px 0;
  /* the badge hangs off this, outside the content measure */
  position: relative;
}

/* --------------------------------------------------------------------------
   The Bentonville badge on the Why band
   It sits in the gutter, not in the grid. The band's content is capped at
   --content-max and sits on the left edge, so on a wide screen there is a
   long empty right side and on a laptop there is none at all. Putting the
   badge in the grid would take its width out of the copy and the quote card
   at every size, to fill space that only exists at some of them.

   1460 is measured, not chosen. Below 1400 the content already runs to the
   right gutter and there is no space to sit in at all; 1460 is the first width
   where the badge clears the content and still keeps a margin from the screen
   edge. Re-measure it if --content-max, --edge or the badge width changes.

   It also has to sit outside .why-inner. That element carries a transform
   from the scroll-reveal, and a transform makes an element the containing
   block for anything absolute inside it, so from in there `right: var(--edge)`
   pins to the 1400px measure rather than to the section.
   -------------------------------------------------------------------------- */
.why-badge { display: none; }

@media (min-width: 1460px) {
  .why-badge {
    display: block;
    position: absolute;
    /* Anchored to the right end of the content, not to the right end of the
       screen. Pinned to the gutter it sat 470px clear of the quote card at
       1920 and 1000px clear at 2560, which reads as something that fell off
       the layout rather than part of it. */
    left: calc(min(100vw, var(--content-max)) - var(--edge) + 56px);
    top: 50%;
    /* the `translate` property, not `transform`. The scroll-reveal animates
       transform and settles it to `none`, which silently threw the centring
       away and dropped the badge half its own height. These two compose. */
    translate: 0 -50%;
    width: 136px;
    height: auto;
  }
}
.why-inner {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: 56px;
  align-items: center;
}
.why h2 { color: #fff; }
.why-list { list-style: none; display: flex; flex-direction: column; gap: 20px; margin: 26px 0 32px; }
.why-list li { color: #C9C9CC; font-size: 0.98rem; }
.why-list strong { color: #fff; display: block; margin-bottom: 3px; }
.why-card {
  background: var(--glass-dark);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(255, 255, 255, 0.11);
  border-radius: var(--radius-lg);
  padding: 38px;
  box-shadow: 0 30px 60px rgba(0,0,0,0.35);
  transition: transform 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
.why-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 36px 72px rgba(0,0,0,0.4);
}
.quote {
  color: var(--gold);
  font-size: 1.3rem;
  font-weight: 600;
  line-height: 1.45;
}

/* Partners */
.partners { padding: 96px 0; text-align: center; }
.partners .section-sub { margin-left: auto; margin-right: auto; }
.partner-row {
  display: flex;
  justify-content: center;
  gap: 40px;
  flex-wrap: wrap;
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--charcoal);
}
.partner-row span {
  opacity: 0.65;
  transition: opacity 0.2s var(--ease), color 0.2s var(--ease), transform 0.2s var(--ease);
}
.partner-row span:hover {
  opacity: 1;
  color: var(--gold-dark);
  transform: translateY(-2px);
}

/* Contact */
.contact { background: var(--cream); padding: 96px 0; }
.contact-inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 56px;
}
.contact-copy p { margin: 14px 0 30px; font-size: 1.05rem; }
.contact-details { display: flex; flex-direction: column; gap: 18px; }
.contact-details span {
  display: block;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--gray);
  margin-bottom: 2px;
}
.contact-details a {
  font-weight: 700;
  font-size: 1.05rem;
  transition: color 0.2s var(--ease);
}
.contact-details a:hover { color: var(--gold-dark); }
/* The gold accent panel sits behind this form's top-right corner. Solid white
   hid it; frosted, the gold reads through the glass, which is the one place on
   the page where the effect has something worth showing. */
.contact-form {
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(255, 255, 255, 0.8);
  border-radius: var(--radius-lg);
  padding: 32px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  box-shadow: var(--shadow-lg);
}
.contact-form label {
  display: flex;
  flex-direction: column;
  gap: 7px;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--charcoal);
}
.contact-form input,
.contact-form textarea {
  font-family: inherit;
  font-size: 0.95rem;
  color: var(--black);
  padding: 12px 14px;
  border: 1.5px solid var(--border);
  border-radius: 8px;
  background: var(--cream);
  resize: vertical;
  transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease), background 0.2s var(--ease);
}
.contact-form input:hover,
.contact-form textarea:hover {
  border-color: var(--gray-light);
}
.contact-form input:focus,
.contact-form textarea:focus {
  outline: none;
  border-color: var(--gold-dark);
  background: #fff;
  box-shadow: 0 0 0 4px var(--gold-soft);
}
.contact-form button[type="submit"]:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  transform: none;
}
.form-note { font-size: 0.85rem; color: var(--gold-dark); min-height: 1em; transition: opacity 0.2s var(--ease); }

/* Footer */
.site-footer { padding: 28px 0; border-top: 1px solid var(--border); }
.footer-top {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: 56px;
  max-width: var(--content-max);
  padding-bottom: 44px;
}
/* Set, not placed. The wordmark PNG is white "Retail" plus gold "Mark", drawn
   for the black header; on the light footer the white half simply vanishes.
   Boxing it in a black chip is what the header was deliberately changed away
   from, so the footer sets the name in the site's own typeface instead. */
.footer-wordmark {
  display: inline-block;
  font-weight: 800;
  font-size: 1.44rem;
  letter-spacing: -0.02em;
  color: var(--black);
  margin-bottom: 18px;
}
.footer-wordmark span { color: var(--gold-dark); }
.footer-brand p {
  font-size: 0.92rem;
  color: var(--gray);
  max-width: 380px;
  margin-bottom: 22px;
}
.footer-col h2 {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--black);
  margin-bottom: 18px;
}
.footer-col a { display: block; }
.footer-col a, .footer-contact a {
  color: var(--gray);
  transition: color 0.2s var(--ease);
}
.footer-col a:hover, .footer-contact a:hover { color: var(--gold-dark); }
.footer-col > a { padding: 5px 0; font-size: 0.92rem; color: var(--gray); }
.footer-col > a:hover { color: var(--gold-dark); }

.footer-contact { list-style: none; padding: 0; margin: 0; font-size: 0.92rem; }
.footer-contact li { margin-bottom: 14px; color: var(--gray); }
.footer-contact span {
  display: block;
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--gray-light);
  margin-bottom: 1px;
}

.footer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
  padding-top: 22px;
  border-top: 1px solid var(--border);
  font-size: 0.85rem;
  color: var(--gray);
}

/* The build credit. A plain brand name, linked once per page and not stuffed
   with keywords, which is the pattern Google treats as a credit rather than as
   a link scheme. */
.footer-credit a {
  color: var(--charcoal);
  font-weight: 600;
  /* A resting underline, faint. Sat in grey with no rule it was the same
     colour and weight as the copyright line beside it, so the one thing on
     the page that is meant to be clicked did not look clickable. */
  border-bottom: 1px solid rgba(107, 107, 111, 0.4);
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.footer-credit a:hover, .footer-credit a:focus-visible {
  color: var(--gold-dark);
  border-bottom-color: currentColor;
}

@media (max-width: 940px) {
  .footer-top { grid-template-columns: 1fr 1fr; gap: 36px; }
  .footer-brand { grid-column: 1 / -1; }
}
@media (max-width: 620px) {
  .footer-top { grid-template-columns: 1fr; gap: 30px; }
  .footer-bottom { flex-direction: column; align-items: flex-start; gap: 8px; }
}
.footer-badge {
  display: inline-flex;
  align-items: center;
  background: var(--black);
  border-radius: 6px;
  padding: 6px 10px;
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.footer-badge:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-sm);
}
.footer-badge img {
  height: 28px;
  width: auto;
  display: block;
}

/* Scroll reveal */
.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}
.reveal.in-view {
  opacity: 1;
  transform: translateY(0);
}
.reveal-stagger.in-view .service-card {
  animation: reveal-fade 0.6s var(--ease) both;
}
.reveal-stagger.in-view .service-card:nth-child(1) { animation-delay: 0.02s; }
.reveal-stagger.in-view .service-card:nth-child(2) { animation-delay: 0.06s; }
.reveal-stagger.in-view .service-card:nth-child(3) { animation-delay: 0.1s; }
.reveal-stagger.in-view .service-card:nth-child(4) { animation-delay: 0.14s; }
.reveal-stagger.in-view .service-card:nth-child(5) { animation-delay: 0.18s; }
.reveal-stagger.in-view .service-card:nth-child(6) { animation-delay: 0.22s; }
.reveal-stagger.in-view .service-card:nth-child(7) { animation-delay: 0.26s; }
.reveal-stagger.in-view .service-card:nth-child(8) { animation-delay: 0.3s; }
.reveal-stagger.in-view .service-card:nth-child(9) { animation-delay: 0.34s; }
@keyframes reveal-fade {
  from { opacity: 0; transform: translateY(16px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal, .reveal-stagger .service-card {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
    transition: none !important;
  }
}

/* Responsive */
@media (max-width: 860px) {
  .why-inner, .contact-inner { grid-template-columns: 1fr; }
  .service-grid { grid-template-columns: repeat(2, 1fr); }
}

/* 940, and it has moved twice for the same reason. It was 640, and between
   roughly 640 and 780 the bar tried to hold the logo, five nav links and the
   CTA with no room for them, so the CTA ran 45px past the viewport and every
   tablet got a horizontal scrollbar. 860 fixed that for five links. Home made
   it six, and the CTA ran 30px over again between 861 and about 940.

   The rule to keep: this number is not a guess about tablets. It is the width
   at which the bar actually runs out of room, and it has to be re-measured
   every time a nav link is added or removed. */
@media (max-width: 940px) {
  .main-nav, .btn-nav { display: none; }
  .nav-toggle { display: flex; }

  /* The open menu is a panel under the bar, not a row inside it.
     It used to be a row inside it: the JS set display:flex and the nav's own
     `flex: 1; justify-content: center` laid six links across a 390px header,
     on top of the wordmark. The links were there and could not be tapped,
     because the logo sat over them and swallowed the touch. */
  .main-nav.open {
    display: flex;
    flex-direction: column;
    gap: 0;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex: none;
    justify-content: flex-start;
    /* Solid, not 0.98. Two percent of a cream page under a near-black panel
       is a five-level difference, which is invisible on a swatch and clearly
       readable as ghosted headline text once it is spread across a whole
       panel. A menu is not a place for a translucency effect. */
    background: var(--ink-raised);
    padding: 4px var(--edge) 14px;
    border-top: 1px solid rgba(255, 255, 255, 0.10);
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.30);
  }
  .main-nav.open a {
    padding: 15px 2px;                 /* a 44px tap target, not a 20px one */
    font-size: 1.02rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  }
  .main-nav.open a:last-child { border-bottom: none; }
  /* the sliding underline is a hover affordance, and there is no hover here */
  .main-nav.open a::after { display: none; }
}

@media (max-width: 860px) {
  .service-grid { grid-template-columns: 1fr; }
  .logos-row, .partner-row { gap: 24px; }
}

/* ==========================================================================
   HERO 3D + real logo walls
   ========================================================================== */
/* The hero is cream with dark copy, and the render sits in the right-hand
   space rather than behind the text. No scrim needed, and no contrast problem
   to fix.

   The copy is a LEFT COLUMN, not a centred block. `.hero-inner` carries
   `.container`, so capping it at 780px left it centred in the viewport and the
   headline ran straight over the shelf — "without" sat on top of the render at
   1440px wide. Instead the container keeps its full width, so the copy starts
   on the same left gutter as the logo in the header above it, and a grid holds
   every child in column one. Column two is deliberately empty: it is the room
   the shelf needs to breathe. */
/* Full bleed: the hero uses the whole screen width, so the copy sits on the
   very left gutter, directly under the logo in the header above it.

   One column now. It used to be two, the second deliberately empty to give the
   3D shelf room. The shelf is gone — Justin did not like it, and neither
   competitor in this market animates a hero — so a second column would just be
   a dead half-screen. The measure below is what keeps the headline readable
   instead of running the full width of a monitor. */
.hero-inner{
  position:relative;z-index:1;
  width:100%;
  max-width:none;margin:0;
  padding-left:var(--edge);padding-right:var(--edge);
  display:grid;
  grid-template-columns:minmax(0,var(--hero-copy));
  text-align:left;
  align-items:center;
}
.site-header .header-inner{
  max-width:none;
  padding-left:var(--edge);padding-right:var(--edge);
}
.hero-copy{grid-column:1}
/* The badge is a pill: as a grid item it would stretch to the column width and
   stop looking like one. Everything else is meant to fill the column — the
   stats rule above the row draws its line across it. */
.hero-badge{justify-self:start}
/* The pill is a black lozenge, which on cream was the contrast. On a dark
   scrim it is nearly its own ground, so the gold text floats on a smudge. A
   hairline of the gold gives it its edge back without turning it into a second
   gold button competing with the real one below. */
.hero .hero-badge {
  background: rgba(17, 17, 17, 0.72);
  box-shadow: inset 0 0 0 1px rgba(232, 185, 35, 0.55);
}

/* --------------------------------------------------------------------------
   Hero lockup, and the hand-off to the header
   The wordmark sits on the page above the headline. The header carries only
   the RM monogram until you have scrolled past it, then opens out into the
   full mark.

   It is the same four letter slices the brand band animates, at the same
   wordmark coordinates, so this is literally the band's collapse played
   backwards rather than a second drawing of the logo that has to be kept in
   step with the first.

   Geometry, all in the SVG's user units (294 tall):
     R      0 .. 172
     etail  160 .. 724
     M      749 .. 986      slid -551 it lands at 198 .. 435
     ark    1006 .. 1470
   So the closed mark is 435 wide and the open one is 1470, giving the two
   aspect ratios below: 435/294 = 1.4796 and 1470/294 = 5.
   -------------------------------------------------------------------------- */

/* The hero wordmark. Its intrinsic width is 1479px, so without an explicit
   width here it renders at that and only the global img{max-width:100%} keeps
   it inside the page — which means it looks catastrophic while still passing
   an overflow check. Measure the rendered width, not the scrollbar. */
.hero-logo {
  display: block;
  /* Grown about a fifth, at Justin's ask — it is the first thing on the page
     and it was sitting smaller than the headline under it. The badge's width
     and its font-size are the same expression scaled by the same factor: the
     three move together or the lockup stops being one. */
  width: clamp(255px, 29vw, 400px);
  height: auto;
  margin-bottom: 22px;
  justify-self: start;
  /* drop-shadow, not box-shadow, for the same reason the header's mark uses it:
     it follows the letterforms' alpha instead of drawing a rectangle around a
     transparent PNG. Offset down rather than spread evenly, so it reads as the
     mark sitting above the cream rather than glowing on it. */
  filter: drop-shadow(0 4px 14px rgba(17, 17, 17, 0.55));
}

.logo { --logo-h: 40px; }

.logo-mark {
  height: var(--logo-h);
  /* The SVG box is always the full wordmark, so the artwork never rescales
     during the transition — the link's own box is what opens and closes, and
     the letters simply stop being clipped. Scaling the SVG instead would
     shrink the R and the M as they closed, which is a different animation and
     a worse one. */
  width: calc(var(--logo-h) * 5);
  display: block;
  /* flex: none is load bearing. .logo is a flex row, so with the default
     flex-shrink the SVG obediently shrank to whatever width the link had —
     which scaled the whole viewBox down and rendered a 30%-size RM instead of
     a full-size one with the tail clipped off. The SVG must keep its full
     width and let the parent's overflow do the hiding. */
  flex: none;
  /* drop-shadow, not box-shadow: it follows the letterforms' alpha rather than
     drawing a rectangle around transparent PNGs. */
  filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.34));
}

/* Open by default. Every page except the home page has no hero wordmark, and
   with JavaScript off no page does, so the full mark is the resting state and
   the closed one is the exception. */
.logo {
  overflow: hidden;
  width: calc(var(--logo-h) * 5);
  flex: 0 0 auto;
}

.hero-lockup .site-header:not(.logo-shown) .logo {
  width: calc(var(--logo-h) * 1.4796);
}
.hero-lockup .site-header:not(.logo-shown) .lm-etail,
.hero-lockup .site-header:not(.logo-shown) .lm-ark {
  opacity: 0;
  /* they pull left as they fade, so the word reads as being drawn in rather
     than switched on — the same gesture as the band, reversed */
  transform: translateX(-90px);
}
.hero-lockup .site-header:not(.logo-shown) .lm-m {
  transform: translateX(-551px);
}

/* Transitions on the parts, not the parent, so the box and the letters open
   together. The letters wait for the box to start moving, which is what makes
   it read as the mark unfolding rather than three things happening at once. */
.logo { transition: width .52s cubic-bezier(.65, 0, .2, 1); }
.lm-etail, .lm-ark {
  transition: opacity .42s ease .12s, transform .52s cubic-bezier(.65, 0, .2, 1) .06s;
}
.lm-m { transition: transform .52s cubic-bezier(.65, 0, .2, 1); }

.hero-lockup .site-header .lockup-tagline {
  opacity: 0;
  visibility: hidden;
  transition: opacity .32s var(--ease), visibility 0s linear .32s;
}
.hero-lockup .site-header.logo-shown .lockup-tagline {
  opacity: 1;
  visibility: visible;
  transition: opacity .32s var(--ease) .2s, visibility 0s;
}

/* The mark still opens and closes — it is a state, not decoration — it just
   arrives there instantly. */
@media (prefers-reduced-motion: reduce) {
  .logo, .lm-etail, .lm-ark, .lm-m,
  .hero-lockup .site-header .lockup-tagline { transition: none; }
}

.logos-row,.partner-row{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:clamp(1.6rem,5vw,3.4rem);
}
.logos-row img{height:clamp(38px,5vw,62px);width:auto;display:block}
.partner-row img{
  height:clamp(22px,3vw,32px);width:auto;display:block;
  opacity:.62;filter:grayscale(1);transition:opacity .25s var(--ease),filter .25s var(--ease);
}
.partner-row img:hover{opacity:1;filter:grayscale(0)}

@media (max-width:900px){
  /* The enlarged mark only fits where there is room for it. Below this the
     header is tight enough that the wider pill steals width from the nav, the
     nav wraps a line early, and a wrapped nav is a taller banner. So every
     width under 900px keeps the original logo size. */
  .logo{padding:13.6px 16.2px}
  .logo{--logo-h:10.8px}
}
@media (max-width:640px){
  .logos-row img{height:34px}
}

/* --------------------------------------------------------------------------
   Brand band
   One beat of nothing but the mark, sitting between the last proof section and
   the ask. Black ground because the wordmark is white and gold — it has no
   contrast on cream, and the section above it is white, so the alternation
   does the separating work without needing a rule or a shadow.
   -------------------------------------------------------------------------- */

.brandmark {
  background: var(--black);
  padding: clamp(54px, 8vw, 104px) var(--edge);
  display: grid;
  place-items: center;
}
.brandmark-img {
  /* Deliberately large. Capped in px as well as in %, or it becomes absurd on
     an ultrawide monitor; capped by viewport height too, so a short landscape
     window doesn't lose the sections either side of it. */
  width: min(76%, 1200px);
  max-height: 34vh;
  height: auto;
  object-fit: contain;
  display: block;
}

/* --------------------------------------------------------------------------
   Lexicon
   A reference block, not a marketing block. Set as a real definition list so
   it reads as reference material to a screen reader and to a search engine,
   and so the terms carry the semantic weight rather than just being bold text.
   -------------------------------------------------------------------------- */

.lexicon { padding: 96px 0; background: var(--cream); }

.lex-grid {
  display: grid;
  /* 235px so all four groups sit on one row inside the 1160px container.
     At 280px it wrapped to two rows and left two thirds of the second row
     empty, which reads as a mistake rather than a layout. */
  grid-template-columns: repeat(auto-fit, minmax(235px, 1fr));
  gap: 34px 32px;
  align-items: start;
}

.lex-group h3 {
  font-size: 0.82rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--gold-dark);
  padding-bottom: 10px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--border);
}

.lex-group dl { margin: 0; }
.lex-group dt {
  font-weight: 700;
  font-size: 0.98rem;
  color: var(--black);
  margin-bottom: 3px;
}
/* the alias, for the terms people say two ways */
.lex-group dt span {
  font-weight: 500;
  font-size: 0.84rem;
  color: var(--gray-light);
  margin-left: 6px;
}
.lex-group dd {
  margin: 0 0 18px;
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--gray);
}
.lex-group dd:last-child { margin-bottom: 0; }

@media (max-width: 640px) {
  .lexicon { padding: 64px 0; }
  .lex-grid { gap: 28px; }
}

/* --------------------------------------------------------------------------
   Interior pages
   The homepage hero carries the 3D render and a full viewport of height. An
   interior page needs none of that: it needs to say where you are and get out
   of the way of the content.
   -------------------------------------------------------------------------- */

.page-hero {
  background:
    radial-gradient(circle at 88% 0%, rgba(232, 185, 35,0.16), transparent 58%),
    var(--cream);
  padding: 66px 0 54px;
  border-bottom: 1px solid var(--border);
}
.page-hero h1 { font-size: clamp(1.9rem, 4vw, 2.9rem); margin-bottom: 14px; }
.page-hero-sub { font-size: 1.08rem; max-width: 620px; }

.crumbs { font-size: 0.85rem; color: var(--gray); margin-bottom: 14px; }
.crumbs a { color: var(--gray); }
.crumbs a:hover { color: var(--gold-dark); }
.crumbs span { margin: 0 6px; color: var(--gray-light); }

/* the nav entry for the page you are already on */
.main-nav a.current { color: var(--gold-dark); }
.main-nav a.current::after { right: 0; }

/* --------------------------------------------------------------------------
   Services detail page
   Nine sections on one page rather than nine thin pages: nine near-identical
   pages compete with each other for the same search, and in a site with no
   build step they are also nine copies of the header to keep in sync.
   -------------------------------------------------------------------------- */

.services-detail { padding: 72px 0 84px; background: #fff; }

.svc {
  display: grid;
  /* Three columns from 1080px: number, copy, photograph. The copy column is
     1fr rather than a fixed width so it absorbs the shrink on the way down and
     the photograph keeps a usable size; .svc-body's own max-width still holds
     the measure on a wide screen. */
  grid-template-columns: 92px minmax(0, 1fr) minmax(200px, 340px);
  gap: 26px;
  padding: 42px 0;
  border-top: 1px solid var(--border);
  /* the header is fixed, so an anchor jump would otherwise land under it */
  scroll-margin-top: 110px;
}
.svc:first-child { border-top: none; padding-top: 8px; }

.svc-num {
  font-size: 2.6rem;
  font-weight: 800;
  line-height: 1;
  color: var(--gold);
  letter-spacing: -0.02em;
}
.svc-body { max-width: 720px; }
.svc h2 { font-size: clamp(1.35rem, 2.4vw, 1.85rem); margin-bottom: 12px; }
.svc-lede { font-size: 1.04rem; margin-bottom: 20px; }

.svc-list { list-style: none; padding: 0; margin: 0; }
.svc-list li {
  position: relative;
  padding-left: 26px;
  margin-bottom: 11px;
  font-size: 0.97rem;
  color: var(--gray-dark, var(--gray));
}
.svc-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 11px;
  height: 2px;
  background: var(--gold);
}

/* The photograph for each service. Same nine files the home page cards use, so
   on a second page view they come out of cache rather than off the network.
   Decorative: the heading beside it already names the service, and nine alt
   texts restating it is nine things a screen reader has to sit through. */
.svc-media {
  align-self: start;
  border-radius: var(--frame-radius);
  overflow: hidden;
  box-shadow: var(--shadow-frame);
  background: var(--gold-soft);   /* what shows while the WebP is in flight */
}
.svc-media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  filter: grayscale(1) contrast(1.04);
}

/* Below 1080 the photograph stops being a column and becomes a banner over the
   copy. Two columns of 300px each is neither a readable measure nor a legible
   picture, and `order` is what puts it above the text rather than stranded
   under the last bullet. */
@media (max-width: 1079px) {
  .svc { grid-template-columns: 1fr; gap: 14px; }
  .svc-num   { order: 1; }
  .svc-media { order: 2; max-width: 720px; }   /* the same measure .svc-body has,
                                                  or the banner overhangs the
                                                  text it belongs to */
  .svc-body  { order: 3; }
}

@media (max-width: 700px) {
  .svc { gap: 12px; padding: 34px 0; }
  .svc-num { font-size: 1.6rem; }
}

/* --------------------------------------------------------------------------
   Prose bands (Why Us), platform list (Partners), contact extras
   -------------------------------------------------------------------------- */

.prose-band { padding: 72px 0; background: #fff; }
.prose-band.alt { background: var(--cream); }
.prose { max-width: 720px; }
.prose h2 { font-size: clamp(1.35rem, 2.4vw, 1.85rem); margin-bottom: 14px; }
.prose p { margin-bottom: 16px; font-size: 1.02rem; }

.steps { list-style: none; counter-reset: step; padding: 0; margin: 24px 0 0; }
.steps li {
  counter-increment: step;
  position: relative;
  padding-left: 46px;
  margin-bottom: 20px;
  font-size: 1rem;
}
.steps li::before {
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: -1px;
  font-weight: 800;
  font-size: 0.95rem;
  color: var(--gold-dark);
  background: var(--gold-soft);
  width: 32px;
  height: 32px;
  border-radius: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.steps.compact li { font-size: 0.94rem; margin-bottom: 14px; padding-left: 40px; }
.steps.compact li::before { width: 27px; height: 27px; font-size: 0.82rem; }

/* Partners */
.platform-list { padding: 66px 0 40px; background: #fff; }
.platform {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 34px;
  align-items: center;
  padding: 34px 0;
  border-top: 1px solid var(--border);
  scroll-margin-top: 110px;
}
.platform:first-child { border-top: none; padding-top: 4px; }
.platform-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 74px;
  padding: 12px 18px;
  background: var(--cream);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
/* six logos from six design teams, so contained rather than sized */
.platform-mark img { max-width: 100%; max-height: 100%; object-fit: contain; }
.platform-copy { max-width: 680px; }
.platform-copy h2 { font-size: 1.22rem; margin-bottom: 8px; }
.platform-copy p { font-size: 0.97rem; }

.partners-brands { padding: 56px 0 78px; background: var(--cream); }
.partners-brands h2 { margin-bottom: 8px; }
.partners-brands .section-sub { margin-bottom: 30px; }

@media (max-width: 700px) {
  .platform { grid-template-columns: 1fr; gap: 16px; padding: 26px 0; }
  .platform-mark { height: 62px; max-width: 200px; }
}

/* Contact page extras */
/* The location is not a link, but it sits where one does. Everything the
   label span sets has to be undone, or it renders as a second label:
   BENTONVILLE, ARKANSAS in 0.78rem caps. */
.contact-details .plain {
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--black);
  text-transform: none;
  letter-spacing: normal;
  margin-bottom: 0;
}
.next-steps { margin-top: 34px; }
.next-steps h3 { font-size: 1.02rem; margin-bottom: 4px; }

.cta-pair { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.text-link {
  font-weight: 700;
  font-size: 0.94rem;
  color: var(--gold-dark);
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s var(--ease);
}
.text-link:hover { border-bottom-color: currentColor; }
.why .text-link { color: var(--gold); }
.section-more { margin-top: 26px; text-align: center; }

/* Footer nav: the same links again, which is where a crawler expects to find
   them and where a person looks after reading to the bottom. */

/* --------------------------------------------------------------------------
   The band under the header
   The header is glass. At the top of the page that means it takes its colour
   from the cream hero and nearly disappears, which is what Caleb was seeing.
   This puts black behind it instead, so the bar reads black at rest and the
   glass still does its job the moment you scroll past.

   Its height is set from the header's own measured height by script.js, not
   typed in here: the bar is 81px on a desktop and shorter once the nav
   collapses, and a hard-coded number would leave either a black sliver under
   the bar or a stripe of cream over the black.
   -------------------------------------------------------------------------- */

.bar-band {
  /* Out of flow and pinned to the top of the document, so it is BEHIND the
     sticky bar rather than a strip underneath it. In flow it sat below the
     header, adding 81px of black to the page; pulled back up with a negative
     margin it disappeared under the hero entirely.

     It scrolls away with the page, which is the point: the glass reads black
     at rest and takes the hero's colour the moment you scroll past. */
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--bar-h, 81px);
  background: var(--black);
  z-index: 0;
}

/* --------------------------------------------------------------------------
   The hero copy column
   The photographs used to be three framed strips in a second column here. They
   are the background now, so the copy gets one column again — capped, because
   a headline running the full width of a 2560 monitor is unreadable, and the
   right of the frame is where the picture shows through the scrim.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  /* No cycling. One photograph, held. */
  .hero-bg img { transition: none; }
}

/* --------------------------------------------------------------------------
   Adaptive header
   The bar reads whatever section is passing under it and flips its own text to
   suit: light type over a dark section, dark type over a light one. That is
   what makes it survive a page it was not designed against — a new dark band,
   a reordered page, a palette swap.

   The solid bar stays as the resting state and the no-JS state, so a browser
   that never runs script.js gets the readable version rather than white text
   on cream. .adaptive is only added once the script has confirmed it can
   actually measure what is underneath.
   -------------------------------------------------------------------------- */

.site-header.adaptive {
  background: rgba(var(--ink-rgb), 0.055);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  border-bottom-color: rgba(var(--ink-rgb), 0.07);
  transition: background .3s var(--ease), border-color .3s var(--ease);
}

/* over a dark section: the bar itself darkens and the type goes light */
.site-header.adaptive[data-under="dark"] {
  background: rgba(var(--ink-rgb), 0.72);
  border-bottom-color: rgba(255, 255, 255, 0.10);
}
.site-header.adaptive[data-under="dark"] .main-nav a { color: rgba(255, 255, 255, 0.82); }
.site-header.adaptive[data-under="dark"] .main-nav a:hover,
.site-header.adaptive[data-under="dark"] .main-nav a.current { color: var(--gold); }
.site-header.adaptive[data-under="dark"] .main-nav a::after { background: var(--gold); }
.site-header.adaptive[data-under="dark"] .lockup-tagline { color: rgba(255, 255, 255, 0.5); }
.site-header.adaptive[data-under="dark"] .nav-toggle span { background: #fff; }
.site-header.adaptive[data-under="dark"] .logo-mark { filter: drop-shadow(0 0 5px rgba(255,255,255,0.3)); }

/* over a light section: dark type, and the wordmark inverts so its white half
   does not vanish. The mark is one file; inverting is cheaper and safer than
   shipping and syncing a second one. */
.site-header.adaptive[data-under="light"] .main-nav a { color: var(--charcoal); }
.site-header.adaptive[data-under="light"] .main-nav a:hover,
.site-header.adaptive[data-under="light"] .main-nav a.current { color: var(--gold-ink); }
.site-header.adaptive[data-under="light"] .main-nav a::after { background: var(--gold-ink); }
.site-header.adaptive[data-under="light"] .lockup-tagline { color: var(--gray); }
.site-header.adaptive[data-under="light"] .nav-toggle span { background: var(--black); }
/* Per slice, not per mark. Inverting the whole SVG turned the gold half a
   blue-orange (invert takes #E8B923 to #1746DC, and no amount of hue-rotate
   brings that back to gold). The wordmark already splits into an ink half —
   r and etail — and a gold half, so the ink half is simply driven to black,
   which brightness(0) does exactly while leaving alpha alone, and the gold
   half is darkened just enough to hold on a light ground. */
.site-header.adaptive[data-under="light"] .lm-r,
.site-header.adaptive[data-under="light"] .lm-etail { filter: brightness(0); }
.site-header.adaptive[data-under="light"] .lm-m,
.site-header.adaptive[data-under="light"] .lm-ark { filter: saturate(1.25) brightness(0.82); }
.site-header.adaptive[data-under="light"] .logo-mark { filter: none; }

/* The open mobile panel is always its own dark surface, whatever is behind the
   bar, or its links would inherit the light-section colours and disappear.
   The current-page link needs saying separately: over a light section it is
   --gold-dark, which is chosen to read on cream and is far too dim on the
   panel's near-black. */
.site-header.adaptive .main-nav.open a { color: rgba(255, 255, 255, 0.88); }
.site-header.adaptive .main-nav.open a.current,
.site-header.adaptive .main-nav.open a:hover { color: var(--gold); }

@media (prefers-reduced-motion: reduce) {
  .site-header.adaptive { transition: none; }
}

/* Firefox only shipped backdrop-filter on by default recently and it is still
   absent in some builds. Without it these three would render as their
   translucent backgrounds with nothing blurred behind — the form would be a
   washed-out white box over gold, and the ghost button would lose its edge.
   So where it is unsupported they go back to being solid. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  /* the glow and the lit edge survive; only the frost is lost */
  .btn-ghost { background: rgba(255, 255, 255, 0.72); }
  .contact-form { background: #fff; }
  .why-card { background: linear-gradient(160deg, var(--charcoal), var(--card-dark)); }
}

/* --------------------------------------------------------------------------
   Retailer band
   Set as type, not as logos. RetailMark is a brokerage, not an affiliate, and
   putting five retailers' marks on the page implies an endorsement none of
   them has given — the same reason there is no Walmart logo anywhere on this
   site. Their names in RetailMark's own typeface say the true thing.
   -------------------------------------------------------------------------- */

.retail-band {
  background: var(--black);
  color: #fff;
  padding: clamp(30px, 3.6vw, 46px) 0;
  /* Centred, unlike most of the page. The site aligns to one left gutter, but
     this band's neighbour below — the brand marquee and its label — is centred
     too, and two centred bands running together read as one deliberate block
     where a left-aligned one between them read as a mistake. */
  text-align: center;
}
.retail-label {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 16px;
}
.retail-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  /* The gap's ceiling is 46, not the 52 it was with five names. The row is
     capped at the 1112px container until 1650, and the font stops growing at
     1350 — so above that only the gap grows, and with a sixth name it pushed
     the row past the container between about 1490 and 1640. The row broke into
     two lines and then un-broke 150px later, which is exactly where a 1512
     laptop sits. 46 is the widest ceiling that keeps six on one line inside
     1112. Add a seventh banner and this has to be measured again. */
  gap: 12px clamp(20px, 3.4vw, 46px);
  font-size: clamp(1.05rem, 2.2vw, 1.85rem);
  font-weight: 800;
  letter-spacing: -0.02em;
}
/* A hairline between names rather than a bullet: at this weight a dot reads as
   punctuation inside the name next to it. */
.retail-list li { position: relative; }
.retail-list li + li::before {
  content: "";
  position: absolute;
  left: calc(clamp(20px, 3.4vw, 46px) / -2);
  top: 0.32em;
  bottom: 0.28em;
  width: 1px;
  background: rgba(255, 255, 255, 0.22);
}
.retail-note {
  color: rgba(255, 255, 255, 0.62);
  font-size: 0.94rem;
  /* the measure stays; auto margins are what centre it inside the band */
  max-width: 60ch;
  margin: 18px auto 0;
}

@media (max-width: 560px) {
  .retail-list { gap: 8px 16px; font-size: 1rem; }
  .retail-list li + li::before { display: none; }
  .retail-list li:not(:last-child)::after { content: " \00b7"; color: rgba(255,255,255,0.3); }
}

/* --------------------------------------------------------------------------
   Blog
   The index is a list, not a grid of cards. A weekly post is a headline and a
   sentence; laid out in three columns each one becomes a small box with a lot
   of air in it, and eight of them read as a directory rather than as something
   worth reading. A list puts the headlines in a column so they can be scanned
   the way anyone actually scans a blog.
   -------------------------------------------------------------------------- */

.blog-index { padding: 66px 0 88px; background: #fff; }

.post-list { max-width: 760px; }

.post-card {
  padding: 30px 0;
  border-top: 1px solid var(--border);
  scroll-margin-top: 110px;
}
.post-card:first-child { border-top: none; padding-top: 6px; }
.post-card time {
  display: block;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--gray);
  margin-bottom: 8px;
}
.post-card h2 { font-size: clamp(1.2rem, 2.1vw, 1.6rem); margin-bottom: 8px; }
.post-card h2 a { color: var(--black); transition: color 0.2s var(--ease); }
.post-card:hover h2 a { color: var(--gold-dark); }
.post-card p { font-size: 0.98rem; margin-bottom: 10px; }
.post-card-more {
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--gold-dark);
}
.post-empty { color: var(--gray); }
.post-empty code {
  background: var(--cream);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 5px;
  font-size: 0.9em;
}

/* The post itself. One column, capped at a readable measure — the rest of the
   site runs to 1400px, which is right for a three-column grid and far too wide
   for prose. */
.post { padding: 54px 0 74px; background: #fff; }
.post h1 { font-size: clamp(1.75rem, 3.4vw, 2.6rem); max-width: 20ch; margin-bottom: 12px; }
.post-meta {
  font-size: 0.86rem;
  color: var(--gray);
  margin-bottom: 34px;
}
.post-meta span { margin: 0 7px; color: var(--gray-light); }

.post-body { max-width: 680px; }
.post-body p { font-size: 1.06rem; line-height: 1.72; margin-bottom: 22px; }
.post-body h2 {
  font-size: clamp(1.2rem, 2.2vw, 1.55rem);
  margin: 40px 0 14px;
}
.post-body h3 { font-size: 1.06rem; margin: 28px 0 10px; }
.post-body ul, .post-body ol { margin: 0 0 24px; padding-left: 0; list-style: none; }
.post-body ol { counter-reset: n; }
.post-body li {
  position: relative;
  padding-left: 26px;
  margin-bottom: 11px;
  font-size: 1.02rem;
  line-height: 1.62;
}
.post-body ul li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 11px;
  height: 2px;
  background: var(--gold);
}
.post-body ol li { counter-increment: n; }
.post-body ol li::before {
  content: counter(n) ".";
  position: absolute;
  left: 0;
  font-weight: 700;
  color: var(--gold-dark);
}
.post-body blockquote {
  margin: 0 0 24px;
  padding-left: 20px;
  border-left: 3px solid var(--gold);
}
.post-body blockquote p { margin: 0; font-size: 1.08rem; }
.post-body a { color: var(--gold-dark); border-bottom: 1px solid rgba(199, 154, 21,0.4); }
.post-body a:hover { border-bottom-color: currentColor; }
.post-body code {
  background: var(--cream);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 5px;
  font-size: 0.92em;
}

.post-back { margin-top: 44px; font-weight: 700; }
.post-back a { color: var(--gold-dark); }

/* the glossary is the whole page here, so it does not need to announce itself
   a second time under the page title */
.lexicon-page { padding-top: 62px; background: #fff; }

.glossary-cta {
  background: var(--black);
  color: #fff;
  padding: 76px 0;
  text-align: center;
}
.glossary-cta h2 { color: #fff; margin-bottom: 10px; }
.glossary-cta p { color: rgba(255,255,255,0.72); margin-bottom: 26px; }

/* --------------------------------------------------------------------------
   Brand wall
   Sixteen logos, not four, so this is a grid rather than a centred flex row.
   A wrapping flex row leaves the last line short and off-centre, which reads
   as "we ran out" — a grid keeps the columns honest however many there are.
   Each logo sits in a fixed cell and is contained inside it, because these
   come from sixteen different design teams and share no aspect ratio, no
   padding convention and no idea of how big a logo should be.
   -------------------------------------------------------------------------- */

.logos-strip { padding: 44px 0; }

.logos-row {
  display: flex;
  /* Wrapping flex, not grid. A grid keeps its columns whatever the count, so
     an odd number of logos leaves a hole at the end of the last row. Wrapping
     centres the short row instead, which reads as deliberate — and the count
     changes whenever a brand is added or a relationship ends. */
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 28px 20px;
}
.logos-row img {
  /* Capped on both axes. Height alone leaves a square logo tiny next to a wide
     wordmark; width alone lets the wide ones dominate. These two numbers keep
     sixteen logos from sixteen design teams at roughly equal visual weight. */
  flex: 0 0 auto;
  max-width: 126px;
  max-height: 58px;
  width: auto;
  height: auto;
  object-fit: contain;
  /* Full colour on purpose. The greyed-out logo wall is a convention, but it
     was washing the paler marks here almost off the page — and these are proof,
     which is the one thing on the site that should not be subtle. */
  opacity: 1;
  transition: transform 0.25s var(--ease);
}
.logos-row img:hover { transform: translateY(-2px); }

@media (max-width: 640px) {
  .logos-row { gap: 22px 18px; }
  .logos-row img { max-width: 92px; max-height: 42px; }
}

/* --------------------------------------------------------------------------
   Brand marquee
   Roughly four logos in view, rolling left and never stopping. Two identical
   sets sit end to end and the track slides exactly one set's width, so the
   moment it finishes the second set is where the first started and the loop is
   invisible.

   The CSS animation is the FALLBACK. When script.js is running it adds
   .is-live and takes the transform over itself, because a speed you can push
   on has to be a number in a loop, not a fixed animation-duration. Without
   JavaScript the strip still rolls at a constant rate off this rule alone.

   --items keeps the SPEED constant as brands are added: the duration scales
   with the count rather than the same duration being shared out among more
   logos and getting faster every time the CRM publishes.
   -------------------------------------------------------------------------- */

.logos-strip { padding: 44px 0; }

.marquee {
  overflow: hidden;
  cursor: grab;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}
.marquee.is-dragging { cursor: grabbing; }

.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee calc(var(--items, 10) * 5.4s) linear infinite;
  /* the pointer should grab the strip, not pick up an individual logo */
  user-select: none;
  -webkit-user-drag: none;
  touch-action: pan-y;
}
.marquee.is-live .marquee-track { animation: none; }

@keyframes marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

.marquee-set {
  display: flex;
  align-items: center;
  list-style: none;
  margin: 0;
  padding: 0;
}
.marquee-set li {
  flex: 0 0 auto;
  /* The slot only needs to be a little wider than the mark it holds. At 260px
     around a 132px cap, half of every slot was empty and the strip read as
     five logos adrift rather than a wall of them. */
  width: clamp(122px, 11vw, 172px);
  display: grid;
  place-items: center;
  padding: 0 7px;
}
.marquee-set img {
  /* min(px, 100%) — the pixel cap keeps a mark from ballooning on a wide
     screen, the 100% keeps it inside its slot on a narrow one. A bare pixel
     cap did the first and not the second: at 390px the slot was 122px and the
     marks were still trying to be 158, so neighbours overlapped. */
  max-width: min(152px, 100%);
  max-height: 70px;
  width: auto;
  height: auto;
  object-fit: contain;
  pointer-events: none;               /* so a drag never becomes an image drag */
}

/* Motion that never stops is exactly what a vestibular sensitivity reacts to,
   so for anyone who has asked their system to reduce motion this stops being
   an animation and becomes an ordinary strip they scroll themselves. */
@media (prefers-reduced-motion: reduce) {
  .marquee { overflow-x: auto; cursor: default; }
  .marquee-track { animation: none; transform: none !important; }
  .marquee-set[aria-hidden="true"] { display: none; }
}

/* --------------------------------------------------------------------------
   Tagline
   Two of Justin's five lines, doing different jobs. The header carries
   "Connecting Brands to Retail" — a descriptor, what the company IS. The hero
   headline carries "From Opportunity to On Shelf" — what it DOES for you. Two
   different lines is what stops the page repeating itself in 3.4rem type a
   hundred pixels apart.

   The lockup sits beside the wordmark, but only from 1240px up: below that the
   bar is already carrying the logo, six nav links and the CTA, and squeezing a
   further thing in pushes the CTA past the right edge —
   which makes the header taller, which is the one thing it must not do.
   The footer copy is unconditional, so the line is on every page at every
   width regardless.
   -------------------------------------------------------------------------- */

.lockup-tagline {
  display: none;
  flex: 0 0 auto;
  margin-left: 14px;
  padding-left: 16px;
  border-left: 1px solid var(--border);
  font-size: 0.82rem;
  font-weight: 500;
  line-height: 1.25;
  color: var(--gray);
  white-space: nowrap;
}
@media (min-width: 1240px) { .lockup-tagline { display: block; } }

.footer-tagline { font-weight: 600; color: var(--charcoal); }

/* ==========================================================================
   DARK HEADER
   The bar is black, so the wordmark no longer needs a black pill behind it to
   sit on — it sits straight on the bar. Everything in here supersedes the
   header rules earlier in this file, which are from the light-bar version.
   ========================================================================== */

.site-header {
  background: rgba(var(--ink-rgb), 0.94);
  border-bottom-color: rgba(255, 255, 255, 0.10);
}
.site-header.is-scrolled {
  box-shadow: 0 4px 22px rgba(0, 0, 0, 0.32);
  border-bottom-color: transparent;
}

/* No pill: no ground, no padding, no radius. The mark IS the element now. */
.logo {
  background: none;
  padding: 0;
  border-radius: 0;
}
.logo:hover { box-shadow: none; transform: translateY(-1px); }


.main-nav a { color: rgba(255, 255, 255, 0.80); }
.main-nav a:hover { color: var(--gold); }
.main-nav a::after { background: var(--gold); }
.main-nav a.current { color: var(--gold); }

.lockup-tagline {
  color: rgba(255, 255, 255, 0.58);
  border-left-color: rgba(255, 255, 255, 0.18);
}

.nav-toggle span { background: #fff; }

/* Below 900 the bar is tight. Re-declared here because the earlier 900px block
   sizes a pill that no longer exists.

   17px looks arbitrary and is not: the wordmark is 5.03:1, so 17px tall is
   ~86px wide — the exact width the old pill occupied. Any wider and it steals
   room from the nav, the nav wraps to a second line, and the bar gets taller.
   Unboxed it still reads BIGGER than before, because the old pill was mostly
   padding around a 10.8px mark. */
@media (max-width: 900px) {
  .logo { padding: 0; --logo-h: 17px; }
}

/* Wherever the nav has collapsed to the hamburger, the mark is the only thing
   setting the bar's height, so it comes back up. Keyed to the same 860 as that
   collapse — left at 640 it produced a 53px bar between 660 and 860, a 17px
   mark sitting alone next to a hamburger with nothing else in the row. */
@media (max-width: 860px) {
  .logo { --logo-h: 38px; }
}

/* --------------------------------------------------------------------------
   Wordmark -> monogram, then the band splits in two
   RetailMark collapses to RM, the letters drifting left as they go, and the
   monogram settles on the left. The right of the band is then free, and the
   statement fades up into it.

   The numbers are the wordmark's own pixels, because the viewBox is its pixel
   grid. 551 is the exact distance from the M's real position to 26 units after
   the R, and 26 is the wordmark's own l-to-M gap, so the finished lockup keeps
   its native kerning instead of a spacing I picked.
   -------------------------------------------------------------------------- */

.brandmark {
  padding: clamp(38px, 4.4vw, 70px) var(--edge);
  /* Both of these, and the second is the one that actually matters. The
     original centred band was a grid with place-items:center. Switching to
     block is not enough: justify-items applies to block containers too under
     CSS Box Alignment, and Chromium implements it, so the row stayed
     shrink-wrapped and centred with display:block computed. Resetting the
     alignment is the real fix — the monogram starts on the same left gutter
     as the headline and the header logo. */
  display: block;
  justify-items: stretch;
}

.brandmark-inner {
  display: flex;
  align-items: center;
  /* space-between, not a flexing middle. Letting the statement absorb the
     slack made its BOX fill the middle while its TEXT still ended early, so
     the slack all pooled into one void before the box. Distributing it puts
     the monogram on the left edge, the box on the right, and the statement
     centred in what is left. */
  /* Was space-between, for a row of three. With the box gone that pushed the
     monogram and the statement to opposite ends of the band with a canyon
     between them. They sit together on the left now, on the same gutter as
     everything else, and the slack collects to the right. */
  justify-content: flex-start;
  gap: clamp(28px, 5vw, 88px);
}

/* The SVG is only as wide as the finished monogram. The letters are drawn well
   outside it and overflow on purpose, so at rest the wordmark occupies the
   whole band and the collapse is the letters withdrawing into their own box. */
.rm {
  flex: 0 0 auto;
  height: clamp(58px, 9vw, 152px);
  width: auto;
  overflow: visible;
}

/* Capped so it breaks at its own full stop into two lines and reads as a
   block, rather than one long line that leaves the row lopsided. */
.brandmark-quote { margin: 0; min-width: 0; flex: 0 1 auto; max-width: 19em; }
.brandmark-quote p {
  margin: 0 0 12px;
  font-family: var(--font-head, inherit);
  font-size: clamp(1.15rem, 2.1vw, 1.9rem);
  font-weight: 700;
  line-height: 1.28;
  letter-spacing: -0.01em;
  color: #fff;
  text-wrap: balance;
}
.brandmark-quote cite {
  font-style: normal;
  font-size: 0.82rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold);
}

/* The wordmark starts centred in the band and travels left as it collapses.

   --rm-x is that starting offset, and script.js measures it: it depends on the
   band's width and the wordmark's rendered size, neither of which CSS can put
   in an SVG user-unit transform. It is a plain number because a CSS transform
   on an SVG child is in the local user coordinate system, so the calc() below
   turns it into user units, not pixels.

   Nothing runs until the band is on screen; script.js adds the class. Before
   that it is the full wordmark, which is also what a visitor without
   JavaScript keeps — so the statement must be visible by default, not faded. */
.rm-group { transform: translateX(calc(var(--rm-x, 0) * 1px)); }
.brandmark.is-revealed .rm-etail,
.brandmark.is-revealed .rm-ark {
  animation: rm-drift 1140ms cubic-bezier(.4, 0, .2, 1) 840ms forwards;
}
.brandmark.is-revealed .rm-m {
  animation: rm-close 1380ms cubic-bezier(.65, 0, .2, 1) 1020ms forwards;
}
.brandmark.is-revealed .rm-group {
  animation: rm-travel 1380ms cubic-bezier(.65, 0, .2, 1) 1020ms forwards;
}
.brandmark.is-revealed .brandmark-quote {
  animation: rm-quote 960ms cubic-bezier(.16, 1, .3, 1) 2100ms both;
}

/* they fade AND travel left, so the word looks like it is being drawn in
   rather than simply switched off */
@keyframes rm-drift {
  to { opacity: 0; transform: translateX(-90px); }
}
@keyframes rm-close {
  to { transform: translateX(-551px); }
}
@keyframes rm-travel {
  from { transform: translateX(calc(var(--rm-x, 0) * 1px)); }
  to   { transform: translateX(0); }
}
@keyframes rm-quote {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

@media (max-width: 760px) {
  .brandmark-inner { flex-direction: column; align-items: flex-start; gap: 26px; }
}

/* Motion this large is what a vestibular sensitivity reacts to, and the
   wordmark is the more informative of the two states. The statement is
   visible either way — it never depends on an animation to appear. */
@media (prefers-reduced-motion: reduce) {
  .brandmark.is-revealed .rm-etail,
  .brandmark.is-revealed .rm-ark,
  .brandmark.is-revealed .rm-m,
  .brandmark.is-revealed .rm-group,
  .brandmark.is-revealed .brandmark-quote { animation: none; }
}


/* ==========================================================================
   SCROLL REVEALS
   Each piece fades and lifts into place the first time it is scrolled to, and
   then stays put. Once, not on every pass — a section that re-animates every
   time you scroll past it stops reading as polish and starts reading as a
   page that cannot settle.

   The selector list below is mirrored in script.js. Keep the two in step: CSS
   decides what starts hidden, script.js decides what gets watched, and an
   element in one list but not the other either never appears or never moves.

   Nothing is hidden until the inline script in <head> sets .js-reveal on the
   document. That ordering is the whole safety net: if the script never runs,
   no rule below ever matches and the page is simply a normal page. It is in
   the head rather than with the rest of the JS so the hidden state is in place
   before first paint, instead of content appearing and then being taken away.
   ========================================================================== */

.js-reveal :is(
  .hero-badge, .hero h1, .hero-sub, .hero-cta, .hero-stats > div,
  .logos-label, .marquee,
  .services > .container > h2, .services > .container > .section-sub, .service-card,
  .why-copy > *, .why-card, .why-badge, .retail-band .container > *,
  .partners > .container > h2, .partners > .container > .section-sub, .partner-row,
  .contact-copy > *, .contact-form,
  .page-hero .crumbs, .page-hero h1, .page-hero-sub,
  .lex-group, .svc, .platform, .prose > *, .post-card,
  .glossary-cta > .container > *,
  .site-footer .container > *
):not(.is-in) {
  opacity: 0;
  transform: translateY(18px);
}

.js-reveal .is-in {
  opacity: 1;
  transform: none;
  /* the delay is the stagger, set per element by script.js */
  transition: opacity .893s cubic-bezier(.16, 1, .3, 1) var(--reveal-delay, 0ms),
              transform .893s cubic-bezier(.16, 1, .3, 1) var(--reveal-delay, 0ms);
}

/* Reveal-on-scroll is motion, and a page where everything slides is exactly
   what a vestibular sensitivity reacts to. Everything is simply present. */
@media (prefers-reduced-motion: reduce) {
  .js-reveal :is(
    .hero-badge, .hero h1, .hero-sub, .hero-cta, .hero-stats > div,
    .logos-label, .marquee,
    .services > .container > h2, .services > .container > .section-sub, .service-card,
    .why-copy > *, .why-card, .why-badge, .retail-band .container > *,
    .partners > .container > h2, .partners > .container > .section-sub, .partner-row,
    .contact-copy > *, .contact-form,
    .page-hero .crumbs, .page-hero h1, .page-hero-sub,
    .lex-group, .svc, .platform, .prose > *, .post-card,
  .glossary-cta > .container > *,
    .site-footer .container > *
  ) {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

/* ==========================================================================
   ONE LEFT EDGE
   The site had two. The header, hero and brand band sat on the --edge gutter;
   every content section sat inside a centred 1160px container. At 1512 that is
   68px against 200px, so the eye tracks a step in the margin on every scroll —
   which is exactly what it looked like.

   Everything now starts on --edge. The gutter was already the site's real
   left: the logo, the headline and the monogram all use it, and moving those
   right to meet the container would undo the full-bleed layout rather than fix
   the alignment.

   Content still gets a measure. Without --content-max the three-column grids
   would be 770px per card on a 2560 monitor, which fixes the margin and breaks
   the reading.
   ========================================================================== */

:root { --content-max: 1400px; }

.container {
  max-width: none;
  margin: 0;
  /* padding-left/right, NOT the shorthand. `padding: 0 var(--edge)` also sets
     top and bottom to zero, which silently wiped the 14px the header adds for
     its own height — the bar went from 81px to 53px with nothing in the header
     rules having changed. A shorthand here reaches every .container on the
     site, so it only gets to touch the axis it means to. */
  padding-left: var(--edge);
  padding-right: var(--edge);
}

.service-grid,
.why-inner,
.contact-inner,
.lex-grid { max-width: var(--content-max); }

/* The centred sections have no left edge to align, so they keep their own
   measure and stay centred in the full width. */
.partners .section-sub,
.logos-label { margin-left: auto; margin-right: auto; }

/* --------------------------------------------------------------------------
   Button arrow on hover
   Borrowed from the current retailmark.com, whose Divi buttons slide an arrow
   in from the right while the label shifts left to make room. It reads as the
   button leaning toward the thing it does.

   One thing changed in the borrowing. Divi grows the button — it goes from
   16px of side padding to 11.2 left and 32 right, about 11px wider — so
   hovering one button nudges whatever sits beside it. The hero has two side by
   side, so the padding here shifts by the SAME amount in both directions: the
   label moves, the arrow gets its room, and the width never changes.
   -------------------------------------------------------------------------- */

.btn {
  position: relative;
  transition: transform .2s var(--ease), box-shadow .2s var(--ease),
              background .2s var(--ease), color .2s var(--ease),
              padding .22s var(--ease);
}

.btn::after {
  content: "→";
  position: absolute;
  right: 14px;
  opacity: 0;
  transform: translateX(-7px);
  font-size: 1.05em;
  line-height: 1;
  pointer-events: none;
  transition: opacity .22s var(--ease), transform .22s var(--ease);
}

.btn:hover::after,
.btn:focus-visible::after { opacity: 1; transform: translateX(0); }

/* -8 left, +8 right: the label slides, the width holds still */
.btn:hover, .btn:focus-visible { padding-left: 14px; padding-right: 30px; }
.btn-lg:hover, .btn-lg:focus-visible { padding-left: 21px; padding-right: 39px; }
.btn-sm:hover, .btn-sm:focus-visible { padding-left: 6px; padding-right: 18px; }

/* The submit button is full-width, so its label is centred in a box that never
   moves; shifting its padding would slide the label off centre for no reason.
   It gets the arrow only. */
.btn-block:hover, .btn-block:focus-visible { padding-left: 22px; padding-right: 22px; }

@media (prefers-reduced-motion: reduce) {
  .btn, .btn::after { transition: none; }
  .btn:hover, .btn:focus-visible { padding-left: 22px; padding-right: 22px; }
  .btn-lg:hover, .btn-lg:focus-visible { padding-left: 30px; padding-right: 30px; }
}

/* --------------------------------------------------------------------------
   Contact: two panels converging
   The idea is lifted from the current retailmark.com, where a gold panel
   slides up from +223px while a dark one slides down from -117px and the two
   settle into an overlap. Read off their page rather than guessed at.

   What is taken is the MOTION, not the layout: theirs is a gold heading panel
   over a dark services list, ours is a gold panel behind the form. Copying the
   arrangement would have meant rebuilding a section that already works.
   -------------------------------------------------------------------------- */

/* overflow-x: clip, not hidden — clip does not create a scroll container, so
   the panel can still overhang inside the section without the page gaining a
   horizontal scrollbar. Which it did at 1000px, where the gutter bottoms out
   at 24px and the panel's 34px overhang ran off the viewport. */
.contact { overflow-x: clip; }
.contact-stack { position: relative; }

.contact-accent {
  position: absolute;
  inset: -34px -34px auto auto;      /* peeks out past the form's top-right */
  width: 62%;
  height: 58%;
  background: var(--gold);
  border-radius: var(--radius-lg);
  z-index: 0;
}
.contact-form { position: relative; z-index: 1; }

/* They arrive from opposite directions and meet. The form travels further and
   lands last, so the gold is already in place for it to sit against. */
.js-reveal .contact-accent:not(.is-in) { opacity: 0; transform: translate(46px, -34px); }
.js-reveal .contact-form:not(.is-in)   { opacity: 0; transform: translateY(52px); }

.js-reveal .contact-accent.is-in,
.js-reveal .contact-form.is-in {
  opacity: 1;
  transform: none;
  transition: opacity 2.4s cubic-bezier(.16, 1, .3, 1) var(--reveal-delay, 0ms),
              transform 2.4s cubic-bezier(.16, 1, .3, 1) var(--reveal-delay, 0ms);
}

/* Below the wide gutters there is less room to overhang into, so the offset
   comes in rather than being clipped flat against the edge. */
@media (max-width: 1200px) {
  .contact-accent { inset: -22px -14px auto auto; }
}
@media (max-width: 860px) {
  /* stacked, the offset panel would just stick out past the page */
  .contact-accent { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .contact-accent, .contact-form { opacity: 1 !important; transform: none !important; }
}
--on-dark-muted: #C9C9CC;