/*
Theme Name: Rush-Mor Records 2026
Theme URI: https://www.rushmor.com
Description: Single-page ACF-driven theme for Rush-Mor Records, Bay View, Milwaukee. Replaces the 2012 Skeleton-based Rushmor_v1. Plain CSS by design - no build step. See docs/.
Author: Martin Defatte for Guerrilla Digital
Author URI: https://www.guerrilladigital.cc
Version: 1.0.0
Requires at least: 6.4
Requires PHP: 8.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: rushmor
*/

/* ==========================================================================
   THIS FILE IS THE SOURCE. There is no Sass, no build step, nothing to compile.
   Edit it and upload it. That is the whole pipeline, and it is deliberate:
   this site was last touched in 2012 and will likely go untouched for years
   again. A toolchain that has to survive that long is a liability.

   Everything a preprocessor was doing in the reference themes has a native
   equivalent here:
     - $variables      -> custom properties (also readable at runtime by JS)
     - @include responsive() -> container queries, which are better: a module
                          adapts to ITS OWN width, not the viewport's
     - 7-1 import order -> @layer, which makes precedence explicit instead of
                          depending on the order files happen to load
     - @each colorways  -> one rule + a --module-bkg property per modifier.
                          The adjacent-fusing that needed a generated loop is
                          computed in PHP now (rm_module_attrs), because the
                          dispatcher already knows both rows' backgrounds.

   LAYER ORDER IS THE CASCADE. Later layers beat earlier ones regardless of
   specificity, so a plain .rm-btn in `components` still wins over a
   high-specificity selector in `base`. Never add an @import above this line.
   ========================================================================== */

@layer tokens, base, layout, components, modules, utilities;

/* --------------------------------------------------------------------------
   FONTS - self-hosted, no Google CDN (cookie/privacy house rule).
   Both faces are VARIABLE with weight AND width axes, which is why there is
   one file per subset instead of one per weight. font-display: swap so text
   paints immediately in the fallback rather than sitting invisible.
   latin-ext is not optional here: this is a record shop, and its copy will
   hit Motorhead, Bjork and Sigur Ros.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 400 800;
  font-stretch: 75% 100%;
  font-display: swap;
  src: url('fonts/bricolage-grotesque/bricolage-grotesque-latin-var.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
                 U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 400 800;
  font-stretch: 75% 100%;
  font-display: swap;
  src: url('fonts/bricolage-grotesque/bricolage-grotesque-latin-ext-var.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
                 U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                 U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 700;
  font-stretch: 75% 100%;
  font-display: swap;
  src: url('fonts/instrument-sans/instrument-sans-latin-var.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
                 U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 700;
  font-stretch: 75% 100%;
  font-display: swap;
  src: url('fonts/instrument-sans/instrument-sans-latin-ext-var.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
                 U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                 U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Real italic. Without this face, font-style:italic renders as a browser-
   synthesized slant, which on a grotesque looks visibly wrong. */
