/* ==========================================================================
   TheBullseye — site stylesheet
   Built to the TheBullseye Brand Guidelines v4.

   Colour        Bern Red #E50914 primary; black, gunmetal, quick silver and
                 white as the neutral stage. Baby pink, pacific blue and amber
                 orange are accents and are used sparingly.
   Typography    Pathway Extreme for headings, Red Hat Display for body.
                 Emphasis inside body copy uses bold Red Hat Display, never
                 Pathway Extreme (brand book, Typography > Structure).
   Imagery       People photography renders grayscale. Gradients stay
                 supportive and never overpower type.
   Logo          Never below 75px wide, never above 150px, never restyled.
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Pathway+Extreme:opsz,wght@8..144,200..800&family=Red+Hat+Display:ital,wght@0,300..900;1,300..900&display=swap');

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Primary */
  --bern-red: #E50914;
  --bern-red-dark: #B80710;
  --bern-red-tint: rgba(229, 9, 20, 0.08);

  /* Secondary — the neutral stage */
  --black: #000000;
  --ink: #07080A;
  --gunmetal: #2B303A;
  --quick-silver: #A6A6A8;
  --white: #FFFFFF;

  /* Accents — use sparingly */
  --baby-pink: #F8C0C8;
  --pacific-blue: #1CA9C9;
  --amber-orange: #FF8700;

  /* Derived surfaces */
  --bg: var(--white);
  --bg-soft: #F7F7F8;
  --bg-dark: var(--ink);
  --text: var(--ink);
  --text-muted: #5B6070;
  --text-faint: #8A8F9E;
  --border: #E6E7EB;
  --border-strong: #D3D5DC;

  /* Type */
  --font-display: 'Pathway Extreme', 'Segoe UI', system-ui, sans-serif;
  --font-body: 'Red Hat Display', 'Segoe UI', system-ui, sans-serif;

  /* Scale */
  --step--1: clamp(0.82rem, 0.79rem + 0.14vw, 0.9rem);
  --step-0:  clamp(1rem, 0.96rem + 0.18vw, 1.09rem);
  --step-1:  clamp(1.2rem, 1.12rem + 0.4vw, 1.45rem);
  --step-2:  clamp(1.5rem, 1.35rem + 0.75vw, 2rem);
  --step-3:  clamp(1.9rem, 1.62rem + 1.4vw, 2.9rem);
  --step-4:  clamp(2.1rem, 1.75rem + 2.1vw, 3.5rem);
  --step-5:  clamp(2.5rem, 1.9rem + 3.4vw, 4.8rem);

  /* Rhythm — the brand book asks for generous spacing */
  --gutter: clamp(1.15rem, 4vw, 2.5rem);
  --section-y: clamp(4.5rem, 9vw, 8.5rem);
  --max: 1240px;
  --max-narrow: 820px;

  --radius: 14px;
  --radius-lg: 26px;
  --radius-pill: 999px;

  --shadow-sm: 0 1px 2px rgba(7, 8, 10, 0.05), 0 4px 14px rgba(7, 8, 10, 0.04);
  --shadow-md: 0 10px 34px rgba(7, 8, 10, 0.09);
  --shadow-lg: 0 26px 70px rgba(7, 8, 10, 0.14);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 88px;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.62;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* clip, not hidden: hidden turns body into a scroll container, which is the
     usual reason position:sticky quietly stops sticking. The services section
     depends on sticky, so this must stay clip. */
  overflow-x: clip;
}

h1, h2, h3, h4, h5 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.06;
  letter-spacing: -0.022em;
  margin: 0 0 0.5em;
  color: var(--ink);
  text-wrap: balance;
}

h1 { font-size: var(--step-5); }
h2 { font-size: var(--step-4); }
h3 { font-size: var(--step-2); }
h4 { font-size: var(--step-1); }

p { margin: 0 0 1.15em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

/* Emphasis in body copy is bold Red Hat Display, per the brand book. */
strong, b { font-family: var(--font-body); font-weight: 700; color: var(--ink); }

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

img { max-width: 100%; height: auto; display: block; }

ul, ol { margin: 0 0 1.15em; padding-left: 1.2em; }
li { margin-bottom: 0.4em; }

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

:focus-visible {
  outline: 3px solid var(--bern-red);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 999;
  background: var(--ink);
  color: var(--white);
  padding: 0.8rem 1.2rem;
  border-radius: 0 0 var(--radius) 0;
}
.skip-link:focus { left: 0; }

/* --------------------------------------------------------------------------
   3. Layout helpers
   -------------------------------------------------------------------------- */
.wrap {
  width: 100%;
  max-width: var(--max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.wrap-narrow { max-width: var(--max-narrow); }

.section { padding-block: var(--section-y); position: relative; }
.section-soft { background: var(--bg-soft); }
.section-dark { background: var(--bg-dark); color: rgba(255,255,255,0.82); }
.section-dark h1, .section-dark h2, .section-dark h3, .section-dark h4 { color: var(--white); }

.eyebrow {
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--bern-red);
  margin: 0 0 1rem;
  display: block;
}
.section-dark .eyebrow { color: var(--bern-red); }

.lede {
  font-size: var(--step-1);
  color: var(--text-muted);
  max-width: 62ch;
  line-height: 1.55;
}
.section-dark .lede { color: rgba(255,255,255,0.7); }

.section-head { max-width: 68ch; margin-bottom: clamp(2.5rem, 5vw, 4rem); }
.section-head.center { margin-inline: auto; text-align: center; }

/* --------------------------------------------------------------------------
   4. Buttons
   -------------------------------------------------------------------------- */
.btn {
  --btn-bg: var(--bern-red);
  --btn-fg: var(--white);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  padding: 0.92rem 1.7rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1.5px solid var(--btn-bg);
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--step-0);
  line-height: 1;
  cursor: pointer;
  transition: transform 0.22s var(--ease), background 0.22s var(--ease),
              border-color 0.22s var(--ease), color 0.22s var(--ease),
              box-shadow 0.22s var(--ease);
  white-space: nowrap;
}
.btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 26px rgba(229, 9, 20, 0.26);
  background: var(--bern-red-dark);
  border-color: var(--bern-red-dark);
}
.btn:active { transform: translateY(0); }

.btn-ghost {
  --btn-bg: transparent;
  --btn-fg: var(--ink);
  border-color: var(--border-strong);
}
.btn-ghost:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--white);
  box-shadow: var(--shadow-md);
}

.btn-on-dark {
  --btn-bg: transparent;
  --btn-fg: var(--white);
  border-color: rgba(255,255,255,0.35);
}
.btn-on-dark:hover {
  background: var(--white);
  border-color: var(--white);
  color: var(--ink);
  box-shadow: none;
}

.btn-sm { padding: 0.66rem 1.25rem; font-size: var(--step--1); }

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-weight: 700;
  color: var(--bern-red);
  font-size: var(--step--1);
}
.link-arrow::after {
  content: "→";
  transition: transform 0.24s var(--ease);
}
.link-arrow:hover::after { transform: translateX(5px); }

/* --------------------------------------------------------------------------
   5. Header
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(255,255,255,0.82);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
.site-header.is-stuck {
  border-bottom-color: var(--border);
  box-shadow: 0 1px 20px rgba(7,8,10,0.05);
}

.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-height: 84px;
}

/* Brand book: logo never below 75px or above 150px wide on screen. The
   source art is now cropped to the ink (see assets/logo-wordmark-*.png), so
   this width is the width of the visible wordmark rather than of a mostly
   transparent canvas. Sits at the top of the permitted range. */
.logo img {
  width: clamp(124px, 12vw, 150px);
  min-width: 75px;
  max-width: 150px;
  height: auto;
  display: block;
}

.nav { display: flex; align-items: center; gap: 0.35rem; }

.nav a.nav-link,
.nav button.nav-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.55rem 0.9rem;
  border: 0;
  background: none;
  border-radius: var(--radius-pill);
  font-weight: 600;
  font-size: 0.96rem;
  color: var(--text-muted);
  cursor: pointer;
  transition: color 0.2s var(--ease), background 0.2s var(--ease);
}
.nav .nav-link:hover { color: var(--ink); background: var(--bg-soft); }
.nav .nav-link[aria-current="page"] { color: var(--ink); }
.nav .nav-link[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: 0.9rem;
  right: 0.9rem;
  bottom: 0.28rem;
  height: 2px;
  background: var(--bern-red);
  border-radius: 2px;
}

.nav-caret { transition: transform 0.24s var(--ease); font-size: 0.7em; }
[aria-expanded="true"] .nav-caret { transform: rotate(180deg); }

/* Resources dropdown */
.has-menu { position: relative; }
.nav-menu {
  position: absolute;
  top: calc(100% + 0.6rem);
  left: 50%;
  translate: -50% 0;
  width: min(400px, 88vw);
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 0.6rem;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity 0.24s var(--ease), transform 0.24s var(--ease), visibility 0.24s;
}
.has-menu.open .nav-menu { opacity: 1; visibility: visible; transform: translateY(0); }

.nav-menu a {
  display: block;
  padding: 0.75rem 0.9rem;
  border-radius: var(--radius);
  transition: background 0.18s var(--ease);
}
.nav-menu a:hover { background: var(--bg-soft); }
.nav-menu .m-label { font-weight: 700; color: var(--ink); display: block; }
.nav-menu .m-desc { font-size: var(--step--1); color: var(--text-faint); }

.nav-toggle {
  display: none;
  width: 44px; height: 44px;
  align-items: center; justify-content: center;
  border: 1px solid var(--border);
  background: var(--white);
  border-radius: 12px;
  cursor: pointer;
}
.nav-toggle span {
  display: block; width: 19px; height: 2px;
  background: var(--ink); border-radius: 2px;
  position: relative; transition: background 0.2s;
}
.nav-toggle span::before, .nav-toggle span::after {
  content: ""; position: absolute; left: 0;
  width: 19px; height: 2px; background: var(--ink); border-radius: 2px;
  transition: transform 0.26s var(--ease);
}
.nav-toggle span::before { top: -6px; }
.nav-toggle span::after  { top: 6px; }
.nav-toggle[aria-expanded="true"] span { background: transparent; }
.nav-toggle[aria-expanded="true"] span::before { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span::after  { transform: translateY(-6px) rotate(-45deg); }

/* --------------------------------------------------------------------------
   6. Hero
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  padding-block: clamp(3.5rem, 7vw, 6.5rem) clamp(3rem, 6vw, 5rem);
  overflow: hidden;
}

/* Supportive brand gradient — never louder than the type. */
.hero::before {
  content: "";
  position: absolute;
  inset: -30% -10% auto -10%;
  height: 78%;
  background:
    radial-gradient(58% 62% at 18% 12%, rgba(229,9,20,0.11), transparent 68%),
    radial-gradient(48% 55% at 88% 4%, rgba(255,135,0,0.09), transparent 70%);
  filter: blur(8px);
  pointer-events: none;
  z-index: 0;
}
.hero > * { position: relative; z-index: 1; }

.availability {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.44rem 1rem 0.44rem 0.7rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  background: rgba(255,255,255,0.72);
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 1.6rem;
}
.availability .dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--bern-red);
  box-shadow: 0 0 0 0 rgba(229,9,20,0.55);
  animation: pulse 2.4s infinite;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(229,9,20,0.5); }
  70%  { box-shadow: 0 0 0 9px rgba(229,9,20,0); }
  100% { box-shadow: 0 0 0 0 rgba(229,9,20,0); }
}

.hero h1 { max-width: 17ch; margin-bottom: 0.35em; }
.hero .accent { color: var(--bern-red); }

/* Rotating word in the headline */
.rotator {
  display: inline-grid;
  vertical-align: baseline;
  overflow: hidden;
  text-align: left;
  /* width is set by js/site.js to match the word currently showing */
  transition: width 0.52s var(--ease-out);
}
.rotator > span {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translateY(0.5em) rotateX(-35deg);
  transition: opacity 0.5s var(--ease-out), transform 0.5s var(--ease-out);
  color: var(--bern-red);
  white-space: nowrap;
}
.rotator > span.is-active { opacity: 1; transform: none; }
.rotator > span.is-leaving { opacity: 0; transform: translateY(-0.5em) rotateX(35deg); }

.hero-sub { font-size: var(--step-1); color: var(--text-muted); max-width: 44ch; margin-bottom: 2rem; }
.hero-actions { display: flex; flex-wrap: wrap; gap: 0.85rem; }

/* --------------------------------------------------------------------------
   7. Marquees (clients, work, testimonials)
   -------------------------------------------------------------------------- */
.marquee {
  position: relative;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
}
.marquee-track {
  display: flex;
  gap: var(--mq-gap, 3.2rem);
  width: max-content;
  animation: marquee var(--mq-duration, 52s) linear infinite;
  will-change: transform;
}
.marquee:hover .marquee-track { animation-play-state: paused; }
.marquee-reverse .marquee-track { animation-direction: reverse; }
@keyframes marquee {
  from { transform: translate3d(0,0,0); }
  to   { transform: translate3d(-50%,0,0); }
}

.trust-heading {
  text-align: center;
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 2.2rem;
}

.client-logo {
  flex: 0 0 auto;
  height: 34px;
  width: auto;
  object-fit: contain;
  filter: grayscale(1);
  opacity: 0.5;
  transition: filter 0.3s var(--ease), opacity 0.3s var(--ease);
}
.client-logo:hover { filter: grayscale(0); opacity: 1; }

/* --------------------------------------------------------------------------
   8. Cards
   -------------------------------------------------------------------------- */