@font-face {
  font-family: 'Instrument Sans';
  font-style: italic;
  font-weight: 400 700;
  font-stretch: 75% 100%;
  font-display: swap;
  src: url('fonts/instrument-sans/instrument-sans-latin-italic-var.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
                 U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: italic;
  font-weight: 400 700;
  font-stretch: 75% 100%;
  font-display: swap;
  src: url('fonts/instrument-sans/instrument-sans-latin-ext-italic-var.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
                 U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                 U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Font Awesome 7 Free, SUBSET to the ~13 glyphs this theme uses (214KB -> 1.6KB).
   Adding an icon means adding its codepoint in tools/subset-icons.sh and
   re-running it. A glyph outside the subset renders as a blank box and fails
   SILENTLY - there is no error. See that script's header.
   font-display: block (not swap) on purpose: a swapped-in fallback glyph is a
   wrong-looking box, worse than a brief blank. Never use an FA icon as the only
   carrier of meaning - every one is aria-hidden with a text label beside it. */
@font-face {
  font-family: 'Font Awesome 7 Free';
  font-style: normal;
  font-weight: 900;
  font-display: block;
  src: url('fonts/fontawesome/fa-solid-900.woff2') format('woff2');
}

/* ==========================================================================
   TOKENS
   ========================================================================== */
@layer tokens {
  :root {
    /* ---- Palette -------------------------------------------------------
       Sampled from the actual artwork, not invented. Ratios below were
       MEASURED (tools/check-contrast.py), not estimated. AA needs 4.5:1 for
       body text, 3:1 for large text and UI boundaries.

       #B80442 is the logo fill. #44C5DA is the painted storefront sign.
       #00514B is the green the building is painted. #560F1D is the barn-board
       the sign is mounted on. #EFE9D9 is the 2012 site's paper ground, kept
       because it is genuinely right for the shop. */

    --rm-red:        #B80442;  /* 5.53 on cream, 6.70 on white; white on it 6.70. AA both ways. */
    --rm-red-dark:   #8B0332;  /* hover/active. white on it 9.74. A filled button darkens on hover, never lightens. */

    /* ⚠ --rm-teal FAILS as text or as a fill under white text: 1.69 on cream,
       2.05 on white, 2.05 for white on it. It is an ACCENT ON DARK GROUNDS
       ONLY (6.91 on oxblood, 4.50 on green). For teal that carries text, use
       the two tokens below. This is the mistake the 2012 site made - its logo
       sat on a teal band where the white "RECORDS" scored 2.05. */
    --rm-teal:       #44C5DA;
    /* The 2012 site's header blue, brought back at Marty's request. The logo's
       crimson only scores 2.62 on it (vs 2.70 on ink) so by luminance it is a
       wash - but red and teal are near-complementary HUES, so the mark
       separates chromatically in a way a warm near-black cannot deliver. WCAG
       measures luminance only; this is the part it does not see.
       ⚠ Text on this band must be INK (7.08) or OXBLOOD (5.54). Cream scores
       2.11 and white 2.56 - both fail AA outright. */
    --rm-teal-band:  #4EAFBF;
    --rm-teal-ink:   #22626D;  /* teal TEXT on light. 5.71 cream / 6.92 white. */
    --rm-teal-deep:  #1E5862;  /* teal FILL under white text. 7.99. */

    --rm-cream:      #EFE9D9;  /* page ground */
    --rm-cream-dim:  #E4DCC8;  /* zebra rows, insets */
    --rm-white:      #FFFFFF;
    --rm-ink:        #1A1512;  /* body text AND the header/footer band. 14.94 on cream. */
    --rm-muted:      #5A5148;  /* quiet text FLOOR - the lightest ink still passing AA on cream (6.41). */
    --rm-green:      #00514B;  /* storefront green. white 9.22, cream 7.60, yellow 6.82. */
    --rm-oxblood:    #560F1D;  /* sign barn-board. white 14.17, cream 11.69, teal 6.91. */
    --rm-yellow:     #FADB86;  /* accent on dark grounds only (6.82 green / 10.49 oxblood). */
    --rm-hairline:   rgb(26 21 18 / 0.14);

    /* ---- Type ----------------------------------------------------------
       Bricolage Grotesque carries display; it has real character without
       fighting the logo, which is already doing the shouting. Instrument Sans
       is the quiet workhorse underneath.
       16px rem root on purpose - NOT the 62.5% trick, which silently collapses
       clamp() floors and breaks user font-size preferences. */
    --rm-font-display: 'Bricolage Grotesque', 'Arial Black', system-ui, sans-serif;
    --rm-font-text:    'Instrument Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;

    /* Fluid scale. Each clamp() has a real floor (readable on a 320px phone)
       and a real ceiling (does not run away on a 32" monitor). */
    /* Floor lowered from 2.75rem so "Milwaukee's oldest record store" sets in
       two lines at 390px instead of three. The ceiling is unchanged - this only
       affects small screens. */
    --rm-fs-hero:  clamp(2.05rem, 1.1rem + 5.2vw, 6rem);
    --rm-fs-h2:    clamp(2rem,    1.4rem + 2.8vw, 3.5rem);
    --rm-fs-h3:    clamp(1.375rem, 1.15rem + 1.1vw, 1.875rem);
    --rm-fs-h4:    clamp(1.125rem, 1.05rem + 0.4vw, 1.3125rem);
    --rm-fs-lead:  clamp(1.125rem, 1.05rem + 0.45vw, 1.375rem);
    --rm-fs-body:  1.0625rem;
    --rm-fs-small: 0.9375rem;
    --rm-fs-meta:  0.8125rem;

    --rm-lh-tight: 1.02;
    --rm-lh-head:  1.12;
    --rm-lh-body:  1.6;

    /* ---- Space ---------------------------------------------------------- */
    --rm-space-3xs: 0.25rem;
    --rm-space-2xs: 0.5rem;
    --rm-space-xs:  0.75rem;
    --rm-space-s:   1rem;
    --rm-space-m:   1.5rem;
    --rm-space-l:   2.5rem;
    --rm-space-xl:  4rem;
    --rm-space-2xl: 6rem;
    /* Section rhythm, fluid so bands do not feel cramped on phones or
       cavernous on desktop. */
    --rm-band-y: clamp(2.75rem, 1.5rem + 5vw, 5.5rem);

    /* ---- Measure + width ------------------------------------------------ */
    --rm-measure: 40rem;   /* ~62 characters. Prose never gets wider than this. */
    --rm-max:     78rem;   /* content max */
    --rm-gutter:  clamp(1.25rem, 4vw, 2.5rem);

    /* ---- Shape ----------------------------------------------------------
       The logo is a heavy black keyline around flat colour. The UI echoes it:
       thick ink borders and a hard offset shadow, like a screenprinted flyer
       or a sticker. No blur - a soft drop shadow would read as generic SaaS
       and fight the artwork. Used on CTA cards and primary buttons ONLY;
       everywhere would be a gimmick. */
    --rm-radius:      3px;
    --rm-border:      2px;
    --rm-border-bold: 3px;
    --rm-shadow-hard: 5px 5px 0 var(--rm-ink);
    --rm-shadow-hard-sm: 3px 3px 0 var(--rm-ink);

    /* ---- Motion --------------------------------------------------------- */
    --rm-fast:   120ms;  /* hover, opacity, small state flips */
    --rm-medium: 180ms;  /* panels, reveals */
    --rm-slow:   240ms;  /* collapses that move layout */
    --rm-ease:      cubic-bezier(0.2, 0, 0, 1);      /* entrances ease OUT */
    --rm-ease-in:   cubic-bezier(0.4, 0, 1, 1);      /* exits ease IN */
    --rm-ease-emph: cubic-bezier(0.2, 0.8, 0.2, 1);

    /* ---- Chrome --------------------------------------------------------- */
    --rm-header-h: 4.25rem;
    --rm-z-header: 100;
    --rm-z-drawer: 200;
    --rm-z-skip:   1000;
  }
}

/* ==========================================================================
   BASE
   ========================================================================== */
@layer base {
  *, *::before, *::after { box-sizing: border-box; }

  html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    /* Every in-page anchor clears the sticky header. Set here rather than per
       target so a new module cannot forget it and land under the bar. */
    scroll-padding-top: calc(var(--rm-header-actual, var(--rm-header-h)) + var(--rm-space-s));
  }

  body {
    margin: 0;
    background: var(--rm-cream);
    color: var(--rm-ink);
    font-family: var(--rm-font-text);
    font-size: var(--rm-fs-body);
    line-height: var(--rm-lh-body);
    font-synthesis-weight: none;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
  }

  h1, h2, h3, h4, h5, h6 {
    font-family: var(--rm-font-display);
    line-height: var(--rm-lh-head);
    text-wrap: balance;      /* stops one-word orphan lines in headings */
    margin: 0 0 var(--rm-space-s);
    letter-spacing: -0.02em;
  }
  h1 { font-size: var(--rm-fs-hero); line-height: var(--rm-lh-tight); font-weight: 800; letter-spacing: -0.035em; }
  h2 { font-size: var(--rm-fs-h2);  font-weight: 800; letter-spacing: -0.03em; }
  h3 { font-size: var(--rm-fs-h3);  font-weight: 700; }
  h4 { font-size: var(--rm-fs-h4);  font-weight: 700; }
  h5, h6 { font-size: var(--rm-fs-body); font-weight: 700; }

  p, ul, ol, dl, blockquote, figure, table { margin: 0 0 var(--rm-space-s); }
  p:last-child, ul:last-child, ol:last-child { margin-bottom: 0; }
  p { text-wrap: pretty; }

  a {
    color: var(--rm-teal-ink);
    text-decoration-thickness: 2px;
    text-underline-offset: 0.18em;
    transition: color var(--rm-fast) var(--rm-ease);
  }
  a:hover { color: var(--rm-red); }

  /* Phone numbers must be tappable on a phone and inert on a laptop, where a
     tel: link opens nothing useful. Colour is inherited so it does not look
     like a broken link on desktop. */
  a[href^='tel:'] { color: inherit; text-decoration: none; }
  @media (min-width: 62rem) {
    a[href^='tel:'] { pointer-events: none; cursor: default; }
  }

  img, svg, video, iframe { max-width: 100%; height: auto; display: block; }
  /* ⚠ NO background-color on img. A placeholder tint looks tidy on photographs
     but shows straight through the transparency of a PNG logo - it painted a
     cream halo around the wordmark on the dark header band. Reserve space with
     width/height attributes instead, which costs nothing and cannot leak. */

  strong, b { font-weight: 700; }
  small { font-size: var(--rm-fs-small); }

  ul, ol { padding-left: 1.25em; }
  li + li { margin-top: var(--rm-space-3xs); }

  hr {
    border: 0;
    border-top: var(--rm-border) solid var(--rm-hairline);
    margin: var(--rm-space-l) 0;
  }

  blockquote {
    margin-inline: 0;
    padding-left: var(--rm-space-m);
    border-left: var(--rm-border-bold) solid var(--rm-red);
    font-size: var(--rm-fs-lead);
  }

  table { border-collapse: collapse; width: 100%; }
  th, td { text-align: left; padding: var(--rm-space-2xs) var(--rm-space-xs); }
  th { font-weight: 700; }

  button, input, select, textarea { font: inherit; color: inherit; }

  /* ---- Focus ----------------------------------------------------------
     ⚠ THE RING IS TWO-TONE AND HAS TO BE. Focusable things on this site sit
     on grounds from #FFFFFF to #1A1512 to a full-bleed photograph. No single
     colour clears 3:1 against all of them - this is exactly the trap the
     reference theme documented, where a one-colour ring passed only 92 of 208
     tab stops.

     A near-black outline plus a white box-shadow band: whichever one
     disappears into its background, the other shows, and the boundary between
     them is 18.6:1. WCAG 1.4.11 explicitly permits a two-colour indicator.

     Order matters. outline-offset leaves a 2px gap showing whatever is behind;
     the box-shadow (spread 2, no blur, no offset) fills exactly that gap. It
     also survives any legacy `outline: 0` rule, since that cannot touch
     box-shadow. */
  :focus-visible {
    outline: 3px solid var(--rm-ink);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--rm-white);
    border-radius: 1px;
  }
  /* Dark bands invert the pair so the white band is the one that carries.
     ⚠ .site-header is NOT in this list any more - it became a light teal band,
     so it takes the default ink-outline ring like any other light surface. */
  .rm-module--dark :focus-visible,
  .site-footer :focus-visible {
    outline-color: var(--rm-white);
    box-shadow: 0 0 0 2px var(--rm-ink);
  }
  :focus:not(:focus-visible) { outline: none; }

  /* ---- Reduced motion -------------------------------------------------
     Global, not per-component, so a new module cannot forget it (WCAG 2.3.3).
     0.01ms rather than 0 so transitionend still fires and JS waiting on it
     does not hang. */
  @media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
      scroll-behavior: auto !important;
    }
  }
}

/* ==========================================================================
   LAYOUT
   ========================================================================== */