.grid { display: grid; gap: clamp(1rem, 2vw, 1.6rem); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }

.card {
  position: relative;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: clamp(1.5rem, 2.4vw, 2.1rem);
  overflow: hidden;
  transition: transform 0.34s var(--ease), box-shadow 0.34s var(--ease),
              border-color 0.34s var(--ease);
}
.card:hover {
  transform: translateY(-5px);
  box-shadow: var(--shadow-md);
  border-color: var(--border-strong);
}
.card h3 { margin-bottom: 0.35em; }

/* A hairline of Bern Red that draws itself on hover. */
.card::after {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 3px;
  background: var(--bern-red);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.4s var(--ease-out);
}
.card:hover::after { transform: scaleX(1); }

.card-promise { font-weight: 700; color: var(--bern-red); margin-bottom: 0.7em; font-size: var(--step-0); }
.card-body { color: var(--text-muted); font-size: 0.98rem; margin-bottom: 1.3em; }

.service-card.is-featured { border-color: var(--bern-red); }
.service-badge {
  position: absolute;
  top: 1.1rem; right: 1.1rem;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bern-red);
  background: var(--bern-red-tint);
  padding: 0.32rem 0.66rem;
  border-radius: var(--radius-pill);
}
.service-media {
  aspect-ratio: 16 / 10;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-soft);
  margin-bottom: 1.25rem;
}
/* `contain`, not `cover`.

   The artwork is 1600x1200 and 1184x864 - roughly 4:3 - and it was sitting in
   a 16/10 box under `object-fit: cover`, which fills the box by cropping
   whatever does not fit. That quietly sliced 15-20% off the top and bottom of
   every service icon, and got worse the narrower the screen.

   `contain` fits the whole image inside the box instead. Nothing is ever cut;
   at an awkward window size you get a little of the card's own background
   above and below, which is why there is padding here to make that read as
   deliberate. */
.service-media img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 0.6rem;
}

/* --------------------------------------------------------------------------
   9. Process timeline
   -------------------------------------------------------------------------- */
.process-list { position: relative; display: grid; gap: clamp(1rem, 2vw, 1.4rem); }
.process-list::before {
  content: "";
  position: absolute;
  left: 27px; top: 12px; bottom: 12px;
  width: 2px;
  background: var(--border);
}
/* Filled by JS as the section scrolls through the viewport. */
.process-list::after {
  content: "";
  position: absolute;
  left: 27px; top: 12px;
  width: 2px;
  height: var(--progress, 0%);
  background: var(--bern-red);
  transition: height 0.18s linear;
}

.process-step {
  position: relative;
  display: grid;
  grid-template-columns: 56px 1fr;
  gap: 1.3rem;
  align-items: start;
}
.process-dot {
  position: relative;
  z-index: 1;
  width: 56px; height: 56px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--white);
  border: 2px solid var(--border);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.02rem;
  color: var(--text-faint);
  transition: border-color 0.34s var(--ease), color 0.34s var(--ease),
              background 0.34s var(--ease), transform 0.34s var(--ease);
}
.process-step.is-active .process-dot {
  border-color: var(--bern-red);
  color: var(--white);
  background: var(--bern-red);
  transform: scale(1.06);
}
.process-body {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: clamp(1.2rem, 2vw, 1.8rem);
  transition: border-color 0.34s var(--ease), box-shadow 0.34s var(--ease);
}
.process-step.is-active .process-body { border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
.process-body h3 { font-size: var(--step-1); margin-bottom: 0.4em; }
.process-body p { color: var(--text-muted); font-size: 0.98rem; }

.tools { display: flex; flex-wrap: wrap; gap: 0.45rem; margin-top: 1rem; }
.tool {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-muted);
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 0.3rem 0.72rem;
}

/* --------------------------------------------------------------------------
   10. Counters / stat row
   -------------------------------------------------------------------------- */
.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1.5rem; }
.stat { text-align: center; }
.stat-num {
  font-family: var(--font-display);
  font-size: var(--step-4);
  font-weight: 700;
  line-height: 1;
  color: var(--bern-red);
  letter-spacing: -0.03em;
}
.stat-label { font-size: var(--step--1); color: var(--text-muted); margin-top: 0.5rem; font-weight: 600; }

/* --------------------------------------------------------------------------
   11. Work cards
   -------------------------------------------------------------------------- */
.work-card {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  aspect-ratio: 16 / 9;
  background: var(--gunmetal);
  display: block;
}
.work-card img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.66s var(--ease); }
.work-card:hover img { transform: scale(1.06); }
.work-card::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(0,0,0,0.82), rgba(0,0,0,0.06) 55%, transparent);
}
.work-meta {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 0.9rem 1rem;
  z-index: 1;
  color: var(--white);
}
.work-name { font-size: 0.8rem; font-weight: 600; opacity: 0.85; }
.work-type { font-size: 0.92rem; font-weight: 700; }
.work-play {
  position: absolute;
  inset: 0;
  display: grid; place-items: center;
  z-index: 1;
  opacity: 0;
  transition: opacity 0.3s var(--ease);
}
.work-card:hover .work-play { opacity: 1; }
.work-play span {
  width: 52px; height: 52px;
  border-radius: 50%;
  background: rgba(229,9,20,0.94);
  display: grid; place-items: center;
  color: var(--white);
  font-size: 1.05rem;
  padding-left: 4px;
  box-shadow: 0 8px 26px rgba(0,0,0,0.35);
}

.work-strip .marquee-track { --mq-gap: 1rem; }
.work-strip .work-card { flex: 0 0 clamp(240px, 30vw, 330px); }

/* Portfolio grid card */
.pf-item { display: flex; flex-direction: column; gap: 0.7rem; }
.pf-item .pf-desc { font-size: 0.86rem; color: var(--text-muted); line-height: 1.5; }

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: end;
  padding: 1.2rem;
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  margin-bottom: 2.4rem;
}
.field { display: flex; flex-direction: column; gap: 0.4rem; min-width: 220px; flex: 1; }
.field label { font-size: 0.78rem; font-weight: 700; color: var(--text-muted); }
.field select, .field input {
  height: 46px;
  padding: 0 0.9rem;
  border: 1px solid var(--border-strong);
  border-radius: 11px;
  background: var(--white);
  font-size: 0.95rem;
}
.result-count { font-size: var(--step--1); color: var(--text-faint); font-weight: 600; }

/* --------------------------------------------------------------------------
   11b. Video lightbox
   --------------------------------------------------------------------------
   The overlay a portfolio card opens into. One of these exists per page; the
   player inside it is built on open and thrown away on close, so nothing keeps
   playing behind a closed overlay.
   -------------------------------------------------------------------------- */
.video-lightbox {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: grid;
  place-items: center;
  padding: clamp(1rem, 4vw, 3rem);
  opacity: 0;
  transition: opacity 0.28s var(--ease);
}
.video-lightbox[hidden] { display: none; }
.video-lightbox.is-open { opacity: 1; }

.video-lightbox-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(7, 8, 10, 0.88);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.video-lightbox-inner {
  position: relative;
  width: min(1180px, 100%);
  /* The stage below is locked to 16:9, so on a short-and-wide window - a
     laptop in landscape, a phone turned sideways - width is what has to give,
     or the player runs off the bottom of the screen and takes its controls
     with it. The 9rem is the padding above and below plus the title line. */
  max-width: calc((100vh - 9rem) * 16 / 9);
  max-width: calc((100svh - 9rem) * 16 / 9);
  margin-inline: auto;
  transform: translateY(14px) scale(0.985);
  transition: transform 0.42s var(--ease-out);
}
.video-lightbox.is-open .video-lightbox-inner { transform: none; }

.video-lightbox-title {
  margin: 0 0 0.7rem;
  padding-right: 3.2rem;
  color: var(--white);
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 700;
  letter-spacing: -0.01em;
}

.video-lightbox-stage {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--black);
  box-shadow: var(--shadow-lg);
}
.video-lightbox-stage iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.video-lightbox-close {
  position: absolute;
  top: -0.2rem;
  right: 0;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  color: var(--white);
  cursor: pointer;
  transition: background 0.24s var(--ease), transform 0.24s var(--ease);
}
.video-lightbox-close:hover { background: var(--bern-red); transform: scale(1.06); }
.video-lightbox-close:focus-visible { outline: 2px solid var(--white); outline-offset: 3px; }
.video-lightbox-close svg { width: 20px; height: 20px; }

/* The page behind must not scroll while the overlay is up.

   This goes on <html>, not on <body>. Body carries `overflow-x: clip` on
   purpose - see the note on the body rule - and `overflow: hidden` here would
   both overwrite that and turn body into a scroll container, which is exactly
   what stops the sticky services section from sticking. Locking the root
   leaves body alone and keeps the scroll position where it was. */
html.has-lightbox { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .video-lightbox,
  .video-lightbox-inner { transition: none; }
  .video-lightbox-inner { transform: none; }
}

/* --------------------------------------------------------------------------
   12. Testimonials
   -------------------------------------------------------------------------- */
.quote-card {
  flex: 0 0 min(400px, 82vw);
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.8rem;
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}
.quote-mark {
  font-family: var(--font-display);
  font-size: 2.6rem;
  line-height: 0.6;
  color: var(--bern-red);
  height: 1.1rem;
}
.quote-text { color: var(--text); font-size: 0.99rem; line-height: 1.6; flex: 1; }
.quote-author { font-size: var(--step--1); font-weight: 700; color: var(--text-faint); }

/* --------------------------------------------------------------------------
   12b. Showreel
   The red rim and glow are lifted from thebullseye.in. Nothing loads until
   the section is nearly in view; the ambient loop is silent, and the play
   button is the only control, so the video never starts making noise on its
   own and keyboard users have a real target to hit.
   -------------------------------------------------------------------------- */
.showreel-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: 36px;
  overflow: hidden;
  background: #0b0c0e;
  border: 2px solid var(--bern-red);
  box-shadow: 0 0 60px -8px rgba(229, 9, 20, 0.55),
              0 0 0 1px rgba(229, 9, 20, 0.32);
  transition: box-shadow 0.5s var(--ease-premium), transform 0.5s var(--ease-premium);
}
.showreel-frame.is-live {
  box-shadow: 0 0 90px -6px rgba(229, 9, 20, 0.65),
              0 0 0 1px rgba(229, 9, 20, 0.4);
}
.showreel-frame.is-empty {
  display: grid;
  place-items: center;
  text-align: center;
  padding: 2rem;
  border-style: dashed;
  border-color: rgba(255, 255, 255, 0.2);
  box-shadow: none;
}

/* THE VIDEO MUST NOT EAT THE SCROLL.

   A cross-origin iframe swallows wheel events itself - the parent page never
   receives them. With the reel sitting full width across the section, rolling
   the wheel over it did nothing at all, and crossing its edge made the page
   stutter as scrolling handed back and forth. That was the "not navigating
   properly" in this section.

   Nothing here needs to be clickable: the player runs in background mode with
   no controls of its own, it is aria-hidden and out of the tab order, and the
   only control is .showreel-toggle, which is a sibling above this layer and
   keeps its own pointer events. So the whole stage opts out, the wheel falls
   through to the page, and Lenis carries on smoothly. */
.showreel-stage { position: absolute; inset: 0; pointer-events: none; }
.showreel-stage iframe { pointer-events: none; }

/* Decorative too - it should never be the thing under the pointer either. */
.showreel-poster { pointer-events: none; }
.showreel-stage iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  /* No animation, and no opacity trickery. The player is simply visible.

     This element had a fade-in twice over, and both spellings failed the same
     way. First `opacity: 0` with an animation to bring it back; then
     `opacity: 1` with `animation-fill-mode: both`, which still applies the
     0% keyframe during the delay. In each case Vimeo was loading and playing
     perfectly behind something the browser was drawing at zero opacity, and
     the section read as an empty black panel.

     Nothing about the video's visibility depends on an animation now. The
     poster underneath covers the moment before the player paints, and Vimeo's
     own player fades itself in, so nothing is lost. */
  opacity: 1;
}

/* A still frame of the reel, sitting under the player.

   The player is not instant: it has to be fetched, and on a blocked autoplay
   or reduced-motion visit it may never start at all. Without this the section
   is a black rectangle in all of those cases. With it, there is always the
   video to look at. */
.showreel-poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}
.showreel-stage { z-index: 1; }
.showreel-toggle { z-index: 2; }

/* Before anything mounts the panel is not just black - it breathes, so the
   section reads as loading rather than broken. */
.showreel-frame::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 90% at 50% 45%,
              rgba(229, 9, 20, 0.16), transparent 70%);
  opacity: 1;
  transition: opacity 0.7s var(--ease-premium);
}
.showreel-frame.is-live::before { opacity: 0; }

/* The reel's only control.

   The panel used to carry a full-bleed dark scrim with an 84px red play button
   in the middle, because pressing it swapped the silent loop for a version
   with sound. There is no sound any more, so a button that large has nothing
   to justify it - it only stood between the reader and the picture.

   What is left is a small pill in the corner. It is deliberately quiet, and
   deliberately not shaped like a video player's chrome: the point is that this
   section reads as part of thebullseye.sg, not as an embed. */
.showreel-toggle {
  position: absolute;
  right: clamp(0.8rem, 2vw, 1.4rem);
  bottom: clamp(0.8rem, 2vw, 1.4rem);
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  padding: 0.5rem 1rem 0.5rem 0.75rem;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: var(--radius-pill);
  background: rgba(7, 8, 10, 0.55);
  -webkit-backdrop-filter: blur(10px);
          backdrop-filter: blur(10px);
  color: var(--white);
  font-family: var(--font-body);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  cursor: pointer;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease),
              background 0.3s var(--ease), border-color 0.3s var(--ease);
}