@layer layout {
  .rm-container {
    width: 100%;
    max-width: var(--rm-max);
    margin-inline: auto;
    padding-inline: var(--rm-gutter);
  }
  .rm-container--narrow { max-width: calc(var(--rm-measure) + var(--rm-gutter) * 2); }
  .rm-container--wide   { max-width: none; }

  /* Prose measure. Applied to the text column, never the band, so the
     background still runs full width. */
  .rm-prose { max-width: var(--rm-measure); }
  .rm-prose--center { margin-inline: auto; }

  /* ---- Header ---------------------------------------------------------
     ⚠ The band is INK, not teal, and that is a hard constraint rather than a
     preference. The logo's "RECORDS" is pure white with no keyline, so on any
     light ground it vanishes. The 2012 site put it on teal, where the white
     scored 2.05:1 and was genuinely hard to read. On ink the white hits 18.10
     and the crimson reads at 2.70 - the best available of the dark options,
     and the mark's own black outline melts into the band, which suits a
     hand-drawn logotype. Do not lighten this band. */
  /* ⚠ The admin bar is FIXED at >=783px, so a sticky header at top:0 slides
     underneath it and the logo disappears behind the toolbar. Below 783px the
     bar scrolls away with the page, so the offset has to go back to zero -
     WordPress does not do this for you, and the two rules are easy to get
     backwards. */
  body.admin-bar .site-header { top: 32px; }
  @media (max-width: 782px) {
    body.admin-bar .site-header { top: 0; }
  }
  body.admin-bar { --rm-admin-bar: 32px; }
  @media (max-width: 782px) {
    body.admin-bar { --rm-admin-bar: 0px; }
  }

  .site-header {
    position: sticky;
    top: 0;
    z-index: var(--rm-z-header);
    background: var(--rm-teal-band);
    color: var(--rm-ink);
    border-bottom: var(--rm-border-bold) solid var(--rm-ink);
  }
  .site-header__inner {
    display: flex;
    align-items: center;
    gap: var(--rm-space-m);
    min-height: var(--rm-header-h);
    /* Room for the larger wordmark without clipping it. */
    padding-block: var(--rm-space-2xs);
    padding-block: var(--rm-space-2xs);
  }
  .site-header__brand {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    margin-right: auto;
    text-decoration: none;
  }
  .site-header__brand img {
    width: auto;
    /* Sized up - the mark is the shop's whole identity and was reading as an
       afterthought at 44px. The header grows with it via min-height. */
    height: clamp(2.75rem, 1.9rem + 3.4vw, 4rem);
  }

  .site-header a { color: var(--rm-ink); }
  .site-header a:hover { color: var(--rm-oxblood); }

  /* ---- Footer --------------------------------------------------------- */
  .site-footer {
    background: var(--rm-ink);
    color: var(--rm-cream);
    padding-block: var(--rm-space-xl) var(--rm-space-l);
    border-top: var(--rm-border-bold) solid var(--rm-red);
  }
  .site-footer a { color: var(--rm-cream); }
  .site-footer a:hover { color: var(--rm-teal); }
  .site-footer__grid {
    display: grid;
    gap: var(--rm-space-l);
    grid-template-columns: 1fr;
    margin-bottom: var(--rm-space-l);
  }
  @media (min-width: 46rem) {
    .site-footer__grid { grid-template-columns: 1.4fr 1fr 1fr; }
  }
  .site-footer__heading {
    font-family: var(--rm-font-display);
    font-size: var(--rm-fs-meta);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--rm-teal);
    margin: 0 0 var(--rm-space-xs);
  }
  .site-footer__list { list-style: none; margin: 0; padding: 0; }
  .site-footer__list li + li { margin-top: var(--rm-space-2xs); }
  .site-footer__colophon {
    border-top: 1px solid rgb(239 233 217 / 0.18);
    padding-top: var(--rm-space-m);
    font-size: var(--rm-fs-meta);
    color: rgb(239 233 217 / 0.72);
  }
  .site-footer__colophon a { text-decoration-color: rgb(239 233 217 / 0.4); }

  main { display: block; }
}

/* ==========================================================================
   COMPONENTS
   ========================================================================== */