/* It stays out of the way until the panel is hovered or it has focus - but it
   is always there for a keyboard, and always there once paused. */
.showreel-frame:hover .showreel-toggle,
.showreel-toggle:focus-visible,
.showreel-toggle.is-paused,
.showreel-frame:not(.is-live) .showreel-toggle { opacity: 1; transform: none; }

.showreel-toggle:hover {
  background: var(--bern-red);
  border-color: var(--bern-red);
}
.showreel-toggle:focus-visible { outline: 3px solid var(--white); outline-offset: 3px; }

.showreel-toggle-icon { display: grid; place-items: center; width: 18px; height: 18px; }
.showreel-toggle-icon svg { width: 18px; height: 18px; grid-area: 1 / 1; }

/* One icon or the other, never both. */
.showreel-toggle .i-play  { display: none; }
.showreel-toggle.is-paused .i-pause { display: none; }
.showreel-toggle.is-paused .i-play  { display: block; }

@media (max-width: 640px) {
  .showreel-frame { border-radius: 22px; }
  /* No hover on a phone, so the control is simply always visible. */
  .showreel-toggle { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .showreel-frame, .showreel-toggle { transition: none; }
  .showreel-toggle { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   13. (removed: FAQ accordion)
   -------------------------------------------------------------------------- */


/* --------------------------------------------------------------------------
   14. CTA bands
   -------------------------------------------------------------------------- */
.cta-band {
  position: relative;
  border-radius: var(--radius-lg);
  padding: clamp(2.4rem, 5vw, 4.2rem);
  background: var(--ink);
  color: var(--white);
  overflow: hidden;
  text-align: center;
}
.cta-band::before {
  content: "";
  position: absolute;
  inset: auto -20% -70% -20%;
  height: 150%;
  background:
    radial-gradient(50% 55% at 30% 100%, rgba(229,9,20,0.42), transparent 70%),
    radial-gradient(46% 50% at 78% 96%, rgba(255,135,0,0.22), transparent 72%);
  pointer-events: none;
}
.cta-band > * { position: relative; }
.cta-band h2 { color: var(--white); max-width: 20ch; margin-inline: auto; }
.cta-band p { color: rgba(255,255,255,0.72); max-width: 52ch; margin-inline: auto; margin-bottom: 2rem; }

.cta-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: clamp(1.6rem, 3vw, 2.4rem) clamp(1.6rem, 3vw, 2.6rem);
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.cta-strip h3 { margin-bottom: 0.25em; }
.cta-strip p { color: var(--text-muted); margin: 0; }

/* --------------------------------------------------------------------------
   15. Pricing
   -------------------------------------------------------------------------- */
.price-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: 1.4rem; align-items: start; }
.price-card { display: flex; flex-direction: column; height: 100%; }
.price-card.is-featured {
  border-color: var(--bern-red);
  box-shadow: 0 18px 50px rgba(229,9,20,0.13);
}
.price-card.is-featured::after { transform: scaleX(1); }
.price-name { font-family: var(--font-display); font-size: var(--step-2); font-weight: 600; margin-bottom: 0.2em; }
.price-amount { font-family: var(--font-display); font-size: var(--step-3); font-weight: 700; color: var(--bern-red); letter-spacing: -0.03em; margin-bottom: 1.2rem; }
.price-label { font-size: 0.74rem; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-faint); margin-bottom: 0.5rem; }
.price-best { color: var(--text-muted); font-size: 0.94rem; margin-bottom: 1.4rem; }
.price-list { list-style: none; padding: 0; margin: 0 0 1.8rem; display: grid; gap: 0.65rem; }
.price-list li { position: relative; padding-left: 1.7rem; font-size: 0.94rem; color: var(--text); margin: 0; }
.price-list li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.44em;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--bern-red);
}
.price-card .btn { margin-top: auto; width: 100%; font-size: 0.82rem; letter-spacing: 0.08em; }

.compare { width: 100%; border-collapse: collapse; }
.compare th, .compare td { padding: 1.05rem 1.1rem; text-align: left; vertical-align: top; border-bottom: 1px solid var(--border); font-size: 0.94rem; }
.compare thead th { font-family: var(--font-display); font-size: 0.98rem; font-weight: 700; color: var(--ink); border-bottom: 2px solid var(--ink); }
.compare tbody th { font-weight: 700; color: var(--ink); width: 22%; }
.compare .col-us { color: var(--text); background: var(--bern-red-tint); }
.compare .col-them { color: var(--text-faint); }
.table-scroll { overflow-x: auto; border-radius: var(--radius); }

/* --------------------------------------------------------------------------
   16. (removed: booking quiz panel)
   -------------------------------------------------------------------------- */


.numbered { list-style: none; padding: 0; margin: 0; display: grid; gap: 1rem; }
.numbered li { display: grid; grid-template-columns: 34px 1fr; gap: 0.9rem; margin: 0; }
.numbered .n {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--bern-red);
  font-size: 0.9rem;
  padding-top: 0.15em;
}

/* --------------------------------------------------------------------------
   17. Article cards
   -------------------------------------------------------------------------- */
.article-card { display: flex; flex-direction: column; height: 100%; }
.article-media { aspect-ratio: 16/9; border-radius: var(--radius); overflow: hidden; background: var(--bg-soft); margin-bottom: 1.1rem; }
.article-media img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.6s var(--ease); }
.card:hover .article-media img { transform: scale(1.05); }
.article-tag { font-size: 0.7rem; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; color: var(--bern-red); margin-bottom: 0.6rem; }
.article-card h3 { font-size: var(--step-1); }
.article-meta { font-size: var(--step--1); color: var(--text-faint); margin-top: auto; padding-top: 1rem; font-weight: 600; }

/* --------------------------------------------------------------------------
   18. Team
   -------------------------------------------------------------------------- */
.team-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1.4rem; }
.team-card { text-align: center; }
.team-avatar {
  width: 92px; height: 92px;
  margin: 0 auto 1.1rem;
  border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--font-display);
  font-size: 2.1rem;
  font-weight: 700;
  color: var(--white);
  background: linear-gradient(140deg, var(--bern-red), #8E0510);
  box-shadow: 0 10px 28px rgba(229,9,20,0.24);
}
.team-name { font-family: var(--font-display); font-size: var(--step-1); font-weight: 600; margin-bottom: 0.15em; }
.team-role { font-size: var(--step--1); color: var(--text-muted); font-weight: 600; }

/* --------------------------------------------------------------------------
   19. Footer
   -------------------------------------------------------------------------- */
.site-footer { background: var(--ink); color: rgba(255,255,255,0.62); padding-block: clamp(3rem, 6vw, 4.5rem) 2rem; }
.footer-top { display: grid; grid-template-columns: minmax(240px, 1.6fr) repeat(auto-fit, minmax(150px, 1fr)); gap: clamp(1.8rem, 4vw, 3rem); padding-bottom: 2.8rem; border-bottom: 1px solid rgba(255,255,255,0.1); }
.footer-brand img { width: 168px; height: auto; display: block; margin-bottom: 1.1rem; }
.footer-brand p { color: rgba(255,255,255,0.55); font-size: 0.94rem; max-width: 34ch; }
.footer-col h4 { color: var(--white); font-size: 0.82rem; font-family: var(--font-body); font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; margin-bottom: 1.1rem; }
.footer-col ul { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.62rem; }
.footer-col li { margin: 0; }
.footer-col a { font-size: 0.93rem; color: rgba(255,255,255,0.62); transition: color 0.2s var(--ease); }
.footer-col a:hover { color: var(--white); }

.form-note { font-size: 0.8rem; margin-top: 0.7rem; color: var(--quick-silver); min-height: 1.1em; }

.footer-bottom { display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between; align-items: center; padding-top: 1.8rem; font-size: 0.86rem; }
.footer-legal { display: flex; gap: 1.3rem; }
.footer-legal a:hover { color: var(--white); }

/* --------------------------------------------------------------------------
   20. Legal / prose pages
   -------------------------------------------------------------------------- */
.prose { max-width: 72ch; }
.prose h2 { font-size: var(--step-2); margin-top: 2.4em; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { font-size: var(--step-1); margin-top: 1.8em; }
.prose p, .prose li { color: var(--text-muted); }

/* --------------------------------------------------------------------------
   21. Scroll animation primitives
   Everything below is inert until js/site.js adds .in-view.
   -------------------------------------------------------------------------- */
/* Gated on html.js, so a reader without JavaScript sees the full page. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 0.72s var(--ease-out), transform 0.72s var(--ease-out);
  transition-delay: var(--delay, 0ms);
  will-change: opacity, transform;
}
.js [data-reveal="left"]  { transform: translateX(-34px); }
.js [data-reveal="right"] { transform: translateX(34px); }
.js [data-reveal="scale"] { transform: scale(0.955); }
.js [data-reveal="fade"]  { transform: none; }

.js [data-reveal].in-view { opacity: 1; transform: none; }

/* Words of a headline rising in sequence */
.word-rise { display: inline-block; overflow: hidden; vertical-align: baseline; }
.js .word-rise > span {
  display: inline-block;
  transform: translateY(105%);
  transition: transform 0.78s var(--ease-out);
  transition-delay: var(--delay, 0ms);
}
.in-view .word-rise > span, .word-rise.in-view > span { transform: translateY(0); }

/* Scroll progress bar under the header */
.scroll-progress {
  position: fixed;
  top: 0; left: 0;
  height: 3px;
  width: 100%;
  transform: scaleX(var(--sp, 0));
  transform-origin: left;
  background: var(--bern-red);
  z-index: 200;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   22. Responsive
   -------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .nav-toggle { display: inline-flex; }
  .nav {
    position: fixed;
    inset: 76px 0 auto 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0.2rem;
    background: var(--white);
    border-bottom: 1px solid var(--border);
    padding: 1rem var(--gutter) 1.6rem;
    box-shadow: var(--shadow-lg);
    transform: translateY(-14px);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.26s var(--ease), transform 0.26s var(--ease), visibility 0.26s;
    max-height: calc(100vh - 76px);
    overflow-y: auto;
  }
  .nav.open { opacity: 1; visibility: visible; transform: none; }
  .nav .nav-link { justify-content: space-between; padding: 0.9rem 0.6rem; font-size: 1.05rem; }
  .nav .nav-link[aria-current="page"]::after { display: none; }
  .nav .btn { margin-top: 0.6rem; }

  .nav-menu {
    position: static;
    translate: none;
    width: auto;
    opacity: 1;
    visibility: visible;
    transform: none;
    box-shadow: none;
    border: 0;
    border-left: 2px solid var(--border);
    border-radius: 0;
    padding: 0 0 0 0.7rem;
    margin: 0.2rem 0 0.6rem 0.6rem;
    display: none;
  }
  .has-menu.open .nav-menu { display: block; }
}

@media (max-width: 640px) {
  .process-list::before, .process-list::after { left: 21px; }
  .process-step { grid-template-columns: 44px 1fr; gap: 0.9rem; }
  .process-dot { width: 44px; height: 44px; font-size: 0.85rem; }
  .cta-strip { flex-direction: column; align-items: flex-start; }
  .footer-bottom { flex-direction: column; align-items: flex-start; }
  .quote-card { flex-basis: 84vw; }
}

/* --------------------------------------------------------------------------
   23. Reduced motion — respected everywhere, per the brand's quality floor
   -------------------------------------------------------------------------- */
@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;
  }
  .js [data-reveal] { opacity: 1 !important; transform: none !important; }
  .js .word-rise > span { transform: none !important; }
  .marquee-track { animation: none !important; }
  .rotator > span { position: static; }
}

/* --------------------------------------------------------------------------
   24. Print
   -------------------------------------------------------------------------- */