@layer components {

  /* ---- Skip link ------------------------------------------------------ */
  .skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: var(--rm-z-skip);
    background: var(--rm-red);
    color: var(--rm-white);
    padding: var(--rm-space-xs) var(--rm-space-m);
    font-weight: 700;
    text-decoration: none;
  }
  .skip-link:focus { left: 0; color: var(--rm-white); }

  /* ---- Anchor nav ------------------------------------------------------
     Desktop: inline links. Phone: a drawer. The breakpoint is where the six
     links stop fitting, not a device width. */
  .rm-nav__list {
    display: flex;
    align-items: center;
    gap: var(--rm-space-m);
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .rm-nav__list li { margin: 0; }
  /* ⚠ The underline is a pseudo-element, not border-bottom. A border changes
     the element's box, so animating it shifts the text by 2px; a pseudo-element
     scales in place. transform+opacity also stay off the layout path, so the
     hover cannot cause reflow in a sticky header.
     ⚠ And the states are INK/OXBLOOD, not teal: the band itself is teal now, so
     the previous `is-current { color: teal }` rendered the current page marker
     invisible against its own background. */
  .rm-nav__link {
    position: relative;
    font-family: var(--rm-font-display);
    font-size: var(--rm-fs-small);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    text-decoration: none;
    padding-block: var(--rm-space-3xs);
    white-space: nowrap;
    transition: color var(--rm-fast) var(--rm-ease);
  }
  .rm-nav__link::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: -2px;
    height: 3px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform var(--rm-medium) var(--rm-ease);
  }
  .rm-nav__link:hover,
  .rm-nav__link:focus-visible { color: var(--rm-oxblood); }
  .rm-nav__link:hover::after,
  .rm-nav__link:focus-visible::after { transform: scaleX(1); }
  /* Current section, set by js/rm-nav.js from the IntersectionObserver that
     also fires the GA4 section events - one observer, two consumers. */
  .rm-nav__link.is-current { color: var(--rm-oxblood); }
  .rm-nav__link.is-current::after {
    transform: scaleX(1);
    /* Origin flipped so the marker slides in from the opposite side when the
       reader scrolls back up - it reads as tracking position, not as a hover. */
    transform-origin: right center;
  }

  /* ⚠ Drawer-only, and hidden by DEFAULT rather than shown by default.
     These three live inside the max-width media query, so anything styled only
     in there is UNSTYLED on desktop - not absent. The shop links duly appeared
     in the desktop header as raw bulleted list items. Hide first, reveal in the
     drawer. */
  .rm-nav__toggle,
  .rm-nav__close,
  .rm-nav__shop { display: none; }

  @media (max-width: 60rem) {
    .rm-nav__toggle {
      display: inline-flex;
      align-items: center;
      gap: var(--rm-space-2xs);
      background: none;
      border: var(--rm-border) solid currentColor;
      border-radius: var(--rm-radius);
      color: var(--rm-ink);
      font-family: var(--rm-font-display);
      font-size: var(--rm-fs-small);
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.06em;
      padding: var(--rm-space-3xs) var(--rm-space-xs);
      cursor: pointer;
      /* 44px minimum touch target (WCAG 2.5.8). */
      min-height: 44px;
    }
    .rm-nav__panel {
      position: fixed;
      /* ⚠ --rm-header-actual is MEASURED at runtime by js/rm-nav.js, not the
         static --rm-header-h token. The token is a minimum, not the real
         height: the logo grew, the header grew with it, and the WordPress
         admin bar pushes the whole thing down another 32px. Offsetting by the
         token left the drawer starting partway UP the header, covering the
         logo. getBoundingClientRect().bottom accounts for all of it.
         The token stays as the no-JS fallback. */
      inset: var(--rm-header-actual, var(--rm-header-h)) 0 0 auto;
      width: min(22rem, 86vw);
      background: var(--rm-ink);
      border-left: var(--rm-border-bold) solid var(--rm-red);
      padding: var(--rm-space-l) var(--rm-gutter);
      overflow-y: auto;
      z-index: var(--rm-z-drawer);
      transform: translateX(100%);
      visibility: hidden;
      transition: transform var(--rm-medium) var(--rm-ease),
                  visibility 0s linear var(--rm-medium);
    }
    .rm-nav__panel.is-open {
      transform: translateX(0);
      visibility: visible;
      transition: transform var(--rm-medium) var(--rm-ease), visibility 0s;
    }
    .rm-nav__list {
      flex-direction: column;
      align-items: stretch;
      gap: 0;
    }
    .rm-nav__link {
      display: block;
      font-size: var(--rm-fs-h4);
      padding-block: var(--rm-space-xs);
      border-bottom: 1px solid rgb(239 233 217 / 0.16);
    }
    .rm-nav__link { color: var(--rm-cream); }
    .rm-nav__link:hover,
    .rm-nav__link:focus-visible,
    .rm-nav__link.is-current { color: var(--rm-teal); }
    /* The drawer rows already carry a divider; a second animated rule under
       each one would just be noise in a stacked list. */
    .rm-nav__link::after { display: none; }

    /* ⚠ The last anchor's divider plus the shop list's border-top drew TWO
       parallel rules with a gap between them. The shop group owns the
       separator, so the final link drops its own. */
    .rm-nav__list li:last-child .rm-nav__link { border-bottom: 0; }
    /* Marketplace + social, below the anchor list. Separated by a rule so it
       reads as a second group rather than more nav items. */
    .rm-nav__shop {
      display: grid;
      list-style: none;
      margin: var(--rm-space-m) 0 0;
      padding: var(--rm-space-m) 0 0;
      border-top: var(--rm-border) solid rgb(239 233 217 / 0.22);
      gap: var(--rm-space-2xs);
    }
    .rm-nav__shop li { margin: 0; min-width: 0; }
    .rm-nav__shop-link {
      display: flex;
      align-items: center;
      gap: var(--rm-space-2xs);
      min-height: 44px;
      color: var(--rm-cream);
      text-decoration: none;
      font-family: var(--rm-font-display);
      font-weight: 700;
      font-size: var(--rm-fs-small);
      text-transform: uppercase;
      letter-spacing: 0.06em;
    }
    .rm-nav__shop-link:hover,
    .rm-nav__shop-link:focus-visible { color: var(--rm-teal); }
    .rm-nav__shop-link .rm-brand { width: 1.1em; height: 1.1em; }

    .rm-nav__close {
      display: block;
      position: absolute;
      top: var(--rm-space-s);
      right: var(--rm-gutter);
      background: none;
      border: 0;
      color: var(--rm-cream);
      font-size: 1.5rem;
      line-height: 1;
      padding: var(--rm-space-2xs);
      min-width: 44px;
      min-height: 44px;
      cursor: pointer;
    }
    .rm-nav__scrim {
      position: fixed;
      inset: var(--rm-header-actual, var(--rm-header-h)) 0 0 0;
      background: rgb(26 21 18 / 0.6);
      z-index: calc(var(--rm-z-drawer) - 1);
      opacity: 0;
      visibility: hidden;
      transition: opacity var(--rm-medium) var(--rm-ease),
                  visibility 0s linear var(--rm-medium);
    }
    .rm-nav__scrim.is-open {
      opacity: 1;
      visibility: visible;
      transition: opacity var(--rm-medium) var(--rm-ease), visibility 0s;
    }
  }

  /* ---- Buttons --------------------------------------------------------
     ⚠ Bare .rm-btn is STRUCTURAL ONLY - geometry and type, no colour. Every
     button needs a variant class or it renders as invisible text. Never set
     `color` on .rm-btn from module scope; the variant owns both states.
     House law: a filled button hovers DARKER, never lighter. */
  .rm-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--rm-space-2xs);
    font-family: var(--rm-font-display);
    font-size: var(--rm-fs-small);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    text-decoration: none;
    padding: var(--rm-space-xs) var(--rm-space-m);
    min-height: 44px;
    border: var(--rm-border) solid transparent;
    border-radius: var(--rm-radius);
    cursor: pointer;
    text-align: center;
    transition: background-color var(--rm-fast) var(--rm-ease),
                color var(--rm-fast) var(--rm-ease),
                border-color var(--rm-fast) var(--rm-ease),
                transform var(--rm-fast) var(--rm-ease),
                box-shadow var(--rm-fast) var(--rm-ease);
  }
  /* ⚠ Filled and stroked buttons are geometrically IDENTICAL - same padding,
     same 2px border, same 44px floor (measured: 52/52 and 63/63). The stroked
     one still READS as taller, and the cause is the hard shadow: it sits on the
     filled button only, so in a pair the two have different visual mass and the
     eye reads the difference as height.
     The shadow is therefore reserved for buttons that stand alone as the single
     primary action (the form submit, Map It!) and dropped where a filled and a
     stroked button sit side by side. See .rm-actions .rm-btn--primary below. */
  .rm-btn--primary {
    background: var(--rm-red);
    color: var(--rm-white);
    border-color: var(--rm-ink);
    box-shadow: var(--rm-shadow-hard-sm);
  }
  .rm-btn--primary:hover,
  .rm-btn--primary:focus-visible {
    background: var(--rm-red-dark);
    color: var(--rm-white);
    /* Press the sticker down instead of lifting it - the shadow shrinks as the
       button moves into it, so the whole thing stays put optically. */
    transform: translate(2px, 2px);
    box-shadow: 1px 1px 0 var(--rm-ink);
  }
  .rm-btn--outline {
    background: transparent;
    color: var(--rm-ink);
    border-color: var(--rm-ink);
  }
  .rm-btn--outline:hover,
  .rm-btn--outline:focus-visible {
    background: var(--rm-ink);
    color: var(--rm-cream);
  }
  /* For use on ink/green/oxblood bands, where the outline variant would be
     invisible. */
  .rm-btn--invert {
    background: transparent;
    color: var(--rm-cream);
    border-color: var(--rm-cream);
  }
  .rm-btn--invert:hover,
  .rm-btn--invert:focus-visible {
    background: var(--rm-cream);
    color: var(--rm-ink);
  }
  /* In a group, a filled button drops its shadow so it carries the same visual
     weight as the stroked one beside it. Alone, it keeps it. */
  .rm-actions .rm-btn--primary,
  .rm-actions--fill .rm-btn--primary { box-shadow: none; }
  .rm-actions .rm-btn--primary:hover,
  .rm-actions .rm-btn--primary:focus-visible { transform: none; box-shadow: none; }

  .rm-btn--large { font-size: var(--rm-fs-body); padding: var(--rm-space-s) var(--rm-space-l); }

  /* ---- Button widths are decided by the GROUP, not the button -----------
     The problem this solves: with width left to `auto`, every button was as
     wide as its own label happened to be - seven different widths across one
     page (136, 154, 164, 179, 191, 246, 286, 306). That is not a system, it is
     whatever the copy did.

     So width becomes a property of the CONTAINER:

       .rm-actions            stacked and full-width on small screens,
                              auto-width in a row once there is space
       .rm-actions--inline    always a row; wraps rather than stretching.
                              For pairs that read as one line - Map It! and the
                              phone number.
       .rm-actions--fill      always full width of whatever contains it. Used
                              inside cards, where "full width of the card" also
                              makes every card's button identical for free,
                              because the cards themselves are equal width.

     A standalone button with no group (the form submit) stays auto-width. */
  .rm-actions {
    display: grid;
    gap: var(--rm-space-xs);
  }
  .rm-actions > .rm-btn { width: 100%; }

  /* ⚠ flex-wrap, NOT grid-auto-flow: column. A column grid track cannot wrap,
     so at 200% zoom the two hero buttons (max-content, ~604px together) sat in
     a 589px container and pushed 15px of horizontal scroll onto the page - a
     1.4.10 reflow failure. Flex lays them out in a row and drops one to the
     next line when they genuinely do not fit. */
  @container module (min-width: 30rem) {
    .rm-actions {
      display: flex;
      flex-wrap: wrap;
      justify-content: flex-start;
    }
    .rm-actions > .rm-btn { width: auto; }
  }

  /* Pairs that belong on one line at every size. They wrap to their own lines
     if they genuinely do not fit, but they never stretch. */
  .rm-actions--inline {
    display: flex;
    flex-wrap: wrap;
    gap: var(--rm-space-xs);
  }
  .rm-actions--inline > .rm-btn { width: auto; }

  .rm-actions--fill { display: grid; gap: var(--rm-space-xs); }
  .rm-actions--fill > .rm-btn { width: 100%; }

  .rm-btn--block { display: flex; width: 100%; }

  /* ---- Icons ----------------------------------------------------------
     Every icon is decorative and aria-hidden; the accessible name lives on
     the parent link/button or an adjacent text label. */
  .fa-solid {
    font-family: 'Font Awesome 7 Free';
    font-weight: 900;
    font-style: normal;
    display: inline-block;
    line-height: 1;
    text-rendering: auto;
    -webkit-font-smoothing: antialiased;
  }
  .fa-phone::before             { content: '\f095'; }
  .fa-envelope::before          { content: '\f0e0'; }
  .fa-location-dot::before      { content: '\f3c5'; }
  .fa-clock::before             { content: '\f017'; }
  .fa-arrow-right::before       { content: '\f061'; }
  .fa-arrow-up::before          { content: '\f062'; }
  .fa-bars::before              { content: '\f0c9'; }
  .fa-xmark::before             { content: '\f00d'; }
  .fa-record-vinyl::before      { content: '\f8d9'; }
  .fa-compact-disc::before      { content: '\f51f'; }
  .fa-diamond-turn-right::before{ content: '\f5eb'; }
  .fa-chevron-down::before      { content: '\f078'; }
  .fa-circle-check::before      { content: '\f058'; }
  .fa-arrow-up-right-from-square::before { content: '\f08e'; }
  /* External-link marks sit a touch smaller than a directional arrow - they are
     a signal about the destination, not a call to move forward. */
  .rm-btn .fa-arrow-up-right-from-square,
  a .fa-arrow-up-right-from-square { font-size: 0.82em; }

  /* Brand marks - Simple Icons sprite, inlined in template-parts/brand-sprite.php.
     currentColor so a mark inherits whatever it sits on. */
  .rm-brand-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
  .rm-brand {
    width: 1em;
    height: 1em;
    fill: currentColor;
    display: inline-block;
    vertical-align: -0.125em;
    flex: none;
  }

  /* ---- Back to top ---------------------------------------------------- */
  .rm-to-top {
    position: fixed;
    right: var(--rm-gutter);
    bottom: var(--rm-gutter);
    z-index: calc(var(--rm-z-header) - 1);
    width: 48px;
    height: 48px;
    display: grid;
    place-items: center;
    background: var(--rm-ink);
    color: var(--rm-cream);
    border: var(--rm-border) solid var(--rm-cream);
    border-radius: 50%;
    cursor: pointer;
    opacity: 0;
    visibility: hidden;
    transform: translateY(8px);
    transition: opacity var(--rm-medium) var(--rm-ease),
                transform var(--rm-medium) var(--rm-ease),
                visibility 0s linear var(--rm-medium),
                background-color var(--rm-fast) var(--rm-ease);
  }
  .rm-to-top.is-visible {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition: opacity var(--rm-medium) var(--rm-ease),
                transform var(--rm-medium) var(--rm-ease),
                visibility 0s,
                background-color var(--rm-fast) var(--rm-ease);
  }
  .rm-to-top:hover { background: var(--rm-red); }
  .rm-to-top[hidden] { display: none; }  /* no-JS fallback: never a dead control */
}