@media print {
  .site-header, .site-footer, .scroll-progress, .marquee { display: none; }
  body { color: #000; }
  .js [data-reveal] { opacity: 1; transform: none; }
}

/* ==========================================================================
   23. PREMIUM MOTION LAYER
   --------------------------------------------------------------------------
   Added to make the site feel closer to a Framer-built agency site: inertial
   smooth scroll, longer and larger reveals, headlines that fill with colour
   as you scroll, marquees that react to scroll speed, and a custom cursor.

   These rules come last on purpose, so they win over the earlier ones without
   anything above needing to be edited.
   ========================================================================== */

/* PERFORMANCE: values written by JavaScript on every scroll or pointer frame
   are registered as non-inheriting. An ordinary custom property inherits, so
   changing it on an element also recalculates the style of everything inside
   that element; registered with inherits:false, only the element itself is
   touched. Do NOT register --fill, --i, --n, --f or --delay here: child
   elements read those from their parent. */
@property --mq-skew { syntax: '<angle>';      inherits: false; initial-value: 0deg; }
@property --zs      { syntax: '<number>';     inherits: false; initial-value: 1; }
@property --py      { syntax: '<length>';     inherits: false; initial-value: 0px; }
@property --sp      { syntax: '<number>';     inherits: false; initial-value: 0; }
@property --hx      { syntax: '<number>';     inherits: false; initial-value: 0; }
@property --hp      { syntax: '<number>';     inherits: false; initial-value: 0; }
@property --cx      { syntax: '<length>';     inherits: false; initial-value: -50px; }
@property --cy      { syntax: '<length>';     inherits: false; initial-value: -50px; }
@property --rx      { syntax: '<length>';     inherits: false; initial-value: -50px; }
@property --ry      { syntax: '<length>';     inherits: false; initial-value: -50px; }
@property --tx      { syntax: '<length>';     inherits: false; initial-value: -60px; }
@property --ty      { syntax: '<length>';     inherits: false; initial-value: -60px; }
@property --mxp     { syntax: '<percentage>'; inherits: false; initial-value: 50%; }
@property --myp     { syntax: '<percentage>'; inherits: false; initial-value: 32%; }

:root {
  /* The curve kemana.com uses. Quick to leave, very long to settle — that
     long tail is most of what reads as "expensive". */
  --ease-premium: cubic-bezier(0.12, 0.23, 0.5, 1);
  --ease-glide:   cubic-bezier(0.16, 1, 0.3, 1);

  /* Reveal distances, tiered by how much weight the element carries. */
  --rise-sm: 18px;
  --rise:    50px;
  --rise-lg: 90px;
}

/* ---------------------------------------------------------- smooth scroll */
/* Lenis drives the scroll position itself, so the native smoothing must be
   off or the two fight each other. */
html.lenis, html.lenis body { height: auto; }
/* The stylesheet sets scroll-behavior: smooth further up. Lenis nudges the
   window every frame, so leaving that on makes the browser try to animate
   each nudge and the whole page judders. The .lenis class is present the
   whole time Lenis is running, so this switches it off for exactly as long
   as Lenis is in charge — and leaves native smooth scrolling in place if
   the script never loads. */
html.lenis { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }

/* -------------------------------------------------------- upgraded reveals */
/* opacity 0.001 rather than 0 keeps the element on its own GPU layer, so the
   first frame of the transition does not hitch. */
.js [data-reveal] {
  opacity: 0.001;
  transform: translate3d(0, var(--rise), 0);
  transition:
    opacity   1.05s var(--ease-premium),
    transform 1.05s var(--ease-premium);
  transition-delay: var(--delay, 0ms);
  will-change: opacity, transform;
}
.js [data-reveal="sm"]    { transform: translate3d(0, var(--rise-sm), 0); }
.js [data-reveal="lg"]    { transform: translate3d(0, var(--rise-lg), 0); }
.js [data-reveal="left"]  { transform: translate3d(-56px, 0, 0); }
.js [data-reveal="right"] { transform: translate3d(56px, 0, 0); }
.js [data-reveal="scale"] { transform: scale(0.94) translate3d(0, 28px, 0); }
.js [data-reveal="fade"]  { transform: none; }

/* A wipe that uncovers the element from the bottom up. Used on imagery. */
.js [data-reveal="clip"] {
  transform: none;
  opacity: 1;
  clip-path: inset(100% 0 0 0);
  transition: clip-path 1.15s var(--ease-premium);
  transition-delay: var(--delay, 0ms);
}
.js [data-reveal="clip"].in-view { clip-path: inset(0 0 0 0); }

.js [data-reveal].in-view { opacity: 1; transform: none; }

/* Headline words rise further and settle longer than before. */
.js .word-rise > span {
  transform: translate3d(0, 110%, 0) rotate(2.5deg);
  transition: transform 1.1s var(--ease-premium);
  transition-delay: var(--delay, 0ms);
}
.in-view .word-rise > span,
.word-rise.in-view > span { transform: translate3d(0, 0, 0) rotate(0); }

/* ------------------------------------------------- scroll-driven text fill */
/* The heading starts faint and fills to full colour word by word as the
   section travels up the screen. --fill is written once per frame by premium.js;
   each word works out its own opacity from it, so there is only ever one
   style write per heading per frame. */
.fill-text > span {
  opacity: clamp(0.16, calc(var(--fill, 0) * var(--n, 1) - var(--i, 0)), 1);
  transition: opacity 0.18s linear;
}
html:not(.js) .fill-text > span { opacity: 1; }

/* ------------------------------------------------------------ stats band */
.stats-band {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.stat {
  background: var(--bg);
  padding: clamp(1.6rem, 3.2vw, 2.6rem) clamp(1.1rem, 2vw, 1.8rem);
  text-align: center;
  transition: background 0.5s var(--ease-premium);
}
.stat:hover { background: var(--bg-soft); }
.stat-num {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(2.2rem, 1.6rem + 2.6vw, 3.6rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.stat-num .unit { color: var(--bern-red); }
.stat-label {
  display: block;
  margin-top: 0.7rem;
  font-size: var(--step--1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--text-faint);
}

/* --------------------------------------------------- marquee, made premium */
/* The row leans into the direction of travel when you scroll fast, then
   settles back. premium.js writes --mq-skew on the .marquee host.
   PERFORMANCE: the skew sits on the host, never inside @keyframes marquee.
   A custom property inside keyframes forces the browser to re-resolve the
   animation on the main thread every time it changes, for every logo; kept
   out, the track's translate animation runs on the compositor. */
.marquee { transform: skewX(var(--mq-skew, 0deg)); }
/* Wider fade so logos dissolve rather than getting cut off at the edge. */
.marquee {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
}
/* Hovering slows the row (premium.js lowers its playbackRate). */
.marquee:hover .marquee-track { animation-play-state: running; }

.client-logo {
  height: 42px;
  opacity: 0.42;
  filter: grayscale(1) contrast(1.05);
  transition: filter 0.55s var(--ease-premium),
              opacity 0.55s var(--ease-premium),
              transform 0.55s var(--ease-premium);
}
.client-logo:hover { opacity: 1; filter: grayscale(0); transform: scale(1.08); }

/* Three rows of clients, the middle one running the other way. */
.client-rows { display: grid; gap: clamp(1.1rem, 2.2vw, 1.9rem); }
.client-rows .marquee:nth-child(2) .client-logo { height: 34px; }

/* ------------------------------------------------------------ custom cursor */
/* Pointer-fine only: never shown on touch, and never in the way of a click. */
.cursor-dot, .cursor-ring {
  position: fixed;
  top: 0; left: 0;
  border-radius: 50%;
  pointer-events: none;
  z-index: 9999;
  opacity: 0;
  transition: opacity 0.3s var(--ease-premium);
}
.cursor-dot {
  width: 6px; height: 6px;
  background: var(--bern-red);
  transform: translate3d(var(--cx, -50px), var(--cy, -50px), 0) translate(-50%, -50%);
}
.cursor-ring {
  width: 38px; height: 38px;
  border: 1px solid rgba(229, 9, 20, 0.5);
  transform: translate3d(var(--rx, -50px), var(--ry, -50px), 0) translate(-50%, -50%);
  transition: opacity 0.3s var(--ease-premium),
              width 0.4s var(--ease-premium),
              height 0.4s var(--ease-premium),
              background 0.4s var(--ease-premium),
              border-color 0.4s var(--ease-premium);
}
.has-cursor .cursor-dot, .has-cursor .cursor-ring { opacity: 1; }
.has-cursor.cursor-hover .cursor-ring {
  width: 68px; height: 68px;
  background: rgba(229, 9, 20, 0.08);
  border-color: rgba(229, 9, 20, 0.85);
}
.has-cursor.cursor-hover .cursor-dot { opacity: 0; }
@media (hover: none), (pointer: coarse) {
  .cursor-dot, .cursor-ring { display: none; }
}

/* --------------------------------------------------------- magnetic buttons */
[data-magnetic] {
  transform: translate3d(var(--mx, 0px), var(--my, 0px), 0);
  transition: transform 0.45s var(--ease-glide);
}
[data-magnetic].is-pulled { transition: transform 0.14s linear; }

/* A light sweep that crosses a button on hover. */
.btn { position: relative; overflow: hidden; isolation: isolate; }
.btn::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(115deg, transparent 30%, rgba(255,255,255,0.22) 50%, transparent 70%);
  transform: translateX(-120%);
  transition: transform 0.85s var(--ease-premium);
}
.btn:hover::after { transform: translateX(120%); }

/* ------------------------------------------------------ service card polish */
.service-card { transition: transform 0.7s var(--ease-premium), box-shadow 0.7s var(--ease-premium), border-color 0.7s var(--ease-premium); }
.service-card:hover { transform: translateY(-8px); }
/* No hover zoom on these. Scaling an image inside a clipped box is another
   way of cropping it, which is the thing being fixed. The card itself still
   lifts on hover, so the interaction is not lost. */
.work-card img { transition: transform 1.1s var(--ease-premium); }

/* ------------------------------------------------------------ reduced motion */
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal],
  .js [data-reveal="clip"],
  .js .word-rise > span {
    transition: none !important;
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
  .marquee-track { animation: none !important; transform: none !important; }
  .marquee { transform: none !important; }
  .cursor-dot, .cursor-ring { display: none !important; }
  .fill-text > span { opacity: 1 !important; }
  .btn::after { display: none; }
}

/* ==========================================================================
   24. STAGE TWO — opening sequence, live background, horizontal scroll
   --------------------------------------------------------------------------
   Added on top of section 23. Covers:
     A. the logo curtain that opens the site
     B. the background the whole site now sits on
     C. the pinned horizontal scroll used by the services section
     D. zoom-on-scroll
     E. the drag-to-browse testimonial rail
     F. the reworked cursor
   ========================================================================== */

:root {
  /* The page no longer sits on flat white. */
  --bg-base:  #FAFAFA;
  --bg-tint:  #F4F4F6;
  --grid-line: rgba(43, 48, 58, 0.055);
  --aurora-red: rgba(229, 9, 20, 0.11);
  --aurora-ink: rgba(43, 48, 58, 0.09);
  --curtain-ease: cubic-bezier(0.76, 0, 0.24, 1);
}

/* ==========================================================================
   A. Opening curtain
   Only ever shown when JavaScript is on, only once per browsing session, and
   never when the visitor has asked for reduced motion. Clicking or pressing a
   key skips it.
   ========================================================================== */
.preloader { display: none; }

.js .preloader {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: grid;
  place-items: center;
  background: var(--ink);
  transform: translateY(0);
  transition: transform 0.85s var(--curtain-ease);
}
.js .preloader.is-lifting { transform: translateY(-101%); }
.js .preloader.is-done    { display: none; }

.preloader-inner { display: grid; justify-items: center; gap: 1.6rem; }

.preloader-logo {
  width: clamp(132px, 17vw, 200px);
  height: auto;
  opacity: 0;
  transform: translateY(14px) scale(0.97);
  animation: pl-logo 0.7s var(--ease-premium) 0.1s forwards;
}
@keyframes pl-logo {
  to { opacity: 1; transform: none; }
}

/* A hairline that fills for the length of the hold, so the pause reads as
   loading rather than as the page being broken. */
.preloader-bar {
  width: clamp(120px, 16vw, 180px);
  height: 2px;
  background: rgba(255, 255, 255, 0.16);
  overflow: hidden;
}
.preloader-bar > span {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--bern-red);
  transform: scaleX(0);
  transform-origin: left;
  animation: pl-bar var(--pl-hold, 2200ms) cubic-bezier(0.4, 0, 0.2, 1) 0.2s forwards;
}
@keyframes pl-bar { to { transform: scaleX(1); } }

.preloader-word {
  font-family: var(--font-body);
  font-size: 0.68rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.42);
  opacity: 0;
  animation: pl-logo 0.55s var(--ease-premium) 0.32s forwards;
}

/* The page itself drops into place as the curtain leaves. */
.js body.is-booting .site-header,
.js body.is-booting main,
.js body.is-booting .site-footer { opacity: 0; transform: translateY(-5vh); }

.js .site-header, .js main, .js .site-footer {
  transition: opacity 0.75s var(--ease-premium) 0.1s,
              transform 0.85s var(--curtain-ease) 0.1s;
}

/* A guaranteed resting state. Once the entrance has had its time, the page is
   pinned visible with no transition left to get stuck part-way. A blank page
   is the worst thing this file could cause, so it is made unreachable. */
.js body.is-revealed .site-header,
.js body.is-revealed main,
.js body.is-revealed .site-footer {
  opacity: 1;
  transform: none;
  transition: none;
}

/* ==========================================================================
   B. The background everything sits on
   Four stacked layers, all of them faint. The brand book asks that gradients
   stay supportive and never fight the type, so nothing here goes above 11%.
   ========================================================================== */
html { background: var(--bg-base); }
body { background: transparent; }

.bg-canvas {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
  background: var(--bg-base);
}

/* 1 — engineering grid, faded out towards the edges */
.bg-grid {
  position: absolute;
  inset: -2px;
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: 68px 68px;
  -webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 32%, #000 20%, transparent 78%);
          mask-image: radial-gradient(ellipse 90% 70% at 50% 32%, #000 20%, transparent 78%);
}

/* 2 — two slow-drifting colour fields
   PERFORMANCE: the drift animates translate only. Animating scale on a
   blurred layer makes the browser re-draw the blur as the size changes;
   a pure translate is moved by the compositor without re-drawing. */
.bg-aurora {
  position: absolute;
  border-radius: 50%;
  filter: blur(70px);
  will-change: transform;
}
.bg-aurora.a1 {
  width: 52vw; height: 52vw;
  top: -14vw; left: -8vw;
  background: radial-gradient(circle, var(--aurora-red), transparent 68%);
  animation: drift-a 34s ease-in-out infinite alternate;
}
.bg-aurora.a2 {
  width: 46vw; height: 46vw;
  top: 34vh; right: -12vw;
  background: radial-gradient(circle, var(--aurora-ink), transparent 68%);
  animation: drift-b 41s ease-in-out infinite alternate;
}
@keyframes drift-a {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(9vw, 7vh, 0); }
}
@keyframes drift-b {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-11vw, -9vh, 0); }
}