/* ==========================================================================
   MODULES
   The engine, then one block per layout. Adding a layout means adding a block
   HERE plus the ACF layout plus template-parts/modules/module-<layout>.php.
   The dispatcher needs no edit - it resolves partials by convention.
   ========================================================================== */
@layer modules {

  /* ---- Engine ---------------------------------------------------------
     Every module is a full-width band with its own ground colour. One rule
     reads --module-bkg; each colorway modifier sets it. Adding a colorway is
     two lines, and it cannot leak into the others.

     Each module is also a CONTAINER, so its contents respond to the module's
     own width rather than the viewport's. That is what makes these blocks
     genuinely reusable: drop a card grid into a narrow column later and it
     restacks correctly with no new breakpoint. */
  .rm-module {
    background: var(--module-bkg, var(--rm-cream));
    color: var(--module-ink, var(--rm-ink));
    padding-block: var(--rm-band-y);
    container-type: inline-size;
    container-name: module;
  }
  .rm-module--bkg-cream   { --module-bkg: var(--rm-cream); }
  .rm-module--bkg-white   { --module-bkg: var(--rm-white); }
  .rm-module--bkg-ink     { --module-bkg: var(--rm-ink);     --module-ink: var(--rm-cream); }
  .rm-module--bkg-green   { --module-bkg: var(--rm-green);   --module-ink: var(--rm-cream); }
  .rm-module--bkg-oxblood { --module-bkg: var(--rm-oxblood); --module-ink: var(--rm-cream); }
  .rm-module--bkg-red     { --module-bkg: var(--rm-red);     --module-ink: var(--rm-white); }

  /* Dark bands remap link and heading colour in one place. .rm-module--dark is
     added by PHP for any colorway in RM_DARK_BKGS, so this list and that
     constant are the only two things to keep in step. */
  .rm-module--dark { color: var(--rm-cream); }
  .rm-module--dark h2,
  .rm-module--dark h3,
  .rm-module--dark h4 { color: var(--rm-white); }
  .rm-module--dark .rm-module__lead { color: var(--rm-teal); }

  /* ⚠ LINK COLOUR TRAVELS AS A PROPERTY, and it has to.
     A blanket `.rm-module--dark a { color: teal }` is wrong the moment a
     component paints its own LIGHT surface inside a DARK band - which is
     exactly what the We Support cards are: white panels on oxblood. That rule
     rendered their titles at 2.05:1, measured. Token-level auditing could not
     see it, because the tokens were fine; it was the application that leaked.
     Inheriting through a custom property lets the light surface opt back out. */
  .rm-module { --link-ink: var(--rm-teal-ink); --link-hover: var(--rm-red); }
  .rm-module--dark { --link-ink: var(--rm-teal); --link-hover: var(--rm-yellow); }
  .rm-card, .rm-links__item { --link-ink: var(--rm-teal-ink); --link-hover: var(--rm-red); }

  .rm-module a:not(.rm-btn) { color: var(--link-ink); }
  .rm-module a:not(.rm-btn):hover { color: var(--link-hover); }

  /* These anchors ARE the surface, so they keep their own ink and their own
     inverted hover rather than taking the link colour. */
  .rm-module .rm-links__item { color: var(--rm-ink); }
  .rm-module .rm-links__item:hover,
  .rm-module .rm-links__item:focus-visible { color: var(--rm-cream); }

  /* Adjacent modules sharing a ground fuse into one continuous band instead of
     stacking two lots of padding. ⚠ The class is computed in PHP
     (rm_module_attrs compares this row's background to the previous row's) -
     there is no CSS way to compare two siblings' colorways generically, which
     is exactly why the reference theme had to GENERATE one rule per colour. */
  .rm-module--fused { padding-block-start: 0; }

  /* ---- Section heading ------------------------------------------------
     All module headings are h2 by contract; the template owns the h1. */
  .rm-module__header { margin-bottom: var(--rm-space-l); }
  .rm-module__header--center { text-align: center; margin-inline: auto; max-width: var(--rm-measure); }
  .rm-module__lead {
    display: block;
    font-family: var(--rm-font-display);
    font-size: var(--rm-fs-meta);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    color: var(--rm-red);
    margin-bottom: var(--rm-space-2xs);
  }
  .rm-module__title { margin-bottom: var(--rm-space-xs); }
  .rm-module__intro { font-size: var(--rm-fs-lead); max-width: var(--rm-measure); }
  .rm-module__header--center .rm-module__intro { margin-inline: auto; }

  /* ---- hero -----------------------------------------------------------
     Full-bleed storefront photograph with the wordmark and the two things a
     visitor actually wants: whether it is open, and how to get there. */
  .rm-module--hero {
    padding-block: 0;
    position: relative;
    --module-bkg: var(--rm-ink);
    --module-ink: var(--rm-cream);
  }
  .rm-hero {
    position: relative;
    display: grid;
    min-height: clamp(26rem, 20rem + 26vw, 40rem);
  }
  .rm-hero__media,
  .rm-hero__body { grid-area: 1 / 1; }
  /* ---- Hero duotone ---------------------------------------------------
     The photograph is desaturated to greyscale, then a brand-coloured
     gradient is MULTIPLIED over it. Two things fall out of that:

     1. It stops being a photograph competing with the headline and becomes a
        graphic ground that recedes behind it.
     2. Multiply is not a wash - it maps the image's own luminance through the
        gradient's colour, so the storefront's detail survives instead of being
        flattened under flat black at 92% opacity.

     The gradient runs brand teal at the top to near-black at the bottom, so it
     does the tinting AND the darkening in one pass: no separate scrim layer is
     needed to keep the type legible.

     isolation: isolate confines the blend to this box. Without it the multiply
     reaches through to whatever is painted behind the hero. */
  .rm-hero__media { isolation: isolate; background: var(--rm-ink); }
  .rm-hero__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 62%;  /* keeps the storefront, not the sky */
    filter: grayscale(1) contrast(1.08);
  }
  .rm-hero__media::after {
    content: '';
    position: absolute;
    inset: 0;
    /* ⚠ WARM, not teal - and the reason is the header above it.
       The header band is now teal. A teal-duotoned hero directly beneath it
       merged into one continuous mass and the header stopped reading as its
       own element. The teal eyebrow inside the hero lost separation too, sitting
       teal-on-teal.
       A darkened-cream ramp fixes both: the teal band reads as a distinct edge,
       the teal eyebrow pops, and - unlike an oxblood ramp, which was also
       tried - the red CTA stays loud instead of sinking into a red ground.
       It also reads as aged newsprint, which suits a shop trading since 1971
       and sits naturally above the cream page ground below. */
    background: linear-gradient(
      to top,
      #1C1610 0%,    /* near-black warm: this is the scrim, doing double duty */
      #3A2C1C 30%,
      #7A6547 62%,
      #C9B98F 100%   /* darkened cream in the sky */
    );
    mix-blend-mode: multiply;
    pointer-events: none;
  }
  /* ⚠ THIS SCRIM IS LOAD-BEARING, not a mood effect. Measured over the actual
     duotone, the eyebrow scored 1.93:1 where it needs 4.5 (tools/qa/wcag-audit.mjs
     samples the real pixels behind each text box). The background there was
     mid-tone enough that NO foreground colour could pass - white only reaches
     3.89 - so the fix had to be the ground, not the type.

     It covers the whole copy block rather than the bottom 78%: the eyebrow sits
     at the TOP of that block, which is exactly the part the old gradient barely
     reached. Warm ink to match the duotone, so it deepens the image rather than
     greying it. */
  /* ⚠ A FLAT TINT, and 0.55 is not a taste decision - it is the measured
     minimum. Swept from 0 upward (tools/qa, sweep): 0.50 leaves the eyebrow at
     4.46:1 against a 4.5 requirement; 0.55 clears it at 4.89.

     The eyebrow is the ONLY thing forcing this number. It is 13px, so it needs
     the full 4.5; the headline needs 3, and everything else is already way
     clear. Measured minimums, flat tint:
         teal  eyebrow -> 0.55   (0.50 gives 4.46, just misses)
         cream eyebrow -> 0.20   (0.15 gives 4.16, just misses)
     The eyebrow is cream, so this sits at 0.30 - above the 0.20 floor for
     margin, and still a little over half the tint teal would have demanded.

     It replaced a gradient because the gradient had to reach 0.70 at the
     bottom to carry the eyebrow higher up, which crushed the photograph
     exactly where there was most to see. */
  .rm-hero__body::before {
    content: '';
    position: absolute;
    inset: -85% 0 0 0;
    background: rgb(20 15 10 / 0.30);
    pointer-events: none;
    z-index: -1;
  }
  .rm-hero__body {
    position: relative;
    isolation: isolate;
    z-index: 1;
    align-self: end;
    padding-block: var(--rm-space-xl) var(--rm-space-l);
  }
  .rm-hero__title {
    color: var(--rm-white);
    margin-bottom: var(--rm-space-s);
    max-width: 18ch;
  }
  .rm-hero__lead {
    /* block so it takes its own line, fit-content so the BOX is only as wide as
       the text - that is what lets the rule below match the copy rather than
       stretching to the width of the h1. */
    display: block;
    width: fit-content;
    font-family: var(--rm-font-display);
    font-size: var(--rm-fs-meta);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    /* ⚠ letter-spacing adds its full amount AFTER the last character too, so
       the box overhangs the visible text by 0.18em and the rule would run
       proud on the right. Pulling the end margin back by the same amount
       trims exactly that trailing space. */
    margin-inline-end: -0.18em;
    /* ⚠ CREAM, NOT TEAL - and this single declaration is what sets the scrim
       opacity below. As 13px text the eyebrow needs the full 4.5:1, and it was
       the ONLY element in the hero that could not reach it: teal forced a 0.55
       flat tint over the photograph, cream clears the same bar at 0.25. Half
       the tint, for one colour change. The red rule underneath keeps the brand
       accent. Change this back to teal and the scrim MUST go back to 0.55. */
    color: var(--rm-cream);
    margin-bottom: var(--rm-space-s);
  }
  /* The separator is now a slash in the copy ("Bay View, Milwaukee / Since
     1971") and the detail moved here, to a drawn rule. A centred interpunct is
     a recognisable house style of generated text; a rule is a deliberate mark
     and reads as typeset. */
  .rm-hero__lead::after {
    content: '';
    display: block;
    width: 100%;
    height: 3px;
    background: var(--rm-red);
    margin-top: var(--rm-space-2xs);
  }
  .rm-hero__intro {
    font-size: var(--rm-fs-lead);
    color: var(--rm-cream);
    max-width: 46ch;
    margin-bottom: var(--rm-space-m);
  }
  /* Layout comes from .rm-actions now; this only sets the spacing below. */
  .rm-hero__actions { margin-bottom: var(--rm-space-m); }
  /* Status strip - open/closed plus today's hours. The one thing people come
     to a shop's site to find out. */
  .rm-hero__status {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--rm-space-2xs) var(--rm-space-m);
    font-size: var(--rm-fs-small);
    color: var(--rm-cream);
    border-top: 1px solid rgb(239 233 217 / 0.25);
    padding-top: var(--rm-space-s);
  }
  .rm-hero__status-item { display: inline-flex; align-items: center; gap: var(--rm-space-2xs); }
  .rm-hero__status-item .fa-solid { color: var(--rm-teal); }
  .rm-status-dot {
    width: 0.6em;
    height: 0.6em;
    border-radius: 50%;
    flex: none;
    background: currentColor;
  }
  /* ⚠ Never colour-only. The dot is reinforced by the words "Open now" /
     "Closed" beside it (WCAG 1.4.1). */
  .rm-status--open   { color: #6FE3A0; }
  .rm-status--closed { color: var(--rm-yellow); }
}

@layer modules {
  /* ---- content_block --------------------------------------------------- */
  .rm-module__content { font-size: var(--rm-fs-body); }
  /* ⚠ The measure is applied to the PROSE CHILDREN, not to the wrapper.
     Capping the wrapper trapped the statements block inside a 40rem column,
     which left half the band empty and forced its two items into an uneven
     2-line / 3-line split. Constraining the text elements individually keeps
     the reading measure exactly where it matters and lets full-width blocks
     actually be full width. */
  .rm-module__content--reading > :is(p, h3, h4, h5, h6, ol, blockquote, figure),
  .rm-module__content--reading > ul:not(.rm-statements) { max-width: var(--rm-measure); }
  .rm-module__content--reading.is-centered > * { margin-inline: auto; }
  .rm-module__content > :last-child { margin-bottom: 0; }
  .rm-module__content h3 { margin-top: var(--rm-space-l); }
  .rm-module__content h3:first-child { margin-top: 0; }

  /* ---- Statements -----------------------------------------------------
     Two short lines lifted out of the About paragraphs: the special-order
     promise and the local-music one. Inside running text they read as asides;
     given a rule, the display face and their own column they read as the
     commitments they are.

     Authored as <ul class="rm-statements"> in the WYSIWYG rather than as a new
     module - the markup is three tags and does not warrant a layout of its own.
     ⚠ If an editor rewrites this block in the visual editor, the classes are
     what carry the styling. See docs/MODULES.md. */
  .rm-statements {
    list-style: none;
    padding: 0;
    margin: var(--rm-space-l) 0;
    display: grid;
    gap: var(--rm-space-m);
  }
  @container module (min-width: 46rem) {
    .rm-statements { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  }
  .rm-statements li {
    margin: 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--rm-space-2xs);
    padding-top: var(--rm-space-s);
    border-top: var(--rm-border-bold) solid var(--rm-red);
  }
  .rm-statements__text {
    font-family: var(--rm-font-display);
    font-weight: 700;
    font-size: var(--rm-fs-h3);
    line-height: 1.15;
    letter-spacing: -0.02em;
    text-wrap: balance;
  }
  /* The special-order line is a service, not a slogan, so it gets a route to
     the form instead of just sitting there being claimed. */
  .rm-statements__cta {
    font-family: var(--rm-font-display);
    font-size: var(--rm-fs-meta);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    text-decoration: none;
    color: var(--rm-teal-ink);
    display: inline-flex;
    align-items: center;
    gap: var(--rm-space-3xs);
    margin-top: auto;
  }
  .rm-statements__cta::after {
    font-family: 'Font Awesome 7 Free';
    font-weight: 900;
    content: '\f061';
    font-size: 0.9em;
    transition: transform var(--rm-fast) var(--rm-ease);
  }
  .rm-statements__cta:hover { color: var(--rm-red); }
  .rm-statements__cta:hover::after { transform: translateX(3px); }

  /* ---- cta_cards ------------------------------------------------------
     The catalog cards. The sticker treatment (hard ink
     keyline + offset shadow) is spent HERE, on the primary commercial action,
     and on primary buttons. Applying it everywhere would make it wallpaper. */
  /* ⚠ minmax(0, 1fr), NEVER a bare 1fr, and min-width: 0 on the item.
     A grid item's automatic minimum size is its MIN-CONTENT size, not zero. The
     card holds a button whose label cannot wrap below a certain width, so with
     the default min-width:auto the track computed to 303px inside a 280px grid
     and pushed 3px of horizontal scroll onto every 320px phone. Measured, not
     theorised - tools/qa/overflow.mjs catches exactly this. */
  .rm-cards {
    display: grid;
    gap: var(--rm-space-m);
    grid-template-columns: minmax(0, 1fr);
  }
  @container module (min-width: 34rem) {
    .rm-cards { grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); }
  }
  .rm-card {
    display: flex;
    flex-direction: column;
    min-width: 0;
    background: var(--rm-white);
    color: var(--rm-ink);
    border: var(--rm-border-bold) solid var(--rm-ink);
    border-radius: var(--rm-radius);
    box-shadow: var(--rm-shadow-hard);
    padding: var(--rm-space-m);
    transition: transform var(--rm-medium) var(--rm-ease),
                box-shadow var(--rm-medium) var(--rm-ease);
  }
  /* :has() lets the whole card react to focus landing on the link inside it,
     so keyboard and mouse get the same affordance without a JS listener. */
  .rm-card:hover,
  .rm-card:has(a:focus-visible) {
    transform: translate(3px, 3px);
    box-shadow: 2px 2px 0 var(--rm-ink);
  }
  .rm-card__icon {
    font-size: 2rem;
    line-height: 1;
    color: var(--rm-red);
    margin-bottom: var(--rm-space-s);
  }
  .rm-card__icon .rm-brand { width: 2rem; height: 2rem; }
  .rm-card__title { margin-bottom: var(--rm-space-2xs); }
  .rm-card__text { margin-bottom: var(--rm-space-m); color: var(--rm-muted); }
  /* Push every card's action to the same baseline across a row, and let it
     fill the card. Because the cards are equal-width grid tracks, that makes
     every card button identical without hard-coding a width anywhere. */
  .rm-card__action { margin-top: auto; align-self: stretch; width: 100%; }
  /* Stretched link: the whole card is the hit area, but the accessible name
     still comes from the real anchor text. */
  .rm-card__action::after { content: ''; position: absolute; inset: 0; }
  .rm-card { position: relative; }

  /* ---- visit ----------------------------------------------------------- */
  .rm-visit {
    display: grid;
    gap: var(--rm-space-l);
    grid-template-columns: 1fr;
    align-items: start;
  }
  @container module (min-width: 46rem) {
    .rm-visit { grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); gap: var(--rm-space-xl); }
  }
  .rm-visit__address { font-style: normal; font-size: var(--rm-fs-lead); margin-bottom: var(--rm-space-m); }
  .rm-visit__actions { margin-bottom: var(--rm-space-l); }

  .rm-hours { width: 100%; margin: 0 0 var(--rm-space-m); }
  .rm-hours caption {
    text-align: left;
    font-family: var(--rm-font-display);
    font-weight: 700;
    font-size: var(--rm-fs-meta);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--rm-red);
    padding-bottom: var(--rm-space-2xs);
  }
  .rm-hours th, .rm-hours td {
    padding: var(--rm-space-2xs) var(--rm-space-xs);
    border-bottom: 1px solid var(--rm-hairline);
  }
  .rm-hours th { font-weight: 400; }
  .rm-hours td { text-align: right; font-variant-numeric: tabular-nums; }
  .rm-hours tr:last-child th, .rm-hours tr:last-child td { border-bottom: 0; }

  /* Zebra kept VERY quiet - 3.5% ink. A seven-row, two-column table does not
     need banding to be scannable, so this is texture rather than a wayfinding
     device; anything stronger competes with the one row that actually matters.

     ⚠ :not(.is-today) IS LOAD-BEARING, not tidiness. Without it:
         .rm-hours tbody tr:nth-child(odd)  = (0,2,2)
         .rm-hours .is-today                = (0,2,0)
     the zebra out-specifies the today highlight, so the white background only
     appeared on EVEN rows. That is a bug that hides itself: Thursday is row 4
     and looked perfect, Friday is row 5 and silently lost its highlight. Any
     "works on some days" symptom in this table is this. */
  .rm-hours tbody tr:nth-child(odd):not(.is-today) { background: rgb(26 21 18 / 0.035); }

  /* Today. A white card on the cream band, so it lifts off the zebra instead of
     fighting it, plus a red rule down the leading edge.
     ⚠ Not colour alone: the row is also bolder, carries the rule, and the cell
     has a screen-reader "(today)" label (WCAG 1.4.1). */
  .rm-hours .is-today { background: var(--rm-white); box-shadow: inset 3px 0 0 var(--rm-red); }
  .rm-hours .is-today th, .rm-hours .is-today td { font-weight: 700; color: var(--rm-red); }
  .rm-module--dark .rm-hours tbody tr:nth-child(odd):not(.is-today) { background: rgb(239 233 217 / 0.06); }
  .rm-module--dark .rm-hours .is-today { background: rgb(239 233 217 / 0.12); box-shadow: inset 3px 0 0 var(--rm-teal); }
  .rm-module--dark .rm-hours th,
  .rm-module--dark .rm-hours td { border-bottom-color: rgb(239 233 217 / 0.2); }
  .rm-module--dark .rm-hours .is-today th,
  .rm-module--dark .rm-hours .is-today td { color: var(--rm-teal); }
  .rm-module--dark .rm-hours caption { color: var(--rm-teal); }

  /* Map. aspect-ratio reserves the box before the iframe loads, so nothing
     below it jumps (CLS). */
  .rm-map {
    position: relative;
    aspect-ratio: 4 / 3;
    border: var(--rm-border-bold) solid var(--rm-ink);
    border-radius: var(--rm-radius);
    overflow: hidden;
    background: var(--rm-cream-dim);
  }
  .rm-map iframe { width: 100%; height: 100%; border: 0; display: block; }
  /* Click-to-load facade. The map is a third-party frame that sets cookies the
     moment it loads, so it stays behind a button - same reasoning that made us
     self-host the fonts. The address and Map It! link are always visible
     regardless, so nobody has to load a map to get directions. */
  .rm-map__facade {
    position: absolute;
    inset: 0;
    display: grid;
    place-content: center;
    gap: var(--rm-space-xs);
    justify-items: center;
    text-align: center;
    padding: var(--rm-space-m);
    background: var(--rm-cream-dim);
    border: 0;
    cursor: pointer;
    color: var(--rm-ink);
  }
  .rm-map__facade-note { font-size: var(--rm-fs-meta); color: var(--rm-muted); max-width: 30ch; }

  /* ---- link_grid (We Support) ------------------------------------------ */
  .rm-links {
    display: grid;
    gap: var(--rm-space-s);
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .rm-links li { margin: 0; min-width: 0; }
  .rm-links__item {
    display: flex;
    flex-direction: column;
    gap: var(--rm-space-3xs);
    height: 100%;
    padding: var(--rm-space-m);
    background: var(--rm-white);
    border: var(--rm-border) solid var(--rm-ink);
    border-radius: var(--rm-radius);
    text-decoration: none;
    color: var(--rm-ink);
    transition: background-color var(--rm-fast) var(--rm-ease),
                color var(--rm-fast) var(--rm-ease);
  }
  .rm-links__item:hover,
  .rm-links__item:focus-visible { background: var(--rm-ink); color: var(--rm-cream); }
  .rm-links__name { font-family: var(--rm-font-display); font-weight: 700; font-size: var(--rm-fs-h4); }
  .rm-links__note { font-size: var(--rm-fs-small); color: var(--rm-muted); }
  .rm-links__item:hover .rm-links__note,
  .rm-links__item:focus-visible .rm-links__note { color: var(--rm-cream); }

  /* ---- form ------------------------------------------------------------ */
  .rm-form-wrap { max-width: var(--rm-measure); }
  .rm-form-wrap .gform_wrapper { margin: 0; }
  .rm-form-wrap label,
  .rm-form-wrap .gfield_label { font-weight: 700; display: block; margin-bottom: var(--rm-space-3xs); }
  .rm-form-wrap input[type='text'],
  .rm-form-wrap input[type='email'],
  .rm-form-wrap input[type='tel'],
  .rm-form-wrap textarea,
  .rm-form-wrap select {
    width: 100%;
    padding: var(--rm-space-xs) var(--rm-space-s);
    background: var(--rm-white);
    border: var(--rm-border) solid var(--rm-ink);
    border-radius: var(--rm-radius);
    min-height: 44px;
  }
  .rm-form-wrap textarea { min-height: 9rem; resize: vertical; }
  /* GF ships its own list markup for choice fields; these are STRUCTURE, not
     prose, so they get no list indent. */
  .rm-form-wrap ul, .rm-form-wrap ol { list-style: none; padding-left: 0; }
  .rm-form-wrap .gform_footer { margin-top: var(--rm-space-m); }
  /* GF's own theme stylesheets are disabled (inc/integrations.php), and the
     submit control now carries .rm-btn .rm-btn--primary via the gform_submit_button
     filter - so it inherits the site button wholesale. All that is left is
     neutralising GF's stray `button` class and the browser default. */
  .rm-form-wrap .gform_button {
    appearance: none;
    -webkit-appearance: none;
    width: auto;
  }
  .rm-form-wrap .gfield_required { color: var(--rm-red); }
  .rm-form-wrap .gfield_description.validation_message,
  .rm-form-wrap .gform_validation_errors {
    color: var(--rm-red);
    font-weight: 700;
    /* Errors are never colour-only - GF prints text, and the icon below adds a
       second non-colour cue (WCAG 1.4.1). */
  }
  .rm-form-wrap .validation_message::before {
    font-family: 'Font Awesome 7 Free';
    font-weight: 900;
    content: '\f00d';
    margin-right: var(--rm-space-3xs);
  }
}