/* 3 — a soft light that follows the pointer. This is the "interactive" part;
       --mxp/--myp are written by premium.js. */
.bg-spot {
  position: absolute;
  inset: 0;
  background: radial-gradient(
    380px circle at var(--mxp, 50%) var(--myp, 32%),
    rgba(229, 9, 20, 0.075),
    transparent 62%);
  transition: opacity 0.6s var(--ease-premium);
}
@media (hover: none), (pointer: coarse) { .bg-spot { opacity: 0; } }

/* 4 — a little grain so the flat areas are not dead flat */
.bg-noise {
  position: absolute;
  inset: 0;
  opacity: 0.032;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Soft sections become a translucent tint so the canvas still reads through. */
.section-soft { background: rgba(244, 244, 246, 0.72); }

/* --- hero furniture: oversized concentric rings, on brand for a bullseye --- */
.hero { position: relative; overflow: hidden; }
.hero-rings {
  position: absolute;
  top: 50%; right: -6vw;
  width: min(760px, 62vw);
  aspect-ratio: 1;
  transform: translate3d(0, calc(-50% + var(--py, 0px)), 0);
  pointer-events: none;
  z-index: 0;
  opacity: 0.5;
}
.hero-rings span {
  position: absolute;
  inset: 0;
  border: 1px solid rgba(229, 9, 20, 0.16);
  border-radius: 50%;
  animation: ring-pulse 7s var(--ease-premium) infinite;
}
.hero-rings span:nth-child(2) { inset: 12%; border-color: rgba(229, 9, 20, 0.13); animation-delay: 0.5s; }
.hero-rings span:nth-child(3) { inset: 24%; border-color: rgba(43, 48, 58, 0.11);  animation-delay: 1.0s; }
.hero-rings span:nth-child(4) { inset: 36%; border-color: rgba(229, 9, 20, 0.10); animation-delay: 1.5s; }
.hero-rings span:nth-child(5) {
  inset: 46%;
  background: radial-gradient(circle, rgba(229,9,20,0.13), transparent 70%);
  border-color: transparent;
  animation-delay: 2s;
}
@keyframes ring-pulse {
  0%, 100% { transform: scale(1);    opacity: 0.75; }
  50%      { transform: scale(1.045); opacity: 1; }
}
.hero .wrap { position: relative; z-index: 1; }
@media (max-width: 820px) { .hero-rings { opacity: 0.3; right: -30vw; } }

/* ==========================================================================
   C. Pinned horizontal scroll
   The section is made tall; the inner panel sticks while the track slides
   sideways. premium.js measures the track and sets both heights.
   ========================================================================== */
.hscroll { position: relative; }
.hscroll-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(0.9rem, 1.8vw, 1.6rem);
  overflow: hidden;
  /* Trimmed from 4.5-7rem. On a laptop the heading block was taking so much of
     the screen that the cards were left with barely a third of it. */
  padding-block: clamp(3.2rem, 6vh, 5rem) clamp(1rem, 2vh, 1.8rem);
}
.hscroll-head { flex: 0 0 auto; }
.hscroll-viewport {
  flex: 1 1 auto;
  /* `stretch`, not `center`. The track has to actually fill this box, because
     the cards size themselves against it - see below. */
  display: flex;
  align-items: stretch;
  overflow: hidden;
  min-height: 0;
}
.hscroll-track {
  display: flex;
  align-items: center;
  gap: clamp(1.1rem, 2vw, 1.8rem);
  padding-inline: var(--gutter);
  will-change: transform;
  transform: translate3d(calc(var(--hx, 0) * -1px), 0, 0);

  /* A DEFINITE height, and this is the whole fix.

     The cards carry `max-height: 100%`, and a percentage height only means
     anything when its parent has a height to measure against. The track used
     to be auto-height - derived from the tallest card - so `100%` resolved to
     the card's own height and capped nothing at all. Cards stayed 455px in a
     279px panel and the bottom of every one was sliced off, which is why the
     body copy stopped mid-sentence. */
  height: 100%;
}
.hscroll-card {
  flex: 0 0 clamp(280px, 27vw, 390px);
  display: flex;
  flex-direction: column;

  /* The panel is pinned at one screen tall and hides its overflow, so a card
     taller than the space left between the heading and the footer had its top
     and bottom sliced off - which is why the copy and the images looked cut
     short. Capping the card at the height available stops it overflowing in
     the first place. */
  max-height: 100%;
}

/* And the picture is what gives way, not the words.

   The image had a fixed 16/10 aspect ratio, so on a short window it was the
   card's largest fixed block and pushed the text out of the visible area.
   Here it is the only flexible part: it shrinks to whatever is spare once the
   heading, the promise and the body have taken what they need, down to a
   floor of 100px. Text is never the thing that gets cut. */
.hscroll-card .service-media {
  aspect-ratio: auto;
  flex: 1 1 auto;
  min-height: 100px;
}
.hscroll-card > h3,
.hscroll-card .card-promise,
.hscroll-card .card-body { flex: 0 0 auto; }

/* ------------------------------------------------------------------------
   Making the card actually fit the panel.

   Measured on a 1440x820 laptop: the heading block was taking 358px of the
   820, leaving the cards 326px when they needed 408 - so the bottom of every
   one was sliced off mid-sentence. Nothing here changes a single word; it
   just stops the heading eating the room the cards need.
   ------------------------------------------------------------------------ */

/* The section heading, pinned, does not need to be display-sized. */
.hscroll .section-head { margin-bottom: 0; }
.hscroll .section-head h2 { font-size: var(--step-2); margin-bottom: 0.35em; }
.hscroll .section-head .lede {
  font-size: var(--step-0);
  max-width: 76ch;
  margin-bottom: 0;
}

/* Tighter cards. The copy is unchanged - this is padding and heading size. */
.hscroll-card { padding: clamp(1.1rem, 1.7vw, 1.5rem); }
.hscroll-card h3 { font-size: var(--step-1); margin-bottom: 0.3em; }
.hscroll-card .card-promise { margin-bottom: 0.45em; }
.hscroll-card .card-body { margin-bottom: 0; }

/* The image scales with the height of the screen, between a floor and a
   ceiling. On a tall monitor it is generous; on a short laptop it gives way
   so the words still fit. It is the only flexible part of the card, and the
   card's own `max-height: 100%` is the backstop that keeps the whole thing
   inside the panel whatever happens. */
.hscroll-card .service-media {
  /* 12vh, not 17. At 17 the floor on a 660px-tall laptop was 112px, which is
     taller than the image is allowed to shrink to - so flex could not give
     the words their room back and one card clipped again. 12vh keeps the
     floor under the shrink point at every height that was tested. */
  min-height: clamp(76px, 12vh, 170px);
  max-height: 200px;
  margin-bottom: 0.9rem;
}

/* Where you are in the run, and a nudge that you should keep scrolling. */
.hscroll-foot {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 1.1rem;
  padding-inline: var(--gutter);
}
.hscroll-bar {
  position: relative;
  flex: 1 1 auto;
  height: 2px;
  background: var(--border);
  overflow: hidden;
}
.hscroll-bar > span {
  position: absolute;
  inset: 0;
  background: var(--bern-red);
  transform: scaleX(var(--hp, 0));
  transform-origin: left;
}
.hscroll-hint {
  flex: 0 0 auto;
  font-size: 0.68rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--text-faint);
  white-space: nowrap;
}
.hscroll-count { font-variant-numeric: tabular-nums; color: var(--text); }

/* Below the pin breakpoint, and under reduced motion, it becomes an ordinary
   swipeable row. Nothing is pinned and nothing is hidden. */
.hscroll.is-static .hscroll-sticky { position: static; height: auto; display: block; padding-block: 0; }
.hscroll.is-static .hscroll-viewport { overflow: visible; display: block; }
.hscroll.is-static .hscroll-track {
  transform: none;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: 1rem;
  -webkit-overflow-scrolling: touch;
}
.hscroll.is-static .hscroll-card { scroll-snap-align: start; }
.hscroll.is-static .hscroll-foot { display: none; }

/* ==========================================================================
   D. Zoom on scroll
   --zs is written per frame by premium.js: the element is slightly enlarged
   as it enters, settles at its true size mid-screen, and swells again as it
   leaves. Applied to media, never to body text.
   ========================================================================== */
[data-zoom] { overflow: hidden; }
[data-zoom] > img,
[data-zoom] > .zoom-inner {
  display: block;
  width: 100%;
  transform: scale(var(--zs, 1));
  transform-origin: center;
  will-change: transform;
}
.zoom-pop { transform: scale(var(--zs, 1)); transform-origin: center; will-change: transform; }

/* ==========================================================================
   E. Drag-to-browse rail (testimonials)
   Built on a real overflow container, so trackpads, touch, keyboard and the
   scrollbar all work before any drag code runs. Dragging is an addition, not
   the only way through — WCAG 2.2 asks for exactly that.
   ========================================================================== */
.drag-rail {
  overflow-x: auto;
  overflow-y: hidden;
  /* Stop a hard flick at either end of the row chaining into the page - on a
     trackpad that reads as the whole site lurching sideways, and in some
     browsers it triggers the back-swipe gesture. */
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  cursor: grab;
  padding-block: 0.5rem 1.4rem;
  padding-inline: var(--gutter);
  -webkit-overflow-scrolling: touch;
}
.drag-rail::-webkit-scrollbar { display: none; }
.drag-rail.is-dragging { cursor: grabbing; scroll-snap-type: none; scroll-behavior: auto; }
.drag-rail.is-dragging * { user-select: none; pointer-events: none; }

.drag-track { display: flex; gap: clamp(1rem, 1.8vw, 1.6rem); width: max-content; }
.drag-rail .quote-card {
  flex: 0 0 clamp(290px, 30vw, 420px);
  scroll-snap-align: center;
  white-space: normal;
  transition: border-color 0.5s var(--ease-premium), box-shadow 0.5s var(--ease-premium),
              transform 0.5s var(--ease-premium);
}
.drag-rail .quote-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); }

.rail-controls {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: 0.4rem;
}
.rail-btn {
  width: 46px; height: 46px;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 1px solid var(--border-strong);
  background: var(--white);
  color: var(--text);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background 0.35s var(--ease-premium), color 0.35s var(--ease-premium),
              border-color 0.35s var(--ease-premium), transform 0.35s var(--ease-premium);
}
.rail-btn:hover:not(:disabled) { background: var(--bern-red); border-color: var(--bern-red); color: #fff; transform: scale(1.06); }
.rail-btn:disabled { opacity: 0.35; cursor: default; }
.rail-btn svg { width: 17px; height: 17px; }
/* The arrows sit at the right-hand end. */
.rail-controls { justify-content: flex-end; }

/* ==========================================================================
   F. Cursor, reworked
   A hard dot that tracks exactly, and a large ring that lags a long way
   behind it. The lag is the effect; it is set in premium.js.
   ========================================================================== */
.cursor-ring {
  /* 46px before. A pointer should be findable, not furniture. */
  width: 28px; height: 28px;
  border: 1px solid rgba(229, 9, 20, 0.42);
  background: rgba(229, 9, 20, 0.03);
  backdrop-filter: blur(1.5px);
  transition: width 0.55s var(--ease-premium), height 0.55s var(--ease-premium),
              background 0.55s var(--ease-premium), border-color 0.55s var(--ease-premium),
              opacity 0.4s var(--ease-premium);
}
/* Two fainter rings even further behind, so the trail reads as a tail. */
.cursor-trail {
  position: fixed;
  top: 0; left: 0;
  width: 20px; height: 20px;
  border-radius: 50%;
  border: 1px solid rgba(229, 9, 20, 0.16);
  pointer-events: none;
  z-index: 9998;
  opacity: 0;
  transform: translate3d(var(--tx, -60px), var(--ty, -60px), 0) translate(-50%, -50%);
  transition: opacity 0.4s var(--ease-premium);
}
.cursor-trail.t2 { width: 12px; height: 12px; border-color: rgba(229, 9, 20, 0.1); }
.has-cursor .cursor-trail { opacity: 1; }

/* The ring can carry a word when it is over something worth saying it about. */
.cursor-label {
  font-family: var(--font-body);
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #fff;
  opacity: 0;
  transition: opacity 0.3s var(--ease-premium);
  white-space: nowrap;
}
/* Hovering something clickable brightens the ring and nudges it up a little.
   It does NOT balloon: that only happens when there is a word to hold. */
.has-cursor.cursor-hover .cursor-ring {
  width: 38px; height: 38px;
  background: rgba(229, 9, 20, 0.10);
  border-color: rgba(229, 9, 20, 0.75);
}

/* The one case that earns the big ring - a card that says "View". */
.has-cursor.cursor-has-label .cursor-ring {
  width: 62px; height: 62px;
  background: rgba(229, 9, 20, 0.88);
  border-color: rgba(229, 9, 20, 0.88);
  backdrop-filter: none;
}
.has-cursor.cursor-hover .cursor-label { opacity: 0; }
.has-cursor.cursor-has-label .cursor-label { opacity: 1; }

/* ------------------------------------------------------------------------
   On a dark panel or a solid red button.

   Red on near-black is hard to pick out, and a red ring sitting on a red
   button is worse than no cursor at all - it hides the label you are about
   to click. So on those surfaces it turns white, shrinks, and thins out
   until it is barely more than a locator.
   ------------------------------------------------------------------------ */
.has-cursor.cursor-on-dark .cursor-ring {
  width: 22px; height: 22px;
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.5);
  backdrop-filter: none;
}
.has-cursor.cursor-on-dark .cursor-dot { background: rgba(255, 255, 255, 0.9); }
.has-cursor.cursor-on-dark .cursor-trail {
  border-color: rgba(255, 255, 255, 0.14);
  opacity: 0.5;
}