@layer modules {
  /* ---- gallery ---------------------------------------------------------
     Pattern-library module. Not on the page today; built because the shop will
     want to show in-store shots and RSD queues. */
  .rm-gallery {
    display: grid;
    gap: var(--rm-space-s);
    grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .rm-gallery li { margin: 0; min-width: 0; }
  .rm-gallery a,
  .rm-gallery img { display: block; width: 100%; }
  .rm-gallery img {
    aspect-ratio: 1;
    object-fit: cover;
    border: var(--rm-border) solid var(--rm-ink);
    border-radius: var(--rm-radius);
    transition: opacity var(--rm-fast) var(--rm-ease);
  }
  .rm-gallery a:hover img { opacity: 0.85; }

  .rm-lightbox {
    border: none;
    padding: 0;
    background: transparent;
    max-width: 100vw;
    max-height: 100vh;
  }
  .rm-lightbox::backdrop { background: rgb(26 21 18 / 0.92); }
  .rm-lightbox__fig { margin: 0; display: grid; gap: var(--rm-space-s); justify-items: center; }
  .rm-lightbox__fig img { max-height: 82vh; width: auto; border: var(--rm-border-bold) solid var(--rm-cream); }
  .rm-lightbox__cap { color: var(--rm-cream); font-size: var(--rm-fs-small); text-align: center; }
  .rm-lightbox__close {
    position: fixed;
    top: var(--rm-space-s);
    right: var(--rm-space-s);
    width: 44px;
    height: 44px;
    display: grid;
    place-items: center;
    background: var(--rm-ink);
    color: var(--rm-cream);
    border: var(--rm-border) solid var(--rm-cream);
    border-radius: 50%;
    cursor: pointer;
  }

  /* ---- media_text ------------------------------------------------------ */
  .rm-media-text { display: grid; gap: var(--rm-space-l); align-items: center; }
  .rm-media-text > * { min-width: 0; }
  @container module (min-width: 44rem) {
    .rm-media-text { grid-template-columns: 1fr 1fr; gap: var(--rm-space-xl); }
    /* Source order stays text-then-image so it reads correctly when stacked;
       the flip is presentational only. */
    .rm-media-text--flip .rm-media-text__media { order: -1; }
  }
  .rm-media-text__media img {
    width: 100%;
    border: var(--rm-border-bold) solid var(--rm-ink);
    border-radius: var(--rm-radius);
  }

  /* ---- quote ----------------------------------------------------------- */
  .rm-quote { max-width: var(--rm-measure); margin-inline: auto; text-align: center; }
  .rm-quote__text {
    font-family: var(--rm-font-display);
    font-size: var(--rm-fs-h3);
    font-weight: 500;
    line-height: 1.3;
    margin: 0 0 var(--rm-space-s);
    text-wrap: balance;
  }
  .rm-quote__cite { font-style: normal; font-size: var(--rm-fs-small); color: var(--rm-muted); }
  .rm-module--dark .rm-quote__cite { color: var(--rm-teal); }

  /* ---- accordion -------------------------------------------------------
     Native <details>/<summary>. Zero JavaScript, keyboard-operable and
     screen-reader-announced for free. */
  .rm-accordion { max-width: var(--rm-measure); }
  .rm-accordion__item { border-bottom: var(--rm-border) solid var(--rm-hairline); }
  .rm-accordion__summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--rm-space-s);
    padding: var(--rm-space-s) 0;
    cursor: pointer;
    font-family: var(--rm-font-display);
    font-weight: 700;
    font-size: var(--rm-fs-h4);
    list-style: none;
    min-height: 44px;
  }
  .rm-accordion__summary::-webkit-details-marker { display: none; }
  .rm-accordion__summary::after {
    font-family: 'Font Awesome 7 Free';
    font-weight: 900;
    content: '\f078';
    font-size: 0.75em;
    color: var(--rm-red);
    transition: transform var(--rm-fast) var(--rm-ease);
    flex: none;
  }
  .rm-accordion__item[open] .rm-accordion__summary::after { transform: rotate(180deg); }
  .rm-accordion__body { padding-bottom: var(--rm-space-s); }
}

/* ==========================================================================
   UTILITIES  - last layer, so these always win.
   ========================================================================== */
@layer utilities {
  /* Visually hidden but announced. The clip-path pairing keeps it working in
     browsers that have dropped the deprecated clip property. */
  .screen-reader-text {
    position: absolute !important;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
  .screen-reader-text:focus {
    position: static !important;
    width: auto;
    height: auto;
    clip: auto;
    clip-path: none;
    margin: 0;
  }

  .rm-center { text-align: center; }
  .rm-stack > * + * { margin-top: var(--rm-space-s); }
  .rm-row { display: flex; flex-wrap: wrap; gap: var(--rm-space-xs); }
  .rm-nowrap { white-space: nowrap; }
  [hidden] { display: none !important; }

  /* Utility pages (404, /thanks/) - short documents that need vertical
     presence without a hero. */
  .rm-utility {
    min-height: 58vh;
    display: grid;
    align-content: center;
    padding-block: var(--rm-space-2xl);
  }
  .rm-utility__inner {
    display: grid;
    gap: var(--rm-space-l);
    grid-template-columns: 1fr;
    align-items: center;
  }
  @media (min-width: 44rem) {
    .rm-utility__inner { grid-template-columns: 1.4fr 0.6fr; }
  }
  .rm-utility__art { justify-self: center; }
  .rm-utility__art img { max-width: 15rem; }
  .rm-utility__routes { list-style: none; padding: 0; margin: var(--rm-space-m) 0 0; }
  .rm-utility__routes li { margin: 0 0 var(--rm-space-2xs); }
}