/* Even hovering a button on a dark panel, it stays out of the way. */
.has-cursor.cursor-on-dark.cursor-hover .cursor-ring {
  width: 30px; height: 30px;
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.75);
}

/* A label still needs room to be readable, dark surface or not. */
.has-cursor.cursor-on-dark.cursor-has-label .cursor-ring {
  width: 62px; height: 62px;
  background: rgba(229, 9, 20, 0.88);
  border-color: rgba(229, 9, 20, 0.88);
}
.has-cursor.cursor-hover .cursor-trail { opacity: 0; }
.has-cursor.cursor-down .cursor-ring { transform:
  translate3d(var(--rx, -50px), var(--ry, -50px), 0) translate(-50%, -50%) scale(0.82); }

@media (hover: none), (pointer: coarse) { .cursor-trail { display: none; } }

/* ==========================================================================
   Reduced motion — everything above resolves to a plain, still page.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .js .preloader { display: none !important; }
  .js body.is-booting .site-header,
  .js body.is-booting main,
  .js body.is-booting .site-footer { opacity: 1 !important; transform: none !important; }
  .bg-aurora, .hero-rings span { animation: none !important; }
  .bg-spot { opacity: 0 !important; }
  .hscroll-track { transform: none !important; }
  [data-zoom] > img, [data-zoom] > .zoom-inner, .zoom-pop { transform: none !important; }
  .cursor-trail { display: none !important; }
  .drag-rail { scroll-behavior: auto; }
}

/* --------------------------------------------------------------------------
   25. Sideways reveals must not widen the page
   --------------------------------------------------------------------------
   data-reveal="left"/"right" travel horizontally. In a row that already runs
   to the edge of the container, that travel sticks out past the viewport for
   the second or so the transition is running, and the browser answers with a
   horizontal scrollbar that appears and then vanishes.

   Clipping the row on the x-axis stops it. `clip` is used rather than
   `hidden` on purpose: hidden would turn these into scroll containers, and
   `overflow-y` stays visible so hover shadows still show.
   -------------------------------------------------------------------------- */
.grid,
.price-grid,
.team-grid,
.process-list,
.footer-top { overflow-x: clip; }

/* Slightly shorter sideways travel, so there is less to clip in the first
   place and the motion still reads. */
.js [data-reveal="left"]  { transform: translate3d(-44px, 0, 0); }
.js [data-reveal="right"] { transform: translate3d(44px, 0, 0); }

/* ==========================================================================
   F. Testimonial rail motion
   Everything positional is written by js/premium.js as a single transform per
   card, once a frame. Nothing here transitions transform or opacity, because
   a transition on a per-frame value just makes it lag behind the drag.

   What CSS still owns is the dressing keyed off --f, the card's nearness to
   the middle of the rail: 0 out at the edges, 1 dead centre.
   ========================================================================== */
.quote-rail {
  /* Cards tilt and grow, and the rail clips vertically, so it needs headroom
     that the plain drag rail does not. */
  padding-block: 2.2rem 2.6rem;
  perspective: 1400px;
}
.quote-rail .drag-track {
  transform-style: preserve-3d;
  align-items: stretch;
}

.quote-rail .quote-card {
  /* transform and opacity belong to the loop; only the dressing eases. */
  transition: border-color 0.45s var(--ease-premium),
              background 0.45s var(--ease-premium);
  will-change: transform, opacity;
  backface-visibility: hidden;
  position: relative;
  /* Resting shadow only, and it never changes. The lift is the layer below. */
  box-shadow: var(--shadow-sm);
}

/* The raised shadow of the card nearest the middle.

   This used to be one box-shadow on the card whose blur radius was driven
   straight off --f, so every frame the browser re-blurred a 50px-soft shadow
   for all ten cards. A changing blur radius cannot be composited - it repaints
   - and that was the main reason dragging the row felt heavy.

   Here the blur is fixed, so the shadow is rasterised once, and only the
   layer's opacity follows --f. Opacity is composited and costs effectively
   nothing. An outer box-shadow paints only outside the border box, so this
   never washes over the card's own background or its text. */
.quote-rail .quote-card::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: 0 22px 50px rgba(7, 8, 10, 0.15);
  opacity: var(--f, 0);
  pointer-events: none;
}

/* The card in the middle picks up the brand red on its edge and its mark. */
@supports (border-color: color-mix(in srgb, red 50%, blue)) {
  .quote-rail .quote-card {
    border-color: color-mix(in srgb,
                  var(--bern-red) calc(var(--f, 0) * 60%), var(--border));
  }
}
.quote-rail .quote-mark {
  opacity: calc(0.32 + var(--f, 0) * 0.68);
  transform: scale(calc(0.92 + var(--f, 0) * 0.18));
  transform-origin: left center;
}
/* The attribution carries the proof, so it does not get dimmed on top of
   whatever the card's own opacity is already doing. --text-faint measures
   3.23:1 on white, under the 4.5:1 minimum, so on these cards it steps up to
   Gunmetal from the brand palette (13.2:1) instead. */
.quote-rail .quote-author { color: var(--gunmetal); }

/* Hover is a separate, quieter signal - the loop owns transform, so this
   only touches what the loop does not. */
.quote-rail .quote-card:hover { background: #fff; }

/* While a drag is in progress the browser must not also try to smooth-scroll
   the rail, or the lean reads as lag. Handled in JS via .is-dragging. */
.quote-rail.is-dragging { scroll-behavior: auto; }

@media (prefers-reduced-motion: reduce) {
  /* premium.js never starts the loop here, so the cards keep whatever the
     base stylesheet gave them. Undo the headroom the motion needed. */
  .quote-rail { padding-block: 0.5rem 1.4rem; perspective: none; }
  .quote-rail .quote-card { box-shadow: none; opacity: 1; transform: none; }
  .quote-rail .quote-card::before { display: none; }
  .quote-rail .quote-mark { opacity: 1; transform: none; }
  .quote-rail .quote-author { opacity: 1; }
}


/* ==========================================================================
   ABOUT + CONTACT
   Added when the Pricing and Resources pages were retired, the "Let's Talk"
   button became a real Contact page, and About was cut back to one scroll.
   ========================================================================== */

/* Text that only screen readers should reach. Used by the scramble effect,
   which shows noise to the eye and must not read as noise to a reader. */
.sr-only {
  position: absolute;
  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;
}

/* --------------------------------------------------------------------------
   About - hero
   -------------------------------------------------------------------------- */
.about-hero .lede { max-width: 58ch; }
.about-headline { margin-bottom: 0.55em; }

/* The domain, presented as a live chip under the headline. */
.domain-chip {
  margin: 0 0 1.6rem;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  flex-wrap: wrap;
}

/* The other office. Quieter than the main domain chip on purpose - it is a
   footnote to the address above, not a second headline. */
.branch-chip {
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text-muted);
}
.branch-chip a {
  color: var(--text-muted);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.branch-chip a:hover,
.branch-chip a:focus-visible { color: var(--bern-red-dark); }
.domain-chip a {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 1.05rem 0.5rem 0.85rem;
  min-height: 44px;
  border: 1.5px solid var(--border-strong);
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--step-0);
  color: var(--text);
  text-decoration: none;
  background: rgba(255, 255, 255, 0.7);
  transition: border-color 0.28s var(--ease), color 0.28s var(--ease),
              transform 0.28s var(--ease), box-shadow 0.28s var(--ease);
}
.domain-chip a:hover,
.domain-chip a:focus-visible {
  border-color: var(--bern-red);
  color: var(--bern-red-dark);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.domain-dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--bern-red);
  box-shadow: 0 0 0 0 rgba(229, 9, 20, 0.55);
  animation: domain-pulse 2.4s var(--ease) infinite;
}
@keyframes domain-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(229, 9, 20, 0.5); }
  70%  { box-shadow: 0 0 0 11px rgba(229, 9, 20, 0); }
  100% { box-shadow: 0 0 0 0 rgba(229, 9, 20, 0); }
}

/* Counters */
.about-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1.6rem;
  margin-top: 3.2rem;
  padding-top: 2.4rem;
  border-top: 1px solid var(--border);
}
.about-stat { display: flex; flex-direction: column; gap: 0.4rem; }
.about-stat-num {
  font-family: var(--font-display);
  font-size: var(--step-4);
  font-weight: 700;
  line-height: 1;
  color: var(--bern-red);
  font-variant-numeric: tabular-nums;
}
.about-stat-label {
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text-muted);
  max-width: 22ch;
}

/* --------------------------------------------------------------------------
   About - the domain ribbon
   A full-bleed band that says the address out loud. Decorative, so it is
   aria-hidden in the markup and the same words appear as a real link above.
   -------------------------------------------------------------------------- */
.domain-band {
  background: var(--ink);
  padding: 1.15rem 0;
  overflow: hidden;
  border-block: 1px solid rgba(255, 255, 255, 0.08);
}
.domain-band .marquee-track { --mq-gap: 0; }
.ribbon-item {
  display: inline-flex;
  align-items: center;
  gap: 1.6rem;
  padding-right: 1.6rem;
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 700;
  letter-spacing: 0.02em;
  color: rgba(255, 255, 255, 0.9);
  white-space: nowrap;
}
.ribbon-item:nth-child(even) { color: var(--bern-red); }
.ribbon-dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.6;
}

/* --------------------------------------------------------------------------
   About - the company
   -------------------------------------------------------------------------- */
.story-section { position: relative; }
.story-spine {
  position: absolute;
  left: max(1rem, calc((100vw - var(--max)) / 2 - 34px));
  top: 12%;
  width: 40px;
  height: 76%;
  opacity: 0.55;
  pointer-events: none;
}
.story-copy {
  max-width: 62ch;
  margin-bottom: 3.4rem;
}
.story-copy .lede:last-child { margin-bottom: 0; }

.pillar-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.4rem;
}
.pillar,
.leader-card,
.aside-card {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  transform-style: preserve-3d;
  will-change: transform;
  transition: box-shadow 0.36s var(--ease), border-color 0.36s var(--ease);
}
.pillar { padding: 2rem 1.7rem 2.1rem; }
.pillar:hover,
.leader-card:hover,
.aside-card:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow-md);
}
.pillar-key {
  display: inline-block;
  font-size: var(--step--1);
  font-weight: 800;
  letter-spacing: 0.16em;
  color: var(--bern-red);
  margin-bottom: 1.1rem;
}
.pillar-title {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
  margin-bottom: 0.5em;
}
.pillar-body { color: var(--text-muted); margin: 0; }

/* The highlight that follows the cursor across a tilted card. It only
   appears while premium.js is actually tracking a pointer. */
.pillar-sheen {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(
    260px circle at var(--mx, 50%) var(--my, 50%),
    rgba(229, 9, 20, 0.10), transparent 68%);
  transition: opacity 0.35s var(--ease);
}
.is-tilting .pillar-sheen { opacity: 1; }

/* --------------------------------------------------------------------------
   About - leadership
   -------------------------------------------------------------------------- */
.leader-wrap { display: flex; justify-content: center; }
.leader-card {
  max-width: 640px;
  margin: 0;
  padding: 2.8rem 2.2rem 2.4rem;
  text-align: center;
}
.leader-avatar {
  width: 84px; height: 84px;
  margin: 0 auto 1.4rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--bern-red);
  color: var(--white);
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 700;
  line-height: 1;
}
.leader-quote {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 600;
  line-height: 1.3;
  margin: 0 0 1.5rem;
  text-wrap: balance;
}
.leader-quote::before { content: "\201C"; }
.leader-quote::after  { content: "\201D"; }
.leader-meta { display: flex; flex-direction: column; gap: 0.2rem; margin-bottom: 1.4rem; }
.leader-name {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 700;
}
.leader-role {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--bern-red-dark);
}
.leader-body {
  color: var(--text-muted);
  max-width: 46ch;
  margin: 0 auto;
}

/* --------------------------------------------------------------------------
   Contact
   -------------------------------------------------------------------------- */
.contact-hero .lede { max-width: 54ch; }
.contact-headline { margin-bottom: 0.5em; }

.contact-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap: clamp(1.4rem, 3vw, 2.6rem);
  align-items: start;
}

.form-card {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: clamp(1.4rem, 3.4vw, 2.6rem);
}
.form-heading {
  font-size: var(--step-2);
  margin-bottom: 1.8rem;
}

/* Error summary. Sits above the fields, takes focus after a failed submit. */
.form-summary {
  border: 2px solid var(--bern-red-dark);
  border-radius: var(--radius);
  padding: 1.1rem 1.25rem;
  margin-bottom: 1.8rem;
  background: var(--bern-red-tint);
}
.form-summary:focus-visible {
  outline: 3px solid var(--bern-red);
  outline-offset: 3px;
}
.form-summary-title {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 700;
  color: var(--bern-red-dark);
  margin: 0 0 0.6rem;
}
.form-summary ul { margin: 0; padding-left: 1.1rem; }
.form-summary li { margin-bottom: 0.3rem; }
.form-summary a { color: var(--bern-red-dark); font-weight: 600; }

/* Fields */
.fld-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.2rem;
}
.fld { display: flex; flex-direction: column; gap: 0.42rem; grid-column: 1 / -1; }
.fld-half { grid-column: span 1; }

.fld-label {
  font-size: var(--step--1);
  font-weight: 700;
  color: var(--text);
}
.fld-req { color: var(--bern-red-dark); }
.fld-opt {
  font-weight: 600;
  color: var(--text-muted);
  text-transform: none;
  letter-spacing: 0;
}

.fld-input {
  width: 100%;
  min-height: 48px;
  padding: 0.75rem 0.95rem;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--text);
  background: var(--bg-soft);
  border: 1.5px solid var(--border-strong);
  border-radius: var(--radius);
  transition: border-color 0.22s var(--ease), box-shadow 0.22s var(--ease),
              background 0.22s var(--ease);
}
textarea.fld-input { min-height: 132px; resize: vertical; line-height: 1.55; }
/* Chrome sizes a select from its intrinsic content and ignores min-height,
   which left it 2px shorter than the inputs beside it. */
select.fld-input { cursor: pointer; height: 48px; }
.fld-input::placeholder { color: var(--text-faint); }
.fld-input:hover { border-color: var(--gunmetal); }
.fld-input:focus {
  outline: none;
  background: var(--white);
  border-color: var(--bern-red);
  box-shadow: 0 0 0 4px rgba(229, 9, 20, 0.14);
}
.fld-input:focus-visible { outline: 2px solid var(--bern-red); outline-offset: 2px; }

.fld-input.is-invalid {
  border-color: var(--bern-red-dark);
  background: var(--bern-red-tint);
}

.fld-help { font-size: var(--step--1); color: var(--text-muted); margin: 0; }
.fld-err {
  font-size: var(--step--1);
  font-weight: 700;
  color: var(--bern-red-dark);
  margin: 0;
  display: flex;
  align-items: flex-start;
  gap: 0.4rem;
}
/* The error carries a mark as well as a colour, so it does not rely on red
   alone to say something is wrong. */
.fld-err::before { content: "\26A0"; line-height: 1.4; }

/* An author `display` beats the `hidden` attribute, which the browser only
   styles as `display: none` in its own default sheet. Without this, every
   field sat under a bare red warning mark and no message, because the empty
   error paragraph was still being laid out by its own `display: flex`.
   Anything this page shows and hides through `hidden` needs the same guard. */
.fld-err[hidden],
.form-summary[hidden],
.form-done[hidden],
#contact-form[hidden] { display: none !important; }

/* Honeypot - off screen for people, visible to the bots that fill it. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

.form-foot {
  display: flex;
  align-items: center;
  gap: 1.2rem;
  flex-wrap: wrap;
  margin-top: 1.9rem;
}
.form-card .form-note {
  color: var(--text-muted);
  margin: 0;
  font-size: var(--step--1);
  min-height: 0;
}
.form-submit[disabled] { opacity: 0.62; cursor: progress; }
.form-spinner {
  width: 16px; height: 16px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.4);
  border-top-color: var(--white);
  display: none;
}
.form-submit.is-busy .form-spinner {
  display: block;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Success panel */
.form-done { text-align: center; padding: 1.4rem 0 0.6rem; }
.form-done:focus-visible { outline: 3px solid var(--bern-red); outline-offset: 6px; }
.done-title {
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 600;
  margin-bottom: 0.4em;
}
.done-body { color: var(--text-muted); max-width: 44ch; margin: 0 auto; }
.done-note {
  margin: 1.2rem auto 0;
  max-width: 46ch;
  font-size: var(--step--1);
  color: var(--text-muted);
  border-top: 1px solid var(--border);
  padding-top: 1.1rem;
}

/* Aside */
.aside-card { padding: 2rem 1.8rem; }
.aside-heading { font-size: var(--step-1); margin-bottom: 1.3rem; }
.aside-list { list-style: none; margin: 0 0 1.8rem; padding: 0; }
.aside-list li {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.85rem 0;
  border-top: 1px solid var(--border);
}
.aside-list li:first-child { border-top: 0; padding-top: 0; }
.aside-label {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.aside-value {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  min-height: 32px;
  display: inline-flex;
  align-items: center;
}
.aside-value:hover, .aside-value:focus-visible { color: var(--bern-red-dark); }
.aside-response {
  border-top: 1px solid var(--border);
  padding-top: 1.4rem;
}
.aside-response h3 {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bern-red);
  margin-bottom: 0.5em;
}
.aside-response p { color: var(--text-muted); margin: 0; font-size: var(--step-0); }

/* --------------------------------------------------------------------------
   Narrow screens
   -------------------------------------------------------------------------- */
@media (max-width: 920px) {
  .contact-layout { grid-template-columns: minmax(0, 1fr); }
  .story-spine { display: none; }
}
@media (max-width: 560px) {
  .fld-grid { grid-template-columns: minmax(0, 1fr); }
  .fld-half { grid-column: 1 / -1; }
  .form-foot { align-items: stretch; }
  .form-submit { width: 100%; }
  .ribbon-item { font-size: var(--step-1); }
  .leader-card { padding: 2rem 1.4rem; }
}

/* --------------------------------------------------------------------------
   Reduced motion
   Every effect above is either transform-only or driven by premium.js, which
   does not start under this query. These are the leftovers.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .domain-dot { animation: none; }
  .form-submit.is-busy .form-spinner { animation: none; opacity: 0.7; }
  .pillar, .leader-card, .aside-card { transform: none !important; }
  .pillar-sheen { display: none; }
  .story-spine path { stroke-dashoffset: 0 !important; }
}

/* --------------------------------------------------------------------------
   Location — the address card and UEN, About page
   One centred card. No map: the section loads nothing from a third party.
   -------------------------------------------------------------------------- */
.location-grid {
  display: grid;
  justify-content: center;
  margin-top: clamp(2rem, 4vw, 3.2rem);
}

.location-card {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.1rem;
  width: min(520px, 100%);
  padding: clamp(1.8rem, 3vw, 2.6rem);
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  transform-style: preserve-3d;
  will-change: transform;
  transition: box-shadow 0.36s var(--ease), border-color 0.36s var(--ease);
}
.location-card:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow-md);
}

/* The pin is drawn, not an image file - one less request, and it inherits the
   brand red automatically. Decorative, so it is hidden from screen readers. */
.location-pin {
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
  background: var(--bern-red);
  box-shadow: 0 6px 18px rgba(229, 9, 20, 0.28);
}
.location-pin::after {
  content: "";
  display: block;
  width: 12px;
  height: 12px;
  margin: 11px 0 0 11px;
  border-radius: 50%;
  background: var(--white);
}

/* --ink on --white is about 19:1, well past the 4.5:1 floor. */
.location-address {
  font-family: var(--font-display);
  font-style: normal;          /* <address> italicises by default */
  font-size: var(--step-1);
  font-weight: 600;
  line-height: 1.5;
  color: var(--ink);
  margin: 0;
}

/* The UEN. A hairline separates company identity from the address without
   needing a second card. */
.location-uen {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  width: 100%;
  margin: 0;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}
.location-uen-label {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--bern-red);
}
.location-uen-value {
  font-family: var(--font-display);
  font-size: var(--step-0);
  font-weight: 600;
  color: var(--ink);
  /* A UEN is read digit by digit, so it gets tabular figures and a little
     extra tracking - 0 and O, 1 and I stay distinguishable. */
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
}

.location-note {
  font-size: var(--step--1);
  color: var(--text-muted);
  margin: 0;
  max-width: 34ch;             /* keeps the measure inside the readable range */
}

@media (prefers-reduced-motion: reduce) {
  .location-card { transform: none !important; }
}

/* --------------------------------------------------------------------------
   Capabilities — "What we make", About page
   Replaced the scrolling domain band and the three counters. Two columns of
   plain text on desktop, one on mobile. Nothing moves.
   -------------------------------------------------------------------------- */
.cap-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: clamp(1.4rem, 3vw, 2.4rem) clamp(1.6rem, 4vw, 3.4rem);
  margin-top: clamp(2rem, 4vw, 3rem);
}

.cap-card {
  position: relative;
  padding-top: 1.2rem;
  border-top: 1px solid var(--border);
}
/* A short red rule sitting on the hairline - a marker per item without
   numbering them, since these are a set and not a sequence. */
.cap-card::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  width: 34px;
  height: 2px;
  background: var(--bern-red);
}

.cap-name {
  margin: 0 0 0.55rem;
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 700;
  line-height: 1.25;
  color: var(--ink);
  text-wrap: balance;
}

.cap-body {
  margin: 0;
  font-size: var(--step-0);
  line-height: 1.65;
  color: var(--text-muted);
  max-width: 62ch;        /* keeps the measure in the readable 60-75 range */
}


/* ==========================================================================
   30. RESOURCES LIBRARY
   --------------------------------------------------------------------------
   Everything below styles three things that did not exist before: the
   Resources hub, the Blog listing, and the long-form article pages.

   It is additive on purpose. Nothing here changes a rule above it, so the
   homepage, portfolio, about and contact pages render exactly as they did
   before this block was added. If the library is ever removed again, this
   whole section can be deleted in one cut.
   ========================================================================== */

/* ------------------------------------------------- the category filter row */
.lib-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-bottom: 2.6rem;
}

.lib-filter {
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 0.55rem 1.15rem;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: color 0.3s var(--ease), border-color 0.3s var(--ease),
              background-color 0.3s var(--ease);
}

.lib-filter:hover { color: var(--ink); border-color: var(--ink); }

.lib-filter[aria-pressed="true"] {
  background: var(--bern-red);
  border-color: var(--bern-red);
  color: var(--white);
}

/* ---------------------------------------------------------- featured slot */
/* The flagship guides, given room at the top of the hub. Below 860px the
   picture stacks above the words rather than shrinking into a stamp. */
.lib-feature {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: clamp(1.4rem, 3vw, 2.8rem);
  align-items: center;
  padding: clamp(1.2rem, 2.5vw, 1.9rem);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--white);
  box-shadow: var(--shadow-sm);
  margin-bottom: 1.4rem;
  transition: box-shadow 0.5s var(--ease), transform 0.5s var(--ease),
              border-color 0.5s var(--ease);
}

.lib-feature:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--border-strong);
  transform: translateY(-3px);
}

.lib-feature-media {
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-soft);
}

.lib-feature-media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.7s var(--ease);
}

.lib-feature:hover .lib-feature-media img { transform: scale(1.04); }

.lib-feature h3 {
  font-size: var(--step-2);
  margin: 0.5rem 0 0.7rem;
  text-wrap: balance;
}

.lib-feature h3 a { color: inherit; text-decoration: none; }
.lib-feature h3 a:hover { color: var(--bern-red); }

.lib-feature p { color: var(--text-muted); margin: 0 0 1rem; max-width: 56ch; }

@media (max-width: 860px) {
  .lib-feature { grid-template-columns: 1fr; }
  .lib-feature-media { order: -1; }
}

/* ------------------------------------------------------------ the grid */
.lib-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(288px, 1fr));
  gap: clamp(1.4rem, 3vw, 2.2rem);
}

/* Hidden by the category filter. Set as an attribute rather than an inline
   style so the filter never has to remember what display used to be. */
.lib-grid > [hidden] { display: none !important; }

.lib-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 0;
  background: transparent;
  border: 0;
}

.lib-card .article-media { margin-bottom: 1rem; }

.lib-card h3 {
  font-size: var(--step-1);
  margin: 0 0 0.55rem;
  line-height: 1.3;
  text-wrap: balance;
}

.lib-card h3 a { color: inherit; text-decoration: none; }
.lib-card h3 a:hover { color: var(--bern-red); }

.lib-card p {
  color: var(--text-muted);
  font-size: var(--step-0);
  line-height: 1.6;
  margin: 0;
}

/* The whole card lifts, so the image needs the parent hover, not its own. */
.lib-card .article-media img { transition: transform 0.7s var(--ease); }
.lib-card:hover .article-media img { transform: scale(1.05); }

.lib-empty {
  padding: 3rem 0;
  color: var(--text-faint);
  font-weight: 600;
}

/* --------------------------------------------------------- article pages */
/* A single readable column. --max-narrow is 820px and the prose measure is
   capped at 72ch above, so text never runs to an unreadable width even on
   a very wide monitor. */
.article-head { max-width: var(--max-narrow); }

.article-head h1 { margin: 0.4rem 0 1rem; text-wrap: balance; }

.article-byline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text-faint);
  padding-bottom: 1.6rem;
  border-bottom: 1px solid var(--border);
}

.article-byline .sep { color: var(--border-strong); }

.article-hero {
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--bg-soft);
  margin: 2.2rem 0 0;
}

.article-hero img { width: 100%; height: 100%; object-fit: cover; }

/* The standfirst - one paragraph, larger than the body, that says what the
   reader is about to get. Google frequently lifts this as the snippet. */
.article-standfirst {
  font-size: var(--step-1);
  line-height: 1.55;
  color: var(--text);
  font-weight: 500;
  margin: 0 0 2rem;
}

/* --------------------------------------------------------- contents box */
.toc {
  border: 1px solid var(--border);
  border-left: 3px solid var(--bern-red);
  border-radius: var(--radius);
  background: var(--bg-soft);
  padding: 1.3rem 1.5rem;
  margin: 0 0 2.6rem;
}

.toc h2 {
  font-family: var(--font-body);
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 0.8rem !important;
}

.toc ol { margin: 0; padding-left: 1.1rem; }
.toc li { margin-bottom: 0.4rem; color: var(--text-muted); }
.toc a { color: var(--text-muted); text-decoration: none; font-weight: 600; }
.toc a:hover { color: var(--bern-red); text-decoration: underline; }

/* Anchored headings must clear the fixed header when jumped to. */
.prose h2[id], .prose h3[id] { scroll-margin-top: 100px; }

/* ------------------------------------------------- prose additions */
/* .prose already sets the measure and the heading sizes. These are the
   pieces long-form articles need that the legal pages never did. */
.prose > p, .prose > ul, .prose > ol { margin-bottom: 1.15em; }
.prose li { margin-bottom: 0.4em; }
.prose strong { color: var(--ink); font-weight: 700; }

.prose blockquote {
  margin: 2rem 0;
  padding: 0.2rem 0 0.2rem 1.4rem;
  border-left: 3px solid var(--bern-red);
  font-family: var(--font-display);
  font-size: var(--step-1);
  line-height: 1.5;
  color: var(--ink);
}

/* A stated fact with its source attached. Used wherever this site puts a
   number in front of a reader - the number and where it came from should
   never be more than one glance apart. */
.stat-callout {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 0 1.3rem;
  align-items: baseline;
  margin: 2rem 0;
  padding: 1.4rem 1.6rem;
  border-radius: var(--radius);
  background: var(--bg-soft);
  border: 1px solid var(--border);
}

.stat-callout .stat-num {
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 1.4rem + 2vw, 2.8rem);
  font-weight: 700;
  line-height: 1;
  color: var(--bern-red);
  white-space: nowrap;
}

.stat-callout .stat-text {
  color: var(--text-muted);
  font-size: var(--step-0);
  line-height: 1.6;
}

.stat-callout .stat-text cite {
  display: block;
  margin-top: 0.5rem;
  font-style: normal;
  font-size: var(--step--1);
  color: var(--text-faint);
}

@media (max-width: 520px) {
  .stat-callout { grid-template-columns: 1fr; gap: 0.7rem; }
}

/* Tables carry the price bands. They must scroll inside their own box
   rather than making the whole page scroll sideways on a phone. */
.table-scroll {
  overflow-x: auto;
  margin: 2rem 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  -webkit-overflow-scrolling: touch;
}

.prose table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--step--1);
  min-width: 520px;
}

.prose th, .prose td {
  text-align: left;
  padding: 0.85rem 1.1rem;
  border-bottom: 1px solid var(--border);
}

.prose thead th {
  background: var(--bg-soft);
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-size: 0.72rem;
  color: var(--text-faint);
}

.prose tbody tr:last-child td { border-bottom: 0; }
.prose td strong { color: var(--ink); }

/* -------------------------------------------------------- the references */
/* Every statistic in these articles is traceable. The list is numbered to
   match the [1]-style markers in the body text. */
.refs {
  margin-top: 3.5rem;
  padding-top: 2rem;
  border-top: 1px solid var(--border);
}

.refs h2 {
  font-family: var(--font-body) !important;
  font-size: 0.8rem !important;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 1.1rem !important;
}

.refs ol { padding-left: 1.3rem; }

.refs li {
  font-size: var(--step--1);
  line-height: 1.6;
  color: var(--text-faint);
  margin-bottom: 0.75rem;
  overflow-wrap: anywhere;
}

.refs a { color: var(--text-muted); }

/* A citation marker in the body copy. Small, superscript, clickable. */
.cite-ref {
  font-size: 0.68em;
  vertical-align: super;
  line-height: 0;
  font-weight: 700;
  color: var(--bern-red);
  text-decoration: none;
  padding: 0 0.1em;
}

.cite-ref:hover { text-decoration: underline; }

/* ------------------------------------------------------------ next up */
.article-next {
  margin-top: 3.5rem;
  padding-top: 2.4rem;
  border-top: 1px solid var(--border);
}

.article-next h2 {
  font-family: var(--font-body);
  font-size: 0.8rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 1.4rem;
}

.article-next .lib-grid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }

/* An in-article call to action. Deliberately quieter than the homepage
   band - it interrupts a piece of writing, so it earns less shouting. */
.article-cta {
  margin: 2.8rem 0;
  padding: clamp(1.5rem, 3vw, 2.2rem);
  border-radius: var(--radius-lg);
  background: var(--ink);
  color: rgba(255, 255, 255, 0.72);
}

.article-cta h3 {
  color: var(--white);
  font-size: var(--step-1);
  margin: 0 0 0.6rem;
}

.article-cta p { color: rgba(255, 255, 255, 0.68); margin: 0 0 1.3rem; max-width: 52ch; }

/* ==========================================================================
   RESOURCES v2 — added 2026-09-11 from the competitor blog audit
   (SEO/research_ai). Every top-ranking agency blog carries the same
   handful of parts: a takeaways box up top, a visible FAQ, a real
   author line, and a searchable hub. These are those parts.
   ========================================================================== */

/* "Updated" date in the byline - freshness is a ranking signal and the
   first thing a buyer checks on a pricing article. */
.article-updated { color: var(--text-muted); }

/* ------------------------------------------------------ key takeaways */
/* Sits between the standfirst and the contents box. Written so it can be
   lifted whole as a featured snippet: a heading and 3-5 short bullets. */
.article-takeaways {
  margin: 0 0 2rem;
  padding: 1.3rem 1.5rem 1.1rem;
  border-radius: var(--radius);
  background: var(--white);
  border: 1px solid var(--border-strong);
  box-shadow: var(--shadow-sm);
}

.article-takeaways h2 {
  font-family: var(--font-body);
  font-size: 0.78rem !important;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bern-red);
  margin: 0 0 0.8rem !important;
}

.article-takeaways ul { margin: 0; padding-left: 1.1rem; }
.article-takeaways li { margin-bottom: 0.5rem; color: var(--text); }

/* ------------------------------------------------------------ the FAQ */
/* Native <details>, so it opens without JavaScript and every answer is in
   the HTML a crawler reads. The same questions are in FAQPage schema. */
.article-faq { margin: 3rem 0 0; }

.article-faq details {
  border-bottom: 1px solid var(--border);
}

.article-faq details:first-of-type { border-top: 1px solid var(--border); }

.article-faq summary {
  list-style: none;
  cursor: pointer;
  padding: 1.1rem 2.2rem 1.1rem 0;
  position: relative;
  font-weight: 700;
  color: var(--ink);
  line-height: 1.45;
}

.article-faq summary::-webkit-details-marker { display: none; }

.article-faq summary::after {
  content: "+";
  position: absolute;
  right: 0.2rem;
  top: 0.95rem;
  font-size: 1.3rem;
  font-weight: 400;
  color: var(--bern-red);
  transition: transform 0.3s var(--ease);
}

.article-faq details[open] summary::after { transform: rotate(45deg); }
.article-faq summary:hover { color: var(--bern-red); }
.article-faq details p { margin: 0 0 1.2rem; padding-right: 2rem; color: var(--text-muted); }

/* --------------------------------------------------------- author box */
.article-author {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 1.1rem;
  align-items: start;
  margin: 3rem 0 0;
  padding: 1.4rem 1.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-soft);
}

.article-author img {
  width: 52px; height: 52px;
  object-fit: contain;
  border-radius: 50%;
  background: var(--white);
  border: 1px solid var(--border);
  padding: 8px;
}

.article-author p { margin: 0; font-size: var(--step--1); color: var(--text-muted); line-height: 1.6; }
.article-author p strong { display: block; font-size: var(--step-0); color: var(--ink); margin-bottom: 0.2rem; }

/* ------------------------------------------------------- the glossary */
.glossary { margin: 0; }
.glossary dt {
  font-weight: 800;
  color: var(--ink);
  margin-top: 1.4rem;
  scroll-margin-top: 100px;
}
.glossary dd { margin: 0.3rem 0 0; color: var(--text-muted); }

.glossary-jump {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0 0 2rem;
}

.glossary-jump a {
  display: inline-block;
  min-width: 2.1rem;
  text-align: center;
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  font-weight: 700;
  font-size: var(--step--1);
  color: var(--text-muted);
  text-decoration: none;
}

.glossary-jump a:hover { color: var(--white); background: var(--bern-red); border-color: var(--bern-red); }

/* -------------------------------------------------- embedded example video */
/* Lazy-loaded iframe in a 16:9 box, with the "why it works" note under it. */
.article-video { margin: 2rem 0; }

.article-video-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--ink);
}

.article-video-frame iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0;
}

.article-video figcaption {
  margin-top: 0.7rem;
  font-size: var(--step--1);
  color: var(--text-faint);
}

/* ---------------------------------------------------- hub search + topics */
.lib-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 1.5rem;
  margin-bottom: 2.6rem;
}

.lib-toolbar .lib-filters { margin-bottom: 0; }

.lib-search {
  position: relative;
  flex: 0 1 300px;
  min-width: 220px;
}

.lib-search input {
  width: 100%;
  font: inherit;
  font-size: var(--step--1);
  padding: 0.65rem 1rem 0.65rem 2.4rem;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border-strong);
  background: var(--white);
  color: var(--ink);
}

.lib-search input:focus { outline: 2px solid var(--bern-red); outline-offset: 2px; border-color: var(--bern-red); }

.lib-search svg {
  position: absolute;
  left: 0.9rem; top: 50%;
  width: 16px; height: 16px;
  transform: translateY(-50%);
  color: var(--text-faint);
  pointer-events: none;
}

/* "Start here" topic clusters under the hub hero - one link per pillar,
   which is also the internal-link map the SEO plan relies on. */
/* Six tiles, so an even 3 x 2 on desktop, 2 x 3 on tablets and one column
   on phones - auto-fill left two empty slots in a 4 + 2 wrap. */
.lib-topics {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem;
  margin: 0 0 3rem;
}

@media (max-width: 860px) { .lib-topics { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 480px) { .lib-topics { grid-template-columns: 1fr; } }

.lib-topic {
  display: block;
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--white);
  text-decoration: none;
  transition: border-color 0.3s var(--ease), transform 0.3s var(--ease);
}

.lib-topic:hover { border-color: var(--bern-red); transform: translateY(-2px); }
.lib-topic span { display: block; font-size: 0.7rem; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; color: var(--bern-red); margin-bottom: 0.35rem; }
.lib-topic strong { display: block; color: var(--ink); line-height: 1.35; }

@media (prefers-reduced-motion: reduce) {
  .lib-topic, .article-faq summary::after { transition: none; }
  .lib-topic:hover { transform: none; }
}

/* --------------------------------------------------------------------------
   Scroll scenes: one published study, told in three frames while the reader
   scrolls. js/scroll-scene.js adds .is-live, sets the wrapper's height and
   drives the frames. Without it (or with reduced motion) the first frame
   shows and every step is listed, so nothing is lost.
   -------------------------------------------------------------------------- */
.scroll-scene { margin: 2.8rem 0; }

.scene-stage {
  margin: 0;
  padding: clamp(1rem, 2vw, 1.4rem);
  border-radius: var(--radius-lg);
  background: var(--ink);
  color: var(--white);
  box-shadow: var(--shadow-md);
}

.scene-kicker {
  margin: 0 0 0.8rem;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--baby-pink);
}

.scene-frames {
  position: relative;
  aspect-ratio: 16 / 9;
  max-height: 54vh;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--gunmetal);
}

.scene-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  will-change: opacity, transform;
}

.scene-frame + .scene-frame { opacity: 0; }

.scene-bar {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 3px;
  background: rgba(255, 255, 255, 0.16);
}
.scene-bar i {
  display: block;
  height: 100%;
  background: var(--bern-red);
  transform: scaleX(0);
  transform-origin: left center;
}

.scene-steps {
  list-style: none;
  counter-reset: step;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  grid-auto-flow: column;
  gap: 0.9rem;
  margin: 1rem 0 0;
  padding: 0;
}
.prose .scene-steps li { margin: 0; }
.scene-steps li {
  counter-increment: step;
  padding-top: 0.6rem;
  border-top: 2px solid rgba(255, 255, 255, 0.18);
  font-size: var(--step--1);
  line-height: 1.45;
  color: rgba(255, 255, 255, 0.92);
  transition: opacity 0.35s var(--ease), border-color 0.35s var(--ease);
}
/* Numbered by position: on phones the inactive steps are display:none, and a
   hidden item does not advance a CSS counter, so every step would read 01. */
.scene-steps li:nth-child(2)::before { content: "02"; }
.scene-steps li:nth-child(3)::before { content: "03"; }
.scene-steps li:nth-child(4)::before { content: "04"; }
.scene-steps li::before {
  content: "01";
  display: block;
  margin-bottom: 0.2rem;
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--bern-red);
}

.scene-stage figcaption {
  margin-top: 1rem;
  padding-top: 0.9rem;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  font-size: var(--step--1);
  line-height: 1.55;
  color: var(--quick-silver);
}
.scene-stage figcaption strong { color: var(--white); }
.scene-stage figcaption a { color: var(--baby-pink); }

/* Live: the stage pins while the wrapper's extra height scrolls past. */
.scroll-scene.is-live .scene-stage {
  position: sticky;
  top: clamp(4.8rem, 9vh, 6.5rem);
}
.scroll-scene.is-live .scene-steps li { opacity: 0.38; }
.scroll-scene.is-live .scene-steps li.is-on { opacity: 1; border-color: var(--bern-red); }

@media (max-width: 640px) {
  .scene-steps { grid-auto-flow: row; grid-template-columns: 1fr; gap: 0.5rem; }
  /* On a phone only the current step shows, so the stage stays short. */
  .scroll-scene.is-live .scene-steps li { display: none; }
  .scroll-scene.is-live .scene-steps li.is-on { display: block; }
  .scroll-scene.is-live .scene-steps { min-height: 6.2em; }
}

@media (prefers-reduced-motion: reduce) {
  .scene-steps li { transition: none; }
}
